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.
This commit is contained in:
Niko Matsakis 2019-10-08 19:26:57 -04:00
parent b52414fede
commit 534f044425
22 changed files with 269 additions and 58 deletions

View File

@ -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);

View File

@ -167,11 +167,17 @@ 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(
@ -179,6 +185,11 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
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
@ -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.
@ -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(..) => {

View File

@ -577,7 +577,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
ty::RePlaceholder(..)
| ty::ReVar(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReStatic
| ty::ReScope(..)
| ty::ReEarlyBound(..)

View File

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

View File

@ -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,

View File

@ -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

View File

@ -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.
@ -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(),
),
}
}
@ -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);
@ -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;
@ -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(..), _)
@ -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(),
@ -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))
@ -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(
@ -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

View File

@ -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
@ -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

View File

@ -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),

View File

@ -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>,
}
@ -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),
}

View File

@ -1382,7 +1382,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false,
ty::ReStatic | ty::ReEmpty | ty::ReClosureBound(_) => true,
ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
}
}
}
@ -1464,10 +1464,14 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> {
p!(write("'static"));
return Ok(self);
}
ty::ReEmpty => {
ty::ReEmpty(ty::UniverseIndex::ROOT) => {
p!(write("'<empty>"));
return Ok(self);
}
ty::ReEmpty(ui) => {
p!(write("'<empty:{:?}>", ui));
return Ok(self);
}
// The user should never encounter these in unsubstituted form.
ty::ReClosureBound(vid) => {

View File

@ -108,7 +108,7 @@ impl fmt::Debug for ty::RegionKind {
ty::RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
ty::ReEmpty => write!(f, "ReEmpty"),
ty::ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui),
ty::ReErased => write!(f, "ReErased"),
}

View File

@ -1269,11 +1269,67 @@ rustc_index::newtype_index! {
pub type Region<'tcx> = &'tcx RegionKind;
/// Representation of regions.
/// Representation of (lexical) regions. Note that the NLL checker
/// uses a distinct representation of regions. For this reason, it
/// internally replaces all the regions with inference variables --
/// the index of the variable is then used to index into internal NLL
/// data structures. See `rustc_mir::borrow_check` module for more
/// information.
///
/// Unlike types, most region variants are "fictitious", not concrete,
/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
/// ones representing concrete regions.
/// ## The Region lattice within a given function
///
/// In general, the (lexical, and hence deprecated) region lattice
/// looks like
///
/// ```
/// static ----------+-----...------+ (greatest)
/// | | |
/// early-bound and | |
/// free regions | |
/// | | |
/// scope regions | |
/// | | |
/// empty(root) placeholder(U1) |
/// | / |
/// | / placeholder(Un)
/// empty(U1) -- /
/// | /
/// ... /
/// | /
/// empty(Un) -------- (smallest)
/// ```
///
/// Early-bound/free regions are the named lifetimes in scope from the
/// function declaration. They have relationships to one another
/// determined based on the declared relationships from the
/// function. They all collectively outlive the scope regions. (See
/// `RegionRelations` type, and particularly
/// `crate::infer::outlives::free_region_map::FreeRegionMap`.)
///
/// The scope regions are related to one another based on the AST
/// structure. (See `RegionRelations` type, and particularly the
/// `rustc::middle::region::ScopeTree`.)
///
/// Note that inference variables and bound regions are not included
/// in this diagram. In the case of inference variables, they should
/// be inferred to some other region from the diagram. In the case of
/// bound regions, they are excluded because they don't make sense to
/// include -- the diagram indicates the relationship between free
/// regions.
///
/// ## Inference variables
///
/// During region inference, we sometimes create inference variables,
/// represented as `ReVar`. These will be inferred by the code in
/// `infer::lexical_region_resolve` to some free region from the
/// lattice above (the minimal region that meets the
/// constraints).
///
/// During NLL checking, where regions are defined differently, we
/// also use `ReVar` -- in that case, the index is used to index into
/// the NLL region checker's data structures. The variable may in fact
/// represent either a free region or an inference variable, in that
/// case.
///
/// ## Bound Regions
///
@ -1356,14 +1412,13 @@ pub enum RegionKind {
/// Should not exist after typeck.
RePlaceholder(ty::PlaceholderRegion),
/// Empty lifetime is for data that is never accessed.
/// Bottom in the region lattice. We treat ReEmpty somewhat
/// specially; at least right now, we do not generate instances of
/// it during the GLB computations, but rather
/// generate an error instead. This is to improve error messages.
/// The only way to get an instance of ReEmpty is to have a region
/// variable with no constraints.
ReEmpty,
/// Empty lifetime is for data that is never accessed. We tag the
/// empty lifetime with a universe -- the idea is that we don't
/// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
/// Therefore, the `'empty` in a universe U is less than all
/// regions visible from U, but not less than regions not visible
/// from U.
ReEmpty(ty::UniverseIndex),
/// Erased region, used by trait selection, in MIR and during codegen.
ReErased,
@ -1612,7 +1667,7 @@ impl RegionKind {
RegionKind::ReStatic => true,
RegionKind::ReVar(..) => false,
RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
RegionKind::ReEmpty => false,
RegionKind::ReEmpty(_) => false,
RegionKind::ReErased => false,
RegionKind::ReClosureBound(..) => false,
}
@ -1695,7 +1750,7 @@ impl RegionKind {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
}
ty::ReEmpty | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => {
ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
ty::ReErased => {}
@ -1705,7 +1760,7 @@ impl RegionKind {
}
match *self {
ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (),
ty::ReStatic | ty::ReEmpty(_) | ty::ReErased | ty::ReLateBound(..) => (),
_ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES,
}

View File

@ -574,6 +574,14 @@ impl<I: Idx, T> IndexVec<I, T> {
IndexVec { raw: vec![elem; n], _marker: PhantomData }
}
/// Create an `IndexVec` with `n` elements, where the value of each
/// element is the result of `func(i)`
#[inline]
pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self {
let indices = (0..n).map(I::new);
Self::from_raw(indices.map(func).collect())
}
#[inline]
pub fn push(&mut self, d: T) -> I {
let idx = I::new(self.len());

View File

@ -291,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
| ty::ReScope(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReErased
| ty::ReClosureBound(..) => None,
}

View File

@ -160,7 +160,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) {
if let ty::ReEmpty = a {
// FIXME -- this is not the fix I would prefer
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a {
return;
}
let b = self.to_region_vid(b);
@ -175,7 +176,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
if let ty::ReEmpty = a {
// FIXME: I'd prefer if NLL had a notion of empty
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a {
return;
}
let type_test = self.verify_to_type_test(kind, a, bound);

View File

@ -333,7 +333,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
// `where Type:` is lowered to `where Type: 'empty` so that
// we check `Type` is well formed, but there's no use for
// this bound here.
if let ty::ReEmpty = r1 {
if let ty::ReEmpty(_) = r1 {
return;
}

View File

@ -246,9 +246,11 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> {
assert_eq!(a_bound.assert_bound_var(), b_bound.assert_bound_var());
}
(ty::ReStatic, ty::ReStatic)
| (ty::ReErased, ty::ReErased)
| (ty::ReEmpty, ty::ReEmpty) => (),
(ty::ReStatic, ty::ReStatic) | (ty::ReErased, ty::ReErased) => (),
(ty::ReEmpty(a_ui), ty::ReEmpty(b_ui)) => {
assert_eq!(a_ui, b_ui);
}
(&ty::ReFree(a_free), &ty::ReFree(b_free)) => {
assert_eq!(a_free, b_free);

View File

@ -2322,7 +2322,8 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
// compiler/tooling bugs from not handling WF predicates.
} else {
let span = bound_pred.bounded_ty.span;
let predicate = ty::OutlivesPredicate(ty, tcx.mk_region(ty::ReEmpty));
let re_root_empty = tcx.lifetimes.re_root_empty;
let predicate = ty::OutlivesPredicate(ty, re_root_empty);
predicates.push((
ty::Predicate::TypeOutlives(ty::Binder::dummy(predicate)),
span,

View File

@ -166,7 +166,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
//
// struct Bar<T>(<Self as Foo>::Type) where Self: ;
// struct Baz<'a>(&'a Self) where Self: ;
RegionKind::ReEmpty => false,
RegionKind::ReEmpty(_) => false,
// These regions don't appear in types from type declarations:
RegionKind::ReErased

View File

@ -453,7 +453,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
| ty::ReScope(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReErased => {
// We don't expect to see anything but 'static or bound
// regions when visiting member types or method types.

View File

@ -447,7 +447,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
| ty::ReScope(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty
| ty::ReEmpty(_)
| ty::ReClosureBound(_)
| ty::ReErased => {
debug!("cannot clean region {:?}", self);
@ -521,7 +521,7 @@ impl<'tcx> Clean<Option<WherePredicate>>
let ty::OutlivesPredicate(ref a, ref b) = *self;
match (a, b) {
(ty::ReEmpty, ty::ReEmpty) => {
(ty::ReEmpty(_), ty::ReEmpty(_)) => {
return None;
}
_ => {}
@ -539,7 +539,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
match lt {
ty::ReEmpty => return None,
ty::ReEmpty(_) => return None,
_ => {}
}