use crate::*;
pub trait Shift<I: Interner>: TypeFoldable<I> {
fn shifted_in(self, interner: I) -> Self;
fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> Self;
fn shifted_out(self, interner: I) -> Fallible<Self>;
fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<Self>;
}
impl<T: TypeFoldable<I>, I: Interner> Shift<I> for T {
fn shifted_in(self, interner: I) -> Self {
self.shifted_in_from(interner, DebruijnIndex::ONE)
}
fn shifted_in_from(self, interner: I, source_binder: DebruijnIndex) -> T {
self.try_fold_with(
&mut Shifter {
source_binder,
interner,
},
DebruijnIndex::INNERMOST,
)
.unwrap()
}
fn shifted_out_to(self, interner: I, target_binder: DebruijnIndex) -> Fallible<T> {
self.try_fold_with(
&mut DownShifter {
target_binder,
interner,
},
DebruijnIndex::INNERMOST,
)
}
fn shifted_out(self, interner: I) -> Fallible<Self> {
self.shifted_out_to(interner, DebruijnIndex::ONE)
}
}
#[derive(FallibleTypeFolder)]
struct Shifter<I: Interner> {
source_binder: DebruijnIndex,
interner: I,
}
impl<I: Interner> Shifter<I> {
fn adjust(&self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> BoundVar {
bound_var
.shifted_in_from(self.source_binder)
.shifted_in_from(outer_binder)
}
}
impl<I: Interner> TypeFolder<I> for Shifter<I> {
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> {
TyKind::<I>::BoundVar(self.adjust(bound_var, outer_binder))
.intern(TypeFolder::interner(self))
}
fn fold_free_var_lifetime(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Lifetime<I> {
LifetimeData::<I>::BoundVar(self.adjust(bound_var, outer_binder))
.intern(TypeFolder::interner(self))
}
fn fold_free_var_const(
&mut self,
ty: Ty<I>,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Const<I> {
self.adjust(bound_var, outer_binder)
.to_const(TypeFolder::interner(self), ty)
}
fn interner(&self) -> I {
self.interner
}
}
struct DownShifter<I> {
target_binder: DebruijnIndex,
interner: I,
}
impl<I> DownShifter<I> {
fn adjust(&self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Fallible<BoundVar> {
match bound_var.shifted_out_to(self.target_binder) {
Some(bound_var1) => Ok(bound_var1.shifted_in_from(outer_binder)),
None => Err(NoSolution),
}
}
}
impl<I: Interner> FallibleTypeFolder<I> for DownShifter<I> {
type Error = NoSolution;
fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<I, Error = Self::Error> {
self
}
fn try_fold_free_var_ty(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Ty<I>> {
Ok(TyKind::<I>::BoundVar(self.adjust(bound_var, outer_binder)?).intern(self.interner()))
}
fn try_fold_free_var_lifetime(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Lifetime<I>> {
Ok(
LifetimeData::<I>::BoundVar(self.adjust(bound_var, outer_binder)?)
.intern(self.interner()),
)
}
fn try_fold_free_var_const(
&mut self,
ty: Ty<I>,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Const<I>> {
Ok(self
.adjust(bound_var, outer_binder)?
.to_const(self.interner(), ty))
}
fn interner(&self) -> I {
self.interner
}
}