Rollup merge of #124690 - compiler-errors:only-ambig-if-ambig, r=lcnr
Only consider ambiguous goals when finding best obligation for ambiguities We don't care about ambiguous goals when reporting true errors, and vice versa for ambiguities. r? lcnr
This commit is contained in:
commit
7fbfd8d770
3 changed files with 24 additions and 20 deletions
|
@ -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))?;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue