use crate::interner::TargetInterner;
use crate::*;
use std::fmt::Debug;
mod binder_impls;
mod boring_impls;
pub mod shift;
mod subst;
pub use self::shift::Shift;
pub use self::subst::Subst;
pub trait Folder<'i, I: Interner, TI: TargetInterner<I> = I>
where
I: 'i,
TI: 'i,
{
fn as_dyn(&mut self) -> &mut dyn Folder<'i, I, TI>;
fn fold_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> Fallible<Ty<TI>> {
ty.super_fold_with(self.as_dyn(), outer_binder)
}
fn fold_lifetime(
&mut self,
lifetime: &Lifetime<I>,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<TI>> {
lifetime.super_fold_with(self.as_dyn(), outer_binder)
}
fn fold_const(
&mut self,
constant: &Const<I>,
outer_binder: DebruijnIndex,
) -> Fallible<Const<TI>> {
constant.super_fold_with(self.as_dyn(), outer_binder)
}
fn fold_program_clause(
&mut self,
clause: &ProgramClause<I>,
outer_binder: DebruijnIndex,
) -> Fallible<ProgramClause<TI>> {
clause.super_fold_with(self.as_dyn(), outer_binder)
}
fn fold_goal(&mut self, goal: &Goal<I>, outer_binder: DebruijnIndex) -> Fallible<Goal<TI>> {
goal.super_fold_with(self.as_dyn(), outer_binder)
}
fn forbid_free_vars(&self) -> bool {
false
}
fn fold_free_var_ty(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Ty<TI>> {
if self.forbid_free_vars() {
panic!(
"unexpected free variable with depth `{:?}` with outer binder {:?}",
bound_var, outer_binder
)
} else {
let bound_var = bound_var.shifted_in_from(outer_binder);
Ok(TyKind::<TI>::BoundVar(bound_var).intern(self.target_interner()))
}
}
fn fold_free_var_lifetime(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<TI>> {
if self.forbid_free_vars() {
panic!(
"unexpected free variable with depth `{:?}` with outer binder {:?}",
bound_var, outer_binder
)
} else {
let bound_var = bound_var.shifted_in_from(outer_binder);
Ok(LifetimeData::<TI>::BoundVar(bound_var).intern(self.target_interner()))
}
}
fn fold_free_var_const(
&mut self,
ty: &Ty<I>,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Const<TI>> {
if self.forbid_free_vars() {
panic!(
"unexpected free variable with depth `{:?}` with outer binder {:?}",
bound_var, outer_binder
)
} else {
let bound_var = bound_var.shifted_in_from(outer_binder);
Ok(ConstData {
ty: ty.fold_with(self.as_dyn(), outer_binder)?,
value: ConstValue::<TI>::BoundVar(bound_var),
}
.intern(self.target_interner()))
}
}
fn forbid_free_placeholders(&self) -> bool {
false
}
#[allow(unused_variables)]
fn fold_free_placeholder_ty(
&mut self,
universe: PlaceholderIndex,
outer_binder: DebruijnIndex,
) -> Fallible<Ty<TI>> {
if self.forbid_free_placeholders() {
panic!("unexpected placeholder type `{:?}`", universe)
} else {
Ok(universe.to_ty::<TI>(self.target_interner()))
}
}
#[allow(unused_variables)]
fn fold_free_placeholder_lifetime(
&mut self,
universe: PlaceholderIndex,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<TI>> {
if self.forbid_free_placeholders() {
panic!("unexpected placeholder lifetime `{:?}`", universe)
} else {
Ok(universe.to_lifetime(self.target_interner()))
}
}
#[allow(unused_variables)]
fn fold_free_placeholder_const(
&mut self,
ty: &Ty<I>,
universe: PlaceholderIndex,
outer_binder: DebruijnIndex,
) -> Fallible<Const<TI>> {
if self.forbid_free_placeholders() {
panic!("unexpected placeholder const `{:?}`", universe)
} else {
Ok(universe.to_const(
self.target_interner(),
ty.fold_with(self.as_dyn(), outer_binder)?,
))
}
}
fn forbid_inference_vars(&self) -> bool {
false
}
#[allow(unused_variables)]
fn fold_inference_ty(
&mut self,
var: InferenceVar,
kind: TyVariableKind,
outer_binder: DebruijnIndex,
) -> Fallible<Ty<TI>> {
if self.forbid_inference_vars() {
panic!("unexpected inference type `{:?}`", var)
} else {
Ok(var.to_ty(self.target_interner(), kind))
}
}
#[allow(unused_variables)]
fn fold_inference_lifetime(
&mut self,
var: InferenceVar,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<TI>> {
if self.forbid_inference_vars() {
panic!("unexpected inference lifetime `'{:?}`", var)
} else {
Ok(var.to_lifetime(self.target_interner()))
}
}
#[allow(unused_variables)]
fn fold_inference_const(
&mut self,
ty: &Ty<I>,
var: InferenceVar,
outer_binder: DebruijnIndex,
) -> Fallible<Const<TI>> {
if self.forbid_inference_vars() {
panic!("unexpected inference const `{:?}`", var)
} else {
Ok(var.to_const(
self.target_interner(),
ty.fold_with(self.as_dyn(), outer_binder)?,
))
}
}
fn interner(&self) -> &'i I;
fn target_interner(&self) -> &'i TI;
}
pub trait Fold<I: Interner, TI: TargetInterner<I> = I>: Debug {
type Result;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i;
}
pub trait SuperFold<I: Interner, TI: TargetInterner<I> = I>: Fold<I, TI> {
fn super_fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i;
}
impl<I: Interner, TI: TargetInterner<I>> Fold<I, TI> for Ty<I> {
type Result = Ty<TI>;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
folder.fold_ty(self, outer_binder)
}
}
impl<I, TI> SuperFold<I, TI> for Ty<I>
where
I: Interner,
TI: TargetInterner<I>,
{
fn super_fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Ty<TI>>
where
I: 'i,
TI: 'i,
{
let interner = folder.interner();
Ok(match self.kind(interner) {
TyKind::BoundVar(bound_var) => {
if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
folder.fold_free_var_ty(bound_var1, outer_binder)?
} else {
TyKind::<TI>::BoundVar(*bound_var).intern(folder.target_interner())
}
}
TyKind::Dyn(clauses) => TyKind::Dyn(clauses.fold_with(folder, outer_binder)?)
.intern(folder.target_interner()),
TyKind::InferenceVar(var, kind) => {
folder.fold_inference_ty(*var, *kind, outer_binder)?
}
TyKind::Placeholder(ui) => folder.fold_free_placeholder_ty(*ui, outer_binder)?,
TyKind::Alias(proj) => TyKind::Alias(proj.fold_with(folder, outer_binder)?)
.intern(folder.target_interner()),
TyKind::Function(fun) => TyKind::Function(fun.fold_with(folder, outer_binder)?)
.intern(folder.target_interner()),
TyKind::Adt(id, substitution) => TyKind::Adt(
id.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::AssociatedType(assoc_ty, substitution) => TyKind::AssociatedType(
assoc_ty.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Scalar(scalar) => TyKind::Scalar(scalar.fold_with(folder, outer_binder)?)
.intern(folder.target_interner()),
TyKind::Str => TyKind::Str.intern(folder.target_interner()),
TyKind::Tuple(arity, substitution) => {
TyKind::Tuple(*arity, substitution.fold_with(folder, outer_binder)?)
.intern(folder.target_interner())
}
TyKind::OpaqueType(opaque_ty, substitution) => TyKind::OpaqueType(
opaque_ty.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Slice(substitution) => {
TyKind::Slice(substitution.fold_with(folder, outer_binder)?)
.intern(folder.target_interner())
}
TyKind::FnDef(fn_def, substitution) => TyKind::FnDef(
fn_def.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Ref(mutability, lifetime, ty) => TyKind::Ref(
mutability.fold_with(folder, outer_binder)?,
lifetime.fold_with(folder, outer_binder)?,
ty.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Raw(mutability, ty) => TyKind::Raw(
mutability.fold_with(folder, outer_binder)?,
ty.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Never => TyKind::Never.intern(folder.target_interner()),
TyKind::Array(ty, const_) => TyKind::Array(
ty.fold_with(folder, outer_binder)?,
const_.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Closure(id, substitution) => TyKind::Closure(
id.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Generator(id, substitution) => TyKind::Generator(
id.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::GeneratorWitness(id, substitution) => TyKind::GeneratorWitness(
id.fold_with(folder, outer_binder)?,
substitution.fold_with(folder, outer_binder)?,
)
.intern(folder.target_interner()),
TyKind::Foreign(id) => TyKind::Foreign(id.fold_with(folder, outer_binder)?)
.intern(folder.target_interner()),
TyKind::Error => TyKind::Error.intern(folder.target_interner()),
})
}
}
impl<I: Interner, TI: TargetInterner<I>> Fold<I, TI> for Lifetime<I> {
type Result = Lifetime<TI>;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
folder.fold_lifetime(self, outer_binder)
}
}
impl<I, TI> SuperFold<I, TI> for Lifetime<I>
where
I: Interner,
TI: TargetInterner<I>,
{
fn super_fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<TI>>
where
I: 'i,
TI: 'i,
{
let interner = folder.interner();
match self.data(interner) {
LifetimeData::BoundVar(bound_var) => {
if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
folder.fold_free_var_lifetime(bound_var1, outer_binder)
} else {
Ok(LifetimeData::<TI>::BoundVar(*bound_var).intern(folder.target_interner()))
}
}
LifetimeData::InferenceVar(var) => folder.fold_inference_lifetime(*var, outer_binder),
LifetimeData::Placeholder(universe) => {
folder.fold_free_placeholder_lifetime(*universe, outer_binder)
}
LifetimeData::Static => Ok(LifetimeData::<TI>::Static.intern(folder.target_interner())),
LifetimeData::Phantom(..) => unreachable!(),
}
}
}
impl<I: Interner, TI: TargetInterner<I>> Fold<I, TI> for Const<I> {
type Result = Const<TI>;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
folder.fold_const(self, outer_binder)
}
}
impl<I, TI> SuperFold<I, TI> for Const<I>
where
I: Interner,
TI: TargetInterner<I>,
{
fn super_fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Const<TI>>
where
I: 'i,
TI: 'i,
{
let interner = folder.interner();
let target_interner = folder.target_interner();
let ConstData { ref ty, ref value } = self.data(interner);
let mut fold_ty = || ty.fold_with(folder, outer_binder);
match value {
ConstValue::BoundVar(bound_var) => {
if let Some(bound_var1) = bound_var.shifted_out_to(outer_binder) {
folder.fold_free_var_const(ty, bound_var1, outer_binder)
} else {
Ok(bound_var.to_const(target_interner, fold_ty()?))
}
}
ConstValue::InferenceVar(var) => folder.fold_inference_const(ty, *var, outer_binder),
ConstValue::Placeholder(universe) => {
folder.fold_free_placeholder_const(ty, *universe, outer_binder)
}
ConstValue::Concrete(ev) => Ok(ConstData {
ty: fold_ty()?,
value: ConstValue::Concrete(ConcreteConst {
interned: folder.target_interner().transfer_const(&ev.interned),
}),
}
.intern(folder.target_interner())),
}
}
}
impl<I: Interner, TI: TargetInterner<I>> Fold<I, TI> for Goal<I> {
type Result = Goal<TI>;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
folder.fold_goal(self, outer_binder)
}
}
impl<I: Interner, TI: TargetInterner<I>> SuperFold<I, TI> for Goal<I> {
fn super_fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
let interner = folder.interner();
let target_interner = folder.target_interner();
Ok(Goal::new(
target_interner,
self.data(interner).fold_with(folder, outer_binder)?,
))
}
}
impl<I: Interner, TI: TargetInterner<I>> Fold<I, TI> for ProgramClause<I> {
type Result = ProgramClause<TI>;
fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
folder.fold_program_clause(self, outer_binder)
}
}