Skip to content

Commit 7c306f6

Browse files
committed
Auto merge of rust-lang#108121 - aliemjay:resolve-var-region, r=lcnr
always resolve to universal regions if possible `RegionConstraintCollector::opportunistic_resolve_var`, which is used in canonicalization and projection logic, doesn't resolve the region var to an equal universal region. So if we have equated `'static == '1 == '2`, it doesn't resolve `'1` or `'2` to `'static`. Now it does! Addresses review comment rust-lang#107376 (comment). r? `@lcnr`
2 parents 60445fd + 0b232d0 commit 7c306f6

File tree

10 files changed

+86
-71
lines changed

10 files changed

+86
-71
lines changed

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

+5-7
Original file line numberDiff line numberDiff line change
@@ -352,19 +352,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
352352
}
353353

354354
ty::ReVar(vid) => {
355-
let resolved_vid = self
355+
let resolved = self
356356
.infcx
357357
.inner
358358
.borrow_mut()
359359
.unwrap_region_constraints()
360-
.opportunistic_resolve_var(vid);
360+
.opportunistic_resolve_var(self.tcx, vid);
361361
debug!(
362-
"canonical: region var found with vid {:?}, \
363-
opportunistically resolved to {:?}",
364-
vid, resolved_vid
362+
"canonical: region var found with vid {vid:?}, \
363+
opportunistically resolved to {resolved:?}",
365364
);
366-
let r = self.tcx.mk_re_var(resolved_vid);
367-
self.canonicalize_mode.canonicalize_free_region(self, r)
365+
self.canonicalize_mode.canonicalize_free_region(self, resolved)
368366
}
369367

370368
ty::ReStatic

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

+21-24
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
420420
// `RegionConstraintData` contains the relationship here.
421421
if *any_unifications {
422422
*any_unifications = false;
423-
self.unification_table().reset_unifications(|_| UnifiedRegion(None));
423+
self.unification_table_mut().reset_unifications(|_| UnifiedRegion::new(None));
424424
}
425425

426426
data
@@ -447,7 +447,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
447447
) -> RegionVid {
448448
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
449449

450-
let u_vid = self.unification_table().new_key(UnifiedRegion(None));
450+
let u_vid = self.unification_table_mut().new_key(UnifiedRegion::new(None));
451451
assert_eq!(vid, u_vid.vid);
452452
self.undo_log.push(AddVar(vid));
453453
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
@@ -516,13 +516,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
516516
match (sub, sup) {
517517
(Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
518518
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
519-
self.unification_table().union(*sub, *sup);
519+
self.unification_table_mut().union(*sub, *sup);
520520
self.any_unifications = true;
521521
}
522522
(Region(Interned(ReVar(vid), _)), value)
523523
| (value, Region(Interned(ReVar(vid), _))) => {
524524
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
525-
self.unification_table().union_value(*vid, UnifiedRegion(Some(value)));
525+
self.unification_table_mut().union_value(*vid, UnifiedRegion::new(Some(value)));
526526
self.any_unifications = true;
527527
}
528528
(_, _) => {}
@@ -633,28 +633,25 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
633633
}
634634
}
635635

636-
/// Resolves the passed RegionVid to the root RegionVid in the unification table
637-
pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
638-
self.unification_table().find(rid).vid
639-
}
640-
641-
/// If the Region is a `ReVar`, then resolves it either to the root value in
642-
/// the unification table, if it exists, or to the root `ReVar` in the table.
643-
/// If the Region is not a `ReVar`, just returns the Region itself.
644-
pub fn opportunistic_resolve_region(
636+
/// Resolves a region var to its value in the unification table, if it exists.
637+
/// Otherwise, it is resolved to the root `ReVar` in the table.
638+
pub fn opportunistic_resolve_var(
645639
&mut self,
646640
tcx: TyCtxt<'tcx>,
647-
region: ty::Region<'tcx>,
641+
vid: ty::RegionVid,
648642
) -> ty::Region<'tcx> {
649-
match *region {
650-
ty::ReVar(rid) => {
651-
let unified_region = self.unification_table().probe_value(rid);
652-
unified_region.0.unwrap_or_else(|| {
653-
let root = self.unification_table().find(rid).vid;
654-
tcx.mk_re_var(root)
655-
})
656-
}
657-
_ => region,
643+
let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
644+
let root_vid = ut.find(vid).vid;
645+
let resolved = ut
646+
.probe_value(root_vid)
647+
.get_value_ignoring_universes()
648+
.unwrap_or_else(|| tcx.mk_re_var(root_vid));
649+
650+
// Don't resolve a variable to a region that it cannot name.
651+
if self.var_universe(vid).can_name(self.universe(resolved)) {
652+
resolved
653+
} else {
654+
tcx.mk_re_var(vid)
658655
}
659656
}
660657

@@ -733,7 +730,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
733730
}
734731

735732
#[inline]
736-
fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
733+
fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
737734
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
738735
}
739736
}

compiler/rustc_infer/src/infer/resolve.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,12 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
8585

8686
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
8787
match *r {
88-
ty::ReVar(rid) => {
89-
let resolved = self
90-
.infcx
91-
.inner
92-
.borrow_mut()
93-
.unwrap_region_constraints()
94-
.opportunistic_resolve_var(rid);
95-
TypeFolder::interner(self).mk_re_var(resolved)
96-
}
88+
ty::ReVar(vid) => self
89+
.infcx
90+
.inner
91+
.borrow_mut()
92+
.unwrap_region_constraints()
93+
.opportunistic_resolve_var(TypeFolder::interner(self), vid),
9794
_ => r,
9895
}
9996
}

compiler/rustc_middle/src/infer/unify_key.rs

+33-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ty::{self, Ty, TyCtxt};
1+
use crate::ty::{self, Region, Ty, TyCtxt};
22
use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue};
33
use rustc_span::def_id::DefId;
44
use rustc_span::symbol::Symbol;
@@ -11,7 +11,20 @@ pub trait ToType {
1111
}
1212

1313
#[derive(PartialEq, Copy, Clone, Debug)]
14-
pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
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+
}
27+
}
1528

1629
#[derive(PartialEq, Copy, Clone, Debug)]
1730
pub struct RegionVidKey<'tcx> {
@@ -44,11 +57,27 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
4457
type Error = NoError;
4558

4659
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
47-
Ok(match (value1.0, value2.0) {
60+
// We pick the value of the least universe because it is compatible with more variables.
61+
// This is *not* neccessary for soundness, but it allows more region variables to be
62+
// resolved to the said value.
63+
#[cold]
64+
fn min_universe<'tcx>(r1: Region<'tcx>, r2: Region<'tcx>) -> Region<'tcx> {
65+
cmp::min_by_key(r1, r2, |r| match r.kind() {
66+
ty::ReStatic
67+
| ty::ReErased
68+
| ty::ReFree(..)
69+
| ty::ReEarlyBound(..)
70+
| ty::ReError(_) => ty::UniverseIndex::ROOT,
71+
ty::RePlaceholder(placeholder) => placeholder.universe,
72+
ty::ReVar(..) | ty::ReLateBound(..) => bug!("not a universal region"),
73+
})
74+
}
75+
76+
Ok(match (value1.value, value2.value) {
4877
// Here we can just pick one value, because the full constraints graph
4978
// will be handled later. Ideally, we might want a `MultipleValues`
5079
// variant or something. For now though, this is fine.
51-
(Some(_), Some(_)) => *value1,
80+
(Some(val1), Some(val2)) => Self { value: Some(min_universe(val1, val2)) },
5281

5382
(Some(_), _) => *value1,
5483
(_, Some(_)) => *value2,

compiler/rustc_trait_selection/src/traits/project.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -870,12 +870,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
870870

871871
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
872872
let r1 = match *r0 {
873-
ty::ReVar(_) => self
873+
ty::ReVar(vid) => self
874874
.infcx
875875
.inner
876876
.borrow_mut()
877877
.unwrap_region_constraints()
878-
.opportunistic_resolve_region(self.infcx.tcx, r0),
878+
.opportunistic_resolve_var(self.infcx.tcx, vid),
879879
_ => r0,
880880
};
881881

tests/rustdoc/normalize-assoc-item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ impl<'a> Lifetimes<'a> for usize {
6363
type Y = &'a isize;
6464
}
6565

66-
// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust item-decl"]' "pub fn g() -> &isize"
66+
// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust item-decl"]' "pub fn g() -> &'static isize"
6767
pub fn g() -> <usize as Lifetimes<'static>>::Y {
6868
&0
6969
}
7070

71-
// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust item-decl"]' "pub const A: &isize"
71+
// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust item-decl"]' "pub const A: &'static isize"
7272
pub const A: <usize as Lifetimes<'static>>::Y = &0;
7373

7474
// test cross-crate re-exports

tests/ui/traits/inductive-overflow/lifetime.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ impl<'a> Y for C<'a> {
1515
struct C<'a>(&'a ());
1616
struct X<T: Y>(T::P);
1717

18-
impl<T: NotAuto> NotAuto for Box<T> {} //~ NOTE: required
18+
impl<T: NotAuto> NotAuto for Box<T> {}
19+
impl<T: Y> NotAuto for X<T> where T::P: NotAuto {} //~ NOTE: required
1920
//~^ NOTE unsatisfied trait bound introduced here
20-
impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
2121
impl<'a> NotAuto for C<'a> {}
2222

2323
fn is_send<S: NotAuto>() {}
@@ -28,6 +28,4 @@ fn main() {
2828
// Should only be a few notes.
2929
is_send::<X<C<'static>>>();
3030
//~^ ERROR overflow evaluating
31-
//~| 3 redundant requirements hidden
32-
//~| required for
3331
}

tests/ui/traits/inductive-overflow/lifetime.stderr

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
error[E0275]: overflow evaluating the requirement `X<C<'_>>: NotAuto`
1+
error[E0275]: overflow evaluating the requirement `Box<X<C<'static>>>: NotAuto`
22
--> $DIR/lifetime.rs:29:5
33
|
44
LL | is_send::<X<C<'static>>>();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
note: required for `Box<X<C<'_>>>` to implement `NotAuto`
8-
--> $DIR/lifetime.rs:18:18
7+
note: required for `X<C<'static>>` to implement `NotAuto`
8+
--> $DIR/lifetime.rs:19:12
99
|
10-
LL | impl<T: NotAuto> NotAuto for Box<T> {}
11-
| ------- ^^^^^^^ ^^^^^^
12-
| |
13-
| unsatisfied trait bound introduced here
14-
= note: 3 redundant requirements hidden
15-
= note: required for `X<C<'static>>` to implement `NotAuto`
10+
LL | impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
11+
| ^^^^^^^ ^^^^ ------- unsatisfied trait bound introduced here
1612
note: required by a bound in `is_send`
1713
--> $DIR/lifetime.rs:23:15
1814
|

tests/ui/wf/hir-wf-check-erase-regions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
pub struct Table<T, const N: usize>([Option<T>; N]);
55

66
impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> {
7-
type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; //~ ERROR `&T` is not an iterator
7+
type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; //~ ERROR `&'a T` is not an iterator
88
type Item = &'a T;
99

10-
fn into_iter(self) -> Self::IntoIter { //~ ERROR `&T` is not an iterator
10+
fn into_iter(self) -> Self::IntoIter { //~ ERROR `&'a T` is not an iterator
1111
unimplemented!()
1212
}
1313
}

tests/ui/wf/hir-wf-check-erase-regions.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
error[E0277]: `&T` is not an iterator
1+
error[E0277]: `&'a T` is not an iterator
22
--> $DIR/hir-wf-check-erase-regions.rs:7:21
33
|
44
LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&T` is not an iterator
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator
66
|
7-
= help: the trait `Iterator` is not implemented for `&T`
7+
= help: the trait `Iterator` is not implemented for `&'a T`
88
= help: the trait `Iterator` is implemented for `&mut I`
9-
= note: required for `&T` to implement `IntoIterator`
9+
= note: required for `&'a T` to implement `IntoIterator`
1010
note: required by a bound in `Flatten`
1111
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
1212

13-
error[E0277]: `&T` is not an iterator
13+
error[E0277]: `&'a T` is not an iterator
1414
--> $DIR/hir-wf-check-erase-regions.rs:10:27
1515
|
1616
LL | fn into_iter(self) -> Self::IntoIter {
17-
| ^^^^^^^^^^^^^^ `&T` is not an iterator
17+
| ^^^^^^^^^^^^^^ `&'a T` is not an iterator
1818
|
19-
= help: the trait `Iterator` is not implemented for `&T`
19+
= help: the trait `Iterator` is not implemented for `&'a T`
2020
= help: the trait `Iterator` is implemented for `&mut I`
21-
= note: required for `&T` to implement `IntoIterator`
21+
= note: required for `&'a T` to implement `IntoIterator`
2222
note: required by a bound in `Flatten`
2323
--> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL
2424

0 commit comments

Comments
 (0)