Skip to content

Commit 26d6e91

Browse files
committed
Auto merge of rust-lang#116828 - compiler-errors:nightlyify-rustc_type_ir, r=<try>
Begin to abstract `rustc_type_ir` for rust-analyzer Not totally happy with this yet, but if the new trait solver is ever to be used by external users, we need to make rustc-type-ir build without internal deps. This adds the "nightly" feature which is used by the compiler, and falls back to more simple implementations when that is not active. r? `@lcnr` or `@jackh726` -- happy to block this pr on a discussion about design and long-term direction for rustc-type-ir tho
2 parents 49691b1 + 6f43680 commit 26d6e91

File tree

9 files changed

+337
-152
lines changed

9 files changed

+337
-152
lines changed

Diff for: compiler/rustc_type_ir/Cargo.toml

+16-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,19 @@ edition = "2021"
77

88
[dependencies]
99
bitflags = "1.2.1"
10-
rustc_index = { path = "../rustc_index" }
11-
rustc_serialize = { path = "../rustc_serialize" }
12-
rustc_data_structures = { path = "../rustc_data_structures" }
13-
rustc_macros = { path = "../rustc_macros" }
14-
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
10+
rustc_index = { path = "../rustc_index", default-features = false }
11+
rustc_serialize = { path = "../rustc_serialize", optional = true }
12+
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
13+
rustc_macros = { path = "../rustc_macros", optional = true }
14+
smallvec = { version = "1.8.1" }
15+
16+
[features]
17+
default = ["nightly"]
18+
nightly = [
19+
"smallvec/may_dangle",
20+
"smallvec/union",
21+
"rustc_index/nightly",
22+
"rustc_serialize",
23+
"rustc_data_structures",
24+
"rustc_macros"
25+
]

Diff for: compiler/rustc_type_ir/src/fold.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
//! ```
4747
use crate::{visit::TypeVisitable, Interner};
4848

49+
#[cfg(feature = "nightly")]
50+
type Never = !;
51+
52+
#[cfg(not(feature = "nightly"))]
53+
type Never = std::convert::Infallible;
54+
4955
/// This trait is implemented for every type that can be folded,
5056
/// providing the skeleton of the traversal.
5157
///
@@ -74,7 +80,10 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
7480
/// folders. Do not override this method, to ensure coherence with
7581
/// `try_fold_with`.
7682
fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
77-
self.try_fold_with(folder).into_ok()
83+
match self.try_fold_with(folder) {
84+
Ok(t) => t,
85+
Err(_) => unreachable!(),
86+
}
7887
}
7988
}
8089

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

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

114126
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
@@ -203,39 +215,39 @@ impl<I: Interner, F> FallibleTypeFolder<I> for F
203215
where
204216
F: TypeFolder<I>,
205217
{
206-
type Error = !;
218+
type Error = Never;
207219

208220
fn interner(&self) -> I {
209221
TypeFolder::interner(self)
210222
}
211223

212-
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !>
224+
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Never>
213225
where
214226
T: TypeFoldable<I>,
215227
I::Binder<T>: TypeSuperFoldable<I>,
216228
{
217229
Ok(self.fold_binder(t))
218230
}
219231

220-
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !>
232+
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never>
221233
where
222234
I::Ty: TypeSuperFoldable<I>,
223235
{
224236
Ok(self.fold_ty(t))
225237
}
226238

227-
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> {
239+
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Never> {
228240
Ok(self.fold_region(r))
229241
}
230242

231-
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !>
243+
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never>
232244
where
233245
I::Const: TypeSuperFoldable<I>,
234246
{
235247
Ok(self.fold_const(c))
236248
}
237249

238-
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !>
250+
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never>
239251
where
240252
I::Predicate: TypeSuperFoldable<I>,
241253
{

Diff for: compiler/rustc_type_ir/src/index.rs

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
2+
pub struct DebruijnIndex {
3+
pub(crate) private: u32,
4+
}
5+
6+
impl DebruijnIndex {
7+
pub const fn from_u32(u: u32) -> Self {
8+
Self { private: u }
9+
}
10+
11+
pub const fn as_u32(self) -> u32 {
12+
self.private
13+
}
14+
}
15+
16+
pub const INNERMOST: DebruijnIndex = DebruijnIndex { private: 0 };
17+
18+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
19+
pub struct UniverseIndex {
20+
pub(crate) private: u32,
21+
}
22+
23+
impl UniverseIndex {
24+
pub const fn from_u32(u: u32) -> Self {
25+
Self { private: u }
26+
}
27+
28+
pub const fn as_u32(self) -> u32 {
29+
self.private
30+
}
31+
}
32+
33+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
34+
pub struct TyVid {
35+
pub(crate) private: u32,
36+
}
37+
38+
impl TyVid {
39+
pub const fn from_u32(u: u32) -> Self {
40+
Self { private: u }
41+
}
42+
43+
pub const fn as_u32(self) -> u32 {
44+
self.private
45+
}
46+
}
47+
48+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
49+
pub struct FloatVid {
50+
pub(crate) private: u32,
51+
}
52+
53+
impl FloatVid {
54+
pub const fn from_u32(u: u32) -> Self {
55+
Self { private: u }
56+
}
57+
58+
pub const fn as_u32(self) -> u32 {
59+
self.private
60+
}
61+
}
62+
63+
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
64+
pub struct IntVid {
65+
pub(crate) private: u32,
66+
}
67+
68+
impl IntVid {
69+
pub const fn from_u32(u: u32) -> Self {
70+
Self { private: u }
71+
}
72+
73+
pub const fn as_u32(self) -> u32 {
74+
self.private
75+
}
76+
}

Diff for: compiler/rustc_type_ir/src/index_nightly.rs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
rustc_index::newtype_index! {
2+
/// A [De Bruijn index][dbi] is a standard means of representing
3+
/// regions (and perhaps later types) in a higher-ranked setting. In
4+
/// particular, imagine a type like this:
5+
/// ```ignore (illustrative)
6+
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
7+
/// // ^ ^ | | |
8+
/// // | | | | |
9+
/// // | +------------+ 0 | |
10+
/// // | | |
11+
/// // +----------------------------------+ 1 |
12+
/// // | |
13+
/// // +----------------------------------------------+ 0
14+
/// ```
15+
/// In this type, there are two binders (the outer fn and the inner
16+
/// fn). We need to be able to determine, for any given region, which
17+
/// fn type it is bound by, the inner or the outer one. There are
18+
/// various ways you can do this, but a De Bruijn index is one of the
19+
/// more convenient and has some nice properties. The basic idea is to
20+
/// count the number of binders, inside out. Some examples should help
21+
/// clarify what I mean.
22+
///
23+
/// Let's start with the reference type `&'b isize` that is the first
24+
/// argument to the inner function. This region `'b` is assigned a De
25+
/// Bruijn index of 0, meaning "the innermost binder" (in this case, a
26+
/// fn). The region `'a` that appears in the second argument type (`&'a
27+
/// isize`) would then be assigned a De Bruijn index of 1, meaning "the
28+
/// second-innermost binder". (These indices are written on the arrows
29+
/// in the diagram).
30+
///
31+
/// What is interesting is that De Bruijn index attached to a particular
32+
/// variable will vary depending on where it appears. For example,
33+
/// the final type `&'a char` also refers to the region `'a` declared on
34+
/// the outermost fn. But this time, this reference is not nested within
35+
/// any other binders (i.e., it is not an argument to the inner fn, but
36+
/// rather the outer one). Therefore, in this case, it is assigned a
37+
/// De Bruijn index of 0, because the innermost binder in that location
38+
/// is the outer fn.
39+
///
40+
/// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
41+
#[derive(HashStable_Generic)]
42+
#[debug_format = "DebruijnIndex({})"]
43+
pub struct DebruijnIndex {
44+
const INNERMOST = 0;
45+
}
46+
}
47+
48+
rustc_index::newtype_index! {
49+
/// A **ty**pe **v**ariable **ID**.
50+
#[debug_format = "?{}t"]
51+
pub struct TyVid {}
52+
}
53+
54+
rustc_index::newtype_index! {
55+
/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
56+
#[debug_format = "?{}i"]
57+
pub struct IntVid {}
58+
}
59+
60+
rustc_index::newtype_index! {
61+
/// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
62+
#[debug_format = "?{}f"]
63+
pub struct FloatVid {}
64+
}
65+
66+
rustc_index::newtype_index! {
67+
/// "Universes" are used during type- and trait-checking in the
68+
/// presence of `for<..>` binders to control what sets of names are
69+
/// visible. Universes are arranged into a tree: the root universe
70+
/// contains names that are always visible. Each child then adds a new
71+
/// set of names that are visible, in addition to those of its parent.
72+
/// We say that the child universe "extends" the parent universe with
73+
/// new names.
74+
///
75+
/// To make this more concrete, consider this program:
76+
///
77+
/// ```ignore (illustrative)
78+
/// struct Foo { }
79+
/// fn bar<T>(x: T) {
80+
/// let y: for<'a> fn(&'a u8, Foo) = ...;
81+
/// }
82+
/// ```
83+
///
84+
/// The struct name `Foo` is in the root universe U0. But the type
85+
/// parameter `T`, introduced on `bar`, is in an extended universe U1
86+
/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
87+
/// of `bar`, we cannot name `T`. Then, within the type of `y`, the
88+
/// region `'a` is in a universe U2 that extends U1, because we can
89+
/// name it inside the fn type but not outside.
90+
///
91+
/// Universes are used to do type- and trait-checking around these
92+
/// "forall" binders (also called **universal quantification**). The
93+
/// idea is that when, in the body of `bar`, we refer to `T` as a
94+
/// type, we aren't referring to any type in particular, but rather a
95+
/// kind of "fresh" type that is distinct from all other types we have
96+
/// actually declared. This is called a **placeholder** type, and we
97+
/// use universes to talk about this. In other words, a type name in
98+
/// universe 0 always corresponds to some "ground" type that the user
99+
/// declared, but a type name in a non-zero universe is a placeholder
100+
/// type -- an idealized representative of "types in general" that we
101+
/// use for checking generic functions.
102+
#[derive(HashStable_Generic)]
103+
#[debug_format = "U{}"]
104+
pub struct UniverseIndex {}
105+
}

0 commit comments

Comments
 (0)