Skip to content

Commit

Permalink
drop some impl candidates before evaluating candidates
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed May 25, 2022
1 parent f80e454 commit eb49408
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 168 deletions.
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

0 comments on commit eb49408

Please sign in to comment.