diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 4a6e704cb0020..6f7a1ede0315d 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -54,9 +54,9 @@ use crate::inherent::*; use crate::relate::{Relate, RelateResult, TypeRelation, VarianceDiagInfo}; use crate::visit::TypeVisitableExt; use crate::{ - AliasTy, Binder, BoundRegion, BoundVar, BoundVariableKind, ClauseKind, DebruijnIndex, - InferCtxtLike, Interner, IsRigid, OutlivesClause, Region, RegionKind, TyKind, TypeFoldable, - TypeFolder, TypingMode, UniverseIndex, Variance, elaborate, max_universe, + AliasTy, Binder, BoundRegion, BoundRegionKind, BoundVar, BoundVariableKind, ClauseKind, + DebruijnIndex, InferCtxtLike, Interner, IsRigid, OutlivesClause, Region, RegionKind, TyKind, + TypeFoldable, TypeFolder, TypingMode, UniverseIndex, Variance, elaborate, max_universe, set_aliases_to_non_rigid, }; @@ -964,16 +964,16 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl let higher_ranked_candidate_for_outlived_region = |region| { let bound_outlives = bound_outlives.map_bound(|(alias, _)| (alias, region)); - let mut replacer = PlaceholderReplacer { - cx: infcx.cx(), - existing_var_count: bound_outlives.bound_vars().len(), - bound_vars: IndexMap::default(), + let mut replacer = MakeHigherRankederer { + cx: infcx, + preexisting_var_count: bound_outlives.bound_vars().len(), + regions: IndexMap::default(), universe: u, current_index: DebruijnIndex::ZERO, }; let escaping_outlives = bound_outlives.skip_binder().fold_with(&mut replacer); let bound_vars = bound_outlives.bound_vars().iter().chain( - core::mem::take(&mut replacer.bound_vars) + core::mem::take(&mut replacer.regions) .into_iter() .map(|(_, bound_region)| BoundVariableKind::Region(bound_region.kind)), ); @@ -982,7 +982,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl I::BoundVarKinds::from_vars(infcx.cx(), bound_vars), ); - // `PlaceholderReplacer` only folds regions. A non-lifetime binder can leave + // `MakeHigherRankederer` only folds regions. A non-lifetime binder can leave // a placeholder type in `u`, so this type-outlives constraint cannot be // handled by the region-outlives-only eager placeholder machinery. if max_universe(infcx, bound_outlives) == u { @@ -1078,30 +1078,52 @@ pub fn regions_outlived_by_placeholder( }) } -pub struct PlaceholderReplacer { - cx: I, - existing_var_count: usize, - bound_vars: IndexMap>, +pub struct MakeHigherRankederer<'a, I: Interner, Infcx: InferCtxtLike> { + cx: &'a Infcx, + preexisting_var_count: usize, + regions: IndexMap, BoundRegion>, universe: UniverseIndex, current_index: DebruijnIndex, } -impl TypeFolder for PlaceholderReplacer { +impl<'a, I: Interner, Infcx: InferCtxtLike> MakeHigherRankederer<'a, I, Infcx> { + fn existing_var_count(&self) -> usize { + self.preexisting_var_count + self.regions.len() + } +} + +impl<'a, I: Interner, Infcx: InferCtxtLike> TypeFolder + for MakeHigherRankederer<'a, I, Infcx> +{ fn cx(&self) -> I { - self.cx + self.cx.cx() } fn fold_region(&mut self, r: Region) -> Region { + let cx = self.cx(); + match r.kind() { RegionKind::RePlaceholder(p) if p.universe == self.universe => { - let bound_vars_len = self.bound_vars.len(); - let mapped_var = self.bound_vars.entry(p.bound.var).or_insert(BoundRegion { - var: BoundVar::from_usize(self.existing_var_count + bound_vars_len), + let existing_var_count = self.existing_var_count(); + let mapped_var = self.regions.entry(r).or_insert(BoundRegion { + var: BoundVar::from_usize(existing_var_count), kind: p.bound.kind, }); - Region::new_bound(self.cx, self.current_index, *mapped_var) + Region::new_bound(cx, self.current_index, *mapped_var) + } + RegionKind::ReVar(inf) => { + let u = self.cx.universe_of_region(inf).unwrap(); + if u == self.universe { + let existing_var_count = self.existing_var_count(); + let mapped_var = self.regions.entry(r).or_insert(BoundRegion { + var: BoundVar::from_usize(existing_var_count), + kind: BoundRegionKind::Anon, + }); + Region::new_bound(cx, self.current_index, *mapped_var) + } else { + r + } } - // FIXME(-Zassumptions-on-binders): We should be handling region variables here somehow _ => r, } } diff --git a/tests/ui/assumptions_on_binders/replace_region_vars_with_placeholders.rs b/tests/ui/assumptions_on_binders/replace_region_vars_with_placeholders.rs new file mode 100644 index 0000000000000..2a8237501e039 --- /dev/null +++ b/tests/ui/assumptions_on_binders/replace_region_vars_with_placeholders.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally +//@ check-pass + +// test that when rewriting alias outlives constraints we will replace +// region variables in the universe being handled, with (new) bound vars +// on the alias outlives constraint's binder. +// +// we previously did not do this and would get ambiguity which was overly +// conservative + +#![feature(test_binder_constraints)] + +trait Trait<'a> { + type Assoc; +} + +core::test_binder_constraints! { + impl Trait<'a>> { + forall<'b> + where + for<'a> >::Assoc: 'b + { + forall<> { + exists<'a> { + for<> >::Assoc: 'b + } + } expect { + for<'a> >::Assoc: 'b + } + } expect { + or { and {} } + } + } +} + +fn main() {}