Report higher-ranked trait error when higher-ranked projection goal fails in new solver
This commit is contained in:
parent
f06e5c1e35
commit
f6faaee372
7 changed files with 122 additions and 38 deletions
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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`.
|
|
||||||
|
|
|
@ -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>>() {
|
||||||
|
|
|
@ -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
|
67
tests/ui/mismatched_types/closure-mismatch.next.stderr
Normal file
67
tests/ui/mismatched_types/closure-mismatch.next.stderr
Normal 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`.
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue