Skip to content

Commit 6794b19

Browse files
Report higher-ranked trait error when higher-ranked projection goal fails in new solver
1 parent c6c1796 commit 6794b19

7 files changed

+111
-38
lines changed

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
374374
source: CandidateSource::Impl(impl_def_id),
375375
result: _,
376376
} = candidate.kind()
377-
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
377+
&& tcx.do_not_recommend_impl(impl_def_id)
378378
{
379379
trace!("#[do_not_recommend] -> exit");
380380
return ControlFlow::Break(self.obligation.clone());
@@ -486,7 +486,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
486486
if let Some(obligation) = goal
487487
.infcx()
488488
.visit_proof_tree_at_depth(
489-
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())),
489+
goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
490490
goal.depth() + 1,
491491
self,
492492
)
@@ -496,7 +496,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
496496
} else if let Some(obligation) = goal
497497
.infcx()
498498
.visit_proof_tree_at_depth(
499-
goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())),
499+
goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
500500
goal.depth() + 1,
501501
self,
502502
)
@@ -506,6 +506,25 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
506506
}
507507
}
508508

509+
// HACK: When a higher-ranked projection goal fails, check that the corresponding
510+
// higher-ranked trait goal holds or not. This is because the process of instantiating
511+
// and then re-canonicalizing the binder of the projection goal forces us to be unable
512+
// to see that the leak check failed in the nested `NormalizesTo` goal, so we don't
513+
// fall back to the regular machinery that should catch when a projection goal fails
514+
// due to an unsatisfied trait goal.
515+
if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
516+
&& !projection_clause.bound_vars().is_empty()
517+
{
518+
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
519+
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
520+
goal.infcx().visit_proof_tree_at_depth(
521+
goal.goal().with(tcx, pred),
522+
goal.depth() + 1,
523+
this,
524+
)
525+
})?;
526+
}
527+
509528
ControlFlow::Break(self.obligation.clone())
510529
}
511530
}

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

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`.

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>>() {

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
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 arguments `(&(),)`
11+
found a closure with arguments `(&(),)`
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 arguments `(&(),)`
43+
found a closure with arguments `(&(),)`
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`.
+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)