From 4547b622d8d29df964fa2914213088b148c498fc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:32 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/chalk-ir/src/lib.rs | 3055 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3055 insertions(+) create mode 100644 vendor/chalk-ir/src/lib.rs (limited to 'vendor/chalk-ir/src/lib.rs') diff --git a/vendor/chalk-ir/src/lib.rs b/vendor/chalk-ir/src/lib.rs new file mode 100644 index 000000000..5cf44b0c3 --- /dev/null +++ b/vendor/chalk-ir/src/lib.rs @@ -0,0 +1,3055 @@ +//! 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; +} -- cgit v1.2.3