diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 2c460bcb72d8b..fcb0978111ecb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -500,7 +500,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Returns an iterator over all the region indices. - pub fn regions(&self) -> impl Iterator + '_ { + pub fn regions(&self) -> impl Iterator + 'tcx { self.definitions.indices() } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c43cf07b3ad0a..c9589a7048870 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -114,6 +114,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type DelaySpanBugEmitted = DelaySpanBugEmitted; type PredicateKind = ty::PredicateKind<'tcx>; type AllocId = crate::mir::interpret::AllocId; + + type EarlyBoundRegion = ty::EarlyBoundRegion; + type BoundRegion = ty::BoundRegion; + type FreeRegion = ty::FreeRegion; + type RegionVid = ty::RegionVid; + type PlaceholderRegion = ty::PlaceholderRegion; } /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s @@ -136,7 +142,7 @@ pub struct CtxtInterners<'tcx> { type_: InternedSet<'tcx, WithStableHash>>, substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, - region: InternedSet<'tcx, RegionKind>, + region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List>>>, predicate: InternedSet<'tcx, PredicateS<'tcx>>, @@ -2175,7 +2181,7 @@ macro_rules! direct_interners { } direct_interners! { - region: mk_region(RegionKind): Region -> Region<'tcx>, + region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>, const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>, const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>, @@ -2274,7 +2280,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Same a `self.mk_region(kind)`, but avoids accessing the interners if /// `*r == kind`. #[inline] - pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> { + pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { if *r == kind { r } else { self.mk_region(kind) } } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 42e5a05d63b76..88397a2bb56ba 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -11,7 +11,6 @@ use rustc_data_structures::stable_hasher::HashingControls; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_query_system::ich::StableHashingContext; use std::cell::RefCell; -use std::mem; impl<'a, 'tcx, T> HashStable> for &'tcx ty::List where @@ -102,43 +101,12 @@ impl<'a, 'tcx> HashStable> for ty::subst::GenericArgKin } } -impl<'a> HashStable> for ty::RegionKind { +impl<'a> HashStable> for ty::EarlyBoundRegion { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - ty::ReErased | ty::ReStatic => { - // No variant fields to hash for these ... - } - ty::ReEmpty(universe) => { - universe.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => { - db.hash_stable(hcx, hasher); - i.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name), .. }) => { - db.hash_stable(hcx, hasher); - def_id.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv, .. }) => { - db.hash_stable(hcx, hasher); - } - ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { - def_id.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - name.hash_stable(hcx, hasher); - } - ty::ReFree(ref free_region) => { - free_region.hash_stable(hcx, hasher); - } - ty::RePlaceholder(p) => { - p.hash_stable(hcx, hasher); - } - ty::ReVar(reg) => { - reg.hash_stable(hcx, hasher); - } - } + self.def_id.hash_stable(hcx, hasher); + self.index.hash_stable(hcx, hasher); + self.name.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6789f02c46abf..9c1972e81e19e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -55,6 +55,7 @@ use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::InferTy::*; +pub use rustc_type_ir::RegionKind::*; pub use rustc_type_ir::TyKind::*; pub use rustc_type_ir::*; @@ -80,7 +81,6 @@ pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::BoundRegionKind::*; -pub use self::sty::RegionKind::*; pub use self::sty::{ Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, @@ -1161,83 +1161,6 @@ impl<'tcx> OpaqueHiddenType<'tcx> { } } -rustc_index::newtype_index! { - /// "Universes" are used during type- and trait-checking in the - /// presence of `for<..>` binders to control what sets of names are - /// visible. Universes are arranged into a tree: the root universe - /// contains names that are always visible. Each child then adds a new - /// set of names that are visible, in addition to those of its parent. - /// We say that the child universe "extends" the parent universe with - /// new names. - /// - /// To make this more concrete, consider this program: - /// - /// ```ignore (illustrative) - /// struct Foo { } - /// fn bar(x: T) { - /// let y: for<'a> fn(&'a u8, Foo) = ...; - /// } - /// ``` - /// - /// The struct name `Foo` is in the root universe U0. But the type - /// parameter `T`, introduced on `bar`, is in an extended universe U1 - /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside - /// of `bar`, we cannot name `T`. Then, within the type of `y`, the - /// region `'a` is in a universe U2 that extends U1, because we can - /// name it inside the fn type but not outside. - /// - /// Universes are used to do type- and trait-checking around these - /// "forall" binders (also called **universal quantification**). The - /// idea is that when, in the body of `bar`, we refer to `T` as a - /// type, we aren't referring to any type in particular, but rather a - /// kind of "fresh" type that is distinct from all other types we have - /// actually declared. This is called a **placeholder** type, and we - /// use universes to talk about this. In other words, a type name in - /// universe 0 always corresponds to some "ground" type that the user - /// declared, but a type name in a non-zero universe is a placeholder - /// type -- an idealized representative of "types in general" that we - /// use for checking generic functions. - pub struct UniverseIndex { - derive [HashStable] - DEBUG_FORMAT = "U{}", - } -} - -impl UniverseIndex { - pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0); - - /// Returns the "next" universe index in order -- this new index - /// is considered to extend all previous universes. This - /// corresponds to entering a `forall` quantifier. So, for - /// example, suppose we have this type in universe `U`: - /// - /// ```ignore (illustrative) - /// for<'a> fn(&'a u32) - /// ``` - /// - /// Once we "enter" into this `for<'a>` quantifier, we are in a - /// new universe that extends `U` -- in this new universe, we can - /// name the region `'a`, but that region was not nameable from - /// `U` because it was not in scope there. - pub fn next_universe(self) -> UniverseIndex { - UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) - } - - /// Returns `true` if `self` can name a name from `other` -- in other words, - /// if the set of names in `self` is a superset of those in - /// `other` (`self >= other`). - pub fn can_name(self, other: UniverseIndex) -> bool { - self.private >= other.private - } - - /// Returns `true` if `self` cannot name some names from `other` -- in other - /// words, if the set of names in `self` is a strict subset of - /// those in `other` (`self < other`). - pub fn cannot_name(self, other: UniverseIndex) -> bool { - self.private < other.private - } -} - /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 7ae23d371e59f..d57cf8f014911 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -57,7 +57,7 @@ pub trait Printer<'tcx>: Sized { self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref) } - fn print_region(self, region: ty::Region<'_>) -> Result; + fn print_region(self, region: ty::Region<'tcx>) -> Result; fn print_type(self, ty: Ty<'tcx>) -> Result; @@ -291,7 +291,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new()) } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> { +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> { type Output = P::Region; type Error = P::Error; fn print(&self, cx: P) -> Result { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 58dab0f96aba5..97e5a4983fcd1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -182,7 +182,7 @@ impl<'tcx> RegionHighlightMode<'tcx> { } /// Returns `Some(n)` with the number to use for the given region, if any. - fn region_highlighted(&self, region: ty::Region<'_>) -> Option { + fn region_highlighted(&self, region: ty::Region<'tcx>) -> Option { self.highlight_regions.iter().find_map(|h| match h { Some((r, n)) if *r == region => Some(*n), _ => None, @@ -276,7 +276,7 @@ pub trait PrettyPrinter<'tcx>: /// Returns `true` if the region should be printed in /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. /// This is typically the case for all non-`'_` regions. - fn should_print_region(&self, region: ty::Region<'_>) -> bool; + fn should_print_region(&self, region: ty::Region<'tcx>) -> bool; // Defaults (should not be overridden): @@ -1706,7 +1706,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self.default_print_def_path(def_id, substs) } - fn print_region(self, region: ty::Region<'_>) -> Result { + fn print_region(self, region: ty::Region<'tcx>) -> Result { self.pretty_print_region(region) } @@ -1911,7 +1911,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { Ok(inner) } - fn should_print_region(&self, region: ty::Region<'_>) -> bool { + fn should_print_region(&self, region: ty::Region<'tcx>) -> bool { let highlight = self.region_highlight_mode; if highlight.region_highlighted(region).is_some() { return true; @@ -1978,8 +1978,8 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { } // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`. -impl FmtPrinter<'_, '_> { - pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result { +impl<'tcx> FmtPrinter<'_, 'tcx> { + pub fn pretty_print_region(mut self, region: ty::Region<'tcx>) -> Result { define_scoped_cx!(self); // Watch out for region highlights. @@ -2383,15 +2383,6 @@ macro_rules! define_print_and_forward_display { }; } -// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting. -impl<'tcx> fmt::Display for ty::Region<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ty::tls::with(|tcx| { - f.write_str(&self.print(FmtPrinter::new(tcx, Namespace::TypeNS))?.into_buffer()) - }) - } -} - /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait path. That is, it will print `Trait` instead of /// `>`. @@ -2456,6 +2447,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { } forward_display_to_print! { + ty::Region<'tcx>, Ty<'tcx>, &'tcx ty::List>>, ty::Const<'tcx>, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 961792260e410..8ba5b882fdd57 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -81,30 +81,6 @@ impl fmt::Debug for ty::BoundRegionKind { } } -impl fmt::Debug for ty::RegionKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::ReEarlyBound(ref data) => write!(f, "ReEarlyBound({}, {})", data.index, data.name), - - ty::ReLateBound(binder_id, ref bound_region) => { - write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region) - } - - ty::ReFree(ref fr) => fr.fmt(f), - - ty::ReStatic => write!(f, "ReStatic"), - - ty::ReVar(ref vid) => vid.fmt(f), - - ty::RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder), - - ty::ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui), - - ty::ReErased => write!(f, "ReErased"), - } - } -} - impl fmt::Debug for ty::FreeRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index cc85859e1cc0a..296442e243607 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -29,11 +29,13 @@ use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; +use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; // Re-export the `TyKind` from `rustc_type_ir` here for convenience #[rustc_diagnostic_item = "TyKind"] pub type TyKind<'tcx> = IrTyKind>; +pub type RegionKind<'tcx> = IrRegionKind>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, Lift)] @@ -1308,12 +1310,12 @@ impl ParamConst { /// Use this rather than `RegionKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>); +pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); impl<'tcx> Deref for Region<'tcx> { - type Target = RegionKind; + type Target = RegionKind<'tcx>; - fn deref(&self) -> &RegionKind { + fn deref(&self) -> &RegionKind<'tcx> { &self.0.0 } } @@ -1324,157 +1326,19 @@ impl<'tcx> fmt::Debug for Region<'tcx> { } } -/// Representation of 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_const_eval::borrow_check` -/// module for more information. -/// -/// Note: operations are on the wrapper `Region` type, which is interned, -/// rather than this type. -/// -/// ## The Region lattice within a given function -/// -/// In general, the region lattice looks like -/// -/// ```text -/// static ----------+-----...------+ (greatest) -/// | | | -/// early-bound and | | -/// free 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. -/// -/// 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 -/// -/// These are regions that are stored behind a binder and must be substituted -/// with some concrete region before being used. There are two kind of -/// bound regions: early-bound, which are bound in an item's `Generics`, -/// and are substituted by an `InternalSubsts`, and late-bound, which are part of -/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by -/// the likes of `liberate_late_bound_regions`. The distinction exists -/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. -/// -/// Unlike `Param`s, bound regions are not supposed to exist "in the wild" -/// outside their binder, e.g., in types passed to type inference, and -/// should first be substituted (by placeholder regions, free regions, -/// or region variables). -/// -/// ## Placeholder and Free Regions -/// -/// One often wants to work with bound regions without knowing their precise -/// identity. For example, when checking a function, the lifetime of a borrow -/// can end up being assigned to some region parameter. In these cases, -/// it must be ensured that bounds on the region can't be accidentally -/// assumed without being checked. -/// -/// To do this, we replace the bound regions with placeholder markers, -/// which don't satisfy any relation not explicitly provided. -/// -/// There are two kinds of placeholder regions in rustc: `ReFree` and -/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed -/// to be used. These also support explicit bounds: both the internally-stored -/// *scope*, which the region is assumed to outlive, as well as other -/// relations stored in the `FreeRegionMap`. Note that these relations -/// aren't checked when you `make_subregion` (or `eq_types`), only by -/// `resolve_regions_and_report_errors`. -/// -/// When working with higher-ranked types, some region relations aren't -/// yet known, so you can't just call `resolve_regions_and_report_errors`. -/// `RePlaceholder` is designed for this purpose. In these contexts, -/// there's also the risk that some inference variable laying around will -/// get unified with your placeholder region: if you want to check whether -/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` -/// with a placeholder region `'%a`, the variable `'_` would just be -/// instantiated to the placeholder region `'%a`, which is wrong because -/// the inference variable is supposed to satisfy the relation -/// *for every value of the placeholder region*. To ensure that doesn't -/// happen, you can use `leak_check`. This is more clearly explained -/// by the [rustc dev guide]. -/// -/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ -/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html -#[derive(Clone, PartialEq, Eq, Hash, Copy, TyEncodable, TyDecodable, PartialOrd, Ord)] -pub enum RegionKind { - /// Region bound in a type or fn declaration which will be - /// substituted 'early' -- that is, at the same time when type - /// parameters are substituted. - ReEarlyBound(EarlyBoundRegion), - - /// Region bound in a function scope, which will be substituted when the - /// function is called. - ReLateBound(ty::DebruijnIndex, BoundRegion), - - /// When checking a function body, the types of all arguments and so forth - /// that refer to bound region parameters are modified to refer to free - /// region parameters. - ReFree(FreeRegion), - - /// Static data that has an "infinite" lifetime. Top in the region lattice. - ReStatic, - - /// A region variable. Should not exist outside of type inference. - ReVar(RegionVid), - - /// A placeholder region -- basically, the higher-ranked version of `ReFree`. - /// Should not exist outside of type inference. - RePlaceholder(ty::PlaceholderRegion), - - /// 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, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] pub struct EarlyBoundRegion { pub def_id: DefId, pub index: u32, pub name: Symbol, } +impl fmt::Debug for EarlyBoundRegion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}, {}", self.index, self.name) + } +} + /// A **`const`** **v**ariable **ID**. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] pub struct ConstVid<'tcx> { @@ -1590,7 +1454,7 @@ impl<'tcx> PolyExistentialProjection<'tcx> { /// Region utilities impl<'tcx> Region<'tcx> { - pub fn kind(self) -> RegionKind { + pub fn kind(self) -> RegionKind<'tcx> { *self.0.0 } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index ca29dd7c08f45..ad2898ccd67ba 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -82,7 +82,7 @@ impl<'tcx> GenericArgKind<'tcx> { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0); - (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize) + (REGION_TAG, lt.0.0 as *const ty::RegionKind<'tcx> as usize) } GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. @@ -153,7 +153,7 @@ impl<'tcx> GenericArg<'tcx> { unsafe { match ptr & TAG_MASK { REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked( - &*((ptr & !TAG_MASK) as *const ty::RegionKind), + &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>), ))), TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( &*((ptr & !TAG_MASK) as *const WithStableHash>), diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b9c9581312139..38846031badab 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -574,7 +574,7 @@ impl<'tcx> TyCtxt<'tcx> { self, closure_def_id: DefId, closure_substs: SubstsRef<'tcx>, - env_region: ty::RegionKind, + env_region: ty::RegionKind<'tcx>, ) -> Option> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); let closure_kind_ty = closure_substs.as_closure().kind_ty(); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 6380001b57c08..cb1602816ae5e 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -42,6 +42,12 @@ pub trait Interner { type DelaySpanBugEmitted: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; type PredicateKind: Clone + Debug + Hash + PartialEq + Eq; type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; + + type EarlyBoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; + type BoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; + type FreeRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; + type RegionVid: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; + type PlaceholderRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; } pub trait InternAs { @@ -767,3 +773,85 @@ impl fmt::Display for InferTy { } } } + +rustc_index::newtype_index! { + /// "Universes" are used during type- and trait-checking in the + /// presence of `for<..>` binders to control what sets of names are + /// visible. Universes are arranged into a tree: the root universe + /// contains names that are always visible. Each child then adds a new + /// set of names that are visible, in addition to those of its parent. + /// We say that the child universe "extends" the parent universe with + /// new names. + /// + /// To make this more concrete, consider this program: + /// + /// ```ignore (illustrative) + /// struct Foo { } + /// fn bar(x: T) { + /// let y: for<'a> fn(&'a u8, Foo) = ...; + /// } + /// ``` + /// + /// The struct name `Foo` is in the root universe U0. But the type + /// parameter `T`, introduced on `bar`, is in an extended universe U1 + /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside + /// of `bar`, we cannot name `T`. Then, within the type of `y`, the + /// region `'a` is in a universe U2 that extends U1, because we can + /// name it inside the fn type but not outside. + /// + /// Universes are used to do type- and trait-checking around these + /// "forall" binders (also called **universal quantification**). The + /// idea is that when, in the body of `bar`, we refer to `T` as a + /// type, we aren't referring to any type in particular, but rather a + /// kind of "fresh" type that is distinct from all other types we have + /// actually declared. This is called a **placeholder** type, and we + /// use universes to talk about this. In other words, a type name in + /// universe 0 always corresponds to some "ground" type that the user + /// declared, but a type name in a non-zero universe is a placeholder + /// type -- an idealized representative of "types in general" that we + /// use for checking generic functions. + pub struct UniverseIndex { + DEBUG_FORMAT = "U{}", + } +} + +impl UniverseIndex { + pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0); + + /// Returns the "next" universe index in order -- this new index + /// is considered to extend all previous universes. This + /// corresponds to entering a `forall` quantifier. So, for + /// example, suppose we have this type in universe `U`: + /// + /// ```ignore (illustrative) + /// for<'a> fn(&'a u32) + /// ``` + /// + /// Once we "enter" into this `for<'a>` quantifier, we are in a + /// new universe that extends `U` -- in this new universe, we can + /// name the region `'a`, but that region was not nameable from + /// `U` because it was not in scope there. + pub fn next_universe(self) -> UniverseIndex { + UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) + } + + /// Returns `true` if `self` can name a name from `other` -- in other words, + /// if the set of names in `self` is a superset of those in + /// `other` (`self >= other`). + pub fn can_name(self, other: UniverseIndex) -> bool { + self.private >= other.private + } + + /// Returns `true` if `self` cannot name some names from `other` -- in other + /// words, if the set of names in `self` is a strict subset of + /// those in `other` (`self < other`). + pub fn cannot_name(self, other: UniverseIndex) -> bool { + self.private < other.private + } +} + +impl HashStable for UniverseIndex { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.private.hash_stable(ctx, hasher); + } +} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 9407218439993..5cd2901324a2e 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -10,7 +10,9 @@ use crate::Interner; use crate::TyDecoder; use crate::TyEncoder; use crate::UintTy; +use crate::UniverseIndex; +use self::RegionKind::*; use self::TyKind::*; use rustc_data_structures::stable_hasher::HashStable; @@ -20,8 +22,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable}; /// /// Types written by the user start out as `hir::TyKind` and get /// converted to this representation using `AstConv::ast_ty_to_ty`. -/// -/// The `HashStable` implementation for this type is defined in `rustc_query_system::ich`. #[rustc_diagnostic_item = "IrTyKind"] pub enum TyKind { /// The primitive boolean type. Written as `bool`. @@ -202,7 +202,7 @@ impl TyKind { // This is manually implemented for `TyKind` because `std::mem::discriminant` // returns an opaque value that is `PartialEq` but not `PartialOrd` #[inline] -const fn discriminant(value: &TyKind) -> usize { +const fn tykind_discriminant(value: &TyKind) -> usize { match value { Bool => 0, Char => 1, @@ -273,8 +273,8 @@ impl Clone for TyKind { impl PartialEq for TyKind { #[inline] fn eq(&self, other: &TyKind) -> bool { - let __self_vi = discriminant(self); - let __arg_1_vi = discriminant(other); + let __self_vi = tykind_discriminant(self); + let __arg_1_vi = tykind_discriminant(other); if __self_vi == __arg_1_vi { match (&*self, &*other) { (&Int(ref __self_0), &Int(ref __arg_1_0)) => __self_0 == __arg_1_0, @@ -345,8 +345,8 @@ impl PartialOrd for TyKind { impl Ord for TyKind { #[inline] fn cmp(&self, other: &TyKind) -> Ordering { - let __self_vi = discriminant(self); - let __arg_1_vi = discriminant(other); + let __self_vi = tykind_discriminant(self); + let __arg_1_vi = tykind_discriminant(other); if __self_vi == __arg_1_vi { match (&*self, &*other) { (&Int(ref __self_0), &Int(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), @@ -444,109 +444,109 @@ impl hash::Hash for TyKind { fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () { match (&*self,) { (&Int(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Uint(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Float(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Adt(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Foreign(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Array(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Slice(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&RawPtr(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Ref(ref __self_0, ref __self_1, ref __self_2),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state); hash::Hash::hash(__self_2, state) } (&FnDef(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&FnPtr(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Dynamic(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Closure(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Generator(ref __self_0, ref __self_1, ref __self_2),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state); hash::Hash::hash(__self_2, state) } (&GeneratorWitness(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Tuple(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Projection(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Opaque(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Param(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Bound(ref __self_0, ref __self_1),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); hash::Hash::hash(__self_1, state) } (&Placeholder(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Infer(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } (&Error(ref __self_0),) => { - hash::Hash::hash(&discriminant(self), state); + hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } - _ => hash::Hash::hash(&discriminant(self), state), + _ => hash::Hash::hash(&tykind_discriminant(self), state), } } } @@ -716,7 +716,7 @@ where I::AllocId: Encodable, { fn encode(&self, e: &mut E) { - let disc = discriminant(self); + let disc = tykind_discriminant(self); match self { Bool => e.emit_enum_variant(disc, |_| {}), Char => e.emit_enum_variant(disc, |_| {}), @@ -991,3 +991,439 @@ where } } } + +/// Representation of 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_const_eval::borrow_check` +/// module for more information. +/// +/// Note: operations are on the wrapper `Region` type, which is interned, +/// rather than this type. +/// +/// ## The Region lattice within a given function +/// +/// In general, the region lattice looks like +/// +/// ```text +/// static ----------+-----...------+ (greatest) +/// | | | +/// early-bound and | | +/// free 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. +/// +/// 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 +/// +/// These are regions that are stored behind a binder and must be substituted +/// with some concrete region before being used. There are two kind of +/// bound regions: early-bound, which are bound in an item's `Generics`, +/// and are substituted by an `InternalSubsts`, and late-bound, which are part of +/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by +/// the likes of `liberate_late_bound_regions`. The distinction exists +/// because higher-ranked lifetimes aren't supported in all places. See [1][2]. +/// +/// Unlike `Param`s, bound regions are not supposed to exist "in the wild" +/// outside their binder, e.g., in types passed to type inference, and +/// should first be substituted (by placeholder regions, free regions, +/// or region variables). +/// +/// ## Placeholder and Free Regions +/// +/// One often wants to work with bound regions without knowing their precise +/// identity. For example, when checking a function, the lifetime of a borrow +/// can end up being assigned to some region parameter. In these cases, +/// it must be ensured that bounds on the region can't be accidentally +/// assumed without being checked. +/// +/// To do this, we replace the bound regions with placeholder markers, +/// which don't satisfy any relation not explicitly provided. +/// +/// There are two kinds of placeholder regions in rustc: `ReFree` and +/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed +/// to be used. These also support explicit bounds: both the internally-stored +/// *scope*, which the region is assumed to outlive, as well as other +/// relations stored in the `FreeRegionMap`. Note that these relations +/// aren't checked when you `make_subregion` (or `eq_types`), only by +/// `resolve_regions_and_report_errors`. +/// +/// When working with higher-ranked types, some region relations aren't +/// yet known, so you can't just call `resolve_regions_and_report_errors`. +/// `RePlaceholder` is designed for this purpose. In these contexts, +/// there's also the risk that some inference variable laying around will +/// get unified with your placeholder region: if you want to check whether +/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` +/// with a placeholder region `'%a`, the variable `'_` would just be +/// instantiated to the placeholder region `'%a`, which is wrong because +/// the inference variable is supposed to satisfy the relation +/// *for every value of the placeholder region*. To ensure that doesn't +/// happen, you can use `leak_check`. This is more clearly explained +/// by the [rustc dev guide]. +/// +/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ +/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html +pub enum RegionKind { + /// Region bound in a type or fn declaration which will be + /// substituted 'early' -- that is, at the same time when type + /// parameters are substituted. + ReEarlyBound(I::EarlyBoundRegion), + + /// Region bound in a function scope, which will be substituted when the + /// function is called. + ReLateBound(DebruijnIndex, I::BoundRegion), + + /// When checking a function body, the types of all arguments and so forth + /// that refer to bound region parameters are modified to refer to free + /// region parameters. + ReFree(I::FreeRegion), + + /// Static data that has an "infinite" lifetime. Top in the region lattice. + ReStatic, + + /// A region variable. Should not exist outside of type inference. + ReVar(I::RegionVid), + + /// A placeholder region -- basically, the higher-ranked version of `ReFree`. + /// Should not exist outside of type inference. + RePlaceholder(I::PlaceholderRegion), + + /// 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(UniverseIndex), + + /// Erased region, used by trait selection, in MIR and during codegen. + ReErased, +} + +// This is manually implemented for `RegionKind` because `std::mem::discriminant` +// returns an opaque value that is `PartialEq` but not `PartialOrd` +#[inline] +const fn regionkind_discriminant(value: &RegionKind) -> usize { + match value { + ReEarlyBound(_) => 0, + ReLateBound(_, _) => 1, + ReFree(_) => 2, + ReStatic => 3, + ReVar(_) => 4, + RePlaceholder(_) => 5, + ReEmpty(_) => 6, + ReErased => 7, + } +} + +// This is manually implemented because a derive would require `I: Copy` +impl Copy for RegionKind +where + I::EarlyBoundRegion: Copy, + I::BoundRegion: Copy, + I::FreeRegion: Copy, + I::RegionVid: Copy, + I::PlaceholderRegion: Copy, +{ +} + +// This is manually implemented because a derive would require `I: Clone` +impl Clone for RegionKind { + fn clone(&self) -> Self { + match self { + ReEarlyBound(a) => ReEarlyBound(a.clone()), + ReLateBound(a, b) => ReLateBound(a.clone(), b.clone()), + ReFree(a) => ReFree(a.clone()), + ReStatic => ReStatic, + ReVar(a) => ReVar(a.clone()), + RePlaceholder(a) => RePlaceholder(a.clone()), + ReEmpty(a) => ReEmpty(a.clone()), + ReErased => ReErased, + } + } +} + +// This is manually implemented because a derive would require `I: PartialEq` +impl PartialEq for RegionKind { + #[inline] + fn eq(&self, other: &RegionKind) -> bool { + let __self_vi = regionkind_discriminant(self); + let __arg_1_vi = regionkind_discriminant(other); + if __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => { + __self_0 == __arg_1_0 + } + ( + &ReLateBound(ref __self_0, ref __self_1), + &ReLateBound(ref __arg_1_0, ref __arg_1_1), + ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1, + (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => __self_0 == __arg_1_0, + (&ReStatic, &ReStatic) => true, + (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => __self_0 == __arg_1_0, + (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { + __self_0 == __arg_1_0 + } + (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => __self_0 == __arg_1_0, + (&ReErased, &ReErased) => true, + _ => true, + } + } else { + false + } + } +} + +// This is manually implemented because a derive would require `I: Eq` +impl Eq for RegionKind {} + +// This is manually implemented because a derive would require `I: PartialOrd` +impl PartialOrd for RegionKind { + #[inline] + fn partial_cmp(&self, other: &RegionKind) -> Option { + Some(Ord::cmp(self, other)) + } +} + +// This is manually implemented because a derive would require `I: Ord` +impl Ord for RegionKind { + #[inline] + fn cmp(&self, other: &RegionKind) -> Ordering { + let __self_vi = regionkind_discriminant(self); + let __arg_1_vi = regionkind_discriminant(other); + if __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => { + Ord::cmp(__self_0, __arg_1_0) + } + ( + &ReLateBound(ref __self_0, ref __self_1), + &ReLateBound(ref __arg_1_0, ref __arg_1_1), + ) => match Ord::cmp(__self_0, __arg_1_0) { + Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), + cmp => cmp, + }, + (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), + (&ReStatic, &ReStatic) => Ordering::Equal, + (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), + (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => { + Ord::cmp(__self_0, __arg_1_0) + } + (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), + (&ReErased, &ReErased) => Ordering::Equal, + _ => Ordering::Equal, + } + } else { + Ord::cmp(&__self_vi, &__arg_1_vi) + } + } +} + +// This is manually implemented because a derive would require `I: Hash` +impl hash::Hash for RegionKind { + fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () { + match (&*self,) { + (&ReEarlyBound(ref __self_0),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state) + } + (&ReLateBound(ref __self_0, ref __self_1),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state); + hash::Hash::hash(__self_1, state) + } + (&ReFree(ref __self_0),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state) + } + (&ReStatic,) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + } + (&ReVar(ref __self_0),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state) + } + (&RePlaceholder(ref __self_0),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state) + } + (&ReEmpty(ref __self_0),) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + hash::Hash::hash(__self_0, state) + } + (&ReErased,) => { + hash::Hash::hash(®ionkind_discriminant(self), state); + } + } + } +} + +// This is manually implemented because a derive would require `I: Debug` +impl fmt::Debug for RegionKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ReEarlyBound(ref data) => write!(f, "ReEarlyBound({:?})", data), + + ReLateBound(binder_id, ref bound_region) => { + write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region) + } + + ReFree(ref fr) => fr.fmt(f), + + ReStatic => write!(f, "ReStatic"), + + ReVar(ref vid) => vid.fmt(f), + + RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder), + + ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui), + + ReErased => write!(f, "ReErased"), + } + } +} + +// This is manually implemented because a derive would require `I: Encodable` +impl Encodable for RegionKind +where + I::EarlyBoundRegion: Encodable, + I::BoundRegion: Encodable, + I::FreeRegion: Encodable, + I::RegionVid: Encodable, + I::PlaceholderRegion: Encodable, +{ + fn encode(&self, e: &mut E) { + let disc = regionkind_discriminant(self); + match self { + ReEarlyBound(a) => e.emit_enum_variant(disc, |e| { + a.encode(e); + }), + ReLateBound(a, b) => e.emit_enum_variant(disc, |e| { + a.encode(e); + b.encode(e); + }), + ReFree(a) => e.emit_enum_variant(disc, |e| { + a.encode(e); + }), + ReStatic => e.emit_enum_variant(disc, |_| {}), + ReVar(a) => e.emit_enum_variant(disc, |e| { + a.encode(e); + }), + RePlaceholder(a) => e.emit_enum_variant(disc, |e| { + a.encode(e); + }), + ReEmpty(a) => e.emit_enum_variant(disc, |e| { + a.encode(e); + }), + ReErased => e.emit_enum_variant(disc, |_| {}), + } + } +} + +// This is manually implemented because a derive would require `I: Decodable` +impl> Decodable for RegionKind +where + I::EarlyBoundRegion: Decodable, + I::BoundRegion: Decodable, + I::FreeRegion: Decodable, + I::RegionVid: Decodable, + I::PlaceholderRegion: Decodable, +{ + fn decode(d: &mut D) -> Self { + match Decoder::read_usize(d) { + 0 => ReEarlyBound(Decodable::decode(d)), + 1 => ReLateBound(Decodable::decode(d), Decodable::decode(d)), + 2 => ReFree(Decodable::decode(d)), + 3 => ReStatic, + 4 => ReVar(Decodable::decode(d)), + 5 => RePlaceholder(Decodable::decode(d)), + 6 => ReEmpty(Decodable::decode(d)), + 7 => ReErased, + _ => panic!( + "{}", + format!( + "invalid enum variant tag while decoding `{}`, expected 0..{}", + "RegionKind", 8, + ) + ), + } + } +} + +// This is not a derived impl because a derive would require `I: HashStable` +impl HashStable for RegionKind +where + I::EarlyBoundRegion: HashStable, + I::BoundRegion: HashStable, + I::FreeRegion: HashStable, + I::RegionVid: HashStable, + I::PlaceholderRegion: HashStable, +{ + #[inline] + fn hash_stable( + &self, + hcx: &mut CTX, + hasher: &mut rustc_data_structures::stable_hasher::StableHasher, + ) { + std::mem::discriminant(self).hash_stable(hcx, hasher); + match self { + ReErased | ReStatic => { + // No variant fields to hash for these ... + } + ReEmpty(universe) => { + universe.hash_stable(hcx, hasher); + } + ReLateBound(db, br) => { + db.hash_stable(hcx, hasher); + br.hash_stable(hcx, hasher); + } + ReEarlyBound(eb) => { + eb.hash_stable(hcx, hasher); + } + ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } + RePlaceholder(p) => { + p.hash_stable(hcx, hasher); + } + ReVar(reg) => { + reg.hash_stable(hcx, hasher); + } + } + } +}