Skip to content

Commit ea2cc43

Browse files
committed
Auto merge of #121442 - lcnr:region-var-universe-uwu, r=compiler-errors
region unification: update universe of region vars necessary for #119106. see inline comment for why this is necessary r? `@compiler-errors` `@BoxyUwU`
2 parents 6dadb6e + 16350d7 commit ea2cc43

File tree

5 files changed

+130
-96
lines changed

5 files changed

+130
-96
lines changed

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,12 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
175175
),
176176

177177
ty::ReVar(vid) => {
178-
let universe =
179-
infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid);
178+
let universe = infcx
179+
.inner
180+
.borrow_mut()
181+
.unwrap_region_constraints()
182+
.probe_value(vid)
183+
.unwrap_err();
180184
canonicalizer.canonical_var_for_region(
181185
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
182186
r,

compiler/rustc_infer/src/infer/mod.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
374374
}
375375

376376
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
377-
Some(self.universe_of_region_vid(lt))
377+
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
378+
Err(universe) => Some(universe),
379+
Ok(_) => None,
380+
}
378381
}
379382

380383
fn root_ty_var(&self, vid: TyVid) -> TyVid {
@@ -1155,11 +1158,6 @@ impl<'tcx> InferCtxt<'tcx> {
11551158
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
11561159
}
11571160

1158-
/// Return the universe that the region variable `r` was created in.
1159-
pub fn universe_of_region_vid(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
1160-
self.inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
1161-
}
1162-
11631161
/// Number of region variables created so far.
11641162
pub fn num_region_vars(&self) -> usize {
11651163
self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()

compiler/rustc_infer/src/infer/region_constraints/leak_check.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
9090
}
9191
}
9292

93-
struct LeakCheck<'me, 'tcx> {
93+
struct LeakCheck<'a, 'b, 'tcx> {
9494
tcx: TyCtxt<'tcx>,
9595
outer_universe: ty::UniverseIndex,
96-
mini_graph: &'me MiniGraph<'tcx>,
97-
rcc: &'me RegionConstraintCollector<'me, 'tcx>,
96+
mini_graph: &'a MiniGraph<'tcx>,
97+
rcc: &'a mut RegionConstraintCollector<'b, 'tcx>,
9898

9999
// Initially, for each SCC S, stores a placeholder `P` such that `S = P`
100100
// must hold.
@@ -117,13 +117,13 @@ struct LeakCheck<'me, 'tcx> {
117117
scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
118118
}
119119

120-
impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
120+
impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> {
121121
fn new(
122122
tcx: TyCtxt<'tcx>,
123123
outer_universe: ty::UniverseIndex,
124124
max_universe: ty::UniverseIndex,
125-
mini_graph: &'me MiniGraph<'tcx>,
126-
rcc: &'me RegionConstraintCollector<'me, 'tcx>,
125+
mini_graph: &'a MiniGraph<'tcx>,
126+
rcc: &'a mut RegionConstraintCollector<'b, 'tcx>,
127127
) -> Self {
128128
let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
129129
Self {

compiler/rustc_infer/src/infer/region_constraints/mod.rs

+69-38
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ use super::{
88
};
99

1010
use rustc_data_structures::fx::FxHashMap;
11-
use rustc_data_structures::intern::Interned;
1211
use rustc_data_structures::sync::Lrc;
1312
use rustc_data_structures::undo_log::UndoLogs;
1413
use rustc_data_structures::unify as ut;
1514
use rustc_index::IndexVec;
16-
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
15+
use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey};
1716
use rustc_middle::ty::ReStatic;
1817
use rustc_middle::ty::{self, Ty, TyCtxt};
1918
use rustc_middle::ty::{ReBound, ReVar};
@@ -292,6 +291,18 @@ type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>;
292291
#[derive(Debug, Clone, Copy)]
293292
pub struct RegionVariableInfo {
294293
pub origin: RegionVariableOrigin,
294+
// FIXME: This is only necessary for `fn take_and_reset_data` and
295+
// `lexical_region_resolve`. We should rework `lexical_region_resolve`
296+
// in the near/medium future anyways and could move the unverse info
297+
// for `fn take_and_reset_data` into a separate table which is
298+
// only populated when needed.
299+
//
300+
// For both of these cases it is fine that this can diverge from the
301+
// actual universe of the variable, which is directly stored in the
302+
// unification table for unknown region variables. At some point we could
303+
// stop emitting bidirectional outlives constraints if equate succeeds.
304+
// This would be currently unsound as it would cause us to drop the universe
305+
// changes in `lexical_region_resolve`.
295306
pub universe: ty::UniverseIndex,
296307
}
297308

@@ -395,7 +406,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
395406
// `RegionConstraintData` contains the relationship here.
396407
if *any_unifications {
397408
*any_unifications = false;
398-
self.unification_table_mut().reset_unifications(|_| UnifiedRegion::new(None));
409+
// Manually inlined `self.unification_table_mut()` as `self` is used in the closure.
410+
ut::UnificationTable::with_log(&mut self.storage.unification_table, &mut self.undo_log)
411+
.reset_unifications(|key| RegionVariableValue::Unknown {
412+
universe: self.storage.var_infos[key.vid].universe,
413+
});
399414
}
400415

401416
data
@@ -422,18 +437,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
422437
) -> RegionVid {
423438
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
424439

425-
let u_vid = self.unification_table_mut().new_key(UnifiedRegion::new(None));
440+
let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe });
426441
assert_eq!(vid, u_vid.vid);
427442
self.undo_log.push(AddVar(vid));
428443
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
429444
vid
430445
}
431446

432-
/// Returns the universe for the given variable.
433-
pub(super) fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex {
434-
self.var_infos[vid].universe
435-
}
436-
437447
/// Returns the origin for the given variable.
438448
pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
439449
self.var_infos[vid].origin
@@ -467,26 +477,41 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
467477
pub(super) fn make_eqregion(
468478
&mut self,
469479
origin: SubregionOrigin<'tcx>,
470-
sub: Region<'tcx>,
471-
sup: Region<'tcx>,
480+
a: Region<'tcx>,
481+
b: Region<'tcx>,
472482
) {
473-
if sub != sup {
483+
if a != b {
474484
// Eventually, it would be nice to add direct support for
475485
// equating regions.
476-
self.make_subregion(origin.clone(), sub, sup);
477-
self.make_subregion(origin, sup, sub);
478-
479-
match (sub, sup) {
480-
(Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
481-
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
482-
self.unification_table_mut().union(*sub, *sup);
483-
self.any_unifications = true;
486+
self.make_subregion(origin.clone(), a, b);
487+
self.make_subregion(origin, b, a);
488+
489+
match (a.kind(), b.kind()) {
490+
(ty::ReVar(a), ty::ReVar(b)) => {
491+
debug!("make_eqregion: unifying {:?} with {:?}", a, b);
492+
if self.unification_table_mut().unify_var_var(a, b).is_ok() {
493+
self.any_unifications = true;
494+
}
495+
}
496+
(ty::ReVar(vid), _) => {
497+
debug!("make_eqregion: unifying {:?} with {:?}", vid, b);
498+
if self
499+
.unification_table_mut()
500+
.unify_var_value(vid, RegionVariableValue::Known { value: b })
501+
.is_ok()
502+
{
503+
self.any_unifications = true;
504+
};
484505
}
485-
(Region(Interned(ReVar(vid), _)), value)
486-
| (value, Region(Interned(ReVar(vid), _))) => {
487-
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
488-
self.unification_table_mut().union_value(*vid, UnifiedRegion::new(Some(value)));
489-
self.any_unifications = true;
506+
(_, ty::ReVar(vid)) => {
507+
debug!("make_eqregion: unifying {:?} with {:?}", a, vid);
508+
if self
509+
.unification_table_mut()
510+
.unify_var_value(vid, RegionVariableValue::Known { value: a })
511+
.is_ok()
512+
{
513+
self.any_unifications = true;
514+
};
490515
}
491516
(_, _) => {}
492517
}
@@ -603,18 +628,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
603628
tcx: TyCtxt<'tcx>,
604629
vid: ty::RegionVid,
605630
) -> ty::Region<'tcx> {
606-
let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
631+
let mut ut = self.unification_table_mut();
607632
let root_vid = ut.find(vid).vid;
608-
let resolved = ut
609-
.probe_value(root_vid)
610-
.get_value_ignoring_universes()
611-
.unwrap_or_else(|| ty::Region::new_var(tcx, root_vid));
612-
613-
// Don't resolve a variable to a region that it cannot name.
614-
if self.var_universe(vid).can_name(self.universe(resolved)) {
615-
resolved
616-
} else {
617-
ty::Region::new_var(tcx, vid)
633+
match ut.probe_value(root_vid) {
634+
RegionVariableValue::Known { value } => value,
635+
RegionVariableValue::Unknown { .. } => ty::Region::new_var(tcx, root_vid),
636+
}
637+
}
638+
639+
pub fn probe_value(
640+
&mut self,
641+
vid: ty::RegionVid,
642+
) -> Result<ty::Region<'tcx>, ty::UniverseIndex> {
643+
match self.unification_table_mut().probe_value(vid) {
644+
RegionVariableValue::Known { value } => Ok(value),
645+
RegionVariableValue::Unknown { universe } => Err(universe),
618646
}
619647
}
620648

@@ -654,15 +682,18 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
654682
new_r
655683
}
656684

657-
pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
685+
pub fn universe(&mut self, region: Region<'tcx>) -> ty::UniverseIndex {
658686
match *region {
659687
ty::ReStatic
660688
| ty::ReErased
661689
| ty::ReLateParam(..)
662690
| ty::ReEarlyParam(..)
663691
| ty::ReError(_) => ty::UniverseIndex::ROOT,
664692
ty::RePlaceholder(placeholder) => placeholder.universe,
665-
ty::ReVar(vid) => self.var_universe(vid),
693+
ty::ReVar(vid) => match self.probe_value(vid) {
694+
Ok(value) => self.universe(value),
695+
Err(universe) => universe,
696+
},
666697
ty::ReBound(..) => bug!("universe(): encountered bound region {:?}", region),
667698
}
668699
}

compiler/rustc_middle/src/infer/unify_key.rs

+45-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ty::{self, Region, Ty, TyCtxt};
1+
use crate::ty::{self, Ty, TyCtxt};
22
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
33
use rustc_span::def_id::DefId;
44
use rustc_span::symbol::Symbol;
@@ -10,26 +10,16 @@ pub trait ToType {
1010
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
1111
}
1212

13-
#[derive(PartialEq, Copy, Clone, Debug)]
14-
pub struct UnifiedRegion<'tcx> {
15-
value: Option<ty::Region<'tcx>>,
16-
}
17-
18-
impl<'tcx> UnifiedRegion<'tcx> {
19-
pub fn new(value: Option<Region<'tcx>>) -> Self {
20-
Self { value }
21-
}
22-
23-
/// The caller is responsible for checking universe compatibility before using this value.
24-
pub fn get_value_ignoring_universes(self) -> Option<Region<'tcx>> {
25-
self.value
26-
}
13+
#[derive(Copy, Clone, Debug)]
14+
pub enum RegionVariableValue<'tcx> {
15+
Known { value: ty::Region<'tcx> },
16+
Unknown { universe: ty::UniverseIndex },
2717
}
2818

2919
#[derive(PartialEq, Copy, Clone, Debug)]
3020
pub struct RegionVidKey<'tcx> {
3121
pub vid: ty::RegionVid,
32-
pub phantom: PhantomData<UnifiedRegion<'tcx>>,
22+
pub phantom: PhantomData<RegionVariableValue<'tcx>>,
3323
}
3424

3525
impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
@@ -39,7 +29,7 @@ impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
3929
}
4030

4131
impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
42-
type Value = UnifiedRegion<'tcx>;
32+
type Value = RegionVariableValue<'tcx>;
4333
#[inline]
4434
fn index(&self) -> u32 {
4535
self.vid.as_u32()
@@ -53,36 +43,47 @@ impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
5343
}
5444
}
5545

56-
impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
57-
type Error = NoError;
46+
pub struct RegionUnificationError;
47+
impl<'tcx> UnifyValue for RegionVariableValue<'tcx> {
48+
type Error = RegionUnificationError;
5849

59-
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
60-
// We pick the value of the least universe because it is compatible with more variables.
61-
// This is *not* necessary for completeness.
62-
#[cold]
63-
fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> {
64-
cmp::min_by_key(r1, r2, |r| match r.kind() {
65-
ty::ReStatic
66-
| ty::ReErased
67-
| ty::ReLateParam(..)
68-
| ty::ReEarlyParam(..)
69-
| ty::ReError(_) => ty::UniverseIndex::ROOT,
70-
ty::RePlaceholder(placeholder) => placeholder.universe,
71-
ty::ReVar(..) | ty::ReBound(..) => bug!("not a universal region"),
72-
})
73-
}
74-
75-
Ok(match (value1.value, value2.value) {
76-
// Here we can just pick one value, because the full constraints graph
77-
// will be handled later. Ideally, we might want a `MultipleValues`
78-
// variant or something. For now though, this is fine.
79-
(Some(val1), Some(val2)) => Self { value: Some(min_universe(val1, val2)) },
50+
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
51+
match (*value1, *value2) {
52+
(RegionVariableValue::Known { .. }, RegionVariableValue::Known { .. }) => {
53+
Err(RegionUnificationError)
54+
}
8055

81-
(Some(_), _) => *value1,
82-
(_, Some(_)) => *value2,
56+
(RegionVariableValue::Known { value }, RegionVariableValue::Unknown { universe })
57+
| (RegionVariableValue::Unknown { universe }, RegionVariableValue::Known { value }) => {
58+
let universe_of_value = match value.kind() {
59+
ty::ReStatic
60+
| ty::ReErased
61+
| ty::ReLateParam(..)
62+
| ty::ReEarlyParam(..)
63+
| ty::ReError(_) => ty::UniverseIndex::ROOT,
64+
ty::RePlaceholder(placeholder) => placeholder.universe,
65+
ty::ReVar(..) | ty::ReBound(..) => bug!("not a universal region"),
66+
};
67+
68+
if universe.can_name(universe_of_value) {
69+
Ok(RegionVariableValue::Known { value })
70+
} else {
71+
Err(RegionUnificationError)
72+
}
73+
}
8374

84-
(None, None) => *value1,
85-
})
75+
(
76+
RegionVariableValue::Unknown { universe: a },
77+
RegionVariableValue::Unknown { universe: b },
78+
) => {
79+
// If we unify two unconstrained regions then whatever
80+
// value they wind up taking (which must be the same value) must
81+
// be nameable by both universes. Therefore, the resulting
82+
// universe is the minimum of the two universes, because that is
83+
// the one which contains the fewest names in scope.
84+
Ok(RegionVariableValue::Unknown { universe: a.min(b) })
85+
}
86+
}
8687
}
8788
}
8889

0 commit comments

Comments
 (0)