Auto merge of #79169 - LeSeulArtichaut:ty-lib, r=nikomatsakis
Create `rustc_type_ir`
Decided to start small 😄
This PR creates a `rustc_type_ir` crate as part of the WG-Traits plan to create a shared type library.
~~There already exists a `rustc_ty` crate, so I named the new crate `rustc_ty_library`. However I think it would make sense to rename the current `rustc_ty` to something else (e.g. `rustc_ty_passes`) to free the name for this new crate.~~
r? `@jackh726`
This commit is contained in:
commit
3f2088aa60
11
Cargo.lock
11
Cargo.lock
@ -3932,6 +3932,7 @@ dependencies = [
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_type_ir",
|
||||
"smallvec 1.4.2",
|
||||
"tracing",
|
||||
]
|
||||
@ -4266,6 +4267,16 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_type_ir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
"rustc_serialize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_typeck"
|
||||
version = "0.0.0"
|
||||
|
@ -30,3 +30,4 @@ chalk-ir = "0.36.0"
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
measureme = "9.0.0"
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
|
@ -56,7 +56,7 @@ pub use self::sty::InferTy::*;
|
||||
pub use self::sty::RegionKind;
|
||||
pub use self::sty::RegionKind::*;
|
||||
pub use self::sty::TyKind::*;
|
||||
pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST};
|
||||
pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar};
|
||||
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
|
||||
pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
|
||||
pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
|
||||
@ -67,6 +67,7 @@ pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
|
||||
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
|
||||
pub use self::sty::{PolyTraitRef, TraitRef, TyKind};
|
||||
pub use crate::ty::diagnostics::*;
|
||||
pub use rustc_type_ir::{DebruijnIndex, TypeFlags, INNERMOST};
|
||||
|
||||
pub use self::binding::BindingMode;
|
||||
pub use self::binding::BindingMode::*;
|
||||
@ -497,91 +498,6 @@ pub struct CReaderCacheKey {
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags that we track on types. These flags are propagated upwards
|
||||
/// through the type during type construction, so that we can quickly check
|
||||
/// whether the type has various kinds of types in it without recursing
|
||||
/// over the type itself.
|
||||
pub struct TypeFlags: u32 {
|
||||
// Does this have parameters? Used to determine whether substitution is
|
||||
// required.
|
||||
/// Does this have [Param]?
|
||||
const HAS_TY_PARAM = 1 << 0;
|
||||
/// Does this have [ReEarlyBound]?
|
||||
const HAS_RE_PARAM = 1 << 1;
|
||||
/// Does this have [ConstKind::Param]?
|
||||
const HAS_CT_PARAM = 1 << 2;
|
||||
|
||||
const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
|
||||
| TypeFlags::HAS_RE_PARAM.bits
|
||||
| TypeFlags::HAS_CT_PARAM.bits;
|
||||
|
||||
/// Does this have [Infer]?
|
||||
const HAS_TY_INFER = 1 << 3;
|
||||
/// Does this have [ReVar]?
|
||||
const HAS_RE_INFER = 1 << 4;
|
||||
/// Does this have [ConstKind::Infer]?
|
||||
const HAS_CT_INFER = 1 << 5;
|
||||
|
||||
/// Does this have inference variables? Used to determine whether
|
||||
/// inference is required.
|
||||
const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
|
||||
| TypeFlags::HAS_RE_INFER.bits
|
||||
| TypeFlags::HAS_CT_INFER.bits;
|
||||
|
||||
/// Does this have [Placeholder]?
|
||||
const HAS_TY_PLACEHOLDER = 1 << 6;
|
||||
/// Does this have [RePlaceholder]?
|
||||
const HAS_RE_PLACEHOLDER = 1 << 7;
|
||||
/// Does this have [ConstKind::Placeholder]?
|
||||
const HAS_CT_PLACEHOLDER = 1 << 8;
|
||||
|
||||
/// `true` if there are "names" of regions and so forth
|
||||
/// that are local to a particular fn/inferctxt
|
||||
const HAS_FREE_LOCAL_REGIONS = 1 << 9;
|
||||
|
||||
/// `true` if there are "names" of types and regions and so forth
|
||||
/// that are local to a particular fn
|
||||
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
|
||||
| TypeFlags::HAS_CT_PARAM.bits
|
||||
| TypeFlags::HAS_TY_INFER.bits
|
||||
| TypeFlags::HAS_CT_INFER.bits
|
||||
| TypeFlags::HAS_TY_PLACEHOLDER.bits
|
||||
| TypeFlags::HAS_CT_PLACEHOLDER.bits
|
||||
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
|
||||
|
||||
/// Does this have [Projection]?
|
||||
const HAS_TY_PROJECTION = 1 << 10;
|
||||
/// Does this have [Opaque]?
|
||||
const HAS_TY_OPAQUE = 1 << 11;
|
||||
/// Does this have [ConstKind::Unevaluated]?
|
||||
const HAS_CT_PROJECTION = 1 << 12;
|
||||
|
||||
/// Could this type be normalized further?
|
||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||
| TypeFlags::HAS_CT_PROJECTION.bits;
|
||||
|
||||
/// Is an error type/const reachable?
|
||||
const HAS_ERROR = 1 << 13;
|
||||
|
||||
/// Does this have any region that "appears free" in the type?
|
||||
/// Basically anything but [ReLateBound] and [ReErased].
|
||||
const HAS_FREE_REGIONS = 1 << 14;
|
||||
|
||||
/// Does this have any [ReLateBound] regions? Used to check
|
||||
/// if a global bound is safe to evaluate.
|
||||
const HAS_RE_LATE_BOUND = 1 << 15;
|
||||
|
||||
/// Does this have any [ReErased] regions?
|
||||
const HAS_RE_ERASED = 1 << 16;
|
||||
|
||||
/// Does this value have parameters/placeholders/inference variables which could be
|
||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
pub struct TyS<'tcx> {
|
||||
/// This field shouldn't be used directly and may be removed in the future.
|
||||
|
@ -1289,53 +1289,6 @@ impl<'tcx> ParamConst {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A [De Bruijn index][dbi] is a standard means of representing
|
||||
/// regions (and perhaps later types) in a higher-ranked setting. In
|
||||
/// particular, imagine a type like this:
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
|
||||
/// ^ ^ | | |
|
||||
/// | | | | |
|
||||
/// | +------------+ 0 | |
|
||||
/// | | |
|
||||
/// +----------------------------------+ 1 |
|
||||
/// | |
|
||||
/// +----------------------------------------------+ 0
|
||||
///
|
||||
/// In this type, there are two binders (the outer fn and the inner
|
||||
/// fn). We need to be able to determine, for any given region, which
|
||||
/// fn type it is bound by, the inner or the outer one. There are
|
||||
/// various ways you can do this, but a De Bruijn index is one of the
|
||||
/// more convenient and has some nice properties. The basic idea is to
|
||||
/// count the number of binders, inside out. Some examples should help
|
||||
/// clarify what I mean.
|
||||
///
|
||||
/// Let's start with the reference type `&'b isize` that is the first
|
||||
/// argument to the inner function. This region `'b` is assigned a De
|
||||
/// Bruijn index of 0, meaning "the innermost binder" (in this case, a
|
||||
/// fn). The region `'a` that appears in the second argument type (`&'a
|
||||
/// isize`) would then be assigned a De Bruijn index of 1, meaning "the
|
||||
/// second-innermost binder". (These indices are written on the arrays
|
||||
/// in the diagram).
|
||||
///
|
||||
/// What is interesting is that De Bruijn index attached to a particular
|
||||
/// variable will vary depending on where it appears. For example,
|
||||
/// the final type `&'a char` also refers to the region `'a` declared on
|
||||
/// the outermost fn. But this time, this reference is not nested within
|
||||
/// any other binders (i.e., it is not an argument to the inner fn, but
|
||||
/// rather the outer one). Therefore, in this case, it is assigned a
|
||||
/// De Bruijn index of 0, because the innermost binder in that location
|
||||
/// is the outer fn.
|
||||
///
|
||||
/// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
|
||||
#[derive(HashStable)]
|
||||
pub struct DebruijnIndex {
|
||||
DEBUG_FORMAT = "DebruijnIndex({})",
|
||||
const INNERMOST = 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub type Region<'tcx> = &'tcx RegionKind;
|
||||
|
||||
/// Representation of regions. Note that the NLL checker uses a distinct
|
||||
@ -1450,7 +1403,7 @@ pub enum RegionKind {
|
||||
|
||||
/// Region bound in a function scope, which will be substituted when the
|
||||
/// function is called.
|
||||
ReLateBound(DebruijnIndex, BoundRegion),
|
||||
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
|
||||
@ -1614,65 +1567,6 @@ impl<'tcx> PolyExistentialProjection<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl DebruijnIndex {
|
||||
/// Returns the resulting index when this value is moved into
|
||||
/// `amount` number of new binders. So, e.g., if you had
|
||||
///
|
||||
/// for<'a> fn(&'a x)
|
||||
///
|
||||
/// and you wanted to change it to
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'a x))
|
||||
///
|
||||
/// you would need to shift the index for `'a` into a new binder.
|
||||
#[must_use]
|
||||
pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
|
||||
DebruijnIndex::from_u32(self.as_u32() + amount)
|
||||
}
|
||||
|
||||
/// Update this index in place by shifting it "in" through
|
||||
/// `amount` number of binders.
|
||||
pub fn shift_in(&mut self, amount: u32) {
|
||||
*self = self.shifted_in(amount);
|
||||
}
|
||||
|
||||
/// Returns the resulting index when this value is moved out from
|
||||
/// `amount` number of new binders.
|
||||
#[must_use]
|
||||
pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
|
||||
DebruijnIndex::from_u32(self.as_u32() - amount)
|
||||
}
|
||||
|
||||
/// Update in place by shifting out from `amount` binders.
|
||||
pub fn shift_out(&mut self, amount: u32) {
|
||||
*self = self.shifted_out(amount);
|
||||
}
|
||||
|
||||
/// Adjusts any De Bruijn indices so as to make `to_binder` the
|
||||
/// innermost binder. That is, if we have something bound at `to_binder`,
|
||||
/// it will now be bound at INNERMOST. This is an appropriate thing to do
|
||||
/// when moving a region out from inside binders:
|
||||
///
|
||||
/// ```
|
||||
/// for<'a> fn(for<'b> for<'c> fn(&'a u32), _)
|
||||
/// // Binder: D3 D2 D1 ^^
|
||||
/// ```
|
||||
///
|
||||
/// Here, the region `'a` would have the De Bruijn index D3,
|
||||
/// because it is the bound 3 binders out. However, if we wanted
|
||||
/// to refer to that region `'a` in the second argument (the `_`),
|
||||
/// those two binders would not be in scope. In that case, we
|
||||
/// might invoke `shift_out_to_binder(D3)`. This would adjust the
|
||||
/// De Bruijn index of `'a` to D1 (the innermost binder).
|
||||
///
|
||||
/// If we invoke `shift_out_to_binder` and the region is in fact
|
||||
/// bound by one of the binders we are shifting out of, that is an
|
||||
/// error (and should fail an assertion failure).
|
||||
pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
|
||||
self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
/// Region utilities
|
||||
impl RegionKind {
|
||||
/// Is this region named by the user?
|
||||
@ -1703,7 +1597,7 @@ impl RegionKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool {
|
||||
pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
|
||||
match *self {
|
||||
ty::ReLateBound(debruijn, _) => debruijn >= index,
|
||||
_ => false,
|
||||
|
14
compiler/rustc_type_ir/Cargo.toml
Normal file
14
compiler/rustc_type_ir/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "rustc_type_ir"
|
||||
version = "0.0.0"
|
||||
authors = ["The Rust Project Developers"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
204
compiler/rustc_type_ir/src/lib.rs
Normal file
204
compiler/rustc_type_ir/src/lib.rs
Normal file
@ -0,0 +1,204 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(const_panic)]
|
||||
#![feature(control_flow_enum)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
||||
bitflags! {
|
||||
/// Flags that we track on types. These flags are propagated upwards
|
||||
/// through the type during type construction, so that we can quickly check
|
||||
/// whether the type has various kinds of types in it without recursing
|
||||
/// over the type itself.
|
||||
pub struct TypeFlags: u32 {
|
||||
// Does this have parameters? Used to determine whether substitution is
|
||||
// required.
|
||||
/// Does this have `Param`?
|
||||
const HAS_TY_PARAM = 1 << 0;
|
||||
/// Does this have `ReEarlyBound`?
|
||||
const HAS_RE_PARAM = 1 << 1;
|
||||
/// Does this have `ConstKind::Param`?
|
||||
const HAS_CT_PARAM = 1 << 2;
|
||||
|
||||
const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
|
||||
| TypeFlags::HAS_RE_PARAM.bits
|
||||
| TypeFlags::HAS_CT_PARAM.bits;
|
||||
|
||||
/// Does this have `Infer`?
|
||||
const HAS_TY_INFER = 1 << 3;
|
||||
/// Does this have `ReVar`?
|
||||
const HAS_RE_INFER = 1 << 4;
|
||||
/// Does this have `ConstKind::Infer`?
|
||||
const HAS_CT_INFER = 1 << 5;
|
||||
|
||||
/// Does this have inference variables? Used to determine whether
|
||||
/// inference is required.
|
||||
const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
|
||||
| TypeFlags::HAS_RE_INFER.bits
|
||||
| TypeFlags::HAS_CT_INFER.bits;
|
||||
|
||||
/// Does this have `Placeholder`?
|
||||
const HAS_TY_PLACEHOLDER = 1 << 6;
|
||||
/// Does this have `RePlaceholder`?
|
||||
const HAS_RE_PLACEHOLDER = 1 << 7;
|
||||
/// Does this have `ConstKind::Placeholder`?
|
||||
const HAS_CT_PLACEHOLDER = 1 << 8;
|
||||
|
||||
/// `true` if there are "names" of regions and so forth
|
||||
/// that are local to a particular fn/inferctxt
|
||||
const HAS_FREE_LOCAL_REGIONS = 1 << 9;
|
||||
|
||||
/// `true` if there are "names" of types and regions and so forth
|
||||
/// that are local to a particular fn
|
||||
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
|
||||
| TypeFlags::HAS_CT_PARAM.bits
|
||||
| TypeFlags::HAS_TY_INFER.bits
|
||||
| TypeFlags::HAS_CT_INFER.bits
|
||||
| TypeFlags::HAS_TY_PLACEHOLDER.bits
|
||||
| TypeFlags::HAS_CT_PLACEHOLDER.bits
|
||||
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
|
||||
|
||||
/// Does this have `Projection`?
|
||||
const HAS_TY_PROJECTION = 1 << 10;
|
||||
/// Does this have `Opaque`?
|
||||
const HAS_TY_OPAQUE = 1 << 11;
|
||||
/// Does this have `ConstKind::Unevaluated`?
|
||||
const HAS_CT_PROJECTION = 1 << 12;
|
||||
|
||||
/// Could this type be normalized further?
|
||||
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
|
||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||
| TypeFlags::HAS_CT_PROJECTION.bits;
|
||||
|
||||
/// Is an error type/const reachable?
|
||||
const HAS_ERROR = 1 << 13;
|
||||
|
||||
/// Does this have any region that "appears free" in the type?
|
||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||
const HAS_FREE_REGIONS = 1 << 14;
|
||||
|
||||
/// Does this have any `ReLateBound` regions? Used to check
|
||||
/// if a global bound is safe to evaluate.
|
||||
const HAS_RE_LATE_BOUND = 1 << 15;
|
||||
|
||||
/// Does this have any `ReErased` regions?
|
||||
const HAS_RE_ERASED = 1 << 16;
|
||||
|
||||
/// Does this value have parameters/placeholders/inference variables which could be
|
||||
/// replaced later, in a way that would change the results of `impl` specialization?
|
||||
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A [De Bruijn index][dbi] is a standard means of representing
|
||||
/// regions (and perhaps later types) in a higher-ranked setting. In
|
||||
/// particular, imagine a type like this:
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
|
||||
/// ^ ^ | | |
|
||||
/// | | | | |
|
||||
/// | +------------+ 0 | |
|
||||
/// | | |
|
||||
/// +----------------------------------+ 1 |
|
||||
/// | |
|
||||
/// +----------------------------------------------+ 0
|
||||
///
|
||||
/// In this type, there are two binders (the outer fn and the inner
|
||||
/// fn). We need to be able to determine, for any given region, which
|
||||
/// fn type it is bound by, the inner or the outer one. There are
|
||||
/// various ways you can do this, but a De Bruijn index is one of the
|
||||
/// more convenient and has some nice properties. The basic idea is to
|
||||
/// count the number of binders, inside out. Some examples should help
|
||||
/// clarify what I mean.
|
||||
///
|
||||
/// Let's start with the reference type `&'b isize` that is the first
|
||||
/// argument to the inner function. This region `'b` is assigned a De
|
||||
/// Bruijn index of 0, meaning "the innermost binder" (in this case, a
|
||||
/// fn). The region `'a` that appears in the second argument type (`&'a
|
||||
/// isize`) would then be assigned a De Bruijn index of 1, meaning "the
|
||||
/// second-innermost binder". (These indices are written on the arrays
|
||||
/// in the diagram).
|
||||
///
|
||||
/// What is interesting is that De Bruijn index attached to a particular
|
||||
/// variable will vary depending on where it appears. For example,
|
||||
/// the final type `&'a char` also refers to the region `'a` declared on
|
||||
/// the outermost fn. But this time, this reference is not nested within
|
||||
/// any other binders (i.e., it is not an argument to the inner fn, but
|
||||
/// rather the outer one). Therefore, in this case, it is assigned a
|
||||
/// De Bruijn index of 0, because the innermost binder in that location
|
||||
/// is the outer fn.
|
||||
///
|
||||
/// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
|
||||
pub struct DebruijnIndex {
|
||||
DEBUG_FORMAT = "DebruijnIndex({})",
|
||||
const INNERMOST = 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl DebruijnIndex {
|
||||
/// Returns the resulting index when this value is moved into
|
||||
/// `amount` number of new binders. So, e.g., if you had
|
||||
///
|
||||
/// for<'a> fn(&'a x)
|
||||
///
|
||||
/// and you wanted to change it to
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'a x))
|
||||
///
|
||||
/// you would need to shift the index for `'a` into a new binder.
|
||||
#[must_use]
|
||||
pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
|
||||
DebruijnIndex::from_u32(self.as_u32() + amount)
|
||||
}
|
||||
|
||||
/// Update this index in place by shifting it "in" through
|
||||
/// `amount` number of binders.
|
||||
pub fn shift_in(&mut self, amount: u32) {
|
||||
*self = self.shifted_in(amount);
|
||||
}
|
||||
|
||||
/// Returns the resulting index when this value is moved out from
|
||||
/// `amount` number of new binders.
|
||||
#[must_use]
|
||||
pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
|
||||
DebruijnIndex::from_u32(self.as_u32() - amount)
|
||||
}
|
||||
|
||||
/// Update in place by shifting out from `amount` binders.
|
||||
pub fn shift_out(&mut self, amount: u32) {
|
||||
*self = self.shifted_out(amount);
|
||||
}
|
||||
|
||||
/// Adjusts any De Bruijn indices so as to make `to_binder` the
|
||||
/// innermost binder. That is, if we have something bound at `to_binder`,
|
||||
/// it will now be bound at INNERMOST. This is an appropriate thing to do
|
||||
/// when moving a region out from inside binders:
|
||||
///
|
||||
/// ```
|
||||
/// for<'a> fn(for<'b> for<'c> fn(&'a u32), _)
|
||||
/// // Binder: D3 D2 D1 ^^
|
||||
/// ```
|
||||
///
|
||||
/// Here, the region `'a` would have the De Bruijn index D3,
|
||||
/// because it is the bound 3 binders out. However, if we wanted
|
||||
/// to refer to that region `'a` in the second argument (the `_`),
|
||||
/// those two binders would not be in scope. In that case, we
|
||||
/// might invoke `shift_out_to_binder(D3)`. This would adjust the
|
||||
/// De Bruijn index of `'a` to D1 (the innermost binder).
|
||||
///
|
||||
/// If we invoke `shift_out_to_binder` and the region is in fact
|
||||
/// bound by one of the binders we are shifting out of, that is an
|
||||
/// error (and should fail an assertion failure).
|
||||
pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
|
||||
self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for DebruijnIndex {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.as_u32().hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user