Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] discard impl candidates before evaluating #97380

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0275.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ trait Foo {}
struct Bar<T>(T);

impl<T> Foo for T where Bar<T>: Foo {}

fn takes_foo<T: Foo>() {}

fn calls_takes_foo() {
takes_foo::<()>();
}
```

This error occurs when there was a recursive trait requirement that overflowed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

// Winnow, but record the exact outcome of evaluation, which
// is needed for specialization. Propagate overflow if it occurs.
let mut eval_cand = |c| match self.evaluate_candidate(stack, &c) {
Ok(eval) if eval.may_apply() => {
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
}
Ok(_) => Ok(None),
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
};

// this is very not perf and should be fixed xd
let drop_impl_candidates = candidates
.iter()
.filter(|c| matches!(c, SelectionCandidate::ParamCandidate(_)))
.cloned()
.map(&mut eval_cand)
.flat_map(Result::transpose)
.try_fold(false, |should_drop, param_candidate| {
let cand = &param_candidate?.candidate;
Ok::<_, SelectionError<'_>>(
should_drop || !(cand.is_global() && !cand.has_late_bound_regions()),
)
})?;
let mut candidates = candidates
.into_iter()
.map(|c| match self.evaluate_candidate(stack, &c) {
Ok(eval) if eval.may_apply() => {
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
}
Ok(_) => Ok(None),
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
})
.filter(|c| !matches!(c, SelectionCandidate::ImplCandidate(_) if drop_impl_candidates))
.map(&mut eval_cand)
.flat_map(Result::transpose)
.collect::<Result<Vec<_>, _>>()?;

Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/const-generics/issues/issue-90318.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ fn consume<T: 'static>(_val: T)
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
//~^ ERROR: overly complex generic constant
//~| ERROR: cannot call non-const operator in constants
{
}

fn test<T: 'static>()
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
//~^ ERROR: overly complex generic constant
//~| ERROR: cannot call non-const operator in constants
{
}

Expand Down
33 changes: 2 additions & 31 deletions src/test/ui/const-generics/issues/issue-90318.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,8 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
= help: consider moving this anonymous constant into a `const` function
= note: this operation may be supported in the future

error[E0015]: cannot call non-const operator in constants
--> $DIR/issue-90318.rs:14:10
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
|
LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
| ^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)

error: overly complex generic constant
--> $DIR/issue-90318.rs:22:8
--> $DIR/issue-90318.rs:21:8
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
| ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -34,20 +20,5 @@ LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
= help: consider moving this anonymous constant into a `const` function
= note: this operation may be supported in the future

error[E0015]: cannot call non-const operator in constants
--> $DIR/issue-90318.rs:22:10
|
LL | If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/any.rs:LL:COL
|
LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
| ^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
5 changes: 4 additions & 1 deletion src/test/ui/error-codes/E0275.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ trait Foo {}

struct Bar<T>(T);

impl<T> Foo for T where Bar<T>: Foo {} //~ ERROR E0275
impl<T> Foo for T where Bar<T>: Foo {}

fn takes_foo<T: Foo>() {}

fn main() {
takes_foo::<()>(); //~ ERROR E0275
}
17 changes: 11 additions & 6 deletions src/test/ui/error-codes/E0275.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:5:33
error[E0275]: overflow evaluating the requirement `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<()>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/E0275.rs:10:5
|
LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^
LL | takes_foo::<()>();
| ^^^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`)
note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
note: required because of the requirements on the impl of `Foo` for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<()>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/E0275.rs:5:9
|
LL | impl<T> Foo for T where Bar<T>: Foo {}
| ^^^ ^
= note: 127 redundant requirements hidden
= note: required because of the requirements on the impl of `Foo` for `Bar<T>`
= note: required because of the requirements on the impl of `Foo` for `()`
note: required by a bound in `takes_foo`
--> $DIR/E0275.rs:7:17
|
LL | fn takes_foo<T: Foo>() {}
| ^^^ required by this bound in `takes_foo`

error: aborting due to previous error

Expand Down
6 changes: 0 additions & 6 deletions src/test/ui/issues/issue-20413.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ struct NoData<T>;
//~^ ERROR: parameter `T` is never used

impl<T> Foo for T where NoData<T>: Foo {
//~^ ERROR: overflow evaluating the requirement
//~| ERROR: overflow evaluating the requirement
fn answer(self) {
let val: NoData<T> = NoData;
}
Expand All @@ -26,16 +24,12 @@ struct AlmostNoData<T>(Option<T>);
struct EvenLessData<T>(Option<T>);

impl<T> Bar for T where EvenLessData<T>: Baz {
//~^ ERROR: overflow evaluating the requirement
//~| ERROR: overflow evaluating the requirement
fn answer(self) {
let val: EvenLessData<T> = EvenLessData(None);
}
}

impl<T> Baz for T where AlmostNoData<T>: Bar {
//~^ ERROR: overflow evaluating the requirement
//~| ERROR: overflow evaluating the requirement
fn answer(self) {
let val: NoData<T> = AlmostNoData(None);
}
Expand Down
Loading