Rollup merge of #124871 - compiler-errors:overflowo, r=lcnr

Don't ICE because recomputing overflow goals during find_best_leaf_obligation causes inference side-effects

See the comments for more info. Reprocessing overflowed obligations may cause *other* goals to go from ambig -> pass/fail, causing an ICE. This suppresses that error, but makes all the overflow obligations messages back to their root obl. That kinda sucks, but 🤷

Fixes #124834
Fixes #124845

r? lcnr
This commit is contained in:
Matthias Krüger 2024-05-16 16:22:44 +02:00 committed by GitHub
commit 71ae7db509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 145 additions and 220 deletions

View File

@ -244,16 +244,23 @@ fn fulfillment_error_for_no_solution<'tcx>(
fn fulfillment_error_for_stalled<'tcx>( fn fulfillment_error_for_stalled<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>, root_obligation: PredicateObligation<'tcx>,
) -> FulfillmentError<'tcx> { ) -> FulfillmentError<'tcx> {
let code = infcx.probe(|_| { let (code, refine_obligation) = infcx.probe(|_| {
match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 { match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::Never).0 {
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
FulfillmentErrorCode::Ambiguity { overflow: None } (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
}
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
} }
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
// Don't look into overflows because we treat overflows weirdly anyways.
// In `instantiate_response_discarding_overflow` we set `has_changed = false`,
// recomputing the goal again during `find_best_leaf_obligation` may apply
// inference guidance that makes other goals go from ambig -> pass, for example.
//
// FIXME: We should probably just look into overflows here.
false,
),
Ok((_, Certainty::Yes)) => { Ok((_, Certainty::Yes)) => {
bug!("did not expect successful goal when collecting ambiguity errors") bug!("did not expect successful goal when collecting ambiguity errors")
} }
@ -264,9 +271,13 @@ fn fulfillment_error_for_stalled<'tcx>(
}); });
FulfillmentError { FulfillmentError {
obligation: find_best_leaf_obligation(infcx, &obligation, true), obligation: if refine_obligation {
find_best_leaf_obligation(infcx, &root_obligation, true)
} else {
root_obligation.clone()
},
code, code,
root_obligation: obligation, root_obligation,
} }
} }
@ -302,42 +313,51 @@ impl<'tcx> BestObligation<'tcx> {
res res
} }
/// Filter out the candidates that aren't either error or ambiguous (depending /// Filter out the candidates that aren't interesting to visit for the
/// on what we are looking for), and also throw out candidates that have no /// purposes of reporting errors. For ambiguities, we only consider
/// failing WC (or higher-ranked obligations, for which there should only be /// candidates that may hold. For errors, we only consider candidates that
/// one candidate anyways -- but I digress). This most likely means that the /// *don't* hold and which have impl-where clauses that also don't hold.
/// goal just didn't unify at all, e.g. a param candidate with an alias in it.
fn non_trivial_candidates<'a>( fn non_trivial_candidates<'a>(
&self, &self,
goal: &'a InspectGoal<'a, 'tcx>, goal: &'a InspectGoal<'a, 'tcx>,
) -> Vec<InspectCandidate<'a, 'tcx>> { ) -> Vec<InspectCandidate<'a, 'tcx>> {
let mut candidates = goal let mut candidates = goal.candidates();
.candidates() match self.consider_ambiguities {
.into_iter() true => {
.filter(|candidate| match self.consider_ambiguities { // If we have an ambiguous obligation, we must consider *all* candidates
true => matches!(candidate.result(), Ok(Certainty::Maybe(_))), // that hold, or else we may guide inference causing other goals to go
false => matches!(candidate.result(), Err(_)), // from ambig -> pass/fail.
}) candidates.retain(|candidate| candidate.result().is_ok());
.collect::<Vec<_>>(); }
false => {
// If we have >1 candidate, one may still be due to "boring" reasons, like // If we have >1 candidate, one may still be due to "boring" reasons, like
// an alias-relate that failed to hold when deeply evaluated. We really // an alias-relate that failed to hold when deeply evaluated. We really
// don't care about reasons like this. // don't care about reasons like this.
if candidates.len() > 1 { if candidates.len() > 1 {
candidates.retain(|candidate| { candidates.retain(|candidate| {
goal.infcx().probe(|_| { goal.infcx().probe(|_| {
candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| { candidate.instantiate_nested_goals(self.span()).iter().any(
|nested_goal| {
matches!( matches!(
nested_goal.source(), nested_goal.source(),
GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked GoalSource::ImplWhereBound
| GoalSource::InstantiateHigherRanked
) && match self.consider_ambiguities { ) && match self.consider_ambiguities {
true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))), true => {
matches!(
nested_goal.result(),
Ok(Certainty::Maybe(MaybeCause::Ambiguity))
)
}
false => matches!(nested_goal.result(), Err(_)), false => matches!(nested_goal.result(), Err(_)),
} }
}) },
)
}) })
}); });
} }
}
}
candidates candidates
} }
@ -401,7 +421,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
// Skip nested goals that aren't the *reason* for our goal's failure. // Skip nested goals that aren't the *reason* for our goal's failure.
match self.consider_ambiguities { match self.consider_ambiguities {
true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {} true if matches!(
nested_goal.result(),
Ok(Certainty::Maybe(MaybeCause::Ambiguity))
) => {}
false if matches!(nested_goal.result(), Err(_)) => {} false if matches!(nested_goal.result(), Err(_)) => {}
_ => continue, _ => continue,
} }

View File

@ -1,12 +1,12 @@
error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>` error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
--> $DIR/coherence-fulfill-overflow.rs:12:1 --> $DIR/coherence-fulfill-overflow.rs:12:1
| |
LL | impl<T: ?Sized + TwoW> Trait for W<T> {} LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
| ------------------------------------- first implementation here | ------------------------------------- first implementation here
LL | impl<T: ?Sized + TwoW> Trait for T {} LL | impl<T: ?Sized + TwoW> Trait for T {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
| |
= note: overflow evaluating the requirement `W<W<W<W<_>>>>: TwoW` = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -1,16 +1,9 @@
error[E0275]: overflow evaluating the requirement `_: Sized` error[E0275]: overflow evaluating the requirement `W<_>: Trait`
--> $DIR/fixpoint-exponential-growth.rs:33:13 --> $DIR/fixpoint-exponential-growth.rs:33:13
| |
LL | impls::<W<_>>(); LL | impls::<W<_>>();
| ^^^^ | ^^^^
| |
note: required for `W<(W<_>, W<_>)>` to implement `Trait`
--> $DIR/fixpoint-exponential-growth.rs:23:12
|
LL | impl<T, U> Trait for W<(W<T>, W<U>)>
| - ^^^^^ ^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `impls` note: required by a bound in `impls`
--> $DIR/fixpoint-exponential-growth.rs:30:13 --> $DIR/fixpoint-exponential-growth.rs:30:13
| |

View File

@ -1,53 +1,21 @@
error[E0275]: overflow evaluating the requirement `(): Inductive` error[E0275]: overflow evaluating the requirement `(): Trait`
--> $DIR/double-cycle-inductive-coinductive.rs:32:19 --> $DIR/double-cycle-inductive-coinductive.rs:32:19
| |
LL | impls_trait::<()>(); LL | impls_trait::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `Trait`
--> $DIR/double-cycle-inductive-coinductive.rs:9:34
|
LL | impl<T: Inductive + Coinductive> Trait for T {}
| --------- ^^^^^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `Inductive`
--> $DIR/double-cycle-inductive-coinductive.rs:12:16
|
LL | impl<T: Trait> Inductive for T {}
| ----- ^^^^^^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 7 redundant requirements hidden
= note: required for `()` to implement `Trait`
note: required by a bound in `impls_trait` note: required by a bound in `impls_trait`
--> $DIR/double-cycle-inductive-coinductive.rs:17:19 --> $DIR/double-cycle-inductive-coinductive.rs:17:19
| |
LL | fn impls_trait<T: Trait>() {} LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait` | ^^^^^ required by this bound in `impls_trait`
error[E0275]: overflow evaluating the requirement `(): CoinductiveRev` error[E0275]: overflow evaluating the requirement `(): TraitRev`
--> $DIR/double-cycle-inductive-coinductive.rs:35:23 --> $DIR/double-cycle-inductive-coinductive.rs:35:23
| |
LL | impls_trait_rev::<()>(); LL | impls_trait_rev::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `TraitRev`
--> $DIR/double-cycle-inductive-coinductive.rs:21:40
|
LL | impl<T: CoinductiveRev + InductiveRev> TraitRev for T {}
| -------------- ^^^^^^^^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `CoinductiveRev`
--> $DIR/double-cycle-inductive-coinductive.rs:27:19
|
LL | impl<T: TraitRev> CoinductiveRev for T {}
| -------- ^^^^^^^^^^^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 7 redundant requirements hidden
= note: required for `()` to implement `TraitRev`
note: required by a bound in `impls_trait_rev` note: required by a bound in `impls_trait_rev`
--> $DIR/double-cycle-inductive-coinductive.rs:29:23 --> $DIR/double-cycle-inductive-coinductive.rs:29:23
| |

View File

@ -1,19 +1,9 @@
error[E0275]: overflow evaluating the requirement `W<W<_>>: Trait` error[E0275]: overflow evaluating the requirement `W<_>: Trait`
--> $DIR/inductive-fixpoint-hang.rs:31:19 --> $DIR/inductive-fixpoint-hang.rs:31:19
| |
LL | impls_trait::<W<_>>(); LL | impls_trait::<W<_>>();
| ^^^^ | ^^^^
| |
note: required for `W<W<W<_>>>` to implement `Trait`
--> $DIR/inductive-fixpoint-hang.rs:22:17
|
LL | impl<T: ?Sized> Trait for W<W<T>>
| ^^^^^ ^^^^^^^
LL | where
LL | W<T>: Trait,
| ----- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>` to implement `Trait`
note: required by a bound in `impls_trait` note: required by a bound in `impls_trait`
--> $DIR/inductive-fixpoint-hang.rs:28:19 --> $DIR/inductive-fixpoint-hang.rs:28:19
| |

View File

@ -39,7 +39,7 @@ fn impls_ar<T: AR>() {}
fn main() { fn main() {
impls_a::<()>(); impls_a::<()>();
//~^ ERROR overflow evaluating the requirement `(): B` //~^ ERROR overflow evaluating the requirement `(): A`
impls_ar::<()>(); impls_ar::<()>();
//~^ ERROR overflow evaluating the requirement `(): AR` //~^ ERROR overflow evaluating the requirement `(): AR`

View File

@ -1,25 +1,9 @@
error[E0275]: overflow evaluating the requirement `(): B` error[E0275]: overflow evaluating the requirement `(): A`
--> $DIR/inductive-not-on-stack.rs:41:15 --> $DIR/inductive-not-on-stack.rs:41:15
| |
LL | impls_a::<()>(); LL | impls_a::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `A`
--> $DIR/inductive-not-on-stack.rs:21:16
|
LL | impl<T: B + C> A for T {}
| - ^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `B`
--> $DIR/inductive-not-on-stack.rs:22:12
|
LL | impl<T: A> B for T {}
| - ^ ^
| |
| unsatisfied trait bound introduced here
= note: 7 redundant requirements hidden
= note: required for `()` to implement `A`
note: required by a bound in `impls_a` note: required by a bound in `impls_a`
--> $DIR/inductive-not-on-stack.rs:25:15 --> $DIR/inductive-not-on-stack.rs:25:15
| |
@ -32,29 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR`
LL | impls_ar::<()>(); LL | impls_ar::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `BR`
--> $DIR/inductive-not-on-stack.rs:35:13
|
LL | impl<T: AR> BR for T {}
| -- ^^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `CR`
--> $DIR/inductive-not-on-stack.rs:36:13
|
LL | impl<T: BR> CR for T {}
| -- ^^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `AR`
--> $DIR/inductive-not-on-stack.rs:34:18
|
LL | impl<T: CR + BR> AR for T {}
| -- ^^ ^
| |
| unsatisfied trait bound introduced here
= note: 6 redundant requirements hidden
= note: required for `()` to implement `AR`
note: required by a bound in `impls_ar` note: required by a bound in `impls_ar`
--> $DIR/inductive-not-on-stack.rs:38:16 --> $DIR/inductive-not-on-stack.rs:38:16
| |

View File

@ -35,5 +35,5 @@ fn impls_a<T: A>() {}
fn main() { fn main() {
impls_a::<()>(); impls_a::<()>();
//~^ ERROR overflow evaluating the requirement `(): CInd` //~^ ERROR overflow evaluating the requirement `(): A`
} }

View File

@ -1,46 +1,9 @@
error[E0275]: overflow evaluating the requirement `(): CInd` error[E0275]: overflow evaluating the requirement `(): A`
--> $DIR/mixed-cycles-1.rs:37:15 --> $DIR/mixed-cycles-1.rs:37:15
| |
LL | impls_a::<()>(); LL | impls_a::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `B`
--> $DIR/mixed-cycles-1.rs:31:28
|
LL | impl<T: ?Sized + CInd + C> B for T {}
| ---- ^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `C`
--> $DIR/mixed-cycles-1.rs:32:25
|
LL | impl<T: ?Sized + B + A> C for T {}
| - ^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `CInd`
--> $DIR/mixed-cycles-1.rs:28:21
|
LL | impl<T: ?Sized + C> CInd for T {}
| - ^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 4 redundant requirements hidden
= note: required for `()` to implement `B`
note: required for `()` to implement `BInd`
--> $DIR/mixed-cycles-1.rs:23:21
|
LL | impl<T: ?Sized + B> BInd for T {}
| - ^^^^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `A`
--> $DIR/mixed-cycles-1.rs:30:28
|
LL | impl<T: ?Sized + BInd + C> A for T {}
| ---- ^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `impls_a` note: required by a bound in `impls_a`
--> $DIR/mixed-cycles-1.rs:34:15 --> $DIR/mixed-cycles-1.rs:34:15
| |

View File

@ -28,5 +28,5 @@ fn impls_a<T: A>() {}
fn main() { fn main() {
impls_a::<()>(); impls_a::<()>();
//~^ ERROR overflow evaluating the requirement `(): BInd` //~^ ERROR overflow evaluating the requirement `(): A`
} }

View File

@ -1,32 +1,9 @@
error[E0275]: overflow evaluating the requirement `(): BInd` error[E0275]: overflow evaluating the requirement `(): A`
--> $DIR/mixed-cycles-2.rs:30:15 --> $DIR/mixed-cycles-2.rs:30:15
| |
LL | impls_a::<()>(); LL | impls_a::<()>();
| ^^ | ^^
| |
note: required for `()` to implement `B`
--> $DIR/mixed-cycles-2.rs:25:24
|
LL | impl<T: ?Sized + BInd> B for T {}
| ---- ^ ^
| |
| unsatisfied trait bound introduced here
note: required for `()` to implement `BInd`
--> $DIR/mixed-cycles-2.rs:22:21
|
LL | impl<T: ?Sized + B> BInd for T {}
| - ^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 6 redundant requirements hidden
= note: required for `()` to implement `BInd`
note: required for `()` to implement `A`
--> $DIR/mixed-cycles-2.rs:24:28
|
LL | impl<T: ?Sized + BInd + B> A for T {}
| ---- ^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `impls_a` note: required by a bound in `impls_a`
--> $DIR/mixed-cycles-2.rs:27:15 --> $DIR/mixed-cycles-2.rs:27:15
| |

View File

@ -0,0 +1,21 @@
//@ compile-flags: -Znext-solver
trait Trait {
type Assoc;
}
struct W<T>(*mut T);
impl<T> Trait for W<W<T>>
where
W<T>: Trait,
{
type Assoc = ();
}
trait NoOverlap {}
impl<T: Trait> NoOverlap for T {}
impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
--> $DIR/ambiguous-fail.rs:18:1
|
LL | impl<T: Trait> NoOverlap for T {}
| ------------------------------ first implementation here
LL |
LL | impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,21 @@
//@ compile-flags: -Znext-solver
trait Trait {
type Assoc;
}
struct W<T>(*mut T);
impl<T> Trait for W<W<T>>
where
W<T>: Trait,
{
type Assoc = ();
}
trait NoOverlap {}
impl<T: Trait> NoOverlap for T {}
impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
fn main() {}

View File

@ -0,0 +1,12 @@
error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
--> $DIR/ambiguous-pass.rs:18:1
|
LL | impl<T: Trait> NoOverlap for T {}
| ------------------------------ first implementation here
LL |
LL | impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -15,5 +15,5 @@ fn impls<T: Trait>() {}
fn main() { fn main() {
impls::<W<_>>(); impls::<W<_>>();
//~^ ERROR overflow evaluating the requirement `_: Sized` //~^ ERROR overflow evaluating the requirement `W<_>: Trait`
} }

View File

@ -1,16 +1,9 @@
error[E0275]: overflow evaluating the requirement `_: Sized` error[E0275]: overflow evaluating the requirement `W<_>: Trait`
--> $DIR/exponential-trait-goals.rs:17:13 --> $DIR/exponential-trait-goals.rs:17:13
| |
LL | impls::<W<_>>(); LL | impls::<W<_>>();
| ^^^^ | ^^^^
| |
note: required for `W<(W<_>, W<_>)>` to implement `Trait`
--> $DIR/exponential-trait-goals.rs:7:12
|
LL | impl<T, U> Trait for W<(W<T>, W<U>)>
| - ^^^^^ ^^^^^^^^^^^^^^^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `impls` note: required by a bound in `impls`
--> $DIR/exponential-trait-goals.rs:14:13 --> $DIR/exponential-trait-goals.rs:14:13
| |

View File

@ -5,15 +5,6 @@ LL | impls_trait::<Four<Four<Four<Four<()>>>>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`) = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>` to implement `Trait`
--> $DIR/global-cache.rs:12:16
|
LL | impl<T: Trait> Trait for Inc<T> {}
| ----- ^^^^^ ^^^^^^
| |
| unsatisfied trait bound introduced here
= note: 5 redundant requirements hidden
= note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>>>>` to implement `Trait`
note: required by a bound in `impls_trait` note: required by a bound in `impls_trait`
--> $DIR/global-cache.rs:15:19 --> $DIR/global-cache.rs:15:19
| |