Repository navigation
-Zassumptions-on-binders: replace region vars with bound vars when handling alias outlives' #164045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<I: Interner>( | |
| }) | ||
| } | ||
|
|
||
| pub struct PlaceholderReplacer<I: Interner> { | ||
| cx: I, | ||
| existing_var_count: usize, | ||
| bound_vars: IndexMap<BoundVar, BoundRegion<I>>, | ||
| pub struct MakeHigherRankederer<'a, I: Interner, Infcx: InferCtxtLike<Interner = I>> { | ||
| cx: &'a Infcx, | ||
| preexisting_var_count: usize, | ||
| regions: IndexMap<Region<I>, BoundRegion<I>>, | ||
| universe: UniverseIndex, | ||
| current_index: DebruijnIndex, | ||
| } | ||
|
|
||
| impl<I: Interner> TypeFolder<I> for PlaceholderReplacer<I> { | ||
| impl<'a, I: Interner, Infcx: InferCtxtLike<Interner = I>> MakeHigherRankederer<'a, I, Infcx> { | ||
| fn existing_var_count(&self) -> usize { | ||
| self.preexisting_var_count + self.regions.len() | ||
| } | ||
| } | ||
|
|
||
| impl<'a, I: Interner, Infcx: InferCtxtLike<Interner = I>> TypeFolder<I> | ||
| for MakeHigherRankederer<'a, I, Infcx> | ||
| { | ||
| fn cx(&self) -> I { | ||
| self.cx | ||
| self.cx.cx() | ||
| } | ||
|
|
||
| fn fold_region(&mut self, r: Region<I>) -> Region<I> { | ||
| 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(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mostly a note for myself, I'm unfamiliar with phasing and when things are resolved/run, so I'm unsure if this is possible to ever be resolved and so
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we just crash here sometimes yeah :3 Should actually be proper after #164103 |
||
| 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, | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<T: for<'a> Trait<'a>> { | ||
| forall<'b> | ||
| where | ||
| for<'a> <T as Trait<'a>>::Assoc: 'b | ||
| { | ||
| forall<> { | ||
| exists<'a> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you know I'm realizing that I accidentally never actually tested
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✨ |
||
| for<> <T as Trait<'a>>::Assoc: 'b | ||
| } | ||
| } expect { | ||
| for<'a> <T as Trait<'a>>::Assoc: 'b | ||
| } | ||
| } expect { | ||
| or { and {} } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is technically useless/not needed, right? just
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh yeah |
||
| } | ||
| } | ||
| } | ||
|
|
||
| fn main() {} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not in this PR, but, should we be folding types as well? for
#![feature(non_lifetime_binders)]. tbh I don't know the state ofnon_lifetime_binders, if something likeT::Alias<?x>: 'a->for<NLB> T::Alias<NLB>: 'ais valid (in the sense of if it gets ICEy or not)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it doesn't get ICEy but we do just downgrade to ambiguity because we don't handle it. I have no idea what the right thing to do for non lifetime binders is lol that feature is not being actively developed rn tho