Report higher-ranked trait error when higher-ranked projection goal fails in new solver

This commit is contained in:
Michael Goulet 2025-04-08 05:18:17 +00:00
parent f06e5c1e35
commit f6faaee372
7 changed files with 122 additions and 38 deletions

View file

@ -291,6 +291,34 @@ impl<'tcx> BestObligation<'tcx> {
} }
} }
/// When a higher-ranked projection goal fails, check that the corresponding
/// higher-ranked trait goal holds or not. This is because the process of
/// instantiating and then re-canonicalizing the binder of the projection goal
/// forces us to be unable to see that the leak check failed in the nested
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
/// that should catch when a projection goal fails due to an unsatisfied trait
/// goal.
fn detect_error_in_higher_ranked_projection(
&mut self,
goal: &inspect::InspectGoal<'_, 'tcx>,
) -> ControlFlow<PredicateObligation<'tcx>> {
let tcx = goal.infcx().tcx;
if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
&& !projection_clause.bound_vars().is_empty()
{
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
goal.infcx().visit_proof_tree_at_depth(
goal.goal().with(tcx, pred),
goal.depth() + 1,
this,
)
})
} else {
ControlFlow::Continue(())
}
}
/// It is likely that `NormalizesTo` failed without any applicable candidates /// It is likely that `NormalizesTo` failed without any applicable candidates
/// because the alias is not well-formed. /// because the alias is not well-formed.
/// ///
@ -374,7 +402,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
source: CandidateSource::Impl(impl_def_id), source: CandidateSource::Impl(impl_def_id),
result: _, result: _,
} = candidate.kind() } = candidate.kind()
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id) && tcx.do_not_recommend_impl(impl_def_id)
{ {
trace!("#[do_not_recommend] -> exit"); trace!("#[do_not_recommend] -> exit");
return ControlFlow::Break(self.obligation.clone()); return ControlFlow::Break(self.obligation.clone());
@ -486,7 +514,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
if let Some(obligation) = goal if let Some(obligation) = goal
.infcx() .infcx()
.visit_proof_tree_at_depth( .visit_proof_tree_at_depth(
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
goal.depth() + 1, goal.depth() + 1,
self, self,
) )
@ -496,7 +524,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} else if let Some(obligation) = goal } else if let Some(obligation) = goal
.infcx() .infcx()
.visit_proof_tree_at_depth( .visit_proof_tree_at_depth(
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
goal.depth() + 1, goal.depth() + 1,
self, self,
) )
@ -506,6 +534,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} }
} }
self.detect_error_in_higher_ranked_projection(goal)?;
ControlFlow::Break(self.obligation.clone()) ControlFlow::Break(self.obligation.clone())
} }
} }

View file

@ -13,7 +13,7 @@ LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@ -22,7 +22,7 @@ LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
found associated type `<T as Trait<'a>>::Assoc` found associated type `<T as Trait<'a>>::Assoc`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other

View file

@ -22,38 +22,20 @@ note: required by a bound in `projection_bound`
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {} LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
--> $DIR/candidate-from-env-universe-err-project.rs:38:24
|
LL | projection_bound::<T>();
| ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
|
note: types differ
--> $DIR/candidate-from-env-universe-err-project.rs:14:18
|
LL | type Assoc = usize;
| ^^^^^
note: required by a bound in `projection_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
error: higher-ranked subtype error error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error error: higher-ranked subtype error
--> $DIR/candidate-from-env-universe-err-project.rs:53:30 --> $DIR/candidate-from-env-universe-err-project.rs:52:30
| |
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 5 previous errors error: aborting due to 4 previous errors
Some errors have detailed explanations: E0271, E0277. For more information about this error, try `rustc --explain E0277`.
For more information about an error, try `rustc --explain E0271`.

View file

@ -36,9 +36,8 @@ fn function2<T: Trait<'static, Assoc = usize>>() {
// does not use the leak check when trying the where-bound, causing us // does not use the leak check when trying the where-bound, causing us
// to prefer it over the impl, resulting in a placeholder error. // to prefer it over the impl, resulting in a placeholder error.
projection_bound::<T>(); projection_bound::<T>();
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize` //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
//[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied //[current]~^^ ERROR mismatched types
//[current]~^^^ ERROR mismatched types
} }
fn function3<T: Trait<'static, Assoc = usize>>() { fn function3<T: Trait<'static, Assoc = usize>>() {

View file

@ -1,5 +1,5 @@
error: implementation of `FnOnce` is not general enough error: implementation of `FnOnce` is not general enough
--> $DIR/closure-mismatch.rs:8:5 --> $DIR/closure-mismatch.rs:12:5
| |
LL | baz(|_| ()); LL | baz(|_| ());
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@ -8,7 +8,7 @@ LL | baz(|_| ());
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `Fn` is not general enough error: implementation of `Fn` is not general enough
--> $DIR/closure-mismatch.rs:8:5 --> $DIR/closure-mismatch.rs:12:5
| |
LL | baz(|_| ()); LL | baz(|_| ());
| ^^^^^^^^^^^ implementation of `Fn` is not general enough | ^^^^^^^^^^^ implementation of `Fn` is not general enough
@ -17,7 +17,7 @@ LL | baz(|_| ());
= note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough error: implementation of `FnOnce` is not general enough
--> $DIR/closure-mismatch.rs:11:5 --> $DIR/closure-mismatch.rs:16:5
| |
LL | baz(|x| ()); LL | baz(|x| ());
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough | ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@ -26,7 +26,7 @@ LL | baz(|x| ());
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2` = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
error: implementation of `Fn` is not general enough error: implementation of `Fn` is not general enough
--> $DIR/closure-mismatch.rs:11:5 --> $DIR/closure-mismatch.rs:16:5
| |
LL | baz(|x| ()); LL | baz(|x| ());
| ^^^^^^^^^^^ implementation of `Fn` is not general enough | ^^^^^^^^^^^ implementation of `Fn` is not general enough

View file

@ -0,0 +1,67 @@
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}: Foo` is not satisfied
--> $DIR/closure-mismatch.rs:12:9
|
LL | baz(|_| ());
| --- ^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}`
= note: expected a closure with signature `for<'a> fn(&'a ())`
found a closure with signature `fn(&())`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/closure-mismatch.rs:12:9
|
LL | baz(|_| ());
| ----^^^----
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required for `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` to implement `Foo`
--> $DIR/closure-mismatch.rs:7:18
|
LL | impl<T: Fn(&())> Foo for T {}
| ------- ^^^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `baz`
--> $DIR/closure-mismatch.rs:9:11
|
LL | fn baz<T: Foo>(_: T) {}
| ^^^ required by this bound in `baz`
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}: Foo` is not satisfied
--> $DIR/closure-mismatch.rs:16:9
|
LL | baz(|x| ());
| --- ^^^^^^ unsatisfied trait bound
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}`
= note: expected a closure with signature `for<'a> fn(&'a ())`
found a closure with signature `fn(&())`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/closure-mismatch.rs:16:9
|
LL | baz(|x| ());
| ----^^^----
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required for `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` to implement `Foo`
--> $DIR/closure-mismatch.rs:7:18
|
LL | impl<T: Fn(&())> Foo for T {}
| ------- ^^^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `baz`
--> $DIR/closure-mismatch.rs:9:11
|
LL | fn baz<T: Foo>(_: T) {}
| ^^^ required by this bound in `baz`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,3 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
trait Foo {} trait Foo {}
impl<T: Fn(&())> Foo for T {} impl<T: Fn(&())> Foo for T {}
@ -6,9 +10,11 @@ fn baz<T: Foo>(_: T) {}
fn main() { fn main() {
baz(|_| ()); baz(|_| ());
//~^ ERROR implementation of `FnOnce` is not general enough //[current]~^ ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `Fn` is not general enough //[current]~| ERROR implementation of `Fn` is not general enough
//[next]~^^^ ERROR Foo` is not satisfied
baz(|x| ()); baz(|x| ());
//~^ ERROR implementation of `FnOnce` is not general enough //[current]~^ ERROR implementation of `FnOnce` is not general enough
//~| ERROR implementation of `Fn` is not general enough //[current]~| ERROR implementation of `Fn` is not general enough
//[next]~^^^ ERROR Foo` is not satisfied
} }