Skip to content

Commit

Permalink
index ReEmpty by universe
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikomatsakis committed Feb 6, 2020
1 parent b52414f commit 534f044
Show file tree
Hide file tree
Showing 22 changed files with 269 additions and 58 deletions.
5 changes: 4 additions & 1 deletion src/librustc/ich/impls_ty.rs
Expand Up @@ -63,9 +63,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
ty::ReErased | ty::ReStatic | ty::ReEmpty => {
ty::ReErased | ty::ReStatic => {
// No variant fields to hash for these ...
}
ty::ReEmpty(universe) => {
universe.hash_stable(hcx, hasher);
}
ty::ReLateBound(db, ty::BrAnon(i)) => {
db.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
Expand Down
17 changes: 14 additions & 3 deletions src/librustc/infer/canonical/canonicalizer.rs
Expand Up @@ -167,18 +167,29 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match r {
ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
ty::ReFree(_)
| ty::ReErased
| ty::ReStatic
| ty::ReEmpty(ty::UniverseIndex::ROOT)
| ty::ReEarlyBound(..) => r,

ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) },
r,
),

ty::ReVar(vid) => {
let universe = canonicalizer.region_var_universe(*vid);
canonicalizer.canonical_var_for_region(
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
r,
)
}

ty::ReEmpty(ui) => {
bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME
}

_ => {
// Other than `'static` or `'empty`, the query
// response should be executing in a fully
Expand Down Expand Up @@ -213,7 +224,7 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match r {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReEmpty | ty::ReStatic => r,
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
_ => {
// We only expect region names that the user can type.
Expand Down Expand Up @@ -320,8 +331,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
| ty::ReEarlyBound(..)
| ty::ReFree(_)
| ty::ReScope(_)
| ty::ReEmpty(_)
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),

ty::ReClosureBound(..) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/combine.rs
Expand Up @@ -577,7 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {

ty::RePlaceholder(..)
| ty::ReVar(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReStatic
| ty::ReScope(..)
| ty::ReEarlyBound(..)
Expand Down
35 changes: 33 additions & 2 deletions src/librustc/infer/error_reporting/mod.rs
Expand Up @@ -138,7 +138,10 @@ pub(super) fn note_and_explain_region(
msg_span_from_free_region(tcx, region)
}

ty::ReEmpty => ("the empty lifetime".to_owned(), None),
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),

// uh oh, hope no user ever sees THIS
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),

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

Expand Down Expand Up @@ -181,7 +184,8 @@ fn msg_span_from_free_region(
msg_span_from_early_bound_and_free_regions(tcx, region)
}
ty::ReStatic => ("the static lifetime".to_owned(), None),
ty::ReEmpty => ("an empty lifetime".to_owned(), None),
ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
_ => bug!("{:?}", region),
}
}
Expand Down Expand Up @@ -375,6 +379,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}

RegionResolutionError::UpperBoundUniverseConflict(
_,
_,
var_universe,
sup_origin,
sup_r,
) => {
assert!(sup_r.is_placeholder());

// Make a dummy value for the "sub region" --
// this is the initial value of the
// placeholder. In practice, we expect more
// tailored errors that don't really use this
// value.
let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe));

self.report_placeholder_failure(
region_scope_tree,
sup_origin,
sub_r,
sup_r,
)
.emit();
}

RegionResolutionError::MemberConstraintFailure {
opaque_type_def_id,
hidden_ty,
Expand Down Expand Up @@ -429,6 +458,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::GenericBoundFailure(..) => true,
RegionResolutionError::ConcreteFailure(..)
| RegionResolutionError::SubSupConflict(..)
| RegionResolutionError::UpperBoundUniverseConflict(..)
| RegionResolutionError::MemberConstraintFailure { .. } => false,
};

Expand All @@ -443,6 +473,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
});
errors
Expand Down
Expand Up @@ -107,6 +107,25 @@ impl NiceRegionError<'me, 'tcx> {
found.substs,
)),

Some(RegionResolutionError::UpperBoundUniverseConflict(
vid,
_,
_,
SubregionOrigin::Subtype(box TypeTrace {
cause,
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
}),
sup_placeholder @ ty::RePlaceholder(_),
)) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
Some(self.tcx().mk_region(ty::ReVar(*vid))),
cause,
None,
Some(*sup_placeholder),
expected.def_id,
expected.substs,
found.substs,
)),

Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::Subtype(box TypeTrace {
cause,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/freshen.rs
Expand Up @@ -130,7 +130,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
| ty::ReScope(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReErased => {
// replace all free regions with 'erased
self.tcx().lifetimes.re_erased
Expand Down
98 changes: 84 additions & 14 deletions src/librustc/infer/lexical_region_resolve/mod.rs
Expand Up @@ -82,6 +82,16 @@ pub enum RegionResolutionError<'tcx> {
Region<'tcx>,
),

/// Indicates a `'b: 'a` constraint where `'a` is in a universe that
/// cannot name the placeholder `'b`
UpperBoundUniverseConflict(
RegionVid,
RegionVariableOrigin,
ty::UniverseIndex, // the universe index of the region variable
SubregionOrigin<'tcx>, // cause of the constraint
Region<'tcx>, // the placeholder `'b`
),

/// Indicates a failure of a `MemberConstraint`. These arise during
/// impl trait processing explicitly -- basically, the impl trait's hidden type
/// included some region that it was not supposed to.
Expand Down Expand Up @@ -149,7 +159,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
error_region: tcx.lifetimes.re_static,
values: IndexVec::from_elem_n(VarValue::Value(tcx.lifetimes.re_empty), self.num_vars()),
values: IndexVec::from_fn_n(
|vid| {
let vid_universe = self.var_infos[vid].universe;
let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe));
VarValue::Value(re_empty)
},
self.num_vars(),
),
}
}

Expand Down Expand Up @@ -381,8 +398,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// This is a specialized version of the `lub_concrete_regions`
// check below for a common case, here purely as an
// optimization.
if let ReEmpty = a_region {
return false;
let b_universe = self.var_infos[b_vid].universe;
if let ReEmpty(a_universe) = a_region {
if *a_universe == b_universe {
return false;
}
}

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

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

(r @ &ReStatic, _) | (_, r @ &ReStatic) => {
r // nothing lives longer than static
}

(&ReEmpty, r) | (r, &ReEmpty) => {
r // everything lives longer than empty
}

(&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
span_bug!(
self.var_infos[v_id].origin.span(),
Expand All @@ -475,6 +490,41 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
);
}

(&ReStatic, _) | (_, &ReStatic) => {
// nothing lives longer than static
self.tcx().lifetimes.re_static
}

(&ReEmpty(_), r @ ReEarlyBound(_))
| (r @ ReEarlyBound(_), &ReEmpty(_))
| (&ReEmpty(_), r @ ReFree(_))
| (r @ ReFree(_), &ReEmpty(_))
| (&ReEmpty(_), r @ ReScope(_))
| (r @ ReScope(_), &ReEmpty(_)) => {
// all empty regions are less than early-bound, free,
// and scope regions
r
}

(&ReEmpty(a_ui), &ReEmpty(b_ui)) => {
// empty regions are ordered according to the universe
// they are associated with
let ui = a_ui.min(b_ui);
self.tcx().mk_region(ReEmpty(ui))
}

(&ReEmpty(empty_ui), &RePlaceholder(placeholder))
| (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => {
// If this empty region is from a universe that can
// name the placeholder, then the placeholder is
// larger; otherwise, the only ancestor is `'static`.
if empty_ui.can_name(placeholder.universe) {
self.tcx().mk_region(RePlaceholder(placeholder))
} else {
self.tcx().lifetimes.re_static
}
}

(&ReEarlyBound(_), &ReScope(s_id))
| (&ReScope(s_id), &ReEarlyBound(_))
| (&ReFree(_), &ReScope(s_id))
Expand Down Expand Up @@ -800,6 +850,26 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}

// If we have a scenario like `exists<'a> { forall<'b> { 'b:
// 'a } }`, we wind up without any lower-bound -- all we have
// are placeholders as upper bounds, but the universe of the
// variable `'a` doesn't permit those placeholders.
for upper_bound in &upper_bounds {
if let ty::RePlaceholder(p) = upper_bound.region {
if node_universe.cannot_name(p.universe) {
let origin = self.var_infos[node_idx].origin.clone();
errors.push(RegionResolutionError::UpperBoundUniverseConflict(
node_idx,
origin,
node_universe,
upper_bound.origin.clone(),
upper_bound.region,
));
return;
}
}
}

// Errors in earlier passes can yield error variables without
// resolution errors here; delay ICE in favor of those errors.
self.tcx().sess.delay_span_bug(
Expand Down Expand Up @@ -914,7 +984,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}

VerifyBound::IsEmpty => {
if let ty::ReEmpty = min {
if let ty::ReEmpty(_) = min {
true
} else {
false
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/infer/opaque_types/mod.rs
Expand Up @@ -611,7 +611,7 @@ pub fn unexpected_hidden_region_diagnostic(
);

// Explain the region we are capturing.
if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty = hidden_region {
if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region {
// Assuming regionck succeeded (*), we ought to always be
// capturing *some* region from the fn header, and hence it
// ought to be free. So under normal circumstances, we will go
Expand Down Expand Up @@ -843,7 +843,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
.emit();
}
}
self.tcx.lifetimes.re_empty
self.tcx.lifetimes.re_root_empty
}
None => {
self.tcx
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/region_constraints/mod.rs
Expand Up @@ -795,10 +795,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
match *region {
ty::ReScope(..)
| ty::ReStatic
| ty::ReEmpty
| ty::ReErased
| ty::ReFree(..)
| ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
ty::ReEmpty(ui) => ui,
ty::RePlaceholder(placeholder) => placeholder.universe,
ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
Expand Down
9 changes: 7 additions & 2 deletions src/librustc/ty/context.rs
Expand Up @@ -173,8 +173,13 @@ pub struct CommonTypes<'tcx> {
}

pub struct CommonLifetimes<'tcx> {
pub re_empty: Region<'tcx>,
/// ReEmpty in the root universe
pub re_root_empty: Region<'tcx>,

/// ReStatic
pub re_static: Region<'tcx>,

/// Erased region, used after type-checking
pub re_erased: Region<'tcx>,
}

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

CommonLifetimes {
re_empty: mk(RegionKind::ReEmpty),
re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)),
re_static: mk(RegionKind::ReStatic),
re_erased: mk(RegionKind::ReErased),
}
Expand Down

0 comments on commit 534f044

Please sign in to comment.