use voile_util::meta::MI;
use crate::{
check::{
monad::{MetaSol, TCE, TCMS, TCS},
rules::term::simplify,
},
syntax::{
common::Bind,
core::{Closure, Elim, Term, Val, ValData},
},
};
pub trait HasMeta: Sized {
fn inline_meta(self, tcs: TCS) -> TCMS<Self>;
}
impl<T: HasMeta> HasMeta for Vec<T> {
fn inline_meta(self, mut tcs: TCS) -> TCMS<Self> {
let mut r = Vec::with_capacity(self.len());
for t in self {
let (t, new_tcs) = t.inline_meta(tcs)?;
tcs = new_tcs;
r.push(t);
}
Ok((r, tcs))
}
}
impl HasMeta for ValData {
fn inline_meta(self, tcs: TCS) -> TCMS<Self> {
let (args, tcs) = self.args.inline_meta(tcs)?;
Ok((ValData::new(self.kind, self.def, args), tcs))
}
}
impl HasMeta for Elim {
fn inline_meta(self, tcs: TCS) -> TCMS<Self> {
match self {
Elim::App(a) => a.inline_meta(tcs).map(|(a, tcs)| (Elim::app(a), tcs)),
Elim::Proj(p) => Ok((Elim::Proj(p), tcs)),
}
}
}
impl HasMeta for Term {
fn inline_meta(self, tcs: TCS) -> TCMS<Self> {
match self {
Term::Whnf(Val::Meta(mi, elims)) => solve_meta(tcs, mi, elims),
Term::Whnf(w) => w.inline_meta(tcs).map(|(w, tcs)| (Term::Whnf(w), tcs)),
Term::Redex(gi, id, elims) => {
let (elims, tcs) = elims.inline_meta(tcs)?;
Ok((Term::Redex(gi, id, elims), tcs))
}
}
}
}
impl<T: HasMeta> HasMeta for Bind<T> {
fn inline_meta(self, tcs: TCS) -> TCMS<Self> {
let (ty, tcs) = self.ty.inline_meta(tcs)?;
Ok((Bind::new(self.licit, self.name, ty), tcs))
}
}
impl HasMeta for Closure {
fn inline_meta(self, mut tcs: TCS) -> TCMS<Self> {
tcs.unify_depth += 1;
let (closure, mut tcs) = match self {
Closure::Plain(body) => {
let (body, tcs) = body.inline_meta(tcs)?;
(Closure::plain(body), tcs)
}
};
tcs.unify_depth -= 1;
Ok((closure, tcs))
}
}
fn solve_meta(tcs: TCS, mi: MI, elims: Vec<Elim>) -> TCMS<Term> {
use MetaSol::*;
let (_ix, sol) = match tcs.meta_ctx().solution(mi) {
Solved(ix, sol) => (*ix, sol.clone()),
Unsolved => return Err(TCE::MetaUnsolved(mi)),
};
let (elims, tcs) = elims.inline_meta(tcs)?;
Ok((sol.apply_elim(elims), tcs))
}
impl HasMeta for Val {
fn inline_meta(self, tcs: TCS) -> TCMS<Self> {
use Val::*;
match self {
Type(l) => Ok((Type(l), tcs)),
Data(info) => info.inline_meta(tcs).map(|(i, tcs)| (Data(i), tcs)),
Pi(t, clos) => {
let (t, tcs) = t.unboxed().inline_meta(tcs)?;
let (clos, tcs) = clos.inline_meta(tcs)?;
Ok((Val::Pi(t.boxed(), clos), tcs))
}
Cons(c, ts) => ts.inline_meta(tcs).map(|(ts, tcs)| (Cons(c, ts), tcs)),
Meta(mi, elims) => {
let (sol, tcs) = solve_meta(tcs, mi, elims)?;
simplify(tcs, sol)
}
Axiom(a) => Ok((Axiom(a), tcs)),
Var(head, args) => args.inline_meta(tcs).map(|(a, tcs)| (Var(head, a), tcs)),
Id(t, a, b) => {
let (t, tcs) = t.inline_meta(tcs)?;
let (a, tcs) = a.inline_meta(tcs)?;
let (b, tcs) = b.inline_meta(tcs)?;
Ok((Val::identity(t, a, b), tcs))
}
Refl => Ok((Refl, tcs)),
}
}
}