use std::fmt::Debug;
use crate::{
BoundVar, DebruijnIndex, DomainGoal, Goal, InferenceVar, Interner, Lifetime, LifetimeData,
PlaceholderIndex, ProgramClause, Ty, TyData, WhereClause,
};
mod binder_impls;
mod boring_impls;
pub mod visitors;
pub use visitors::VisitExt;
pub trait VisitResult: Sized {
fn new() -> Self;
fn return_early(&self) -> bool;
fn combine(self, other: Self) -> Self;
fn and_then(self, op: impl FnOnce() -> Self) -> Self {
if self.return_early() {
self
} else {
self.combine(op())
}
}
}
impl VisitResult for () {
fn new() -> () {}
fn return_early(&self) -> bool {
false
}
fn combine(self, _other: Self) {}
}
pub trait Visitor<'i, I: Interner>
where
I: 'i,
{
type Result: VisitResult;
fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result>;
fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> Self::Result {
ty.super_visit_with(self.as_dyn(), outer_binder)
}
fn visit_lifetime(
&mut self,
lifetime: &Lifetime<I>,
outer_binder: DebruijnIndex,
) -> Self::Result {
lifetime.super_visit_with(self.as_dyn(), outer_binder)
}
fn visit_program_clause(
&mut self,
clause: &ProgramClause<I>,
outer_binder: DebruijnIndex,
) -> Self::Result {
clause.super_visit_with(self.as_dyn(), outer_binder)
}
fn visit_goal(&mut self, goal: &Goal<I>, outer_binder: DebruijnIndex) -> Self::Result {
goal.super_visit_with(self.as_dyn(), outer_binder)
}
fn visit_domain_goal(
&mut self,
domain_goal: &DomainGoal<I>,
outer_binder: DebruijnIndex,
) -> Self::Result {
domain_goal.super_visit_with(self.as_dyn(), outer_binder)
}
fn forbid_free_vars(&self) -> bool {
false
}
fn visit_free_var_ty(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_free_vars() {
panic!(
"unexpected free variable `{:?}` with outer binder {:?}",
bound_var, outer_binder
)
} else {
Self::Result::new()
}
}
fn visit_bound_var_ty(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
) -> Self::Result {
Self::Result::new()
}
fn visit_free_var_lifetime(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_free_vars() {
panic!(
"unexpected free variable `{:?}` with outer binder {:?}",
bound_var, outer_binder
)
} else {
Self::Result::new()
}
}
fn visit_bound_var_lifetime(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
) -> Self::Result {
Self::Result::new()
}
fn forbid_free_placeholders(&self) -> bool {
false
}
fn visit_free_placeholder_ty(
&mut self,
universe: PlaceholderIndex,
_outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_free_placeholders() {
panic!("unexpected placeholder type `{:?}`", universe)
} else {
Self::Result::new()
}
}
fn visit_where_clause(
&mut self,
where_clause: &WhereClause<I>,
outer_binder: DebruijnIndex,
) -> Self::Result {
where_clause.super_visit_with(self.as_dyn(), outer_binder)
}
fn visit_free_placeholder_lifetime(
&mut self,
universe: PlaceholderIndex,
_outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_free_placeholders() {
panic!("unexpected placeholder lifetime `{:?}`", universe)
} else {
Self::Result::new()
}
}
fn forbid_inference_vars(&self) -> bool {
false
}
fn visit_inference_ty(
&mut self,
var: InferenceVar,
_outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_inference_vars() {
panic!("unexpected inference type `{:?}`", var)
} else {
Self::Result::new()
}
}
fn visit_inference_lifetime(
&mut self,
var: InferenceVar,
_outer_binder: DebruijnIndex,
) -> Self::Result {
if self.forbid_inference_vars() {
panic!("unexpected inference lifetime `'{:?}`", var)
} else {
Self::Result::new()
}
}
fn interner(&self) -> &'i I;
}
pub trait Visit<I: Interner>: Debug {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i;
}
pub trait SuperVisit<I: Interner>: Visit<I> {
fn super_visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i;
}
impl<I: Interner> Visit<I> for Ty<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_ty(self, outer_binder)
}
}
impl<I> SuperVisit<I> for Ty<I>
where
I: Interner,
{
fn super_visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
let interner = visitor.interner();
match self.data(interner) {
TyData::BoundVar(bound_var) => {
if let Some(_) = bound_var.shifted_out_to(outer_binder) {
visitor.visit_free_var_lifetime(*bound_var, outer_binder)
} else {
visitor.visit_bound_var_lifetime(*bound_var, outer_binder)
}
}
TyData::Dyn(clauses) => clauses.visit_with(visitor, outer_binder),
TyData::InferenceVar(var) => visitor.visit_inference_ty(*var, outer_binder),
TyData::Apply(apply) => apply.visit_with(visitor, outer_binder),
TyData::Placeholder(ui) => visitor.visit_free_placeholder_ty(*ui, outer_binder),
TyData::Alias(proj) => proj.visit_with(visitor, outer_binder),
TyData::Function(fun) => fun.visit_with(visitor, outer_binder),
}
}
}
impl<I: Interner> Visit<I> for Lifetime<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_lifetime(self, outer_binder)
}
}
impl<I: Interner> SuperVisit<I> for Lifetime<I> {
fn super_visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
let interner = visitor.interner();
match self.data(interner) {
LifetimeData::BoundVar(bound_var) => {
if let Some(_) = bound_var.shifted_out_to(outer_binder) {
visitor.visit_free_var_lifetime(*bound_var, outer_binder)
} else {
visitor.visit_bound_var_lifetime(*bound_var, outer_binder)
}
}
LifetimeData::InferenceVar(var) => visitor.visit_inference_lifetime(*var, outer_binder),
LifetimeData::Placeholder(universe) => {
visitor.visit_free_placeholder_lifetime(*universe, outer_binder)
}
LifetimeData::Phantom(..) => unreachable!(),
}
}
}
impl<I: Interner> Visit<I> for Goal<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_goal(self, outer_binder)
}
}
impl<I: Interner> SuperVisit<I> for Goal<I> {
fn super_visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
let interner = visitor.interner();
self.data(interner).visit_with(visitor, outer_binder)
}
}
impl<I: Interner> Visit<I> for ProgramClause<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_program_clause(self, outer_binder)
}
}
impl<I: Interner> Visit<I> for WhereClause<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_where_clause(self, outer_binder)
}
}
impl<I: Interner> Visit<I> for DomainGoal<I> {
fn visit_with<'i, R: VisitResult>(
&self,
visitor: &mut dyn Visitor<'i, I, Result = R>,
outer_binder: DebruijnIndex,
) -> R
where
I: 'i,
{
visitor.visit_domain_goal(self, outer_binder)
}
}