diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 64b63f4c5eb4f..a4e8acf3d667e 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -23,6 +23,8 @@ use rustc_macros::HashStable; use rustc_type_ir::Canonical as IrCanonical; +use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo; +pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind}; use smallvec::SmallVec; use std::ops::Index; @@ -33,6 +35,8 @@ use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; pub type Canonical<'tcx, V> = IrCanonical, V>; +pub type CanonicalVarInfo<'tcx> = IrCanonicalVarInfo>; + pub type CanonicalVarInfos<'tcx> = &'tcx List>; impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { @@ -138,158 +142,6 @@ impl<'tcx> Default for OriginalQueryValues<'tcx> { } } -/// 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(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct CanonicalVarInfo<'tcx> { - pub kind: CanonicalVarKind<'tcx>, -} - -impl<'tcx> CanonicalVarInfo<'tcx> { - pub fn universe(&self) -> ty::UniverseIndex { - self.kind.universe() - } - - #[must_use] - pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarInfo<'tcx> { - 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 => bug!("expected placeholder: {self:?}"), - - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(), - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.bound.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(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] -pub enum CanonicalVarKind<'tcx> { - /// Some kind of type inference variable. - Ty(CanonicalTyVarKind), - - /// A "placeholder" that represents "any type". - PlaceholderTy(ty::PlaceholderType), - - /// Region variable `'?R`. - Region(ty::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(ty::PlaceholderRegion), - - /// Some kind of const inference variable. - Const(ty::UniverseIndex, Ty<'tcx>), - - /// Effect variable `'?E`. - Effect, - - /// A "placeholder" that represents "any const". - PlaceholderConst(ty::PlaceholderConst, Ty<'tcx>), -} - -impl<'tcx> CanonicalVarKind<'tcx> { - pub fn universe(self) -> ty::UniverseIndex { - match self { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui, - CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { - ty::UniverseIndex::ROOT - } - CanonicalVarKind::Effect => ty::UniverseIndex::ROOT, - CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, - CanonicalVarKind::Region(ui) => ui, - CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, - CanonicalVarKind::Const(ui, _) => ui, - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe, - } - } - - /// 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: ty::UniverseIndex) -> CanonicalVarKind<'tcx> { - match self { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) - } - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) - | CanonicalVarKind::Effect => { - assert_eq!(ui, ty::UniverseIndex::ROOT); - self - } - CanonicalVarKind::PlaceholderTy(placeholder) => { - CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder }) - } - CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), - CanonicalVarKind::PlaceholderRegion(placeholder) => { - CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe: ui, ..placeholder }) - } - CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), - CanonicalVarKind::PlaceholderConst(placeholder, ty) => { - CanonicalVarKind::PlaceholderConst( - ty::Placeholder { universe: ui, ..placeholder }, - ty, - ) - } - } - } -} - -/// 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, TyDecodable, TyEncodable, HashStable)] -pub enum CanonicalTyVarKind { - /// General type variable `?T` that can be unified with arbitrary types. - General(ty::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, -} - /// After we execute a query with a canonicalized key, we get back a /// `Canonical>`. You can use /// `instantiate_query_result` to access the data in this result. @@ -366,7 +218,6 @@ pub type QueryOutlivesConstraint<'tcx> = TrivialTypeTraversalImpls! { crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalTyVarKind, } impl<'tcx> CanonicalVarValues<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c33803925de99..24b6c15488b62 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1518,8 +1518,36 @@ pub struct Placeholder { pub type PlaceholderRegion = Placeholder; +impl rustc_type_ir::Placeholder for PlaceholderRegion { + fn universe(&self) -> UniverseIndex { + self.universe + } + + fn var(&self) -> BoundVar { + self.bound.var + } + + fn with_updated_universe(self, ui: UniverseIndex) -> Self { + Placeholder { universe: ui, ..self } + } +} + pub type PlaceholderType = Placeholder; +impl rustc_type_ir::Placeholder for PlaceholderType { + fn universe(&self) -> UniverseIndex { + self.universe + } + + fn var(&self) -> BoundVar { + self.bound.var + } + + fn with_updated_universe(self, ui: UniverseIndex) -> Self { + Placeholder { universe: ui, ..self } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TyEncodable, TyDecodable, PartialOrd, Ord)] pub struct BoundConst<'tcx> { @@ -1529,6 +1557,20 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst = Placeholder; +impl rustc_type_ir::Placeholder for PlaceholderConst { + fn universe(&self) -> UniverseIndex { + self.universe + } + + fn var(&self) -> BoundVar { + self.bound + } + + fn with_updated_universe(self, ui: UniverseIndex) -> Self { + Placeholder { universe: ui, ..self } + } +} + /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this /// particular point. diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 08a52865fa67b..1fdcf2f8faeb8 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{Interner, UniverseIndex}; +use crate::{Interner, Placeholder, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are @@ -113,3 +113,257 @@ 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 = ""), + Hash(bound = ""), + Copy(bound = "CanonicalVarKind: Copy"), + Debug(bound = "") +)] +#[derive(TyDecodable, TyEncodable, HashStable_NoContext)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, +} + +impl PartialEq for CanonicalVarInfo { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + } +} + +impl Eq for CanonicalVarInfo {} + +impl TypeVisitable for CanonicalVarInfo +where + I::Ty: TypeVisitable, +{ + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.kind.visit_with(visitor) + } +} + +impl TypeFoldable for CanonicalVarInfo +where + I::Ty: TypeFoldable, +{ + fn try_fold_with>(self, folder: &mut F) -> Result { + Ok(CanonicalVarInfo { kind: self.kind.try_fold_with(folder)? }) + } +} + +impl CanonicalVarInfo { + pub fn universe(&self) -> UniverseIndex { + self.kind.universe() + } + + #[must_use] + pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarInfo { + 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 = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive(TyDecodable, TyEncodable, HashStable_NoContext)] +pub enum CanonicalVarKind { + /// 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 Copy for CanonicalVarKind +where + I::PlaceholderTy: Copy, + I::PlaceholderRegion: Copy, + I::PlaceholderConst: Copy, + I::Ty: Copy, +{ +} + +impl PartialEq for CanonicalVarKind { + 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 Eq for CanonicalVarKind {} + +impl TypeVisitable for CanonicalVarKind +where + I::Ty: TypeVisitable, +{ + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + 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 TypeFoldable for CanonicalVarKind +where + I::Ty: TypeFoldable, +{ + fn try_fold_with>(self, folder: &mut F) -> Result { + 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 CanonicalVarKind { + 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 { + 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)] +#[derive(Decodable, Encodable, 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/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7f75e5b35a204..b3b58957eb003 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,7 +2,7 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; -use crate::{DebugWithInfcx, Mutability}; +use crate::{BoundVar, DebugWithInfcx, Mutability, UniverseIndex}; pub trait Interner: Sized { type DefId: Clone + Debug + Hash + Ord; @@ -26,7 +26,7 @@ pub trait Interner: Sized { type AliasTy: Clone + DebugWithInfcx + Hash + Ord; type ParamTy: Clone + Debug + Hash + Ord; type BoundTy: Clone + Debug + Hash + Ord; - type PlaceholderTy: Clone + Debug + Hash + Ord; + type PlaceholderTy: Clone + Debug + Hash + Ord + Placeholder; type InferTy: Clone + DebugWithInfcx + Hash + Ord; // Things stored inside of tys @@ -39,7 +39,7 @@ pub trait Interner: Sized { type Const: Clone + DebugWithInfcx + Hash + Ord; type InferConst: Clone + DebugWithInfcx + Hash + Ord; type AliasConst: Clone + DebugWithInfcx + Hash + Ord; - type PlaceholderConst: Clone + Debug + Hash + Ord; + type PlaceholderConst: Clone + Debug + Hash + Ord + Placeholder; type ParamConst: Clone + Debug + Hash + Ord; type BoundConst: Clone + Debug + Hash + Ord; type ValueConst: Clone + Debug + Hash + Ord; @@ -51,7 +51,7 @@ pub trait Interner: Sized { type BoundRegion: Clone + Debug + Hash + Ord; type FreeRegion: Clone + Debug + Hash + Ord; type InferRegion: Clone + DebugWithInfcx + Hash + Ord; - type PlaceholderRegion: Clone + Debug + Hash + Ord; + type PlaceholderRegion: Clone + Debug + Hash + Ord + Placeholder; // Predicates type Predicate: Clone + Debug + Hash + Eq; @@ -66,6 +66,14 @@ pub trait Interner: Sized { fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability); } +/// Common capabilities of placeholder kinds +pub trait Placeholder { + fn universe(&self) -> UniverseIndex; + fn var(&self) -> BoundVar; + + fn with_updated_universe(self, ui: UniverseIndex) -> Self; +} + /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` /// that produces `T` items. You could combine them with /// `f(&iter.collect::>())`, but this requires allocating memory for the