diff options
Diffstat (limited to 'compiler/rustc_type_ir')
-rw-r--r-- | compiler/rustc_type_ir/Cargo.toml | 21 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/canonical.rs | 257 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/const_kind.rs | 133 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/debug.rs | 44 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/flags.rs | 18 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/fold.rs | 34 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/infcx.rs | 40 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/interner.rs | 128 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/lib.rs | 107 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/macros.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/predicate_kind.rs | 188 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/region_kind.rs | 105 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/ty_info.rs | 12 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/ty_kind.rs | 243 | ||||
-rw-r--r-- | compiler/rustc_type_ir/src/visit.rs | 6 |
15 files changed, 810 insertions, 528 deletions
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index b39ba3059..3a08d89cc 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -7,9 +7,20 @@ edition = "2021" # tidy-alphabetical-start bitflags = "1.2.1" derivative = "2.2.0" -rustc_data_structures = { path = "../rustc_data_structures" } -rustc_index = { path = "../rustc_index" } -rustc_macros = { path = "../rustc_macros" } -rustc_serialize = { path = "../rustc_serialize" } -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_index = { path = "../rustc_index", default-features = false } +rustc_macros = { path = "../rustc_macros", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } +smallvec = { version = "1.8.1" } # tidy-alphabetical-end + +[features] +default = ["nightly"] +nightly = [ + "smallvec/may_dangle", + "smallvec/union", + "rustc_index/nightly", + "rustc_serialize", + "rustc_data_structures", + "rustc_macros", +] diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ace9eade7..5bc2bfe28 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -2,18 +2,16 @@ use std::fmt; use std::hash::Hash; use std::ops::ControlFlow; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{HashStableContext, Interner, UniverseIndex}; +use crate::{Interner, PlaceholderLike, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. #[derive(derivative::Derivative)] #[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))] -#[derive(TyEncodable, TyDecodable)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct Canonical<I: Interner, V> { pub value: V, pub max_universe: UniverseIndex, @@ -60,17 +58,6 @@ impl<I: Interner, V> Canonical<I, V> { } } -impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V> -where - I::CanonicalVars: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.value.hash_stable(hcx, hasher); - self.max_universe.hash_stable(hcx, hasher); - self.variables.hash_stable(hcx, hasher); - } -} - impl<I: Interner, V: Eq> Eq for Canonical<I, V> {} impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> { @@ -126,3 +113,243 @@ where self.variables.visit_with(folder) } } + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct CanonicalVarInfo<I: Interner> { + pub kind: CanonicalVarKind<I>, +} + +impl<I: Interner> PartialEq for CanonicalVarInfo<I> { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} + +impl<I: Interner> Eq for CanonicalVarInfo<I> {} + +impl<I: Interner> TypeVisitable<I> for CanonicalVarInfo<I> +where + I::Ty: TypeVisitable<I>, +{ + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.kind.visit_with(visitor) + } +} + +impl<I: Interner> TypeFoldable<I> for CanonicalVarInfo<I> +where + I::Ty: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(CanonicalVarInfo { kind: self.kind.try_fold_with(folder)? }) + } +} + +impl<I: Interner> CanonicalVarInfo<I> { + pub fn universe(self) -> UniverseIndex { + self.kind.universe() + } + + #[must_use] + pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo<I> { + CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) } + } + + pub fn is_existential(&self) -> bool { + match self.kind { + CanonicalVarKind::Ty(_) => true, + CanonicalVarKind::PlaceholderTy(_) => false, + CanonicalVarKind::Region(_) => true, + CanonicalVarKind::PlaceholderRegion(..) => false, + CanonicalVarKind::Const(..) => true, + CanonicalVarKind::PlaceholderConst(_, _) => false, + CanonicalVarKind::Effect => true, + } + } + + pub fn is_region(&self) -> bool { + match self.kind { + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, + CanonicalVarKind::Ty(_) + | CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::PlaceholderConst(_, _) + | CanonicalVarKind::Effect => false, + } + } + + pub fn expect_placeholder_index(self) -> usize { + match self.kind { + CanonicalVarKind::Ty(_) + | CanonicalVarKind::Region(_) + | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"), + + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.var().as_usize(), + } + } +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum CanonicalVarKind<I: Interner> { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// A "placeholder" that represents "any type". + PlaceholderTy(I::PlaceholderTy), + + /// Region variable `'?R`. + Region(UniverseIndex), + + /// A "placeholder" that represents "any region". Created when you + /// are solving a goal like `for<'a> T: Foo<'a>` to represent the + /// bound region `'a`. + PlaceholderRegion(I::PlaceholderRegion), + + /// Some kind of const inference variable. + Const(UniverseIndex, I::Ty), + + /// Effect variable `'?E`. + Effect, + + /// A "placeholder" that represents "any const". + PlaceholderConst(I::PlaceholderConst, I::Ty), +} + +impl<I: Interner> PartialEq for CanonicalVarKind<I> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Ty(l0), Self::Ty(r0)) => l0 == r0, + (Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0, + (Self::Region(l0), Self::Region(r0)) => l0 == r0, + (Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0, + (Self::Const(l0, l1), Self::Const(r0, r1)) => l0 == r0 && l1 == r1, + (Self::PlaceholderConst(l0, l1), Self::PlaceholderConst(r0, r1)) => { + l0 == r0 && l1 == r1 + } + _ => std::mem::discriminant(self) == std::mem::discriminant(other), + } + } +} + +impl<I: Interner> Eq for CanonicalVarKind<I> {} + +impl<I: Interner> TypeVisitable<I> for CanonicalVarKind<I> +where + I::Ty: TypeVisitable<I>, +{ + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match self { + CanonicalVarKind::Ty(_) + | CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::Region(_) + | CanonicalVarKind::PlaceholderRegion(_) + | CanonicalVarKind::Effect => ControlFlow::Continue(()), + CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => { + ty.visit_with(visitor) + } + } + } +} + +impl<I: Interner> TypeFoldable<I> for CanonicalVarKind<I> +where + I::Ty: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(match self { + CanonicalVarKind::Ty(kind) => CanonicalVarKind::Ty(kind), + CanonicalVarKind::Region(kind) => CanonicalVarKind::Region(kind), + CanonicalVarKind::Const(kind, ty) => { + CanonicalVarKind::Const(kind, ty.try_fold_with(folder)?) + } + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(placeholder) + } + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(placeholder) + } + CanonicalVarKind::PlaceholderConst(placeholder, ty) => { + CanonicalVarKind::PlaceholderConst(placeholder, ty.try_fold_with(folder)?) + } + CanonicalVarKind::Effect => CanonicalVarKind::Effect, + }) + } +} + +impl<I: Interner> CanonicalVarKind<I> { + pub fn universe(self) -> UniverseIndex { + match self { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui, + CanonicalVarKind::Region(ui) => ui, + CanonicalVarKind::Const(ui, _) => ui, + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(), + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe(), + CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { + UniverseIndex::ROOT + } + CanonicalVarKind::Effect => UniverseIndex::ROOT, + } + } + + /// Replaces the universe of this canonical variable with `ui`. + /// + /// In case this is a float or int variable, this causes an ICE if + /// the updated universe is not the root. + pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> { + match self { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) + } + CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), + CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), + + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui)) + } + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui)) + } + CanonicalVarKind::PlaceholderConst(placeholder, ty) => { + CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui), ty) + } + CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) + | CanonicalVarKind::Effect => { + assert_eq!(ui, UniverseIndex::ROOT); + self + } + } + } +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General(UniverseIndex), + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 33782b13c..0aaaad5af 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,8 +1,8 @@ -use rustc_data_structures::stable_hasher::HashStable; -use rustc_data_structures::stable_hasher::StableHasher; +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::fmt; -use crate::{DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, WithInfcx}; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use self::ConstKind::*; @@ -10,19 +10,20 @@ use self::ConstKind::*; #[derive(derivative::Derivative)] #[derivative( Clone(bound = ""), + Copy(bound = ""), PartialOrd(bound = ""), PartialOrd = "feature_allow_slow_enum", Ord(bound = ""), Ord = "feature_allow_slow_enum", Hash(bound = "") )] -#[derive(TyEncodable, TyDecodable)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ConstKind<I: Interner> { /// A const generic parameter. Param(I::ParamConst), /// Infer the value of the const. - Infer(I::InferConst), + Infer(InferConst), /// Bound const variable, used only when preparing a trait query. Bound(DebruijnIndex, I::BoundConst), @@ -47,48 +48,6 @@ pub enum ConstKind<I: Interner> { Expr(I::ExprConst), } -const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize { - match value { - Param(_) => 0, - Infer(_) => 1, - Bound(_, _) => 2, - Placeholder(_) => 3, - Unevaluated(_) => 4, - Value(_) => 5, - Error(_) => 6, - Expr(_) => 7, - } -} - -impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I> -where - I::ParamConst: HashStable<CTX>, - I::InferConst: HashStable<CTX>, - I::BoundConst: HashStable<CTX>, - I::PlaceholderConst: HashStable<CTX>, - I::AliasConst: HashStable<CTX>, - I::ValueConst: HashStable<CTX>, - I::ErrorGuaranteed: HashStable<CTX>, - I::ExprConst: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - const_kind_discriminant(self).hash_stable(hcx, hasher); - match self { - Param(p) => p.hash_stable(hcx, hasher), - Infer(i) => i.hash_stable(hcx, hasher), - Bound(d, b) => { - d.hash_stable(hcx, hasher); - b.hash_stable(hcx, hasher); - } - Placeholder(p) => p.hash_stable(hcx, hasher), - Unevaluated(u) => u.hash_stable(hcx, hasher), - Value(v) => v.hash_stable(hcx, hasher), - Error(e) => e.hash_stable(hcx, hasher), - Expr(e) => e.hash_stable(hcx, hasher), - } - } -} - impl<I: Interner> PartialEq for ConstKind<I> { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -123,7 +82,7 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { match this.data { Param(param) => write!(f, "{param:?}"), Infer(var) => write!(f, "{:?}", &this.wrap(var)), - Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()), + Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var), Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => { write!(f, "{:?}", &this.wrap(uv)) @@ -134,3 +93,81 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { } } } + +rustc_index::newtype_index! { + /// A **`const`** **v**ariable **ID**. + #[encodable] + #[orderable] + #[debug_format = "?{}c"] + #[gate_rustc_only] + pub struct ConstVid {} +} + +rustc_index::newtype_index! { + /// An **effect** **v**ariable **ID**. + /// + /// Handling effect infer variables happens separately from const infer variables + /// because we do not want to reuse any of the const infer machinery. If we try to + /// relate an effect variable with a normal one, we would ICE, which can catch bugs + /// where we are not correctly using the effect var for an effect param. Fallback + /// is also implemented on top of having separate effect and normal const variables. + #[encodable] + #[orderable] + #[debug_format = "?{}e"] + #[gate_rustc_only] + pub struct EffectVid {} +} + +/// An inference variable for a const, for use in const generics. +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] +pub enum InferConst { + /// Infer the value of the const. + Var(ConstVid), + /// Infer the value of the effect. + /// + /// For why this is separate from the `Var` variant above, see the + /// documentation on `EffectVid`. + EffectVar(EffectVid), + /// A fresh const variable. See `infer::freshen` for more details. + Fresh(u32), +} + +impl fmt::Debug for InferConst { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InferConst::Var(var) => write!(f, "{var:?}"), + InferConst::EffectVar(var) => write!(f, "{var:?}"), + InferConst::Fresh(var) => write!(f, "Fresh({var:?})"), + } + } +} +impl<I: Interner> DebugWithInfcx<I> for InferConst { + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match *this.data { + InferConst::Var(vid) => match this.infcx.universe_of_ct(vid) { + None => write!(f, "{:?}", this.data), + Some(universe) => write!(f, "?{}_{}c", vid.index(), universe.index()), + }, + InferConst::EffectVar(vid) => write!(f, "?{}e", vid.index()), + InferConst::Fresh(_) => { + unreachable!() + } + } + } +} + +#[cfg(feature = "nightly")] +impl<CTX> HashStable<CTX> for InferConst { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + match self { + InferConst::Var(_) | InferConst::EffectVar(_) => { + panic!("const variables should not be hashed: {self:?}") + } + InferConst::Fresh(i) => i.hash_stable(hcx, hasher), + } + } +} diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 4ea3eb3e8..9c8e45b43 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -1,36 +1,46 @@ -use crate::{Interner, UniverseIndex}; +use crate::{ConstVid, InferCtxtLike, Interner, TyVid, UniverseIndex}; use core::fmt; use std::marker::PhantomData; -pub trait InferCtxtLike { - type Interner: Interner; +pub struct NoInfcx<I>(PhantomData<I>); - fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>; +impl<I: Interner> InferCtxtLike for NoInfcx<I> { + type Interner = I; - fn universe_of_lt( - &self, - lt: <Self::Interner as Interner>::InferRegion, - ) -> Option<UniverseIndex>; + fn interner(&self) -> Self::Interner { + unreachable!() + } - fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst) - -> Option<UniverseIndex>; -} + fn universe_of_ty(&self, _ty: TyVid) -> Option<UniverseIndex> { + None + } -pub struct NoInfcx<I>(PhantomData<I>); + fn universe_of_lt(&self, _lt: I::InferRegion) -> Option<UniverseIndex> { + None + } -impl<I: Interner> InferCtxtLike for NoInfcx<I> { - type Interner = I; + fn universe_of_ct(&self, _ct: ConstVid) -> Option<UniverseIndex> { + None + } - fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> { + fn root_ty_var(&self, vid: TyVid) -> TyVid { + vid + } + + fn probe_ty_var(&self, _vid: TyVid) -> Option<I::Ty> { None } - fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> { + fn opportunistic_resolve_lt_var(&self, _vid: I::InferRegion) -> Option<I::Region> { None } - fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> { + fn root_ct_var(&self, vid: ConstVid) -> ConstVid { + vid + } + + fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> { None } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 8472a0845..af741a0a3 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -8,7 +8,7 @@ bitflags! { // required. /// Does this have `Param`? const HAS_TY_PARAM = 1 << 0; - /// Does this have `ReEarlyBound`? + /// Does this have `ReEarlyParam`? const HAS_RE_PARAM = 1 << 1; /// Does this have `ConstKind::Param`? const HAS_CT_PARAM = 1 << 2; @@ -85,20 +85,20 @@ bitflags! { const HAS_ERROR = 1 << 14; /// Does this have any region that "appears free" in the type? - /// Basically anything but `ReLateBound` and `ReErased`. + /// Basically anything but `ReBound` and `ReErased`. const HAS_FREE_REGIONS = 1 << 15; - /// Does this have any `ReLateBound` regions? - const HAS_RE_LATE_BOUND = 1 << 16; + /// Does this have any `ReBound` regions? + const HAS_RE_BOUND = 1 << 16; /// Does this have any `Bound` types? - const HAS_TY_LATE_BOUND = 1 << 17; + const HAS_TY_BOUND = 1 << 17; /// Does this have any `ConstKind::Bound` consts? - const HAS_CT_LATE_BOUND = 1 << 18; + const HAS_CT_BOUND = 1 << 18; /// Does this have any bound variables? /// Used to check if a global bound is safe to evaluate. - const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits - | TypeFlags::HAS_TY_LATE_BOUND.bits - | TypeFlags::HAS_CT_LATE_BOUND.bits; + const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits + | TypeFlags::HAS_TY_BOUND.bits + | TypeFlags::HAS_CT_BOUND.bits; /// Does this have any `ReErased` regions? const HAS_RE_ERASED = 1 << 19; diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index fc56400df..8d4025883 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -45,12 +45,18 @@ //! - u.fold_with(folder) //! ``` -use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use std::mem; +use crate::Lrc; 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. /// @@ -79,7 +85,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(e) => match e {}, + } } } @@ -100,7 +109,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(e) => match e {}, + } } } @@ -113,7 +125,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> @@ -208,13 +220,13 @@ 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>, @@ -222,25 +234,25 @@ where 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>, { @@ -311,7 +323,7 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> { // Call to `Lrc::make_mut` above guarantees that `unique` is the // sole reference to the contained value, so we can avoid doing // a checked `get_mut` here. - let slot = Lrc::get_mut_unchecked(&mut unique); + let slot = Lrc::get_mut(&mut unique).unwrap_unchecked(); // Semantically move the contained type out from `unique`, fold // it, then move the folded value back into `unique`. Should diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs new file mode 100644 index 000000000..28b71f0ea --- /dev/null +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -0,0 +1,40 @@ +use crate::{ConstVid, Interner, TyVid, UniverseIndex}; + +pub trait InferCtxtLike { + type Interner: Interner; + + fn interner(&self) -> Self::Interner; + + fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>; + + /// Resolve `TyVid` to its root `TyVid`. + fn root_ty_var(&self, vid: TyVid) -> TyVid; + + /// Resolve `TyVid` to its inferred type, if it has been equated with a non-infer type. + fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>; + + fn universe_of_lt( + &self, + lt: <Self::Interner as Interner>::InferRegion, + ) -> Option<UniverseIndex>; + + /// Resolve `InferRegion` to its inferred region, if it has been equated with + /// a non-infer region. + /// + /// FIXME: This has slightly different semantics than `{probe,resolve}_{ty,ct}_var`, + /// that has to do with the fact unlike `Ty` or `Const` vars, in rustc, we may + /// not always be able to *name* the root region var from the universe of the + /// var we're trying to resolve. That's why it's called *opportunistic*. + fn opportunistic_resolve_lt_var( + &self, + vid: <Self::Interner as Interner>::InferRegion, + ) -> Option<<Self::Interner as Interner>::Region>; + + fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>; + + /// Resolve `ConstVid` to its root `ConstVid`. + fn root_ct_var(&self, vid: ConstVid) -> ConstVid; + + /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type. + fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7f75e5b35..188910ecc 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,68 +2,110 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; -use crate::{DebugWithInfcx, Mutability}; +use crate::{ + BoundVar, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind, TyKind, + UniverseIndex, +}; pub trait Interner: Sized { - type DefId: Clone + Debug + Hash + Ord; - type AdtDef: Clone + Debug + Hash + Ord; + type DefId: Copy + Debug + Hash + Ord; + type AdtDef: Copy + Debug + Hash + Ord; - type GenericArgs: Clone + type GenericArgs: Copy + DebugWithInfcx<Self> + Hash + Ord + IntoIterator<Item = Self::GenericArg>; - type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord; - type Term: Clone + Debug + Hash + Ord; + type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord; + type Term: Copy + Debug + Hash + Ord; type Binder<T>; - type TypeAndMut: Clone + Debug + Hash + Ord; - type CanonicalVars: Clone + Debug + Hash + Eq; + type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>; // Kinds of tys - type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord; - type Tys: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; - type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord; - type ParamTy: Clone + Debug + Hash + Ord; - type BoundTy: Clone + Debug + Hash + Ord; - type PlaceholderTy: Clone + Debug + Hash + Ord; - type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Ty: Copy + + DebugWithInfcx<Self> + + Hash + + Ord + + Into<Self::GenericArg> + + IntoKind<Kind = TyKind<Self>>; + type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; + type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord; + type ParamTy: Copy + Debug + Hash + Ord; + type BoundTy: Copy + Debug + Hash + Ord; + type PlaceholderTy: Copy + Debug + Hash + Ord + PlaceholderLike; // Things stored inside of tys - type ErrorGuaranteed: Clone + Debug + Hash + Ord; - type BoundExistentialPredicates: Clone + DebugWithInfcx<Self> + Hash + Ord; - type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord; - type AllocId: Clone + Debug + Hash + Ord; + type ErrorGuaranteed: Copy + Debug + Hash + Ord; + type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Ord; + type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Ord; + type AllocId: Copy + Debug + Hash + Ord; // Kinds of consts - type Const: Clone + DebugWithInfcx<Self> + Hash + Ord; - type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord; - type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord; - type PlaceholderConst: Clone + Debug + Hash + Ord; - type ParamConst: Clone + Debug + Hash + Ord; - type BoundConst: Clone + Debug + Hash + Ord; - type ValueConst: Clone + Debug + Hash + Ord; - type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Const: Copy + + DebugWithInfcx<Self> + + Hash + + Ord + + Into<Self::GenericArg> + + IntoKind<Kind = ConstKind<Self>> + + ConstTy<Self>; + type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord; + type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike; + type ParamConst: Copy + Debug + Hash + Ord; + type BoundConst: Copy + Debug + Hash + Ord; + type ValueConst: Copy + Debug + Hash + Ord; + type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Ord; // Kinds of regions - type Region: Clone + DebugWithInfcx<Self> + Hash + Ord; - type EarlyBoundRegion: Clone + Debug + Hash + Ord; - type BoundRegion: Clone + Debug + Hash + Ord; - type FreeRegion: Clone + Debug + Hash + Ord; - type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord; - type PlaceholderRegion: Clone + Debug + Hash + Ord; + type Region: Copy + + DebugWithInfcx<Self> + + Hash + + Ord + + Into<Self::GenericArg> + + IntoKind<Kind = RegionKind<Self>>; + type EarlyParamRegion: Copy + Debug + Hash + Ord; + type LateParamRegion: Copy + Debug + Hash + Ord; + type BoundRegion: Copy + Debug + Hash + Ord; + type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Ord; + type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike; // Predicates - type Predicate: Clone + Debug + Hash + Eq; - type TraitPredicate: Clone + Debug + Hash + Eq; - type RegionOutlivesPredicate: Clone + Debug + Hash + Eq; - type TypeOutlivesPredicate: Clone + Debug + Hash + Eq; - type ProjectionPredicate: Clone + Debug + Hash + Eq; - type SubtypePredicate: Clone + Debug + Hash + Eq; - type CoercePredicate: Clone + Debug + Hash + Eq; - type ClosureKind: Clone + Debug + Hash + Eq; - - fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability); + type Predicate: Copy + Debug + Hash + Eq; + type TraitPredicate: Copy + Debug + Hash + Eq; + type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; + type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; + type ProjectionPredicate: Copy + Debug + Hash + Eq; + type NormalizesTo: Copy + Debug + Hash + Eq; + type SubtypePredicate: Copy + Debug + Hash + Eq; + type CoercePredicate: Copy + Debug + Hash + Eq; + type ClosureKind: Copy + Debug + Hash + Eq; + + fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars; + + // FIXME: We should not have all these constructors on `Interner`, but as functions on some trait. + fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty; + fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region; + fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const; +} + +/// Common capabilities of placeholder kinds +pub trait PlaceholderLike { + fn universe(self) -> UniverseIndex; + fn var(self) -> BoundVar; + + fn with_updated_universe(self, ui: UniverseIndex) -> Self; + + fn new(ui: UniverseIndex, var: BoundVar) -> Self; +} + +pub trait IntoKind { + type Kind; + + fn kind(self) -> Self::Kind; +} + +pub trait ConstTy<I: Interner> { + fn ty(self) -> I::Ty; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e8785fff2..bff938596 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,25 +1,29 @@ -#![feature(associated_type_defaults)] -#![feature(fmt_helpers_for_derive)] -#![feature(get_mut_unchecked)] -#![feature(min_specialization)] -#![feature(never_type)] -#![feature(new_uninit)] -#![feature(rustc_attrs)] -#![feature(unwrap_infallible)] +#![cfg_attr( + feature = "nightly", + feature(associated_type_defaults, min_specialization, never_type, rustc_attrs) +)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -#![allow(internal_features)] +#![allow(rustc::usage_of_ty_tykind)] +#![cfg_attr(feature = "nightly", allow(internal_features))] +#[cfg(feature = "nightly")] extern crate self as rustc_type_ir; #[macro_use] extern crate bitflags; +#[cfg(feature = "nightly")] #[macro_use] extern crate rustc_macros; +#[cfg(feature = "nightly")] +use rustc_data_structures::sync::Lrc; use std::fmt; use std::hash::Hash; +#[cfg(not(feature = "nightly"))] +use std::sync::Arc as Lrc; +#[cfg(feature = "nightly")] pub mod codec; pub mod fold; pub mod ty_info; @@ -32,23 +36,28 @@ mod canonical; mod const_kind; mod debug; mod flags; +mod infcx; mod interner; mod predicate_kind; mod region_kind; pub use canonical::*; +#[cfg(feature = "nightly")] pub use codec::*; pub use const_kind::*; -pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx}; +pub use debug::{DebugWithInfcx, WithInfcx}; pub use flags::*; +pub use infcx::InferCtxtLike; pub use interner::*; pub use predicate_kind::*; pub use region_kind::*; pub use ty_info::*; pub use ty_kind::*; - -/// Needed so we can use #[derive(HashStable_Generic)] -pub trait HashStableContext {} +pub use AliasKind::*; +pub use DynKind::*; +pub use InferTy::*; +pub use RegionKind::*; +pub use TyKind::*; rustc_index::newtype_index! { /// A [De Bruijn index][dbi] is a standard means of representing @@ -90,8 +99,11 @@ rustc_index::newtype_index! { /// is the outer fn. /// /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index - #[derive(HashStable_Generic)] + #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[encodable] + #[orderable] #[debug_format = "DebruijnIndex({})"] + #[gate_rustc_only] pub struct DebruijnIndex { const INNERMOST = 0; } @@ -173,8 +185,9 @@ pub fn debug_bound_var<T: std::fmt::Write>( } } -#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)] -#[rustc_pass_by_value] +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, Hash, HashStable_NoContext))] +#[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum Variance { Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell @@ -289,8 +302,11 @@ rustc_index::newtype_index! { /// 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)] + #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[encodable] + #[orderable] #[debug_format = "U{}"] + #[gate_rustc_only] pub struct UniverseIndex {} } @@ -328,3 +344,60 @@ impl UniverseIndex { self.private < other.private } } + +impl Default for UniverseIndex { + fn default() -> Self { + Self::ROOT + } +} + +rustc_index::newtype_index! { + #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] + #[encodable] + #[orderable] + #[debug_format = "{}"] + #[gate_rustc_only] + pub struct BoundVar {} +} + +/// Represents the various closure traits in the language. This +/// will determine the type of the environment (`self`, in the +/// desugaring) argument that the closure expects. +/// +/// You can get the environment type of a closure using +/// `tcx.closure_env_ty()`. +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +pub enum ClosureKind { + // Warning: Ordering is significant here! The ordering is chosen + // because the trait Fn is a subtrait of FnMut and so in turn, and + // hence we order it so that Fn < FnMut < FnOnce. + Fn, + FnMut, + FnOnce, +} + +impl ClosureKind { + /// This is the initial value used when doing upvar inference. + pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn; + + pub const fn as_str(self) -> &'static str { + match self { + ClosureKind::Fn => "Fn", + ClosureKind::FnMut => "FnMut", + ClosureKind::FnOnce => "FnOnce", + } + } + + /// Returns `true` if a type that impls this closure kind + /// must also implement `other`. + pub fn extends(self, other: ClosureKind) -> bool { + self <= other + } +} + +impl fmt::Display for ClosureKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index cfed84a35..82bb1bf29 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -51,4 +51,6 @@ TrivialTypeTraversalImpls! { crate::DebruijnIndex, crate::AliasRelationDirection, crate::UniverseIndex, + crate::Mutability, + crate::Movability, } diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 48662d426..8c4d0fda6 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,16 +1,15 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::fmt; use std::ops::ControlFlow; use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{HashStableContext, Interner}; +use crate::Interner; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Hash(bound = ""))] -#[derive(TyEncodable, TyDecodable)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ClauseKind<I: Interner> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -38,18 +37,6 @@ pub enum ClauseKind<I: Interner> { ConstEvaluatable(I::Const), } -impl<I: Interner> Copy for ClauseKind<I> -where - I::Ty: Copy, - I::Const: Copy, - I::GenericArg: Copy, - I::TraitPredicate: Copy, - I::ProjectionPredicate: Copy, - I::TypeOutlivesPredicate: Copy, - I::RegionOutlivesPredicate: Copy, -{ -} - impl<I: Interner> PartialEq for ClauseKind<I> { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -67,45 +54,6 @@ impl<I: Interner> PartialEq for ClauseKind<I> { impl<I: Interner> Eq for ClauseKind<I> {} -fn clause_kind_discriminant<I: Interner>(value: &ClauseKind<I>) -> usize { - match value { - ClauseKind::Trait(_) => 0, - ClauseKind::RegionOutlives(_) => 1, - ClauseKind::TypeOutlives(_) => 2, - ClauseKind::Projection(_) => 3, - ClauseKind::ConstArgHasType(_, _) => 4, - ClauseKind::WellFormed(_) => 5, - ClauseKind::ConstEvaluatable(_) => 6, - } -} - -impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ClauseKind<I> -where - I::Ty: HashStable<CTX>, - I::Const: HashStable<CTX>, - I::GenericArg: HashStable<CTX>, - I::TraitPredicate: HashStable<CTX>, - I::ProjectionPredicate: HashStable<CTX>, - I::TypeOutlivesPredicate: HashStable<CTX>, - I::RegionOutlivesPredicate: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - clause_kind_discriminant(self).hash_stable(hcx, hasher); - match self { - ClauseKind::Trait(p) => p.hash_stable(hcx, hasher), - ClauseKind::RegionOutlives(p) => p.hash_stable(hcx, hasher), - ClauseKind::TypeOutlives(p) => p.hash_stable(hcx, hasher), - ClauseKind::Projection(p) => p.hash_stable(hcx, hasher), - ClauseKind::ConstArgHasType(c, t) => { - c.hash_stable(hcx, hasher); - t.hash_stable(hcx, hasher); - } - ClauseKind::WellFormed(t) => t.hash_stable(hcx, hasher), - ClauseKind::ConstEvaluatable(c) => c.hash_stable(hcx, hasher), - } - } -} - impl<I: Interner> TypeFoldable<I> for ClauseKind<I> where I::Ty: TypeFoldable<I>, @@ -160,8 +108,14 @@ where } #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Hash(bound = ""))] -#[derive(TyEncodable, TyDecodable)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum PredicateKind<I: Interner> { /// Prove a clause Clause(ClauseKind<I>), @@ -169,11 +123,6 @@ pub enum PredicateKind<I: Interner> { /// Trait must be object-safe. ObjectSafe(I::DefId), - /// No direct syntax. May be thought of as `where T: FnFoo<...>` - /// for some generic args `...` and `T` being a closure type. - /// Satisfied (or refuted) once we know the closure's kind. - ClosureKind(I::DefId, I::GenericArgs, I::ClosureKind), - /// `T1 <: T2` /// /// This obligation is created most often when we have two @@ -198,6 +147,15 @@ pub enum PredicateKind<I: Interner> { /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. Ambiguous, + /// The alias normalizes to `term`. Unlike `Projection`, this always fails if the alias + /// cannot be normalized in the current context. + /// + /// `Projection(<T as Trait>::Assoc, ?x)` results in `?x == <T as Trait>::Assoc` while + /// `NormalizesTo(<T as Trait>::Assoc, ?x)` results in `NoSolution`. + /// + /// Only used in the new solver. + NormalizesTo(I::NormalizesTo), + /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother. /// @@ -205,90 +163,6 @@ pub enum PredicateKind<I: Interner> { AliasRelate(I::Term, I::Term, AliasRelationDirection), } -impl<I: Interner> Copy for PredicateKind<I> -where - I::DefId: Copy, - I::Const: Copy, - I::GenericArgs: Copy, - I::Term: Copy, - I::CoercePredicate: Copy, - I::SubtypePredicate: Copy, - I::ClosureKind: Copy, - ClauseKind<I>: Copy, -{ -} - -impl<I: Interner> PartialEq for PredicateKind<I> { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Clause(l0), Self::Clause(r0)) => l0 == r0, - (Self::ObjectSafe(l0), Self::ObjectSafe(r0)) => l0 == r0, - (Self::ClosureKind(l0, l1, l2), Self::ClosureKind(r0, r1, r2)) => { - l0 == r0 && l1 == r1 && l2 == r2 - } - (Self::Subtype(l0), Self::Subtype(r0)) => l0 == r0, - (Self::Coerce(l0), Self::Coerce(r0)) => l0 == r0, - (Self::ConstEquate(l0, l1), Self::ConstEquate(r0, r1)) => l0 == r0 && l1 == r1, - (Self::AliasRelate(l0, l1, l2), Self::AliasRelate(r0, r1, r2)) => { - l0 == r0 && l1 == r1 && l2 == r2 - } - _ => core::mem::discriminant(self) == core::mem::discriminant(other), - } - } -} - -impl<I: Interner> Eq for PredicateKind<I> {} - -fn predicate_kind_discriminant<I: Interner>(value: &PredicateKind<I>) -> usize { - match value { - PredicateKind::Clause(_) => 0, - PredicateKind::ObjectSafe(_) => 1, - PredicateKind::ClosureKind(_, _, _) => 2, - PredicateKind::Subtype(_) => 3, - PredicateKind::Coerce(_) => 4, - PredicateKind::ConstEquate(_, _) => 5, - PredicateKind::Ambiguous => 6, - PredicateKind::AliasRelate(_, _, _) => 7, - } -} - -impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for PredicateKind<I> -where - I::DefId: HashStable<CTX>, - I::Const: HashStable<CTX>, - I::GenericArgs: HashStable<CTX>, - I::Term: HashStable<CTX>, - I::CoercePredicate: HashStable<CTX>, - I::SubtypePredicate: HashStable<CTX>, - I::ClosureKind: HashStable<CTX>, - ClauseKind<I>: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - predicate_kind_discriminant(self).hash_stable(hcx, hasher); - match self { - PredicateKind::Clause(p) => p.hash_stable(hcx, hasher), - PredicateKind::ObjectSafe(d) => d.hash_stable(hcx, hasher), - PredicateKind::ClosureKind(d, g, k) => { - d.hash_stable(hcx, hasher); - g.hash_stable(hcx, hasher); - k.hash_stable(hcx, hasher); - } - PredicateKind::Subtype(p) => p.hash_stable(hcx, hasher), - PredicateKind::Coerce(p) => p.hash_stable(hcx, hasher), - PredicateKind::ConstEquate(c1, c2) => { - c1.hash_stable(hcx, hasher); - c2.hash_stable(hcx, hasher); - } - PredicateKind::Ambiguous => {} - PredicateKind::AliasRelate(t1, t2, r) => { - t1.hash_stable(hcx, hasher); - t2.hash_stable(hcx, hasher); - r.hash_stable(hcx, hasher); - } - } - } -} - impl<I: Interner> TypeFoldable<I> for PredicateKind<I> where I::DefId: TypeFoldable<I>, @@ -297,24 +171,20 @@ where I::Term: TypeFoldable<I>, I::CoercePredicate: TypeFoldable<I>, I::SubtypePredicate: TypeFoldable<I>, - I::ClosureKind: TypeFoldable<I>, + I::NormalizesTo: TypeFoldable<I>, ClauseKind<I>: TypeFoldable<I>, { fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { Ok(match self { PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?), PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?), - PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind( - d.try_fold_with(folder)?, - g.try_fold_with(folder)?, - k.try_fold_with(folder)?, - ), PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?), PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?), PredicateKind::ConstEquate(a, b) => { PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?) } PredicateKind::Ambiguous => PredicateKind::Ambiguous, + PredicateKind::NormalizesTo(p) => PredicateKind::NormalizesTo(p.try_fold_with(folder)?), PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate( a.try_fold_with(folder)?, b.try_fold_with(folder)?, @@ -332,18 +202,13 @@ where I::Term: TypeVisitable<I>, I::CoercePredicate: TypeVisitable<I>, I::SubtypePredicate: TypeVisitable<I>, - I::ClosureKind: TypeVisitable<I>, + I::NormalizesTo: TypeVisitable<I>, ClauseKind<I>: TypeVisitable<I>, { fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { match self { PredicateKind::Clause(p) => p.visit_with(visitor), PredicateKind::ObjectSafe(d) => d.visit_with(visitor), - PredicateKind::ClosureKind(d, g, k) => { - d.visit_with(visitor)?; - g.visit_with(visitor)?; - k.visit_with(visitor) - } PredicateKind::Subtype(s) => s.visit_with(visitor), PredicateKind::Coerce(s) => s.visit_with(visitor), PredicateKind::ConstEquate(a, b) => { @@ -351,6 +216,7 @@ where b.visit_with(visitor) } PredicateKind::Ambiguous => ControlFlow::Continue(()), + PredicateKind::NormalizesTo(p) => p.visit_with(visitor), PredicateKind::AliasRelate(a, b, d) => { a.visit_with(visitor)?; b.visit_with(visitor)?; @@ -361,7 +227,7 @@ where } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[derive(HashStable_Generic, Encodable, Decodable)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, Encodable, Decodable))] pub enum AliasRelationDirection { Equate, Subtype, @@ -403,11 +269,9 @@ impl<I: Interner> fmt::Debug for PredicateKind<I> { PredicateKind::ObjectSafe(trait_def_id) => { write!(f, "ObjectSafe({trait_def_id:?})") } - PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { - write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})") - } PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), PredicateKind::Ambiguous => write!(f, "Ambiguous"), + PredicateKind::NormalizesTo(p) => p.fmt(f), PredicateKind::AliasRelate(t1, t2, dir) => { write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 69ed5bada..3b5e41e8d 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,8 +1,8 @@ -use rustc_data_structures::stable_hasher::HashStable; -use rustc_data_structures::stable_hasher::StableHasher; +#[cfg(feature = "nightly")] +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::fmt; -use crate::{DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, WithInfcx}; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; use self::RegionKind::*; @@ -22,8 +22,8 @@ use self::RegionKind::*; /// ```text /// static ----------+-----...------+ (greatest) /// | | | -/// early-bound and | | -/// free regions | | +/// param regions | | +/// | | | /// | | | /// | | | /// empty(root) placeholder(U1) | @@ -88,8 +88,8 @@ use self::RegionKind::*; /// 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 +/// There are two kinds of placeholder regions in rustc: `ReLateParam` and +/// `RePlaceholder`. When checking an item's body, `ReLateParam` 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 @@ -115,27 +115,44 @@ use self::RegionKind::*; #[derive(derivative::Derivative)] #[derivative( Clone(bound = ""), + Copy(bound = ""), PartialOrd(bound = ""), PartialOrd = "feature_allow_slow_enum", Ord(bound = ""), Ord = "feature_allow_slow_enum", Hash(bound = "") )] -#[derive(TyEncodable, TyDecodable)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum RegionKind<I: Interner> { - /// 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), + /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. + /// + /// There are some important differences between region and type parameters. + /// Not all region parameters in the source are represented via `ReEarlyParam`: + /// late-bound function parameters are instead lowered to a `ReBound`. Late-bound + /// regions get eagerly replaced with `ReLateParam` which behaves in the same way as + /// `ReEarlyParam`. Region parameters are also sometimes implicit, + /// e.g. in `impl Trait for &()`. + ReEarlyParam(I::EarlyParamRegion), - /// Region bound in a function scope, which will be substituted when the - /// function is called. - ReLateBound(DebruijnIndex, I::BoundRegion), + /// A higher-ranked region. These represent either late-bound function parameters + /// or bound variables from a `for<'a>`-binder. + /// + /// While inside of a function, e.g. during typeck, the late-bound function parameters + /// can be converted to `ReLateParam` by calling `tcx.liberate_late_bound_regions`. + /// + /// Bound regions inside of types **must not** be erased, as they impact trait + /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and + /// `fn(&'static ())` are different types and have to be treated as such. + ReBound(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), + /// Late-bound function parameters are represented using a `ReBound`. When + /// inside of a function, we convert these bound variables to placeholder + /// parameters via `tcx.liberate_late_bound_regions`. They are then treated + /// the same way as `ReEarlyParam` while inside of the function. + /// + /// See <https://rustc-dev-guide.rust-lang.org/early-late-bound-summary.html> for + /// more info about early and late bound lifetime parameters. + ReLateParam(I::LateParamRegion), /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -143,8 +160,11 @@ pub enum RegionKind<I: Interner> { /// A region variable. Should not exist outside of type inference. ReVar(I::InferRegion), - /// A placeholder region -- basically, the higher-ranked version of `ReFree`. + /// A placeholder region -- the higher-ranked version of `ReLateParam`. /// Should not exist outside of type inference. + /// + /// Used when instantiating a `forall` binder via + /// `infcx.instantiate_binder_with_placeholders`. RePlaceholder(I::PlaceholderRegion), /// Erased region, used by trait selection, in MIR and during codegen. @@ -159,9 +179,9 @@ pub enum RegionKind<I: Interner> { #[inline] const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize { match value { - ReEarlyBound(_) => 0, - ReLateBound(_, _) => 1, - ReFree(_) => 2, + ReEarlyParam(_) => 0, + ReBound(_, _) => 1, + ReLateParam(_) => 2, ReStatic => 3, ReVar(_) => 4, RePlaceholder(_) => 5, @@ -170,27 +190,15 @@ const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize { } } -// This is manually implemented because a derive would require `I: Copy` -impl<I: Interner> Copy for RegionKind<I> -where - I::EarlyBoundRegion: Copy, - I::BoundRegion: Copy, - I::FreeRegion: Copy, - I::InferRegion: Copy, - I::PlaceholderRegion: Copy, - I::ErrorGuaranteed: Copy, -{ -} - // This is manually implemented because a derive would require `I: PartialEq` impl<I: Interner> PartialEq for RegionKind<I> { #[inline] fn eq(&self, other: &RegionKind<I>) -> bool { regionkind_discriminant(self) == regionkind_discriminant(other) && match (self, other) { - (ReEarlyBound(a_r), ReEarlyBound(b_r)) => a_r == b_r, - (ReLateBound(a_d, a_r), ReLateBound(b_d, b_r)) => a_d == b_d && a_r == b_r, - (ReFree(a_r), ReFree(b_r)) => a_r == b_r, + (ReEarlyParam(a_r), ReEarlyParam(b_r)) => a_r == b_r, + (ReBound(a_d, a_r), ReBound(b_d, b_r)) => a_d == b_d && a_r == b_r, + (ReLateParam(a_r), ReLateParam(b_r)) => a_r == b_r, (ReStatic, ReStatic) => true, (ReVar(a_r), ReVar(b_r)) => a_r == b_r, (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r, @@ -216,13 +224,13 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data { - ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"), + ReEarlyParam(data) => write!(f, "ReEarlyParam({data:?})"), - ReLateBound(binder_id, bound_region) => { - write!(f, "ReLateBound({binder_id:?}, {bound_region:?})") + ReBound(binder_id, bound_region) => { + write!(f, "ReBound({binder_id:?}, {bound_region:?})") } - ReFree(fr) => write!(f, "{fr:?}"), + ReLateParam(fr) => write!(f, "{fr:?}"), ReStatic => f.write_str("ReStatic"), @@ -242,12 +250,13 @@ impl<I: Interner> fmt::Debug for RegionKind<I> { } } +#[cfg(feature = "nightly")] // This is not a derived impl because a derive would require `I: HashStable` -impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I> +impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I> where - I::EarlyBoundRegion: HashStable<CTX>, + I::EarlyParamRegion: HashStable<CTX>, I::BoundRegion: HashStable<CTX>, - I::FreeRegion: HashStable<CTX>, + I::LateParamRegion: HashStable<CTX>, I::InferRegion: HashStable<CTX>, I::PlaceholderRegion: HashStable<CTX>, { @@ -258,14 +267,14 @@ where ReErased | ReStatic | ReError(_) => { // No variant fields to hash for these ... } - ReLateBound(d, r) => { + ReBound(d, r) => { d.hash_stable(hcx, hasher); r.hash_stable(hcx, hasher); } - ReEarlyBound(r) => { + ReEarlyParam(r) => { r.hash_stable(hcx, hasher); } - ReFree(r) => { + ReLateParam(r) => { r.hash_stable(hcx, hasher); } RePlaceholder(r) => { diff --git a/compiler/rustc_type_ir/src/ty_info.rs b/compiler/rustc_type_ir/src/ty_info.rs index d986e310c..0e4930552 100644 --- a/compiler/rustc_type_ir/src/ty_info.rs +++ b/compiler/rustc_type_ir/src/ty_info.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "nightly")] use rustc_data_structures::fingerprint::Fingerprint; +#[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; @@ -16,6 +18,8 @@ use crate::{DebruijnIndex, TypeFlags}; #[derive(Copy, Clone)] pub struct WithCachedTypeInfo<T> { pub internee: T, + + #[cfg(feature = "nightly")] pub stable_hash: Fingerprint, /// This field provides fast access to information that is also contained @@ -81,14 +85,16 @@ impl<T> Deref for WithCachedTypeInfo<T> { impl<T: Hash> Hash for WithCachedTypeInfo<T> { #[inline] fn hash<H: Hasher>(&self, s: &mut H) { + #[cfg(feature = "nightly")] if self.stable_hash != Fingerprint::ZERO { - self.stable_hash.hash(s) - } else { - self.internee.hash(s) + return self.stable_hash.hash(s); } + + self.internee.hash(s) } } +#[cfg(feature = "nightly")] impl<T: HashStable<CTX>, CTX> HashStable<CTX> for WithCachedTypeInfo<T> { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { if self.stable_hash == Fingerprint::ZERO || cfg!(debug_assertions) { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 09a9a3322..70adfbee2 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,11 +1,11 @@ -#![allow(rustc::usage_of_ty_tykind)] - +#[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +#[cfg(feature = "nightly")] use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; use std::fmt; -use std::mem::discriminant; -use crate::HashStableContext; +use crate::fold::{FallibleTypeFolder, TypeFoldable}; +use crate::visit::{TypeVisitable, TypeVisitor}; use crate::Interner; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -13,8 +13,8 @@ use self::TyKind::*; /// The movability of a coroutine / closure literal: /// whether a coroutine contains self-references, causing it to be `!Unpin`. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug, Copy)] -#[derive(HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum Movability { /// May contain self-references, `!Unpin`. Static, @@ -23,7 +23,7 @@ pub enum Movability { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[derive(HashStable_Generic, Encodable, Decodable)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum Mutability { // N.B. Order is deliberate, so that Not < Mut Not, @@ -75,7 +75,7 @@ impl Mutability { /// Specifies how a trait object is represented. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum DynKind { /// An unsized `dyn Trait` object Dyn, @@ -89,7 +89,7 @@ pub enum DynKind { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum AliasKind { /// A projection `<Type as Trait>::AssocType`. /// Can get normalized away if monomorphic enough. @@ -109,17 +109,18 @@ pub enum AliasKind { /// /// Types written by the user start out as `hir::TyKind` and get /// converted to this representation using `AstConv::ast_ty_to_ty`. -#[rustc_diagnostic_item = "IrTyKind"] +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[derive(derivative::Derivative)] #[derivative( Clone(bound = ""), + Copy(bound = ""), PartialOrd(bound = ""), PartialOrd = "feature_allow_slow_enum", Ord(bound = ""), Ord = "feature_allow_slow_enum", Hash(bound = "") )] -#[derive(TyEncodable, TyDecodable)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TyKind<I: Interner> { /// The primitive boolean type. Written as `bool`. Bool, @@ -159,7 +160,7 @@ pub enum TyKind<I: Interner> { Slice(I::Ty), /// A raw pointer. Written as `*mut T` or `*const T` - RawPtr(I::TypeAndMut), + RawPtr(TypeAndMut<I>), /// A reference; a pointer with an associated lifetime. Written as /// `&'a mut T` or `&'a T`. @@ -281,7 +282,7 @@ pub enum TyKind<I: Interner> { /// correctly deal with higher ranked types. Though unlike placeholders, /// that universe is stored in the `InferCtxt` instead of directly /// inside of the type. - Infer(I::InferTy), + Infer(InferTy), /// A placeholder for a type which could not be computed; this is /// propagated to avoid useless error messages. @@ -394,7 +395,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { Float(float) => write!(f, "{float:?}"), Adt(d, s) => { write!(f, "{d:?}")?; - let mut s = s.clone().into_iter(); + let mut s = s.into_iter(); let first = s.next(); match first { Some(first) => write!(f, "<{:?}", first)?, @@ -407,12 +408,11 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { write!(f, ">") } - Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), + Foreign(d) => f.debug_tuple("Foreign").field(d).finish(), Str => write!(f, "str"), Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), - RawPtr(p) => { - let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone()); + RawPtr(TypeAndMut { ty, mutbl }) => { match mutbl { Mutability::Mut => write!(f, "*mut "), Mutability::Not => write!(f, "*const "), @@ -423,7 +423,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { Mutability::Mut => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)), Mutability::Not => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)), }, - FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, &this.wrap(s)), + FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(), FnPtr(s) => write!(f, "{:?}", &this.wrap(s)), Dynamic(p, r, repr) => match repr { DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)), @@ -431,16 +431,18 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r)) } }, - Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)), - Coroutine(d, s, m) => f.debug_tuple_field3_finish("Coroutine", d, &this.wrap(s), m), + Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(), + Coroutine(d, s, m) => { + f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).field(m).finish() + } CoroutineWitness(d, s) => { - f.debug_tuple_field2_finish("CoroutineWitness", d, &this.wrap(s)) + f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish() } Never => write!(f, "!"), Tuple(t) => { write!(f, "(")?; let mut count = 0; - for ty in t.clone() { + for ty in *t { if count > 0 { write!(f, ", ")?; } @@ -453,7 +455,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { } write!(f, ")") } - Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, &this.wrap(a)), + Alias(i, a) => f.debug_tuple("Alias").field(i).field(&this.wrap(a)).finish(), Param(p) => write!(f, "{p:?}"), Bound(d, b) => crate::debug_bound_var(f, *d, b), Placeholder(p) => write!(f, "{p:?}"), @@ -470,120 +472,8 @@ impl<I: Interner> fmt::Debug for TyKind<I> { } } -// This is not a derived impl because a derive would require `I: HashStable` -#[allow(rustc::usage_of_ty_tykind)] -impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for TyKind<I> -where - I::AdtDef: HashStable<CTX>, - I::DefId: HashStable<CTX>, - I::GenericArgs: HashStable<CTX>, - I::Ty: HashStable<CTX>, - I::Const: HashStable<CTX>, - I::TypeAndMut: HashStable<CTX>, - I::PolyFnSig: HashStable<CTX>, - I::BoundExistentialPredicates: HashStable<CTX>, - I::Region: HashStable<CTX>, - I::Tys: HashStable<CTX>, - I::AliasTy: HashStable<CTX>, - I::BoundTy: HashStable<CTX>, - I::ParamTy: HashStable<CTX>, - I::PlaceholderTy: HashStable<CTX>, - I::InferTy: HashStable<CTX>, - I::ErrorGuaranteed: HashStable<CTX>, -{ - #[inline] - fn hash_stable(&self, __hcx: &mut CTX, __hasher: &mut StableHasher) { - std::mem::discriminant(self).hash_stable(__hcx, __hasher); - match self { - Bool => {} - Char => {} - Int(i) => { - i.hash_stable(__hcx, __hasher); - } - Uint(u) => { - u.hash_stable(__hcx, __hasher); - } - Float(f) => { - f.hash_stable(__hcx, __hasher); - } - Adt(adt, args) => { - adt.hash_stable(__hcx, __hasher); - args.hash_stable(__hcx, __hasher); - } - Foreign(def_id) => { - def_id.hash_stable(__hcx, __hasher); - } - Str => {} - Array(t, c) => { - t.hash_stable(__hcx, __hasher); - c.hash_stable(__hcx, __hasher); - } - Slice(t) => { - t.hash_stable(__hcx, __hasher); - } - RawPtr(tam) => { - tam.hash_stable(__hcx, __hasher); - } - Ref(r, t, m) => { - r.hash_stable(__hcx, __hasher); - t.hash_stable(__hcx, __hasher); - m.hash_stable(__hcx, __hasher); - } - FnDef(def_id, args) => { - def_id.hash_stable(__hcx, __hasher); - args.hash_stable(__hcx, __hasher); - } - FnPtr(polyfnsig) => { - polyfnsig.hash_stable(__hcx, __hasher); - } - Dynamic(l, r, repr) => { - l.hash_stable(__hcx, __hasher); - r.hash_stable(__hcx, __hasher); - repr.hash_stable(__hcx, __hasher); - } - Closure(def_id, args) => { - def_id.hash_stable(__hcx, __hasher); - args.hash_stable(__hcx, __hasher); - } - Coroutine(def_id, args, m) => { - def_id.hash_stable(__hcx, __hasher); - args.hash_stable(__hcx, __hasher); - m.hash_stable(__hcx, __hasher); - } - CoroutineWitness(def_id, args) => { - def_id.hash_stable(__hcx, __hasher); - args.hash_stable(__hcx, __hasher); - } - Never => {} - Tuple(args) => { - args.hash_stable(__hcx, __hasher); - } - Alias(k, p) => { - k.hash_stable(__hcx, __hasher); - p.hash_stable(__hcx, __hasher); - } - Param(p) => { - p.hash_stable(__hcx, __hasher); - } - Bound(d, b) => { - d.hash_stable(__hcx, __hasher); - b.hash_stable(__hcx, __hasher); - } - Placeholder(p) => { - p.hash_stable(__hcx, __hasher); - } - Infer(i) => { - i.hash_stable(__hcx, __hasher); - } - Error(d) => { - d.hash_stable(__hcx, __hasher); - } - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum IntTy { Isize, I8, @@ -641,7 +531,7 @@ impl IntTy { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum UintTy { Usize, U8, @@ -699,7 +589,7 @@ impl UintTy { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum FloatTy { F32, F64, @@ -732,19 +622,28 @@ pub struct FloatVarValue(pub FloatTy); rustc_index::newtype_index! { /// A **ty**pe **v**ariable **ID**. + #[encodable] + #[orderable] #[debug_format = "?{}t"] + #[gate_rustc_only] pub struct TyVid {} } rustc_index::newtype_index! { /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. + #[encodable] + #[orderable] #[debug_format = "?{}i"] + #[gate_rustc_only] pub struct IntVid {} } rustc_index::newtype_index! { /// A **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. + #[encodable] + #[orderable] #[debug_format = "?{}f"] + #[gate_rustc_only] pub struct FloatVid {} } @@ -753,7 +652,8 @@ rustc_index::newtype_index! { /// E.g., if we have an empty array (`[]`), then we create a fresh /// type variable for the element type since we won't know until it's /// used what the element type is supposed to be. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] pub enum InferTy { /// A type variable. TyVar(TyVid), @@ -786,6 +686,7 @@ pub enum InferTy { /// Raw `TyVid` are used as the unification key for `sub_relations`; /// they carry no values. +#[cfg(feature = "nightly")] impl UnifyKey for TyVid { type Value = (); #[inline] @@ -801,8 +702,10 @@ impl UnifyKey for TyVid { } } +#[cfg(feature = "nightly")] impl EqUnifyValue for IntVarValue {} +#[cfg(feature = "nightly")] impl UnifyKey for IntVid { type Value = Option<IntVarValue>; #[inline] // make this function eligible for inlining - it is quite hot. @@ -818,8 +721,10 @@ impl UnifyKey for IntVid { } } +#[cfg(feature = "nightly")] impl EqUnifyValue for FloatVarValue {} +#[cfg(feature = "nightly")] impl UnifyKey for FloatVid { type Value = Option<FloatVarValue>; #[inline] @@ -835,10 +740,11 @@ impl UnifyKey for FloatVid { } } +#[cfg(feature = "nightly")] impl<CTX> HashStable<CTX> for InferTy { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; - discriminant(self).hash_stable(ctx, hasher); + std::mem::discriminant(self).hash_stable(ctx, hasher); match self { TyVar(_) | IntVar(_) | FloatVar(_) => { panic!("type variables should not be hashed: {self:?}") @@ -909,20 +815,59 @@ impl fmt::Debug for InferTy { } } -impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy { +impl<I: Interner> DebugWithInfcx<I> for InferTy { fn fmt<Infcx: InferCtxtLike<Interner = I>>( this: WithInfcx<'_, Infcx, &Self>, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { - use InferTy::*; - match this.infcx.universe_of_ty(*this.data) { - None => write!(f, "{:?}", this.data), - Some(universe) => match *this.data { - TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()), - IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => { - unreachable!() + match this.data { + InferTy::TyVar(vid) => { + if let Some(universe) = this.infcx.universe_of_ty(*vid) { + write!(f, "?{}_{}t", vid.index(), universe.index()) + } else { + write!(f, "{:?}", this.data) } - }, + } + _ => write!(f, "{:?}", this.data), } } } + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialOrd(bound = ""), + Ord(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Hash(bound = ""), + Debug(bound = "") +)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct TypeAndMut<I: Interner> { + pub ty: I::Ty, + pub mutbl: Mutability, +} + +impl<I: Interner> TypeFoldable<I> for TypeAndMut<I> +where + I::Ty: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(TypeAndMut { + ty: self.ty.try_fold_with(folder)?, + mutbl: self.mutbl.try_fold_with(folder)?, + }) + } +} + +impl<I: Interner> TypeVisitable<I> for TypeAndMut<I> +where + I::Ty: TypeVisitable<I>, +{ + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> std::ops::ControlFlow<V::BreakTy> { + self.ty.visit_with(visitor)?; + self.mutbl.visit_with(visitor) + } +} diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 9c7b8156b..7aa990046 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -41,12 +41,12 @@ //! - u.visit_with(visitor) //! ``` -use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use std::fmt; use std::ops::ControlFlow; use crate::Interner; +use crate::Lrc; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -82,8 +82,12 @@ pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> { /// method defined for every type of interest. Each such method has a default /// that recurses into the type's fields in a non-custom fashion. pub trait TypeVisitor<I: Interner>: Sized { + #[cfg(feature = "nightly")] type BreakTy = !; + #[cfg(not(feature = "nightly"))] + type BreakTy; + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy> where I::Binder<T>: TypeSuperVisitable<I>, |