use logicaffeine_kernel::prelude::StandardLibrary;
use logicaffeine_kernel::{
double_check, infer_type, is_subtype, normalize, Context, DoubleCheck, Term, Universe,
};
fn g(n: &str) -> Term {
Term::Global(n.to_string())
}
fn v(n: &str) -> Term {
Term::Var(n.to_string())
}
fn app(f: Term, x: Term) -> Term {
Term::App(Box::new(f), Box::new(x))
}
fn lam(p: &str, ty: Term, body: Term) -> Term {
Term::Lambda { param: p.to_string(), param_type: Box::new(ty), body: Box::new(body) }
}
fn pi(p: &str, ty: Term, body: Term) -> Term {
Term::Pi { param: p.to_string(), param_type: Box::new(ty), body_type: Box::new(body) }
}
fn std_ctx() -> Context {
let mut ctx = Context::new();
StandardLibrary::register(&mut ctx);
ctx
}
#[test]
fn eta_function_conversion_both_directions() {
let ctx = std_ctx();
let succ = g("Succ");
let eta = lam("x", g("Nat"), app(g("Succ"), v("x")));
assert!(is_subtype(&ctx, &succ, &eta), "Succ ≡ λx. Succ x (η)");
assert!(is_subtype(&ctx, &eta, &succ), "λx. Succ x ≡ Succ (η, other direction)");
}
#[test]
fn eta_is_two_kernel_verified() {
let ctx = std_ctx();
let nat2nat = pi("_", g("Nat"), g("Nat"));
let succ = g("Succ");
let eta = lam("x", g("Nat"), app(g("Succ"), v("x")));
let refl_succ = app(app(g("refl"), nat2nat.clone()), succ.clone());
let term = app(
app(app(app(g("Eq_sym"), nat2nat), succ), eta),
refl_succ,
);
assert!(infer_type(&ctx, &term).is_ok(), "η lets the refl witness check: {:?}", infer_type(&ctx, &term));
assert_eq!(double_check(&ctx, &term), DoubleCheck::Agreed, "η must be two-kernel verified");
}
#[test]
fn proof_irrelevance_collapses_proofs_of_a_prop() {
let mut ctx = std_ctx();
ctx.add("P", Term::Sort(Universe::Prop));
ctx.add("a", v("P"));
ctx.add("b", v("P"));
assert!(is_subtype(&ctx, &v("a"), &v("b")), "any two proofs of a Prop are definitionally equal");
}
#[test]
fn proof_irrelevance_does_not_collapse_type_values() {
let mut ctx = std_ctx();
ctx.add("T", Term::Sort(Universe::Type(0)));
ctx.add("x", v("T"));
ctx.add("y", v("T"));
assert!(!is_subtype(&ctx, &v("x"), &v("y")), "distinct Type-level values must stay distinct");
let zero = g("Zero");
let one = app(g("Succ"), g("Zero"));
assert!(!is_subtype(&ctx, &zero, &one), "0 ≢ 1");
}
#[test]
fn proof_irrelevance_is_two_kernel_verified() {
let ctx = std_ctx();
let or_tt = app(app(g("Or"), g("True")), g("True"));
let l = app(app(app(g("left"), g("True")), g("True")), g("I"));
let r = app(app(app(g("right"), g("True")), g("True")), g("I"));
let refl_l = app(app(g("refl"), or_tt.clone()), l.clone());
let term = app(app(app(app(g("Eq_sym"), or_tt), l), r), refl_l);
assert!(
infer_type(&ctx, &term).is_ok(),
"proof irrelevance lets the refl witness check: {:?}",
infer_type(&ctx, &term)
);
assert_eq!(double_check(&ctx, &term), DoubleCheck::Agreed, "proof irrelevance must be two-kernel verified");
assert!(is_subtype(&ctx, &normalize(&ctx, &term), &normalize(&ctx, &term)));
}