#![deny(rust_2018_idioms)]
#![warn(missing_docs)]
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;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Void {}
pub type Fallible<T> = Result<T, NoSolution>;
pub enum FallibleOrFloundered<T> {
Ok(T),
NoSolution,
Floundered,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NoSolution;
pub struct Floundered;
macro_rules! impl_debugs {
($($id:ident), *) => {
$(
impl<I: Interner> std::fmt::Debug for $id<I> {
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;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Variance {
Covariant,
Invariant,
Contravariant,
}
impl Variance {
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,
}
}
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)]
pub struct Environment<I: Interner> {
pub clauses: ProgramClauses<I>,
}
impl<I: Interner> Copy for Environment<I> where I::InternedProgramClauses: Copy {}
impl<I: Interner> Environment<I> {
pub fn new(interner: I) -> Self {
Environment {
clauses: ProgramClauses::empty(interner),
}
}
pub fn add_clauses<II>(&self, interner: I, clauses: II) -> Self
where
II: IntoIterator<Item = ProgramClause<I>>,
{
let mut env = self.clone();
env.clauses =
ProgramClauses::from_iter(interner, env.clauses.iter(interner).cloned().chain(clauses));
env
}
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 => {
assert!(implication.skip_binders().conditions.is_empty(interner));
assert!(implication.skip_binders().constraints.is_empty(interner));
true
}
_ => false,
}
})
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
#[allow(missing_docs)]
pub struct InEnvironment<G: HasInterner> {
pub environment: Environment<G::Interner>,
pub goal: G,
}
impl<G: HasInterner<Interner = I> + Copy, I: Interner> Copy for InEnvironment<G> where
I::InternedProgramClauses: Copy
{
}
impl<G: HasInterner> InEnvironment<G> {
pub fn new(environment: &Environment<G::Interner>, goal: G) -> Self {
InEnvironment {
environment: environment.clone(),
goal,
}
}
pub fn map<OP, H>(self, op: OP) -> InEnvironment<H>
where
OP: FnOnce(G) -> H,
H: HasInterner<Interner = G::Interner>,
{
InEnvironment {
environment: self.environment,
goal: op(self.goal),
}
}
}
impl<G: HasInterner> HasInterner for InEnvironment<G> {
type Interner = G::Interner;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub enum IntTy {
Isize,
I8,
I16,
I32,
I64,
I128,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub enum UintTy {
Usize,
U8,
U16,
U32,
U64,
U128,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub enum FloatTy {
F32,
F64,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub enum Scalar {
Bool,
Char,
Int(IntTy),
Uint(UintTy),
Float(FloatTy),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Safety {
Safe,
Unsafe,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Mutability {
Mut,
Not,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UniverseIndex {
pub counter: usize,
}
impl UniverseIndex {
pub const ROOT: UniverseIndex = UniverseIndex { counter: 0 };
pub fn root() -> UniverseIndex {
Self::ROOT
}
pub fn can_see(self, ui: UniverseIndex) -> bool {
self.counter >= ui.counter
}
pub fn next(self) -> UniverseIndex {
UniverseIndex {
counter: self.counter + 1,
}
}
}
#[derive(Clone, Debug)]
pub struct UniverseMap {
pub universes: Vec<UniverseIndex>,
}
impl UniverseMap {
pub fn new() -> Self {
UniverseMap {
universes: vec![UniverseIndex::root()],
}
}
pub fn num_canonical_universes(&self) -> usize {
self.universes.len()
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AdtId<I: Interner>(pub I::InternedAdtId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TraitId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ImplId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ClauseId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AssocTypeId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OpaqueTyId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FnDefId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ClosureId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GeneratorId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForeignDefId<I: Interner>(pub I::DefId);
impl_debugs!(ImplId, ClauseId);
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct Ty<I: Interner> {
interned: I::InternedType,
}
impl<I: Interner> Ty<I> {
pub fn new(interner: I, data: impl CastTo<TyKind<I>>) -> Self {
let ty_kind = data.cast(interner);
Ty {
interned: I::intern_ty(interner, ty_kind),
}
}
pub fn interned(&self) -> &I::InternedType {
&self.interned
}
pub fn data(&self, interner: I) -> &TyData<I> {
I::ty_data(interner, &self.interned)
}
pub fn kind(&self, interner: I) -> &TyKind<I> {
&I::ty_data(interner, &self.interned).kind
}
pub fn from_env(&self) -> FromEnv<I> {
FromEnv::Ty(self.clone())
}
pub fn well_formed(&self) -> WellFormed<I> {
WellFormed::Ty(self.clone())
}
pub fn into_from_env_goal(self, interner: I) -> DomainGoal<I> {
self.from_env().cast(interner)
}
pub fn bound_var(&self, interner: I) -> Option<BoundVar> {
if let TyKind::BoundVar(bv) = self.kind(interner) {
Some(*bv)
} else {
None
}
}
pub fn inference_var(&self, interner: I) -> Option<InferenceVar> {
if let TyKind::InferenceVar(depth, _) = self.kind(interner) {
Some(*depth)
} else {
None
}
}
pub fn is_general_var(&self, interner: I, binders: &CanonicalVarKinds<I>) -> 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,
}
}
pub fn is_alias(&self, interner: I) -> bool {
matches!(self.kind(interner), TyKind::Alias(..))
}
pub fn is_integer(&self, interner: I) -> bool {
matches!(
self.kind(interner),
TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_))
)
}
pub fn is_float(&self, interner: I) -> bool {
matches!(self.kind(interner), TyKind::Scalar(Scalar::Float(_)))
}
pub fn adt_id(&self, interner: I) -> Option<AdtId<I>> {
match self.kind(interner) {
TyKind::Adt(adt_id, _) => Some(*adt_id),
_ => None,
}
}
pub fn needs_shift(&self, interner: I) -> bool {
self.has_free_vars(interner)
}
}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
pub struct TyData<I: Interner> {
pub kind: TyKind<I>,
pub flags: TypeFlags,
}
bitflags! {
pub struct TypeFlags : u16 {
const HAS_TY_INFER = 1;
const HAS_RE_INFER = 1 << 1;
const HAS_CT_INFER = 1 << 2;
const HAS_TY_PLACEHOLDER = 1 << 3;
const HAS_RE_PLACEHOLDER = 1 << 4;
const HAS_CT_PLACEHOLDER = 1 << 5;
const HAS_FREE_LOCAL_REGIONS = 1 << 6;
const HAS_TY_PROJECTION = 1 << 7;
const HAS_TY_OPAQUE = 1 << 8;
const HAS_CT_PROJECTION = 1 << 9;
const HAS_ERROR = 1 << 10;
const HAS_FREE_REGIONS = 1 << 11;
const HAS_RE_LATE_BOUND = 1 << 12;
const HAS_RE_ERASED = 1 << 13;
const STILL_FURTHER_SPECIALIZABLE = 1 << 14;
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;
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
| TypeFlags::HAS_TY_OPAQUE.bits
| TypeFlags::HAS_CT_PROJECTION.bits;
}
}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
pub enum TyKind<I: Interner> {
Adt(AdtId<I>, Substitution<I>),
AssociatedType(AssocTypeId<I>, Substitution<I>),
Scalar(Scalar),
Tuple(usize, Substitution<I>),
Array(Ty<I>, Const<I>),
Slice(Ty<I>),
Raw(Mutability, Ty<I>),
Ref(Mutability, Lifetime<I>, Ty<I>),
OpaqueType(OpaqueTyId<I>, Substitution<I>),
FnDef(FnDefId<I>, Substitution<I>),
Str,
Never,
Closure(ClosureId<I>, Substitution<I>),
Generator(GeneratorId<I>, Substitution<I>),
GeneratorWitness(GeneratorId<I>, Substitution<I>),
Foreign(ForeignDefId<I>),
Error,
Placeholder(PlaceholderIndex),
Dyn(DynTy<I>),
Alias(AliasTy<I>),
Function(FnPointer<I>),
BoundVar(BoundVar),
InferenceVar(InferenceVar, TyVariableKind),
}
impl<I: Interner> Copy for TyKind<I>
where
I::InternedLifetime: Copy,
I::InternedSubstitution: Copy,
I::InternedVariableKinds: Copy,
I::InternedQuantifiedWhereClauses: Copy,
I::InternedType: Copy,
I::InternedConst: Copy,
{
}
impl<I: Interner> TyKind<I> {
pub fn intern(self, interner: I) -> Ty<I> {
Ty::new(interner, self)
}
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),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct BoundVar {
pub debruijn: DebruijnIndex,
pub index: usize,
}
impl BoundVar {
pub fn new(debruijn: DebruijnIndex, index: usize) -> Self {
Self { debruijn, index }
}
pub fn to_ty<I: Interner>(self, interner: I) -> Ty<I> {
TyKind::<I>::BoundVar(self).intern(interner)
}
pub fn to_lifetime<I: Interner>(self, interner: I) -> Lifetime<I> {
LifetimeData::<I>::BoundVar(self).intern(interner)
}
pub fn to_const<I: Interner>(self, interner: I, ty: Ty<I>) -> Const<I> {
ConstData {
ty,
value: ConstValue::<I>::BoundVar(self),
}
.intern(interner)
}
pub fn bound_within(self, outer_binder: DebruijnIndex) -> bool {
self.debruijn.within(outer_binder)
}
#[must_use]
pub fn shifted_in(self) -> Self {
BoundVar::new(self.debruijn.shifted_in(), self.index)
}
#[must_use]
pub fn shifted_in_from(self, outer_binder: DebruijnIndex) -> Self {
BoundVar::new(self.debruijn.shifted_in_from(outer_binder), self.index)
}
#[must_use]
pub fn shifted_out(self) -> Option<Self> {
self.debruijn
.shifted_out()
.map(|db| BoundVar::new(db, self.index))
}
#[must_use]
pub fn shifted_out_to(self, outer_binder: DebruijnIndex) -> Option<Self> {
self.debruijn
.shifted_out_to(outer_binder)
.map(|db| BoundVar::new(db, self.index))
}
pub fn index_if_innermost(self) -> Option<usize> {
self.index_if_bound_at(DebruijnIndex::INNERMOST)
}
pub fn index_if_bound_at(self, debruijn: DebruijnIndex) -> Option<usize> {
if self.debruijn == debruijn {
Some(self.index)
} else {
None
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DebruijnIndex {
depth: u32,
}
impl DebruijnIndex {
pub const INNERMOST: DebruijnIndex = DebruijnIndex { depth: 0 };
pub const ONE: DebruijnIndex = DebruijnIndex { depth: 1 };
pub fn new(depth: u32) -> Self {
DebruijnIndex { depth }
}
pub fn depth(self) -> u32 {
self.depth
}
pub fn within(self, outer_binder: DebruijnIndex) -> bool {
self < outer_binder
}
#[must_use]
pub fn shifted_in(self) -> DebruijnIndex {
self.shifted_in_from(DebruijnIndex::ONE)
}
pub fn shift_in(&mut self) {
*self = self.shifted_in();
}
#[must_use]
pub fn shifted_in_from(self, outer_binder: DebruijnIndex) -> DebruijnIndex {
DebruijnIndex::new(self.depth() + outer_binder.depth())
}
#[must_use]
pub fn shifted_out(self) -> Option<DebruijnIndex> {
self.shifted_out_to(DebruijnIndex::ONE)
}
pub fn shift_out(&mut self) {
*self = self.shifted_out().unwrap();
}
pub fn shifted_out_to(self, outer_binder: DebruijnIndex) -> Option<DebruijnIndex> {
if self.within(outer_binder) {
None
} else {
Some(DebruijnIndex::new(self.depth() - outer_binder.depth()))
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct DynTy<I: Interner> {
pub bounds: Binders<QuantifiedWhereClauses<I>>,
pub lifetime: Lifetime<I>,
}
impl<I: Interner> Copy for DynTy<I>
where
I::InternedLifetime: Copy,
I::InternedQuantifiedWhereClauses: Copy,
I::InternedVariableKinds: Copy,
{
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct InferenceVar {
index: u32,
}
impl From<u32> for InferenceVar {
fn from(index: u32) -> InferenceVar {
InferenceVar { index }
}
}
impl InferenceVar {
pub fn index(self) -> u32 {
self.index
}
pub fn to_ty<I: Interner>(self, interner: I, kind: TyVariableKind) -> Ty<I> {
TyKind::<I>::InferenceVar(self, kind).intern(interner)
}
pub fn to_lifetime<I: Interner>(self, interner: I) -> Lifetime<I> {
LifetimeData::<I>::InferenceVar(self).intern(interner)
}
pub fn to_const<I: Interner>(self, interner: I, ty: Ty<I>) -> Const<I> {
ConstData {
ty,
value: ConstValue::<I>::InferenceVar(self),
}
.intern(interner)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, HasInterner, Debug)]
#[allow(missing_docs)]
pub struct FnSig<I: Interner> {
pub abi: I::FnAbi,
pub safety: Safety,
pub variadic: bool,
}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner, TypeFoldable, TypeVisitable)]
pub struct FnSubst<I: Interner>(pub Substitution<I>);
impl<I: Interner> Copy for FnSubst<I> where I::InternedSubstitution: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
#[allow(missing_docs)]
pub struct FnPointer<I: Interner> {
pub num_binders: usize,
pub sig: FnSig<I>,
pub substitution: FnSubst<I>,
}
impl<I: Interner> Copy for FnPointer<I> where I::InternedSubstitution: Copy {}
impl<I: Interner> FnPointer<I> {
pub fn into_binders(self, interner: I) -> Binders<FnSubst<I>> {
Binders::new(
VariableKinds::from_iter(
interner,
(0..self.num_binders).map(|_| VariableKind::Lifetime),
),
self.substitution,
)
}
pub fn as_binders(&self, interner: I) -> Binders<&FnSubst<I>> {
Binders::new(
VariableKinds::from_iter(
interner,
(0..self.num_binders).map(|_| VariableKind::Lifetime),
),
&self.substitution,
)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct Const<I: Interner> {
interned: I::InternedConst,
}
impl<I: Interner> Const<I> {
pub fn new(interner: I, data: impl CastTo<ConstData<I>>) -> Self {
Const {
interned: I::intern_const(interner, data.cast(interner)),
}
}
pub fn interned(&self) -> &I::InternedConst {
&self.interned
}
pub fn data(&self, interner: I) -> &ConstData<I> {
I::const_data(interner, &self.interned)
}
pub fn bound_var(&self, interner: I) -> Option<BoundVar> {
if let ConstValue::BoundVar(bv) = &self.data(interner).value {
Some(*bv)
} else {
None
}
}
pub fn inference_var(&self, interner: I) -> Option<InferenceVar> {
if let ConstValue::InferenceVar(iv) = &self.data(interner).value {
Some(*iv)
} else {
None
}
}
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,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
pub struct ConstData<I: Interner> {
pub ty: Ty<I>,
pub value: ConstValue<I>,
}
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
pub enum ConstValue<I: Interner> {
BoundVar(BoundVar),
InferenceVar(InferenceVar),
Placeholder(PlaceholderIndex),
Concrete(ConcreteConst<I>),
}
impl<I: Interner> Copy for ConstValue<I> where I::InternedConcreteConst: Copy {}
impl<I: Interner> ConstData<I> {
pub fn intern(self, interner: I) -> Const<I> {
Const::new(interner, self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct ConcreteConst<I: Interner> {
pub interned: I::InternedConcreteConst,
}
impl<I: Interner> ConcreteConst<I> {
pub fn const_eq(&self, ty: &Ty<I>, other: &ConcreteConst<I>, interner: I) -> bool {
interner.const_eq(&ty.interned, &self.interned, &other.interned)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct Lifetime<I: Interner> {
interned: I::InternedLifetime,
}
impl<I: Interner> Lifetime<I> {
pub fn new(interner: I, data: impl CastTo<LifetimeData<I>>) -> Self {
Lifetime {
interned: I::intern_lifetime(interner, data.cast(interner)),
}
}
pub fn interned(&self) -> &I::InternedLifetime {
&self.interned
}
pub fn data(&self, interner: I) -> &LifetimeData<I> {
I::lifetime_data(interner, &self.interned)
}
pub fn bound_var(&self, interner: I) -> Option<BoundVar> {
if let LifetimeData::BoundVar(bv) = self.data(interner) {
Some(*bv)
} else {
None
}
}
pub fn inference_var(&self, interner: I) -> Option<InferenceVar> {
if let LifetimeData::InferenceVar(depth) = self.data(interner) {
Some(*depth)
} else {
None
}
}
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!(),
}
}
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,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub enum LifetimeData<I: Interner> {
BoundVar(BoundVar),
InferenceVar(InferenceVar),
Placeholder(PlaceholderIndex),
Static,
Erased,
Phantom(Void, PhantomData<I>),
}
impl<I: Interner> LifetimeData<I> {
pub fn intern(self, interner: I) -> Lifetime<I> {
Lifetime::new(interner, self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceholderIndex {
pub ui: UniverseIndex,
pub idx: usize,
}
impl PlaceholderIndex {
pub fn to_lifetime<I: Interner>(self, interner: I) -> Lifetime<I> {
LifetimeData::<I>::Placeholder(self).intern(interner)
}
pub fn to_ty<I: Interner>(self, interner: I) -> Ty<I> {
TyKind::Placeholder(self).intern(interner)
}
pub fn to_const<I: Interner>(self, interner: I, ty: Ty<I>) -> Const<I> {
ConstData {
ty,
value: ConstValue::Placeholder(self),
}
.intern(interner)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum TyVariableKind {
General,
Integer,
Float,
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum VariableKind<I: Interner> {
Ty(TyVariableKind),
Lifetime,
Const(Ty<I>),
}
impl<I: Interner> interner::HasInterner for VariableKind<I> {
type Interner = I;
}
impl<I: Interner> Copy for VariableKind<I> where I::InternedType: Copy {}
impl<I: Interner> VariableKind<I> {
fn to_bound_variable(&self, interner: I, bound_var: BoundVar) -> GenericArg<I> {
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),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct GenericArg<I: Interner> {
interned: I::InternedGenericArg,
}
impl<I: Interner> GenericArg<I> {
pub fn new(interner: I, data: GenericArgData<I>) -> Self {
let interned = I::intern_generic_arg(interner, data);
GenericArg { interned }
}
pub fn interned(&self) -> &I::InternedGenericArg {
&self.interned
}
pub fn data(&self, interner: I) -> &GenericArgData<I> {
I::generic_arg_data(interner, &self.interned)
}
pub fn assert_ty_ref(&self, interner: I) -> &Ty<I> {
self.ty(interner).unwrap()
}
pub fn assert_lifetime_ref(&self, interner: I) -> &Lifetime<I> {
self.lifetime(interner).unwrap()
}
pub fn assert_const_ref(&self, interner: I) -> &Const<I> {
self.constant(interner).unwrap()
}
pub fn is_ty(&self, interner: I) -> bool {
match self.data(interner) {
GenericArgData::Ty(_) => true,
GenericArgData::Lifetime(_) => false,
GenericArgData::Const(_) => false,
}
}
pub fn ty(&self, interner: I) -> Option<&Ty<I>> {
match self.data(interner) {
GenericArgData::Ty(t) => Some(t),
_ => None,
}
}
pub fn lifetime(&self, interner: I) -> Option<&Lifetime<I>> {
match self.data(interner) {
GenericArgData::Lifetime(t) => Some(t),
_ => None,
}
}
pub fn constant(&self, interner: I) -> Option<&Const<I>> {
match self.data(interner) {
GenericArgData::Const(c) => Some(c),
_ => None,
}
}
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,
}
}
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, Zip)]
pub enum GenericArgData<I: Interner> {
Ty(Ty<I>),
Lifetime(Lifetime<I>),
Const(Const<I>),
}
impl<I: Interner> Copy for GenericArgData<I>
where
I::InternedType: Copy,
I::InternedLifetime: Copy,
I::InternedConst: Copy,
{
}
impl<I: Interner> GenericArgData<I> {
pub fn intern(self, interner: I) -> GenericArg<I> {
GenericArg::new(interner, self)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct WithKind<I: Interner, T> {
pub kind: VariableKind<I>,
value: T,
}
impl<I: Interner, T: Copy> Copy for WithKind<I, T> where I::InternedType: Copy {}
impl<I: Interner, T> HasInterner for WithKind<I, T> {
type Interner = I;
}
impl<I: Interner, T> From<WithKind<I, T>> for (VariableKind<I>, T) {
fn from(with_kind: WithKind<I, T>) -> Self {
(with_kind.kind, with_kind.value)
}
}
impl<I: Interner, T> WithKind<I, T> {
pub fn new(kind: VariableKind<I>, value: T) -> Self {
Self { kind, value }
}
pub fn map<U, OP>(self, op: OP) -> WithKind<I, U>
where
OP: FnOnce(T) -> U,
{
WithKind {
kind: self.kind,
value: op(self.value),
}
}
pub fn map_ref<U, OP>(&self, op: OP) -> WithKind<I, U>
where
OP: FnOnce(&T) -> U,
{
WithKind {
kind: self.kind.clone(),
value: op(&self.value),
}
}
pub fn skip_kind(&self) -> &T {
&self.value
}
}
#[allow(type_alias_bounds)]
pub type CanonicalVarKind<I: Interner> = WithKind<I, UniverseIndex>;
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub enum AliasTy<I: Interner> {
Projection(ProjectionTy<I>),
Opaque(OpaqueTy<I>),
}
impl<I: Interner> Copy for AliasTy<I> where I::InternedSubstitution: Copy {}
impl<I: Interner> AliasTy<I> {
pub fn intern(self, interner: I) -> Ty<I> {
Ty::new(interner, self)
}
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)
}
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct ProjectionTy<I: Interner> {
pub associated_ty_id: AssocTypeId<I>,
pub substitution: Substitution<I>,
}
impl<I: Interner> Copy for ProjectionTy<I> where I::InternedSubstitution: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct OpaqueTy<I: Interner> {
pub opaque_ty_id: OpaqueTyId<I>,
pub substitution: Substitution<I>,
}
impl<I: Interner> Copy for OpaqueTy<I> where I::InternedSubstitution: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct TraitRef<I: Interner> {
pub trait_id: TraitId<I>,
pub substitution: Substitution<I>,
}
impl<I: Interner> Copy for TraitRef<I> where I::InternedSubstitution: Copy {}
impl<I: Interner> TraitRef<I> {
pub fn type_parameters(&self, interner: I) -> impl Iterator<Item = Ty<I>> + '_ {
self.substitution
.iter(interner)
.filter_map(move |p| p.ty(interner))
.cloned()
}
pub fn self_type_parameter(&self, interner: I) -> Ty<I> {
self.type_parameters(interner).next().unwrap()
}
pub fn from_env(self) -> FromEnv<I> {
FromEnv::Trait(self)
}
pub fn well_formed(self) -> WellFormed<I> {
WellFormed::Trait(self)
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
#[allow(missing_docs)]
pub struct LifetimeOutlives<I: Interner> {
pub a: Lifetime<I>,
pub b: Lifetime<I>,
}
impl<I: Interner> Copy for LifetimeOutlives<I> where I::InternedLifetime: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub struct TypeOutlives<I: Interner> {
pub ty: Ty<I>,
pub lifetime: Lifetime<I>,
}
impl<I: Interner> Copy for TypeOutlives<I>
where
I::InternedLifetime: Copy,
I::InternedType: Copy,
{
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeSuperVisitable, HasInterner, Zip)]
pub enum WhereClause<I: Interner> {
Implemented(TraitRef<I>),
AliasEq(AliasEq<I>),
LifetimeOutlives(LifetimeOutlives<I>),
TypeOutlives(TypeOutlives<I>),
}
impl<I: Interner> Copy for WhereClause<I>
where
I::InternedSubstitution: Copy,
I::InternedLifetime: Copy,
I::InternedType: Copy,
{
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub enum WellFormed<I: Interner> {
Trait(TraitRef<I>),
Ty(Ty<I>),
}
impl<I: Interner> Copy for WellFormed<I>
where
I::InternedType: Copy,
I::InternedSubstitution: Copy,
{
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub enum FromEnv<I: Interner> {
Trait(TraitRef<I>),
Ty(Ty<I>),
}
impl<I: Interner> Copy for FromEnv<I>
where
I::InternedType: Copy,
I::InternedSubstitution: Copy,
{
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeSuperVisitable, HasInterner, Zip)]
pub enum DomainGoal<I: Interner> {
Holds(WhereClause<I>),
WellFormed(WellFormed<I>),
FromEnv(FromEnv<I>),
Normalize(Normalize<I>),
IsLocal(Ty<I>),
IsUpstream(Ty<I>),
IsFullyVisible(Ty<I>),
LocalImplAllowed(TraitRef<I>),
Compatible,
DownstreamType(Ty<I>),
Reveal,
ObjectSafe(TraitId<I>),
}
impl<I: Interner> Copy for DomainGoal<I>
where
I::InternedSubstitution: Copy,
I::InternedLifetime: Copy,
I::InternedType: Copy,
{
}
pub type QuantifiedWhereClause<I> = Binders<WhereClause<I>>;
impl<I: Interner> WhereClause<I> {
pub fn into_well_formed_goal(self, interner: I) -> DomainGoal<I> {
match self {
WhereClause::Implemented(trait_ref) => WellFormed::Trait(trait_ref).cast(interner),
wc => wc.cast(interner),
}
}
pub fn into_from_env_goal(self, interner: I) -> DomainGoal<I> {
match self {
WhereClause::Implemented(trait_ref) => FromEnv::Trait(trait_ref).cast(interner),
wc => wc.cast(interner),
}
}
pub fn trait_id(&self) -> Option<TraitId<I>> {
match self {
WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id),
WhereClause::AliasEq(_) => None,
WhereClause::LifetimeOutlives(_) => None,
WhereClause::TypeOutlives(_) => None,
}
}
}
impl<I: Interner> QuantifiedWhereClause<I> {
pub fn into_well_formed_goal(self, interner: I) -> Binders<DomainGoal<I>> {
self.map(|wc| wc.into_well_formed_goal(interner))
}
pub fn into_from_env_goal(self, interner: I) -> Binders<DomainGoal<I>> {
self.map(|wc| wc.into_from_env_goal(interner))
}
pub fn trait_id(&self) -> Option<TraitId<I>> {
self.skip_binders().trait_id()
}
}
impl<I: Interner> DomainGoal<I> {
pub fn into_from_env_goal(self, interner: I) -> DomainGoal<I> {
match self {
DomainGoal::Holds(wc) => wc.into_from_env_goal(interner),
goal => goal,
}
}
pub fn inputs(&self, interner: I) -> Vec<GenericArg<I>> {
match self {
DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
vec![GenericArgData::Ty(alias_eq.alias.clone().intern(interner)).intern(interner)]
}
_ => Vec::new(),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)]
#[allow(missing_docs)]
pub struct EqGoal<I: Interner> {
pub a: GenericArg<I>,
pub b: GenericArg<I>,
}
impl<I: Interner> Copy for EqGoal<I> where I::InternedGenericArg: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)]
#[allow(missing_docs)]
pub struct SubtypeGoal<I: Interner> {
pub a: Ty<I>,
pub b: Ty<I>,
}
impl<I: Interner> Copy for SubtypeGoal<I> where I::InternedType: Copy {}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)]
#[allow(missing_docs)]
pub struct Normalize<I: Interner> {
pub alias: AliasTy<I>,
pub ty: Ty<I>,
}
impl<I: Interner> Copy for Normalize<I>
where
I::InternedSubstitution: Copy,
I::InternedType: Copy,
{
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, Zip)]
#[allow(missing_docs)]
pub struct AliasEq<I: Interner> {
pub alias: AliasTy<I>,
pub ty: Ty<I>,
}
impl<I: Interner> Copy for AliasEq<I>
where
I::InternedSubstitution: Copy,
I::InternedType: Copy,
{
}
impl<I: Interner> HasInterner for AliasEq<I> {
type Interner = I;
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Binders<T: HasInterner> {
pub binders: VariableKinds<T::Interner>,
value: T,
}
impl<T: HasInterner + Copy> Copy for Binders<T> where
<T::Interner as Interner>::InternedVariableKinds: Copy
{
}
impl<T: HasInterner> HasInterner for Binders<T> {
type Interner = T::Interner;
}
impl<T: Clone + HasInterner> Binders<&T> {
pub fn cloned(self) -> Binders<T> {
self.map(Clone::clone)
}
}
impl<T: HasInterner> Binders<T> {
pub fn new(binders: VariableKinds<T::Interner>, value: T) -> Self {
Self { binders, value }
}
pub fn empty(interner: T::Interner, value: T) -> Self {
let binders = VariableKinds::empty(interner);
Self { binders, value }
}
pub fn skip_binders(&self) -> &T {
&self.value
}
pub fn into_value_and_skipped_binders(self) -> (T, VariableKinds<T::Interner>) {
(self.value, self.binders)
}
pub fn as_ref(&self) -> Binders<&T> {
Binders {
binders: self.binders.clone(),
value: &self.value,
}
}
pub fn map<U, OP>(self, op: OP) -> Binders<U>
where
OP: FnOnce(T) -> U,
U: HasInterner<Interner = T::Interner>,
{
let value = op(self.value);
Binders {
binders: self.binders,
value,
}
}
pub fn filter_map<U, OP>(self, op: OP) -> Option<Binders<U>>
where
OP: FnOnce(T) -> Option<U>,
U: HasInterner<Interner = T::Interner>,
{
let value = op(self.value)?;
Some(Binders {
binders: self.binders,
value,
})
}
pub fn map_ref<'a, U, OP>(&'a self, op: OP) -> Binders<U>
where
OP: FnOnce(&'a T) -> U,
U: HasInterner<Interner = T::Interner>,
{
self.as_ref().map(op)
}
pub fn identity_substitution(&self, interner: T::Interner) -> Substitution<T::Interner> {
Substitution::from_iter(
interner,
self.binders
.iter(interner)
.enumerate()
.map(|p| p.to_generic_arg(interner)),
)
}
pub fn with_fresh_type_var(
interner: T::Interner,
op: impl FnOnce(Ty<T::Interner>) -> T,
) -> Binders<T> {
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 }
}
pub fn len(&self, interner: T::Interner) -> usize {
self.binders.len(interner)
}
}
impl<T, I> Binders<Binders<T>>
where
T: TypeFoldable<I> + HasInterner<Interner = I>,
I: Interner,
{
pub fn fuse_binders(self, interner: T::Interner) -> Binders<T> {
let num_binders = self.len(interner);
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<T: HasInterner> From<Binders<T>> for (VariableKinds<T::Interner>, T) {
fn from(binders: Binders<T>) -> Self {
(binders.binders, binders.value)
}
}
impl<T, I> Binders<T>
where
T: TypeFoldable<I> + HasInterner<Interner = I>,
I: Interner,
{
pub fn substitute(self, interner: I, parameters: &(impl AsParameters<I> + ?Sized)) -> T {
let parameters = parameters.as_parameters(interner);
assert_eq!(self.binders.len(interner), parameters.len());
Subst::apply(interner, parameters, self.value)
}
}
impl<V, U> IntoIterator for Binders<V>
where
V: HasInterner + IntoIterator<Item = U>,
U: HasInterner<Interner = V::Interner>,
{
type Item = Binders<U>;
type IntoIter = BindersIntoIterator<V>;
fn into_iter(self) -> Self::IntoIter {
BindersIntoIterator {
iter: self.value.into_iter(),
binders: self.binders,
}
}
}
pub struct BindersIntoIterator<V: HasInterner + IntoIterator> {
iter: <V as IntoIterator>::IntoIter,
binders: VariableKinds<V::Interner>,
}
impl<V> Iterator for BindersIntoIterator<V>
where
V: HasInterner + IntoIterator,
<V as IntoIterator>::Item: HasInterner<Interner = V::Interner>,
{
type Item = Binders<<V as IntoIterator>::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|v| Binders::new(self.binders.clone(), v))
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub struct ProgramClauseImplication<I: Interner> {
pub consequence: DomainGoal<I>,
pub conditions: Goals<I>,
pub constraints: Constraints<I>,
pub priority: ClausePriority,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum ClausePriority {
High,
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,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, HasInterner, Zip)]
pub struct ProgramClauseData<I: Interner>(pub Binders<ProgramClauseImplication<I>>);
impl<I: Interner> ProgramClauseImplication<I> {
pub fn into_from_env_clause(self, interner: I) -> ProgramClauseImplication<I> {
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<I: Interner> ProgramClauseData<I> {
pub fn into_from_env_clause(self, interner: I) -> ProgramClauseData<I> {
ProgramClauseData(self.0.map(|i| i.into_from_env_clause(interner)))
}
pub fn intern(self, interner: I) -> ProgramClause<I> {
ProgramClause {
interned: interner.intern_program_clause(self),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct ProgramClause<I: Interner> {
interned: I::InternedProgramClause,
}
impl<I: Interner> ProgramClause<I> {
pub fn new(interner: I, clause: ProgramClauseData<I>) -> Self {
let interned = interner.intern_program_clause(clause);
Self { interned }
}
pub fn into_from_env_clause(self, interner: I) -> ProgramClause<I> {
let program_clause_data = self.data(interner);
let new_clause = program_clause_data.clone().into_from_env_clause(interner);
Self::new(interner, new_clause)
}
pub fn interned(&self) -> &I::InternedProgramClause {
&self.interned
}
pub fn data(&self, interner: I) -> &ProgramClauseData<I> {
interner.program_clause_data(&self.interned)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Canonical<T: HasInterner> {
pub value: T,
pub binders: CanonicalVarKinds<T::Interner>,
}
impl<T: HasInterner> HasInterner for Canonical<T> {
type Interner = T::Interner;
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct UCanonical<T: HasInterner> {
pub canonical: Canonical<T>,
pub universes: usize,
}
impl<T: HasInterner> UCanonical<T> {
pub fn is_trivial_substitution(
&self,
interner: T::Interner,
canonical_subst: &Canonical<AnswerSubst<T::Interner>>,
) -> bool {
let subst = &canonical_subst.value.subst;
assert_eq!(
self.canonical.binders.len(interner),
subst.as_slice(interner).len()
);
subst.is_identity_subst(interner)
}
pub fn trivial_substitution(&self, interner: T::Interner) -> Substitution<T::Interner> {
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::<Vec<_>>(),
)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct Goal<I: Interner> {
interned: I::InternedGoal,
}
impl<I: Interner> Goal<I> {
pub fn new(interner: I, interned: GoalData<I>) -> Self {
let interned = I::intern_goal(interner, interned);
Self { interned }
}
pub fn interned(&self) -> &I::InternedGoal {
&self.interned
}
pub fn data(&self, interner: I) -> &GoalData<I> {
interner.goal_data(&self.interned)
}
pub fn quantify(self, interner: I, kind: QuantifierKind, binders: VariableKinds<I>) -> Goal<I> {
GoalData::Quantified(kind, Binders::new(binders, self)).intern(interner)
}
pub fn negate(self, interner: I) -> Self {
GoalData::Not(self).intern(interner)
}
pub fn compatible(self, interner: I) -> Self {
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)
}
pub fn implied_by(self, interner: I, predicates: ProgramClauses<I>) -> Goal<I> {
GoalData::Implies(predicates, self).intern(interner)
}
pub fn is_trivially_true(&self, interner: I) -> bool {
match self.data(interner) {
GoalData::All(goals) => goals.is_empty(interner),
_ => false,
}
}
}
impl<I> Goal<I>
where
I: Interner,
{
pub fn all<II>(interner: I, iter: II) -> Self
where
II: IntoIterator<Item = Goal<I>>,
{
let mut iter = iter.into_iter();
if let Some(goal0) = iter.next() {
if let Some(goal1) = iter.next() {
let goals = Goals::from_iter(
interner,
Some(goal0).into_iter().chain(Some(goal1)).chain(iter),
);
GoalData::All(goals).intern(interner)
} else {
goal0
}
} else {
GoalData::All(Goals::empty(interner)).intern(interner)
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub enum GoalData<I: Interner> {
Quantified(QuantifierKind, Binders<Goal<I>>),
Implies(ProgramClauses<I>, Goal<I>),
All(Goals<I>),
Not(Goal<I>),
EqGoal(EqGoal<I>),
SubtypeGoal(SubtypeGoal<I>),
DomainGoal(DomainGoal<I>),
CannotProve,
}
impl<I: Interner> Copy for GoalData<I>
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<I: Interner> GoalData<I> {
pub fn intern(self, interner: I) -> Goal<I> {
Goal::new(interner, self)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum QuantifierKind {
ForAll,
Exists,
}
#[derive(Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner, Zip)]
pub enum Constraint<I: Interner> {
LifetimeOutlives(Lifetime<I>, Lifetime<I>),
TypeOutlives(Ty<I>, Lifetime<I>),
}
impl<I: Interner> Copy for Constraint<I>
where
I::InternedLifetime: Copy,
I::InternedType: Copy,
{
}
impl<I: Interner> Substitution<I> {
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,
},
}
})
}
pub fn apply<T>(&self, value: T, interner: I) -> T
where
T: TypeFoldable<I>,
{
Substitute::apply(self, value, interner)
}
pub fn type_parameters(&self, interner: I) -> impl Iterator<Item = Ty<I>> + '_ {
self.iter(interner)
.filter_map(move |p| p.ty(interner))
.cloned()
}
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<I>> {
interner: I,
subst: &'i A,
}
impl<I: Interner, A: AsParameters<I>> SubstFolder<'_, I, A> {
pub fn at(&self, index: usize) -> &GenericArg<I> {
let interner = self.interner;
&self.subst.as_parameters(interner)[index]
}
}
pub trait AsParameters<I: Interner> {
fn as_parameters(&self, interner: I) -> &[GenericArg<I>];
}
impl<I: Interner> AsParameters<I> for Substitution<I> {
#[allow(unreachable_code, unused_variables)]
fn as_parameters(&self, interner: I) -> &[GenericArg<I>] {
self.as_slice(interner)
}
}
impl<I: Interner> AsParameters<I> for [GenericArg<I>] {
fn as_parameters(&self, _interner: I) -> &[GenericArg<I>] {
self
}
}
impl<I: Interner> AsParameters<I> for [GenericArg<I>; 1] {
fn as_parameters(&self, _interner: I) -> &[GenericArg<I>] {
self
}
}
impl<I: Interner> AsParameters<I> for Vec<GenericArg<I>> {
fn as_parameters(&self, _interner: I) -> &[GenericArg<I>] {
self
}
}
impl<T, I: Interner> AsParameters<I> for &T
where
T: ?Sized + AsParameters<I>,
{
fn as_parameters(&self, interner: I) -> &[GenericArg<I>] {
T::as_parameters(self, interner)
}
}
pub trait Substitute<I: Interner>: AsParameters<I> {
fn apply<T: TypeFoldable<I>>(&self, value: T, interner: I) -> T;
}
impl<I: Interner, A: AsParameters<I>> Substitute<I> for A {
fn apply<T>(&self, value: T, interner: I) -> T
where
T: TypeFoldable<I>,
{
value
.try_fold_with(
&mut SubstFolder {
interner,
subst: self,
},
DebruijnIndex::INNERMOST,
)
.unwrap()
}
}
pub trait ToGenericArg<I: Interner> {
fn to_generic_arg(&self, interner: I) -> GenericArg<I> {
self.to_generic_arg_at_depth(interner, DebruijnIndex::INNERMOST)
}
fn to_generic_arg_at_depth(&self, interner: I, debruijn: DebruijnIndex) -> GenericArg<I>;
}
impl<'a, I: Interner> ToGenericArg<I> for (usize, &'a VariableKind<I>) {
fn to_generic_arg_at_depth(&self, interner: I, debruijn: DebruijnIndex) -> GenericArg<I> {
let &(index, binder) = self;
let bound_var = BoundVar::new(debruijn, index);
binder.to_bound_variable(interner, bound_var)
}
}
impl<'i, I: Interner, A: AsParameters<I>> TypeFolder<I> for SubstFolder<'i, I, A> {
fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> {
self
}
fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty<I> {
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<I> {
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<I>,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Const<I> {
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) => {
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)]
pub struct $seq<I: Interner> {
interned: I::$interned,
}
impl<I: Interner> $seq<I> {
pub fn interned(&self) -> &I::$interned {
&self.interned
}
pub fn as_slice(&self, interner: I) -> &[$elem] {
Interner::$data(interner, &self.interned)
}
pub fn at(&self, interner: I, index: usize) -> &$elem {
&self.as_slice(interner)[index]
}
pub fn empty(interner: I) -> Self {
Self::from_iter(interner, None::<$elem>)
}
pub fn is_empty(&self, interner: I) -> bool {
self.as_slice(interner).is_empty()
}
pub fn iter(&self, interner: I) -> std::slice::Iter<'_, $elem> {
self.as_slice(interner).iter()
}
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<I: Interner> $seq<I> {
pub fn from_fallible<E>(
interner: I,
elements: impl IntoIterator<Item = Result<impl CastTo<$elem>, E>>,
) -> Result<Self, E> {
Ok(Self {
interned: I::$intern(interner, elements.into_iter().casted(interner))?,
})
}
pub fn from_iter(
interner: I,
elements: impl IntoIterator<Item = impl CastTo<$elem>>,
) -> Self {
Self::from_fallible(
interner,
elements
.into_iter()
.map(|el| -> Result<$elem, ()> { Ok(el.cast(interner)) }),
)
.unwrap()
}
pub fn from1(interner: I, element: impl CastTo<$elem>) -> Self {
Self::from_iter(interner, Some(element))
}
}
};
}
interned_slice!(
QuantifiedWhereClauses,
quantified_where_clauses_data => QuantifiedWhereClause<I>,
intern_quantified_where_clauses => InternedQuantifiedWhereClauses
);
interned_slice!(
ProgramClauses,
program_clauses_data => ProgramClause<I>,
intern_program_clauses => InternedProgramClauses
);
interned_slice!(
VariableKinds,
variable_kinds_data => VariableKind<I>,
intern_generic_arg_kinds => InternedVariableKinds
);
interned_slice!(
CanonicalVarKinds,
canonical_var_kinds_data => CanonicalVarKind<I>,
intern_canonical_var_kinds => InternedCanonicalVarKinds
);
interned_slice!(Goals, goals_data => Goal<I>, intern_goals => InternedGoals);
interned_slice!(
Constraints,
constraints_data => InEnvironment<Constraint<I>>,
intern_constraints => InternedConstraints
);
interned_slice!(
Substitution,
substitution_data => GenericArg<I>,
intern_substitution => InternedSubstitution
);
interned_slice_common!(
Variances,
variances_data => Variance,
intern_variance => InternedVariances
);
impl<I: Interner> Variances<I> {
pub fn from_fallible<E>(
interner: I,
variances: impl IntoIterator<Item = Result<Variance, E>>,
) -> Result<Self, E> {
Ok(Variances {
interned: I::intern_variances(interner, variances.into_iter())?,
})
}
pub fn from_iter(interner: I, variances: impl IntoIterator<Item = Variance>) -> Self {
Self::from_fallible(
interner,
variances
.into_iter()
.map(|p| -> Result<Variance, ()> { Ok(p) }),
)
.unwrap()
}
pub fn from1(interner: I, variance: Variance) -> Self {
Self::from_iter(interner, Some(variance))
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct ConstrainedSubst<I: Interner> {
pub subst: Substitution<I>,
pub constraints: Constraints<I>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable, HasInterner)]
pub struct AnswerSubst<I: Interner> {
pub subst: Substitution<I>,
pub constraints: Constraints<I>,
pub delayed_subgoals: Vec<InEnvironment<Goal<I>>>,
}
pub trait UnificationDatabase<I>
where
Self: std::fmt::Debug,
I: Interner,
{
fn fn_def_variance(&self, fn_def_id: FnDefId<I>) -> Variances<I>;
fn adt_variance(&self, adt_id: AdtId<I>) -> Variances<I>;
}