Skip to content

Commit f6faaee

Browse files
Report higher-ranked trait error when higher-ranked projection goal fails in new solver
1 parent f06e5c1 commit f6faaee

7 files changed

+122
-38
lines changed

Diff for: compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,34 @@ impl<'tcx> BestObligation<'tcx> {
291291
}
292292
}
293293

294+
/// When a higher-ranked projection goal fails, check that the corresponding
295+
/// higher-ranked trait goal holds or not. This is because the process of
296+
/// instantiating and then re-canonicalizing the binder of the projection goal
297+
/// forces us to be unable to see that the leak check failed in the nested
298+
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
299+
/// that should catch when a projection goal fails due to an unsatisfied trait
300+
/// goal.
301+
fn detect_error_in_higher_ranked_projection(
302+
&mut self,
303+
goal: &inspect::InspectGoal<'_, 'tcx>,
304+
) -> ControlFlow<PredicateObligation<'tcx>> {
305+
let tcx = goal.infcx().tcx;
306+
if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
307+
&& !projection_clause.bound_vars().is_empty()
308+
{
309+
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
310+
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
311+
goal.infcx().visit_proof_tree_at_depth(
312+
goal.goal().with(tcx, pred),
313+
goal.depth() + 1,
314+
this,
315+
)
316+
})
317+
} else {
318+
ControlFlow::Continue(())
319+
}
320+
}
321+
294322
/// It is likely that `NormalizesTo` failed without any applicable candidates
295323
/// because the alias is not well-formed.
296324
///
@@ -374,7 +402,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
374402
source: CandidateSource::Impl(impl_def_id),
375403
result: _,
376404
} = candidate.kind()
377-
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
405+
&& tcx.do_not_recommend_impl(impl_def_id)
378406
{
379407
trace!("#[do_not_recommend] -> exit");
380408
return ControlFlow::Break(self.obligation.clone());
@@ -486,7 +514,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
486514
if let Some(obligation) = goal
487515
.infcx()
488516
.visit_proof_tree_at_depth(
489-
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())),
517+
goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
490518
goal.depth() + 1,
491519
self,
492520
)
@@ -496,7 +524,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
496524
} else if let Some(obligation) = goal
497525
.infcx()
498526
.visit_proof_tree_at_depth(
499-
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())),
527+
goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
500528
goal.depth() + 1,
501529
self,
502530
)
@@ -506,6 +534,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
506534
}
507535
}
508536

537+
self.detect_error_in_higher_ranked_projection(goal)?;
538+
509539
ControlFlow::Break(self.obligation.clone())
510540
}
511541
}

Diff for: tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
1313
| ^^^^^^^^^^^^^
1414

1515
error[E0308]: mismatched types
16-
--> $DIR/candidate-from-env-universe-err-project.rs:53:30
16+
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
1717
|
1818
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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) = |_| ();
2222
found associated type `<T as Trait<'a>>::Assoc`
2323

2424
error[E0308]: mismatched types
25-
--> $DIR/candidate-from-env-universe-err-project.rs:53:30
25+
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
2626
|
2727
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
2828
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other

Diff for: tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr

+4-22
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,20 @@ note: required by a bound in `projection_bound`
2222
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
2424

25-
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
26-
--> $DIR/candidate-from-env-universe-err-project.rs:38:24
27-
|
28-
LL | projection_bound::<T>();
29-
| ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
30-
|
31-
note: types differ
32-
--> $DIR/candidate-from-env-universe-err-project.rs:14:18
33-
|
34-
LL | type Assoc = usize;
35-
| ^^^^^
36-
note: required by a bound in `projection_bound`
37-
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
38-
|
39-
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
40-
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
41-
4225
error: higher-ranked subtype error
43-
--> $DIR/candidate-from-env-universe-err-project.rs:53:30
26+
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
4427
|
4528
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
4629
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4730

4831
error: higher-ranked subtype error
49-
--> $DIR/candidate-from-env-universe-err-project.rs:53:30
32+
--> $DIR/candidate-from-env-universe-err-project.rs:52:30
5033
|
5134
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
5235
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5336
|
5437
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
5538

56-
error: aborting due to 5 previous errors
39+
error: aborting due to 4 previous errors
5740

58-
Some errors have detailed explanations: E0271, E0277.
59-
For more information about an error, try `rustc --explain E0271`.
41+
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs

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

4443
fn function3<T: Trait<'static, Assoc = usize>>() {

Diff for: tests/ui/mismatched_types/closure-mismatch.stderr renamed to tests/ui/mismatched_types/closure-mismatch.current.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: implementation of `FnOnce` is not general enough
2-
--> $DIR/closure-mismatch.rs:8:5
2+
--> $DIR/closure-mismatch.rs:12:5
33
|
44
LL | baz(|_| ());
55
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@@ -8,7 +8,7 @@ LL | baz(|_| ());
88
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
99

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

1919
error: implementation of `FnOnce` is not general enough
20-
--> $DIR/closure-mismatch.rs:11:5
20+
--> $DIR/closure-mismatch.rs:16:5
2121
|
2222
LL | baz(|x| ());
2323
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@@ -26,7 +26,7 @@ LL | baz(|x| ());
2626
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
2727

2828
error: implementation of `Fn` is not general enough
29-
--> $DIR/closure-mismatch.rs:11:5
29+
--> $DIR/closure-mismatch.rs:16:5
3030
|
3131
LL | baz(|x| ());
3232
| ^^^^^^^^^^^ implementation of `Fn` is not general enough
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}: Foo` is not satisfied
2+
--> $DIR/closure-mismatch.rs:12:9
3+
|
4+
LL | baz(|_| ());
5+
| --- ^^^^^^ unsatisfied trait bound
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}`
10+
= note: expected a closure with signature `for<'a> fn(&'a ())`
11+
found a closure with signature `fn(&())`
12+
note: this is a known limitation of the trait solver that will be lifted in the future
13+
--> $DIR/closure-mismatch.rs:12:9
14+
|
15+
LL | baz(|_| ());
16+
| ----^^^----
17+
| | |
18+
| | the trait solver is unable to infer the generic types that should be inferred from this argument
19+
| add turbofish arguments to this call to specify the types manually, even if it's redundant
20+
note: required for `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` to implement `Foo`
21+
--> $DIR/closure-mismatch.rs:7:18
22+
|
23+
LL | impl<T: Fn(&())> Foo for T {}
24+
| ------- ^^^ ^
25+
| |
26+
| unsatisfied trait bound introduced here
27+
note: required by a bound in `baz`
28+
--> $DIR/closure-mismatch.rs:9:11
29+
|
30+
LL | fn baz<T: Foo>(_: T) {}
31+
| ^^^ required by this bound in `baz`
32+
33+
error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}: Foo` is not satisfied
34+
--> $DIR/closure-mismatch.rs:16:9
35+
|
36+
LL | baz(|x| ());
37+
| --- ^^^^^^ unsatisfied trait bound
38+
| |
39+
| required by a bound introduced by this call
40+
|
41+
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}`
42+
= note: expected a closure with signature `for<'a> fn(&'a ())`
43+
found a closure with signature `fn(&())`
44+
note: this is a known limitation of the trait solver that will be lifted in the future
45+
--> $DIR/closure-mismatch.rs:16:9
46+
|
47+
LL | baz(|x| ());
48+
| ----^^^----
49+
| | |
50+
| | the trait solver is unable to infer the generic types that should be inferred from this argument
51+
| add turbofish arguments to this call to specify the types manually, even if it's redundant
52+
note: required for `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` to implement `Foo`
53+
--> $DIR/closure-mismatch.rs:7:18
54+
|
55+
LL | impl<T: Fn(&())> Foo for T {}
56+
| ------- ^^^ ^
57+
| |
58+
| unsatisfied trait bound introduced here
59+
note: required by a bound in `baz`
60+
--> $DIR/closure-mismatch.rs:9:11
61+
|
62+
LL | fn baz<T: Foo>(_: T) {}
63+
| ^^^ required by this bound in `baz`
64+
65+
error: aborting due to 2 previous errors
66+
67+
For more information about this error, try `rustc --explain E0277`.

Diff for: tests/ui/mismatched_types/closure-mismatch.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
15
trait Foo {}
26

37
impl<T: Fn(&())> Foo for T {}
@@ -6,9 +10,11 @@ fn baz<T: Foo>(_: T) {}
610

711
fn main() {
812
baz(|_| ());
9-
//~^ ERROR implementation of `FnOnce` is not general enough
10-
//~| ERROR implementation of `Fn` is not general enough
13+
//[current]~^ ERROR implementation of `FnOnce` is not general enough
14+
//[current]~| ERROR implementation of `Fn` is not general enough
15+
//[next]~^^^ ERROR Foo` is not satisfied
1116
baz(|x| ());
12-
//~^ ERROR implementation of `FnOnce` is not general enough
13-
//~| ERROR implementation of `Fn` is not general enough
17+
//[current]~^ ERROR implementation of `FnOnce` is not general enough
18+
//[current]~| ERROR implementation of `Fn` is not general enough
19+
//[next]~^^^ ERROR Foo` is not satisfied
1420
}

0 commit comments

Comments
 (0)