//! Defines the IR for types and logical predicates. #![deny(rust_2018_idioms)] #![warn(missing_docs)] // Allows macros to refer to this crate as `::chalk_ir` extern crate self as chalk_ir; use crate::cast::{Cast, CastTo, Caster}; use crate::fold::shift::Shift; use crate::fold::{FallibleTypeFolder, Subst, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor, VisitExt}; use chalk_derive::{ FallibleTypeFolder, HasInterner, TypeFoldable, TypeSuperVisitable, TypeVisitable, Zip, }; use std::marker::PhantomData; use std::ops::ControlFlow; pub use crate::debug::SeparatorTraitRef; #[macro_use(bitflags)] extern crate bitflags; /// Uninhabited (empty) type, used in combination with `PhantomData`. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Void {} /// Many of our internal operations (e.g., unification) are an attempt /// to perform some operation which may not complete. pub type Fallible = Result; /// A combination of `Fallible` and `Floundered`. pub enum FallibleOrFloundered { /// Success Ok(T), /// No solution. See `chalk_ir::NoSolution`. NoSolution, /// Floundered. See `chalk_ir::Floundered`. Floundered, } /// Indicates that the attempted operation has "no solution" -- i.e., /// cannot be performed. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct NoSolution; /// Indicates that the complete set of program clauses for this goal /// cannot be enumerated. pub struct Floundered; macro_rules! impl_debugs { ($($id:ident), *) => { $( impl std::fmt::Debug for $id { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!(fmt, "{}({:?})", stringify!($id), self.0) } } )* }; } #[macro_use] pub mod zip; #[macro_use] pub mod fold; #[macro_use] pub mod visit; pub mod cast; pub mod interner; use interner::{HasInterner, Interner}; pub mod could_match; pub mod debug; /// Variance #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Variance { /// a <: b Covariant, /// a == b Invariant, /// b <: a Contravariant, } impl Variance { /// `a.xform(b)` combines the variance of a context with the /// variance of a type with the following meaning. If we are in a /// context with variance `a`, and we encounter a type argument in /// a position with variance `b`, then `a.xform(b)` is the new /// variance with which the argument appears. /// /// Example 1: /// /// ```ignore /// *mut Vec /// ``` /// /// Here, the "ambient" variance starts as covariant. `*mut T` is /// invariant with respect to `T`, so the variance in which the /// `Vec` appears is `Covariant.xform(Invariant)`, which /// yields `Invariant`. Now, the type `Vec` is covariant with /// respect to its type argument `T`, and hence the variance of /// the `i32` here is `Invariant.xform(Covariant)`, which results /// (again) in `Invariant`. /// /// Example 2: /// /// ```ignore /// fn(*const Vec, *mut Vec` appears is /// `Contravariant.xform(Covariant)` or `Contravariant`. The same /// is true for its `i32` argument. In the `*mut T` case, the /// variance of `Vec` is `Contravariant.xform(Invariant)`, /// and hence the outermost type is `Invariant` with respect to /// `Vec` (and its `i32` argument). /// /// Source: Figure 1 of "Taming the Wildcards: /// Combining Definition- and Use-Site Variance" published in PLDI'11. /// (Doc from rustc) pub fn xform(self, other: Variance) -> Variance { match (self, other) { (Variance::Invariant, _) => Variance::Invariant, (_, Variance::Invariant) => Variance::Invariant, (_, Variance::Covariant) => self, (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant, (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant, } } /// Converts `Covariant` into `Contravariant` and vice-versa. `Invariant` /// stays the same. pub fn invert(self) -> Variance { match self { Variance::Invariant => Variance::Invariant, Variance::Covariant => Variance::Contravariant, Variance::Contravariant => Variance::Covariant, } } } #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] /// The set of assumptions we've made so far, and the current number of /// universal (forall) quantifiers we're within. pub struct Environment { /// The clauses in the environment. pub clauses: ProgramClauses, } impl Copy for Environment where I::InternedProgramClauses: Copy {} impl Environment { /// Creates a new environment. pub fn new(interner: I) -> Self { Environment { clauses: ProgramClauses::empty(interner), } } /// Adds (an iterator of) clauses to the environment. pub fn add_clauses(&self, interner: I, clauses: II) -> Self where II: IntoIterator>, { let mut env = self.clone(); env.clauses = ProgramClauses::from_iter(interner, env.clauses.iter(interner).cloned().chain(clauses)); env } /// True if any of the clauses in the environment have a consequence of `Compatible`. /// Panics if the conditions or constraints of that clause are not empty. pub fn has_compatible_clause(&self, interner: I) -> bool { self.clauses.as_slice(interner).iter().any(|c| { let ProgramClauseData(implication) = c.data(interner); match implication.skip_binders().consequence { DomainGoal::Compatible => { // We currently don't generate `Compatible` with any conditions or constraints // If this was needed, for whatever reason, then a third "yes, but must evaluate" // return value would have to be added. assert!(implication.skip_binders().conditions.is_empty(interner)); assert!(implication.skip_binders().constraints.is_empty(interner)); true } _ => false, } }) } } /// A goal with an environment to solve it in. #[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] #[allow(missing_docs)] pub struct InEnvironment { pub environment: Environment, pub goal: G, } impl + Copy, I: Interner> Copy for InEnvironment where I::InternedProgramClauses: Copy { } impl InEnvironment { /// Creates a new environment/goal pair. pub fn new(environment: &Environment, goal: G) -> Self { InEnvironment { environment: environment.clone(), goal, } } /// Maps the goal without touching the environment. pub fn map(self, op: OP) -> InEnvironment where OP: FnOnce(G) -> H, H: HasInterner, { InEnvironment { environment: self.environment, goal: op(self.goal), } } } impl HasInterner for InEnvironment { type Interner = G::Interner; } /// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(missing_docs)] pub enum IntTy { Isize, I8, I16, I32, I64, I128, } /// Different unsigned int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(missing_docs)] pub enum UintTy { Usize, U8, U16, U32, U64, U128, } /// Different kinds of float types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(missing_docs)] pub enum FloatTy { F32, F64, } /// Types of scalar values. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(missing_docs)] pub enum Scalar { Bool, Char, Int(IntTy), Uint(UintTy), Float(FloatTy), } /// Whether a function is safe or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Safety { /// Safe Safe, /// Unsafe Unsafe, } /// Whether a type is mutable or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Mutability { /// Mutable Mut, /// Immutable Not, } /// An universe index is how a universally quantified parameter is /// represented when it's binder is moved into the environment. /// An example chain of transformations would be: /// `forall { Goal(T) }` (syntactical representation) /// `forall { Goal(?0) }` (used a DeBruijn index) /// `Goal(!U1)` (the quantifier was moved to the environment and replaced with a universe index) /// See for more. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UniverseIndex { /// The counter for the universe index, starts with 0. pub counter: usize, } impl UniverseIndex { /// Root universe index (0). pub const ROOT: UniverseIndex = UniverseIndex { counter: 0 }; /// Root universe index (0). pub fn root() -> UniverseIndex { Self::ROOT } /// Whether one universe can "see" another. pub fn can_see(self, ui: UniverseIndex) -> bool { self.counter >= ui.counter } /// Increases the index counter. pub fn next(self) -> UniverseIndex { UniverseIndex { counter: self.counter + 1, } } } /// Maps the universes found in the `u_canonicalize` result (the /// "canonical" universes) to the universes found in the original /// value (and vice versa). When used as a folder -- i.e., from /// outside this module -- converts from "canonical" universes to the /// original (but see the `UMapToCanonical` folder). #[derive(Clone, Debug)] pub struct UniverseMap { /// A reverse map -- for each universe Ux that appears in /// `quantified`, the corresponding universe in the original was /// `universes[x]`. pub universes: Vec, } impl UniverseMap { /// Creates a new universe map. pub fn new() -> Self { UniverseMap { universes: vec![UniverseIndex::root()], } } /// Number of canonical universes. pub fn num_canonical_universes(&self) -> usize { self.universes.len() } } /// The id for an Abstract Data Type (i.e. structs, unions and enums). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AdtId(pub I::InternedAdtId); /// The id of a trait definition; could be used to load the trait datum by /// invoking the [`trait_datum`] method. /// /// [`trait_datum`]: ../chalk_solve/trait.RustIrDatabase.html#tymethod.trait_datum #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TraitId(pub I::DefId); /// The id for an impl. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ImplId(pub I::DefId); /// Id for a specific clause. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClauseId(pub I::DefId); /// The id for the associated type member of a trait. The details of the type /// can be found by invoking the [`associated_ty_data`] method. /// /// [`associated_ty_data`]: ../chalk_solve/trait.RustIrDatabase.html#tymethod.associated_ty_data #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssocTypeId(pub I::DefId); /// Id for an opaque type. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OpaqueTyId(pub I::DefId); /// Function definition id. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FnDefId(pub I::DefId); /// Id for Rust closures. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); /// Id for Rust generators. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct GeneratorId(pub I::DefId); /// Id for foreign types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ForeignDefId(pub I::DefId); impl_debugs!(ImplId, ClauseId); /// A Rust type. The actual type data is stored in `TyKind`. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Ty { interned: I::InternedType, } impl Ty { /// Creates a type from `TyKind`. pub fn new(interner: I, data: impl CastTo>) -> Self { let ty_kind = data.cast(interner); Ty { interned: I::intern_ty(interner, ty_kind), } } /// Gets the interned type. pub fn interned(&self) -> &I::InternedType { &self.interned } /// Gets the underlying type data. pub fn data(&self, interner: I) -> &TyData { I::ty_data(interner, &self.interned) } /// Gets the underlying type kind. pub fn kind(&self, interner: I) -> &TyKind { &I::ty_data(interner, &self.interned).kind } /// Creates a `FromEnv` constraint using this type. pub fn from_env(&self) -> FromEnv { FromEnv::Ty(self.clone()) } /// Creates a WF-constraint for this type. pub fn well_formed(&self) -> WellFormed { WellFormed::Ty(self.clone()) } /// Creates a domain goal `FromEnv(T)` where `T` is this type. pub fn into_from_env_goal(self, interner: I) -> DomainGoal { self.from_env().cast(interner) } /// If this is a `TyKind::BoundVar(d)`, returns `Some(d)` else `None`. pub fn bound_var(&self, interner: I) -> Option { if let TyKind::BoundVar(bv) = self.kind(interner) { Some(*bv) } else { None } } /// If this is a `TyKind::InferenceVar(d)`, returns `Some(d)` else `None`. pub fn inference_var(&self, interner: I) -> Option { if let TyKind::InferenceVar(depth, _) = self.kind(interner) { Some(*depth) } else { None } } /// Returns true if this is a `BoundVar` or an `InferenceVar` of `TyVariableKind::General`. pub fn is_general_var(&self, interner: I, binders: &CanonicalVarKinds) -> bool { match self.kind(interner) { TyKind::BoundVar(bv) if bv.debruijn == DebruijnIndex::INNERMOST && binders.at(interner, bv.index).kind == VariableKind::Ty(TyVariableKind::General) => { true } TyKind::InferenceVar(_, TyVariableKind::General) => true, _ => false, } } /// Returns true if this is an `Alias`. pub fn is_alias(&self, interner: I) -> bool { matches!(self.kind(interner), TyKind::Alias(..)) } /// Returns true if this is an `IntTy` or `UintTy`. pub fn is_integer(&self, interner: I) -> bool { matches!( self.kind(interner), TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_)) ) } /// Returns true if this is a `FloatTy`. pub fn is_float(&self, interner: I) -> bool { matches!(self.kind(interner), TyKind::Scalar(Scalar::Float(_))) } /// Returns `Some(adt_id)` if this is an ADT, `None` otherwise pub fn adt_id(&self, interner: I) -> Option> { match self.kind(interner) { TyKind::Adt(adt_id, _) => Some(*adt_id), _ => None, } } /// True if this type contains "bound" types/lifetimes, and hence /// needs to be shifted across binders. This is a very inefficient /// check, intended only for debug assertions, because I am lazy. pub fn needs_shift(&self, interner: I) -> bool { self.has_free_vars(interner) } } /// Contains the data for a Ty #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub struct TyData { /// The kind pub kind: TyKind, /// Type flags pub flags: TypeFlags, } bitflags! { /// Contains flags indicating various properties of a Ty pub struct TypeFlags : u16 { /// Does the type contain an InferenceVar const HAS_TY_INFER = 1; /// Does the type contain a lifetime with an InferenceVar const HAS_RE_INFER = 1 << 1; /// Does the type contain a ConstValue with an InferenceVar const HAS_CT_INFER = 1 << 2; /// Does the type contain a Placeholder TyKind const HAS_TY_PLACEHOLDER = 1 << 3; /// Does the type contain a lifetime with a Placeholder const HAS_RE_PLACEHOLDER = 1 << 4; /// Does the type contain a ConstValue Placeholder const HAS_CT_PLACEHOLDER = 1 << 5; /// True when the type has free lifetimes related to a local context const HAS_FREE_LOCAL_REGIONS = 1 << 6; /// Does the type contain a projection of an associated type const HAS_TY_PROJECTION = 1 << 7; /// Does the type contain an opaque type const HAS_TY_OPAQUE = 1 << 8; /// Does the type contain an unevaluated const projection const HAS_CT_PROJECTION = 1 << 9; /// Does the type contain an error const HAS_ERROR = 1 << 10; /// Does the type contain any free lifetimes const HAS_FREE_REGIONS = 1 << 11; /// True when the type contains lifetimes that will be substituted when function is called const HAS_RE_LATE_BOUND = 1 << 12; /// True when the type contains an erased lifetime const HAS_RE_ERASED = 1 << 13; /// Does the type contain placeholders or inference variables that could be replaced later const STILL_FURTHER_SPECIALIZABLE = 1 << 14; /// True when the type contains free names local to a particular context const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; /// Does the type contain any form of projection const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits | TypeFlags::HAS_TY_OPAQUE.bits | TypeFlags::HAS_CT_PROJECTION.bits; } } /// Type data, which holds the actual type information. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum TyKind { /// Abstract data types, i.e., structs, unions, or enumerations. /// For example, a type like `Vec`. Adt(AdtId, Substitution), /// an associated type like `Iterator::Item`; see `AssociatedType` for details AssociatedType(AssocTypeId, Substitution), /// a scalar type like `bool` or `u32` Scalar(Scalar), /// a tuple of the given arity Tuple(usize, Substitution), /// an array type like `[T; N]` Array(Ty, Const), /// a slice type like `[T]` Slice(Ty), /// a raw pointer type like `*const T` or `*mut T` Raw(Mutability, Ty), /// a reference type like `&T` or `&mut T` Ref(Mutability, Lifetime, Ty), /// a placeholder for opaque types like `impl Trait` OpaqueType(OpaqueTyId, Substitution), /// a function definition FnDef(FnDefId, Substitution), /// the string primitive type Str, /// the never type `!` Never, /// A closure. Closure(ClosureId, Substitution), /// A generator. Generator(GeneratorId, Substitution), /// A generator witness. GeneratorWitness(GeneratorId, Substitution), /// foreign types Foreign(ForeignDefId), /// This can be used to represent an error, e.g. during name resolution of a type. /// Chalk itself will not produce this, just pass it through when given. Error, /// instantiated from a universally quantified type, e.g., from /// `forall { .. }`. Stands in as a representative of "some /// unknown type". Placeholder(PlaceholderIndex), /// A "dyn" type is a trait object type created via the "dyn Trait" syntax. /// In the chalk parser, the traits that the object represents is parsed as /// a QuantifiedInlineBound, and is then changed to a list of where clauses /// during lowering. /// /// See the `Opaque` variant for a discussion about the use of /// binders here. Dyn(DynTy), /// An "alias" type represents some form of type alias, such as: /// - An associated type projection like `::Item` /// - `impl Trait` types /// - Named type aliases like `type Foo = Vec` Alias(AliasTy), /// A function type such as `for<'a> fn(&'a u32)`. /// Note that "higher-ranked" types (starting with `for<>`) are either /// function types or dyn types, and do not appear otherwise in Rust /// surface syntax. Function(FnPointer), /// References the binding at the given depth. The index is a [de /// Bruijn index], so it counts back through the in-scope binders. BoundVar(BoundVar), /// Inference variable defined in the current inference context. InferenceVar(InferenceVar, TyVariableKind), } impl Copy for TyKind where I::InternedLifetime: Copy, I::InternedSubstitution: Copy, I::InternedVariableKinds: Copy, I::InternedQuantifiedWhereClauses: Copy, I::InternedType: Copy, I::InternedConst: Copy, { } impl TyKind { /// Casts the type data to a type. pub fn intern(self, interner: I) -> Ty { Ty::new(interner, self) } /// Compute type flags for a TyKind pub fn compute_flags(&self, interner: I) -> TypeFlags { match self { TyKind::Adt(_, substitution) | TyKind::AssociatedType(_, substitution) | TyKind::Tuple(_, substitution) | TyKind::Closure(_, substitution) | TyKind::Generator(_, substitution) | TyKind::GeneratorWitness(_, substitution) | TyKind::FnDef(_, substitution) | TyKind::OpaqueType(_, substitution) => substitution.compute_flags(interner), TyKind::Scalar(_) | TyKind::Str | TyKind::Never | TyKind::Foreign(_) => { TypeFlags::empty() } TyKind::Error => TypeFlags::HAS_ERROR, TyKind::Slice(ty) | TyKind::Raw(_, ty) => ty.data(interner).flags, TyKind::Ref(_, lifetime, ty) => { lifetime.compute_flags(interner) | ty.data(interner).flags } TyKind::Array(ty, const_ty) => { let flags = ty.data(interner).flags; let const_data = const_ty.data(interner); flags | const_data.ty.data(interner).flags | match const_data.value { ConstValue::BoundVar(_) | ConstValue::Concrete(_) => TypeFlags::empty(), ConstValue::InferenceVar(_) => { TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE } ConstValue::Placeholder(_) => { TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE } } } TyKind::Placeholder(_) => TypeFlags::HAS_TY_PLACEHOLDER, TyKind::Dyn(dyn_ty) => { let lifetime_flags = dyn_ty.lifetime.compute_flags(interner); let mut dyn_flags = TypeFlags::empty(); for var_kind in dyn_ty.bounds.skip_binders().iter(interner) { match &(var_kind.skip_binders()) { WhereClause::Implemented(trait_ref) => { dyn_flags |= trait_ref.substitution.compute_flags(interner) } WhereClause::AliasEq(alias_eq) => { dyn_flags |= alias_eq.alias.compute_flags(interner); dyn_flags |= alias_eq.ty.data(interner).flags; } WhereClause::LifetimeOutlives(lifetime_outlives) => { dyn_flags |= lifetime_outlives.a.compute_flags(interner) | lifetime_outlives.b.compute_flags(interner); } WhereClause::TypeOutlives(type_outlives) => { dyn_flags |= type_outlives.ty.data(interner).flags; dyn_flags |= type_outlives.lifetime.compute_flags(interner); } } } lifetime_flags | dyn_flags } TyKind::Alias(alias_ty) => alias_ty.compute_flags(interner), TyKind::BoundVar(_) => TypeFlags::empty(), TyKind::InferenceVar(_, _) => TypeFlags::HAS_TY_INFER, TyKind::Function(fn_pointer) => fn_pointer.substitution.0.compute_flags(interner), } } } /// Identifies a particular bound variable within a binder. /// Variables are identified by the combination of a [`DebruijnIndex`], /// which identifies the *binder*, and an index within that binder. /// /// Consider this case: /// /// ```ignore /// forall<'a, 'b> { forall<'c, 'd> { ... } } /// ``` /// /// Within the `...` term: /// /// * the variable `'a` have a debruijn index of 1 and index 0 /// * the variable `'b` have a debruijn index of 1 and index 1 /// * the variable `'c` have a debruijn index of 0 and index 0 /// * the variable `'d` have a debruijn index of 0 and index 1 /// /// The variables `'a` and `'b` both have debruijn index of 1 because, /// counting out, they are the 2nd binder enclosing `...`. The indices /// identify the location *within* that binder. /// /// The variables `'c` and `'d` both have debruijn index of 0 because /// they appear in the *innermost* binder enclosing the `...`. The /// indices identify the location *within* that binder. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct BoundVar { /// Debruijn index, which identifies the binder. pub debruijn: DebruijnIndex, /// Index within the binder. pub index: usize, } impl BoundVar { /// Creates a new bound variable. pub fn new(debruijn: DebruijnIndex, index: usize) -> Self { Self { debruijn, index } } /// Casts the bound variable to a type. pub fn to_ty(self, interner: I) -> Ty { TyKind::::BoundVar(self).intern(interner) } /// Wrap the bound variable in a lifetime. pub fn to_lifetime(self, interner: I) -> Lifetime { LifetimeData::::BoundVar(self).intern(interner) } /// Wraps the bound variable in a constant. pub fn to_const(self, interner: I, ty: Ty) -> Const { ConstData { ty, value: ConstValue::::BoundVar(self), } .intern(interner) } /// True if this variable is bound within the `amount` innermost binders. pub fn bound_within(self, outer_binder: DebruijnIndex) -> bool { self.debruijn.within(outer_binder) } /// Adjusts the debruijn index (see [`DebruijnIndex::shifted_in`]). #[must_use] pub fn shifted_in(self) -> Self { BoundVar::new(self.debruijn.shifted_in(), self.index) } /// Adjusts the debruijn index (see [`DebruijnIndex::shifted_in`]). #[must_use] pub fn shifted_in_from(self, outer_binder: DebruijnIndex) -> Self { BoundVar::new(self.debruijn.shifted_in_from(outer_binder), self.index) } /// Adjusts the debruijn index (see [`DebruijnIndex::shifted_in`]). #[must_use] pub fn shifted_out(self) -> Option { self.debruijn .shifted_out() .map(|db| BoundVar::new(db, self.index)) } /// Adjusts the debruijn index (see [`DebruijnIndex::shifted_in`]). #[must_use] pub fn shifted_out_to(self, outer_binder: DebruijnIndex) -> Option { self.debruijn .shifted_out_to(outer_binder) .map(|db| BoundVar::new(db, self.index)) } /// Return the index of the bound variable, but only if it is bound /// at the innermost binder. Otherwise, returns `None`. pub fn index_if_innermost(self) -> Option { self.index_if_bound_at(DebruijnIndex::INNERMOST) } /// Return the index of the bound variable, but only if it is bound /// at the innermost binder. Otherwise, returns `None`. pub fn index_if_bound_at(self, debruijn: DebruijnIndex) -> Option { if self.debruijn == debruijn { Some(self.index) } else { None } } } /// References the binder at the given depth. The index is a [de /// Bruijn index], so it counts back through the in-scope binders, /// with 0 being the innermost binder. This is used in impls and /// the like. For example, if we had a rule like `for { (T: /// Clone) :- (T: Copy) }`, then `T` would be represented as a /// `BoundVar(0)` (as the `for` is the innermost binder). /// /// [de Bruijn index]: https://en.wikipedia.org/wiki/De_Bruijn_index #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct DebruijnIndex { depth: u32, } impl DebruijnIndex { /// Innermost index. pub const INNERMOST: DebruijnIndex = DebruijnIndex { depth: 0 }; /// One level higher than the innermost index. pub const ONE: DebruijnIndex = DebruijnIndex { depth: 1 }; /// Creates a new de Bruijn index with a given depth. pub fn new(depth: u32) -> Self { DebruijnIndex { depth } } /// Depth of the De Bruijn index, counting from 0 starting with /// the innermost binder. pub fn depth(self) -> u32 { self.depth } /// True if the binder identified by this index is within the /// binder identified by the index `outer_binder`. /// /// # Example /// /// Imagine you have the following binders in scope /// /// ```ignore /// forall forall forall /// ``` /// /// then the Debruijn index for `c` would be `0`, the index for /// `b` would be 1, and so on. Now consider the following calls: /// /// * `c.within(a) = true` /// * `b.within(a) = true` /// * `a.within(a) = false` /// * `a.within(c) = false` pub fn within(self, outer_binder: DebruijnIndex) -> bool { self < outer_binder } /// Returns the resulting index when this value is moved into /// through one binder. #[must_use] pub fn shifted_in(self) -> DebruijnIndex { self.shifted_in_from(DebruijnIndex::ONE) } /// Update this index in place by shifting it "in" through /// `amount` number of binders. pub fn shift_in(&mut self) { *self = self.shifted_in(); } /// Adds `outer_binder` levels to the `self` index. Intuitively, this /// shifts the `self` index, which was valid at the outer binder, /// so that it is valid at the innermost binder. /// /// Example: Assume that the following binders are in scope: /// /// ```ignore /// for for for for /// ^ outer binder /// ``` /// /// Assume further that the `outer_binder` argument is 2, /// which means that it is referring to the `for` binder /// (since `D` would be the innermost binder). /// /// This means that `self` is relative to the binder `B` -- so /// if `self` is 0 (`INNERMOST`), then it refers to `B`, /// and if `self` is 1, then it refers to `A`. /// /// We will return as follows: /// /// * `0.shifted_in_from(2) = 2` -- i.e., `B`, when shifted in to the binding level `D`, has index 2 /// * `1.shifted_in_from(2) = 3` -- i.e., `A`, when shifted in to the binding level `D`, has index 3 /// * `2.shifted_in_from(1) = 3` -- here, we changed the `outer_binder` to refer to `C`. /// Therefore `2` (relative to `C`) refers to `A`, so the result is still 3 (since `A`, relative to the /// innermost binder, has index 3). #[must_use] pub fn shifted_in_from(self, outer_binder: DebruijnIndex) -> DebruijnIndex { DebruijnIndex::new(self.depth() + outer_binder.depth()) } /// Returns the resulting index when this value is moved out from /// `amount` number of new binders. #[must_use] pub fn shifted_out(self) -> Option { self.shifted_out_to(DebruijnIndex::ONE) } /// Update in place by shifting out from `amount` binders. pub fn shift_out(&mut self) { *self = self.shifted_out().unwrap(); } /// Subtracts `outer_binder` levels from the `self` index. Intuitively, this /// shifts the `self` index, which was valid at the innermost /// binder, to one that is valid at the binder `outer_binder`. /// /// This will return `None` if the `self` index is internal to the /// outer binder (i.e., if `self < outer_binder`). /// /// Example: Assume that the following binders are in scope: /// /// ```ignore /// for for for for /// ^ outer binder /// ``` /// /// Assume further that the `outer_binder` argument is 2, /// which means that it is referring to the `for` binder /// (since `D` would be the innermost binder). /// /// This means that the result is relative to the binder `B` -- so /// if `self` is 0 (`INNERMOST`), then it refers to `B`, /// and if `self` is 1, then it refers to `A`. /// /// We will return as follows: /// /// * `1.shifted_out_to(2) = None` -- i.e., the binder for `C` can't be named from the binding level `B` /// * `3.shifted_out_to(2) = Some(1)` -- i.e., `A`, when shifted out to the binding level `B`, has index 1 pub fn shifted_out_to(self, outer_binder: DebruijnIndex) -> Option { if self.within(outer_binder) { None } else { Some(DebruijnIndex::new(self.depth() - outer_binder.depth())) } } } /// A "DynTy" represents a trait object (`dyn Trait`). Trait objects /// are conceptually very related to an "existential type" of the form /// `exists { T: Trait }` (another example of such type is `impl Trait`). /// `DynTy` represents the bounds on that type. /// /// The "bounds" here represents the unknown self type. So, a type like /// `dyn for<'a> Fn(&'a u32)` would be represented with two-levels of /// binder, as "depicted" here: /// /// ```notrust /// exists { /// vec![ /// // A QuantifiedWhereClause: /// forall { ^1.0: Fn(&^0.0 u32) } /// ] /// } /// ``` /// /// The outer `exists` binder indicates that there exists /// some type that meets the criteria within, but that type is not /// known. It is referenced within the type using `^1.0`, indicating /// a bound type with debruijn index 1 (i.e., skipping through one /// level of binder). #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct DynTy { /// The unknown self type. pub bounds: Binders>, /// Lifetime of the `DynTy`. pub lifetime: Lifetime, } impl Copy for DynTy where I::InternedLifetime: Copy, I::InternedQuantifiedWhereClauses: Copy, I::InternedVariableKinds: Copy, { } /// A type, lifetime or constant whose value is being inferred. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InferenceVar { index: u32, } impl From for InferenceVar { fn from(index: u32) -> InferenceVar { InferenceVar { index } } } impl InferenceVar { /// Gets the underlying index value. pub fn index(self) -> u32 { self.index } /// Wraps the inference variable in a type. pub fn to_ty(self, interner: I, kind: TyVariableKind) -> Ty { TyKind::::InferenceVar(self, kind).intern(interner) } /// Wraps the inference variable in a lifetime. pub fn to_lifetime(self, interner: I) -> Lifetime { LifetimeData::::InferenceVar(self).intern(interner) } /// Wraps the inference variable in a constant. pub fn to_const(self, interner: I, ty: Ty) -> Const { ConstData { ty, value: ConstValue::::InferenceVar(self), } .intern(interner) } } /// A function signature. #[derive(Clone, Copy, PartialEq, Eq, Hash, HasInterner, Debug)] #[allow(missing_docs)] pub struct FnSig { pub abi: I::FnAbi, pub safety: Safety, pub variadic: bool, } /// A wrapper for the substs on a Fn. #[derive(Clone, PartialEq, Eq, Hash, HasInterner, TypeFoldable, TypeVisitable)] pub struct FnSubst(pub Substitution); impl Copy for FnSubst where I::InternedSubstitution: Copy {} /// for<'a...'z> X -- all binders are instantiated at once, /// and we use deBruijn indices within `self.ty` #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] #[allow(missing_docs)] pub struct FnPointer { pub num_binders: usize, pub sig: FnSig, pub substitution: FnSubst, } impl Copy for FnPointer where I::InternedSubstitution: Copy {} impl FnPointer { /// Represent the current `Fn` as if it was wrapped in `Binders` pub fn into_binders(self, interner: I) -> Binders> { Binders::new( VariableKinds::from_iter( interner, (0..self.num_binders).map(|_| VariableKind::Lifetime), ), self.substitution, ) } /// Represent the current `Fn` as if it was wrapped in `Binders` pub fn as_binders(&self, interner: I) -> Binders<&FnSubst> { Binders::new( VariableKinds::from_iter( interner, (0..self.num_binders).map(|_| VariableKind::Lifetime), ), &self.substitution, ) } } /// Constants. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Const { interned: I::InternedConst, } impl Const { /// Create a `Const` using something that can be cast to const data. pub fn new(interner: I, data: impl CastTo>) -> Self { Const { interned: I::intern_const(interner, data.cast(interner)), } } /// Gets the interned constant. pub fn interned(&self) -> &I::InternedConst { &self.interned } /// Gets the constant data from the interner. pub fn data(&self, interner: I) -> &ConstData { I::const_data(interner, &self.interned) } /// If this is a `ConstData::BoundVar(d)`, returns `Some(d)` else `None`. pub fn bound_var(&self, interner: I) -> Option { if let ConstValue::BoundVar(bv) = &self.data(interner).value { Some(*bv) } else { None } } /// If this is a `ConstData::InferenceVar(d)`, returns `Some(d)` else `None`. pub fn inference_var(&self, interner: I) -> Option { if let ConstValue::InferenceVar(iv) = &self.data(interner).value { Some(*iv) } else { None } } /// True if this const is a "bound" const, and hence /// needs to be shifted across binders. Meant for debug assertions. pub fn needs_shift(&self, interner: I) -> bool { match &self.data(interner).value { ConstValue::BoundVar(_) => true, ConstValue::InferenceVar(_) => false, ConstValue::Placeholder(_) => false, ConstValue::Concrete(_) => false, } } } /// Constant data, containing the constant's type and value. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub struct ConstData { /// Type that holds the constant. pub ty: Ty, /// The value of the constant. pub value: ConstValue, } /// A constant value, not necessarily concrete. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum ConstValue { /// Bound var (e.g. a parameter). BoundVar(BoundVar), /// Constant whose value is being inferred. InferenceVar(InferenceVar), /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), /// Concrete constant value. Concrete(ConcreteConst), } impl Copy for ConstValue where I::InternedConcreteConst: Copy {} impl ConstData { /// Wraps the constant data in a `Const`. pub fn intern(self, interner: I) -> Const { Const::new(interner, self) } } /// Concrete constant, whose value is known (as opposed to /// inferred constants and placeholders). #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ConcreteConst { /// The interned constant. pub interned: I::InternedConcreteConst, } impl ConcreteConst { /// Checks whether two concrete constants are equal. pub fn const_eq(&self, ty: &Ty, other: &ConcreteConst, interner: I) -> bool { interner.const_eq(&ty.interned, &self.interned, &other.interned) } } /// A Rust lifetime. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Lifetime { interned: I::InternedLifetime, } impl Lifetime { /// Create a lifetime from lifetime data /// (or something that can be cast to lifetime data). pub fn new(interner: I, data: impl CastTo>) -> Self { Lifetime { interned: I::intern_lifetime(interner, data.cast(interner)), } } /// Gets the interned value. pub fn interned(&self) -> &I::InternedLifetime { &self.interned } /// Gets the lifetime data. pub fn data(&self, interner: I) -> &LifetimeData { I::lifetime_data(interner, &self.interned) } /// If this is a `Lifetime::BoundVar(d)`, returns `Some(d)` else `None`. pub fn bound_var(&self, interner: I) -> Option { if let LifetimeData::BoundVar(bv) = self.data(interner) { Some(*bv) } else { None } } /// If this is a `Lifetime::InferenceVar(d)`, returns `Some(d)` else `None`. pub fn inference_var(&self, interner: I) -> Option { if let LifetimeData::InferenceVar(depth) = self.data(interner) { Some(*depth) } else { None } } /// True if this lifetime is a "bound" lifetime, and hence /// needs to be shifted across binders. Meant for debug assertions. pub fn needs_shift(&self, interner: I) -> bool { match self.data(interner) { LifetimeData::BoundVar(_) => true, LifetimeData::InferenceVar(_) => false, LifetimeData::Placeholder(_) => false, LifetimeData::Static => false, LifetimeData::Erased => false, LifetimeData::Phantom(..) => unreachable!(), } } ///compute type flags for Lifetime fn compute_flags(&self, interner: I) -> TypeFlags { match self.data(interner) { LifetimeData::InferenceVar(_) => { TypeFlags::HAS_RE_INFER | TypeFlags::HAS_FREE_LOCAL_REGIONS | TypeFlags::HAS_FREE_REGIONS } LifetimeData::Placeholder(_) => { TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_FREE_LOCAL_REGIONS | TypeFlags::HAS_FREE_REGIONS } LifetimeData::Static => TypeFlags::HAS_FREE_REGIONS, LifetimeData::Phantom(_, _) => TypeFlags::empty(), LifetimeData::BoundVar(_) => TypeFlags::HAS_RE_LATE_BOUND, LifetimeData::Erased => TypeFlags::HAS_RE_ERASED, } } } /// Lifetime data, including what kind of lifetime it is and what it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub enum LifetimeData { /// See TyKind::BoundVar. BoundVar(BoundVar), /// Lifetime whose value is being inferred. InferenceVar(InferenceVar), /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), /// Static lifetime Static, /// An erased lifetime, used by rustc to improve caching when we doesn't /// care about lifetimes Erased, /// Lifetime on phantom data. Phantom(Void, PhantomData), } impl LifetimeData { /// Wrap the lifetime data in a lifetime. pub fn intern(self, interner: I) -> Lifetime { Lifetime::new(interner, self) } } /// Index of an universally quantified parameter in the environment. /// Two indexes are required, the one of the universe itself /// and the relative index inside the universe. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PlaceholderIndex { /// Index *of* the universe. pub ui: UniverseIndex, /// Index *in* the universe. pub idx: usize, } impl PlaceholderIndex { /// Wrap the placeholder instance in a lifetime. pub fn to_lifetime(self, interner: I) -> Lifetime { LifetimeData::::Placeholder(self).intern(interner) } /// Create an interned type. pub fn to_ty(self, interner: I) -> Ty { TyKind::Placeholder(self).intern(interner) } /// Wrap the placeholder index in a constant. pub fn to_const(self, interner: I, ty: Ty) -> Const { ConstData { ty, value: ConstValue::Placeholder(self), } .intern(interner) } } /// Represents some extra knowledge we may have about the type variable. /// ```ignore /// let x: &[u32]; /// let i = 1; /// x[i] /// ``` /// In this example, `i` is known to be some type of integer. We can infer that /// it is `usize` because that is the only integer type that slices have an /// `Index` impl for. `i` would have a `TyVariableKind` of `Integer` to guide the /// inference process. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub enum TyVariableKind { General, Integer, Float, } /// The "kind" of variable. Type, lifetime or constant. #[derive(Clone, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub enum VariableKind { Ty(TyVariableKind), Lifetime, Const(Ty), } impl interner::HasInterner for VariableKind { type Interner = I; } impl Copy for VariableKind where I::InternedType: Copy {} impl VariableKind { fn to_bound_variable(&self, interner: I, bound_var: BoundVar) -> GenericArg { match self { VariableKind::Ty(_) => { GenericArgData::Ty(TyKind::BoundVar(bound_var).intern(interner)).intern(interner) } VariableKind::Lifetime => { GenericArgData::Lifetime(LifetimeData::BoundVar(bound_var).intern(interner)) .intern(interner) } VariableKind::Const(ty) => GenericArgData::Const( ConstData { ty: ty.clone(), value: ConstValue::BoundVar(bound_var), } .intern(interner), ) .intern(interner), } } } /// A generic argument, see `GenericArgData` for more information. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct GenericArg { interned: I::InternedGenericArg, } impl GenericArg { /// Constructs a generic argument using `GenericArgData`. pub fn new(interner: I, data: GenericArgData) -> Self { let interned = I::intern_generic_arg(interner, data); GenericArg { interned } } /// Gets the interned value. pub fn interned(&self) -> &I::InternedGenericArg { &self.interned } /// Gets the underlying data. pub fn data(&self, interner: I) -> &GenericArgData { I::generic_arg_data(interner, &self.interned) } /// Asserts that this is a type argument. pub fn assert_ty_ref(&self, interner: I) -> &Ty { self.ty(interner).unwrap() } /// Asserts that this is a lifetime argument. pub fn assert_lifetime_ref(&self, interner: I) -> &Lifetime { self.lifetime(interner).unwrap() } /// Asserts that this is a constant argument. pub fn assert_const_ref(&self, interner: I) -> &Const { self.constant(interner).unwrap() } /// Checks whether the generic argument is a type. pub fn is_ty(&self, interner: I) -> bool { match self.data(interner) { GenericArgData::Ty(_) => true, GenericArgData::Lifetime(_) => false, GenericArgData::Const(_) => false, } } /// Returns the type if it is one, `None` otherwise. pub fn ty(&self, interner: I) -> Option<&Ty> { match self.data(interner) { GenericArgData::Ty(t) => Some(t), _ => None, } } /// Returns the lifetime if it is one, `None` otherwise. pub fn lifetime(&self, interner: I) -> Option<&Lifetime> { match self.data(interner) { GenericArgData::Lifetime(t) => Some(t), _ => None, } } /// Returns the constant if it is one, `None` otherwise. pub fn constant(&self, interner: I) -> Option<&Const> { match self.data(interner) { GenericArgData::Const(c) => Some(c), _ => None, } } /// Compute type flags for GenericArg fn compute_flags(&self, interner: I) -> TypeFlags { match self.data(interner) { GenericArgData::Ty(ty) => ty.data(interner).flags, GenericArgData::Lifetime(lifetime) => lifetime.compute_flags(interner), GenericArgData::Const(constant) => { let data = constant.data(interner); let flags = data.ty.data(interner).flags; match data.value { ConstValue::BoundVar(_) => flags, ConstValue::InferenceVar(_) => { flags | TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE } ConstValue::Placeholder(_) => { flags | TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE } ConstValue::Concrete(_) => flags, } } } } } /// Generic arguments data. #[derive(Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, Zip)] pub enum GenericArgData { /// Type argument Ty(Ty), /// Lifetime argument Lifetime(Lifetime), /// Constant argument Const(Const), } impl Copy for GenericArgData where I::InternedType: Copy, I::InternedLifetime: Copy, I::InternedConst: Copy, { } impl GenericArgData { /// Create an interned type. pub fn intern(self, interner: I) -> GenericArg { GenericArg::new(interner, self) } } /// A value with an associated variable kind. #[derive(Clone, PartialEq, Eq, Hash)] pub struct WithKind { /// The associated variable kind. pub kind: VariableKind, /// The wrapped value. value: T, } impl Copy for WithKind where I::InternedType: Copy {} impl HasInterner for WithKind { type Interner = I; } impl From> for (VariableKind, T) { fn from(with_kind: WithKind) -> Self { (with_kind.kind, with_kind.value) } } impl WithKind { /// Creates a `WithKind` from a variable kind and a value. pub fn new(kind: VariableKind, value: T) -> Self { Self { kind, value } } /// Maps the value in `WithKind`. pub fn map(self, op: OP) -> WithKind where OP: FnOnce(T) -> U, { WithKind { kind: self.kind, value: op(self.value), } } /// Maps a function taking `WithKind` over `&WithKind`. pub fn map_ref(&self, op: OP) -> WithKind where OP: FnOnce(&T) -> U, { WithKind { kind: self.kind.clone(), value: op(&self.value), } } /// Extract the value, ignoring the variable kind. pub fn skip_kind(&self) -> &T { &self.value } } /// A variable kind with universe index. #[allow(type_alias_bounds)] pub type CanonicalVarKind = WithKind; /// An alias, which is a trait indirection such as a projection or opaque type. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub enum AliasTy { /// An associated type projection. Projection(ProjectionTy), /// An opaque type. Opaque(OpaqueTy), } impl Copy for AliasTy where I::InternedSubstitution: Copy {} impl AliasTy { /// Create an interned type for this alias. pub fn intern(self, interner: I) -> Ty { Ty::new(interner, self) } /// Compute type flags for aliases fn compute_flags(&self, interner: I) -> TypeFlags { match self { AliasTy::Projection(projection_ty) => { TypeFlags::HAS_TY_PROJECTION | projection_ty.substitution.compute_flags(interner) } AliasTy::Opaque(opaque_ty) => { TypeFlags::HAS_TY_OPAQUE | opaque_ty.substitution.compute_flags(interner) } } } } /// A projection `>::AssocItem`. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct ProjectionTy { /// The id for the associated type member. pub associated_ty_id: AssocTypeId, /// The substitution for the projection. pub substitution: Substitution, } impl Copy for ProjectionTy where I::InternedSubstitution: Copy {} /// An opaque type `opaque type T<..>: Trait = HiddenTy`. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct OpaqueTy { /// The id for the opaque type. pub opaque_ty_id: OpaqueTyId, /// The substitution for the opaque type. pub substitution: Substitution, } impl Copy for OpaqueTy where I::InternedSubstitution: Copy {} /// A trait reference describes the relationship between a type and a trait. /// This can be used in two forms: /// - `P0: Trait` (e.g. `i32: Copy`), which mentions that the type /// implements the trait. /// - `>` (e.g. `i32 as Copy`), which casts the type to /// that specific trait. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct TraitRef { /// The trait id. pub trait_id: TraitId, /// The substitution, containing both the `Self` type and the parameters. pub substitution: Substitution, } impl Copy for TraitRef where I::InternedSubstitution: Copy {} impl TraitRef { /// Gets all type parameters in this trait ref, including `Self`. pub fn type_parameters(&self, interner: I) -> impl Iterator> + '_ { self.substitution .iter(interner) .filter_map(move |p| p.ty(interner)) .cloned() } /// Gets the type parameters of the `Self` type in this trait ref. pub fn self_type_parameter(&self, interner: I) -> Ty { self.type_parameters(interner).next().unwrap() } /// Construct a `FromEnv` using this trait ref. pub fn from_env(self) -> FromEnv { FromEnv::Trait(self) } /// Construct a `WellFormed` using this trait ref. pub fn well_formed(self) -> WellFormed { WellFormed::Trait(self) } } /// Lifetime outlives, which for `'a: 'b`` checks that the lifetime `'a` /// is a superset of the value of `'b`. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] #[allow(missing_docs)] pub struct LifetimeOutlives { pub a: Lifetime, pub b: Lifetime, } impl Copy for LifetimeOutlives where I::InternedLifetime: Copy {} /// Type outlives, which for `T: 'a` checks that the type `T` /// lives at least as long as the lifetime `'a` #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub struct TypeOutlives { /// The type which must outlive the given lifetime. pub ty: Ty, /// The lifetime which the type must outlive. pub lifetime: Lifetime, } impl Copy for TypeOutlives where I::InternedLifetime: Copy, I::InternedType: Copy, { } /// Where clauses that can be written by a Rust programmer. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeSuperVisitable, HasInterner, Zip)] pub enum WhereClause { /// Type implements a trait. Implemented(TraitRef), /// Type is equal to an alias. AliasEq(AliasEq), /// One lifetime outlives another. LifetimeOutlives(LifetimeOutlives), /// Type outlives a lifetime. TypeOutlives(TypeOutlives), } impl Copy for WhereClause where I::InternedSubstitution: Copy, I::InternedLifetime: Copy, I::InternedType: Copy, { } /// Checks whether a type or trait ref is well-formed. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub enum WellFormed { /// A predicate which is true when some trait ref is well-formed. /// For example, given the following trait definitions: /// /// ```notrust /// trait Clone { ... } /// trait Copy where Self: Clone { ... } /// ``` /// /// then we have the following rule: /// /// ```notrust /// WellFormed(?Self: Copy) :- ?Self: Copy, WellFormed(?Self: Clone) /// ``` Trait(TraitRef), /// A predicate which is true when some type is well-formed. /// For example, given the following type definition: /// /// ```notrust /// struct Set where K: Hash { /// ... /// } /// ``` /// /// then we have the following rule: `WellFormedTy(Set) :- Implemented(K: Hash)`. Ty(Ty), } impl Copy for WellFormed where I::InternedType: Copy, I::InternedSubstitution: Copy, { } /// Checks whether a type or trait ref can be derived from the contents of the environment. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub enum FromEnv { /// A predicate which enables deriving everything which should be true if we *know* that /// some trait ref is well-formed. For example given the above trait definitions, we can use /// `FromEnv(T: Copy)` to derive that `T: Clone`, like in: /// /// ```notrust /// forall { /// if (FromEnv(T: Copy)) { /// T: Clone /// } /// } /// ``` Trait(TraitRef), /// A predicate which enables deriving everything which should be true if we *know* that /// some type is well-formed. For example given the above type definition, we can use /// `FromEnv(Set)` to derive that `K: Hash`, like in: /// /// ```notrust /// forall { /// if (FromEnv(Set)) { /// K: Hash /// } /// } /// ``` Ty(Ty), } impl Copy for FromEnv where I::InternedType: Copy, I::InternedSubstitution: Copy, { } /// A "domain goal" is a goal that is directly about Rust, rather than a pure /// logical statement. As much as possible, the Chalk solver should avoid /// decomposing this enum, and instead treat its values opaquely. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeSuperVisitable, HasInterner, Zip)] pub enum DomainGoal { /// Simple goal that is true if the where clause is true. Holds(WhereClause), /// True if the type or trait ref is well-formed. WellFormed(WellFormed), /// True if the trait ref can be derived from in-scope where clauses. FromEnv(FromEnv), /// True if the alias type can be normalized to some other type Normalize(Normalize), /// True if a type is considered to have been "defined" by the current crate. This is true for /// a `struct Foo { }` but false for a `#[upstream] struct Foo { }`. However, for fundamental types /// like `Box`, it is true if `T` is local. IsLocal(Ty), /// True if a type is *not* considered to have been "defined" by the current crate. This is /// false for a `struct Foo { }` but true for a `#[upstream] struct Foo { }`. However, for /// fundamental types like `Box`, it is true if `T` is upstream. IsUpstream(Ty), /// True if a type and its input types are fully visible, known types. That is, there are no /// unknown type parameters anywhere in this type. /// /// More formally, for each struct S: /// forall { /// IsFullyVisible(S) :- /// IsFullyVisible(P0), /// ... /// IsFullyVisible(Pn) /// } /// /// Note that any of these types can have lifetimes in their parameters too, but we only /// consider type parameters. IsFullyVisible(Ty), /// Used to dictate when trait impls are allowed in the current (local) crate based on the /// orphan rules. /// /// `LocalImplAllowed(T: Trait)` is true if the type T is allowed to impl trait Trait in /// the current crate. Under the current rules, this is unconditionally true for all types if /// the Trait is considered to be "defined" in the current crate. If that is not the case, then /// `LocalImplAllowed(T: Trait)` can still be true if `IsLocal(T)` is true. LocalImplAllowed(TraitRef), /// Used to activate the "compatible modality" rules. Rules that introduce predicates that have /// to do with "all compatible universes" should depend on this clause so that they only apply /// if this is present. Compatible, /// Used to indicate that a given type is in a downstream crate. Downstream crates contain the /// current crate at some level of their dependencies. /// /// Since chalk does not actually see downstream types, this is usually introduced with /// implication on a fresh, universally quantified type. /// /// forall { if (DownstreamType(T)) { /* ... */ } } /// /// This makes a new type `T` available and makes `DownstreamType(T)` provable for that type. DownstreamType(Ty), /// Used to activate the "reveal mode", in which opaque (`impl Trait`) types can be equated /// to their actual type. Reveal, /// Used to indicate that a trait is object safe. ObjectSafe(TraitId), } impl Copy for DomainGoal where I::InternedSubstitution: Copy, I::InternedLifetime: Copy, I::InternedType: Copy, { } /// A where clause that can contain `forall<>` or `exists<>` quantifiers. pub type QuantifiedWhereClause = Binders>; impl WhereClause { /// Turn a where clause into the WF version of it i.e.: /// * `Implemented(T: Trait)` maps to `WellFormed(T: Trait)` /// * `ProjectionEq(::Item = Foo)` maps to `WellFormed(::Item = Foo)` /// * any other clause maps to itself pub fn into_well_formed_goal(self, interner: I) -> DomainGoal { match self { WhereClause::Implemented(trait_ref) => WellFormed::Trait(trait_ref).cast(interner), wc => wc.cast(interner), } } /// Same as `into_well_formed_goal` but with the `FromEnv` predicate instead of `WellFormed`. pub fn into_from_env_goal(self, interner: I) -> DomainGoal { match self { WhereClause::Implemented(trait_ref) => FromEnv::Trait(trait_ref).cast(interner), wc => wc.cast(interner), } } /// If where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { match self { WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id), WhereClause::AliasEq(_) => None, WhereClause::LifetimeOutlives(_) => None, WhereClause::TypeOutlives(_) => None, } } } impl QuantifiedWhereClause { /// As with `WhereClause::into_well_formed_goal`, but for a /// quantified where clause. For example, `forall { /// Implemented(T: Trait)}` would map to `forall { /// WellFormed(T: Trait) }`. pub fn into_well_formed_goal(self, interner: I) -> Binders> { self.map(|wc| wc.into_well_formed_goal(interner)) } /// As with `WhereClause::into_from_env_goal`, but mapped over any /// binders. For example, `forall { /// Implemented(T: Trait)}` would map to `forall { /// FromEnv(T: Trait) }`. pub fn into_from_env_goal(self, interner: I) -> Binders> { self.map(|wc| wc.into_from_env_goal(interner)) } /// If the underlying where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { self.skip_binders().trait_id() } } impl DomainGoal { /// Convert `Implemented(...)` into `FromEnv(...)`, but leave other /// goals unchanged. pub fn into_from_env_goal(self, interner: I) -> DomainGoal { match self { DomainGoal::Holds(wc) => wc.into_from_env_goal(interner), goal => goal, } } /// Lists generic arguments that are inputs to this domain goal. pub fn inputs(&self, interner: I) -> Vec> { match self { DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => { vec![GenericArgData::Ty(alias_eq.alias.clone().intern(interner)).intern(interner)] } _ => Vec::new(), } } } /// Equality goal: tries to prove that two values are equal. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)] #[allow(missing_docs)] pub struct EqGoal { pub a: GenericArg, pub b: GenericArg, } impl Copy for EqGoal where I::InternedGenericArg: Copy {} /// Subtype goal: tries to prove that `a` is a subtype of `b` #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)] #[allow(missing_docs)] pub struct SubtypeGoal { pub a: Ty, pub b: Ty, } impl Copy for SubtypeGoal where I::InternedType: Copy {} /// Proves that the given type alias **normalizes** to the given /// type. A projection `T::Foo` normalizes to the type `U` if we can /// **match it to an impl** and that impl has a `type Foo = V` where /// `U = V`. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)] #[allow(missing_docs)] pub struct Normalize { pub alias: AliasTy, pub ty: Ty, } impl Copy for Normalize where I::InternedSubstitution: Copy, I::InternedType: Copy, { } /// Proves **equality** between an alias and a type. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)] #[allow(missing_docs)] pub struct AliasEq { pub alias: AliasTy, pub ty: Ty, } impl Copy for AliasEq where I::InternedSubstitution: Copy, I::InternedType: Copy, { } impl HasInterner for AliasEq { type Interner = I; } /// Indicates that the `value` is universally quantified over `N` /// parameters of the given kinds, where `N == self.binders.len()`. A /// variable with depth `i < N` refers to the value at /// `self.binders[i]`. Variables with depth `>= N` are free. /// /// (IOW, we use deBruijn indices, where binders are introduced in reverse order /// of `self.binders`.) #[derive(Clone, PartialEq, Eq, Hash)] pub struct Binders { /// The binders that quantify over the value. pub binders: VariableKinds, /// The value being quantified over. value: T, } impl Copy for Binders where ::InternedVariableKinds: Copy { } impl HasInterner for Binders { type Interner = T::Interner; } impl Binders<&T> { /// Converts a `Binders<&T>` to a `Binders` by cloning `T`. pub fn cloned(self) -> Binders { self.map(Clone::clone) } } impl Binders { /// Create new binders. pub fn new(binders: VariableKinds, value: T) -> Self { Self { binders, value } } /// Wraps the given value in a binder without variables, i.e. `for<> /// (value)`. Since our deBruijn indices count binders, not variables, this /// is sometimes useful. pub fn empty(interner: T::Interner, value: T) -> Self { let binders = VariableKinds::empty(interner); Self { binders, value } } /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about /// De Bruijn indices and the like. `skip_binder` is only valid /// when you are either extracting data that has nothing to /// do with bound vars, or you are being very careful about /// your depth accounting. /// /// Some examples where `skip_binder` is reasonable: /// /// - extracting the `TraitId` from a TraitRef; /// - checking if there are any fields in a StructDatum pub fn skip_binders(&self) -> &T { &self.value } /// Skips the binder and returns the "bound" value as well as the skipped free variables. This /// is just as risky as [`skip_binders`][Self::skip_binders]. pub fn into_value_and_skipped_binders(self) -> (T, VariableKinds) { (self.value, self.binders) } /// Converts `&Binders` to `Binders<&T>`. Produces new `Binders` /// with cloned quantifiers containing a reference to the original /// value, leaving the original in place. pub fn as_ref(&self) -> Binders<&T> { Binders { binders: self.binders.clone(), value: &self.value, } } /// Maps the binders by applying a function. pub fn map(self, op: OP) -> Binders where OP: FnOnce(T) -> U, U: HasInterner, { let value = op(self.value); Binders { binders: self.binders, value, } } /// Transforms the inner value according to the given function; returns /// `None` if the function returns `None`. pub fn filter_map(self, op: OP) -> Option> where OP: FnOnce(T) -> Option, U: HasInterner, { let value = op(self.value)?; Some(Binders { binders: self.binders, value, }) } /// Maps a function taking `Binders<&T>` over `&Binders`. pub fn map_ref<'a, U, OP>(&'a self, op: OP) -> Binders where OP: FnOnce(&'a T) -> U, U: HasInterner, { self.as_ref().map(op) } /// Creates a `Substitution` containing bound vars such that applying this /// substitution will not change the value, i.e. `^0.0, ^0.1, ^0.2` and so /// on. pub fn identity_substitution(&self, interner: T::Interner) -> Substitution { Substitution::from_iter( interner, self.binders .iter(interner) .enumerate() .map(|p| p.to_generic_arg(interner)), ) } /// Creates a fresh binders that contains a single type /// variable. The result of the closure will be embedded in this /// binder. Note that you should be careful with what you return /// from the closure to account for the binder that will be added. /// /// XXX FIXME -- this is potentially a pretty footgun-y function. pub fn with_fresh_type_var( interner: T::Interner, op: impl FnOnce(Ty) -> T, ) -> Binders { // The new variable is at the front and everything afterwards is shifted up by 1 let new_var = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(interner); let value = op(new_var); let binders = VariableKinds::from1(interner, VariableKind::Ty(TyVariableKind::General)); Binders { binders, value } } /// Returns the number of binders. pub fn len(&self, interner: T::Interner) -> usize { self.binders.len(interner) } } impl Binders> where T: TypeFoldable + HasInterner, I: Interner, { /// This turns two levels of binders (`for for`) into one level (`for`). pub fn fuse_binders(self, interner: T::Interner) -> Binders { let num_binders = self.len(interner); // generate a substitution to shift the indexes of the inner binder: let subst = Substitution::from_iter( interner, self.value .binders .iter(interner) .enumerate() .map(|(i, pk)| (i + num_binders, pk).to_generic_arg(interner)), ); let binders = VariableKinds::from_iter( interner, self.binders .iter(interner) .chain(self.value.binders.iter(interner)) .cloned(), ); let value = self.value.substitute(interner, &subst); Binders { binders, value } } } impl From> for (VariableKinds, T) { fn from(binders: Binders) -> Self { (binders.binders, binders.value) } } impl Binders where T: TypeFoldable + HasInterner, I: Interner, { /// Substitute `parameters` for the variables introduced by these /// binders. So if the binders represent (e.g.) ` { T }` and /// parameters is the slice `[A, B]`, then returns `[X => A, Y => /// B] T`. pub fn substitute(self, interner: I, parameters: &(impl AsParameters + ?Sized)) -> T { let parameters = parameters.as_parameters(interner); assert_eq!(self.binders.len(interner), parameters.len()); Subst::apply(interner, parameters, self.value) } } /// Allows iterating over a Binders>, for instance. /// Each element will include the same set of parameter bounds. impl IntoIterator for Binders where V: HasInterner + IntoIterator, U: HasInterner, { type Item = Binders; type IntoIter = BindersIntoIterator; fn into_iter(self) -> Self::IntoIter { BindersIntoIterator { iter: self.value.into_iter(), binders: self.binders, } } } /// `IntoIterator` for binders. pub struct BindersIntoIterator { iter: ::IntoIter, binders: VariableKinds, } impl Iterator for BindersIntoIterator where V: HasInterner + IntoIterator, ::Item: HasInterner, { type Item = Binders<::Item>; fn next(&mut self) -> Option { self.iter .next() .map(|v| Binders::new(self.binders.clone(), v)) } } /// Represents one clause of the form `consequence :- conditions` where /// `conditions = cond_1 && cond_2 && ...` is the conjunction of the individual /// conditions. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub struct ProgramClauseImplication { /// The consequence of the clause, which holds if the conditions holds. pub consequence: DomainGoal, /// The condition goals that should hold. pub conditions: Goals, /// The lifetime constraints that should be proven. pub constraints: Constraints, /// The relative priority of the implication. pub priority: ClausePriority, } /// Specifies how important an implication is. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum ClausePriority { /// High priority, the solver should prioritize this. High, /// Low priority, this implication has lower chance to be relevant to the goal. Low, } impl std::ops::BitAnd for ClausePriority { type Output = ClausePriority; fn bitand(self, rhs: ClausePriority) -> Self::Output { match (self, rhs) { (ClausePriority::High, ClausePriority::High) => ClausePriority::High, _ => ClausePriority::Low, } } } /// Contains the data for a program clause. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, HasInterner, Zip)] pub struct ProgramClauseData(pub Binders>); impl ProgramClauseImplication { /// Change the implication into an application holding a `FromEnv` goal. pub fn into_from_env_clause(self, interner: I) -> ProgramClauseImplication { if self.conditions.is_empty(interner) { ProgramClauseImplication { consequence: self.consequence.into_from_env_goal(interner), conditions: self.conditions.clone(), constraints: self.constraints.clone(), priority: self.priority, } } else { self } } } impl ProgramClauseData { /// Change the program clause data into a `FromEnv` program clause. pub fn into_from_env_clause(self, interner: I) -> ProgramClauseData { ProgramClauseData(self.0.map(|i| i.into_from_env_clause(interner))) } /// Intern the program clause data. pub fn intern(self, interner: I) -> ProgramClause { ProgramClause { interned: interner.intern_program_clause(self), } } } /// A program clause is a logic expression used to describe a part of the program. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ProgramClause { interned: I::InternedProgramClause, } impl ProgramClause { /// Create a new program clause using `ProgramClauseData`. pub fn new(interner: I, clause: ProgramClauseData) -> Self { let interned = interner.intern_program_clause(clause); Self { interned } } /// Change the clause into a `FromEnv` clause. pub fn into_from_env_clause(self, interner: I) -> ProgramClause { let program_clause_data = self.data(interner); let new_clause = program_clause_data.clone().into_from_env_clause(interner); Self::new(interner, new_clause) } /// Get the interned program clause. pub fn interned(&self) -> &I::InternedProgramClause { &self.interned } /// Get the program clause data. pub fn data(&self, interner: I) -> &ProgramClauseData { interner.program_clause_data(&self.interned) } } /// Wraps a "canonicalized item". Items are canonicalized as follows: /// /// All unresolved existential variables are "renumbered" according to their /// first appearance; the kind/universe of the variable is recorded in the /// `binders` field. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Canonical { /// The item that is canonicalized. pub value: T, /// The kind/universe of the variable. pub binders: CanonicalVarKinds, } impl HasInterner for Canonical { type Interner = T::Interner; } /// A "universe canonical" value. This is a wrapper around a /// `Canonical`, indicating that the universes within have been /// "renumbered" to start from 0 and collapse unimportant /// distinctions. /// /// To produce one of these values, use the `u_canonicalize` method. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct UCanonical { /// The wrapped `Canonical`. pub canonical: Canonical, /// The number of universes that have been collapsed. pub universes: usize, } impl UCanonical { /// Checks whether the universe canonical value is a trivial /// substitution (e.g. an identity substitution). pub fn is_trivial_substitution( &self, interner: T::Interner, canonical_subst: &Canonical>, ) -> bool { let subst = &canonical_subst.value.subst; assert_eq!( self.canonical.binders.len(interner), subst.as_slice(interner).len() ); subst.is_identity_subst(interner) } /// Creates an identity substitution. pub fn trivial_substitution(&self, interner: T::Interner) -> Substitution { let binders = &self.canonical.binders; Substitution::from_iter( interner, binders .iter(interner) .enumerate() .map(|(index, pk)| { let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, index); match &pk.kind { VariableKind::Ty(_) => { GenericArgData::Ty(TyKind::BoundVar(bound_var).intern(interner)) .intern(interner) } VariableKind::Lifetime => GenericArgData::Lifetime( LifetimeData::BoundVar(bound_var).intern(interner), ) .intern(interner), VariableKind::Const(ty) => GenericArgData::Const( ConstData { ty: ty.clone(), value: ConstValue::BoundVar(bound_var), } .intern(interner), ) .intern(interner), } }) .collect::>(), ) } } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] /// A general goal; this is the full range of questions you can pose to Chalk. pub struct Goal { interned: I::InternedGoal, } impl Goal { /// Create a new goal using `GoalData`. pub fn new(interner: I, interned: GoalData) -> Self { let interned = I::intern_goal(interner, interned); Self { interned } } /// Gets the interned goal. pub fn interned(&self) -> &I::InternedGoal { &self.interned } /// Gets the interned goal data. pub fn data(&self, interner: I) -> &GoalData { interner.goal_data(&self.interned) } /// Create a goal using a `forall` or `exists` quantifier. pub fn quantify(self, interner: I, kind: QuantifierKind, binders: VariableKinds) -> Goal { GoalData::Quantified(kind, Binders::new(binders, self)).intern(interner) } /// Takes a goal `G` and turns it into `not { G }`. pub fn negate(self, interner: I) -> Self { GoalData::Not(self).intern(interner) } /// Takes a goal `G` and turns it into `compatible { G }`. pub fn compatible(self, interner: I) -> Self { // compatible { G } desugars into: forall { if (Compatible, DownstreamType(T)) { G } } // This activates the compatible modality rules and introduces an anonymous downstream type GoalData::Quantified( QuantifierKind::ForAll, Binders::with_fresh_type_var(interner, |ty| { GoalData::Implies( ProgramClauses::from_iter( interner, vec![DomainGoal::Compatible, DomainGoal::DownstreamType(ty)], ), self.shifted_in(interner), ) .intern(interner) }), ) .intern(interner) } /// Create an implication goal that holds if the predicates are true. pub fn implied_by(self, interner: I, predicates: ProgramClauses) -> Goal { GoalData::Implies(predicates, self).intern(interner) } /// True if this goal is "trivially true" -- i.e., no work is /// required to prove it. pub fn is_trivially_true(&self, interner: I) -> bool { match self.data(interner) { GoalData::All(goals) => goals.is_empty(interner), _ => false, } } } impl Goal where I: Interner, { /// Creates a single goal that only holds if a list of goals holds. pub fn all(interner: I, iter: II) -> Self where II: IntoIterator>, { let mut iter = iter.into_iter(); if let Some(goal0) = iter.next() { if let Some(goal1) = iter.next() { // More than one goal to prove let goals = Goals::from_iter( interner, Some(goal0).into_iter().chain(Some(goal1)).chain(iter), ); GoalData::All(goals).intern(interner) } else { // One goal to prove goal0 } } else { // No goals to prove, always true GoalData::All(Goals::empty(interner)).intern(interner) } } } #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] /// A general goal; this is the full range of questions you can pose to Chalk. pub enum GoalData { /// Introduces a binding at depth 0, shifting other bindings up /// (deBruijn index). Quantified(QuantifierKind, Binders>), /// A goal that holds given some clauses (like an if-statement). Implies(ProgramClauses, Goal), /// List of goals that all should hold. All(Goals), /// Negation: the inner goal should not hold. Not(Goal), /// Make two things equal; the rules for doing so are well known to the logic EqGoal(EqGoal), /// Make one thing a subtype of another; the rules for doing so are well known to the logic SubtypeGoal(SubtypeGoal), /// A "domain goal" indicates some base sort of goal that can be /// proven via program clauses DomainGoal(DomainGoal), /// Indicates something that cannot be proven to be true or false /// definitively. This can occur with overflow but also with /// unifications of skolemized variables like `forall { X = Y /// }`. Of course, that statement is false, as there exist types /// X, Y where `X = Y` is not true. But we treat it as "cannot /// prove" so that `forall { not { X = Y } }` also winds up /// as cannot prove. CannotProve, } impl Copy for GoalData where I::InternedType: Copy, I::InternedLifetime: Copy, I::InternedGenericArg: Copy, I::InternedSubstitution: Copy, I::InternedGoal: Copy, I::InternedGoals: Copy, I::InternedProgramClauses: Copy, I::InternedVariableKinds: Copy, { } impl GoalData { /// Create an interned goal. pub fn intern(self, interner: I) -> Goal { Goal::new(interner, self) } } /// Kinds of quantifiers in the logic, such as `forall` and `exists`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum QuantifierKind { /// Universal quantifier `ForAll`. /// /// A formula with the universal quantifier `forall(x). P(x)` is satisfiable /// if and only if the subformula `P(x)` is true for all possible values for x. ForAll, /// Existential quantifier `Exists`. /// /// A formula with the existential quantifier `exists(x). P(x)` is satisfiable /// if and only if there exists at least one value for all possible values of x /// which satisfies the subformula `P(x)`. /// In the context of chalk, the existential quantifier usually demands the /// existence of exactly one instance (i.e. type) that satisfies the formula /// (i.e. type constraints). More than one instance means that the result is ambiguous. Exists, } /// A constraint on lifetimes. /// /// When we search for solutions within the trait system, we essentially ignore /// lifetime constraints, instead gathering them up to return with our solution /// for later checking. This allows for decoupling between type and region /// checking in the compiler. #[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)] pub enum Constraint { /// Outlives constraint `'a: 'b`, indicating that the value of `'a` must be /// a superset of the value of `'b`. LifetimeOutlives(Lifetime, Lifetime), /// Type outlives constraint `T: 'a`, indicating that the type `T` must live /// at least as long as the value of `'a`. TypeOutlives(Ty, Lifetime), } impl Copy for Constraint where I::InternedLifetime: Copy, I::InternedType: Copy, { } impl Substitution { /// A substitution is an **identity substitution** if it looks /// like this /// /// ```text /// ?0 := ?0 /// ?1 := ?1 /// ?2 := ?2 /// ... /// ``` /// /// Basically, each value is mapped to a type or lifetime with its /// same index. pub fn is_identity_subst(&self, interner: I) -> bool { self.iter(interner).zip(0..).all(|(generic_arg, index)| { let index_db = BoundVar::new(DebruijnIndex::INNERMOST, index); match generic_arg.data(interner) { GenericArgData::Ty(ty) => match ty.kind(interner) { TyKind::BoundVar(depth) => index_db == *depth, _ => false, }, GenericArgData::Lifetime(lifetime) => match lifetime.data(interner) { LifetimeData::BoundVar(depth) => index_db == *depth, _ => false, }, GenericArgData::Const(constant) => match &constant.data(interner).value { ConstValue::BoundVar(depth) => index_db == *depth, _ => false, }, } }) } /// Apply the substitution to a value. pub fn apply(&self, value: T, interner: I) -> T where T: TypeFoldable, { Substitute::apply(self, value, interner) } /// Gets an iterator of all type parameters. pub fn type_parameters(&self, interner: I) -> impl Iterator> + '_ { self.iter(interner) .filter_map(move |p| p.ty(interner)) .cloned() } /// Compute type flags for Substitution fn compute_flags(&self, interner: I) -> TypeFlags { let mut flags = TypeFlags::empty(); for generic_arg in self.iter(interner) { flags |= generic_arg.compute_flags(interner); } flags } } #[derive(FallibleTypeFolder)] struct SubstFolder<'i, I: Interner, A: AsParameters> { interner: I, subst: &'i A, } impl> SubstFolder<'_, I, A> { /// Index into the list of parameters. pub fn at(&self, index: usize) -> &GenericArg { let interner = self.interner; &self.subst.as_parameters(interner)[index] } } /// Convert a value to a list of parameters. pub trait AsParameters { /// Convert the current value to parameters. fn as_parameters(&self, interner: I) -> &[GenericArg]; } impl AsParameters for Substitution { #[allow(unreachable_code, unused_variables)] fn as_parameters(&self, interner: I) -> &[GenericArg] { self.as_slice(interner) } } impl AsParameters for [GenericArg] { fn as_parameters(&self, _interner: I) -> &[GenericArg] { self } } impl AsParameters for [GenericArg; 1] { fn as_parameters(&self, _interner: I) -> &[GenericArg] { self } } impl AsParameters for Vec> { fn as_parameters(&self, _interner: I) -> &[GenericArg] { self } } impl AsParameters for &T where T: ?Sized + AsParameters, { fn as_parameters(&self, interner: I) -> &[GenericArg] { T::as_parameters(self, interner) } } /// An extension trait to anything that can be represented as list of `GenericArg`s that signifies /// that it can applied as a substituion to a value pub trait Substitute: AsParameters { /// Apply the substitution to a value. fn apply>(&self, value: T, interner: I) -> T; } impl> Substitute for A { fn apply(&self, value: T, interner: I) -> T where T: TypeFoldable, { value .try_fold_with( &mut SubstFolder { interner, subst: self, }, DebruijnIndex::INNERMOST, ) .unwrap() } } /// Utility for converting a list of all the binders into scope /// into references to those binders. Simply pair the binders with /// the indices, and invoke `to_generic_arg()` on the `(binder, /// index)` pair. The result will be a reference to a bound /// variable of appropriate kind at the corresponding index. pub trait ToGenericArg { /// Converts the binders in scope to references to those binders. fn to_generic_arg(&self, interner: I) -> GenericArg { self.to_generic_arg_at_depth(interner, DebruijnIndex::INNERMOST) } /// Converts the binders at the specified depth to references to those binders. fn to_generic_arg_at_depth(&self, interner: I, debruijn: DebruijnIndex) -> GenericArg; } impl<'a, I: Interner> ToGenericArg for (usize, &'a VariableKind) { fn to_generic_arg_at_depth(&self, interner: I, debruijn: DebruijnIndex) -> GenericArg { let &(index, binder) = self; let bound_var = BoundVar::new(debruijn, index); binder.to_bound_variable(interner, bound_var) } } impl<'i, I: Interner, A: AsParameters> TypeFolder for SubstFolder<'i, I, A> { fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let ty = self.at(bound_var.index); let ty = ty.assert_ty_ref(TypeFolder::interner(self)); ty.clone() .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Lifetime { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let l = self.at(bound_var.index); let l = l.assert_lifetime_ref(TypeFolder::interner(self)); l.clone() .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn fold_free_var_const( &mut self, _ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Const { assert_eq!(bound_var.debruijn, DebruijnIndex::INNERMOST); let c = self.at(bound_var.index); let c = c.assert_const_ref(TypeFolder::interner(self)); c.clone() .shifted_in_from(TypeFolder::interner(self), outer_binder) } fn interner(&self) -> I { self.interner } } macro_rules! interned_slice_common { ($seq:ident, $data:ident => $elem:ty, $intern:ident => $interned:ident) => { /// List of interned elements. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct $seq { interned: I::$interned, } impl $seq { /// Get the interned elements. pub fn interned(&self) -> &I::$interned { &self.interned } /// Returns a slice containing the elements. pub fn as_slice(&self, interner: I) -> &[$elem] { Interner::$data(interner, &self.interned) } /// Index into the sequence. pub fn at(&self, interner: I, index: usize) -> &$elem { &self.as_slice(interner)[index] } /// Create an empty sequence. pub fn empty(interner: I) -> Self { Self::from_iter(interner, None::<$elem>) } /// Check whether this is an empty sequence. pub fn is_empty(&self, interner: I) -> bool { self.as_slice(interner).is_empty() } /// Get an iterator over the elements of the sequence. pub fn iter(&self, interner: I) -> std::slice::Iter<'_, $elem> { self.as_slice(interner).iter() } /// Get the length of the sequence. pub fn len(&self, interner: I) -> usize { self.as_slice(interner).len() } } }; } macro_rules! interned_slice { ($seq:ident, $data:ident => $elem:ty, $intern:ident => $interned:ident) => { interned_slice_common!($seq, $data => $elem, $intern => $interned); impl $seq { /// Tries to create a sequence using an iterator of element-like things. pub fn from_fallible( interner: I, elements: impl IntoIterator, E>>, ) -> Result { Ok(Self { interned: I::$intern(interner, elements.into_iter().casted(interner))?, }) } /// Create a sequence from elements pub fn from_iter( interner: I, elements: impl IntoIterator>, ) -> Self { Self::from_fallible( interner, elements .into_iter() .map(|el| -> Result<$elem, ()> { Ok(el.cast(interner)) }), ) .unwrap() } /// Create a sequence from a single element. pub fn from1(interner: I, element: impl CastTo<$elem>) -> Self { Self::from_iter(interner, Some(element)) } } }; } interned_slice!( QuantifiedWhereClauses, quantified_where_clauses_data => QuantifiedWhereClause, intern_quantified_where_clauses => InternedQuantifiedWhereClauses ); interned_slice!( ProgramClauses, program_clauses_data => ProgramClause, intern_program_clauses => InternedProgramClauses ); interned_slice!( VariableKinds, variable_kinds_data => VariableKind, intern_generic_arg_kinds => InternedVariableKinds ); interned_slice!( CanonicalVarKinds, canonical_var_kinds_data => CanonicalVarKind, intern_canonical_var_kinds => InternedCanonicalVarKinds ); interned_slice!(Goals, goals_data => Goal, intern_goals => InternedGoals); interned_slice!( Constraints, constraints_data => InEnvironment>, intern_constraints => InternedConstraints ); interned_slice!( Substitution, substitution_data => GenericArg, intern_substitution => InternedSubstitution ); interned_slice_common!( Variances, variances_data => Variance, intern_variance => InternedVariances ); impl Variances { /// Tries to create a list of canonical variable kinds using an iterator. pub fn from_fallible( interner: I, variances: impl IntoIterator>, ) -> Result { Ok(Variances { interned: I::intern_variances(interner, variances.into_iter())?, }) } /// Creates a list of canonical variable kinds using an iterator. pub fn from_iter(interner: I, variances: impl IntoIterator) -> Self { Self::from_fallible( interner, variances .into_iter() .map(|p| -> Result { Ok(p) }), ) .unwrap() } /// Creates a list of canonical variable kinds from a single canonical variable kind. pub fn from1(interner: I, variance: Variance) -> Self { Self::from_iter(interner, Some(variance)) } } /// Combines a substitution (`subst`) with a set of region constraints /// (`constraints`). This represents the result of a query; the /// substitution stores the values for the query's unknown variables, /// and the constraints represents any region constraints that must /// additionally be solved. #[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct ConstrainedSubst { /// The substitution that is being constrained. /// /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. pub subst: Substitution, /// Region constraints that constrain the substitution. pub constraints: Constraints, } /// The resulting substitution after solving a goal. #[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)] pub struct AnswerSubst { /// The substitution result. /// /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. pub subst: Substitution, /// List of constraints that are part of the answer. pub constraints: Constraints, /// Delayed subgoals, used when the solver answered with an (incomplete) `Answer` (instead of a `CompleteAnswer`). pub delayed_subgoals: Vec>>, } /// Logic to decide the Variance for a given subst pub trait UnificationDatabase where Self: std::fmt::Debug, I: Interner, { /// Gets the variances for the substitution of a fn def fn fn_def_variance(&self, fn_def_id: FnDefId) -> Variances; /// Gets the variances for the substitution of a adt fn adt_variance(&self, adt_id: AdtId) -> Variances; }