Skip to content

Commit 3c659f3

Browse files
committed
move leak check out of candidate evaluation
this prevents higher ranked goals from guiding selection
1 parent bf3c6c5 commit 3c659f3

18 files changed

+402
-186
lines changed

compiler/rustc_trait_selection/src/traits/select/mod.rs

+30-9
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
580580
obligation: &PredicateObligation<'tcx>,
581581
) -> Result<EvaluationResult, OverflowError> {
582582
debug_assert!(!self.infcx.next_trait_solver());
583-
self.evaluation_probe(|this| {
583+
self.evaluation_probe(|this, _outer_universe| {
584584
let goal =
585585
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
586586
let mut result = this.evaluate_predicate_recursively(
@@ -596,13 +596,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
596596
})
597597
}
598598

599+
/// Computes the evaluation result of `op`, discarding any constraints.
600+
///
601+
/// This also runs for leak check to allow higher ranked region errors to impact
602+
/// selection. By default it checks for leaks from all universes created inside of
603+
/// `op`, but this can be overwritten if necessary.
599604
fn evaluation_probe(
600605
&mut self,
601-
op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
606+
op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
602607
) -> Result<EvaluationResult, OverflowError> {
603608
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
604-
let outer_universe = self.infcx.universe();
605-
let result = op(self)?;
609+
let mut outer_universe = self.infcx.universe();
610+
let result = op(self, &mut outer_universe)?;
606611

607612
match self.infcx.leak_check(outer_universe, Some(snapshot)) {
608613
Ok(()) => {}
@@ -1265,9 +1270,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12651270
stack: &TraitObligationStack<'o, 'tcx>,
12661271
candidate: &SelectionCandidate<'tcx>,
12671272
) -> Result<EvaluationResult, OverflowError> {
1268-
let mut result = self.evaluation_probe(|this| {
1269-
let candidate = (*candidate).clone();
1270-
match this.confirm_candidate(stack.obligation, candidate) {
1273+
let mut result = self.evaluation_probe(|this, outer_universe| {
1274+
// We eagerly instantiate higher ranked goals to prevent universe errors
1275+
// from impacting candidate selection. This matches the behavior of the new
1276+
// solver. This slightly weakens type inference.
1277+
//
1278+
// In case there are no unresolved type or const variables this
1279+
// should still not be necessary to select a unique impl as any overlap
1280+
// relying on a universe error from higher ranked goals should have resulted
1281+
// in an overlap error in coherence.
1282+
let p = self.infcx.instantiate_binder_with_placeholders(stack.obligation.predicate);
1283+
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
1284+
*outer_universe = self.infcx.universe();
1285+
match this.confirm_candidate(&obligation, candidate.clone()) {
12711286
Ok(selection) => {
12721287
debug!(?selection);
12731288
this.evaluate_predicates_recursively(
@@ -1704,8 +1719,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
17041719
stack: &TraitObligationStack<'o, 'tcx>,
17051720
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
17061721
) -> Result<EvaluationResult, OverflowError> {
1707-
self.evaluation_probe(|this| {
1708-
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
1722+
self.evaluation_probe(|this, outer_universe| {
1723+
// Eagerly instantiate higher ranked goals.
1724+
//
1725+
// See the comment in `evaluate_candidate` to see why.
1726+
let p = self.infcx.instantiate_binder_with_placeholders(stack.obligation.predicate);
1727+
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
1728+
*outer_universe = self.infcx.universe();
1729+
match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) {
17091730
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
17101731
Err(()) => Ok(EvaluatedToErr),
17111732
}

tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr

-19
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// revisions: classic next
22
//[next] compile-flags: -Znext-solver
3-
//[next] check-pass
3+
// check-pass
44

55
fn ice()
66
where
@@ -10,5 +10,4 @@ where
1010

1111
fn main() {
1212
ice();
13-
//[classic]~^ ERROR expected a `Fn(&'w ())` closure, found `fn(&'w ())`
1413
}

tests/ui/higher-ranked/trait-bounds/future.classic.stderr

-6
This file was deleted.

tests/ui/higher-ranked/trait-bounds/future.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
// ignore-tidy-linelength
21
// edition:2021
32
// revisions: classic next
43
//[next] compile-flags: -Znext-solver
5-
//[next] check-pass
6-
//[classic] known-bug: #112347
7-
//[classic] build-fail
8-
//[classic] failure-status: 101
9-
//[classic] normalize-stderr-test "note: .*\n\n" -> ""
10-
//[classic] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> ""
11-
//[classic] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
12-
//[classic] rustc-env:RUST_BACKTRACE=0
4+
// check-pass
135

146
#![feature(unboxed_closures)]
157

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:20:5
3+
|
4+
LL | impl_trait::<Box<_>>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impl_trait`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
8+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:14:1
9+
|
10+
LL | impl<'a> Leak<'a> for Box<u32> {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl Leak<'static> for Box<u16> {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `impl_trait`
15+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:17:18
16+
|
17+
LL | fn impl_trait<T: for<'a> Leak<'a>>() {}
18+
| ^^^^^^^^^^^^^^^^ required by this bound in `impl_trait`
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:20:5
3+
|
4+
LL | impl_trait::<Box<_>>();
5+
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impl_trait`
6+
|
7+
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
8+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:14:1
9+
|
10+
LL | impl<'a> Leak<'a> for Box<u32> {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl Leak<'static> for Box<u16> {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `impl_trait`
15+
--> $DIR/hr-leak-check-does-not-guide-selection.rs:17:18
16+
|
17+
LL | fn impl_trait<T: for<'a> Leak<'a>>() {}
18+
| ^^^^^^^^^^^^^^^^ required by this bound in `impl_trait`
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// When proving the higher ranked goal `for<'a> Box<_>: Leak<'a>` the
2+
// impl for `Box<u16>` would result in a higher ranked region error.
3+
//
4+
// However, we instantiate higher ranked goals outside of candidate
5+
// selection, so we end up with ambiguity. The old solver previously
6+
// used the leak check to guide selection here.
7+
//
8+
// See trait-system-refactor-initiative#34 for more details here.
9+
10+
// revisions: next old
11+
//[next] compile-flags: -Znext-solver
12+
13+
trait Leak<'a> {}
14+
impl<'a> Leak<'a> for Box<u32> {}
15+
impl Leak<'static> for Box<u16> {}
16+
17+
fn impl_trait<T: for<'a> Leak<'a>>() {}
18+
19+
fn main() {
20+
impl_trait::<Box<_>>();
21+
//~^ ERROR type annotations needed
22+
}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
1-
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
2-
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
1+
error[E0308]: mismatched types
2+
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
33
|
44
LL | want_bar_for_any_ccx(b);
5-
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
6-
| |
7-
| required by a bound introduced by this call
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
86
|
9-
note: required by a bound in `want_bar_for_any_ccx`
7+
= note: expected trait `for<'ccx> Bar<'ccx>`
8+
found trait `Bar<'static>`
9+
note: the lifetime requirement is introduced here
1010
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
1111
|
12-
LL | fn want_bar_for_any_ccx<B>(b: &B)
13-
| -------------------- required by a bound in this function
1412
LL | where B : for<'ccx> Bar<'ccx>
15-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
16-
help: consider further restricting this bound
17-
|
18-
LL | where B : Qux + for<'ccx> Bar<'ccx>
19-
| +++++++++++++++++++++
13+
| ^^^^^^^^^^^^^^^^^^^
2014

2115
error: aborting due to 1 previous error
2216

23-
For more information about this error, try `rustc --explain E0277`.
17+
For more information about this error, try `rustc --explain E0308`.

tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs

+13-19
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,37 @@
11
// Test a trait (`Bar`) with a higher-ranked supertrait.
2+
#![allow(unconditional_recursion)]
23

3-
trait Foo<'tcx>
4-
{
4+
trait Foo<'tcx> {
55
fn foo(&'tcx self) -> &'tcx isize;
66
}
77

8-
trait Bar<'ccx>
9-
: for<'tcx> Foo<'tcx>
10-
{
8+
trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
119
fn bar(&'ccx self) -> &'ccx isize;
1210
}
1311

14-
fn want_foo_for_some_tcx<'x,F>(f: &'x F)
15-
where F : Foo<'x>
16-
{
12+
fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
1713
want_foo_for_some_tcx(f);
18-
want_foo_for_any_tcx(f); //~ ERROR not satisfied
14+
want_foo_for_any_tcx(f);
15+
//~^ ERROR lifetime may not live long enough
16+
//~| ERROR mismatched types
1917
}
2018

21-
fn want_foo_for_any_tcx<F>(f: &F)
22-
where F : for<'tcx> Foo<'tcx>
23-
{
19+
fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
2420
want_foo_for_some_tcx(f);
2521
want_foo_for_any_tcx(f);
2622
}
2723

28-
fn want_bar_for_some_ccx<'x,B>(b: &B)
29-
where B : Bar<'x>
30-
{
24+
fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
3125
want_foo_for_some_tcx(b);
3226
want_foo_for_any_tcx(b);
3327

3428
want_bar_for_some_ccx(b);
35-
want_bar_for_any_ccx(b); //~ ERROR not satisfied
29+
want_bar_for_any_ccx(b);
30+
//~^ ERROR lifetime may not live long enough
31+
//~| ERROR mismatched types
3632
}
3733

38-
fn want_bar_for_any_ccx<B>(b: &B)
39-
where B : for<'ccx> Bar<'ccx>
40-
{
34+
fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
4135
want_foo_for_some_tcx(b);
4236
want_foo_for_any_tcx(b);
4337

Original file line numberDiff line numberDiff line change
@@ -1,43 +1,61 @@
1-
error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
2-
--> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
1+
error: lifetime may not live long enough
2+
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
33
|
4+
LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
5+
| -- lifetime `'x` defined here
6+
LL | want_foo_for_some_tcx(f);
47
LL | want_foo_for_any_tcx(f);
5-
| -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
6-
| |
7-
| required by a bound introduced by this call
8+
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
89
|
9-
note: required by a bound in `want_foo_for_any_tcx`
10-
--> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
10+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
11+
--> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
1112
|
12-
LL | fn want_foo_for_any_tcx<F>(f: &F)
13-
| -------------------- required by a bound in this function
14-
LL | where F : for<'tcx> Foo<'tcx>
15-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
16-
help: consider further restricting this bound
13+
LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
14+
| ^^^^^^^^^^^^^^^^^^^
15+
16+
error[E0308]: mismatched types
17+
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
18+
|
19+
LL | want_foo_for_any_tcx(f);
20+
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
21+
|
22+
= note: expected trait `for<'tcx> Foo<'tcx>`
23+
found trait `Foo<'_>`
24+
note: the lifetime requirement is introduced here
25+
--> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
1726
|
18-
LL | where F : Foo<'x> + for<'tcx> Foo<'tcx>
19-
| +++++++++++++++++++++
27+
LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
28+
| ^^^^^^^^^^^^^^^^^^^
2029

21-
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
22-
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
30+
error: lifetime may not live long enough
31+
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
2332
|
33+
LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
34+
| -- lifetime `'x` defined here
35+
...
2436
LL | want_bar_for_any_ccx(b);
25-
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
26-
| |
27-
| required by a bound introduced by this call
37+
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
2838
|
29-
note: required by a bound in `want_bar_for_any_ccx`
30-
--> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
39+
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
40+
--> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
41+
|
42+
LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
43+
| ^^^^^^^^^^^^^^^^^^^
44+
45+
error[E0308]: mismatched types
46+
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
47+
|
48+
LL | want_bar_for_any_ccx(b);
49+
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
3150
|
32-
LL | fn want_bar_for_any_ccx<B>(b: &B)
33-
| -------------------- required by a bound in this function
34-
LL | where B : for<'ccx> Bar<'ccx>
35-
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
36-
help: consider further restricting this bound
51+
= note: expected trait `for<'ccx> Bar<'ccx>`
52+
found trait `Bar<'_>`
53+
note: the lifetime requirement is introduced here
54+
--> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
3755
|
38-
LL | where B : Bar<'x> + for<'ccx> Bar<'ccx>
39-
| +++++++++++++++++++++
56+
LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
57+
| ^^^^^^^^^^^^^^^^^^^
4058

41-
error: aborting due to 2 previous errors
59+
error: aborting due to 4 previous errors
4260

43-
For more information about this error, try `rustc --explain E0277`.
61+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)