summaryrefslogtreecommitdiff
path: root/dhall/src
diff options
context:
space:
mode:
Diffstat (limited to 'dhall/src')
-rw-r--r--dhall/src/api/mod.rs4
-rw-r--r--dhall/src/core/thunk.rs8
-rw-r--r--dhall/src/core/value.rs90
-rw-r--r--dhall/src/error/mod.rs6
-rw-r--r--dhall/src/phase/binary.rs178
-rw-r--r--dhall/src/phase/mod.rs3
-rw-r--r--dhall/src/phase/normalize.rs63
-rw-r--r--dhall/src/phase/resolve.rs19
-rw-r--r--dhall/src/phase/typecheck.rs824
-rw-r--r--dhall/src/tests.rs48
10 files changed, 539 insertions, 704 deletions
diff --git a/dhall/src/api/mod.rs b/dhall/src/api/mod.rs
index 233d7cf..188b6c0 100644
--- a/dhall/src/api/mod.rs
+++ b/dhall/src/api/mod.rs
@@ -66,10 +66,6 @@ mod typ {
))
}
#[doc(hidden)]
- pub fn from_normalized_expr(e: NormalizedSubExpr) -> Self {
- Type(Typed::from_normalized_expr_untyped(e))
- }
- #[doc(hidden)]
pub fn make_record_type(
kts: impl Iterator<Item = (String, Type)>,
) -> Self {
diff --git a/dhall/src/core/thunk.rs b/dhall/src/core/thunk.rs
index 5c569e1..f41579c 100644
--- a/dhall/src/core/thunk.rs
+++ b/dhall/src/core/thunk.rs
@@ -111,10 +111,6 @@ impl Thunk {
ThunkInternal::Value(WHNF, v).into_thunk()
}
- pub fn from_normalized_expr(e: OutputSubExpr) -> Thunk {
- Thunk::new(NormalizationContext::new(), e.absurd())
- }
-
pub fn from_partial_expr(e: ExprF<Thunk, X>) -> Thunk {
ThunkInternal::PartialExpr(e).into_thunk()
}
@@ -221,6 +217,10 @@ impl TypeThunk {
self.0.to_type()
}
+ pub fn to_typed(&self) -> Typed {
+ self.0.clone()
+ }
+
pub fn normalize_to_expr_maybe_alpha(&self, alpha: bool) -> OutputSubExpr {
self.normalize_nf().normalize_to_expr_maybe_alpha(alpha)
}
diff --git a/dhall/src/core/value.rs b/dhall/src/core/value.rs
index bc8fa34..0b68bf6 100644
--- a/dhall/src/core/value.rs
+++ b/dhall/src/core/value.rs
@@ -1,6 +1,5 @@
use std::collections::HashMap;
-use dhall_proc_macros as dhall;
use dhall_syntax::{
rc, Builtin, Const, ExprF, Integer, InterpolatedTextContents, Label,
NaiveDouble, Natural, X,
@@ -47,6 +46,7 @@ pub enum Value {
DoubleLit(NaiveDouble),
EmptyOptionalLit(TypeThunk),
NEOptionalLit(Thunk),
+ // EmptyListLit(t) means `[] : List t`, not `[] : t`
EmptyListLit(TypeThunk),
NEListLit(Vec<Thunk>),
RecordLit(HashMap<Label, Thunk>),
@@ -57,6 +57,7 @@ pub enum Value {
// Invariant: this must not contain interpolations that are themselves TextLits, and
// contiguous text values must be merged.
TextLit(Vec<InterpolatedTextContents<Thunk>>),
+ Equivalence(TypeThunk, TypeThunk),
// Invariant: this must not contain a value captured by one of the variants above.
PartialExpr(ExprF<Thunk, X>),
}
@@ -73,6 +74,47 @@ impl Value {
/// Convert the value to a fully normalized syntactic expression. Also alpha-normalize
/// if alpha is `true`
pub fn normalize_to_expr_maybe_alpha(&self, alpha: bool) -> OutputSubExpr {
+ // Ad-hoc macro to help construct the unapplied closures
+ macro_rules! make_expr {
+ (Natural) => { rc(ExprF::Builtin(Builtin::Natural)) };
+ (var($var:ident)) => {
+ rc(ExprF::Var(dhall_syntax::V(stringify!($var).into(), 0)))
+ };
+ ($var:ident) => { $var };
+ (List $($rest:tt)*) => {
+ rc(ExprF::App(
+ rc(ExprF::Builtin(Builtin::List)),
+ make_expr!($($rest)*)
+ ))
+ };
+ (Some $($rest:tt)*) => {
+ rc(ExprF::SomeLit(
+ make_expr!($($rest)*)
+ ))
+ };
+ (1 + $($rest:tt)*) => {
+ rc(ExprF::BinOp(
+ dhall_syntax::BinOp::NaturalPlus,
+ rc(ExprF::NaturalLit(1)),
+ make_expr!($($rest)*)
+ ))
+ };
+ ([ $($head:tt)* ] # $($tail:tt)*) => {
+ rc(ExprF::BinOp(
+ dhall_syntax::BinOp::ListAppend,
+ rc(ExprF::NEListLit(vec![make_expr!($($head)*)])),
+ make_expr!($($tail)*)
+ ))
+ };
+ (λ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => {
+ rc(ExprF::Pi(
+ stringify!($var).into(),
+ make_expr!($($ty)*),
+ make_expr!($($rest)*)
+ ))
+ };
+ }
+
match self {
Value::Lam(x, t, e) => rc(ExprF::Lam(
x.to_label_maybe_alpha(alpha),
@@ -91,24 +133,24 @@ impl Value {
}
Value::OptionalSomeClosure(n) => {
let a = n.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(x: a) -> Some x)
+ make_expr!(λ(x: a) -> Some var(x))
}
Value::ListConsClosure(a, None) => {
// Avoid accidental capture of the new `x` variable
let a1 = a.under_binder(Label::from("x"));
let a1 = a1.normalize_to_expr_maybe_alpha(alpha);
let a = a.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(x : a) -> λ(xs : List a1) -> [ x ] # xs)
+ make_expr!(λ(x : a) -> λ(xs : List a1) -> [ var(x) ] # var(xs))
}
Value::ListConsClosure(n, Some(v)) => {
// Avoid accidental capture of the new `xs` variable
let v = v.under_binder(Label::from("xs"));
let v = v.normalize_to_expr_maybe_alpha(alpha);
let a = n.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(xs : List a) -> [ v ] # xs)
+ make_expr!(λ(xs : List a) -> [ v ] # var(xs))
}
Value::NaturalSuccClosure => {
- dhall::subexpr!(λ(x : Natural) -> x + 1)
+ make_expr!(λ(x : Natural) -> 1 + var(x))
}
Value::Pi(x, t, e) => rc(ExprF::Pi(
x.to_label_maybe_alpha(alpha),
@@ -128,9 +170,10 @@ impl Value {
Value::NEOptionalLit(n) => {
rc(ExprF::SomeLit(n.normalize_to_expr_maybe_alpha(alpha)))
}
- Value::EmptyListLit(n) => {
- rc(ExprF::EmptyListLit(n.normalize_to_expr_maybe_alpha(alpha)))
- }
+ Value::EmptyListLit(n) => rc(ExprF::EmptyListLit(rc(ExprF::App(
+ rc(ExprF::Builtin(Builtin::List)),
+ n.normalize_to_expr_maybe_alpha(alpha),
+ )))),
Value::NEListLit(elts) => rc(ExprF::NEListLit(
elts.iter()
.map(|n| n.normalize_to_expr_maybe_alpha(alpha))
@@ -176,19 +219,10 @@ impl Value {
.collect();
rc(ExprF::Field(rc(ExprF::UnionType(kts)), l.clone()))
}
- Value::UnionLit(l, v, kts) => rc(ExprF::UnionLit(
- l.clone(),
+ Value::UnionLit(l, v, kts) => rc(ExprF::App(
+ Value::UnionConstructor(l.clone(), kts.clone())
+ .normalize_to_expr_maybe_alpha(alpha),
v.normalize_to_expr_maybe_alpha(alpha),
- kts.iter()
- .map(|(k, v)| {
- (
- k.clone(),
- v.as_ref().map(|v| {
- v.normalize_to_expr_maybe_alpha(alpha)
- }),
- )
- })
- .collect(),
)),
Value::TextLit(elts) => {
use InterpolatedTextContents::{Expr, Text};
@@ -203,6 +237,11 @@ impl Value {
.collect(),
))
}
+ Value::Equivalence(x, y) => rc(ExprF::BinOp(
+ dhall_syntax::BinOp::Equivalence,
+ x.normalize_to_expr_maybe_alpha(alpha),
+ y.normalize_to_expr_maybe_alpha(alpha),
+ )),
Value::PartialExpr(e) => {
rc(e.map_ref_simple(|v| v.normalize_to_expr_maybe_alpha(alpha)))
}
@@ -289,6 +328,10 @@ impl Value {
}
}
}
+ Value::Equivalence(x, y) => {
+ x.normalize_mut();
+ y.normalize_mut();
+ }
Value::PartialExpr(e) => {
// TODO: need map_mut_simple
e.map_ref_simple(|v| {
@@ -425,6 +468,9 @@ impl Shift for Value {
})
.collect::<Result<_, _>>()?,
),
+ Value::Equivalence(x, y) => {
+ Value::Equivalence(x.shift(delta, var)?, y.shift(delta, var)?)
+ }
Value::PartialExpr(e) => Value::PartialExpr(
e.traverse_ref_with_special_handling_of_binders(
|v| Ok(v.shift(delta, var)?),
@@ -540,6 +586,10 @@ impl Subst<Typed> for Value {
})
.collect(),
),
+ Value::Equivalence(x, y) => Value::Equivalence(
+ x.subst_shift(var, val),
+ y.subst_shift(var, val),
+ ),
}
}
}
diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs
index aed6ccd..3c00017 100644
--- a/dhall/src/error/mod.rs
+++ b/dhall/src/error/mod.rs
@@ -68,7 +68,6 @@ pub(crate) enum TypeMessage {
MissingRecordField(Label, Typed),
MissingUnionField(Label, Normalized),
BinOpTypeMismatch(BinOp, Typed),
- NoDependentTypes(Normalized, Normalized),
InvalidTextInterpolation(Typed),
Merge1ArgMustBeRecord(Typed),
Merge2ArgMustBeUnion(Typed),
@@ -86,7 +85,10 @@ pub(crate) enum TypeMessage {
RecordTypeMergeRequiresRecordType(Type),
RecordTypeMismatch(Type, Type, Type, Type),
UnionTypeDuplicateField,
- Unimplemented,
+ EquivalenceArgumentMustBeTerm(bool, Typed),
+ EquivalenceTypeMismatch(Typed, Typed),
+ AssertMismatch(Typed, Typed),
+ AssertMustTakeEquivalence,
}
impl TypeError {
diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs
index 3acd2d4..6bdc3f9 100644
--- a/dhall/src/phase/binary.rs
+++ b/dhall/src/phase/binary.rs
@@ -49,10 +49,21 @@ fn cbor_value_to_dhall(
Bool(b) => BoolLit(*b),
Array(vec) => match vec.as_slice() {
[String(l), U64(n)] => {
+ if l.as_str() == "_" {
+ Err(DecodeError::WrongFormatError(
+ "`_` variable was encoded incorrectly".to_owned(),
+ ))?
+ }
let l = Label::from(l.as_str());
Var(V(l, *n as usize))
}
[U64(0), f, args..] => {
+ if args.is_empty() {
+ Err(DecodeError::WrongFormatError(
+ "Function application must have at least one argument"
+ .to_owned(),
+ ))?
+ }
let mut f = cbor_value_to_dhall(&f)?;
for a in args {
let a = cbor_value_to_dhall(&a)?;
@@ -66,6 +77,11 @@ fn cbor_value_to_dhall(
Lam(Label::from("_"), x, y)
}
[U64(1), String(l), x, y] => {
+ if l.as_str() == "_" {
+ Err(DecodeError::WrongFormatError(
+ "`_` variable was encoded incorrectly".to_owned(),
+ ))?
+ }
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
let l = Label::from(l.as_str());
@@ -77,6 +93,11 @@ fn cbor_value_to_dhall(
Pi(Label::from("_"), x, y)
}
[U64(2), String(l), x, y] => {
+ if l.as_str() == "_" {
+ Err(DecodeError::WrongFormatError(
+ "`_` variable was encoded incorrectly".to_owned(),
+ ))?
+ }
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
let l = Label::from(l.as_str());
@@ -99,6 +120,7 @@ fn cbor_value_to_dhall(
9 => RightBiasedRecordMerge,
10 => RecursiveRecordTypeMerge,
11 => ImportAlt,
+ 12 => Equivalence,
_ => {
Err(DecodeError::WrongFormatError("binop".to_owned()))?
}
@@ -107,7 +129,7 @@ fn cbor_value_to_dhall(
}
[U64(4), t] => {
let t = cbor_value_to_dhall(&t)?;
- EmptyListLit(t)
+ EmptyListLit(rc(App(rc(ExprF::Builtin(Builtin::List)), t)))
}
[U64(4), Null, rest..] => {
let rest = rest
@@ -116,18 +138,22 @@ fn cbor_value_to_dhall(
.collect::<Result<Vec<_>, _>>()?;
NEListLit(rest)
}
- [U64(5), t] => {
- let t = cbor_value_to_dhall(&t)?;
- OldOptionalLit(None, t)
- }
[U64(5), Null, x] => {
let x = cbor_value_to_dhall(&x)?;
SomeLit(x)
}
+ // Old-style optional literals
+ [U64(5), t] => {
+ let t = cbor_value_to_dhall(&t)?;
+ App(rc(ExprF::Builtin(Builtin::OptionalNone)), t)
+ }
[U64(5), t, x] => {
let x = cbor_value_to_dhall(&x)?;
let t = cbor_value_to_dhall(&t)?;
- OldOptionalLit(Some(x), t)
+ Annot(
+ rc(SomeLit(x)),
+ rc(App(rc(ExprF::Builtin(Builtin::Optional)), t)),
+ )
}
[U64(6), x, y] => {
let x = cbor_value_to_dhall(&x)?;
@@ -153,16 +179,26 @@ fn cbor_value_to_dhall(
let l = Label::from(l.as_str());
Field(x, l)
}
+ [U64(10), x, rest..] => {
+ let x = cbor_value_to_dhall(&x)?;
+ let labels = rest
+ .iter()
+ .map(|s| match s {
+ String(s) => Ok(Label::from(s.as_str())),
+ _ => Err(DecodeError::WrongFormatError(
+ "projection".to_owned(),
+ )),
+ })
+ .collect::<Result<_, _>>()?;
+ Projection(x, labels)
+ }
[U64(11), Object(map)] => {
let map = cbor_map_to_dhall_opt_map(map)?;
UnionType(map)
}
- [U64(12), String(l), x, Object(map)] => {
- let map = cbor_map_to_dhall_opt_map(map)?;
- let x = cbor_value_to_dhall(&x)?;
- let l = Label::from(l.as_str());
- UnionLit(l, x, map)
- }
+ [U64(12), ..] => Err(DecodeError::WrongFormatError(
+ "Union literals are not supported anymore".to_owned(),
+ ))?,
[U64(14), x, y, z] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
@@ -190,10 +226,19 @@ fn cbor_value_to_dhall(
.collect::<Result<_, _>>()?,
)))
}
+ [U64(19), t] => {
+ let t = cbor_value_to_dhall(&t)?;
+ Assert(t)
+ }
[U64(24), hash, U64(mode), U64(scheme), rest..] => {
let mode = match mode {
+ 0 => ImportMode::Code,
1 => ImportMode::RawText,
- _ => ImportMode::Code,
+ 2 => ImportMode::Location,
+ _ => Err(DecodeError::WrongFormatError(format!(
+ "import/mode/unknown_mode: {:?}",
+ mode
+ )))?,
};
let hash = match hash {
Null => None,
@@ -217,18 +262,20 @@ fn cbor_value_to_dhall(
};
let headers = match rest.next() {
Some(Null) => None,
- Some(x) => {
- match cbor_value_to_dhall(&x)?.as_ref() {
- Embed(import) => Some(Box::new(
- import.location_hashed.clone(),
- )),
- _ => Err(DecodeError::WrongFormatError(
- "import/remote/headers".to_owned(),
- ))?,
- }
- }
+ // TODO
+ // Some(x) => {
+ // match cbor_value_to_dhall(&x)?.as_ref() {
+ // Embed(import) => Some(Box::new(
+ // import.location_hashed.clone(),
+ // )),
+ // _ => Err(DecodeError::WrongFormatError(
+ // "import/remote/headers".to_owned(),
+ // ))?,
+ // }
+ // }
_ => Err(DecodeError::WrongFormatError(
- "import/remote/headers".to_owned(),
+ "import/remote/headers is unimplemented"
+ .to_owned(),
))?,
};
let authority = match rest.next() {
@@ -341,6 +388,10 @@ fn cbor_value_to_dhall(
let y = cbor_value_to_dhall(&y)?;
Annot(x, y)
}
+ [U64(28), x] => {
+ let x = cbor_value_to_dhall(&x)?;
+ EmptyListLit(x)
+ }
_ => Err(DecodeError::WrongFormatError(format!("{:?}", data)))?,
},
_ => Err(DecodeError::WrongFormatError(format!("{:?}", data)))?,
@@ -389,7 +440,6 @@ enum Serialize<'a> {
CBOR(cbor::Value),
RecordMap(&'a DupTreeMap<Label, ParsedSubExpr>),
UnionMap(&'a DupTreeMap<Label, Option<ParsedSubExpr>>),
- Import(&'a Import),
}
macro_rules! count {
@@ -414,6 +464,7 @@ where
S: serde::ser::Serializer,
{
use cbor::Value::{String, I64, U64};
+ use dhall_syntax::Builtin;
use dhall_syntax::ExprF::*;
use std::iter::once;
@@ -455,12 +506,23 @@ where
ser_seq!(ser; tag(2), expr(x), expr(y))
}
Pi(l, x, y) => ser_seq!(ser; tag(2), label(l), expr(x), expr(y)),
- // TODO: multilet
- Let(l, None, x, y) => {
- ser_seq!(ser; tag(25), label(l), null(), expr(x), expr(y))
- }
- Let(l, Some(t), x, y) => {
- ser_seq!(ser; tag(25), label(l), expr(t), expr(x), expr(y))
+ Let(_, _, _, _) => {
+ let (bound_e, bindings) = collect_nested_lets(e);
+ let count = 1 + 3 * bindings.len() + 1;
+
+ use serde::ser::SerializeSeq;
+ let mut ser_seq = ser.serialize_seq(Some(count))?;
+ ser_seq.serialize_element(&tag(25))?;
+ for (l, t, v) in bindings {
+ ser_seq.serialize_element(&label(l))?;
+ match t {
+ Some(t) => ser_seq.serialize_element(&expr(t))?,
+ None => ser_seq.serialize_element(&null())?,
+ }
+ ser_seq.serialize_element(&expr(v))?;
+ }
+ ser_seq.serialize_element(&expr(bound_e))?;
+ ser_seq.end()
}
App(_, _) => {
let (f, args) = collect_nested_applications(e);
@@ -471,10 +533,15 @@ where
)
}
Annot(x, y) => ser_seq!(ser; tag(26), expr(x), expr(y)),
- OldOptionalLit(None, t) => ser_seq!(ser; tag(5), expr(t)),
- OldOptionalLit(Some(x), t) => ser_seq!(ser; tag(5), expr(t), expr(x)),
+ Assert(x) => ser_seq!(ser; tag(19), expr(x)),
SomeLit(x) => ser_seq!(ser; tag(5), null(), expr(x)),
- EmptyListLit(x) => ser_seq!(ser; tag(4), expr(x)),
+ EmptyListLit(x) => match x.as_ref() {
+ App(f, a) => match f.as_ref() {
+ ExprF::Builtin(Builtin::List) => ser_seq!(ser; tag(4), expr(a)),
+ _ => ser_seq!(ser; tag(28), expr(x)),
+ },
+ _ => ser_seq!(ser; tag(28), expr(x)),
+ },
NEListLit(xs) => ser.collect_seq(
once(tag(4)).chain(once(null())).chain(xs.iter().map(expr)),
),
@@ -488,9 +555,6 @@ where
RecordType(map) => ser_seq!(ser; tag(7), RecordMap(map)),
RecordLit(map) => ser_seq!(ser; tag(8), RecordMap(map)),
UnionType(map) => ser_seq!(ser; tag(11), UnionMap(map)),
- UnionLit(l, x, map) => {
- ser_seq!(ser; tag(12), label(l), expr(x), UnionMap(map))
- }
Field(x, l) => ser_seq!(ser; tag(9), expr(x), label(l)),
BinOp(op, x, y) => {
use dhall_syntax::BinOp::*;
@@ -507,6 +571,7 @@ where
RightBiasedRecordMerge => 9,
RecursiveRecordTypeMerge => 10,
ImportAlt => 11,
+ Equivalence => 12,
};
ser_seq!(ser; tag(3), U64(op), expr(x), expr(y))
}
@@ -553,6 +618,7 @@ where
let mode = match import.mode {
ImportMode::Code => 0,
ImportMode::RawText => 1,
+ ImportMode::Location => 2,
};
ser_seq.serialize_element(&U64(mode))?;
@@ -576,12 +642,14 @@ where
ImportLocation::Remote(url) => {
match &url.headers {
None => ser_seq.serialize_element(&Null)?,
- Some(location_hashed) => ser_seq.serialize_element(
- &self::Serialize::Import(&Import {
- mode: ImportMode::Code,
- location_hashed: location_hashed.as_ref().clone(),
- }),
- )?,
+ Some(location_hashed) => {
+ ser_seq.serialize_element(&self::Serialize::Expr(
+ &SubExpr::from_expr_no_note(ExprF::Embed(Import {
+ mode: ImportMode::Code,
+ location_hashed: location_hashed.as_ref().clone(),
+ })),
+ ))?
+ }
};
ser_seq.serialize_element(&url.authority)?;
for p in url.path.clone().into_iter() {
@@ -628,7 +696,6 @@ impl<'a> serde::ser::Serialize for Serialize<'a> {
(cbor::Value::String(k.into()), v)
}))
}
- Serialize::Import(import) => serialize_import(ser, import),
}
}
}
@@ -652,3 +719,26 @@ fn collect_nested_applications<'a, N, E>(
let e = go(e, &mut vec);
(e, vec)
}
+
+type LetBinding<'a, N, E> =
+ (&'a Label, &'a Option<SubExpr<N, E>>, &'a SubExpr<N, E>);
+
+fn collect_nested_lets<'a, N, E>(
+ e: &'a SubExpr<N, E>,
+) -> (&'a SubExpr<N, E>, Vec<LetBinding<'a, N, E>>) {
+ fn go<'a, N, E>(
+ e: &'a SubExpr<N, E>,
+ vec: &mut Vec<LetBinding<'a, N, E>>,
+ ) -> &'a SubExpr<N, E> {
+ match e.as_ref() {
+ ExprF::Let(l, t, v, e) => {
+ vec.push((l, t, v));
+ go(e, vec)
+ }
+ _ => e,
+ }
+ }
+ let mut vec = vec![];
+ let e = go(e, &mut vec);
+ (e, vec)
+}
diff --git a/dhall/src/phase/mod.rs b/dhall/src/phase/mod.rs
index 681b7fe..ccedff2 100644
--- a/dhall/src/phase/mod.rs
+++ b/dhall/src/phase/mod.rs
@@ -127,9 +127,6 @@ impl Typed {
pub fn from_value_untyped(v: Value) -> Self {
Typed::from_thunk_untyped(Thunk::from_value(v))
}
- pub fn from_normalized_expr_untyped(e: NormalizedSubExpr) -> Self {
- Typed::from_thunk_untyped(Thunk::from_normalized_expr(e))
- }
// TODO: Avoid cloning if possible
pub fn to_value(&self) -> Value {
diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs
index 35d32cb..405677a 100644
--- a/dhall/src/phase/normalize.rs
+++ b/dhall/src/phase/normalize.rs
@@ -47,6 +47,17 @@ pub fn apply_builtin(b: Builtin, args: Vec<Thunk>) -> Value {
)),
_ => Err(()),
},
+ (NaturalSubtract, [a, b, r..]) => {
+ match (&*a.as_value(), &*b.as_value()) {
+ (NaturalLit(a), NaturalLit(b)) => {
+ Ok((r, NaturalLit(if b > a { b - a } else { 0 })))
+ }
+ (NaturalLit(0), b) => Ok((r, b.clone())),
+ (_, NaturalLit(0)) => Ok((r, NaturalLit(0))),
+ _ if a == b => Ok((r, NaturalLit(0))),
+ _ => Err(()),
+ }
+ }
(IntegerShow, [n, r..]) => match &*n.as_value() {
IntegerLit(n) => {
let s = if *n < 0 {
@@ -72,6 +83,17 @@ pub fn apply_builtin(b: Builtin, args: Vec<Thunk>) -> Value {
(TextShow, [v, r..]) => match &*v.as_value() {
TextLit(elts) => {
match elts.as_slice() {
+ // Empty string literal.
+ [] => {
+ // Printing InterpolatedText takes care of all the escaping
+ let txt: InterpolatedText<X> =
+ std::iter::empty().collect();
+ let s = txt.to_string();
+ Ok((
+ r,
+ TextLit(vec![InterpolatedTextContents::Text(s)]),
+ ))
+ }
// If there are no interpolations (invariants ensure that when there are no
// interpolations, there is a single Text item) in the literal.
[InterpolatedTextContents::Text(s)] => {
@@ -487,9 +509,9 @@ where
fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> {
use BinOp::{
- BoolAnd, BoolEQ, BoolNE, BoolOr, ListAppend, NaturalPlus, NaturalTimes,
- RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge,
- TextAppend,
+ BoolAnd, BoolEQ, BoolNE, BoolOr, Equivalence, ListAppend, NaturalPlus,
+ NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge,
+ RightBiasedRecordMerge, TextAppend,
};
use Value::{
BoolLit, EmptyListLit, NEListLit, NaturalLit, RecordLit, RecordType,
@@ -605,13 +627,18 @@ fn apply_binop<'a>(o: BinOp, x: &'a Thunk, y: &'a Thunk) -> Option<Ret<'a>> {
Ret::Value(RecordType(kvs))
}
+ (Equivalence, _, _) => Ret::Value(Value::Equivalence(
+ TypeThunk::from_thunk(x.clone()),
+ TypeThunk::from_thunk(y.clone()),
+ )),
+
_ => return None,
})
}
pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value {
use Value::{
- BoolLit, DoubleLit, EmptyListLit, EmptyOptionalLit, IntegerLit, Lam,
+ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit, Lam,
NEListLit, NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType,
TextLit, UnionConstructor, UnionLit, UnionType,
};
@@ -620,6 +647,7 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value {
ExprF::Embed(_) => unreachable!(),
ExprF::Var(_) => unreachable!(),
ExprF::Annot(x, _) => Ret::Thunk(x),
+ ExprF::Assert(_) => Ret::Expr(expr),
ExprF::Lam(x, t, e) => {
Ret::Value(Lam(x.into(), TypeThunk::from_thunk(t), e))
}
@@ -639,13 +667,21 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value {
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) => {
- Ret::Value(EmptyOptionalLit(TypeThunk::from_thunk(t)))
- }
- ExprF::OldOptionalLit(Some(e), _) => Ret::Value(NEOptionalLit(e)),
ExprF::SomeLit(e) => Ret::Value(NEOptionalLit(e)),
- ExprF::EmptyListLit(t) => {
- Ret::Value(EmptyListLit(TypeThunk::from_thunk(t)))
+ ExprF::EmptyListLit(ref t) => {
+ // Check if the type is of the form `List x`
+ let t_borrow = t.as_value();
+ match &*t_borrow {
+ AppliedBuiltin(Builtin::List, args) if args.len() == 1 => {
+ Ret::Value(EmptyListLit(TypeThunk::from_thunk(
+ args[0].clone(),
+ )))
+ }
+ _ => {
+ drop(t_borrow);
+ Ret::Expr(expr)
+ }
+ }
}
ExprF::NEListLit(elts) => {
Ret::Value(NEListLit(elts.into_iter().collect()))
@@ -658,13 +694,6 @@ pub fn normalize_one_layer(expr: ExprF<Thunk, X>) -> Value {
.map(|(k, t)| (k, TypeThunk::from_thunk(t)))
.collect(),
)),
- 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) => Ret::Value(UnionType(
kts.into_iter()
.map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t))))
diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs
index ba75be4..ac264e6 100644
--- a/dhall/src/phase/resolve.rs
+++ b/dhall/src/phase/resolve.rs
@@ -87,7 +87,7 @@ fn do_resolve_expr(
}
}
};
- let expr = expr.traverse_embed(resolve)?;
+ let expr = expr.traverse_resolve(resolve)?;
Ok(Resolved(expr))
}
@@ -101,7 +101,7 @@ pub fn skip_resolve_expr(
let resolve = |import: &Import| -> Result<Normalized, ImportError> {
Err(ImportError::UnexpectedImport(import.clone()))
};
- let expr = expr.traverse_embed(resolve)?;
+ let expr = expr.traverse_resolve(resolve)?;
Ok(Resolved(expr))
}
@@ -111,24 +111,35 @@ mod spec_tests {
macro_rules! import_success {
($name:ident, $path:expr) => {
- make_spec_test!(Import, Success, $name, &("success/".to_owned() + $path));
+ make_spec_test!(Import, Success, $name, &("../dhall-lang/tests/import/success/".to_owned() + $path));
};
}
// macro_rules! import_failure {
// ($name:ident, $path:expr) => {
- // make_spec_test!(Import, Failure, $name, &("failure/".to_owned() + $path));
+ // make_spec_test!(Import, Failure, $name, &("../dhall-lang/tests/import/failure/".to_owned() + $path));
// };
// }
// import_success!(success_alternativeEnvNatural, "alternativeEnvNatural");
// import_success!(success_alternativeEnvSimple, "alternativeEnvSimple");
+ // import_success!(success_alternativeHashMismatch, "alternativeHashMismatch");
// import_success!(success_alternativeNatural, "alternativeNatural");
+ // import_success!(success_alternativeParseError, "alternativeParseError");
+ // import_success!(success_alternativeTypeError, "alternativeTypeError");
+ // import_success!(success_asLocation, "asLocation");
// import_success!(success_asText, "asText");
+ // import_success!(success_customHeaders, "customHeaders");
import_success!(success_fieldOrder, "fieldOrder");
+ // note: this one needs special setup with env variables
+ // import_success!(success_hashFromCache, "hashFromCache");
+ // import_success!(success_headerForwarding, "headerForwarding");
+ // import_success!(success_nestedHash, "nestedHash");
+ // import_success!(success_noHeaderForwarding, "noHeaderForwarding");
// import_failure!(failure_alternativeEnv, "alternativeEnv");
// import_failure!(failure_alternativeEnvMissing, "alternativeEnvMissing");
// import_failure!(failure_cycle, "cycle");
+ // import_failure!(failure_hashMismatch, "hashMismatch");
// import_failure!(failure_missing, "missing");
// import_failure!(failure_referentiallyInsane, "referentiallyInsane");
}
diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs
index a3f676c..299997a 100644
--- a/dhall/src/phase/typecheck.rs
+++ b/dhall/src/phase/typecheck.rs
@@ -1,6 +1,5 @@
use std::collections::HashMap;
-use dhall_proc_macros as dhall;
use dhall_syntax::{
rc, Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, Span,
SubExpr, X,
@@ -13,24 +12,6 @@ use crate::core::var::{Shift, Subst};
use crate::error::{TypeError, TypeMessage};
use crate::phase::{Normalized, Resolved, Type, Typed};
-macro_rules! ensure_equal {
- ($x:expr, $y:expr, $err:expr $(,)*) => {
- if $x.to_value() != $y.to_value() {
- return Err($err);
- }
- };
-}
-
-// Ensure the provided type has type `Type`
-macro_rules! ensure_simple_type {
- ($x:expr, $err:expr $(,)*) => {{
- match $x.get_type()?.as_const() {
- Some(dhall_syntax::Const::Type) => {}
- _ => return Err($err),
- }
- }};
-}
-
fn tck_pi_type(
ctx: &TypecheckContext,
x: Label,
@@ -60,18 +41,7 @@ fn tck_pi_type(
}
};
- let k = match function_check(ka, kb) {
- Ok(k) => k,
- Err(()) => {
- return Err(TypeError::new(
- ctx,
- NoDependentTypes(
- tx.to_normalized(),
- te.get_type()?.to_normalized(),
- ),
- ))
- }
- };
+ let k = function_check(ka, kb);
Ok(Typed::from_thunk_and_type(
Value::Pi(x.into(), TypeThunk::from_type(tx), TypeThunk::from_type(te))
@@ -164,45 +134,13 @@ fn tck_union_type(
))
}
-fn tck_list_type(ctx: &TypecheckContext, t: Type) -> Result<Typed, TypeError> {
- use crate::error::TypeMessage::*;
- ensure_simple_type!(
- t,
- TypeError::new(ctx, InvalidListType(t.to_normalized())),
- );
- Ok(Typed::from_thunk_and_type(
- Value::from_builtin(Builtin::List)
- .app(t.to_value())
- .into_thunk(),
- Type::from_const(Const::Type),
- ))
-}
-
-fn tck_optional_type(
- ctx: &TypecheckContext,
- t: Type,
-) -> Result<Typed, TypeError> {
- use crate::error::TypeMessage::*;
- ensure_simple_type!(
- t,
- TypeError::new(ctx, InvalidOptionalType(t.to_normalized())),
- );
- Ok(Typed::from_thunk_and_type(
- Value::from_builtin(Builtin::Optional)
- .app(t.to_value())
- .into_thunk(),
- Type::from_const(Const::Type),
- ))
-}
-
-fn function_check(a: Const, b: Const) -> Result<Const, ()> {
- use dhall_syntax::Const::*;
- match (a, b) {
- (_, Type) => Ok(Type),
- (Kind, Kind) => Ok(Kind),
- (Sort, Sort) => Ok(Sort),
- (Sort, Kind) => Ok(Sort),
- _ => Err(()),
+fn function_check(a: Const, b: Const) -> Const {
+ use dhall_syntax::Const::Type;
+ use std::cmp::max;
+ if b == Type {
+ Type
+ } else {
+ max(a, b)
}
}
@@ -216,40 +154,97 @@ pub fn type_of_const(c: Const) -> Result<Type, TypeError> {
}
}
+// Ad-hoc macro to help construct the types of builtins
+macro_rules! make_type {
+ (Type) => { ExprF::Const(Const::Type) };
+ (Bool) => { ExprF::Builtin(Builtin::Bool) };
+ (Natural) => { ExprF::Builtin(Builtin::Natural) };
+ (Integer) => { ExprF::Builtin(Builtin::Integer) };
+ (Double) => { ExprF::Builtin(Builtin::Double) };
+ (Text) => { ExprF::Builtin(Builtin::Text) };
+ ($var:ident) => {
+ ExprF::Var(dhall_syntax::V(stringify!($var).into(), 0))
+ };
+ (Optional $ty:ident) => {
+ ExprF::App(
+ rc(ExprF::Builtin(Builtin::Optional)),
+ rc(make_type!($ty))
+ )
+ };
+ (List $($rest:tt)*) => {
+ ExprF::App(
+ rc(ExprF::Builtin(Builtin::List)),
+ rc(make_type!($($rest)*))
+ )
+ };
+ ({ $($label:ident : $ty:ident),* }) => {{
+ let mut kts = dhall_syntax::map::DupTreeMap::new();
+ $(
+ kts.insert(
+ Label::from(stringify!($label)),
+ rc(make_type!($ty)),
+ );
+ )*
+ ExprF::RecordType(kts)
+ }};
+ ($ty:ident -> $($rest:tt)*) => {
+ ExprF::Pi(
+ "_".into(),
+ rc(make_type!($ty)),
+ rc(make_type!($($rest)*))
+ )
+ };
+ (($($arg:tt)*) -> $($rest:tt)*) => {
+ ExprF::Pi(
+ "_".into(),
+ rc(make_type!($($arg)*)),
+ rc(make_type!($($rest)*))
+ )
+ };
+ (forall ($var:ident : $($ty:tt)*) -> $($rest:tt)*) => {
+ ExprF::Pi(
+ stringify!($var).into(),
+ rc(make_type!($($ty)*)),
+ rc(make_type!($($rest)*))
+ )
+ };
+}
+
fn type_of_builtin(b: Builtin) -> Expr<X, X> {
use dhall_syntax::Builtin::*;
match b {
- Bool | Natural | Integer | Double | Text => dhall::expr!(Type),
- List | Optional => dhall::expr!(
+ Bool | Natural | Integer | Double | Text => make_type!(Type),
+ List | Optional => make_type!(
Type -> Type
),
- NaturalFold => dhall::expr!(
+ NaturalFold => make_type!(
Natural ->
forall (natural: Type) ->
forall (succ: natural -> natural) ->
forall (zero: natural) ->
natural
),
- NaturalBuild => dhall::expr!(
+ NaturalBuild => make_type!(
(forall (natural: Type) ->
forall (succ: natural -> natural) ->
forall (zero: natural) ->
natural) ->
Natural
),
- NaturalIsZero | NaturalEven | NaturalOdd => dhall::expr!(
+ NaturalIsZero | NaturalEven | NaturalOdd => make_type!(
Natural -> Bool
),
- NaturalToInteger => dhall::expr!(Natural -> Integer),
- NaturalShow => dhall::expr!(Natural -> Text),
+ NaturalToInteger => make_type!(Natural -> Integer),
+ NaturalShow => make_type!(Natural -> Text),
+ NaturalSubtract => make_type!(Natural -> Natural -> Natural),
- IntegerToDouble => dhall::expr!(Integer -> Double),
- IntegerShow => dhall::expr!(Integer -> Text),
- DoubleShow => dhall::expr!(Double -> Text),
- TextShow => dhall::expr!(Text -> Text),
+ IntegerToDouble => make_type!(Integer -> Double),
+ IntegerShow => make_type!(Integer -> Text),
+ DoubleShow => make_type!(Double -> Text),
+ TextShow => make_type!(Text -> Text),
- ListBuild => dhall::expr!(
+ ListBuild => make_type!(
forall (a: Type) ->
(forall (list: Type) ->
forall (cons: a -> list -> list) ->
@@ -257,28 +252,28 @@ fn type_of_builtin(b: Builtin) -> Expr<X, X> {
list) ->
List a
),
- ListFold => dhall::expr!(
+ ListFold => make_type!(
forall (a: Type) ->
- List a ->
+ (List a) ->
forall (list: Type) ->
forall (cons: a -> list -> list) ->
forall (nil: list) ->
list
),
- ListLength => dhall::expr!(forall (a: Type) -> List a -> Natural),
+ ListLength => make_type!(forall (a: Type) -> (List a) -> Natural),
ListHead | ListLast => {
- dhall::expr!(forall (a: Type) -> List a -> Optional a)
+ make_type!(forall (a: Type) -> (List a) -> Optional a)
}
- ListIndexed => dhall::expr!(
+ ListIndexed => make_type!(
forall (a: Type) ->
- List a ->
+ (List a) ->
List { index: Natural, value: a }
),
- ListReverse => dhall::expr!(
- forall (a: Type) -> List a -> List a
+ ListReverse => make_type!(
+ forall (a: Type) -> (List a) -> List a
),
- OptionalBuild => dhall::expr!(
+ OptionalBuild => make_type!(
forall (a: Type) ->
(forall (optional: Type) ->
forall (just: a -> optional) ->
@@ -286,15 +281,15 @@ fn type_of_builtin(b: Builtin) -> Expr<X, X> {
optional) ->
Optional a
),
- OptionalFold => dhall::expr!(
+ OptionalFold => make_type!(
forall (a: Type) ->
- Optional a ->
+ (Optional a) ->
forall (optional: Type) ->
forall (just: a -> optional) ->
forall (nothing: optional) ->
optional
),
- OptionalNone => dhall::expr!(
+ OptionalNone => make_type!(
forall (a: Type) -> Optional a
),
}
@@ -329,9 +324,7 @@ fn type_with(
ctx: &TypecheckContext,
e: SubExpr<Span, Normalized>,
) -> Result<Typed, TypeError> {
- use dhall_syntax::ExprF::{
- Annot, App, Embed, Lam, Let, OldOptionalLit, Pi, SomeLit, Var,
- };
+ use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var};
use Ret::*;
Ok(match e.as_ref() {
@@ -364,18 +357,6 @@ fn type_with(
let v = type_with(ctx, v)?;
return type_with(&ctx.insert_value(x, v.clone())?, e.clone());
}
- OldOptionalLit(None, t) => {
- let none = SubExpr::from_builtin(Builtin::OptionalNone);
- let e = e.rewrap(App(none, t.clone()));
- return type_with(ctx, e);
- }
- OldOptionalLit(Some(x), t) => {
- let optional = SubExpr::from_builtin(Builtin::Optional);
- let x = x.rewrap(SomeLit(x.clone()));
- let t = t.rewrap(App(optional, t.clone()));
- let e = e.rewrap(Annot(x, t));
- return type_with(ctx, e);
- }
Embed(p) => p.clone().into_typed(),
Var(var) => match ctx.lookup(&var) {
Some(typed) => typed,
@@ -418,87 +399,132 @@ fn type_last_layer(
use crate::error::TypeMessage::*;
use dhall_syntax::BinOp::*;
use dhall_syntax::Builtin::*;
+ use dhall_syntax::Const::Type;
use dhall_syntax::ExprF::*;
use Ret::*;
let mkerr = |msg: TypeMessage| TypeError::new(ctx, msg);
match e {
- Lam(_, _, _)
- | Pi(_, _, _)
- | Let(_, _, _, _)
- | OldOptionalLit(_, _)
- | Embed(_)
- | Var(_) => unreachable!(),
+ Lam(_, _, _) | Pi(_, _, _) | Let(_, _, _, _) | Embed(_) | Var(_) => {
+ unreachable!()
+ }
App(f, a) => {
let tf = f.get_type()?;
let (x, tx, tb) = match &tf.to_value() {
Value::Pi(x, tx, tb) => (x.clone(), tx.to_type(), tb.to_type()),
_ => return Err(mkerr(NotAFunction(f.clone()))),
};
- ensure_equal!(a.get_type()?, &tx, {
- mkerr(TypeMismatch(f.clone(), tx.to_normalized(), a.clone()))
- });
+ if a.get_type()?.as_ref() != &tx {
+ return Err(mkerr(TypeMismatch(
+ f.clone(),
+ tx.to_normalized(),
+ a.clone(),
+ )));
+ }
Ok(RetTypeOnly(tb.subst_shift(&x.into(), &a)))
}
Annot(x, t) => {
let t = t.to_type();
- ensure_equal!(
- &t,
- x.get_type()?,
- mkerr(AnnotMismatch(x.clone(), t.to_normalized()))
- );
+ if &t != x.get_type()?.as_ref() {
+ return Err(mkerr(AnnotMismatch(x.clone(), t.to_normalized())));
+ }
Ok(RetTypeOnly(x.get_type()?.into_owned()))
}
+ Assert(t) => {
+ match t.to_value() {
+ Value::Equivalence(x, y) if x == y => {}
+ Value::Equivalence(x, y) => {
+ return Err(mkerr(AssertMismatch(
+ x.to_typed(),
+ y.to_typed(),
+ )))
+ }
+ _ => return Err(mkerr(AssertMustTakeEquivalence)),
+ }
+ Ok(RetTypeOnly(t.to_type()))
+ }
BoolIf(x, y, z) => {
- ensure_equal!(
- x.get_type()?,
- &builtin_to_type(Bool)?,
- mkerr(InvalidPredicate(x.clone())),
- );
+ if x.get_type()?.as_ref() != &builtin_to_type(Bool)? {
+ return Err(mkerr(InvalidPredicate(x.clone())));
+ }
- ensure_simple_type!(
- y.get_type()?,
- mkerr(IfBranchMustBeTerm(true, y.clone())),
- );
+ if y.get_type()?.get_type()?.as_const() != Some(Type) {
+ return Err(mkerr(IfBranchMustBeTerm(true, y.clone())));
+ }
- ensure_simple_type!(
- z.get_type()?,
- mkerr(IfBranchMustBeTerm(false, z.clone())),
- );
+ if z.get_type()?.get_type()?.as_const() != Some(Type) {
+ return Err(mkerr(IfBranchMustBeTerm(false, z.clone())));
+ }
- ensure_equal!(
- y.get_type()?,
- z.get_type()?,
- mkerr(IfBranchMismatch(y.clone(), z.clone()))
- );
+ if y.get_type()? != z.get_type()? {
+ return Err(mkerr(IfBranchMismatch(y.clone(), z.clone())));
+ }
Ok(RetTypeOnly(y.get_type()?.into_owned()))
}
EmptyListLit(t) => {
let t = t.to_type();
- Ok(RetTypeOnly(tck_list_type(ctx, t)?.to_type()))
+ match &t.to_value() {
+ Value::AppliedBuiltin(dhall_syntax::Builtin::List, args)
+ if args.len() == 1 => {}
+ _ => {
+ return Err(TypeError::new(
+ ctx,
+ InvalidListType(t.to_normalized()),
+ ))
+ }
+ }
+ Ok(RetTypeOnly(t))
}
NEListLit(xs) => {
let mut iter = xs.iter().enumerate();
let (_, x) = iter.next().unwrap();
for (i, y) in iter {
- ensure_equal!(
- x.get_type()?,
- y.get_type()?,
- mkerr(InvalidListElement(
+ if x.get_type()? != y.get_type()? {
+ return Err(mkerr(InvalidListElement(
i,
x.get_type()?.to_normalized(),
- y.clone()
- ))
- );
+ y.clone(),
+ )));
+ }
}
- let t = x.get_type()?.into_owned();
- Ok(RetTypeOnly(tck_list_type(ctx, t)?.to_type()))
+ let t = x.get_type()?;
+ if t.get_type()?.as_const() != Some(Type) {
+ return Err(TypeError::new(
+ ctx,
+ InvalidListType(t.to_normalized()),
+ ));
+ }
+
+ Ok(RetTypeOnly(
+ Typed::from_thunk_and_type(
+ Value::from_builtin(dhall_syntax::Builtin::List)
+ .app(t.to_value())
+ .into_thunk(),
+ Typed::from_const(Type),
+ )
+ .to_type(),
+ ))
}
SomeLit(x) => {
let t = x.get_type()?.into_owned();
- Ok(RetTypeOnly(tck_optional_type(ctx, t)?.to_type()))
+ if t.get_type()?.as_const() != Some(Type) {
+ return Err(TypeError::new(
+ ctx,
+ InvalidOptionalType(t.to_normalized()),
+ ));
+ }
+
+ Ok(RetTypeOnly(
+ Typed::from_thunk_and_type(
+ Value::from_builtin(dhall_syntax::Builtin::Optional)
+ .app(t.to_value())
+ .into_thunk(),
+ Typed::from_const(Type).into_type(),
+ )
+ .to_type(),
+ ))
}
RecordType(kts) => Ok(RetWhole(tck_record_type(
ctx,
@@ -517,15 +543,6 @@ fn type_last_layer(
)?
.into_type(),
)),
- UnionLit(x, v, kvs) => {
- use std::iter::once;
- let kts = kvs
- .iter()
- .map(|(x, v)| Ok((x.clone(), v.as_ref().map(|v| v.to_type()))));
- let t = v.get_type()?.into_owned();
- let kts = kts.chain(once(Ok((x.clone(), Some(t)))));
- Ok(RetTypeOnly(tck_union_type(ctx, kts)?.to_type()))
- }
Field(r, x) => {
match &r.get_type()?.to_value() {
Value::RecordType(kts) => match kts.get(&x) {
@@ -589,11 +606,9 @@ fn type_last_layer(
for contents in interpolated.iter() {
use InterpolatedTextContents::Expr;
if let Expr(x) = contents {
- ensure_equal!(
- x.get_type()?,
- &text_type,
- mkerr(InvalidTextInterpolation(x.clone())),
- );
+ if x.get_type()?.as_ref() != &text_type {
+ return Err(mkerr(InvalidTextInterpolation(x.clone())));
+ }
}
}
Ok(RetTypeOnly(text_type))
@@ -609,11 +624,9 @@ fn type_last_layer(
// Check the equality of kinds.
// This is to disallow expression such as:
// "{ x = Text } // { y = 1 }"
- ensure_equal!(
- l_kind,
- r_kind,
- mkerr(RecordMismatch(l.clone(), r.clone())),
- );
+ if l_kind != r_kind {
+ return Err(mkerr(RecordMismatch(l.clone(), r.clone())));
+ }
// Extract the LHS record type
let kts_x = match l_type.to_value() {
@@ -693,11 +706,9 @@ fn type_last_layer(
// Check the equality of kinds.
// This is to disallow expression such as:
// "{ x = Text } // { y = 1 }"
- ensure_equal!(
- l_kind,
- r_kind,
- mkerr(RecordMismatch(l.clone(), r.clone())),
- );
+ if l_kind != r_kind {
+ return Err(mkerr(RecordMismatch(l.clone(), r.clone())));
+ }
// Extract the LHS record type
let kts_x = match l_type.to_value() {
@@ -819,14 +830,35 @@ fn type_last_layer(
_ => return Err(mkerr(BinOpTypeMismatch(*o, l.clone()))),
}
- ensure_equal!(
- l.get_type()?,
- r.get_type()?,
- mkerr(BinOpTypeMismatch(*o, r.clone()))
- );
+ if l.get_type()? != r.get_type()? {
+ return Err(mkerr(BinOpTypeMismatch(*o, r.clone())));
+ }
Ok(RetTypeOnly(l.get_type()?.into_owned()))
}
+ BinOp(Equivalence, l, r) => {
+ if l.get_type()?.get_type()?.as_const() != Some(Type) {
+ return Err(mkerr(EquivalenceArgumentMustBeTerm(
+ true,
+ l.clone(),
+ )));
+ }
+ if r.get_type()?.get_type()?.as_const() != Some(Type) {
+ return Err(mkerr(EquivalenceArgumentMustBeTerm(
+ false,
+ r.clone(),
+ )));
+ }
+
+ if l.get_type()? != r.get_type()? {
+ return Err(mkerr(EquivalenceTypeMismatch(
+ r.clone(),
+ l.clone(),
+ )));
+ }
+
+ Ok(RetTypeOnly(Typed::from_const(Type).into_type()))
+ }
BinOp(o, l, r) => {
let t = builtin_to_type(match o {
BoolAnd => Bool,
@@ -840,20 +872,17 @@ fn type_last_layer(
RightBiasedRecordMerge => unreachable!(),
RecursiveRecordMerge => unreachable!(),
RecursiveRecordTypeMerge => unreachable!(),
- _ => return Err(mkerr(Unimplemented)),
+ ImportAlt => unreachable!("There should remain no import alternatives in a resolved expression"),
+ Equivalence => unreachable!(),
})?;
- ensure_equal!(
- l.get_type()?,
- &t,
- mkerr(BinOpTypeMismatch(*o, l.clone()))
- );
+ if l.get_type()?.as_ref() != &t {
+ return Err(mkerr(BinOpTypeMismatch(*o, l.clone())));
+ }
- ensure_equal!(
- r.get_type()?,
- &t,
- mkerr(BinOpTypeMismatch(*o, r.clone()))
- );
+ if r.get_type()?.as_ref() != &t {
+ return Err(mkerr(BinOpTypeMismatch(*o, r.clone())));
+ }
Ok(RetTypeOnly(t))
}
@@ -882,13 +911,13 @@ fn type_last_layer(
_ => return Err(mkerr(NotAFunction(handler_type))),
};
- ensure_equal!(&variant_type, &tx, {
- mkerr(TypeMismatch(
+ if &variant_type != &tx {
+ return Err(mkerr(TypeMismatch(
handler_type,
tx.to_normalized(),
variant_type,
- ))
- });
+ )));
+ }
// Extract `tb` from under the `x` binder. Fails is `x` was free in `tb`.
match tb.over_binder(x) {
@@ -911,11 +940,9 @@ fn type_last_layer(
match &inferred_type {
None => inferred_type = Some(handler_return_type),
Some(t) => {
- ensure_equal!(
- t,
- &handler_return_type,
- mkerr(MergeHandlerTypeMismatch)
- );
+ if t != &handler_return_type {
+ return Err(mkerr(MergeHandlerTypeMismatch));
+ }
}
}
}
@@ -928,7 +955,9 @@ fn type_last_layer(
match (inferred_type, type_annot) {
(Some(ref t1), Some(t2)) => {
let t2 = t2.to_type();
- ensure_equal!(t1, &t2, mkerr(MergeAnnotMismatch));
+ if t1 != &t2 {
+ return Err(mkerr(MergeAnnotMismatch));
+ }
Ok(RetTypeOnly(t2))
}
(Some(t), None) => Ok(RetTypeOnly(t)),
@@ -985,394 +1014,3 @@ pub fn typecheck_with(e: Resolved, ty: &Type) -> Result<Typed, TypeError> {
pub fn skip_typecheck(e: Resolved) -> Typed {
Typed::from_thunk_untyped(Thunk::new(NormalizationContext::new(), e.0))
}
-
-#[cfg(test)]
-mod spec_tests {
- #![rustfmt::skip]
-
- macro_rules! tc_success {
- ($name:ident, $path:expr) => {
- make_spec_test!(Typecheck, Success, $name, &("success/".to_owned() + $path));
- };
- }
- macro_rules! tc_failure {
- ($name:ident, $path:expr) => {
- make_spec_test!(Typecheck, Failure, $name, &("failure/".to_owned() + $path));
- };
- }
-
- macro_rules! ti_success {
- ($name:ident, $path:expr) => {
- make_spec_test!(TypeInference, Success, $name, &("success/".to_owned() + $path));
- };
- }
- // macro_rules! ti_failure {
- // ($name:ident, $path:expr) => {
- // make_spec_test!(TypeInference, Failure, $name, &("failure/".to_owned() + $path));
- // };
- // }
-
- // tc_success!(tc_success_accessEncodedType, "accessEncodedType");
- // tc_success!(tc_success_accessType, "accessType");
- tc_success!(tc_success_prelude_Bool_and_0, "prelude/Bool/and/0");
- tc_success!(tc_success_prelude_Bool_and_1, "prelude/Bool/and/1");
- tc_success!(tc_success_prelude_Bool_build_0, "prelude/Bool/build/0");
- tc_success!(tc_success_prelude_Bool_build_1, "prelude/Bool/build/1");
- tc_success!(tc_success_prelude_Bool_even_0, "prelude/Bool/even/0");
- tc_success!(tc_success_prelude_Bool_even_1, "prelude/Bool/even/1");
- tc_success!(tc_success_prelude_Bool_even_2, "prelude/Bool/even/2");
- tc_success!(tc_success_prelude_Bool_even_3, "prelude/Bool/even/3");
- tc_success!(tc_success_prelude_Bool_fold_0, "prelude/Bool/fold/0");
- tc_success!(tc_success_prelude_Bool_fold_1, "prelude/Bool/fold/1");
- tc_success!(tc_success_prelude_Bool_not_0, "prelude/Bool/not/0");
- tc_success!(tc_success_prelude_Bool_not_1, "prelude/Bool/not/1");
- tc_success!(tc_success_prelude_Bool_odd_0, "prelude/Bool/odd/0");
- tc_success!(tc_success_prelude_Bool_odd_1, "prelude/Bool/odd/1");
- tc_success!(tc_success_prelude_Bool_odd_2, "prelude/Bool/odd/2");
- tc_success!(tc_success_prelude_Bool_odd_3, "prelude/Bool/odd/3");
- tc_success!(tc_success_prelude_Bool_or_0, "prelude/Bool/or/0");
- tc_success!(tc_success_prelude_Bool_or_1, "prelude/Bool/or/1");
- tc_success!(tc_success_prelude_Bool_show_0, "prelude/Bool/show/0");
- tc_success!(tc_success_prelude_Bool_show_1, "prelude/Bool/show/1");
- tc_success!(tc_success_prelude_Double_show_0, "prelude/Double/show/0");
- tc_success!(tc_success_prelude_Double_show_1, "prelude/Double/show/1");
- tc_success!(tc_success_prelude_Integer_show_0, "prelude/Integer/show/0");
- tc_success!(tc_success_prelude_Integer_show_1, "prelude/Integer/show/1");
- tc_success!(tc_success_prelude_Integer_toDouble_0, "prelude/Integer/toDouble/0");
- tc_success!(tc_success_prelude_Integer_toDouble_1, "prelude/Integer/toDouble/1");
- tc_success!(tc_success_prelude_List_all_0, "prelude/List/all/0");
- tc_success!(tc_success_prelude_List_all_1, "prelude/List/all/1");
- tc_success!(tc_success_prelude_List_any_0, "prelude/List/any/0");
- tc_success!(tc_success_prelude_List_any_1, "prelude/List/any/1");
- tc_success!(tc_success_prelude_List_build_0, "prelude/List/build/0");
- tc_success!(tc_success_prelude_List_build_1, "prelude/List/build/1");
- tc_success!(tc_success_prelude_List_concat_0, "prelude/List/concat/0");
- tc_success!(tc_success_prelude_List_concat_1, "prelude/List/concat/1");
- tc_success!(tc_success_prelude_List_concatMap_0, "prelude/List/concatMap/0");
- tc_success!(tc_success_prelude_List_concatMap_1, "prelude/List/concatMap/1");
- tc_success!(tc_success_prelude_List_filter_0, "prelude/List/filter/0");
- tc_success!(tc_success_prelude_List_filter_1, "prelude/List/filter/1");
- tc_success!(tc_success_prelude_List_fold_0, "prelude/List/fold/0");
- tc_success!(tc_success_prelude_List_fold_1, "prelude/List/fold/1");
- tc_success!(tc_success_prelude_List_fold_2, "prelude/List/fold/2");
- tc_success!(tc_success_prelude_List_generate_0, "prelude/List/generate/0");
- tc_success!(tc_success_prelude_List_generate_1, "prelude/List/generate/1");
- tc_success!(tc_success_prelude_List_head_0, "prelude/List/head/0");
- tc_success!(tc_success_prelude_List_head_1, "prelude/List/head/1");
- tc_success!(tc_success_prelude_List_indexed_0, "prelude/List/indexed/0");
- tc_success!(tc_success_prelude_List_indexed_1, "prelude/List/indexed/1");
- tc_success!(tc_success_prelude_List_iterate_0, "prelude/List/iterate/0");
- tc_success!(tc_success_prelude_List_iterate_1, "prelude/List/iterate/1");
- tc_success!(tc_success_prelude_List_last_0, "prelude/List/last/0");
- tc_success!(tc_success_prelude_List_last_1, "prelude/List/last/1");
- tc_success!(tc_success_prelude_List_length_0, "prelude/List/length/0");
- tc_success!(tc_success_prelude_List_length_1, "prelude/List/length/1");
- tc_success!(tc_success_prelude_List_map_0, "prelude/List/map/0");
- tc_success!(tc_success_prelude_List_map_1, "prelude/List/map/1");
- tc_success!(tc_success_prelude_List_null_0, "prelude/List/null/0");
- tc_success!(tc_success_prelude_List_null_1, "prelude/List/null/1");
- tc_success!(tc_success_prelude_List_replicate_0, "prelude/List/replicate/0");
- tc_success!(tc_success_prelude_List_replicate_1, "prelude/List/replicate/1");
- tc_success!(tc_success_prelude_List_reverse_0, "prelude/List/reverse/0");
- tc_success!(tc_success_prelude_List_reverse_1, "prelude/List/reverse/1");
- tc_success!(tc_success_prelude_List_shifted_0, "prelude/List/shifted/0");
- tc_success!(tc_success_prelude_List_shifted_1, "prelude/List/shifted/1");
- tc_success!(tc_success_prelude_List_unzip_0, "prelude/List/unzip/0");
- tc_success!(tc_success_prelude_List_unzip_1, "prelude/List/unzip/1");
- tc_success!(tc_success_prelude_Monoid_00, "prelude/Monoid/00");
- tc_success!(tc_success_prelude_Monoid_01, "prelude/Monoid/01");
- tc_success!(tc_success_prelude_Monoid_02, "prelude/Monoid/02");
- tc_success!(tc_success_prelude_Monoid_03, "prelude/Monoid/03");
- tc_success!(tc_success_prelude_Monoid_04, "prelude/Monoid/04");
- tc_success!(tc_success_prelude_Monoid_05, "prelude/Monoid/05");
- tc_success!(tc_success_prelude_Monoid_06, "prelude/Monoid/06");
- tc_success!(tc_success_prelude_Monoid_07, "prelude/Monoid/07");
- tc_success!(tc_success_prelude_Monoid_08, "prelude/Monoid/08");
- tc_success!(tc_success_prelude_Monoid_09, "prelude/Monoid/09");
- tc_success!(tc_success_prelude_Monoid_10, "prelude/Monoid/10");
- tc_success!(tc_success_prelude_Natural_build_0, "prelude/Natural/build/0");
- tc_success!(tc_success_prelude_Natural_build_1, "prelude/Natural/build/1");
- tc_success!(tc_success_prelude_Natural_enumerate_0, "prelude/Natural/enumerate/0");
- tc_success!(tc_success_prelude_Natural_enumerate_1, "prelude/Natural/enumerate/1");
- tc_success!(tc_success_prelude_Natural_even_0, "prelude/Natural/even/0");
- tc_success!(tc_success_prelude_Natural_even_1, "prelude/Natural/even/1");
- tc_success!(tc_success_prelude_Natural_fold_0, "prelude/Natural/fold/0");
- tc_success!(tc_success_prelude_Natural_fold_1, "prelude/Natural/fold/1");
- tc_success!(tc_success_prelude_Natural_fold_2, "prelude/Natural/fold/2");
- tc_success!(tc_success_prelude_Natural_isZero_0, "prelude/Natural/isZero/0");
- tc_success!(tc_success_prelude_Natural_isZero_1, "prelude/Natural/isZero/1");
- tc_success!(tc_success_prelude_Natural_odd_0, "prelude/Natural/odd/0");
- tc_success!(tc_success_prelude_Natural_odd_1, "prelude/Natural/odd/1");
- tc_success!(tc_success_prelude_Natural_product_0, "prelude/Natural/product/0");
- tc_success!(tc_success_prelude_Natural_product_1, "prelude/Natural/product/1");
- tc_success!(tc_success_prelude_Natural_show_0, "prelude/Natural/show/0");
- tc_success!(tc_success_prelude_Natural_show_1, "prelude/Natural/show/1");
- tc_success!(tc_success_prelude_Natural_sum_0, "prelude/Natural/sum/0");
- tc_success!(tc_success_prelude_Natural_sum_1, "prelude/Natural/sum/1");
- tc_success!(tc_success_prelude_Natural_toDouble_0, "prelude/Natural/toDouble/0");
- tc_success!(tc_success_prelude_Natural_toDouble_1, "prelude/Natural/toDouble/1");
- tc_success!(tc_success_prelude_Natural_toInteger_0, "prelude/Natural/toInteger/0");
- tc_success!(tc_success_prelude_Natural_toInteger_1, "prelude/Natural/toInteger/1");
- tc_success!(tc_success_prelude_Optional_all_0, "prelude/Optional/all/0");
- tc_success!(tc_success_prelude_Optional_all_1, "prelude/Optional/all/1");
- tc_success!(tc_success_prelude_Optional_any_0, "prelude/Optional/any/0");
- tc_success!(tc_success_prelude_Optional_any_1, "prelude/Optional/any/1");
- tc_success!(tc_success_prelude_Optional_build_0, "prelude/Optional/build/0");
- tc_success!(tc_success_prelude_Optional_build_1, "prelude/Optional/build/1");
- tc_success!(tc_success_prelude_Optional_concat_0, "prelude/Optional/concat/0");
- tc_success!(tc_success_prelude_Optional_concat_1, "prelude/Optional/concat/1");
- tc_success!(tc_success_prelude_Optional_concat_2, "prelude/Optional/concat/2");
- tc_success!(tc_success_prelude_Optional_filter_0, "prelude/Optional/filter/0");
- tc_success!(tc_success_prelude_Optional_filter_1, "prelude/Optional/filter/1");
- tc_success!(tc_success_prelude_Optional_fold_0, "prelude/Optional/fold/0");
- tc_success!(tc_success_prelude_Optional_fold_1, "prelude/Optional/fold/1");
- tc_success!(tc_success_prelude_Optional_head_0, "prelude/Optional/head/0");
- tc_success!(tc_success_prelude_Optional_head_1, "prelude/Optional/head/1");
- tc_success!(tc_success_prelude_Optional_head_2, "prelude/Optional/head/2");
- tc_success!(tc_success_prelude_Optional_last_0, "prelude/Optional/last/0");
- tc_success!(tc_success_prelude_Optional_last_1, "prelude/Optional/last/1");
- tc_success!(tc_success_prelude_Optional_last_2, "prelude/Optional/last/2");
- tc_success!(tc_success_prelude_Optional_length_0, "prelude/Optional/length/0");
- tc_success!(tc_success_prelude_Optional_length_1, "prelude/Optional/length/1");
- tc_success!(tc_success_prelude_Optional_map_0, "prelude/Optional/map/0");
- tc_success!(tc_success_prelude_Optional_map_1, "prelude/Optional/map/1");
- tc_success!(tc_success_prelude_Optional_null_0, "prelude/Optional/null/0");
- tc_success!(tc_success_prelude_Optional_null_1, "prelude/Optional/null/1");
- tc_success!(tc_success_prelude_Optional_toList_0, "prelude/Optional/toList/0");
- tc_success!(tc_success_prelude_Optional_toList_1, "prelude/Optional/toList/1");
- tc_success!(tc_success_prelude_Optional_unzip_0, "prelude/Optional/unzip/0");
- tc_success!(tc_success_prelude_Optional_unzip_1, "prelude/Optional/unzip/1");
- tc_success!(tc_success_prelude_Text_concat_0, "prelude/Text/concat/0");
- tc_success!(tc_success_prelude_Text_concat_1, "prelude/Text/concat/1");
- tc_success!(tc_success_prelude_Text_concatMap_0, "prelude/Text/concatMap/0");
- tc_success!(tc_success_prelude_Text_concatMap_1, "prelude/Text/concatMap/1");
- // tc_success!(tc_success_prelude_Text_concatMapSep_0, "prelude/Text/concatMapSep/0");
- // tc_success!(tc_success_prelude_Text_concatMapSep_1, "prelude/Text/concatMapSep/1");
- // tc_success!(tc_success_prelude_Text_concatSep_0, "prelude/Text/concatSep/0");
- // tc_success!(tc_success_prelude_Text_concatSep_1, "prelude/Text/concatSep/1");
- tc_success!(tc_success_recordOfRecordOfTypes, "recordOfRecordOfTypes");
- tc_success!(tc_success_recordOfTypes, "recordOfTypes");
- // tc_success!(tc_success_simple_access_0, "simple/access/0");
- // tc_success!(tc_success_simple_access_1, "simple/access/1");
- // tc_success!(tc_success_simple_anonymousFunctionsInTypes, "simple/anonymousFunctionsInTypes");
- // tc_success!(tc_success_simple_fieldsAreTypes, "simple/fieldsAreTypes");
- // tc_success!(tc_success_simple_kindParameter, "simple/kindParameter");
- tc_success!(tc_success_simple_mergeEquivalence, "simple/mergeEquivalence");
- // tc_success!(tc_success_simple_mixedFieldAccess, "simple/mixedFieldAccess");
- tc_success!(tc_success_simple_unionsOfTypes, "simple/unionsOfTypes");
-
- tc_failure!(tc_failure_combineMixedRecords, "combineMixedRecords");
- tc_failure!(tc_failure_duplicateFields, "duplicateFields");
- tc_failure!(tc_failure_hurkensParadox, "hurkensParadox");
- // tc_failure!(tc_failure_importBoundary, "importBoundary");
- tc_failure!(tc_failure_mixedUnions, "mixedUnions");
- tc_failure!(tc_failure_preferMixedRecords, "preferMixedRecords");
- tc_failure!(tc_failure_unit_FunctionApplicationArgumentNotMatch, "unit/FunctionApplicationArgumentNotMatch");
- tc_failure!(tc_failure_unit_FunctionApplicationIsNotFunction, "unit/FunctionApplicationIsNotFunction");
- tc_failure!(tc_failure_unit_FunctionArgumentTypeNotAType, "unit/FunctionArgumentTypeNotAType");
- tc_failure!(tc_failure_unit_FunctionDependentType, "unit/FunctionDependentType");
- tc_failure!(tc_failure_unit_FunctionDependentType2, "unit/FunctionDependentType2");
- tc_failure!(tc_failure_unit_FunctionTypeArgumentTypeNotAType, "unit/FunctionTypeArgumentTypeNotAType");
- tc_failure!(tc_failure_unit_FunctionTypeKindSort, "unit/FunctionTypeKindSort");
- tc_failure!(tc_failure_unit_FunctionTypeTypeKind, "unit/FunctionTypeTypeKind");
- tc_failure!(tc_failure_unit_FunctionTypeTypeSort, "unit/FunctionTypeTypeSort");
- tc_failure!(tc_failure_unit_IfBranchesNotMatch, "unit/IfBranchesNotMatch");
- tc_failure!(tc_failure_unit_IfBranchesNotType, "unit/IfBranchesNotType");
- tc_failure!(tc_failure_unit_IfNotBool, "unit/IfNotBool");
- tc_failure!(tc_failure_unit_LetWithWrongAnnotation, "unit/LetWithWrongAnnotation");
- tc_failure!(tc_failure_unit_ListLiteralEmptyNotType, "unit/ListLiteralEmptyNotType");
- tc_failure!(tc_failure_unit_ListLiteralNotType, "unit/ListLiteralNotType");
- tc_failure!(tc_failure_unit_ListLiteralTypesNotMatch, "unit/ListLiteralTypesNotMatch");
- tc_failure!(tc_failure_unit_MergeAlternativeHasNoHandler, "unit/MergeAlternativeHasNoHandler");
- tc_failure!(tc_failure_unit_MergeAnnotationNotType, "unit/MergeAnnotationNotType");
- tc_failure!(tc_failure_unit_MergeEmptyWithoutAnnotation, "unit/MergeEmptyWithoutAnnotation");
- tc_failure!(tc_failure_unit_MergeHandlerNotFunction, "unit/MergeHandlerNotFunction");
- tc_failure!(tc_failure_unit_MergeHandlerNotInUnion, "unit/MergeHandlerNotInUnion");
- tc_failure!(tc_failure_unit_MergeHandlerNotMatchAlternativeType, "unit/MergeHandlerNotMatchAlternativeType");
- tc_failure!(tc_failure_unit_MergeHandlersWithDifferentType, "unit/MergeHandlersWithDifferentType");
- tc_failure!(tc_failure_unit_MergeLhsNotRecord, "unit/MergeLhsNotRecord");
- tc_failure!(tc_failure_unit_MergeRhsNotUnion, "unit/MergeRhsNotUnion");
- tc_failure!(tc_failure_unit_MergeWithWrongAnnotation, "unit/MergeWithWrongAnnotation");
- tc_failure!(tc_failure_unit_OperatorAndNotBool, "unit/OperatorAndNotBool");
- tc_failure!(tc_failure_unit_OperatorEqualNotBool, "unit/OperatorEqualNotBool");
- tc_failure!(tc_failure_unit_OperatorListConcatenateLhsNotList, "unit/OperatorListConcatenateLhsNotList");
- tc_failure!(tc_failure_unit_OperatorListConcatenateListsNotMatch, "unit/OperatorListConcatenateListsNotMatch");
- tc_failure!(tc_failure_unit_OperatorListConcatenateNotListsButMatch, "unit/OperatorListConcatenateNotListsButMatch");
- tc_failure!(tc_failure_unit_OperatorListConcatenateRhsNotList, "unit/OperatorListConcatenateRhsNotList");
- tc_failure!(tc_failure_unit_OperatorNotEqualNotBool, "unit/OperatorNotEqualNotBool");
- tc_failure!(tc_failure_unit_OperatorOrNotBool, "unit/OperatorOrNotBool");
- tc_failure!(tc_failure_unit_OperatorPlusNotNatural, "unit/OperatorPlusNotNatural");
- tc_failure!(tc_failure_unit_OperatorTextConcatenateLhsNotText, "unit/OperatorTextConcatenateLhsNotText");
- tc_failure!(tc_failure_unit_OperatorTextConcatenateRhsNotText, "unit/OperatorTextConcatenateRhsNotText");
- tc_failure!(tc_failure_unit_OperatorTimesNotNatural, "unit/OperatorTimesNotNatural");
- tc_failure!(tc_failure_unit_RecordMixedKinds, "unit/RecordMixedKinds");
- tc_failure!(tc_failure_unit_RecordMixedKinds2, "unit/RecordMixedKinds2");
- tc_failure!(tc_failure_unit_RecordMixedKinds3, "unit/RecordMixedKinds3");
- tc_failure!(tc_failure_unit_RecordProjectionEmpty, "unit/RecordProjectionEmpty");
- tc_failure!(tc_failure_unit_RecordProjectionNotPresent, "unit/RecordProjectionNotPresent");
- tc_failure!(tc_failure_unit_RecordProjectionNotRecord, "unit/RecordProjectionNotRecord");
- tc_failure!(tc_failure_unit_RecordSelectionEmpty, "unit/RecordSelectionEmpty");
- tc_failure!(tc_failure_unit_RecordSelectionNotPresent, "unit/RecordSelectionNotPresent");
- tc_failure!(tc_failure_unit_RecordSelectionNotRecord, "unit/RecordSelectionNotRecord");
- tc_failure!(tc_failure_unit_RecordSelectionTypeNotUnionType, "unit/RecordSelectionTypeNotUnionType");
- tc_failure!(tc_failure_unit_RecordTypeMixedKinds, "unit/RecordTypeMixedKinds");
- tc_failure!(tc_failure_unit_RecordTypeMixedKinds2, "unit/RecordTypeMixedKinds2");
- tc_failure!(tc_failure_unit_RecordTypeMixedKinds3, "unit/RecordTypeMixedKinds3");
- tc_failure!(tc_failure_unit_RecordTypeValueMember, "unit/RecordTypeValueMember");
- tc_failure!(tc_failure_unit_RecursiveRecordMergeLhsNotRecord, "unit/RecursiveRecordMergeLhsNotRecord");
- tc_failure!(tc_failure_unit_RecursiveRecordMergeMixedKinds, "unit/RecursiveRecordMergeMixedKinds");
- tc_failure!(tc_failure_unit_RecursiveRecordMergeOverlapping, "unit/RecursiveRecordMergeOverlapping");
- tc_failure!(tc_failure_unit_RecursiveRecordMergeRhsNotRecord, "unit/RecursiveRecordMergeRhsNotRecord");
- tc_failure!(tc_failure_unit_RecursiveRecordTypeMergeLhsNotRecordType, "unit/RecursiveRecordTypeMergeLhsNotRecordType");
- tc_failure!(tc_failure_unit_RecursiveRecordTypeMergeOverlapping, "unit/RecursiveRecordTypeMergeOverlapping");
- tc_failure!(tc_failure_unit_RecursiveRecordTypeMergeRhsNotRecordType, "unit/RecursiveRecordTypeMergeRhsNotRecordType");
- tc_failure!(tc_failure_unit_RightBiasedRecordMergeLhsNotRecord, "unit/RightBiasedRecordMergeLhsNotRecord");
- tc_failure!(tc_failure_unit_RightBiasedRecordMergeMixedKinds, "unit/RightBiasedRecordMergeMixedKinds");
- tc_failure!(tc_failure_unit_RightBiasedRecordMergeMixedKinds2, "unit/RightBiasedRecordMergeMixedKinds2");
- tc_failure!(tc_failure_unit_RightBiasedRecordMergeMixedKinds3, "unit/RightBiasedRecordMergeMixedKinds3");
- tc_failure!(tc_failure_unit_RightBiasedRecordMergeRhsNotRecord, "unit/RightBiasedRecordMergeRhsNotRecord");
- tc_failure!(tc_failure_unit_SomeNotType, "unit/SomeNotType");
- tc_failure!(tc_failure_unit_Sort, "unit/Sort");
- tc_failure!(tc_failure_unit_TextLiteralInterpolateNotText, "unit/TextLiteralInterpolateNotText");
- tc_failure!(tc_failure_unit_TypeAnnotationWrong, "unit/TypeAnnotationWrong");
- tc_failure!(tc_failure_unit_UnionConstructorFieldNotPresent, "unit/UnionConstructorFieldNotPresent");
- tc_failure!(tc_failure_unit_UnionTypeMixedKinds, "unit/UnionTypeMixedKinds");
- tc_failure!(tc_failure_unit_UnionTypeMixedKinds2, "unit/UnionTypeMixedKinds2");
- tc_failure!(tc_failure_unit_UnionTypeMixedKinds3, "unit/UnionTypeMixedKinds3");
- tc_failure!(tc_failure_unit_UnionTypeNotType, "unit/UnionTypeNotType");
- tc_failure!(tc_failure_unit_VariableFree, "unit/VariableFree");
-
- ti_success!(ti_success_simple_alternativesAreTypes, "simple/alternativesAreTypes");
- ti_success!(ti_success_simple_kindParameter, "simple/kindParameter");
- ti_success!(ti_success_unit_Bool, "unit/Bool");
- ti_success!(ti_success_unit_Double, "unit/Double");
- ti_success!(ti_success_unit_DoubleLiteral, "unit/DoubleLiteral");
- ti_success!(ti_success_unit_DoubleShow, "unit/DoubleShow");
- ti_success!(ti_success_unit_False, "unit/False");
- ti_success!(ti_success_unit_Function, "unit/Function");
- ti_success!(ti_success_unit_FunctionApplication, "unit/FunctionApplication");
- ti_success!(ti_success_unit_FunctionNamedArg, "unit/FunctionNamedArg");
- ti_success!(ti_success_unit_FunctionTypeKindKind, "unit/FunctionTypeKindKind");
- ti_success!(ti_success_unit_FunctionTypeKindTerm, "unit/FunctionTypeKindTerm");
- ti_success!(ti_success_unit_FunctionTypeKindType, "unit/FunctionTypeKindType");
- ti_success!(ti_success_unit_FunctionTypeTermTerm, "unit/FunctionTypeTermTerm");
- ti_success!(ti_success_unit_FunctionTypeTypeTerm, "unit/FunctionTypeTypeTerm");
- ti_success!(ti_success_unit_FunctionTypeTypeType, "unit/FunctionTypeTypeType");
- ti_success!(ti_success_unit_FunctionTypeUsingArgument, "unit/FunctionTypeUsingArgument");
- ti_success!(ti_success_unit_If, "unit/If");
- ti_success!(ti_success_unit_IfNormalizeArguments, "unit/IfNormalizeArguments");
- ti_success!(ti_success_unit_Integer, "unit/Integer");
- ti_success!(ti_success_unit_IntegerLiteral, "unit/IntegerLiteral");
- ti_success!(ti_success_unit_IntegerShow, "unit/IntegerShow");
- ti_success!(ti_success_unit_IntegerToDouble, "unit/IntegerToDouble");
- ti_success!(ti_success_unit_Kind, "unit/Kind");
- ti_success!(ti_success_unit_Let, "unit/Let");
- ti_success!(ti_success_unit_LetNestedTypeSynonym, "unit/LetNestedTypeSynonym");
- ti_success!(ti_success_unit_LetTypeSynonym, "unit/LetTypeSynonym");
- ti_success!(ti_success_unit_LetWithAnnotation, "unit/LetWithAnnotation");
- ti_success!(ti_success_unit_List, "unit/List");
- ti_success!(ti_success_unit_ListBuild, "unit/ListBuild");
- ti_success!(ti_success_unit_ListFold, "unit/ListFold");
- ti_success!(ti_success_unit_ListHead, "unit/ListHead");
- ti_success!(ti_success_unit_ListIndexed, "unit/ListIndexed");
- ti_success!(ti_success_unit_ListLast, "unit/ListLast");
- ti_success!(ti_success_unit_ListLength, "unit/ListLength");
- ti_success!(ti_success_unit_ListLiteralEmpty, "unit/ListLiteralEmpty");
- ti_success!(ti_success_unit_ListLiteralNormalizeArguments, "unit/ListLiteralNormalizeArguments");
- ti_success!(ti_success_unit_ListLiteralOne, "unit/ListLiteralOne");
- ti_success!(ti_success_unit_ListReverse, "unit/ListReverse");
- ti_success!(ti_success_unit_MergeEmptyUnion, "unit/MergeEmptyUnion");
- ti_success!(ti_success_unit_MergeOne, "unit/MergeOne");
- ti_success!(ti_success_unit_MergeOneEmpty, "unit/MergeOneEmpty");
- ti_success!(ti_success_unit_MergeOneWithAnnotation, "unit/MergeOneWithAnnotation");
- ti_success!(ti_success_unit_Natural, "unit/Natural");
- ti_success!(ti_success_unit_NaturalBuild, "unit/NaturalBuild");
- ti_success!(ti_success_unit_NaturalEven, "unit/NaturalEven");
- ti_success!(ti_success_unit_NaturalFold, "unit/NaturalFold");
- ti_success!(ti_success_unit_NaturalIsZero, "unit/NaturalIsZero");
- ti_success!(ti_success_unit_NaturalLiteral, "unit/NaturalLiteral");
- ti_success!(ti_success_unit_NaturalOdd, "unit/NaturalOdd");
- ti_success!(ti_success_unit_NaturalShow, "unit/NaturalShow");
- ti_success!(ti_success_unit_NaturalToInteger, "unit/NaturalToInteger");
- ti_success!(ti_success_unit_None, "unit/None");
- ti_success!(ti_success_unit_OldOptionalNone, "unit/OldOptionalNone");
- ti_success!(ti_success_unit_OldOptionalTrue, "unit/OldOptionalTrue");
- ti_success!(ti_success_unit_OperatorAnd, "unit/OperatorAnd");
- ti_success!(ti_success_unit_OperatorAndNormalizeArguments, "unit/OperatorAndNormalizeArguments");
- ti_success!(ti_success_unit_OperatorEqual, "unit/OperatorEqual");
- ti_success!(ti_success_unit_OperatorEqualNormalizeArguments, "unit/OperatorEqualNormalizeArguments");
- ti_success!(ti_success_unit_OperatorListConcatenate, "unit/OperatorListConcatenate");
- ti_success!(ti_success_unit_OperatorListConcatenateNormalizeArguments, "unit/OperatorListConcatenateNormalizeArguments");
- ti_success!(ti_success_unit_OperatorNotEqual, "unit/OperatorNotEqual");
- ti_success!(ti_success_unit_OperatorNotEqualNormalizeArguments, "unit/OperatorNotEqualNormalizeArguments");
- ti_success!(ti_success_unit_OperatorOr, "unit/OperatorOr");
- ti_success!(ti_success_unit_OperatorOrNormalizeArguments, "unit/OperatorOrNormalizeArguments");
- ti_success!(ti_success_unit_OperatorPlus, "unit/OperatorPlus");
- ti_success!(ti_success_unit_OperatorPlusNormalizeArguments, "unit/OperatorPlusNormalizeArguments");
- ti_success!(ti_success_unit_OperatorTextConcatenate, "unit/OperatorTextConcatenate");
- ti_success!(ti_success_unit_OperatorTextConcatenateNormalizeArguments, "unit/OperatorTextConcatenateNormalizeArguments");
- ti_success!(ti_success_unit_OperatorTimes, "unit/OperatorTimes");
- ti_success!(ti_success_unit_OperatorTimesNormalizeArguments, "unit/OperatorTimesNormalizeArguments");
- ti_success!(ti_success_unit_Optional, "unit/Optional");
- ti_success!(ti_success_unit_OptionalBuild, "unit/OptionalBuild");
- ti_success!(ti_success_unit_OptionalFold, "unit/OptionalFold");
- ti_success!(ti_success_unit_RecordEmpty, "unit/RecordEmpty");
- ti_success!(ti_success_unit_RecordNestedKind, "unit/RecordNestedKind");
- ti_success!(ti_success_unit_RecordNestedKindLike, "unit/RecordNestedKindLike");
- ti_success!(ti_success_unit_RecordNestedType, "unit/RecordNestedType");
- ti_success!(ti_success_unit_RecordNestedTypeLike, "unit/RecordNestedTypeLike");
- ti_success!(ti_success_unit_RecordOneKind, "unit/RecordOneKind");
- ti_success!(ti_success_unit_RecordOneType, "unit/RecordOneType");
- ti_success!(ti_success_unit_RecordOneValue, "unit/RecordOneValue");
- ti_success!(ti_success_unit_RecordProjectionEmpty, "unit/RecordProjectionEmpty");
- ti_success!(ti_success_unit_RecordProjectionKind, "unit/RecordProjectionKind");
- ti_success!(ti_success_unit_RecordProjectionType, "unit/RecordProjectionType");
- ti_success!(ti_success_unit_RecordProjectionValue, "unit/RecordProjectionValue");
- ti_success!(ti_success_unit_RecordSelectionKind, "unit/RecordSelectionKind");
- ti_success!(ti_success_unit_RecordSelectionType, "unit/RecordSelectionType");
- ti_success!(ti_success_unit_RecordSelectionValue, "unit/RecordSelectionValue");
- ti_success!(ti_success_unit_RecordType, "unit/RecordType");
- ti_success!(ti_success_unit_RecordTypeEmpty, "unit/RecordTypeEmpty");
- ti_success!(ti_success_unit_RecordTypeKind, "unit/RecordTypeKind");
- ti_success!(ti_success_unit_RecordTypeKindLike, "unit/RecordTypeKindLike");
- ti_success!(ti_success_unit_RecordTypeNestedKind, "unit/RecordTypeNestedKind");
- ti_success!(ti_success_unit_RecordTypeNestedKindLike, "unit/RecordTypeNestedKindLike");
- ti_success!(ti_success_unit_RecordTypeType, "unit/RecordTypeType");
- ti_success!(ti_success_unit_RecursiveRecordMergeLhsEmpty, "unit/RecursiveRecordMergeLhsEmpty");
- ti_success!(ti_success_unit_RecursiveRecordMergeRecursively, "unit/RecursiveRecordMergeRecursively");
- ti_success!(ti_success_unit_RecursiveRecordMergeRecursivelyKinds, "unit/RecursiveRecordMergeRecursivelyKinds");
- ti_success!(ti_success_unit_RecursiveRecordMergeRecursivelyTypes, "unit/RecursiveRecordMergeRecursivelyTypes");
- ti_success!(ti_success_unit_RecursiveRecordMergeRhsEmpty, "unit/RecursiveRecordMergeRhsEmpty");
- ti_success!(ti_success_unit_RecursiveRecordMergeTwo, "unit/RecursiveRecordMergeTwo");
- ti_success!(ti_success_unit_RecursiveRecordMergeTwoKinds, "unit/RecursiveRecordMergeTwoKinds");
- ti_success!(ti_success_unit_RecursiveRecordMergeTwoTypes, "unit/RecursiveRecordMergeTwoTypes");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeRecursively, "unit/RecursiveRecordTypeMergeRecursively");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeRecursivelyKinds, "unit/RecursiveRecordTypeMergeRecursivelyKinds");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeRecursivelyTypes, "unit/RecursiveRecordTypeMergeRecursivelyTypes");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeRhsEmpty, "unit/RecursiveRecordTypeMergeRhsEmpty");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwo, "unit/RecursiveRecordTypeMergeTwo");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoKinds, "unit/RecursiveRecordTypeMergeTwoKinds");
- ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoTypes, "unit/RecursiveRecordTypeMergeTwoTypes");
- ti_success!(ti_success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty");
- ti_success!(ti_success_unit_RightBiasedRecordMergeTwo, "unit/RightBiasedRecordMergeTwo");
- ti_success!(ti_success_unit_RightBiasedRecordMergeTwoDifferent, "unit/RightBiasedRecordMergeTwoDifferent");
- ti_success!(ti_success_unit_RightBiasedRecordMergeTwoKinds, "unit/RightBiasedRecordMergeTwoKinds");
- ti_success!(ti_success_unit_RightBiasedRecordMergeTwoTypes, "unit/RightBiasedRecordMergeTwoTypes");
- ti_success!(ti_success_unit_SomeTrue, "unit/SomeTrue");
- ti_success!(ti_success_unit_Text, "unit/Text");
- ti_success!(ti_success_unit_TextLiteral, "unit/TextLiteral");
- ti_success!(ti_success_unit_TextLiteralNormalizeArguments, "unit/TextLiteralNormalizeArguments");
- ti_success!(ti_success_unit_TextLiteralWithInterpolation, "unit/TextLiteralWithInterpolation");
- ti_success!(ti_success_unit_TextShow, "unit/TextShow");
- ti_success!(ti_success_unit_True, "unit/True");
- ti_success!(ti_success_unit_Type, "unit/Type");
- ti_success!(ti_success_unit_TypeAnnotation, "unit/TypeAnnotation");
- ti_success!(ti_success_unit_TypeAnnotationSort, "unit/TypeAnnotationSort");
- ti_success!(ti_success_unit_UnionConstructorEmptyField, "unit/UnionConstructorEmptyField");
- ti_success!(ti_success_unit_UnionConstructorField, "unit/UnionConstructorField");
- ti_success!(ti_success_unit_UnionLiteralOne, "unit/UnionLiteralOne");
- ti_success!(ti_success_unit_UnionTypeEmpty, "unit/UnionTypeEmpty");
- ti_success!(ti_success_unit_UnionTypeKind, "unit/UnionTypeKind");
- ti_success!(ti_success_unit_UnionTypeOne, "unit/UnionTypeOne");
- ti_success!(ti_success_unit_UnionTypeType, "unit/UnionTypeType");
-}
diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs
index 2f68dac..15bc97a 100644
--- a/dhall/src/tests.rs
+++ b/dhall/src/tests.rs
@@ -45,6 +45,7 @@ pub enum Feature {
Parser,
Printer,
BinaryEncoding,
+ BinaryDecoding,
Import,
Normalization,
AlphaNormalization,
@@ -80,25 +81,33 @@ pub fn run_test(
) -> Result<()> {
use self::Feature::*;
use self::Status::*;
- let feature_prefix = match feature {
- Parser => "parser/",
- Printer => "parser/",
- BinaryEncoding => "parser/",
- Import => "import/",
- Normalization => "normalization/",
- AlphaNormalization => "alpha-normalization/",
- Typecheck => "typecheck/",
- TypeInference => "type-inference/",
- };
- let base_path =
- "../dhall-lang/tests/".to_owned() + feature_prefix + base_path;
+ let base_path = base_path.to_owned();
match status {
Success => {
+ match feature {
+ BinaryDecoding => {
+ let expr_file_path = base_path.clone() + "A.dhallb";
+ let expr_file_path = PathBuf::from(&expr_file_path);
+ let mut expr_data = Vec::new();
+ {
+ File::open(&expr_file_path)?
+ .read_to_end(&mut expr_data)?;
+ }
+ let expr = Parsed::parse_binary(&expr_data)?;
+ let expected_file_path = base_path + "B.dhall";
+ let expected = parse_file_str(&expected_file_path)?;
+ assert_eq_pretty!(expr, expected);
+
+ return Ok(());
+ }
+ _ => {}
+ }
let expr_file_path = base_path.clone() + "A.dhall";
let expr = parse_file_str(&expr_file_path)?;
match feature {
Parser => {
+ // This exercices both parsing and binary decoding
// Compare parse/decoded
let expected_file_path = base_path + "B.dhallb";
let expected_file_path = PathBuf::from(&expected_file_path);
@@ -164,7 +173,9 @@ pub fn run_test(
.normalize();
match feature {
- Parser | Printer | BinaryEncoding => unreachable!(),
+ Parser | Printer | BinaryEncoding | BinaryDecoding => {
+ unreachable!()
+ }
Import => {
let expr = expr.skip_typecheck().normalize();
assert_eq_display!(expr, expected);
@@ -195,10 +206,21 @@ pub fn run_test(
let err = parse_file_str(&file_path).unwrap_err();
match err {
Error::Parse(_) => {}
+ Error::IO(e)
+ if e.kind() == std::io::ErrorKind::InvalidData => {}
e => panic!("Expected parse error, got: {:?}", e),
}
}
Printer | BinaryEncoding => unreachable!(),
+ BinaryDecoding => {
+ let expr_file_path = file_path + "b";
+ let mut expr_data = Vec::new();
+ {
+ File::open(&PathBuf::from(&expr_file_path))?
+ .read_to_end(&mut expr_data)?;
+ }
+ Parsed::parse_binary(&expr_data).unwrap_err();
+ }
Import => {
parse_file_str(&file_path)?.resolve().unwrap_err();
}