Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,22 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
}

fn fold_region(&mut self, r: I::Region) -> I::Region {
// We canonicalize free regions from the input into placeholder regions so that
// region constraints created in nested contexts can be propagated back to the
// caller, instead of unifying them.
// See the following Zulip discussion for details:
// https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/A.20question.20on.20.23251/near/579240238
let kind = match r.kind() {
ty::ReBound(..) => return r,

// We don't canonicalize `ReStatic` in the `param_env` as we use it
// when checking whether a `ParamEnv` candidate is global.
ty::ReStatic => match self.canonicalize_mode {
CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => {
CanonicalVarKind::Region(ty::UniverseIndex::ROOT)
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
))
}
CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv)
| CanonicalizeMode::Response { .. } => return r,
Expand All @@ -431,24 +439,41 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
// `ReErased`. We may be able to short-circuit registering region
// obligations if we encounter a `ReErased` on one side, for example.
ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Input(_) => {
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
))
}
CanonicalizeMode::Response { .. } => return r,
},

ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode {
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Input(_) => {
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
))
}
CanonicalizeMode::Response { .. } => {
panic!("unexpected region in response: {r:?}")
}
},

ty::RePlaceholder(placeholder) => match self.canonicalize_mode {
// We canonicalize placeholder regions as existentials in query inputs.
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Input(_) => {
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
))
}
CanonicalizeMode::Response { max_input_universe } => {
// If we have a placeholder region inside of a query, it must be from
// a new universe.
if max_input_universe.can_name(placeholder.universe()) {
// a new universe, unless from the root universe, which is used for
// canonicalization of any free region from the input.
if placeholder.universe() != ty::UniverseIndex::ROOT
&& max_input_universe.can_name(placeholder.universe())
{
panic!("new placeholder in universe {max_input_universe:?}: {r:?}");
}
CanonicalVarKind::PlaceholderRegion(placeholder)
Expand All @@ -462,7 +487,12 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
"region vid should have been resolved fully before canonicalization"
);
match self.canonicalize_mode {
CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Input(_) => {
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon(
ty::UniverseIndex::ROOT,
self.variables.len().into(),
))
}
CanonicalizeMode::Response { .. } => {
CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap())
}
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_next_trait_solver/src/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,18 @@ where
} else {
// For placeholders which were already part of the input, we simply map this
// universal bound variable back the placeholder of the input.
//
// For `CanonicalVarKind::PlaceholderRegion`, this differs slightly: we
// canonicalize all free regions from the input into placeholders. This is
// unlike types or consts, where only input placeholders remain placeholders
// in the canonical form.
//
// We can still map these back to the original input regions, as we
// just instantiate the canonical variable with its corresponding
// `original_value`.
//
// For more information on why we canonicalize all input regions as
// placeholders, see the comment in `Canonicalizer::fold_region`.
original_values[kind.expect_placeholder_index()]
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
--> $DIR/normalization-preserve-equality.rs:24:1
--> $DIR/normalization-preserve-equality.rs:27:1
|
LL | fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
| ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -11,7 +11,7 @@ LL | fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>))
= help: consider adding the following bound: `'a: 'b`

error: lifetime may not live long enough
--> $DIR/normalization-preserve-equality.rs:24:1
--> $DIR/normalization-preserve-equality.rs:27:1
|
LL | fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
| ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
13 changes: 8 additions & 5 deletions tests/ui/implied-bounds/normalization-preserve-equality.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Both revisions should pass. `borrowck` revision is a bug!
// All the revisions should pass. `borrowck_current` revision is a bug!
//
//@ revisions: wfcheck borrowck
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ revisions: wfcheck borrowck_current borrowck_next
//@ [wfcheck] check-pass
//@ [borrowck] check-fail
//@ [borrowck] known-bug: #106569
//@ [borrowck_current] check-fail
//@ [borrowck_current] known-bug: #106569
//@ [borrowck_next] compile-flags: -Znext-solver
//@ [borrowck_next] check-pass

struct Equal<'a, 'b>(&'a &'b (), &'b &'a ()); // implies 'a == 'b

Expand All @@ -20,7 +23,7 @@ trait WfCheckTrait {}
#[cfg(wfcheck)]
impl<'a, 'b> WfCheckTrait for (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>) {}

#[cfg(borrowck)]
#[cfg(any(borrowck_current, borrowck_next))]
fn test_borrowck<'a, 'b>(_: (<Equal<'a, 'b> as Trait>::Ty, Equal<'a, 'b>)) {
let _ = None::<Equal<'a, 'b>>;
}
Expand Down
Loading