Skip to content

Commit 534f044

Browse files
committed
index ReEmpty by universe
We now make `'empty` indexed by a universe index, resulting in a region lattice like this: ``` static ----------+-----...------+ (greatest) | | | early-bound and | | free regions | | | | | scope regions | | | | | empty(root) placeholder(U1) | | / | | / placeholder(Un) empty(U1) -- / | / ... / | / empty(Un) -------- (smallest) ``` Therefore, `exists<A> { forall<B> { B: A } }` is now unprovable, because A must be at least Empty(U1) and B is placeholder(U2), and hence the two regions are unrelated.
1 parent b52414f commit 534f044

File tree

22 files changed

+269
-58
lines changed

22 files changed

+269
-58
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
6363
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
6464
mem::discriminant(self).hash_stable(hcx, hasher);
6565
match *self {
66-
ty::ReErased | ty::ReStatic | ty::ReEmpty => {
66+
ty::ReErased | ty::ReStatic => {
6767
// No variant fields to hash for these ...
6868
}
69+
ty::ReEmpty(universe) => {
70+
universe.hash_stable(hcx, hasher);
71+
}
6972
ty::ReLateBound(db, ty::BrAnon(i)) => {
7073
db.hash_stable(hcx, hasher);
7174
i.hash_stable(hcx, hasher);

src/librustc/infer/canonical/canonicalizer.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,29 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
167167
r: ty::Region<'tcx>,
168168
) -> ty::Region<'tcx> {
169169
match r {
170-
ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
170+
ty::ReFree(_)
171+
| ty::ReErased
172+
| ty::ReStatic
173+
| ty::ReEmpty(ty::UniverseIndex::ROOT)
174+
| ty::ReEarlyBound(..) => r,
175+
171176
ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
172177
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) },
173178
r,
174179
),
180+
175181
ty::ReVar(vid) => {
176182
let universe = canonicalizer.region_var_universe(*vid);
177183
canonicalizer.canonical_var_for_region(
178184
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
179185
r,
180186
)
181187
}
188+
189+
ty::ReEmpty(ui) => {
190+
bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME
191+
}
192+
182193
_ => {
183194
// Other than `'static` or `'empty`, the query
184195
// response should be executing in a fully
@@ -213,7 +224,7 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
213224
r: ty::Region<'tcx>,
214225
) -> ty::Region<'tcx> {
215226
match r {
216-
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReEmpty | ty::ReStatic => r,
227+
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
217228
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
218229
_ => {
219230
// We only expect region names that the user can type.
@@ -320,8 +331,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
320331
| ty::ReEarlyBound(..)
321332
| ty::ReFree(_)
322333
| ty::ReScope(_)
334+
| ty::ReEmpty(_)
323335
| ty::RePlaceholder(..)
324-
| ty::ReEmpty
325336
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
326337

327338
ty::ReClosureBound(..) => {

src/librustc/infer/combine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
577577

578578
ty::RePlaceholder(..)
579579
| ty::ReVar(..)
580-
| ty::ReEmpty
580+
| ty::ReEmpty(_)
581581
| ty::ReStatic
582582
| ty::ReScope(..)
583583
| ty::ReEarlyBound(..)

src/librustc/infer/error_reporting/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ pub(super) fn note_and_explain_region(
138138
msg_span_from_free_region(tcx, region)
139139
}
140140

141-
ty::ReEmpty => ("the empty lifetime".to_owned(), None),
141+
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),
142+
143+
// uh oh, hope no user ever sees THIS
144+
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
142145

143146
ty::RePlaceholder(_) => (format!("any other region"), None),
144147

@@ -181,7 +184,8 @@ fn msg_span_from_free_region(
181184
msg_span_from_early_bound_and_free_regions(tcx, region)
182185
}
183186
ty::ReStatic => ("the static lifetime".to_owned(), None),
184-
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
187+
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
188+
ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
185189
_ => bug!("{:?}", region),
186190
}
187191
}
@@ -375,6 +379,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
375379
}
376380
}
377381

382+
RegionResolutionError::UpperBoundUniverseConflict(
383+
_,
384+
_,
385+
var_universe,
386+
sup_origin,
387+
sup_r,
388+
) => {
389+
assert!(sup_r.is_placeholder());
390+
391+
// Make a dummy value for the "sub region" --
392+
// this is the initial value of the
393+
// placeholder. In practice, we expect more
394+
// tailored errors that don't really use this
395+
// value.
396+
let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe));
397+
398+
self.report_placeholder_failure(
399+
region_scope_tree,
400+
sup_origin,
401+
sub_r,
402+
sup_r,
403+
)
404+
.emit();
405+
}
406+
378407
RegionResolutionError::MemberConstraintFailure {
379408
opaque_type_def_id,
380409
hidden_ty,
@@ -429,6 +458,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
429458
RegionResolutionError::GenericBoundFailure(..) => true,
430459
RegionResolutionError::ConcreteFailure(..)
431460
| RegionResolutionError::SubSupConflict(..)
461+
| RegionResolutionError::UpperBoundUniverseConflict(..)
432462
| RegionResolutionError::MemberConstraintFailure { .. } => false,
433463
};
434464

@@ -443,6 +473,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
443473
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
444474
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
445475
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
476+
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
446477
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
447478
});
448479
errors

src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ impl NiceRegionError<'me, 'tcx> {
107107
found.substs,
108108
)),
109109

110+
Some(RegionResolutionError::UpperBoundUniverseConflict(
111+
vid,
112+
_,
113+
_,
114+
SubregionOrigin::Subtype(box TypeTrace {
115+
cause,
116+
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
117+
}),
118+
sup_placeholder @ ty::RePlaceholder(_),
119+
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
120+
Some(self.tcx().mk_region(ty::ReVar(*vid))),
121+
cause,
122+
None,
123+
Some(*sup_placeholder),
124+
expected.def_id,
125+
expected.substs,
126+
found.substs,
127+
)),
128+
110129
Some(RegionResolutionError::ConcreteFailure(
111130
SubregionOrigin::Subtype(box TypeTrace {
112131
cause,

src/librustc/infer/freshen.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
130130
| ty::ReScope(_)
131131
| ty::ReVar(_)
132132
| ty::RePlaceholder(..)
133-
| ty::ReEmpty
133+
| ty::ReEmpty(_)
134134
| ty::ReErased => {
135135
// replace all free regions with 'erased
136136
self.tcx().lifetimes.re_erased

src/librustc/infer/lexical_region_resolve/mod.rs

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ pub enum RegionResolutionError<'tcx> {
8282
Region<'tcx>,
8383
),
8484

85+
/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
86+
/// cannot name the placeholder `'b`
87+
UpperBoundUniverseConflict(
88+
RegionVid,
89+
RegionVariableOrigin,
90+
ty::UniverseIndex, // the universe index of the region variable
91+
SubregionOrigin<'tcx>, // cause of the constraint
92+
Region<'tcx>, // the placeholder `'b`
93+
),
94+
8595
/// Indicates a failure of a `MemberConstraint`. These arise during
8696
/// impl trait processing explicitly -- basically, the impl trait's hidden type
8797
/// included some region that it was not supposed to.
@@ -149,7 +159,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
149159
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
150160
LexicalRegionResolutions {
151161
error_region: tcx.lifetimes.re_static,
152-
values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars()),
162+
values: IndexVec::from_fn_n(
163+
|vid| {
164+
let vid_universe = self.var_infos[vid].universe;
165+
let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe));
166+
VarValue::Value(re_empty)
167+
},
168+
self.num_vars(),
169+
),
153170
}
154171
}
155172

@@ -381,8 +398,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
381398
// This is a specialized version of the `lub_concrete_regions`
382399
// check below for a common case, here purely as an
383400
// optimization.
384-
if let ReEmpty = a_region {
385-
return false;
401+
let b_universe = self.var_infos[b_vid].universe;
402+
if let ReEmpty(a_universe) = a_region {
403+
if *a_universe == b_universe {
404+
return false;
405+
}
386406
}
387407

388408
let mut lub = self.lub_concrete_regions(a_region, cur_region);
@@ -399,7 +419,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
399419
// tighter bound than `'static`.
400420
//
401421
// (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
402-
let b_universe = self.var_infos[b_vid].universe;
403422
if let ty::RePlaceholder(p) = lub {
404423
if b_universe.cannot_name(p.universe) {
405424
lub = self.tcx().lifetimes.re_static;
@@ -445,7 +464,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
445464
self.lub_concrete_regions(a, b) == b
446465
}
447466

448-
/// Returns the smallest region `c` such that `a <= c` and `b <= c`.
467+
/// Returns the least-upper-bound of `a` and `b`; i.e., the
468+
/// smallest region `c` such that `a <= c` and `b <= c`.
469+
///
470+
/// Neither `a` nor `b` may be an inference variable (hence the
471+
/// term "concrete regions").
449472
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
450473
let r = match (a, b) {
451474
(&ty::ReClosureBound(..), _)
@@ -457,14 +480,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
457480
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
458481
}
459482

460-
(r @ &ReStatic, _) | (_, r @ &ReStatic) => {
461-
r // nothing lives longer than static
462-
}
463-
464-
(&ReEmpty, r) | (r, &ReEmpty) => {
465-
r // everything lives longer than empty
466-
}
467-
468483
(&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
469484
span_bug!(
470485
self.var_infos[v_id].origin.span(),
@@ -475,6 +490,41 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
475490
);
476491
}
477492

493+
(&ReStatic, _) | (_, &ReStatic) => {
494+
// nothing lives longer than static
495+
self.tcx().lifetimes.re_static
496+
}
497+
498+
(&ReEmpty(_), r @ ReEarlyBound(_))
499+
| (r @ ReEarlyBound(_), &ReEmpty(_))
500+
| (&ReEmpty(_), r @ ReFree(_))
501+
| (r @ ReFree(_), &ReEmpty(_))
502+
| (&ReEmpty(_), r @ ReScope(_))
503+
| (r @ ReScope(_), &ReEmpty(_)) => {
504+
// all empty regions are less than early-bound, free,
505+
// and scope regions
506+
r
507+
}
508+
509+
(&ReEmpty(a_ui), &ReEmpty(b_ui)) => {
510+
// empty regions are ordered according to the universe
511+
// they are associated with
512+
let ui = a_ui.min(b_ui);
513+
self.tcx().mk_region(ReEmpty(ui))
514+
}
515+
516+
(&ReEmpty(empty_ui), &RePlaceholder(placeholder))
517+
| (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => {
518+
// If this empty region is from a universe that can
519+
// name the placeholder, then the placeholder is
520+
// larger; otherwise, the only ancestor is `'static`.
521+
if empty_ui.can_name(placeholder.universe) {
522+
self.tcx().mk_region(RePlaceholder(placeholder))
523+
} else {
524+
self.tcx().lifetimes.re_static
525+
}
526+
}
527+
478528
(&ReEarlyBound(_), &ReScope(s_id))
479529
| (&ReScope(s_id), &ReEarlyBound(_))
480530
| (&ReFree(_), &ReScope(s_id))
@@ -800,6 +850,26 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
800850
}
801851
}
802852

853+
// If we have a scenario like `exists<'a> { forall<'b> { 'b:
854+
// 'a } }`, we wind up without any lower-bound -- all we have
855+
// are placeholders as upper bounds, but the universe of the
856+
// variable `'a` doesn't permit those placeholders.
857+
for upper_bound in &upper_bounds {
858+
if let ty::RePlaceholder(p) = upper_bound.region {
859+
if node_universe.cannot_name(p.universe) {
860+
let origin = self.var_infos[node_idx].origin.clone();
861+
errors.push(RegionResolutionError::UpperBoundUniverseConflict(
862+
node_idx,
863+
origin,
864+
node_universe,
865+
upper_bound.origin.clone(),
866+
upper_bound.region,
867+
));
868+
return;
869+
}
870+
}
871+
}
872+
803873
// Errors in earlier passes can yield error variables without
804874
// resolution errors here; delay ICE in favor of those errors.
805875
self.tcx().sess.delay_span_bug(
@@ -914,7 +984,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
914984
}
915985

916986
VerifyBound::IsEmpty => {
917-
if let ty::ReEmpty = min {
987+
if let ty::ReEmpty(_) = min {
918988
true
919989
} else {
920990
false

src/librustc/infer/opaque_types/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ pub fn unexpected_hidden_region_diagnostic(
611611
);
612612

613613
// Explain the region we are capturing.
614-
if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty = hidden_region {
614+
if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region {
615615
// Assuming regionck succeeded (*), we ought to always be
616616
// capturing *some* region from the fn header, and hence it
617617
// ought to be free. So under normal circumstances, we will go
@@ -843,7 +843,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
843843
.emit();
844844
}
845845
}
846-
self.tcx.lifetimes.re_empty
846+
self.tcx.lifetimes.re_root_empty
847847
}
848848
None => {
849849
self.tcx

src/librustc/infer/region_constraints/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,10 +795,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
795795
match *region {
796796
ty::ReScope(..)
797797
| ty::ReStatic
798-
| ty::ReEmpty
799798
| ty::ReErased
800799
| ty::ReFree(..)
801800
| ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
801+
ty::ReEmpty(ui) => ui,
802802
ty::RePlaceholder(placeholder) => placeholder.universe,
803803
ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
804804
ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),

src/librustc/ty/context.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,13 @@ pub struct CommonTypes<'tcx> {
173173
}
174174

175175
pub struct CommonLifetimes<'tcx> {
176-
pub re_empty: Region<'tcx>,
176+
/// ReEmpty in the root universe
177+
pub re_root_empty: Region<'tcx>,
178+
179+
/// ReStatic
177180
pub re_static: Region<'tcx>,
181+
182+
/// Erased region, used after type-checking
178183
pub re_erased: Region<'tcx>,
179184
}
180185

@@ -876,7 +881,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
876881
let mk = |r| interners.region.intern(r, |r| Interned(interners.arena.alloc(r))).0;
877882

878883
CommonLifetimes {
879-
re_empty: mk(RegionKind::ReEmpty),
884+
re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)),
880885
re_static: mk(RegionKind::ReStatic),
881886
re_erased: mk(RegionKind::ReErased),
882887
}

0 commit comments

Comments
 (0)