Skip to content

Commit

Permalink
Begin to abstract rustc_type_ir for rust-analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 17, 2023
1 parent 49691b1 commit 6f43680
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 152 deletions.
21 changes: 16 additions & 5 deletions compiler/rustc_type_ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ edition = "2021"

[dependencies]
bitflags = "1.2.1"
rustc_index = { path = "../rustc_index" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_macros = { path = "../rustc_macros" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_serialize = { path = "../rustc_serialize", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_macros = { path = "../rustc_macros", optional = true }
smallvec = { version = "1.8.1" }

[features]
default = ["nightly"]
nightly = [
"smallvec/may_dangle",
"smallvec/union",
"rustc_index/nightly",
"rustc_serialize",
"rustc_data_structures",
"rustc_macros"
]
30 changes: 21 additions & 9 deletions compiler/rustc_type_ir/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
//! ```
use crate::{visit::TypeVisitable, Interner};

#[cfg(feature = "nightly")]
type Never = !;

#[cfg(not(feature = "nightly"))]
type Never = std::convert::Infallible;

/// This trait is implemented for every type that can be folded,
/// providing the skeleton of the traversal.
///
Expand Down Expand Up @@ -74,7 +80,10 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
/// folders. Do not override this method, to ensure coherence with
/// `try_fold_with`.
fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
self.try_fold_with(folder).into_ok()
match self.try_fold_with(folder) {
Ok(t) => t,
Err(_) => unreachable!(),
}
}
}

Expand All @@ -95,7 +104,10 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
/// infallible folders. Do not override this method, to ensure coherence
/// with `try_super_fold_with`.
fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
self.try_super_fold_with(folder).into_ok()
match self.try_super_fold_with(folder) {
Ok(t) => t,
Err(_) => unreachable!(),
}
}
}

Expand All @@ -108,7 +120,7 @@ pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
/// A blanket implementation of [`FallibleTypeFolder`] will defer to
/// the infallible methods of this trait to ensure that the two APIs
/// are coherent.
pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> {
pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
fn interner(&self) -> I;

fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
Expand Down Expand Up @@ -203,39 +215,39 @@ impl<I: Interner, F> FallibleTypeFolder<I> for F
where
F: TypeFolder<I>,
{
type Error = !;
type Error = Never;

fn interner(&self) -> I {
TypeFolder::interner(self)
}

fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !>
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Never>
where
T: TypeFoldable<I>,
I::Binder<T>: TypeSuperFoldable<I>,
{
Ok(self.fold_binder(t))
}

fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !>
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
where
I::Ty: TypeSuperFoldable<I>,
{
Ok(self.fold_ty(t))
}

fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> {
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Never> {
Ok(self.fold_region(r))
}

fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !>
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
where
I::Const: TypeSuperFoldable<I>,
{
Ok(self.fold_const(c))
}

fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !>
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
where
I::Predicate: TypeSuperFoldable<I>,
{
Expand Down
76 changes: 76 additions & 0 deletions compiler/rustc_type_ir/src/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct DebruijnIndex {
pub(crate) private: u32,
}

impl DebruijnIndex {
pub const fn from_u32(u: u32) -> Self {
Self { private: u }
}

pub const fn as_u32(self) -> u32 {
self.private
}
}

pub const INNERMOST: DebruijnIndex = DebruijnIndex { private: 0 };

#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct UniverseIndex {
pub(crate) private: u32,
}

impl UniverseIndex {
pub const fn from_u32(u: u32) -> Self {
Self { private: u }
}

pub const fn as_u32(self) -> u32 {
self.private
}
}

#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct TyVid {
pub(crate) private: u32,
}

impl TyVid {
pub const fn from_u32(u: u32) -> Self {
Self { private: u }
}

pub const fn as_u32(self) -> u32 {
self.private
}
}

#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct FloatVid {
pub(crate) private: u32,
}

impl FloatVid {
pub const fn from_u32(u: u32) -> Self {
Self { private: u }
}

pub const fn as_u32(self) -> u32 {
self.private
}
}

#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct IntVid {
pub(crate) private: u32,
}

impl IntVid {
pub const fn from_u32(u: u32) -> Self {
Self { private: u }
}

pub const fn as_u32(self) -> u32 {
self.private
}
}
105 changes: 105 additions & 0 deletions compiler/rustc_type_ir/src/index_nightly.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
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:
/// ```ignore (illustrative)
/// 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 arrows
/// 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_Generic)]
#[debug_format = "DebruijnIndex({})"]
pub struct DebruijnIndex {
const INNERMOST = 0;
}
}

rustc_index::newtype_index! {
/// A **ty**pe **v**ariable **ID**.
#[debug_format = "?{}t"]
pub struct TyVid {}
}

rustc_index::newtype_index! {
/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
#[debug_format = "?{}i"]
pub struct IntVid {}
}

rustc_index::newtype_index! {
/// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
#[debug_format = "?{}f"]
pub struct FloatVid {}
}

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<T>(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.
#[derive(HashStable_Generic)]
#[debug_format = "U{}"]
pub struct UniverseIndex {}
}
Loading

0 comments on commit 6f43680

Please sign in to comment.