Skip to content

Commit bfdd538

Browse files
committed
Canonicalize free regions from inputs as placeholders in root univ
1 parent 0febdba commit bfdd538

33 files changed

Lines changed: 191 additions & 179 deletions

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
229229
| ty::ReErased
230230
| ty::ReStatic
231231
| ty::ReError(_) => r,
232-
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
232+
ty::ReVar(_) => canonicalizer
233+
.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r),
233234
ty::RePlaceholder(..) | ty::ReBound(..) => {
234235
// We only expect region names that the user can type.
235236
bug!("unexpected region in query response: `{:?}`", r)
@@ -707,23 +708,26 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
707708
}
708709

709710
/// Shorthand helper that creates a canonical region variable for
710-
/// `r` (always in the root universe). The reason that we always
711-
/// put these variables into the root universe is because this
712-
/// method is used during **query construction:** in that case, we
713-
/// are taking all the regions and just putting them into the most
714-
/// generic context we can. This may generate solutions that don't
715-
/// fit (e.g., that equate some region variable with a placeholder
716-
/// it can't name) on the caller side, but that's ok, the caller
717-
/// can figure that out. In the meantime, it maximizes our
711+
/// `r` (always as a placeholder in the root universe). The reason
712+
/// that we always put these variables into the root universe as a
713+
/// placeholder is because this method is used during
714+
/// **query construction:** in that case, we are taking all the
715+
/// free regions and just putting them into the most generic context
716+
/// we can. This makes any region constraints between them, including
717+
/// region equalities, to be preserved and propagated to the caller
718+
/// instead of unifying them. In the meantime, it maximizes our
718719
/// caching.
719-
///
720-
/// (This works because unification never fails -- and hence trait
721-
/// selection is never affected -- due to a universe mismatch.)
722720
fn canonical_var_for_region_in_root_universe(
723721
&mut self,
724722
r: ty::Region<'tcx>,
725723
) -> ty::Region<'tcx> {
726-
self.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r)
724+
self.canonical_var_for_region(
725+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
726+
ty::UniverseIndex::ROOT,
727+
self.var_kinds.len().into(),
728+
)),
729+
r,
730+
)
727731
}
728732

729733
/// Creates a canonical variable (with the given `info`)

compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,10 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
417417
// when checking whether a `ParamEnv` candidate is global.
418418
ty::ReStatic => match self.canonicalize_mode {
419419
CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => {
420-
CanonicalVarKind::Region(ty::UniverseIndex::ROOT)
420+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
421+
ty::UniverseIndex::ROOT,
422+
self.variables.len().into(),
423+
))
421424
}
422425
CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv)
423426
| CanonicalizeMode::Response { .. } => return r,
@@ -431,24 +434,42 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
431434
// `ReErased`. We may be able to short-circuit registering region
432435
// obligations if we encounter a `ReErased` on one side, for example.
433436
ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
434-
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
437+
CanonicalizeMode::Input(_) => {
438+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
439+
ty::UniverseIndex::ROOT,
440+
self.variables.len().into(),
441+
))
442+
}
435443
CanonicalizeMode::Response { .. } => return r,
436444
},
437445

438446
ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
439-
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
447+
CanonicalizeMode::Input(_) => {
448+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
449+
ty::UniverseIndex::ROOT,
450+
self.variables.len().into(),
451+
))
452+
}
440453
CanonicalizeMode::Response { .. } => {
441454
panic!("unexpected region in response: {r:?}")
442455
}
443456
},
444457

445458
ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
446-
// We canonicalize placeholder regions as existentials in query inputs.
447-
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
459+
CanonicalizeMode::Input(_) => {
460+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
461+
ty::UniverseIndex::ROOT,
462+
self.variables.len().into(),
463+
))
464+
}
448465
CanonicalizeMode::Response { max_input_universe } => {
449466
// If we have a placeholder region inside of a query, it must be from
450-
// a new universe.
451-
if max_input_universe.can_name(placeholder.universe()) {
467+
// a new universe, unless it's anon from the root universe, which is
468+
// used for canonicalization of any free region from the input.
469+
if !(placeholder.universe() == ty::UniverseIndex::ROOT
470+
&& placeholder.bound.kind == ty::BoundRegionKind::Anon)
471+
&& max_input_universe.can_name(placeholder.universe())
472+
{
452473
panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
453474
}
454475
CanonicalVarKind::PlaceholderRegion(placeholder)
@@ -462,7 +483,12 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
462483
"region vid should have been resolved fully before canonicalization"
463484
);
464485
match self.canonicalize_mode {
465-
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
486+
CanonicalizeMode::Input(_) => {
487+
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
488+
ty::UniverseIndex::ROOT,
489+
self.variables.len().into(),
490+
))
491+
}
466492
CanonicalizeMode::Response { .. } => {
467493
CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap())
468494
}
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
error: implementation of `Foo` is not general enough
1+
error[E0308]: mismatched types
22
--> $DIR/higher-ranked-auto-trait-10.rs:32:5
33
|
44
LL | Box::new(async move { get_foo(x).await })
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
66
|
7-
= note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
8-
= note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
7+
= note: expected enum `Result<&_, _>`
8+
found enum `Result<&_, _>`
99

10-
error: implementation of `Foo` is not general enough
10+
error: implementation of `Send` is not general enough
1111
--> $DIR/higher-ranked-auto-trait-10.rs:32:5
1212
|
1313
LL | Box::new(async move { get_foo(x).await })
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
1515
|
16-
= note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
17-
= note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
18-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
16+
= note: `Send` would have to be implemented for the type `&str`
17+
= note: ...but `Send` is actually implemented for the type `&'0 str`, for some specific lifetime `'0`
1918

2019
error: aborting due to 2 previous errors
2120

21+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
error: implementation of `Foo` is not general enough
1+
error[E0308]: mismatched types
22
--> $DIR/higher-ranked-auto-trait-10.rs:32:5
33
|
44
LL | Box::new(async move { get_foo(x).await })
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
66
|
7-
= note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
8-
= note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
7+
= note: expected enum `Result<&_, _>`
8+
found enum `Result<&_, _>`
99

10-
error: implementation of `Foo` is not general enough
10+
error: implementation of `Send` is not general enough
1111
--> $DIR/higher-ranked-auto-trait-10.rs:32:5
1212
|
1313
LL | Box::new(async move { get_foo(x).await })
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
1515
|
16-
= note: `Foo<'1>` would have to be implemented for the type `&'0 str`, for any two lifetimes `'0` and `'1`...
17-
= note: ...but `Foo<'2>` is actually implemented for the type `&'2 str`, for some specific lifetime `'2`
18-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
16+
= note: `Send` would have to be implemented for the type `&str`
17+
= note: ...but `Send` is actually implemented for the type `&'0 str`, for some specific lifetime `'0`
1918

2019
error: aborting due to 2 previous errors
2120

21+
For more information about this error, try `rustc --explain E0308`.

tests/ui/async-await/higher-ranked-auto-trait-11.assumptions.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ error: implementation of `Send` is not general enough
1313
LL | Box::pin(async move { <T as Foo<'a>>::foo().await })
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
1515
|
16-
= note: `Send` would have to be implemented for the type `<T as Foo<'0>>::Future`, for any lifetime `'0`...
17-
= note: ...but `Send` is actually implemented for the type `<T as Foo<'1>>::Future`, for some specific lifetime `'1`
16+
= note: `<T as Foo<'0>>::Future` must implement `Send`, for any lifetime `'0`...
17+
= note: ...but `Send` is actually implemented for the type `<T as Foo<'_>>::Future`
1818

1919
error: aborting due to 2 previous errors
2020

tests/ui/async-await/higher-ranked-auto-trait-11.no_assumptions.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ error: implementation of `Send` is not general enough
1313
LL | Box::pin(async move { <T as Foo<'a>>::foo().await })
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
1515
|
16-
= note: `Send` would have to be implemented for the type `<T as Foo<'0>>::Future`, for any lifetime `'0`...
17-
= note: ...but `Send` is actually implemented for the type `<T as Foo<'1>>::Future`, for some specific lifetime `'1`
16+
= note: `<T as Foo<'0>>::Future` must implement `Send`, for any lifetime `'0`...
17+
= note: ...but `Send` is actually implemented for the type `<T as Foo<'_>>::Future`
1818

1919
error: aborting due to 2 previous errors
2020

tests/ui/async-await/higher-ranked-auto-trait-13.no_assumptions.stderr

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ LL | assert_send(my_send_async_method(struct_with_lifetime, data));
1717
= note: ...but `Getter<'2>` is actually implemented for the type `GetterImpl<'2, ConstructableImpl<'_>>`, for some specific lifetime `'2`
1818
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1919

20-
error: implementation of `Callable` is not general enough
20+
error: implementation of `Send` is not general enough
2121
--> $DIR/higher-ranked-auto-trait-13.rs:65:5
2222
|
2323
LL | assert_send(my_send_async_method(struct_with_lifetime, data));
24-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Callable` is not general enough
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Send` is not general enough
2525
|
26-
= note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`...
27-
= note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1`
26+
= note: `Send` would have to be implemented for the type `&Vec<u8>`
27+
= note: ...but `Send` is actually implemented for the type `&'0 Vec<u8>`, for some specific lifetime `'0`
2828

2929
error: implementation of `Getter` is not general enough
3030
--> $DIR/higher-ranked-auto-trait-13.rs:65:5
@@ -54,7 +54,6 @@ LL | assert_send(my_send_async_method(struct_with_lifetime, data));
5454
|
5555
= note: `Callable<'_>` would have to be implemented for the type `ConstructableImpl<'0>`, for any lifetime `'0`...
5656
= note: ...but `Callable<'1>` is actually implemented for the type `ConstructableImpl<'1>`, for some specific lifetime `'1`
57-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
5857

5958
error: aborting due to 6 previous errors
6059

tests/ui/async-await/higher-ranked-auto-trait-5.no_assumptions.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ LL | | call_me.call().await;
66
LL | | });
77
| |______^ implementation of `Send` is not general enough
88
|
9-
= note: `Send` would have to be implemented for the type `&'0 str`, for any lifetime `'0`...
10-
= note: ...but `Send` is actually implemented for the type `&'1 str`, for some specific lifetime `'1`
9+
= note: `Send` would have to be implemented for the type `&Wrap<CallMeImpl<&str>>`
10+
= note: ...but `Send` is actually implemented for the type `&'0 Wrap<CallMeImpl<&str>>`, for some specific lifetime `'0`
1111

1212
error: aborting due to 1 previous error
1313

tests/ui/borrowck/closure-upvar-named-lifetime.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ LL | f(value);
7373
| -------- argument requires that `map` is borrowed for `'a`
7474
LL | }
7575
| - `map` dropped here while still borrowed
76+
|
77+
note: requirement that the value outlives `'a` introduced here
78+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
7679

7780
error[E0716]: temporary value dropped while borrowed
7881
--> $DIR/closure-upvar-named-lifetime.rs:34:21
@@ -87,6 +90,9 @@ LL | let value = map.borrow_mut().entry("foo".to_string());
8790
...
8891
LL | f(value);
8992
| -------- argument requires that borrow lasts for `'a`
93+
|
94+
note: requirement that the value outlives `'a` introduced here
95+
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
9096

9197
error[E0700]: hidden type for `impl Fn(RefCell<HashMap<String, String>>)` captures lifetime that does not appear in bounds
9298
--> $DIR/closure-upvar-named-lifetime.rs:32:5

tests/ui/coroutine/resume-arg-late-bound.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error: implementation of `Coroutine` is not general enough
44
LL | test(gen);
55
| ^^^^^^^^^ implementation of `Coroutine` is not general enough
66
|
7-
= note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:28: 11:44}` must implement `Coroutine<&'1 mut bool>`, for any lifetime `'1`...
8-
= note: ...but it actually implements `Coroutine<&'2 mut bool>`, for some specific lifetime `'2`
7+
= note: `{coroutine@$DIR/resume-arg-late-bound.rs:11:28: 11:44}` must implement `Coroutine<&'1 mut bool>`, for any two lifetimes `'0` and `'1`...
8+
= note: ...but it actually implements `Coroutine<&mut bool>`
99

1010
error: aborting due to 1 previous error
1111

0 commit comments

Comments
 (0)