diff options
Diffstat (limited to 'dhall/src/phase')
-rw-r--r-- | dhall/src/phase/normalize.rs | 199 | ||||
-rw-r--r-- | dhall/src/phase/typecheck.rs | 33 |
2 files changed, 112 insertions, 120 deletions
diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs index 2253ae0..be2ba51 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/phase/normalize.rs @@ -14,6 +14,7 @@ use crate::phase::{NormalizedSubExpr, ResolvedSubExpr, Typed}; pub type InputSubExpr = ResolvedSubExpr; pub type OutputSubExpr = NormalizedSubExpr; +#[allow(clippy::cognitive_complexity)] pub fn apply_builtin(b: Builtin, args: Vec<Thunk>) -> Value { use dhall_syntax::Builtin::*; use Value::*; @@ -206,7 +207,7 @@ pub fn apply_builtin(b: Builtin, args: Vec<Thunk>) -> Value { (NaturalBuild, [f, r..]) => match &*f.as_value() { // fold/build fusion Value::AppliedBuiltin(NaturalFold, args) => { - if args.len() >= 1 { + if !args.is_empty() { Ok((r, args[0].to_value())) } else { // Do we really need to handle this case ? @@ -365,10 +366,10 @@ pub fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value { // Small helper enum to avoid repetition enum Ret<'a> { - RetValue(Value), - RetThunk(Thunk), - RetThunkRef(&'a Thunk), - RetExpr(ExprF<Thunk, X>), + Value(Value), + Thunk(Thunk), + ThunkRef(&'a Thunk), + Expr(ExprF<Thunk, X>), } fn merge_maps<K, V>( @@ -402,7 +403,6 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge, TextAppend, }; - use Ret::{RetThunkRef, RetValue}; use Value::{ BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType, TextLit, @@ -410,65 +410,69 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { let x_borrow = x.as_value(); let y_borrow = y.as_value(); Some(match (o, &*x_borrow, &*y_borrow) { - (BoolAnd, BoolLit(true), _) => RetThunkRef(y), - (BoolAnd, _, BoolLit(true)) => RetThunkRef(x), - (BoolAnd, BoolLit(false), _) => RetValue(BoolLit(false)), - (BoolAnd, _, BoolLit(false)) => RetValue(BoolLit(false)), - (BoolAnd, _, _) if x == y => RetThunkRef(x), - (BoolOr, BoolLit(true), _) => RetValue(BoolLit(true)), - (BoolOr, _, BoolLit(true)) => RetValue(BoolLit(true)), - (BoolOr, BoolLit(false), _) => RetThunkRef(y), - (BoolOr, _, BoolLit(false)) => RetThunkRef(x), - (BoolOr, _, _) if x == y => RetThunkRef(x), - (BoolEQ, BoolLit(true), _) => RetThunkRef(y), - (BoolEQ, _, BoolLit(true)) => RetThunkRef(x), - (BoolEQ, BoolLit(x), BoolLit(y)) => RetValue(BoolLit(x == y)), - (BoolEQ, _, _) if x == y => RetValue(BoolLit(true)), - (BoolNE, BoolLit(false), _) => RetThunkRef(y), - (BoolNE, _, BoolLit(false)) => RetThunkRef(x), - (BoolNE, BoolLit(x), BoolLit(y)) => RetValue(BoolLit(x != y)), - (BoolNE, _, _) if x == y => RetValue(BoolLit(false)), + (BoolAnd, BoolLit(true), _) => Ret::ThunkRef(y), + (BoolAnd, _, BoolLit(true)) => Ret::ThunkRef(x), + (BoolAnd, BoolLit(false), _) => Ret::Value(BoolLit(false)), + (BoolAnd, _, BoolLit(false)) => Ret::Value(BoolLit(false)), + (BoolAnd, _, _) if x == y => Ret::ThunkRef(x), + (BoolOr, BoolLit(true), _) => Ret::Value(BoolLit(true)), + (BoolOr, _, BoolLit(true)) => Ret::Value(BoolLit(true)), + (BoolOr, BoolLit(false), _) => Ret::ThunkRef(y), + (BoolOr, _, BoolLit(false)) => Ret::ThunkRef(x), + (BoolOr, _, _) if x == y => Ret::ThunkRef(x), + (BoolEQ, BoolLit(true), _) => Ret::ThunkRef(y), + (BoolEQ, _, BoolLit(true)) => Ret::ThunkRef(x), + (BoolEQ, BoolLit(x), BoolLit(y)) => Ret::Value(BoolLit(x == y)), + (BoolEQ, _, _) if x == y => Ret::Value(BoolLit(true)), + (BoolNE, BoolLit(false), _) => Ret::ThunkRef(y), + (BoolNE, _, BoolLit(false)) => Ret::ThunkRef(x), + (BoolNE, BoolLit(x), BoolLit(y)) => Ret::Value(BoolLit(x != y)), + (BoolNE, _, _) if x == y => Ret::Value(BoolLit(false)), - (NaturalPlus, NaturalLit(0), _) => RetThunkRef(y), - (NaturalPlus, _, NaturalLit(0)) => RetThunkRef(x), + (NaturalPlus, NaturalLit(0), _) => Ret::ThunkRef(y), + (NaturalPlus, _, NaturalLit(0)) => Ret::ThunkRef(x), (NaturalPlus, NaturalLit(x), NaturalLit(y)) => { - RetValue(NaturalLit(x + y)) + Ret::Value(NaturalLit(x + y)) } - (NaturalTimes, NaturalLit(0), _) => RetValue(NaturalLit(0)), - (NaturalTimes, _, NaturalLit(0)) => RetValue(NaturalLit(0)), - (NaturalTimes, NaturalLit(1), _) => RetThunkRef(y), - (NaturalTimes, _, NaturalLit(1)) => RetThunkRef(x), + (NaturalTimes, NaturalLit(0), _) => Ret::Value(NaturalLit(0)), + (NaturalTimes, _, NaturalLit(0)) => Ret::Value(NaturalLit(0)), + (NaturalTimes, NaturalLit(1), _) => Ret::ThunkRef(y), + (NaturalTimes, _, NaturalLit(1)) => Ret::ThunkRef(x), (NaturalTimes, NaturalLit(x), NaturalLit(y)) => { - RetValue(NaturalLit(x * y)) + Ret::Value(NaturalLit(x * y)) } - (ListAppend, EmptyListLit(_), _) => RetThunkRef(y), - (ListAppend, _, EmptyListLit(_)) => RetThunkRef(x), + (ListAppend, EmptyListLit(_), _) => Ret::ThunkRef(y), + (ListAppend, _, EmptyListLit(_)) => Ret::ThunkRef(x), (ListAppend, NEListLit(xs), NEListLit(ys)) => { - RetValue(NEListLit(xs.iter().chain(ys.iter()).cloned().collect())) + Ret::Value(NEListLit(xs.iter().chain(ys.iter()).cloned().collect())) } - (TextAppend, TextLit(x), _) if x.is_empty() => RetThunkRef(y), - (TextAppend, _, TextLit(y)) if y.is_empty() => RetThunkRef(x), - (TextAppend, TextLit(x), TextLit(y)) => { - RetValue(TextLit(squash_textlit(x.iter().chain(y.iter()).cloned()))) - } + (TextAppend, TextLit(x), _) if x.is_empty() => Ret::ThunkRef(y), + (TextAppend, _, TextLit(y)) if y.is_empty() => Ret::ThunkRef(x), + (TextAppend, TextLit(x), TextLit(y)) => Ret::Value(TextLit( + squash_textlit(x.iter().chain(y.iter()).cloned()), + )), (TextAppend, TextLit(x), _) => { use std::iter::once; let y = InterpolatedTextContents::Expr(y.clone()); - RetValue(TextLit(squash_textlit(x.iter().cloned().chain(once(y))))) + Ret::Value(TextLit(squash_textlit( + x.iter().cloned().chain(once(y)), + ))) } (TextAppend, _, TextLit(y)) => { use std::iter::once; let x = InterpolatedTextContents::Expr(x.clone()); - RetValue(TextLit(squash_textlit(once(x).chain(y.iter().cloned())))) + Ret::Value(TextLit(squash_textlit( + once(x).chain(y.iter().cloned()), + ))) } (RightBiasedRecordMerge, _, RecordLit(kvs)) if kvs.is_empty() => { - RetThunkRef(x) + Ret::ThunkRef(x) } (RightBiasedRecordMerge, RecordLit(kvs), _) if kvs.is_empty() => { - RetThunkRef(y) + Ret::ThunkRef(y) } (RightBiasedRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { let mut kvs = kvs2.clone(); @@ -476,14 +480,14 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { // Insert only if key not already present kvs.entry(x.clone()).or_insert_with(|| v.clone()); } - RetValue(RecordLit(kvs)) + Ret::Value(RecordLit(kvs)) } (RecursiveRecordMerge, _, RecordLit(kvs)) if kvs.is_empty() => { - RetThunkRef(x) + Ret::ThunkRef(x) } (RecursiveRecordMerge, RecordLit(kvs), _) if kvs.is_empty() => { - RetThunkRef(y) + Ret::ThunkRef(y) } (RecursiveRecordMerge, RecordLit(kvs1), RecordLit(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { @@ -493,14 +497,14 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { v2.clone(), )) }); - RetValue(RecordLit(kvs)) + Ret::Value(RecordLit(kvs)) } (RecursiveRecordTypeMerge, _, RecordType(kvs)) if kvs.is_empty() => { - RetThunkRef(x) + Ret::ThunkRef(x) } (RecursiveRecordTypeMerge, RecordType(kvs), _) if kvs.is_empty() => { - RetThunkRef(y) + Ret::ThunkRef(y) } (RecursiveRecordTypeMerge, RecordType(kvs1), RecordType(kvs2)) => { let kvs = merge_maps(kvs1, kvs2, |v1, v2| { @@ -510,7 +514,7 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { v2.to_thunk(), ))) }); - RetValue(RecordType(kvs)) + Ret::Value(RecordType(kvs)) } _ => return None, @@ -518,7 +522,6 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> { } pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { - use Ret::{RetExpr, RetThunk, RetThunkRef, RetValue}; use Value::{ BoolLit, DoubleLit, EmptyListLit, EmptyOptionalLit, IntegerLit, Lam, NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, @@ -528,51 +531,53 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { let ret = match expr { ExprF::Embed(_) => unreachable!(), ExprF::Var(_) => unreachable!(), - ExprF::Annot(x, _) => RetThunk(x), + ExprF::Annot(x, _) => Ret::Thunk(x), ExprF::Lam(x, t, e) => { - RetValue(Lam(x.into(), TypeThunk::from_thunk(t), e)) + Ret::Value(Lam(x.into(), TypeThunk::from_thunk(t), e)) } - ExprF::Pi(x, t, e) => RetValue(Pi( + ExprF::Pi(x, t, e) => Ret::Value(Pi( x.into(), TypeThunk::from_thunk(t), TypeThunk::from_thunk(e), )), ExprF::Let(x, _, v, b) => { let v = Typed::from_thunk_untyped(v); - RetThunk(b.subst_shift(&x.into(), &v)) - } - ExprF::App(v, a) => RetValue(v.app_thunk(a)), - ExprF::Builtin(b) => RetValue(Value::from_builtin(b)), - ExprF::Const(c) => RetValue(Value::Const(c)), - ExprF::BoolLit(b) => RetValue(BoolLit(b)), - ExprF::NaturalLit(n) => RetValue(NaturalLit(n)), - ExprF::IntegerLit(n) => RetValue(IntegerLit(n)), - ExprF::DoubleLit(n) => RetValue(DoubleLit(n)), + Ret::Thunk(b.subst_shift(&x.into(), &v)) + } + ExprF::App(v, a) => Ret::Value(v.app_thunk(a)), + ExprF::Builtin(b) => Ret::Value(Value::from_builtin(b)), + ExprF::Const(c) => Ret::Value(Value::Const(c)), + ExprF::BoolLit(b) => Ret::Value(BoolLit(b)), + ExprF::NaturalLit(n) => Ret::Value(NaturalLit(n)), + ExprF::IntegerLit(n) => Ret::Value(IntegerLit(n)), + ExprF::DoubleLit(n) => Ret::Value(DoubleLit(n)), ExprF::OldOptionalLit(None, t) => { - RetValue(EmptyOptionalLit(TypeThunk::from_thunk(t))) + Ret::Value(EmptyOptionalLit(TypeThunk::from_thunk(t))) } - ExprF::OldOptionalLit(Some(e), _) => RetValue(NEOptionalLit(e)), - ExprF::SomeLit(e) => RetValue(NEOptionalLit(e)), + ExprF::OldOptionalLit(Some(e), _) => Ret::Value(NEOptionalLit(e)), + ExprF::SomeLit(e) => Ret::Value(NEOptionalLit(e)), ExprF::EmptyListLit(t) => { - RetValue(EmptyListLit(TypeThunk::from_thunk(t))) + Ret::Value(EmptyListLit(TypeThunk::from_thunk(t))) } ExprF::NEListLit(elts) => { - RetValue(NEListLit(elts.into_iter().collect())) + Ret::Value(NEListLit(elts.into_iter().collect())) + } + ExprF::RecordLit(kvs) => { + Ret::Value(RecordLit(kvs.into_iter().collect())) } - ExprF::RecordLit(kvs) => RetValue(RecordLit(kvs.into_iter().collect())), - ExprF::RecordType(kts) => RetValue(RecordType( + ExprF::RecordType(kts) => Ret::Value(RecordType( kts.into_iter() .map(|(k, t)| (k, TypeThunk::from_thunk(t))) .collect(), )), - ExprF::UnionLit(l, x, kts) => RetValue(UnionLit( + ExprF::UnionLit(l, x, kts) => Ret::Value(UnionLit( l, x, kts.into_iter() .map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t)))) .collect(), )), - ExprF::UnionType(kts) => RetValue(UnionType( + ExprF::UnionType(kts) => Ret::Value(UnionType( kts.into_iter() .map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t)))) .collect(), @@ -582,28 +587,28 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { let elts: Vec<_> = squash_textlit(elts.into_iter()); // Simplify bare interpolation if let [Expr(th)] = elts.as_slice() { - RetThunk(th.clone()) + Ret::Thunk(th.clone()) } else { - RetValue(TextLit(elts)) + Ret::Value(TextLit(elts)) } } ExprF::BoolIf(ref b, ref e1, ref e2) => { let b_borrow = b.as_value(); match &*b_borrow { - BoolLit(true) => RetThunkRef(e1), - BoolLit(false) => RetThunkRef(e2), + BoolLit(true) => Ret::ThunkRef(e1), + BoolLit(false) => Ret::ThunkRef(e2), _ => { let e1_borrow = e1.as_value(); let e2_borrow = e2.as_value(); match (&*e1_borrow, &*e2_borrow) { // Simplify `if b then True else False` - (BoolLit(true), BoolLit(false)) => RetThunkRef(b), - _ if e1 == e2 => RetThunkRef(e1), + (BoolLit(true), BoolLit(false)) => Ret::ThunkRef(b), + _ if e1 == e2 => Ret::ThunkRef(e1), _ => { drop(b_borrow); drop(e1_borrow); drop(e2_borrow); - RetExpr(expr) + Ret::Expr(expr) } } } @@ -611,16 +616,16 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { } ExprF::BinOp(o, ref x, ref y) => match apply_binop(o, x, y) { Some(ret) => ret, - None => RetExpr(expr), + None => Ret::Expr(expr), }, ExprF::Projection(_, ls) if ls.is_empty() => { - RetValue(RecordLit(HashMap::new())) + Ret::Value(RecordLit(HashMap::new())) } ExprF::Projection(ref v, ref ls) => { let v_borrow = v.as_value(); match &*v_borrow { - RecordLit(kvs) => RetValue(RecordLit( + RecordLit(kvs) => Ret::Value(RecordLit( ls.iter() .filter_map(|l| { kvs.get(l).map(|x| (l.clone(), x.clone())) @@ -629,7 +634,7 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { )), _ => { drop(v_borrow); - RetExpr(expr) + Ret::Expr(expr) } } } @@ -637,18 +642,18 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { let v_borrow = v.as_value(); match &*v_borrow { RecordLit(kvs) => match kvs.get(l) { - Some(r) => RetThunk(r.clone()), + Some(r) => Ret::Thunk(r.clone()), None => { drop(v_borrow); - RetExpr(expr) + Ret::Expr(expr) } }, UnionType(kts) => { - RetValue(UnionConstructor(l.clone(), kts.clone())) + Ret::Value(UnionConstructor(l.clone(), kts.clone())) } _ => { drop(v_borrow); - RetExpr(expr) + Ret::Expr(expr) } } } @@ -658,34 +663,34 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value { let variant_borrow = variant.as_value(); match (&*handlers_borrow, &*variant_borrow) { (RecordLit(kvs), UnionConstructor(l, _)) => match kvs.get(l) { - Some(h) => RetThunk(h.clone()), + Some(h) => Ret::Thunk(h.clone()), None => { drop(handlers_borrow); drop(variant_borrow); - RetExpr(expr) + Ret::Expr(expr) } }, (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) { - Some(h) => RetValue(h.app_thunk(v.clone())), + Some(h) => Ret::Value(h.app_thunk(v.clone())), None => { drop(handlers_borrow); drop(variant_borrow); - RetExpr(expr) + Ret::Expr(expr) } }, _ => { drop(handlers_borrow); drop(variant_borrow); - RetExpr(expr) + Ret::Expr(expr) } } } }; match ret { - RetValue(v) => v, - RetThunk(th) => th.to_value(), - RetThunkRef(th) => th.to_value(), - RetExpr(expr) => Value::PartialExpr(expr), + Ret::Value(v) => v, + Ret::Thunk(th) => th.to_value(), + Ret::ThunkRef(th) => th.to_value(), + Ret::Expr(expr) => Value::PartialExpr(expr), } } diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs index bb36060..419b2e2 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/phase/typecheck.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] -use std::borrow::Borrow; use std::collections::HashMap; use dhall_proc_macros as dhall; @@ -17,7 +15,7 @@ use crate::phase::{Normalized, Resolved, Type, Typed}; macro_rules! ensure_equal { ($x:expr, $y:expr, $err:expr $(,)*) => { - if !prop_equal($x, $y) { + if $x.to_value() != $y.to_value() { return Err($err); } }; @@ -42,7 +40,7 @@ fn tck_pi_type( use crate::error::TypeMessage::*; let ctx2 = ctx.insert_type(&x, tx.clone()); - let kA = match tx.get_type()?.as_const() { + let ka = match tx.get_type()?.as_const() { Some(k) => k, _ => { return Err(TypeError::new( @@ -52,7 +50,7 @@ fn tck_pi_type( } }; - let kB = match te.get_type()?.as_const() { + let kb = match te.get_type()?.as_const() { Some(k) => k, _ => { return Err(TypeError::new( @@ -62,7 +60,7 @@ fn tck_pi_type( } }; - let k = match function_check(kA, kB) { + let k = match function_check(ka, kb) { Ok(k) => k, Err(()) => { return Err(TypeError::new( @@ -109,7 +107,7 @@ fn tck_record_type( return Err(TypeError::new(ctx, RecordTypeDuplicateField)) } Entry::Vacant(_) => { - entry.or_insert(TypeThunk::from_type(t.clone())) + entry.or_insert_with(|| TypeThunk::from_type(t.clone())) } }; } @@ -150,8 +148,9 @@ fn tck_union_type( Entry::Occupied(_) => { return Err(TypeError::new(ctx, UnionTypeDuplicateField)) } - Entry::Vacant(_) => entry - .or_insert(t.as_ref().map(|t| TypeThunk::from_type(t.clone()))), + Entry::Vacant(_) => entry.or_insert_with(|| { + t.as_ref().map(|t| TypeThunk::from_type(t.clone())) + }), }; } @@ -207,24 +206,12 @@ fn function_check(a: Const, b: Const) -> Result<Const, ()> { } } -// Equality up to alpha-equivalence (renaming of bound variables) -fn prop_equal<T, U>(eL0: T, eR0: U) -> bool -where - T: Borrow<Type>, - U: Borrow<Type>, -{ - eL0.borrow().to_value() == eR0.borrow().to_value() -} - pub fn type_of_const(c: Const) -> Result<Type, TypeError> { match c { Const::Type => Ok(Type::from_const(Const::Kind)), Const::Kind => Ok(Type::from_const(Const::Sort)), Const::Sort => { - return Err(TypeError::new( - &TypecheckContext::new(), - TypeMessage::Sort, - )) + Err(TypeError::new(&TypecheckContext::new(), TypeMessage::Sort)) } } } @@ -728,7 +715,7 @@ fn type_last_layer( } (Some(t), None) => Ok(RetTypeOnly(t)), (None, Some(t)) => Ok(RetTypeOnly(t.to_type())), - (None, None) => return Err(mkerr(MergeEmptyNeedsAnnotation)), + (None, None) => Err(mkerr(MergeEmptyNeedsAnnotation)), } } Projection(record, labels) => { |