summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall/src/binary.rs9
-rw-r--r--dhall/src/main.rs7
-rw-r--r--dhall/src/normalize.rs408
-rw-r--r--dhall/src/typecheck.rs548
-rw-r--r--dhall/tests/common/mod.rs18
-rw-r--r--dhall_core/src/core.rs284
-rw-r--r--dhall_generator/src/lib.rs4
7 files changed, 695 insertions, 583 deletions
diff --git a/dhall/src/binary.rs b/dhall/src/binary.rs
index 08bdba4..2279a51 100644
--- a/dhall/src/binary.rs
+++ b/dhall/src/binary.rs
@@ -1,7 +1,7 @@
use dhall_core::*;
use itertools::*;
-use std::rc::Rc;
use serde_cbor::value::value as cbor;
+use std::rc::Rc;
type ParsedExpr = Rc<Expr<X, Import>>;
@@ -22,7 +22,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
use cbor::Value::*;
use dhall_core::{BinOp, Builtin, Const};
use Expr::*;
- let e = match data {
+ Ok(rc(match data {
String(s) => match Builtin::parse(s) {
Some(b) => Expr::Builtin(b),
None => match s.as_str() {
@@ -198,7 +198,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
let expr = cbor_value_to_dhall(expr)?;
return Ok(bindings
.into_iter()
- .fold(expr, |acc, (x, t, v)| bx(Let(x, t, v, acc))));
+ .fold(expr, |acc, (x, t, v)| rc(Let(x, t, v, acc))));
}
[U64(26), x, y] => {
let x = cbor_value_to_dhall(&x)?;
@@ -208,8 +208,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
_ => Err(DecodeError::WrongFormatError)?,
},
_ => Err(DecodeError::WrongFormatError)?,
- };
- Ok(bx(e))
+ }))
}
fn cbor_map_to_dhall_map(
diff --git a/dhall/src/main.rs b/dhall/src/main.rs
index 3328d99..41953e3 100644
--- a/dhall/src/main.rs
+++ b/dhall/src/main.rs
@@ -1,5 +1,6 @@
use std::error::Error;
use std::io::{self, Read};
+use std::rc::Rc;
use term_painter::ToStyle;
use dhall::*;
@@ -65,9 +66,9 @@ fn main() {
}
};
- let expr: Expr<_, _> = imports::panic_imports(&expr);
+ let expr: Rc<Expr<_, _>> = rc(imports::panic_imports(&expr));
- let type_expr = match typecheck::type_of(&expr) {
+ let type_expr = match typecheck::type_of(expr.clone()) {
Err(e) => {
let explain = ::std::env::args().any(|s| s == "--explain");
if !explain {
@@ -89,5 +90,5 @@ fn main() {
println!("{}", type_expr);
println!();
- println!("{}", normalize::<_, X, _>(&expr));
+ println!("{}", normalize::<_, X, _>(expr));
}
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs
index 40112f1..fccc938 100644
--- a/dhall/src/normalize.rs
+++ b/dhall/src/normalize.rs
@@ -9,7 +9,7 @@ use std::rc::Rc;
/// Is identical to normalize on primitive types, but not on more complex
/// types like functions and records.
/// This allows normalization to be lazy.
-pub fn normalize_whnf<S, A>(e: &Expr<S, A>) -> Expr<S, A>
+pub fn normalize_whnf<S, A>(e: &SubExpr<S, A>) -> SubExpr<S, A>
where
S: Clone + fmt::Debug,
A: Clone + fmt::Debug,
@@ -17,158 +17,204 @@ where
use dhall_core::BinOp::*;
use dhall_core::Builtin::*;
use dhall_core::Expr::*;
- match e {
+ rc(match e.as_ref() {
Let(f, _, r, b) => {
let vf0 = &V(f.clone(), 0);
let r2 = shift::<_, S, _>(1, vf0, r);
let b2 = subst::<_, S, _>(vf0, &r2, b);
let b3 = shift::<_, S, _>(-1, vf0, &b2);
- normalize_whnf(&b3)
+ return normalize_whnf(&b3);
}
- Annot(x, _) => normalize_whnf(x),
- Note(_, e) => normalize_whnf(e),
- App(f, args) => match (normalize_whnf(f), args.as_slice()) {
- (f, []) => f,
- (App(f, args1), args2) => normalize_whnf(&App(
- f.clone(),
- args1.iter().chain(args2.iter()).cloned().collect(),
- )),
- (Lam(ref x, _, ref b), [a, rest..]) => {
- // Beta reduce
- let vx0 = &V(x.clone(), 0);
- let a2 = shift::<S, S, A>(1, vx0, a);
- let b2 = subst::<S, S, A>(vx0, &a2, &b);
- let b3 = shift::<S, S, A>(-1, vx0, &b2);
- normalize_whnf(&App(bx(b3), rest.to_vec()))
- }
- // TODO: this is more normalization than needed
- (Builtin(b), args) => match (
- b,
- args.iter()
- .map(|x| normalize_whnf(&*x))
- .collect::<Vec<Expr<_, _>>>()
- .as_slice(),
- ) {
- (OptionalSome, [a]) => OptionalLit(None, Some(bx(a.clone()))),
- (OptionalNone, [a]) => OptionalLit(Some(bx(a.clone())), None),
- (NaturalIsZero, [NaturalLit(n)]) => BoolLit(*n == 0),
- (NaturalEven, [NaturalLit(n)]) => BoolLit(*n % 2 == 0),
- (NaturalOdd, [NaturalLit(n)]) => BoolLit(*n % 2 != 0),
- (NaturalToInteger, [NaturalLit(n)]) => IntegerLit(*n as isize),
- (NaturalShow, [NaturalLit(n)]) => TextLit(n.to_string().into()),
- (ListLength, [_, ListLit(_, ys)]) => NaturalLit(ys.len()),
- (ListHead, [_, ListLit(t, ys)]) => {
- OptionalLit(t.clone(), ys.iter().cloned().next())
- }
- (ListLast, [_, ListLit(t, ys)]) => {
- OptionalLit(t.clone(), ys.iter().cloned().last())
- }
- (ListReverse, [_, ListLit(t, ys)]) => {
- let xs = ys.iter().rev().cloned().collect();
- ListLit(t.clone(), xs)
+ Annot(x, _) => return normalize_whnf(x),
+ Note(_, e) => return normalize_whnf(e),
+ App(f, args) => {
+ let f = normalize_whnf(f);
+ match (f.as_ref(), args.as_slice()) {
+ (_, []) => return f,
+ (App(f, args1), args2) => {
+ return normalize_whnf(&rc(App(
+ f.clone(),
+ args1.iter().chain(args2.iter()).cloned().collect(),
+ )))
}
- (ListBuild, [a0, g]) => {
- // fold/build fusion
- let g = match g {
- App(f, args) => match (&**f, args.as_slice()) {
- (Builtin(ListFold), [_, x, rest..]) => {
- return normalize_whnf(&App(
- x.clone(),
- rest.to_vec(),
- ))
- }
- (_, args) => App(f.clone(), args.to_vec()),
- },
- g => g.clone(),
- };
- let g = bx(g);
- let a0 = bx(a0.clone());
- let a1 = bx(shift(1, &V("a".into(), 0), &a0));
- normalize_whnf(
- &dhall_expr!(g (List a0) (λ(a : a0) -> λ(as : List a1) -> [ a ] # as) ([] : List a0)),
- )
+ (Lam(ref x, _, ref b), [a, rest..]) => {
+ // Beta reduce
+ let vx0 = &V(x.clone(), 0);
+ let a2 = shift::<S, S, A>(1, vx0, a);
+ let b2 = subst::<S, S, A>(vx0, &a2, &b);
+ let b3 = shift::<S, S, A>(-1, vx0, &b2);
+ return normalize_whnf(&rc(App(b3, rest.to_vec())));
}
- (OptionalBuild, [a0, g]) => {
- // fold/build fusion
- let g = match g {
- App(f, args) => match (&**f, args.as_slice()) {
- (Builtin(OptionalFold), [_, x, rest..]) => {
- return normalize_whnf(&App(
- x.clone(),
- rest.to_vec(),
- ))
+ // TODO: this is more normalization than needed
+ (Builtin(b), args) => {
+ let args = args
+ .iter()
+ .map(|x| normalize_whnf(x))
+ .collect::<Vec<Rc<Expr<_, _>>>>();
+
+ match (
+ b,
+ args.iter()
+ .map(Rc::as_ref)
+ .collect::<Vec<_>>()
+ .as_slice(),
+ ) {
+ (OptionalSome, [_]) => {
+ OptionalLit(None, Some(Rc::clone(&args[0])))
+ }
+ (OptionalNone, [_]) => {
+ OptionalLit(Some(Rc::clone(&args[0])), None)
+ }
+ (NaturalIsZero, [NaturalLit(n)]) => BoolLit(*n == 0),
+ (NaturalEven, [NaturalLit(n)]) => BoolLit(*n % 2 == 0),
+ (NaturalOdd, [NaturalLit(n)]) => BoolLit(*n % 2 != 0),
+ (NaturalToInteger, [NaturalLit(n)]) => {
+ IntegerLit(*n as isize)
+ }
+ (NaturalShow, [NaturalLit(n)]) => {
+ TextLit(n.to_string().into())
+ }
+ (ListLength, [_, ListLit(_, ys)]) => {
+ NaturalLit(ys.len())
+ }
+ (ListHead, [_, ListLit(t, ys)]) => {
+ OptionalLit(t.clone(), ys.iter().cloned().next())
+ }
+ (ListLast, [_, ListLit(t, ys)]) => {
+ OptionalLit(t.clone(), ys.iter().cloned().last())
+ }
+ (ListReverse, [_, ListLit(t, ys)]) => {
+ let xs = ys.iter().rev().cloned().collect();
+ ListLit(t.clone(), xs)
+ }
+ (ListBuild, [_, _]) => {
+ // fold/build fusion
+ let g = Rc::clone(&args[1]);
+ let g = match g.as_ref() {
+ App(f, args) => {
+ match (f.as_ref(), args.as_slice()) {
+ (Builtin(ListFold), [_, x, rest..]) => {
+ return normalize_whnf(&rc(App(
+ x.clone(),
+ rest.to_vec(),
+ )))
+ }
+ (_, args) => {
+ rc(App(f.clone(), args.to_vec()))
+ }
+ }
+ }
+ _ => g,
+ };
+ let a0 = Rc::clone(&args[0]);
+ let a1 = shift(1, &V("a".into(), 0), &a0);
+ return normalize_whnf(
+ &dhall_expr!(g (List a0) (λ(a : a0) -> λ(as : List a1) -> [ a ] # as) ([] : List a0)),
+ );
+ }
+ (OptionalBuild, [_, _]) => {
+ // fold/build fusion
+ let g = Rc::clone(&args[1]);
+ let g = match g.as_ref() {
+ App(f, args) => {
+ match (f.as_ref(), args.as_slice()) {
+ (
+ Builtin(OptionalFold),
+ [_, x, rest..],
+ ) => {
+ return normalize_whnf(&rc(App(
+ x.clone(),
+ rest.to_vec(),
+ )))
+ }
+ (_, args) => {
+ rc(App(f.clone(), args.to_vec()))
+ }
+ }
+ }
+ _ => g,
+ };
+ let a0 = Rc::clone(&args[0]);
+ return normalize_whnf(
+ &dhall_expr!((g (Optional a0)) (λ(x: a0) -> [x] : Optional a0) ([] : Optional a0)),
+ );
+ }
+ (ListFold, [_, ListLit(_, xs), _, _, _]) => {
+ let e2: Rc<Expr<_, _>> = xs.iter().rev().fold(
+ Rc::clone(&args[4]),
+ |acc, x| {
+ let x = x.clone();
+ let acc = acc.clone();
+ let cons = Rc::clone(&args[3]);
+ dhall_expr!(cons x acc)
+ },
+ );
+ return normalize_whnf(&e2);
+ }
+ // // fold/build fusion
+ // (ListFold, [_, App(box Builtin(ListBuild), [_, x, rest..]), rest..]) => {
+ // normalize_whnf(&App(bx(x.clone()), rest.to_vec()))
+ // }
+ (
+ OptionalFold,
+ [_, OptionalLit(_, Some(x)), _, _, _],
+ ) => {
+ let x = x.clone();
+ let just = Rc::clone(&args[3]);
+ return normalize_whnf(&dhall_expr!(just x));
+ }
+ (
+ OptionalFold,
+ [_, OptionalLit(_, None), _, _, nothing],
+ ) => (*nothing).clone(),
+ // // fold/build fusion
+ // (OptionalFold, [_, App(box Builtin(OptionalBuild), [_, x, rest..]), rest..]) => {
+ // normalize_whnf(&App(bx(x.clone()), rest.to_vec()))
+ // }
+ (NaturalBuild, [App(f, args)]) => {
+ match (f.as_ref(), args.as_slice()) {
+ // fold/build fusion
+ (Builtin(NaturalFold), [x, rest..]) => {
+ return normalize_whnf(&rc(App(
+ x.clone(),
+ rest.to_vec(),
+ )))
+ }
+ (_, args) => app(
+ Builtin(NaturalBuild),
+ vec![bx(App(f.clone(), args.to_vec()))],
+ ),
}
- (_, args) => App(f.clone(), args.to_vec()),
- },
- g => g.clone(),
- };
- let g = bx(g);
- let a0 = bx(a0.clone());
- normalize_whnf(
- &dhall_expr!((g (Optional a0)) (λ(x: a0) -> [x] : Optional a0) ([] : Optional a0)),
- )
- }
- (ListFold, [_, ListLit(_, xs), _, cons, nil]) => {
- let e2: Expr<_, _> =
- xs.iter().rev().fold((*nil).clone(), |acc, x| {
- let x = (x).clone();
- let acc = bx((acc).clone());
- let cons = bx((cons).clone());
- dhall_expr!(cons x acc)
- });
- normalize_whnf(&e2)
- }
- // // fold/build fusion
- // (ListFold, [_, App(box Builtin(ListBuild), [_, x, rest..]), rest..]) => {
- // normalize_whnf(&App(bx(x.clone()), rest.to_vec()))
- // }
- (OptionalFold, [_, OptionalLit(_, Some(x)), _, just, _]) => {
- let x = x.clone();
- let just = bx(just.clone());
- normalize_whnf(&dhall_expr!(just x))
- }
- (OptionalFold, [_, OptionalLit(_, None), _, _, nothing]) => {
- (*nothing).clone()
- }
- // // fold/build fusion
- // (OptionalFold, [_, App(box Builtin(OptionalBuild), [_, x, rest..]), rest..]) => {
- // normalize_whnf(&App(bx(x.clone()), rest.to_vec()))
- // }
- (NaturalBuild, [App(f, args)]) => {
- match (&**f, args.as_slice()) {
- // fold/build fusion
- (Builtin(NaturalFold), [x, rest..]) => {
- normalize_whnf(&App(x.clone(), rest.to_vec()))
}
- (_, args) => app(
- Builtin(NaturalBuild),
- vec![bx(App(f.clone(), args.to_vec()))],
- ),
- }
- }
- (NaturalFold, [App(f, args)]) => {
- match (&**f, args.as_slice()) {
- // fold/build fusion
- (Builtin(NaturalBuild), [x, rest..]) => {
- normalize_whnf(&App(x.clone(), rest.to_vec()))
+ (NaturalFold, [App(f, args)]) => {
+ match (f.as_ref(), args.as_slice()) {
+ // fold/build fusion
+ (Builtin(NaturalBuild), [x, rest..]) => {
+ return normalize_whnf(&rc(App(
+ x.clone(),
+ rest.to_vec(),
+ )))
+ }
+ (_, args) => app(
+ Builtin(NaturalFold),
+ vec![bx(App(f.clone(), args.to_vec()))],
+ ),
+ }
}
- (_, args) => app(
- Builtin(NaturalFold),
- vec![bx(App(f.clone(), args.to_vec()))],
- ),
+ (b, _) => App(rc(Builtin(*b)), args),
}
}
- (b, args) => {
- App(bx(Builtin(b)), args.iter().cloned().map(bx).collect())
- }
- },
- (f, args) => App(bx(f), args.to_vec()),
- },
- BoolIf(b, t, f) => match normalize_whnf(b) {
- BoolLit(true) => normalize_whnf(t),
- BoolLit(false) => normalize_whnf(f),
- b2 => BoolIf(bx(b2), t.clone(), f.clone()),
- },
+ (_, args) => App(f, args.to_vec()),
+ }
+ }
+ BoolIf(b, t, f) => {
+ let b = normalize_whnf(b);
+ match b.as_ref() {
+ BoolLit(true) => return normalize_whnf(t),
+ BoolLit(false) => return normalize_whnf(f),
+ _ => BoolIf(b, t.clone(), f.clone()),
+ }
+ }
OptionalLit(t, es) => {
if !es.is_none() {
OptionalLit(None, es.clone())
@@ -176,36 +222,52 @@ where
OptionalLit(t.clone(), es.clone())
}
}
- BinOp(o, x, y) => match (o, normalize_whnf(&x), normalize_whnf(&y)) {
- (BoolAnd, BoolLit(x), BoolLit(y)) => BoolLit(x && y),
- (BoolOr, BoolLit(x), BoolLit(y)) => BoolLit(x || y),
- (BoolEQ, BoolLit(x), BoolLit(y)) => BoolLit(x == y),
- (BoolNE, BoolLit(x), BoolLit(y)) => BoolLit(x != y),
- (NaturalPlus, NaturalLit(x), NaturalLit(y)) => NaturalLit(x + y),
- (NaturalTimes, NaturalLit(x), NaturalLit(y)) => NaturalLit(x * y),
- (TextAppend, TextLit(x), TextLit(y)) => TextLit(x + y),
- (ListAppend, ListLit(t1, xs), ListLit(t2, ys)) => {
- // Drop type annotation if the result is nonempty
- let t = if xs.is_empty() && ys.is_empty() {
- t1.or(t2)
- } else {
- None
- };
- let xs = xs.into_iter();
- let ys = ys.into_iter();
- ListLit(t, xs.chain(ys).collect())
+ BinOp(o, x, y) => {
+ let x = normalize_whnf(x);
+ let y = normalize_whnf(y);
+ match (o, x.as_ref(), y.as_ref()) {
+ (BoolAnd, BoolLit(x), BoolLit(y)) => BoolLit(*x && *y),
+ (BoolOr, BoolLit(x), BoolLit(y)) => BoolLit(*x || *y),
+ (BoolEQ, BoolLit(x), BoolLit(y)) => BoolLit(x == y),
+ (BoolNE, BoolLit(x), BoolLit(y)) => BoolLit(x != y),
+ (NaturalPlus, NaturalLit(x), NaturalLit(y)) => {
+ NaturalLit(x + y)
+ }
+ (NaturalTimes, NaturalLit(x), NaturalLit(y)) => {
+ NaturalLit(x * y)
+ }
+ // TODO: interpolation
+ (TextAppend, TextLit(x), TextLit(y)) => {
+ TextLit(x.clone() + y.clone())
+ }
+ (ListAppend, ListLit(t1, xs), ListLit(t2, ys)) => {
+ let t1: Option<Rc<_>> = t1.as_ref().map(Rc::clone);
+ let t2: Option<Rc<_>> = t2.as_ref().map(Rc::clone);
+ // Drop type annotation if the result is nonempty
+ let t = if xs.is_empty() && ys.is_empty() {
+ t1.or(t2)
+ } else {
+ None
+ };
+ let xs = xs.into_iter().cloned();
+ let ys = ys.into_iter().cloned();
+ ListLit(t, xs.chain(ys).collect())
+ }
+ (o, _, _) => BinOp(*o, x, y),
+ }
+ }
+ Field(e, x) => {
+ let e = normalize_whnf(e);
+ match (e.as_ref(), x) {
+ (RecordLit(kvs), x) => match kvs.get(&x) {
+ Some(r) => return normalize_whnf(r),
+ None => Field(e, x.clone()),
+ },
+ (_, x) => Field(e, x.clone()),
}
- (o, x, y) => BinOp(*o, bx(x), bx(y)),
- },
- Field(e, x) => match (normalize_whnf(&e), x) {
- (RecordLit(kvs), x) => match kvs.get(&x) {
- Some(r) => normalize_whnf(r),
- None => Field(bx(RecordLit(kvs)), x.clone()),
- },
- (e, x) => Field(bx(e), x.clone()),
- },
- e => e.clone(),
- }
+ }
+ _ => return Rc::clone(e),
+ })
}
/// Reduce an expression to its normal form, performing beta reduction
@@ -217,16 +279,16 @@ where
/// However, `normalize` will not fail if the expression is ill-typed and will
/// leave ill-typed sub-expressions unevaluated.
///
-pub fn normalize<S, T, A>(e: &Expr<S, A>) -> Expr<T, A>
+pub fn normalize<S, T, A>(e: SubExpr<S, A>) -> SubExpr<T, A>
where
S: Clone + fmt::Debug,
T: Clone + fmt::Debug,
A: Clone + fmt::Debug,
{
- normalize_whnf(e).map_shallow(
- normalize,
+ rc(normalize_whnf(&e).map_shallow_rc(
+ |x| normalize(Rc::clone(x)),
|_| unreachable!(),
|x| x.clone(),
|x| x.clone(),
- )
+ ))
}
diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs
index f5670f7..d6195a5 100644
--- a/dhall/src/typecheck.rs
+++ b/dhall/src/typecheck.rs
@@ -4,13 +4,13 @@ use std::collections::HashSet;
use std::fmt;
use std::rc::Rc;
-use crate::normalize;
+use crate::normalize::normalize;
use dhall_core::context::Context;
use dhall_core::core;
use dhall_core::core::Builtin::*;
use dhall_core::core::Const::*;
use dhall_core::core::Expr::*;
-use dhall_core::core::{bx, shift, subst, Expr, Label, V, X};
+use dhall_core::core::{bx, rc, shift, subst, Expr, Label, V, X};
use dhall_generator::dhall_expr;
use self::TypeMessage::*;
@@ -18,11 +18,11 @@ use self::TypeMessage::*;
fn axiom<S: Clone>(c: core::Const) -> Result<core::Const, TypeError<S>> {
match c {
Type => Ok(Kind),
- Kind => Err(TypeError::new(&Context::new(), &Const(Kind), Untyped)),
+ Kind => Err(TypeError::new(&Context::new(), rc(Const(Kind)), Untyped)),
}
}
-fn rule(a: core::Const, b: core::Const) -> Result<core::Const, ()> {
+fn rule(a: &core::Const, b: &core::Const) -> Result<core::Const, ()> {
match (a, b) {
(Type, Kind) => Err(()),
(Kind, Kind) => Ok(Kind),
@@ -47,30 +47,30 @@ fn match_vars(vl: &V, vr: &V, ctx: &[(Label, Label)]) -> bool {
}
}
-fn prop_equal<S, T>(eL0: &Expr<S, X>, eR0: &Expr<T, X>) -> bool
+fn prop_equal<S, T>(eL0: Rc<Expr<S, X>>, eR0: Rc<Expr<T, X>>) -> bool
where
S: Clone + ::std::fmt::Debug,
T: Clone + ::std::fmt::Debug,
{
fn go<S, T>(
ctx: &mut Vec<(Label, Label)>,
- el: &Expr<S, X>,
- er: &Expr<T, X>,
+ el: Rc<Expr<S, X>>,
+ er: Rc<Expr<T, X>>,
) -> bool
where
S: Clone + ::std::fmt::Debug,
T: Clone + ::std::fmt::Debug,
{
- match (el, er) {
+ match (el.as_ref(), er.as_ref()) {
(&Const(Type), &Const(Type)) | (&Const(Kind), &Const(Kind)) => true,
- (&Var(ref vL), &Var(ref vR)) => match_vars(vL, vR, &*ctx),
+ (&Var(ref vL), &Var(ref vR)) => match_vars(vL, vR, ctx),
(&Pi(ref xL, ref tL, ref bL), &Pi(ref xR, ref tR, ref bR)) => {
//ctx <- State.get
- let eq1 = go(ctx, tL, tR);
+ let eq1 = go(ctx, Rc::clone(tL), Rc::clone(tR));
if eq1 {
//State.put ((xL, xR):ctx)
ctx.push((xL.clone(), xR.clone()));
- let eq2 = go(ctx, bL, bR);
+ let eq2 = go(ctx, Rc::clone(bL), Rc::clone(bR));
//State.put ctx
let _ = ctx.pop();
eq2
@@ -79,8 +79,10 @@ where
}
}
(&App(ref fL, ref aL), &App(ref fR, ref aR)) => {
- if go(ctx, fL, fR) {
- aL.iter().zip(aR.iter()).all(|(aL, aR)| go(ctx, aL, aR))
+ if go(ctx, Rc::clone(fL), Rc::clone(fR)) {
+ aL.iter()
+ .zip(aR.iter())
+ .all(|(aL, aR)| go(ctx, Rc::clone(aL), Rc::clone(aR)))
} else {
false
}
@@ -112,10 +114,9 @@ where
}
true
*/
- !ktsL0
- .iter()
- .zip(ktsR0.iter())
- .any(|((kL, tL), (kR, tR))| kL != kR || !go(ctx, tL, tR))
+ !ktsL0.iter().zip(ktsR0.iter()).any(|((kL, tL), (kR, tR))| {
+ kL != kR || !go(ctx, Rc::clone(tL), Rc::clone(tR))
+ })
}
(&Union(ref ktsL0), &Union(ref ktsR0)) => {
if ktsL0.len() != ktsR0.len() {
@@ -132,40 +133,39 @@ where
loop _ _ = return False
loop (Data.Map.toList ktsL0) (Data.Map.toList ktsR0)
*/
- !ktsL0
- .iter()
- .zip(ktsR0.iter())
- .any(|((kL, tL), (kR, tR))| kL != kR || !go(ctx, tL, tR))
+ !ktsL0.iter().zip(ktsR0.iter()).any(|((kL, tL), (kR, tR))| {
+ kL != kR || !go(ctx, Rc::clone(tL), Rc::clone(tR))
+ })
}
(_, _) => false,
}
}
let mut ctx = vec![];
- go::<S, T>(&mut ctx, &normalize(eL0), &normalize(eR0))
+ go::<S, T>(&mut ctx, normalize(eL0), normalize(eR0))
}
fn op2_type<S, EF>(
- ctx: &Context<Label, Expr<S, X>>,
- e: &Expr<S, X>,
+ ctx: &Context<Label, Rc<Expr<S, X>>>,
+ e: Rc<Expr<S, X>>,
t: core::Builtin,
ef: EF,
- l: &Expr<S, X>,
- r: &Expr<S, X>,
+ l: &Rc<Expr<S, X>>,
+ r: &Rc<Expr<S, X>>,
) -> Result<Expr<S, X>, TypeError<S>>
where
S: Clone + ::std::fmt::Debug,
- EF: FnOnce(Expr<S, X>, Expr<S, X>) -> TypeMessage<S>,
+ EF: FnOnce(Rc<Expr<S, X>>, Rc<Expr<S, X>>) -> TypeMessage<S>,
{
- let tl = normalize(&type_with(ctx, l)?);
- match tl {
+ let tl = normalize(type_with(ctx, l.clone())?);
+ match *tl {
Builtin(lt) if lt == t => {}
- _ => return Err(TypeError::new(ctx, e, ef((*l).clone(), tl))),
+ _ => return Err(TypeError::new(ctx, e, ef(l.clone(), tl))),
}
- let tr = normalize(&type_with(ctx, r)?);
- match tr {
+ let tr = normalize(type_with(ctx, r.clone())?);
+ match *tr {
Builtin(rt) if rt == t => {}
- _ => return Err(TypeError::new(ctx, e, ef((*r).clone(), tr))),
+ _ => return Err(TypeError::new(ctx, e, ef(r.clone(), tr))),
}
Ok(Builtin(t))
@@ -178,55 +178,54 @@ where
/// is not necessary for just type-checking. If you actually care about the
/// returned type then you may want to `normalize` it afterwards.
pub fn type_with<S>(
- ctx: &Context<Label, Expr<S, X>>,
- e: &Expr<S, X>,
-) -> Result<Expr<S, X>, TypeError<S>>
+ ctx: &Context<Label, Rc<Expr<S, X>>>,
+ e: Rc<Expr<S, X>>,
+) -> Result<Rc<Expr<S, X>>, TypeError<S>>
where
S: Clone + ::std::fmt::Debug,
{
use dhall_core::BinOp::*;
use dhall_core::Expr;
match *e {
- Const(c) => axiom(c).map(Const), //.map(Cow::Owned),
+ Const(c) => axiom(c).map(Const),
Var(V(ref x, n)) => {
- ctx.lookup(x, n)
+ return ctx
+ .lookup(x, n)
.cloned()
- //.map(Cow::Borrowed)
- .ok_or_else(|| TypeError::new(ctx, e, UnboundVariable))
+ .ok_or_else(|| TypeError::new(ctx, e.clone(), UnboundVariable))
}
Lam(ref x, ref tA, ref b) => {
let ctx2 = ctx
- .insert(x.clone(), (**tA).clone())
- .map(|e| core::shift(1, &V(x.clone(), 0), e));
- let tB = type_with(&ctx2, b)?;
- let p = Pi(x.clone(), tA.clone(), bx(tB));
- let _ = type_with(ctx, &p)?;
- //Ok(Cow::Owned(p))
- Ok(p)
+ .insert(x.clone(), tA.clone())
+ .map(|e| shift(1, &V(x.clone(), 0), e));
+ let tB = type_with(&ctx2, b.clone())?;
+ let p = rc(Pi(x.clone(), tA.clone(), tB));
+ let _ = type_with(ctx, p.clone())?;
+ return Ok(p);
}
Pi(ref x, ref tA, ref tB) => {
- let tA2 = normalize::<S, S, X>(&type_with(ctx, tA)?);
- let kA = match tA2 {
+ let tA2 = normalize::<S, S, X>(type_with(ctx, tA.clone())?);
+ let kA = match tA2.as_ref() {
Const(k) => k,
_ => {
return Err(TypeError::new(
ctx,
- e,
- InvalidInputType((**tA).clone()),
+ e.clone(),
+ InvalidInputType(tA.clone()),
));
}
};
let ctx2 = ctx
- .insert(x.clone(), (**tA).clone())
- .map(|e| core::shift(1, &V(x.clone(), 0), e));
- let tB = normalize(&type_with(&ctx2, tB)?);
- let kB = match tB {
+ .insert(x.clone(), tA.clone())
+ .map(|e| shift(1, &V(x.clone(), 0), e));
+ let tB = normalize(type_with(&ctx2, tB.clone())?);
+ let kB = match tB.as_ref() {
Const(k) => k,
_ => {
return Err(TypeError::new(
&ctx2,
- e,
+ e.clone(),
InvalidOutputType(tB),
));
}
@@ -235,184 +234,212 @@ where
match rule(kA, kB) {
Err(()) => Err(TypeError::new(
ctx,
- e,
- NoDependentTypes((**tA).clone(), tB),
+ e.clone(),
+ NoDependentTypes(tA.clone(), tB),
)),
Ok(k) => Ok(Const(k)),
}
}
App(ref f, ref args) => {
let (a, args) = match args.split_last() {
- None => return type_with(ctx, f),
+ None => return type_with(ctx, f.clone()),
Some(x) => x,
};
let tf =
- normalize(&type_with(ctx, &App(f.clone(), args.to_vec()))?);
- let (x, tA, tB) = match tf {
+ normalize(type_with(ctx, rc(App(f.clone(), args.to_vec())))?);
+ let (x, tA, tB) = match tf.as_ref() {
Pi(x, tA, tB) => (x, tA, tB),
_ => {
return Err(TypeError::new(
ctx,
- e,
- NotAFunction((**f).clone(), tf),
+ e.clone(),
+ NotAFunction(f.clone(), tf),
));
}
};
- let tA2 = type_with(ctx, a)?;
- if prop_equal(&tA, &tA2) {
- let vx0 = &V(x, 0);
+ let tA2 = type_with(ctx, a.clone())?;
+ if prop_equal(tA.clone(), tA2.clone()) {
+ let vx0 = &V(x.clone(), 0);
let a2 = shift::<S, S, X>(1, vx0, a);
let tB2 = subst(vx0, &a2, &tB);
let tB3 = shift::<S, S, X>(-1, vx0, &tB2);
- Ok(tB3)
+ return Ok(tB3);
} else {
- let nf_A = normalize(&tA);
- let nf_A2 = normalize(&tA2);
+ let nf_A = normalize(tA.clone());
+ let nf_A2 = normalize(tA2);
Err(TypeError::new(
ctx,
- e,
- TypeMismatch((**f).clone(), nf_A, (**a).clone(), nf_A2),
+ e.clone(),
+ TypeMismatch(f.clone(), nf_A, a.clone(), nf_A2),
))
}
}
Let(ref f, ref mt, ref r, ref b) => {
- let tR = type_with(ctx, r)?;
- let ttR = normalize::<S, S, X>(&type_with(ctx, &tR)?);
- let kR = match ttR {
+ let tR = type_with(ctx, r.clone())?;
+ let ttR = normalize::<S, S, X>(type_with(ctx, tR.clone())?);
+ let kR = match ttR.as_ref() {
Const(k) => k,
// Don't bother to provide a `let`-specific version of this error
// message because this should never happen anyway
- _ => return Err(TypeError::new(ctx, e, InvalidInputType(tR))),
+ _ => {
+ return Err(TypeError::new(
+ ctx,
+ e.clone(),
+ InvalidInputType(tR),
+ ))
+ }
};
let ctx2 = ctx.insert(f.clone(), tR.clone());
- let tB = type_with(&ctx2, b)?;
- let ttB = normalize::<S, S, X>(&type_with(ctx, &tB)?);
- let kB = match ttB {
+ let tB = type_with(&ctx2, b.clone())?;
+ let ttB = normalize::<S, S, X>(type_with(ctx, tB.clone())?);
+ let kB = match ttB.as_ref() {
Const(k) => k,
// Don't bother to provide a `let`-specific version of this error
// message because this should never happen anyway
- _ => return Err(TypeError::new(ctx, e, InvalidOutputType(tB))),
+ _ => {
+ return Err(TypeError::new(
+ ctx,
+ e.clone(),
+ InvalidOutputType(tB),
+ ))
+ }
};
if let Err(()) = rule(kR, kB) {
- return Err(TypeError::new(ctx, e, NoDependentLet(tR, tB)));
+ return Err(TypeError::new(
+ ctx,
+ e.clone(),
+ NoDependentLet(tR, tB),
+ ));
}
if let Some(ref t) = *mt {
- let nf_t = normalize(t);
- let nf_tR = normalize(&tR);
- if !prop_equal(&nf_tR, &nf_t) {
+ let nf_t = normalize(t.clone());
+ let nf_tR = normalize(tR);
+ if !prop_equal(nf_tR.clone(), nf_t.clone()) {
return Err(TypeError::new(
ctx,
- e,
- AnnotMismatch((**r).clone(), nf_t, nf_tR),
+ e.clone(),
+ AnnotMismatch(r.clone(), nf_t, nf_tR),
));
}
}
- Ok(tB)
+ return Ok(tB);
}
Annot(ref x, ref t) => {
// This is mainly just to check that `t` is not `Kind`
- let _ = type_with(ctx, t)?;
+ let _ = type_with(ctx, t.clone())?;
- let t2 = type_with(ctx, x)?;
- if prop_equal(t, &t2) {
- Ok((**t).clone())
+ let t2 = type_with(ctx, x.clone())?;
+ if prop_equal(t.clone(), t2.clone()) {
+ return Ok(t.clone());
} else {
- let nf_t = normalize(t);
- let nf_t2 = normalize(&t2);
+ let nf_t = normalize(t.clone());
+ let nf_t2 = normalize(t2);
Err(TypeError::new(
ctx,
- e,
- AnnotMismatch((**x).clone(), nf_t, nf_t2),
+ e.clone(),
+ AnnotMismatch(x.clone(), nf_t, nf_t2),
))
}
}
BoolLit(_) => Ok(Builtin(Bool)),
- BinOp(BoolAnd, ref l, ref r) => op2_type(ctx, e, Bool, CantAnd, l, r),
- BinOp(BoolOr, ref l, ref r) => op2_type(ctx, e, Bool, CantOr, l, r),
- BinOp(BoolEQ, ref l, ref r) => op2_type(ctx, e, Bool, CantEQ, l, r),
- BinOp(BoolNE, ref l, ref r) => op2_type(ctx, e, Bool, CantNE, l, r),
+ BinOp(BoolAnd, ref l, ref r) => {
+ op2_type(ctx, e.clone(), Bool, CantAnd, l, r)
+ }
+ BinOp(BoolOr, ref l, ref r) => {
+ op2_type(ctx, e.clone(), Bool, CantOr, l, r)
+ }
+ BinOp(BoolEQ, ref l, ref r) => {
+ op2_type(ctx, e.clone(), Bool, CantEQ, l, r)
+ }
+ BinOp(BoolNE, ref l, ref r) => {
+ op2_type(ctx, e.clone(), Bool, CantNE, l, r)
+ }
BoolIf(ref x, ref y, ref z) => {
- let tx = normalize(&type_with(ctx, x)?);
- match tx {
+ let tx = normalize(type_with(ctx, x.clone())?);
+ match tx.as_ref() {
Builtin(Bool) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
- InvalidPredicate((**x).clone(), tx),
+ e.clone(),
+ InvalidPredicate(x.clone(), tx),
));
}
}
- let ty = normalize(&type_with(ctx, y)?);
- let tty = normalize(&type_with(ctx, &ty)?);
- match tty {
+ let ty = normalize(type_with(ctx, y.clone())?);
+ let tty = normalize(type_with(ctx, ty.clone())?);
+ match tty.as_ref() {
Const(Type) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
- IfBranchMustBeTerm(true, (**y).clone(), ty, tty),
+ e.clone(),
+ IfBranchMustBeTerm(true, y.clone(), ty, tty),
));
}
}
- let tz = normalize(&type_with(ctx, z)?);
- let ttz = normalize(&type_with(ctx, &tz)?);
- match ttz {
+ let tz = normalize(type_with(ctx, z.clone())?);
+ let ttz = normalize(type_with(ctx, tz.clone())?);
+ match ttz.as_ref() {
Const(Type) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
- IfBranchMustBeTerm(false, (**z).clone(), tz, ttz),
+ e.clone(),
+ IfBranchMustBeTerm(false, z.clone(), tz, ttz),
));
}
}
- if !prop_equal(&ty, &tz) {
+ if !prop_equal(ty.clone(), tz.clone()) {
return Err(TypeError::new(
ctx,
- e,
- IfBranchMismatch((**y).clone(), (**z).clone(), ty, tz),
+ e.clone(),
+ IfBranchMismatch(y.clone(), z.clone(), ty, tz),
));
}
- Ok(ty)
+ return Ok(ty);
}
NaturalLit(_) => Ok(Builtin(Natural)),
- Builtin(NaturalFold) => Ok(dhall_expr!(
- Natural ->
- forall (natural: Type) ->
- forall (succ: natural -> natural) ->
- forall (zero: natural) ->
- natural
- )),
- Builtin(NaturalBuild) => Ok(dhall_expr!(
- (forall (natural: Type) ->
+ Builtin(NaturalFold) => {
+ return Ok(dhall_expr!(
+ Natural ->
+ forall (natural: Type) ->
forall (succ: natural -> natural) ->
forall (zero: natural) ->
- natural) ->
- Natural
- )),
+ natural
+ ))
+ }
+ Builtin(NaturalBuild) => {
+ return Ok(dhall_expr!(
+ (forall (natural: Type) ->
+ forall (succ: natural -> natural) ->
+ forall (zero: natural) ->
+ natural) ->
+ Natural
+ ))
+ }
Builtin(NaturalIsZero) | Builtin(NaturalEven) | Builtin(NaturalOdd) => {
- Ok(dhall_expr!(
+ return Ok(dhall_expr!(
Natural -> Bool
))
}
BinOp(NaturalPlus, ref l, ref r) => {
- op2_type(ctx, e, Natural, CantAdd, l, r)
+ op2_type(ctx, e.clone(), Natural, CantAdd, l, r)
}
BinOp(NaturalTimes, ref l, ref r) => {
- op2_type(ctx, e, Natural, CantMultiply, l, r)
+ op2_type(ctx, e.clone(), Natural, CantMultiply, l, r)
}
IntegerLit(_) => Ok(Builtin(Integer)),
DoubleLit(_) => Ok(Builtin(Double)),
TextLit(_) => Ok(Builtin(Text)),
BinOp(TextAppend, ref l, ref r) => {
- op2_type(ctx, e, Text, CantTextAppend, l, r)
+ op2_type(ctx, e.clone(), Text, CantTextAppend, l, r)
}
ListLit(ref t, ref xs) => {
let mut iter = xs.iter().enumerate();
@@ -420,117 +447,135 @@ where
Some(t) => t.clone(),
None => {
let (_, first_x) = iter.next().unwrap();
- bx(type_with(ctx, first_x)?)
+ type_with(ctx, first_x.clone())?
}
};
- let s = normalize::<_, S, _>(&type_with(ctx, &t)?);
- match s {
+ let s = normalize::<_, S, _>(type_with(ctx, t.clone())?);
+ match s.as_ref() {
Const(Type) => {}
- _ => return Err(TypeError::new(ctx, e, InvalidListType(t))),
+ _ => {
+ return Err(TypeError::new(
+ ctx,
+ e.clone(),
+ InvalidListType(t),
+ ))
+ }
}
for (i, x) in iter {
- let t2 = type_with(ctx, x)?;
- if !prop_equal(&t, &t2) {
- let nf_t = normalize(&t);
- let nf_t2 = normalize(&t2);
+ let t2 = type_with(ctx, x.clone())?;
+ if !prop_equal(t.clone(), t2.clone()) {
+ let nf_t = normalize(t);
+ let nf_t2 = normalize(t2);
return Err(TypeError::new(
ctx,
- e,
- InvalidListElement(i, nf_t, (**x).clone(), nf_t2),
+ e.clone(),
+ InvalidListElement(i, nf_t, x.clone(), nf_t2),
));
}
}
- Ok(dhall_expr!(List t))
+ return Ok(dhall_expr!(List t));
+ }
+ Builtin(ListBuild) => {
+ return Ok(dhall_expr!(
+ forall (a: Type) ->
+ (forall (list: Type) ->
+ forall (cons: a -> list -> list) ->
+ forall (nil: list) ->
+ list) ->
+ List a
+ ))
}
- Builtin(ListBuild) => Ok(dhall_expr!(
- forall (a: Type) ->
- (forall (list: Type) ->
+ Builtin(ListFold) => {
+ return Ok(dhall_expr!(
+ forall (a: Type) ->
+ List a ->
+ forall (list: Type) ->
forall (cons: a -> list -> list) ->
forall (nil: list) ->
- list) ->
- List a
- )),
- Builtin(ListFold) => Ok(dhall_expr!(
- forall (a: Type) ->
- List a ->
- forall (list: Type) ->
- forall (cons: a -> list -> list) ->
- forall (nil: list) ->
- list
- )),
+ list
+ ))
+ }
Builtin(ListLength) => {
- Ok(dhall_expr!(forall (a: Type) -> List a -> Natural))
+ return Ok(dhall_expr!(forall (a: Type) -> List a -> Natural))
}
Builtin(ListHead) | Builtin(ListLast) => {
- Ok(dhall_expr!(forall (a: Type) -> List a -> Optional a))
- }
- Builtin(ListIndexed) => Ok(dhall_expr!(
- forall (a: Type) ->
- List a ->
- List { index: Natural, value: a }
- )),
- Builtin(ListReverse) => Ok(dhall_expr!(
- forall (a: Type) -> List a -> List a
- )),
+ return Ok(dhall_expr!(forall (a: Type) -> List a -> Optional a))
+ }
+ Builtin(ListIndexed) => {
+ return Ok(dhall_expr!(
+ forall (a: Type) ->
+ List a ->
+ List { index: Natural, value: a }
+ ))
+ }
+ Builtin(ListReverse) => {
+ return Ok(dhall_expr!(
+ forall (a: Type) -> List a -> List a
+ ))
+ }
OptionalLit(ref t, ref xs) => {
let mut iter = xs.iter();
let t: Rc<Expr<_, _>> = match t {
Some(t) => t.clone(),
None => {
let x = iter.next().unwrap();
- bx(type_with(ctx, x)?)
+ type_with(ctx, x.clone())?
}
};
- let s = normalize::<_, S, _>(&type_with(ctx, &t)?);
- match s {
+ let s = normalize::<_, S, _>(type_with(ctx, t.clone())?);
+ match s.as_ref() {
Const(Type) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
+ e.clone(),
InvalidOptionalType(t),
));
}
}
for x in iter {
- let t2 = type_with(ctx, x)?;
- if !prop_equal(&t, &t2) {
- let nf_t = normalize(&t);
- let nf_t2 = normalize(&t2);
+ let t2 = type_with(ctx, x.clone())?;
+ if !prop_equal(t.clone(), t2.clone()) {
+ let nf_t = normalize(t);
+ let nf_t2 = normalize(t2);
return Err(TypeError::new(
ctx,
- e,
- InvalidOptionalElement(nf_t, (**x).clone(), nf_t2),
+ e.clone(),
+ InvalidOptionalElement(nf_t, x.clone(), nf_t2),
));
}
}
- Ok(dhall_expr!(Optional t))
- }
- Builtin(OptionalFold) => Ok(dhall_expr!(
- forall (a: Type) ->
- Optional a ->
- forall (optional: Type) ->
- forall (just: a -> optional) ->
- forall (nothing: optional) ->
- optional
- )),
- Builtin(List) | Builtin(Optional) => Ok(dhall_expr!(
- Type -> Type
- )),
+ return Ok(dhall_expr!(Optional t));
+ }
+ Builtin(OptionalFold) => {
+ return Ok(dhall_expr!(
+ forall (a: Type) ->
+ Optional a ->
+ forall (optional: Type) ->
+ forall (just: a -> optional) ->
+ forall (nothing: optional) ->
+ optional
+ ))
+ }
+ Builtin(List) | Builtin(Optional) => {
+ return Ok(dhall_expr!(
+ Type -> Type
+ ))
+ }
Builtin(Bool) | Builtin(Natural) | Builtin(Integer)
| Builtin(Double) | Builtin(Text) => Ok(Const(Type)),
Record(ref kts) => {
for (k, t) in kts {
- let s = normalize::<S, S, X>(&type_with(ctx, t)?);
- match s {
+ let s = normalize::<S, S, X>(type_with(ctx, t.clone())?);
+ match s.as_ref() {
Const(Type) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
- InvalidFieldType((*k).clone(), (**t).clone()),
+ e.clone(),
+ InvalidFieldType(k.clone(), t.clone()),
));
}
}
@@ -541,19 +586,19 @@ where
let kts = kvs
.iter()
.map(|(k, v)| {
- let t = type_with(ctx, v)?;
- let s = normalize::<S, S, X>(&type_with(ctx, &t)?);
- match s {
+ let t = type_with(ctx, v.clone())?;
+ let s = normalize::<S, S, X>(type_with(ctx, t.clone())?);
+ match s.as_ref() {
Const(Type) => {}
_ => {
return Err(TypeError::new(
ctx,
- e,
- InvalidField((*k).clone(), (**v).clone()),
+ e.clone(),
+ InvalidField(k.clone(), v.clone()),
));
}
}
- Ok(((*k).clone(), bx(t)))
+ Ok((k.clone(), t))
})
.collect::<Result<_, _>>()?;
Ok(Record(kts))
@@ -640,21 +685,21 @@ where
return t
*/
Field(ref r, ref x) => {
- let t = normalize(&type_with(ctx, r)?);
- match t {
+ let t = normalize(type_with(ctx, r.clone())?);
+ match t.as_ref() {
Record(ref kts) => {
- kts.get(x).map(|x| &**x).cloned().ok_or_else(|| {
+ return kts.get(x).cloned().ok_or_else(|| {
TypeError::new(
ctx,
- e,
- MissingField((*x).clone(), t.clone()),
+ e.clone(),
+ MissingField(x.clone(), t.clone()),
)
})
}
_ => Err(TypeError::new(
ctx,
- e,
- NotARecord((*x).clone(), (**r).clone(), t.clone()),
+ e.clone(),
+ NotARecord(x.clone(), r.clone(), t.clone()),
)),
}
}
@@ -667,14 +712,15 @@ where
Embed(p) => match p {},
_ => panic!("Unimplemented typecheck case: {:?}", e),
}
+ .map(rc)
}
/// `typeOf` is the same as `type_with` with an empty context, meaning that the
/// expression must be closed (i.e. no free variables), otherwise type-checking
/// will fail.
pub fn type_of<S: Clone + ::std::fmt::Debug>(
- e: &Expr<S, X>,
-) -> Result<Expr<S, X>, TypeError<S>> {
+ e: Rc<Expr<S, X>>,
+) -> Result<Rc<Expr<S, X>>, TypeError<S>> {
let ctx = Context::new();
type_with(&ctx, e) //.map(|e| e.into_owned())
}
@@ -683,64 +729,74 @@ pub fn type_of<S: Clone + ::std::fmt::Debug>(
#[derive(Debug)]
pub enum TypeMessage<S> {
UnboundVariable,
- InvalidInputType(Expr<S, X>),
- InvalidOutputType(Expr<S, X>),
- NotAFunction(Expr<S, X>, Expr<S, X>),
- TypeMismatch(Expr<S, X>, Expr<S, X>, Expr<S, X>, Expr<S, X>),
- AnnotMismatch(Expr<S, X>, Expr<S, X>, Expr<S, X>),
+ InvalidInputType(Rc<Expr<S, X>>),
+ InvalidOutputType(Rc<Expr<S, X>>),
+ NotAFunction(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ TypeMismatch(
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ ),
+ AnnotMismatch(Rc<Expr<S, X>>, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
Untyped,
- InvalidListElement(usize, Expr<S, X>, Expr<S, X>, Expr<S, X>),
+ InvalidListElement(usize, Rc<Expr<S, X>>, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
InvalidListType(Rc<Expr<S, X>>),
- InvalidOptionalElement(Expr<S, X>, Expr<S, X>, Expr<S, X>),
+ InvalidOptionalElement(Rc<Expr<S, X>>, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
InvalidOptionalLiteral(usize),
InvalidOptionalType(Rc<Expr<S, X>>),
- InvalidPredicate(Expr<S, X>, Expr<S, X>),
- IfBranchMismatch(Expr<S, X>, Expr<S, X>, Expr<S, X>, Expr<S, X>),
- IfBranchMustBeTerm(bool, Expr<S, X>, Expr<S, X>, Expr<S, X>),
- InvalidField(Label, Expr<S, X>),
- InvalidFieldType(Label, Expr<S, X>),
- InvalidAlternative(Label, Expr<S, X>),
- InvalidAlternativeType(Label, Expr<S, X>),
+ InvalidPredicate(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ IfBranchMismatch(
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ Rc<Expr<S, X>>,
+ ),
+ IfBranchMustBeTerm(bool, Rc<Expr<S, X>>, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ InvalidField(Label, Rc<Expr<S, X>>),
+ InvalidFieldType(Label, Rc<Expr<S, X>>),
+ InvalidAlternative(Label, Rc<Expr<S, X>>),
+ InvalidAlternativeType(Label, Rc<Expr<S, X>>),
DuplicateAlternative(Label),
- MustCombineARecord(Expr<S, X>, Expr<S, X>),
+ MustCombineARecord(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
FieldCollision(Label),
- MustMergeARecord(Expr<S, X>, Expr<S, X>),
- MustMergeUnion(Expr<S, X>, Expr<S, X>),
+ MustMergeARecord(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ MustMergeUnion(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
UnusedHandler(HashSet<Label>),
MissingHandler(HashSet<Label>),
- HandlerInputTypeMismatch(Label, Expr<S, X>, Expr<S, X>),
- HandlerOutputTypeMismatch(Label, Expr<S, X>, Expr<S, X>),
- HandlerNotAFunction(Label, Expr<S, X>),
- NotARecord(Label, Expr<S, X>, Expr<S, X>),
- MissingField(Label, Expr<S, X>),
- CantAnd(Expr<S, X>, Expr<S, X>),
- CantOr(Expr<S, X>, Expr<S, X>),
- CantEQ(Expr<S, X>, Expr<S, X>),
- CantNE(Expr<S, X>, Expr<S, X>),
- CantTextAppend(Expr<S, X>, Expr<S, X>),
- CantAdd(Expr<S, X>, Expr<S, X>),
- CantMultiply(Expr<S, X>, Expr<S, X>),
- NoDependentLet(Expr<S, X>, Expr<S, X>),
- NoDependentTypes(Expr<S, X>, Expr<S, X>),
+ HandlerInputTypeMismatch(Label, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ HandlerOutputTypeMismatch(Label, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ HandlerNotAFunction(Label, Rc<Expr<S, X>>),
+ NotARecord(Label, Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ MissingField(Label, Rc<Expr<S, X>>),
+ CantAnd(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantOr(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantEQ(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantNE(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantTextAppend(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantAdd(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ CantMultiply(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ NoDependentLet(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
+ NoDependentTypes(Rc<Expr<S, X>>, Rc<Expr<S, X>>),
}
/// A structured type error that includes context
#[derive(Debug)]
pub struct TypeError<S> {
- pub context: Context<Label, Expr<S, X>>,
- pub current: Expr<S, X>,
+ pub context: Context<Label, Rc<Expr<S, X>>>,
+ pub current: Rc<Expr<S, X>>,
pub type_message: TypeMessage<S>,
}
impl<S: Clone> TypeError<S> {
pub fn new(
- context: &Context<Label, Expr<S, X>>,
- current: &Expr<S, X>,
+ context: &Context<Label, Rc<Expr<S, X>>>,
+ current: Rc<Expr<S, X>>,
type_message: TypeMessage<S>,
) -> Self {
TypeError {
context: context.clone(),
- current: current.clone(),
+ current: current,
type_message,
}
}
diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs
index b60262b..4d64fea 100644
--- a/dhall/tests/common/mod.rs
+++ b/dhall/tests/common/mod.rs
@@ -97,25 +97,25 @@ pub fn run_test(base_path: &str, feature: Feature) {
Normalization => {
let expr_file_path = base_path.clone() + "A.dhall";
let expected_file_path = base_path + "B.dhall";
- let expr = read_dhall_file(&expr_file_path).unwrap();
- let expected = read_dhall_file(&expected_file_path).unwrap();
+ let expr = rc(read_dhall_file(&expr_file_path).unwrap());
+ let expected = rc(read_dhall_file(&expected_file_path).unwrap());
assert_eq_display!(
- normalize::<_, X, _>(&expr),
- normalize::<_, X, _>(&expected)
+ normalize::<_, X, _>(expr),
+ normalize::<_, X, _>(expected)
);
}
TypecheckFailure => {
let file_path = base_path + ".dhall";
- let expr = read_dhall_file(&file_path).unwrap();
- typecheck::type_of(&expr).unwrap_err();
+ let expr = rc(read_dhall_file(&file_path).unwrap());
+ typecheck::type_of(expr).unwrap_err();
}
TypecheckSuccess => {
let expr_file_path = base_path.clone() + "A.dhall";
let expected_file_path = base_path + "B.dhall";
- let expr = read_dhall_file(&expr_file_path).unwrap();
- let expected = read_dhall_file(&expected_file_path).unwrap();
- typecheck::type_of(&Expr::Annot(bx(expr), bx(expected))).unwrap();
+ let expr = rc(read_dhall_file(&expr_file_path).unwrap());
+ let expected = rc(read_dhall_file(&expected_file_path).unwrap());
+ typecheck::type_of(rc(Expr::Annot(expr, expected))).unwrap();
}
}
}
diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs
index f5da1df..eba6a42 100644
--- a/dhall_core/src/core.rs
+++ b/dhall_core/src/core.rs
@@ -290,6 +290,8 @@ impl<N: Clone, E: Clone> Add for InterpolatedText<N, E> {
}
}
+pub type SubExpr<Note, Embed> = Rc<Expr<Note, Embed>>;
+
/// Syntax tree for expressions
#[derive(Debug, Clone, PartialEq)]
pub enum Expr<Note, Embed> {
@@ -299,33 +301,33 @@ pub enum Expr<Note, Embed> {
/// `Var (V x n) ~ x@n`
Var(V),
/// `Lam x A b ~ λ(x : A) -> b`
- Lam(Label, Rc<Expr<Note, Embed>>, Rc<Expr<Note, Embed>>),
+ Lam(Label, SubExpr<Note, Embed>, SubExpr<Note, Embed>),
/// `Pi "_" A B ~ A -> B`
/// `Pi x A B ~ ∀(x : A) -> B`
- Pi(Label, Rc<Expr<Note, Embed>>, Rc<Expr<Note, Embed>>),
+ Pi(Label, SubExpr<Note, Embed>, SubExpr<Note, Embed>),
/// `App f A ~ f A`
- App(Rc<Expr<Note, Embed>>, Vec<Rc<Expr<Note, Embed>>>),
+ App(SubExpr<Note, Embed>, Vec<SubExpr<Note, Embed>>),
/// `Let x Nothing r e ~ let x = r in e`
/// `Let x (Just t) r e ~ let x : t = r in e`
Let(
Label,
- Option<Rc<Expr<Note, Embed>>>,
- Rc<Expr<Note, Embed>>,
- Rc<Expr<Note, Embed>>,
+ Option<SubExpr<Note, Embed>>,
+ SubExpr<Note, Embed>,
+ SubExpr<Note, Embed>,
),
/// `Annot x t ~ x : t`
- Annot(Rc<Expr<Note, Embed>>, Rc<Expr<Note, Embed>>),
+ Annot(SubExpr<Note, Embed>, SubExpr<Note, Embed>),
/// Built-in values
Builtin(Builtin),
// Binary operations
- BinOp(BinOp, Rc<Expr<Note, Embed>>, Rc<Expr<Note, Embed>>),
+ BinOp(BinOp, SubExpr<Note, Embed>, SubExpr<Note, Embed>),
/// `BoolLit b ~ b`
BoolLit(bool),
/// `BoolIf x y z ~ if x then y else z`
BoolIf(
- Rc<Expr<Note, Embed>>,
- Rc<Expr<Note, Embed>>,
- Rc<Expr<Note, Embed>>,
+ SubExpr<Note, Embed>,
+ SubExpr<Note, Embed>,
+ SubExpr<Note, Embed>,
),
/// `NaturalLit n ~ +n`
NaturalLit(Natural),
@@ -336,35 +338,32 @@ pub enum Expr<Note, Embed> {
/// `TextLit t ~ t`
TextLit(InterpolatedText<Note, Embed>),
/// `ListLit t [x, y, z] ~ [x, y, z] : List t`
- ListLit(Option<Rc<Expr<Note, Embed>>>, Vec<Rc<Expr<Note, Embed>>>),
+ ListLit(Option<SubExpr<Note, Embed>>, Vec<SubExpr<Note, Embed>>),
/// `OptionalLit t [e] ~ [e] : Optional t`
/// `OptionalLit t [] ~ [] : Optional t`
- OptionalLit(
- Option<Rc<Expr<Note, Embed>>>,
- Option<Rc<Expr<Note, Embed>>>,
- ),
+ OptionalLit(Option<SubExpr<Note, Embed>>, Option<SubExpr<Note, Embed>>),
/// `Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 }`
- Record(BTreeMap<Label, Rc<Expr<Note, Embed>>>),
+ Record(BTreeMap<Label, SubExpr<Note, Embed>>),
/// `RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 }`
- RecordLit(BTreeMap<Label, Rc<Expr<Note, Embed>>>),
+ RecordLit(BTreeMap<Label, SubExpr<Note, Embed>>),
/// `Union [(k1, t1), (k2, t2)] ~ < k1 : t1, k2 : t2 >`
- Union(BTreeMap<Label, Rc<Expr<Note, Embed>>>),
+ Union(BTreeMap<Label, SubExpr<Note, Embed>>),
/// `UnionLit (k1, v1) [(k2, t2), (k3, t3)] ~ < k1 = t1, k2 : t2, k3 : t3 >`
UnionLit(
Label,
- Rc<Expr<Note, Embed>>,
- BTreeMap<Label, Rc<Expr<Note, Embed>>>,
+ SubExpr<Note, Embed>,
+ BTreeMap<Label, SubExpr<Note, Embed>>,
),
/// `Merge x y t ~ merge x y : t`
Merge(
- Rc<Expr<Note, Embed>>,
- Rc<Expr<Note, Embed>>,
- Option<Rc<Expr<Note, Embed>>>,
+ SubExpr<Note, Embed>,
+ SubExpr<Note, Embed>,
+ Option<SubExpr<Note, Embed>>,
),
/// `Field e x ~ e.x`
- Field(Rc<Expr<Note, Embed>>, Label),
+ Field(SubExpr<Note, Embed>, Label),
/// Annotation on the AST. Unused for now but could hold e.g. file location information
- Note(Note, Rc<Expr<Note, Embed>>),
+ Note(Note, SubExpr<Note, Embed>),
/// Embeds an import or the result of resolving the import
Embed(Embed),
}
@@ -444,6 +443,31 @@ impl<S, A> Expr<S, A> {
F3: FnOnce(&A) -> B,
F4: Fn(&Label) -> Label,
{
+ map_shallow(
+ self,
+ |x| rc(map_expr(x.as_ref())),
+ map_note,
+ map_embed,
+ map_label,
+ )
+ }
+
+ pub fn map_shallow_rc<T, B, F1, F2, F3, F4>(
+ &self,
+ map_expr: F1,
+ map_note: F2,
+ map_embed: F3,
+ map_label: F4,
+ ) -> Expr<T, B>
+ where
+ A: Clone,
+ T: Clone,
+ S: Clone,
+ F1: Fn(&SubExpr<S, A>) -> SubExpr<T, B>,
+ F2: FnOnce(&S) -> T,
+ F3: FnOnce(&A) -> B,
+ F4: Fn(&Label) -> Label,
+ {
map_shallow(self, map_expr, map_note, map_embed, map_label)
}
@@ -852,10 +876,7 @@ pub fn app<S, A, Ef>(f: Ef, x: Vec<Rc<Expr<S, A>>>) -> Expr<S, A>
where
Ef: Into<Expr<S, A>>,
{
- Expr::App(
- bx(f.into()),
- x,
- )
+ Expr::App(bx(f.into()), x)
}
pub type Double = f64;
@@ -900,58 +921,55 @@ where
A: Clone,
S: Clone,
T: Clone,
- F1: Fn(&Expr<S, A>) -> Expr<T, B>,
+ F1: Fn(&SubExpr<S, A>) -> SubExpr<T, B>,
F2: FnOnce(&S) -> T,
F3: FnOnce(&A) -> B,
F4: Fn(&Label) -> Label,
{
use crate::Expr::*;
- let bxmap = |x: &Expr<S, A>| -> Rc<Expr<T, B>> { bx(map(x)) };
- let bxbxmap = |x: &Rc<Expr<S, A>>| -> Rc<Expr<T, B>> { bx(map(&**x)) };
- let opt = |x| map_opt_box(x, &map);
+ let map = &map;
+ let opt = |x: &Option<_>| x.as_ref().map(&map);
match *e {
Const(k) => Const(k),
Var(V(ref x, n)) => Var(V(map_label(x), n)),
- Lam(ref x, ref t, ref b) => Lam(map_label(x), bxmap(t), bxmap(b)),
- Pi(ref x, ref t, ref b) => Pi(map_label(x), bxmap(t), bxmap(b)),
+ Lam(ref x, ref t, ref b) => Lam(map_label(x), map(t), map(b)),
+ Pi(ref x, ref t, ref b) => Pi(map_label(x), map(t), map(b)),
App(ref f, ref args) => {
- let args = args.iter().map(bxbxmap).collect();
- App(bxmap(f), args)
+ let args = args.iter().map(map).collect();
+ App(map(f), args)
}
Let(ref l, ref t, ref a, ref b) => {
- Let(map_label(l), opt(t), bxmap(a), bxmap(b))
+ Let(map_label(l), opt(t), map(a), map(b))
}
- Annot(ref x, ref t) => Annot(bxmap(x), bxmap(t)),
+ Annot(ref x, ref t) => Annot(map(x), map(t)),
Builtin(v) => Builtin(v),
BoolLit(b) => BoolLit(b),
- BoolIf(ref b, ref t, ref f) => BoolIf(bxmap(b), bxmap(t), bxmap(f)),
+ BoolIf(ref b, ref t, ref f) => BoolIf(map(b), map(t), map(f)),
NaturalLit(n) => NaturalLit(n),
IntegerLit(n) => IntegerLit(n),
DoubleLit(n) => DoubleLit(n),
- TextLit(ref t) => TextLit(t.map(&bxbxmap)),
- BinOp(o, ref x, ref y) => BinOp(o, bxmap(x), bxmap(y)),
+ TextLit(ref t) => TextLit(t.map(&map)),
+ BinOp(o, ref x, ref y) => BinOp(o, map(x), map(y)),
ListLit(ref t, ref es) => {
- let es = es.iter().map(&bxbxmap).collect();
+ let es = es.iter().map(&map).collect();
ListLit(opt(t), es)
}
OptionalLit(ref t, ref es) => OptionalLit(opt(t), opt(es)),
Record(ref kts) => {
- Record(map_record_value_and_keys(kts, bxbxmap, map_label))
+ Record(map_record_value_and_keys(kts, map, map_label))
}
RecordLit(ref kvs) => {
- RecordLit(map_record_value_and_keys(kvs, bxbxmap, map_label))
- }
- Union(ref kts) => {
- Union(map_record_value_and_keys(kts, bxbxmap, map_label))
+ RecordLit(map_record_value_and_keys(kvs, map, map_label))
}
+ Union(ref kts) => Union(map_record_value_and_keys(kts, map, map_label)),
UnionLit(ref k, ref v, ref kvs) => UnionLit(
map_label(k),
- bxmap(v),
- map_record_value_and_keys(kvs, bxbxmap, map_label),
+ map(v),
+ map_record_value_and_keys(kvs, map, map_label),
),
- Merge(ref x, ref y, ref t) => Merge(bxmap(x), bxmap(y), opt(t)),
- Field(ref r, ref x) => Field(bxmap(r), map_label(x)),
- Note(ref n, ref e) => Note(map_note(n), bxmap(e)),
+ Merge(ref x, ref y, ref t) => Merge(map(x), map(y), opt(t)),
+ Field(ref r, ref x) => Field(map(r), map_label(x)),
+ Note(ref n, ref e) => Note(map_note(n), map(e)),
Embed(ref a) => Embed(map_embed(a)),
}
}
@@ -982,13 +1000,6 @@ where
it.into_iter().map(|(k, v)| (g(k), f(v))).collect()
}
-pub fn map_opt_box<T, U, F>(x: &Option<Rc<T>>, f: F) -> Option<Rc<U>>
-where
- F: FnOnce(&T) -> U,
-{
- x.as_ref().map(|x| x.as_ref()).map(f).map(bx)
-}
-
fn map_op2<T, U, V, F, G>(f: F, g: G, a: T, b: T) -> V
where
F: FnOnce(U, U) -> V,
@@ -1068,10 +1079,14 @@ where
/// descend into a lambda or let expression that binds a variable of the same
/// name in order to avoid shifting the bound variables by mistake.
///
-pub fn shift<S, T, A: Clone>(d: isize, v: &V, e: &Expr<S, A>) -> Expr<T, A> {
+pub fn shift<S, T, A: Clone>(
+ d: isize,
+ v: &V,
+ e: &Rc<Expr<S, A>>,
+) -> Rc<Expr<T, A>> {
use crate::Expr::*;
let V(x, n) = v;
- match e {
+ rc(match e.as_ref() {
Const(a) => Const(*a),
Var(V(x2, n2)) => {
let n3 = if x == x2 && n <= n2 {
@@ -1085,80 +1100,68 @@ pub fn shift<S, T, A: Clone>(d: isize, v: &V, e: &Expr<S, A>) -> Expr<T, A> {
let n2 = if x == x2 { n + 1 } else { *n };
let tA2 = shift(d, v, tA);
let b2 = shift(d, &V(x.clone(), n2), b);
- Lam(x2.clone(), bx(tA2), bx(b2))
+ Lam(x2.clone(), tA2, b2)
}
Pi(x2, tA, tB) => {
let n2 = if x == x2 { n + 1 } else { *n };
let tA2 = shift(d, v, tA);
let tB2 = shift(d, &V(x.clone(), n2), tB);
- Pi(x2.clone(), bx(tA2), bx(tB2))
+ Pi(x2.clone(), tA2, tB2)
}
App(f, args) => {
let f = shift(d, v, f);
- let args = args.iter().map(|a| bx(shift(d, v, a))).collect();
- app(f, args)
+ let args = args.iter().map(|a| shift(d, v, a)).collect();
+ App(f, args)
}
Let(f, mt, r, e) => {
let n2 = if x == f { n + 1 } else { *n };
let e2 = shift(d, &V(x.clone(), n2), e);
- let mt2 = mt.as_ref().map(|t| bx(shift(d, v, t)));
+ let mt2 = mt.as_ref().map(|t| shift(d, v, t));
let r2 = shift(d, v, r);
- Let(f.clone(), mt2, bx(r2), bx(e2))
+ Let(f.clone(), mt2, r2, e2)
}
- Annot(a, b) => shift_op2(Annot, d, v, a, b),
+ Annot(a, b) => map_op2(Annot, |x| shift(d, v, x), a, b),
Builtin(v) => Builtin(*v),
BoolLit(a) => BoolLit(*a),
- BinOp(o, a, b) => shift_op2(|x, y| BinOp(*o, x, y), d, v, a, b),
+ BinOp(o, a, b) => {
+ map_op2(|x, y| BinOp(*o, x, y), |x| shift(d, v, x), a, b)
+ }
BoolIf(a, b, c) => {
- BoolIf(bx(shift(d, v, a)), bx(shift(d, v, b)), bx(shift(d, v, c)))
+ BoolIf(shift(d, v, a), shift(d, v, b), shift(d, v, c))
}
NaturalLit(a) => NaturalLit(*a),
IntegerLit(a) => IntegerLit(*a),
DoubleLit(a) => DoubleLit(*a),
- TextLit(a) => TextLit(a.map(|e| bx(shift(d, v, &*e)))),
+ TextLit(a) => TextLit(a.map(|e| shift(d, v, &*e))),
ListLit(t, es) => ListLit(
- t.as_ref().map(|t| bx(shift(d, v, t))),
- es.iter().map(|e| bx(shift(d, v, e))).collect(),
+ t.as_ref().map(|t| shift(d, v, t)),
+ es.iter().map(|e| shift(d, v, e)).collect(),
),
OptionalLit(t, e) => OptionalLit(
- t.as_ref().map(|t| bx(shift(d, v, t))),
- e.as_ref().map(|t| bx(shift(d, v, t))),
+ t.as_ref().map(|t| shift(d, v, t)),
+ e.as_ref().map(|t| shift(d, v, t)),
),
- Record(a) => Record(map_record_value(a, |val| bx(shift(d, v, &*val)))),
+ Record(a) => Record(map_record_value(a, |val| shift(d, v, &*val))),
RecordLit(a) => {
- RecordLit(map_record_value(a, |val| bx(shift(d, v, &*val))))
+ RecordLit(map_record_value(a, |val| shift(d, v, &*val)))
}
- Union(a) => Union(map_record_value(a, |val| bx(shift(d, v, &*val)))),
+ Union(a) => Union(map_record_value(a, |val| shift(d, v, &*val))),
UnionLit(k, uv, a) => UnionLit(
k.clone(),
- bx(shift(d, v, uv)),
- map_record_value(a, |val| bx(shift(d, v, &*val))),
+ shift(d, v, uv),
+ map_record_value(a, |val| shift(d, v, &*val)),
),
Merge(a, b, c) => Merge(
- bx(shift(d, v, a)),
- bx(shift(d, v, b)),
- c.as_ref().map(|c| bx(shift(d, v, c))),
+ shift(d, v, a),
+ shift(d, v, b),
+ c.as_ref().map(|c| shift(d, v, c)),
),
- Field(a, b) => Field(bx(shift(d, v, a)), b.clone()),
- Note(_, b) => shift(d, v, b),
+ Field(a, b) => Field(shift(d, v, a), b.clone()),
+ Note(_, b) => return shift(d, v, b),
// The Dhall compiler enforces that all embedded values are closed expressions
// and `shift` does nothing to a closed expression
Embed(p) => Embed(p.clone()),
- }
-}
-
-fn shift_op2<S, T, A, F>(
- f: F,
- d: isize,
- v: &V,
- a: &Expr<S, A>,
- b: &Expr<S, A>,
-) -> Expr<T, A>
-where
- F: FnOnce(Rc<Expr<T, A>>, Rc<Expr<T, A>>) -> Expr<T, A>,
- A: Clone,
-{
- map_op2(f, |x| bx(shift(d, v, x)), a, b)
+ })
}
/// Substitute all occurrences of a variable with an expression
@@ -1167,37 +1170,41 @@ where
/// subst x C B ~ B[x := C]
/// ```
///
-pub fn subst<S, T, A>(v: &V, e: &Expr<S, A>, b: &Expr<T, A>) -> Expr<S, A>
+pub fn subst<S, T, A>(
+ v: &V,
+ e: &Rc<Expr<S, A>>,
+ b: &Rc<Expr<T, A>>,
+) -> Rc<Expr<S, A>>
where
S: Clone,
A: Clone,
{
use crate::Expr::*;
let V(x, n) = v;
- match b {
+ rc(match b.as_ref() {
Const(a) => Const(*a),
Lam(y, tA, b) => {
let n2 = if x == y { n + 1 } else { *n };
let b2 =
subst(&V(x.clone(), n2), &shift(1, &V(y.clone(), 0), e), b);
let tA2 = subst(v, e, tA);
- Lam(y.clone(), bx(tA2), bx(b2))
+ Lam(y.clone(), tA2, b2)
}
Pi(y, tA, tB) => {
let n2 = if x == y { n + 1 } else { *n };
let tB2 =
subst(&V(x.clone(), n2), &shift(1, &V(y.clone(), 0), e), tB);
let tA2 = subst(v, e, tA);
- Pi(y.clone(), bx(tA2), bx(tB2))
+ Pi(y.clone(), tA2, tB2)
}
App(f, args) => {
let f2 = subst(v, e, f);
- let args = args.iter().map(|a| bx(subst(v, e, a))).collect();
- app(f2, args)
+ let args = args.iter().map(|a| subst(v, e, a)).collect();
+ App(f2, args)
}
Var(v2) => {
if v == v2 {
- e.clone()
+ return e.clone();
} else {
Var(v2.clone())
}
@@ -1206,63 +1213,50 @@ where
let n2 = if x == f { n + 1 } else { *n };
let b2 =
subst(&V(x.clone(), n2), &shift(1, &V(f.clone(), 0), e), b);
- let mt2 = mt.as_ref().map(|t| bx(subst(v, e, t)));
+ let mt2 = mt.as_ref().map(|t| subst(v, e, t));
let r2 = subst(v, e, r);
- Let(f.clone(), mt2, bx(r2), bx(b2))
+ Let(f.clone(), mt2, r2, b2)
}
- Annot(a, b) => subst_op2(Annot, v, e, a, b),
+ Annot(a, b) => map_op2(Annot, |x| subst(v, e, x), a, b),
Builtin(v) => Builtin(*v),
BoolLit(a) => BoolLit(*a),
- BinOp(o, a, b) => subst_op2(|x, y| BinOp(*o, x, y), v, e, a, b),
+ BinOp(o, a, b) => {
+ map_op2(|x, y| BinOp(*o, x, y), |x| subst(v, e, x), a, b)
+ }
BoolIf(a, b, c) => {
- BoolIf(bx(subst(v, e, a)), bx(subst(v, e, b)), bx(subst(v, e, c)))
+ BoolIf(subst(v, e, a), subst(v, e, b), subst(v, e, c))
}
NaturalLit(a) => NaturalLit(*a),
IntegerLit(a) => IntegerLit(*a),
DoubleLit(a) => DoubleLit(*a),
- TextLit(a) => TextLit(a.map(|b| bx(subst(v, e, &*b)))),
+ TextLit(a) => TextLit(a.map(|b| subst(v, e, &*b))),
ListLit(a, b) => {
- let a2 = a.as_ref().map(|a| bx(subst(v, e, a)));
- let b2 = b.iter().map(|be| bx(subst(v, e, be))).collect();
+ let a2 = a.as_ref().map(|a| subst(v, e, a));
+ let b2 = b.iter().map(|be| subst(v, e, be)).collect();
ListLit(a2, b2)
}
OptionalLit(a, b) => {
- let a2 = a.as_ref().map(|a| bx(subst(v, e, a)));
- let b2 = b.as_ref().map(|a| bx(subst(v, e, a)));
+ let a2 = a.as_ref().map(|a| subst(v, e, a));
+ let b2 = b.as_ref().map(|a| subst(v, e, a));
OptionalLit(a2, b2)
}
- Record(kts) => Record(map_record_value(kts, |t| bx(subst(v, e, &*t)))),
+ Record(kts) => Record(map_record_value(kts, |t| subst(v, e, &*t))),
RecordLit(kvs) => {
- RecordLit(map_record_value(kvs, |val| bx(subst(v, e, &*val))))
+ RecordLit(map_record_value(kvs, |val| subst(v, e, &*val)))
}
- Union(kts) => Union(map_record_value(kts, |t| bx(subst(v, e, &*t)))),
+ Union(kts) => Union(map_record_value(kts, |t| subst(v, e, &*t))),
UnionLit(k, uv, kvs) => UnionLit(
k.clone(),
- bx(subst(v, e, uv)),
- map_record_value(kvs, |val| bx(subst(v, e, &*val))),
+ subst(v, e, uv),
+ map_record_value(kvs, |val| subst(v, e, &*val)),
),
Merge(a, b, c) => Merge(
- bx(subst(v, e, a)),
- bx(subst(v, e, b)),
- c.as_ref().map(|c| bx(subst(v, e, c))),
+ subst(v, e, a),
+ subst(v, e, b),
+ c.as_ref().map(|c| subst(v, e, c)),
),
- Field(a, b) => Field(bx(subst(v, e, a)), b.clone()),
- Note(_, b) => subst(v, e, b),
+ Field(a, b) => Field(subst(v, e, a), b.clone()),
+ Note(_, b) => return subst(v, e, b),
Embed(p) => Embed(p.clone()),
- }
-}
-
-fn subst_op2<S, T, A, F>(
- f: F,
- v: &V,
- e: &Expr<S, A>,
- a: &Expr<T, A>,
- b: &Expr<T, A>,
-) -> Expr<S, A>
-where
- F: FnOnce(Rc<Expr<S, A>>, Rc<Expr<S, A>>) -> Expr<S, A>,
- S: Clone,
- A: Clone,
-{
- map_op2(f, |x| bx(subst(v, e, x)), a, b)
+ })
}
diff --git a/dhall_generator/src/lib.rs b/dhall_generator/src/lib.rs
index 26be4c4..9c0aacf 100644
--- a/dhall_generator/src/lib.rs
+++ b/dhall_generator/src/lib.rs
@@ -13,11 +13,11 @@ pub fn dhall_expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let no_import =
|_: &Import| -> X { panic!("Don't use import in dhall!()") };
let expr = expr.map_embed(&no_import);
- let output = dhall_to_tokenstream(&expr, &Context::new());
+ let output = dhall_to_tokenstream_bx(&expr, &Context::new());
output.into()
}
-// Returns an expression of type Expr<_, _>. Expects input variables
+// Returns an expression of type Expr<_, _>. Expects interpolated variables
// to be of type Rc<Expr<_, _>>.
fn dhall_to_tokenstream(
expr: &Expr<X, X>,