1
Fork 0

Only consider ambiguous goals when finding best obligation for ambiguities

This commit is contained in:
Michael Goulet 2024-05-03 20:08:35 -04:00
parent d7ea27808d
commit 6714216eaa
3 changed files with 24 additions and 20 deletions

View file

@ -137,7 +137,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
.collect(); .collect();
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError { errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
obligation: find_best_leaf_obligation(infcx, &obligation), obligation: find_best_leaf_obligation(infcx, &obligation, true),
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
root_obligation: obligation, root_obligation: obligation,
})); }));
@ -198,7 +198,7 @@ fn fulfillment_error_for_no_solution<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
root_obligation: PredicateObligation<'tcx>, root_obligation: PredicateObligation<'tcx>,
) -> FulfillmentError<'tcx> { ) -> FulfillmentError<'tcx> {
let obligation = find_best_leaf_obligation(infcx, &root_obligation); let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
let code = match obligation.predicate.kind().skip_binder() { let code = match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
@ -266,7 +266,7 @@ fn fulfillment_error_for_stalled<'tcx>(
}); });
FulfillmentError { FulfillmentError {
obligation: find_best_leaf_obligation(infcx, &obligation), obligation: find_best_leaf_obligation(infcx, &obligation, true),
code, code,
root_obligation: obligation, root_obligation: obligation,
} }
@ -275,12 +275,13 @@ fn fulfillment_error_for_stalled<'tcx>(
fn find_best_leaf_obligation<'tcx>( fn find_best_leaf_obligation<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
consider_ambiguities: bool,
) -> PredicateObligation<'tcx> { ) -> PredicateObligation<'tcx> {
let obligation = infcx.resolve_vars_if_possible(obligation.clone()); let obligation = infcx.resolve_vars_if_possible(obligation.clone());
infcx infcx
.visit_proof_tree( .visit_proof_tree(
obligation.clone().into(), obligation.clone().into(),
&mut BestObligation { obligation: obligation.clone() }, &mut BestObligation { obligation: obligation.clone(), consider_ambiguities },
) )
.break_value() .break_value()
.unwrap_or(obligation) .unwrap_or(obligation)
@ -288,6 +289,7 @@ fn find_best_leaf_obligation<'tcx>(
struct BestObligation<'tcx> { struct BestObligation<'tcx> {
obligation: PredicateObligation<'tcx>, obligation: PredicateObligation<'tcx>,
consider_ambiguities: bool,
} }
impl<'tcx> BestObligation<'tcx> { impl<'tcx> BestObligation<'tcx> {
@ -355,11 +357,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} }
} }
// Skip nested goals that hold. // Skip nested goals that aren't the *reason* for our goal's failure.
//FIXME: We should change the max allowed certainty based on if we're match self.consider_ambiguities {
// visiting an ambiguity or error obligation. true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {}
if matches!(nested_goal.result(), Ok(Certainty::Yes)) { false if matches!(nested_goal.result(), Err(_)) => {}
continue; _ => continue,
} }
self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;

View file

@ -61,7 +61,7 @@ where
// entering the cycle from `A` fails, but would work if we were to use the cache // entering the cycle from `A` fails, but would work if we were to use the cache
// result of `B<X>`. // result of `B<X>`.
impls_trait::<A<X>, _, _, _>(); impls_trait::<A<X>, _, _, _>();
//~^ ERROR the trait bound `X: IncompleteGuidance<_, _>` is not satisfied //~^ ERROR the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
} }
fn main() { fn main() {

View file

@ -1,26 +1,28 @@
error[E0277]: the trait bound `X: IncompleteGuidance<_, _>` is not satisfied error[E0277]: the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
--> $DIR/incompleteness-unstable-result.rs:63:19 --> $DIR/incompleteness-unstable-result.rs:63:19
| |
LL | impls_trait::<A<X>, _, _, _>(); LL | impls_trait::<A<X>, _, _, _>();
| ^^^^ the trait `IncompleteGuidance<_, _>` is not implemented for `X`, which is required by `A<X>: Trait<_, _, _>` | ^^^^ the trait `Trait<i32, u8, u8>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
| |
= help: the following other types implement trait `IncompleteGuidance<T, V>`: note: required for `A<X>` to implement `Trait<i32, u8, u8>`
<T as IncompleteGuidance<U, i16>>
<T as IncompleteGuidance<U, i8>>
<T as IncompleteGuidance<U, u8>>
note: required for `A<X>` to implement `Trait<_, _, u8>`
--> $DIR/incompleteness-unstable-result.rs:32:50 --> $DIR/incompleteness-unstable-result.rs:32:50
| |
LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T> LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
| ^^^^^^^^^^^^^^ ^^^^ | ^^^^^^^^^^^^^^ ^^^^
LL | where ...
LL | T: IncompleteGuidance<U, V>, LL | A<T>: Trait<U, D, V>,
| ------------------------ unsatisfied trait bound introduced here | -------------- unsatisfied trait bound introduced here
= note: 8 redundant requirements hidden
= note: required for `A<X>` to implement `Trait<i32, u8, u8>`
note: required by a bound in `impls_trait` note: required by a bound in `impls_trait`
--> $DIR/incompleteness-unstable-result.rs:51:28 --> $DIR/incompleteness-unstable-result.rs:51:28
| |
LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {} LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
| ^^^^^^^^^^^^^^ required by this bound in `impls_trait` | ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
LL | X: IncompleteGuidance<u32, i16>, A<X>: Trait<i32, u8, u8>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error error: aborting due to 1 previous error