summaryrefslogtreecommitdiff
path: root/dhall
diff options
context:
space:
mode:
Diffstat (limited to '')
m---------dhall-lang0
-rw-r--r--dhall/build.rs207
-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
-rw-r--r--dhall/tests/traits.rs30
-rw-r--r--dhall_generated_parser/build.rs15
-rw-r--r--dhall_generated_parser/src/dhall.pest.visibility21
-rw-r--r--dhall_proc_macros/src/lib.rs11
-rw-r--r--dhall_proc_macros/src/quote.rs223
-rw-r--r--dhall_syntax/src/core/expr.rs58
-rw-r--r--dhall_syntax/src/core/import.rs2
-rw-r--r--dhall_syntax/src/core/map.rs95
-rw-r--r--dhall_syntax/src/core/visitor.rs33
-rw-r--r--dhall_syntax/src/parser.rs146
-rw-r--r--dhall_syntax/src/printer.rs27
23 files changed, 1000 insertions, 1111 deletions
diff --git a/dhall-lang b/dhall-lang
-Subproject ee528e5a89f78bce2c28167b5dfb7e7ea6b3d6c
+Subproject 235d2c0b11a539003d2de6110f8666e93ae1ccd
diff --git a/dhall/build.rs b/dhall/build.rs
index 3f09d47..790ad8e 100644
--- a/dhall/build.rs
+++ b/dhall/build.rs
@@ -15,11 +15,15 @@ fn dhall_files_in_dir<'a>(
.filter_map(move |path| {
let path = path.path();
let path = path.strip_prefix(dir).unwrap();
- if path.extension() != Some(&OsString::from("dhall")) {
+ let ext = path.extension();
+ if ext != Some(&OsString::from("dhall"))
+ && ext != Some(&OsString::from("dhallb"))
+ {
return None;
}
+ let ext = ext.unwrap();
let path = path.to_string_lossy();
- let path = &path[..path.len() - 6];
+ let path = &path[..path.len() - 1 - ext.len()];
let path = if take_a_suffix {
if &path[path.len() - 1..] != "A" {
return None;
@@ -37,29 +41,37 @@ fn dhall_files_in_dir<'a>(
fn make_test_module(
w: &mut impl Write, // Where to output the generated code
mod_name: &str, // Name of the module, used in the output of `cargo test`
- dir: &Path, // Directory containing the tests files
+ subdir: &str, // Directory containing the tests files
feature: &str, // Relevant variant of `dhall::tests::Feature`
mut exclude: impl FnMut(&str) -> bool, // Given a file name, whether to exclude it
) -> std::io::Result<()> {
+ let all_tests_dir = Path::new("../dhall-lang/tests/");
+ let tests_dir = all_tests_dir.join(subdir);
writeln!(w, "mod {} {{", mod_name)?;
- for (name, path) in dhall_files_in_dir(&dir.join("success/"), true) {
+ for (name, path) in dhall_files_in_dir(&tests_dir.join("success/"), true) {
if exclude(&("success/".to_owned() + &path)) {
continue;
}
writeln!(
w,
- r#"make_spec_test!({}, Success, success_{}, "success/{}");"#,
- feature, name, path
+ r#"make_spec_test!({}, Success, success_{}, "{}/success/{}");"#,
+ feature,
+ name,
+ tests_dir.to_string_lossy(),
+ path
)?;
}
- for (name, path) in dhall_files_in_dir(&dir.join("failure/"), false) {
+ for (name, path) in dhall_files_in_dir(&tests_dir.join("failure/"), false) {
if exclude(&("failure/".to_owned() + &path)) {
continue;
}
writeln!(
w,
- r#"make_spec_test!({}, Failure, failure_{}, "failure/{}");"#,
- feature, name, path
+ r#"make_spec_test!({}, Failure, failure_{}, "{}/failure/{}");"#,
+ feature,
+ name,
+ tests_dir.to_string_lossy(),
+ path
)?;
}
writeln!(w, "}}")?;
@@ -67,83 +79,198 @@ fn make_test_module(
}
fn main() -> std::io::Result<()> {
- // Tries to detect when the submodule gets updated; doesn't really work.
+ // Tries to detect when the submodule gets updated.
// To force regeneration of the test list, just `touch dhall-lang/.git`
println!("cargo:rerun-if-changed=../dhall-lang/.git");
println!(
"cargo:rerun-if-changed=../.git/modules/dhall-lang/refs/heads/master"
);
let out_dir = env::var("OUT_DIR").unwrap();
- let tests_dir = Path::new("../dhall-lang/tests/");
let parser_tests_path = Path::new(&out_dir).join("spec_tests.rs");
let mut file = File::create(parser_tests_path)?;
- make_test_module(
- &mut file,
- "parse",
- &tests_dir.join("parser/"),
- "Parser",
- |path| {
- // Too slow in debug mode
- path == "success/largeExpression"
- },
- )?;
+ make_test_module(&mut file, "parse", "parser/", "Parser", |path| {
+ // Too slow in debug mode
+ path == "success/largeExpression"
+ // TODO: Inline headers
+ || path == "success/unit/import/inlineUsing"
+ || path == "success/unit/import/Headers"
+ || path == "success/unit/import/HeadersDoubleHash"
+ || path == "success/unit/import/HeadersDoubleHashPrecedence"
+ || path == "success/unit/import/HeadersHashPrecedence"
+ || path == "success/unit/import/HeadersInteriorHash"
+ // TODO: projection by expression
+ || path == "success/recordProjectionByExpression"
+ || path == "success/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByTypeEmpty"
+ || path == "success/unit/RecordProjectFields"
+ // TODO: RFC3986 URLs
+ || path == "success/unit/import/urls/emptyPath0"
+ || path == "success/unit/import/urls/emptyPath1"
+ || path == "success/unit/import/urls/emptyPathSegment"
+ // TODO: toMap
+ || path == "success/toMap"
+ })?;
- make_test_module(
- &mut file,
- "printer",
- &tests_dir.join("parser/"),
- "Printer",
- |path| {
- // Failure tests are only for the parser
- path.starts_with("failure/")
+ make_test_module(&mut file, "printer", "parser/", "Printer", |path| {
+ // Failure tests are only for the parser
+ path.starts_with("failure/")
// Too slow in debug mode
|| path == "success/largeExpression"
- },
- )?;
+ // TODO: Inline headers
+ || path == "success/unit/import/inlineUsing"
+ || path == "success/unit/import/Headers"
+ // TODO: projection by expression
+ || path == "success/recordProjectionByExpression"
+ || path == "success/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByTypeEmpty"
+ // TODO: RFC3986 URLs
+ || path == "success/unit/import/urls/emptyPath0"
+ || path == "success/unit/import/urls/emptyPath1"
+ || path == "success/unit/import/urls/emptyPathSegment"
+ // TODO: toMap
+ || path == "success/toMap"
+ })?;
make_test_module(
&mut file,
"binary_encoding",
- &tests_dir.join("parser/"),
+ "parser/",
"BinaryEncoding",
|path| {
// Failure tests are only for the parser
path.starts_with("failure/")
// Too slow in debug mode
|| path == "success/largeExpression"
- // Too much of a pain to implement; shouldn't make a difference
- // since lets disappear on normalization.
- || path == "success/multilet"
// See https://github.com/pyfisch/cbor/issues/109
|| path == "success/double"
+ || path == "success/unit/DoubleLitExponentNoDot"
+ || path == "success/unit/DoubleLitSecretelyInt"
+ // TODO: Inline headers
+ || path == "success/unit/import/inlineUsing"
+ || path == "success/unit/import/Headers"
+ // TODO: projection by expression
+ || path == "success/recordProjectionByExpression"
+ || path == "success/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByTypeEmpty"
+ // TODO: RFC3986 URLs
+ || path == "success/unit/import/urls/emptyPath0"
+ || path == "success/unit/import/urls/emptyPath1"
+ || path == "success/unit/import/urls/emptyPathSegment"
+ // TODO: toMap
+ || path == "success/toMap"
+ },
+ )?;
+
+ make_test_module(
+ &mut file,
+ "binary_decoding",
+ "binary-decode/",
+ "BinaryDecoding",
+ |path| {
+ false
+ // TODO: projection by expression
+ || path == "success/unit/RecordProjectFields"
+ || path == "success/unit/recordProjectionByExpression"
+ // TODO: toMap
+ || path == "success/unit/ToMap"
+ || path == "success/unit/ToMapAnnotated"
},
)?;
make_test_module(
&mut file,
"beta_normalize",
- &tests_dir.join("normalization/"),
+ "normalization/",
"Normalization",
|path| {
// We don't support bignums
path == "success/simple/integerToDouble"
// Too slow
|| path == "success/remoteSystems"
- // TODO: selection by expression
- || path == "success/unit/RecordProjectionTypeEmpty"
- || path == "success/unit/RecordProjectionTypeNonEmpty"
+ // TODO: projection by expression
+ || path == "success/unit/RecordProjectionByTypeEmpty"
+ || path == "success/unit/RecordProjectionByTypeNonEmpty"
+ || path == "success/unit/RecordProjectionByTypeNormalizeProjection"
+ // TODO: fix Double/show
+ || path == "success/prelude/JSON/number/1"
+ // TODO: toMap
+ || path == "success/unit/EmptyToMap"
+ || path == "success/unit/ToMap"
+ || path == "success/unit/ToMapWithType"
+ // TODO: Normalize field selection further by inspecting the argument
+ || path == "success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0"
+ || path == "success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1"
+ || path == "success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselection"
+ || path == "success/unit/RecordProjectionByTypeWithinFieldSelection"
+ || path == "success/unit/RecordProjectionWithinFieldSelection"
+ || path == "success/unit/RecursiveRecordMergeWithinFieldSelection0"
+ || path == "success/unit/RecursiveRecordMergeWithinFieldSelection1"
+ || path == "success/unit/RecursiveRecordMergeWithinFieldSelection2"
+ || path == "success/unit/RecursiveRecordMergeWithinFieldSelection3"
+ || path == "success/unit/RightBiasedMergeWithinFieldSelection0"
+ || path == "success/unit/RightBiasedMergeWithinFieldSelection1"
+ || path == "success/unit/RightBiasedMergeWithinFieldSelection2"
+ || path == "success/unit/RightBiasedMergeWithinFieldSelection3"
+ || path == "success/unit/RightBiasedMergeEquivalentArguments"
},
)?;
make_test_module(
&mut file,
"alpha_normalize",
- &tests_dir.join("alpha-normalization/"),
+ "alpha-normalization/",
"AlphaNormalization",
|_| false,
)?;
+ make_test_module(
+ &mut file,
+ "typecheck",
+ "typecheck/",
+ "Typecheck",
+ |path| {
+ false
+ // TODO: Enable imports in typecheck tests
+ || path == "failure/importBoundary"
+ // Too slow
+ || path == "success/prelude"
+ // TODO: Inline headers
+ || path == "failure/customHeadersUsingBoundVariable"
+ // TODO: projection by expression
+ || path == "failure/unit/RecordProjectionByTypeFieldTypeMismatch"
+ || path == "failure/unit/RecordProjectionByTypeNotPresent"
+ // TODO: toMap
+ || path == "failure/unit/EmptyToMap"
+ || path == "failure/unit/HeterogenousToMap"
+ || path == "failure/unit/MistypedToMap1"
+ || path == "failure/unit/MistypedToMap2"
+ || path == "failure/unit/MistypedToMap3"
+ || path == "failure/unit/MistypedToMap4"
+ || path == "failure/unit/NonRecordToMap"
+ },
+ )?;
+
+ make_test_module(
+ &mut file,
+ "type_inference",
+ "type-inference/",
+ "TypeInference",
+ |path| {
+ false
+ // TODO: projection by expression
+ || path == "success/unit/RecordProjectionByType"
+ || path == "success/unit/RecordProjectionByTypeEmpty"
+ || path == "success/unit/RecordProjectionByTypeJudgmentalEquality"
+ // TODO: toMap
+ || path == "success/unit/ToMap"
+ || path == "success/unit/ToMapAnnotated"
+ },
+ )?;
+
Ok(())
}
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();
}
diff --git a/dhall/tests/traits.rs b/dhall/tests/traits.rs
index 75eaf75..0f75553 100644
--- a/dhall/tests/traits.rs
+++ b/dhall/tests/traits.rs
@@ -1,23 +1,18 @@
#![feature(proc_macro_hygiene)]
-use dhall::de::{StaticType, Type};
-use dhall_proc_macros::subexpr;
-use dhall_syntax::{SubExpr, X};
+use dhall::de::{from_str, StaticType, Type};
#[test]
fn test_static_type() {
- fn mktype(x: SubExpr<X, X>) -> Type {
- Type::from_normalized_expr(x)
+ fn parse(s: &str) -> Type {
+ from_str(s, None).unwrap()
}
- assert_eq!(bool::static_type(), mktype(subexpr!(Bool)));
- assert_eq!(String::static_type(), mktype(subexpr!(Text)));
- assert_eq!(
- <Option<bool>>::static_type(),
- mktype(subexpr!(Optional Bool))
- );
+ assert_eq!(bool::static_type(), parse("Bool"));
+ assert_eq!(String::static_type(), parse("Text"));
+ assert_eq!(<Option<bool>>::static_type(), parse("Optional Bool"));
assert_eq!(
<(bool, Vec<String>)>::static_type(),
- mktype(subexpr!({ _1: Bool, _2: List Text }))
+ parse("{ _1: Bool, _2: List Text }")
);
#[derive(dhall::de::StaticType)]
@@ -28,7 +23,7 @@ fn test_static_type() {
}
assert_eq!(
<A as dhall::de::StaticType>::static_type(),
- mktype(subexpr!({ field1: Bool, field2: Optional Bool }))
+ parse("{ field1: Bool, field2: Optional Bool }")
);
#[derive(StaticType)]
@@ -52,7 +47,7 @@ fn test_static_type() {
struct D();
assert_eq!(
<C<D>>::static_type(),
- mktype(subexpr!({ _1: {}, _2: Optional Text }))
+ parse("{ _1: {}, _2: Optional Text }")
);
#[derive(StaticType)]
@@ -61,10 +56,7 @@ fn test_static_type() {
A(T),
B(String),
};
- assert_eq!(
- <E<bool>>::static_type(),
- mktype(subexpr!(< A: Bool | B: Text >))
- );
+ assert_eq!(<E<bool>>::static_type(), parse("< A: Bool | B: Text >"));
#[derive(StaticType)]
#[allow(dead_code)]
@@ -72,5 +64,5 @@ fn test_static_type() {
A,
B(bool),
};
- assert_eq!(F::static_type(), mktype(subexpr!(< A | B: Bool >)));
+ assert_eq!(F::static_type(), parse("< A | B: Bool >"));
}
diff --git a/dhall_generated_parser/build.rs b/dhall_generated_parser/build.rs
index eab48bf..5275097 100644
--- a/dhall_generated_parser/build.rs
+++ b/dhall_generated_parser/build.rs
@@ -26,6 +26,8 @@ fn main() -> std::io::Result<()> {
rules.get_mut(&line[2..]).map(|x| x.silent = true);
}
}
+ rules.remove("http");
+ rules.remove("url_path");
rules.remove("simple_label");
rules.remove("nonreserved_label");
@@ -41,6 +43,19 @@ fn main() -> std::io::Result<()> {
| !keyword ~ simple_label_first_char ~ simple_label_next_char*
}}"
)?;
+ // TODO: this is a cheat; actually implement inline headers instead
+ writeln!(
+ &mut file,
+ "http = {{
+ http_raw
+ ~ (whsp
+ ~ using
+ ~ whsp1
+ ~ (import_hashed | ^\"(\" ~ whsp ~ import_hashed ~ whsp ~ ^\")\"))?
+ }}"
+ )?;
+ // TODO: this is a cheat; properly support RFC3986 URLs instead
+ writeln!(&mut file, "url_path = _{{ path }}")?;
writeln!(
&mut file,
"nonreserved_label = _{{
diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall_generated_parser/src/dhall.pest.visibility
index 60de54d..6b4c974 100644
--- a/dhall_generated_parser/src/dhall.pest.visibility
+++ b/dhall_generated_parser/src/dhall.pest.visibility
@@ -1,4 +1,5 @@
# end_of_line
+# valid_non_ascii
# tab
# block_comment
# block_comment_char
@@ -10,6 +11,7 @@
# whsp1
# ALPHA
# DIGIT
+# ALPHANUM
# HEXDIG
# simple_label_first_char
# simple_label_next_char
@@ -21,6 +23,7 @@ label
# any_label
double_quote_chunk
double_quote_escaped
+# unicode_escape
double_quote_char
double_quote_literal
single_quote_continue
@@ -42,11 +45,14 @@ missing
# Infinity
NaN
Some_
+toMap
+assert
# keyword
builtin
Optional
Text
List
+Location
# Bool
# True
# False
@@ -66,6 +72,7 @@ List
# Natural_show
# Integer_toDouble
# Integer_show
+# Natural_subtract
# Double_show
# List_build
# List_fold
@@ -79,6 +86,7 @@ List
# Text_show
# combine
# combine_types
+# equivalent
# prefer
lambda
forall
@@ -116,7 +124,8 @@ authority
# ls32
# IPv4address
# dec_octet
-# reg_name
+# domain
+# domainlabel
# pchar
query
# pct_encoded
@@ -134,8 +143,7 @@ import
expression
annotated_expression
let_binding
-empty_collection
-non_empty_optional
+empty_list_literal
# operator_expression
import_alt_expression
or_expression
@@ -149,6 +157,7 @@ combine_types_expression
times_expression
equal_expression
not_equal_expression
+equivalent_expression
application_expression
first_application_expression
# import_expression
@@ -165,11 +174,9 @@ non_empty_record_type
record_type_entry
non_empty_record_literal
record_literal_entry
-union_type_or_literal
+union_type
empty_union_type
-non_empty_union_type_or_literal
-union_literal_variant_value
+# non_empty_union_type
union_type_entry
-union_type_or_literal_variant_type
non_empty_list_literal
# complete_expression
diff --git a/dhall_proc_macros/src/lib.rs b/dhall_proc_macros/src/lib.rs
index e4aa8b5..5304429 100644
--- a/dhall_proc_macros/src/lib.rs
+++ b/dhall_proc_macros/src/lib.rs
@@ -6,20 +6,9 @@
extern crate proc_macro;
mod derive;
-mod quote;
use proc_macro::TokenStream;
-#[proc_macro]
-pub fn expr(input: TokenStream) -> TokenStream {
- quote::expr(input)
-}
-
-#[proc_macro]
-pub fn subexpr(input: TokenStream) -> TokenStream {
- quote::subexpr(input)
-}
-
#[proc_macro_derive(StaticType)]
pub fn derive_static_type(input: TokenStream) -> TokenStream {
derive::derive_static_type(input)
diff --git a/dhall_proc_macros/src/quote.rs b/dhall_proc_macros/src/quote.rs
deleted file mode 100644
index 3dbfba9..0000000
--- a/dhall_proc_macros/src/quote.rs
+++ /dev/null
@@ -1,223 +0,0 @@
-extern crate proc_macro;
-use dhall_syntax::context::Context;
-use dhall_syntax::*;
-use proc_macro2::TokenStream;
-use quote::quote;
-
-pub fn expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- let input_str = input.to_string();
- let expr: SubExpr<_, Import> = parse_expr(&input_str).unwrap();
- let no_import =
- |_: &Import| -> X { panic!("Don't use import in dhall::expr!()") };
- let expr = expr.map_embed(no_import);
- let output = quote_expr(expr.as_ref(), &Context::new());
- output.into()
-}
-
-pub fn subexpr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- let input_str = input.to_string();
- let expr: SubExpr<_, Import> = parse_expr(&input_str).unwrap();
- let no_import =
- |_: &Import| -> X { panic!("Don't use import in dhall::subexpr!()") };
- let expr = expr.map_embed(no_import);
- let output = quote_subexpr(&expr, &Context::new());
- output.into()
-}
-
-// Returns an expression of type ExprF<T, _>, where T is the
-// type of the subexpressions after interpolation.
-pub fn quote_exprf<TS>(expr: ExprF<TS, X>) -> TokenStream
-where
- TS: quote::ToTokens + std::fmt::Debug,
-{
- use dhall_syntax::ExprF::*;
- match expr {
- Var(_) => unreachable!(),
- Pi(x, t, b) => {
- let x = quote_label(&x);
- quote! { dhall_syntax::ExprF::Pi(#x, #t, #b) }
- }
- Lam(x, t, b) => {
- let x = quote_label(&x);
- quote! { dhall_syntax::ExprF::Lam(#x, #t, #b) }
- }
- App(f, a) => {
- quote! { dhall_syntax::ExprF::App(#f, #a) }
- }
- Annot(x, t) => {
- quote! { dhall_syntax::ExprF::Annot(#x, #t) }
- }
- Const(c) => {
- let c = quote_const(c);
- quote! { dhall_syntax::ExprF::Const(#c) }
- }
- Builtin(b) => {
- let b = quote_builtin(b);
- quote! { dhall_syntax::ExprF::Builtin(#b) }
- }
- BinOp(o, a, b) => {
- let o = quote_binop(o);
- quote! { dhall_syntax::ExprF::BinOp(#o, #a, #b) }
- }
- NaturalLit(n) => {
- quote! { dhall_syntax::ExprF::NaturalLit(#n) }
- }
- BoolLit(b) => {
- quote! { dhall_syntax::ExprF::BoolLit(#b) }
- }
- SomeLit(x) => {
- quote! { dhall_syntax::ExprF::SomeLit(#x) }
- }
- EmptyListLit(t) => {
- quote! { dhall_syntax::ExprF::EmptyListLit(#t) }
- }
- NEListLit(es) => {
- let es = quote_vec(es);
- quote! { dhall_syntax::ExprF::NEListLit(#es) }
- }
- RecordType(m) => {
- let m = quote_map(m);
- quote! { dhall_syntax::ExprF::RecordType(#m) }
- }
- RecordLit(m) => {
- let m = quote_map(m);
- quote! { dhall_syntax::ExprF::RecordLit(#m) }
- }
- UnionType(m) => {
- let m = quote_opt_map(m);
- quote! { dhall_syntax::ExprF::UnionType(#m) }
- }
- e => unimplemented!("{:?}", e),
- }
-}
-
-// Returns an expression of type SubExpr<_, _>. Expects interpolated variables
-// to be of type SubExpr<_, _>.
-fn quote_subexpr<N>(
- expr: &SubExpr<N, X>,
- ctx: &Context<Label, ()>,
-) -> TokenStream {
- use dhall_syntax::ExprF::*;
- match expr.as_ref().map_ref_with_special_handling_of_binders(
- |e| quote_subexpr(e, ctx),
- |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())),
- |_| unreachable!(),
- ) {
- Var(V(ref s, n)) => {
- match ctx.lookup(s, n) {
- // Non-free variable; interpolates as itself
- Some(()) => {
- let s: String = s.into();
- let var = quote! { dhall_syntax::V(#s.into(), #n) };
- rc(quote! { dhall_syntax::ExprF::Var(#var) })
- }
- // Free variable; interpolates as a rust variable
- None => {
- let s: String = s.into();
- // TODO: insert appropriate shifts ?
- let v: TokenStream = s.parse().unwrap();
- quote! { {
- let x: dhall_syntax::SubExpr<_, _> = #v.clone();
- x
- } }
- }
- }
- }
- e => rc(quote_exprf(e)),
- }
-}
-
-// Returns an expression of type Expr<_, _>. Expects interpolated variables
-// to be of type SubExpr<_, _>.
-fn quote_expr<N>(expr: &Expr<N, X>, ctx: &Context<Label, ()>) -> TokenStream {
- use dhall_syntax::ExprF::*;
- match expr.map_ref_with_special_handling_of_binders(
- |e| quote_subexpr(e, ctx),
- |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())),
- |_| unreachable!(),
- ) {
- Var(V(ref s, n)) => {
- match ctx.lookup(s, n) {
- // Non-free variable; interpolates as itself
- Some(()) => {
- let s: String = s.into();
- let var = quote! { dhall_syntax::V(#s.into(), #n) };
- quote! { dhall_syntax::ExprF::Var(#var) }
- }
- // Free variable; interpolates as a rust variable
- None => {
- let s: String = s.into();
- // TODO: insert appropriate shifts ?
- let v: TokenStream = s.parse().unwrap();
- quote! { {
- let x: dhall_syntax::SubExpr<_, _> = #v.clone();
- x.unroll()
- } }
- }
- }
- }
- e => quote_exprf(e),
- }
-}
-
-fn quote_builtin(b: Builtin) -> TokenStream {
- format!("::dhall_syntax::Builtin::{:?}", b).parse().unwrap()
-}
-
-fn quote_const(c: Const) -> TokenStream {
- format!("::dhall_syntax::Const::{:?}", c).parse().unwrap()
-}
-
-fn quote_binop(b: BinOp) -> TokenStream {
- format!("::dhall_syntax::BinOp::{:?}", b).parse().unwrap()
-}
-
-fn quote_label(l: &Label) -> TokenStream {
- let l = String::from(l);
- quote! { dhall_syntax::Label::from(#l) }
-}
-
-fn rc(x: TokenStream) -> TokenStream {
- quote! { ::dhall_syntax::rc(#x) }
-}
-
-fn quote_opt<TS>(x: Option<TS>) -> TokenStream
-where
- TS: quote::ToTokens + std::fmt::Debug,
-{
- match x {
- Some(x) => quote!(Some(#x)),
- None => quote!(None),
- }
-}
-
-fn quote_vec<TS>(e: Vec<TS>) -> TokenStream
-where
- TS: quote::ToTokens + std::fmt::Debug,
-{
- quote! { vec![ #(#e),* ] }
-}
-
-fn quote_map<TS>(m: impl IntoIterator<Item = (Label, TS)>) -> TokenStream
-where
- TS: quote::ToTokens + std::fmt::Debug,
-{
- let entries = m.into_iter().map(|(k, v)| {
- let k = quote_label(&k);
- quote!(m.insert(#k, #v);)
- });
- quote! { {
- let mut m = ::dhall_syntax::map::DupTreeMap::new();
- #( #entries )*
- m
- } }
-}
-
-fn quote_opt_map<TS>(
- m: impl IntoIterator<Item = (Label, Option<TS>)>,
-) -> TokenStream
-where
- TS: quote::ToTokens + std::fmt::Debug,
-{
- quote_map(m.into_iter().map(|(k, v)| (k, quote_opt(v))))
-}
diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs
index da9465d..6522cb1 100644
--- a/dhall_syntax/src/core/expr.rs
+++ b/dhall_syntax/src/core/expr.rs
@@ -1,6 +1,6 @@
use std::rc::Rc;
-use crate::map::DupTreeMap;
+use crate::map::{DupTreeMap, DupTreeSet};
use crate::visitor;
use crate::*;
@@ -44,7 +44,7 @@ impl From<NaiveDouble> for f64 {
}
/// Constants for a pure type system
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Const {
Type,
Kind,
@@ -99,6 +99,8 @@ pub enum BinOp {
BoolEQ,
/// `x != y`
BoolNE,
+ /// x === y
+ Equivalence,
}
/// Built-ins
@@ -119,6 +121,7 @@ pub enum Builtin {
NaturalOdd,
NaturalToInteger,
NaturalShow,
+ NaturalSubtract,
IntegerToDouble,
IntegerShow,
DoubleShow,
@@ -174,6 +177,8 @@ pub enum ExprF<SubExpr, Embed> {
Let(Label, Option<SubExpr>, SubExpr, SubExpr),
/// `x : t`
Annot(SubExpr, SubExpr),
+ /// `assert : t`
+ Assert(SubExpr),
/// Built-in values
Builtin(Builtin),
// Binary operations
@@ -190,14 +195,10 @@ pub enum ExprF<SubExpr, Embed> {
DoubleLit(Double),
/// `"Some ${interpolated} text"`
TextLit(InterpolatedText<SubExpr>),
- /// `[] : List t`
+ /// `[] : t`
EmptyListLit(SubExpr),
/// `[x, y, z]`
NEListLit(Vec<SubExpr>),
- /// Deprecated Optional literal form
- /// `[] : Optional a`
- /// `[x] : Optional a`
- OldOptionalLit(Option<SubExpr>, SubExpr),
/// `Some e`
SomeLit(SubExpr),
/// `{ k1 : t1, k2 : t1 }`
@@ -206,14 +207,12 @@ pub enum ExprF<SubExpr, Embed> {
RecordLit(DupTreeMap<Label, SubExpr>),
/// `< k1 : t1, k2 >`
UnionType(DupTreeMap<Label, Option<SubExpr>>),
- /// `< k1 = t1, k2 : t2, k3 >`
- UnionLit(Label, SubExpr, DupTreeMap<Label, Option<SubExpr>>),
/// `merge x y : t`
Merge(SubExpr, SubExpr, Option<SubExpr>),
/// `e.x`
Field(SubExpr, Label),
/// `e.{ x, y, z }`
- Projection(SubExpr, Vec<Label>),
+ Projection(SubExpr, DupTreeSet<Label>),
/// Embeds an import or the result of resolving the import
Embed(Embed),
}
@@ -311,6 +310,35 @@ impl<N, E> Expr<N, E> {
{
trivial_result(self.traverse_embed(|x| Ok(map_embed(x))))
}
+
+ pub fn traverse_resolve<E2, Err>(
+ &self,
+ visit_embed: impl FnMut(&E) -> Result<E2, Err>,
+ ) -> Result<Expr<N, E2>, Err>
+ where
+ N: Clone,
+ {
+ self.traverse_resolve_with_visitor(&mut visitor::ResolveVisitor(
+ visit_embed,
+ ))
+ }
+
+ pub(crate) fn traverse_resolve_with_visitor<E2, Err, F1>(
+ &self,
+ visitor: &mut visitor::ResolveVisitor<F1>,
+ ) -> Result<Expr<N, E2>, Err>
+ where
+ N: Clone,
+ F1: FnMut(&E) -> Result<E2, Err>,
+ {
+ match self {
+ ExprF::BinOp(BinOp::ImportAlt, l, r) => l
+ .as_ref()
+ .traverse_resolve_with_visitor(visitor)
+ .or(r.as_ref().traverse_resolve_with_visitor(visitor)),
+ _ => self.visit(visitor),
+ }
+ }
}
impl Expr<X, X> {
@@ -387,6 +415,16 @@ impl<N, E> SubExpr<N, E> {
)),
}
}
+
+ pub fn traverse_resolve<E2, Err>(
+ &self,
+ visit_embed: impl FnMut(&E) -> Result<E2, Err>,
+ ) -> Result<SubExpr<N, E2>, Err>
+ where
+ N: Clone,
+ {
+ Ok(self.rewrap(self.as_ref().traverse_resolve(visit_embed)?))
+ }
}
impl SubExpr<X, X> {
diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs
index ea42dbc..82bb7ff 100644
--- a/dhall_syntax/src/core/import.rs
+++ b/dhall_syntax/src/core/import.rs
@@ -57,6 +57,7 @@ pub struct URL {
pub authority: String,
pub path: File,
pub query: Option<String>,
+ // TODO: implement inline headers
pub headers: Option<Box<ImportHashed>>,
}
@@ -71,6 +72,7 @@ pub enum Scheme {
pub enum ImportMode {
Code,
RawText,
+ Location,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/dhall_syntax/src/core/map.rs b/dhall_syntax/src/core/map.rs
index 63f19cd..6a0ebda 100644
--- a/dhall_syntax/src/core/map.rs
+++ b/dhall_syntax/src/core/map.rs
@@ -1,5 +1,6 @@
/// A sorted map that allows multiple values for each key.
pub use dup_tree_map::DupTreeMap;
+pub use dup_tree_set::DupTreeSet;
mod one_or_more {
use either::Either;
@@ -232,3 +233,97 @@ mod dup_tree_map {
// unsafe impl<K, V> iter::TrustedLen for IntoIter<K, V> {}
}
+
+mod dup_tree_set {
+ use super::DupTreeMap;
+ use std::iter;
+
+ #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ pub struct DupTreeSet<K> {
+ map: DupTreeMap<K, ()>,
+ }
+
+ pub type Iter<'a, K> = iter::Map<
+ super::dup_tree_map::Iter<'a, K, ()>,
+ for<'b> fn((&'b K, &'b ())) -> &'b K,
+ >;
+ pub type IntoIter<K> =
+ iter::Map<super::dup_tree_map::IntoIter<K, ()>, fn((K, ())) -> K>;
+
+ impl<K> DupTreeSet<K> {
+ pub fn new() -> Self
+ where
+ K: Ord,
+ {
+ DupTreeSet {
+ map: DupTreeMap::new(),
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.map.len()
+ }
+ pub fn is_empty(&self) -> bool {
+ self.map.is_empty()
+ }
+
+ pub fn iter(&self) -> Iter<'_, K>
+ where
+ K: Ord,
+ {
+ fn foo<'a, K>((k, ()): (&'a K, &'a ())) -> &'a K {
+ k
+ }
+ self.map.iter().map(foo)
+ }
+ }
+
+ impl<K> Default for DupTreeSet<K>
+ where
+ K: Ord,
+ {
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+
+ impl<K> IntoIterator for DupTreeSet<K>
+ where
+ K: Ord + Clone,
+ {
+ type Item = K;
+ type IntoIter = IntoIter<K>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ fn foo<K>((k, ()): (K, ())) -> K {
+ k
+ }
+ self.map.into_iter().map(foo)
+ }
+ }
+
+ impl<'a, K> IntoIterator for &'a DupTreeSet<K>
+ where
+ K: Ord,
+ {
+ type Item = &'a K;
+ type IntoIter = Iter<'a, K>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+ }
+
+ impl<K> iter::FromIterator<K> for DupTreeSet<K>
+ where
+ K: Ord,
+ {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = K>,
+ {
+ let map = iter.into_iter().map(|k| (k, ())).collect();
+ DupTreeSet { map }
+ }
+ }
+}
diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs
index 99a9c11..18f76d9 100644
--- a/dhall_syntax/src/core/visitor.rs
+++ b/dhall_syntax/src/core/visitor.rs
@@ -137,17 +137,10 @@ where
),
EmptyListLit(t) => EmptyListLit(v.visit_subexpr(t)?),
NEListLit(es) => NEListLit(vec(es, |e| v.visit_subexpr(e))?),
- OldOptionalLit(x, t) => OldOptionalLit(
- opt(x, |e| v.visit_subexpr(e))?,
- v.visit_subexpr(t)?,
- ),
SomeLit(e) => SomeLit(v.visit_subexpr(e)?),
RecordType(kts) => RecordType(dupmap(kts, v)?),
RecordLit(kvs) => RecordLit(dupmap(kvs, v)?),
UnionType(kts) => UnionType(optdupmap(kts, v)?),
- UnionLit(k, x, kts) => {
- UnionLit(k.clone(), v.visit_subexpr(x)?, optdupmap(kts, v)?)
- }
Merge(x, y, t) => Merge(
v.visit_subexpr(x)?,
v.visit_subexpr(y)?,
@@ -155,6 +148,7 @@ where
),
Field(e, l) => Field(v.visit_subexpr(e)?, l.clone()),
Projection(e, ls) => Projection(v.visit_subexpr(e)?, ls.clone()),
+ Assert(e) => Assert(v.visit_subexpr(e)?),
Embed(a) => return v.visit_embed_squash(a),
})
}
@@ -362,6 +356,31 @@ where
}
}
+pub struct ResolveVisitor<F1>(pub F1);
+
+impl<'a, 'b, N, E, E2, Err, F1>
+ ExprFFallibleVisitor<'a, SubExpr<N, E>, SubExpr<N, E2>, E, E2>
+ for &'b mut ResolveVisitor<F1>
+where
+ N: Clone + 'a,
+ F1: FnMut(&E) -> Result<E2, Err>,
+{
+ type Error = Err;
+
+ fn visit_subexpr(
+ &mut self,
+ subexpr: &'a SubExpr<N, E>,
+ ) -> Result<SubExpr<N, E2>, Self::Error> {
+ Ok(subexpr.rewrap(
+ subexpr
+ .as_ref()
+ .traverse_resolve_with_visitor(&mut **self)?,
+ ))
+ }
+ fn visit_embed(self, embed: &'a E) -> Result<E2, Self::Error> {
+ (self.0)(embed)
+ }
+}
pub struct NoteAbsurdVisitor;
impl<'a, 'b, N, E>
diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs
index 7675622..a2495ee 100644
--- a/dhall_syntax/src/parser.rs
+++ b/dhall_syntax/src/parser.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
use dhall_generated_parser::{DhallParser, Rule};
-use crate::map::DupTreeMap;
+use crate::map::{DupTreeMap, DupTreeSet};
use crate::ExprF::*;
use crate::*;
@@ -80,6 +80,7 @@ impl crate::Builtin {
"Natural/odd" => Some(NaturalOdd),
"Natural/toInteger" => Some(NaturalToInteger),
"Natural/show" => Some(NaturalShow),
+ "Natural/subtract" => Some(NaturalSubtract),
"Integer/toDouble" => Some(IntegerToDouble),
"Integer/show" => Some(IntegerShow),
"Double/show" => Some(DoubleShow),
@@ -318,6 +319,7 @@ fn can_be_shortcutted(rule: Rule) -> bool {
| times_expression
| equal_expression
| not_equal_expression
+ | equivalent_expression
| application_expression
| first_application_expression
| selector_expression
@@ -410,11 +412,50 @@ make_parser! {
"n" => "\n".to_owned(),
"r" => "\r".to_owned(),
"t" => "\t".to_owned(),
+ // "uXXXX" or "u{XXXXX}"
_ => {
- // "uXXXX"
- use std::convert::TryFrom;
- let c = u16::from_str_radix(&s[1..5], 16).unwrap();
- let c = char::try_from(u32::from(c)).unwrap();
+ use std::convert::{TryFrom, TryInto};
+
+ let s = &s[1..];
+ let s = if &s[0..1] == "{" {
+ &s[1..s.len()-1]
+ } else {
+ &s[0..s.len()]
+ };
+
+ if s.len() > 8 {
+ Err(format!("Escape sequences can't have more than 8 chars: \"{}\"", s))?
+ }
+
+ // pad with zeroes
+ let s: String = std::iter::repeat('0')
+ .take(8 - s.len())
+ .chain(s.chars())
+ .collect();
+
+ // `s` has length 8, so `bytes` has length 4
+ let bytes: &[u8] = &hex::decode(s).unwrap();
+ let i = u32::from_be_bytes(bytes.try_into().unwrap());
+ let c = char::try_from(i).unwrap();
+ match i {
+ 0xD800..=0xDFFF => {
+ let c_ecapsed = c.escape_unicode();
+ Err(format!("Escape sequences can't contain surrogate pairs: \"{}\"", c_ecapsed))?
+ },
+ 0x0FFFE..=0x0FFFF | 0x1FFFE..=0x1FFFF |
+ 0x2FFFE..=0x2FFFF | 0x3FFFE..=0x3FFFF |
+ 0x4FFFE..=0x4FFFF | 0x5FFFE..=0x5FFFF |
+ 0x6FFFE..=0x6FFFF | 0x7FFFE..=0x7FFFF |
+ 0x8FFFE..=0x8FFFF | 0x9FFFE..=0x9FFFF |
+ 0xAFFFE..=0xAFFFF | 0xBFFFE..=0xBFFFF |
+ 0xCFFFE..=0xCFFFF | 0xDFFFE..=0xDFFFF |
+ 0xEFFFE..=0xEFFFF | 0xFFFFE..=0xFFFFF |
+ 0x10FFFE..=0x10FFFF => {
+ let c_ecapsed = c.escape_unicode();
+ Err(format!("Escape sequences can't contain non-characters: \"{}\"", c_ecapsed))?
+ },
+ _ => {}
+ }
std::iter::once(c).collect()
}
}
@@ -692,6 +733,7 @@ make_parser! {
));
token_rule!(Text<()>);
+ token_rule!(Location<()>);
rule!(import<ParsedSubExpr> as expression; span; children!(
[import_hashed(location_hashed)] => {
@@ -706,15 +748,28 @@ make_parser! {
location_hashed
}))
},
+ [import_hashed(location_hashed), Location(_)] => {
+ spanned(span, Embed(Import {
+ mode: ImportMode::Location,
+ location_hashed
+ }))
+ },
));
token_rule!(lambda<()>);
token_rule!(forall<()>);
token_rule!(arrow<()>);
token_rule!(merge<()>);
+ token_rule!(assert<()>);
token_rule!(if_<()>);
token_rule!(in_<()>);
+ rule!(empty_list_literal<ParsedSubExpr> as expression; span; children!(
+ [expression(e)] => {
+ spanned(span, EmptyListLit(e))
+ },
+ ));
+
rule!(expression<ParsedSubExpr> as expression; span; children!(
[lambda(()), label(l), expression(typ),
arrow(()), expression(body)] => {
@@ -739,6 +794,9 @@ make_parser! {
[merge(()), expression(x), expression(y), expression(z)] => {
spanned(span, Merge(x, y, Some(z)))
},
+ [assert(()), expression(x)] => {
+ spanned(span, Assert(x))
+ },
[expression(e)] => e,
));
@@ -753,21 +811,6 @@ make_parser! {
token_rule!(List<()>);
token_rule!(Optional<()>);
- rule!(empty_collection<ParsedSubExpr> as expression; span; children!(
- [List(_), expression(t)] => {
- spanned(span, EmptyListLit(t))
- },
- [Optional(_), expression(t)] => {
- spanned(span, OldOptionalLit(None, t))
- },
- ));
-
- rule!(non_empty_optional<ParsedSubExpr> as expression; span; children!(
- [expression(x), Optional(_), expression(t)] => {
- spanned(span, OldOptionalLit(Some(x), t))
- }
- ));
-
rule!(import_alt_expression<ParsedSubExpr> as expression; children!(
[expression(e)] => e,
[expression(first), expression(rest)..] => {
@@ -852,6 +895,13 @@ make_parser! {
rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e)))
},
));
+ rule!(equivalent_expression<ParsedSubExpr> as expression; children!(
+ [expression(e)] => e,
+ [expression(first), expression(rest)..] => {
+ let o = crate::BinOp::Equivalence;
+ rest.fold(first, |acc, e| unspanned(BinOp(o, acc, e)))
+ },
+ ));
rule!(annotated_expression<ParsedSubExpr> as expression; span; children!(
[expression(e)] => e,
@@ -861,6 +911,7 @@ make_parser! {
));
token_rule!(Some_<()>);
+ token_rule!(toMap<()>);
rule!(application_expression<ParsedSubExpr> as expression; children!(
[expression(e)] => e,
@@ -890,13 +941,13 @@ make_parser! {
}
));
- rule!(selector<Either<Label, Vec<Label>>>; children!(
+ rule!(selector<Either<Label, DupTreeSet<Label>>>; children!(
[label(l)] => Either::Left(l),
[labels(ls)] => Either::Right(ls),
[expression(e)] => unimplemented!("selection by expression"), // TODO
));
- rule!(labels<Vec<Label>>; children!(
+ rule!(labels<DupTreeSet<Label>>; children!(
[label(ls)..] => ls.collect(),
));
@@ -953,67 +1004,22 @@ make_parser! {
[label(name), expression(expr)] => (name, expr)
));
- rule!(union_type_or_literal<ParsedSubExpr> as expression; span; children!(
+ rule!(union_type<ParsedSubExpr> as expression; span; children!(
[empty_union_type(_)] => {
spanned(span, UnionType(Default::default()))
},
- [non_empty_union_type_or_literal((Some((l, e)), entries))] => {
- spanned(span, UnionLit(l, e, entries))
- },
- [non_empty_union_type_or_literal((None, entries))] => {
- spanned(span, UnionType(entries))
+ [union_type_entry(entries)..] => {
+ spanned(span, UnionType(entries.collect()))
},
));
token_rule!(empty_union_type<()>);
- rule!(non_empty_union_type_or_literal
- <(Option<(Label, ParsedSubExpr)>,
- DupTreeMap<Label, Option<ParsedSubExpr>>)>;
- children!(
- [label(l), union_literal_variant_value((e, entries))] => {
- (Some((l, e)), entries)
- },
- [label(l), union_type_or_literal_variant_type((e, rest))] => {
- let (x, mut entries) = rest;
- entries.insert(l, e);
- (x, entries)
- },
- ));
-
- rule!(union_literal_variant_value
- <(ParsedSubExpr, DupTreeMap<Label, Option<ParsedSubExpr>>)>;
- children!(
- [expression(e), union_type_entry(entries)..] => {
- (e, entries.collect())
- },
- ));
-
rule!(union_type_entry<(Label, Option<ParsedSubExpr>)>; children!(
[label(name), expression(expr)] => (name, Some(expr)),
[label(name)] => (name, None),
));
- // TODO: unary union variants
- rule!(union_type_or_literal_variant_type
- <(Option<ParsedSubExpr>,
- (Option<(Label, ParsedSubExpr)>,
- DupTreeMap<Label, Option<ParsedSubExpr>>))>;
- children!(
- [expression(e), non_empty_union_type_or_literal(rest)] => {
- (Some(e), rest)
- },
- [expression(e)] => {
- (Some(e), (None, Default::default()))
- },
- [non_empty_union_type_or_literal(rest)] => {
- (None, rest)
- },
- [] => {
- (None, (None, Default::default()))
- },
- ));
-
rule!(non_empty_list_literal<ParsedSubExpr> as expression; span;
children!(
[expression(items)..] => spanned(
diff --git a/dhall_syntax/src/printer.rs b/dhall_syntax/src/printer.rs
index 8503a1e..5312f23 100644
--- a/dhall_syntax/src/printer.rs
+++ b/dhall_syntax/src/printer.rs
@@ -27,17 +27,11 @@ impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> {
write!(f, " = {} in {}", c, d)?;
}
EmptyListLit(t) => {
- write!(f, "[] : List {}", t)?;
+ write!(f, "[] : {}", t)?;
}
NEListLit(es) => {
fmt_list("[", ", ", "]", es, f, Display::fmt)?;
}
- OldOptionalLit(None, t) => {
- write!(f, "[] : Optional {}", t)?;
- }
- OldOptionalLit(Some(x), t) => {
- write!(f, "[{}] : Optional {}", x, t)?;
- }
SomeLit(e) => {
write!(f, "Some {}", e)?;
}
@@ -50,6 +44,9 @@ impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> {
Annot(a, b) => {
write!(f, "{} : {}", a, b)?;
}
+ Assert(a) => {
+ write!(f, "assert : {}", a)?;
+ }
ExprF::BinOp(op, a, b) => {
write!(f, "{} {} {}", a, op, b)?;
}
@@ -91,16 +88,6 @@ impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> {
}
Ok(())
})?,
- UnionLit(a, b, c) => {
- write!(f, "< {} = {}", a, b)?;
- for (k, v) in c {
- write!(f, " | {}", k)?;
- if let Some(v) = v {
- write!(f, ": {}", v)?;
- }
- }
- f.write_str(" >")?
- }
Embed(a) => a.fmt(f)?,
}
Ok(())
@@ -154,7 +141,6 @@ impl<S: Clone, A: Display + Clone> Expr<S, A> {
| Let(_, _, _, _)
| EmptyListLit(_)
| NEListLit(_)
- | OldOptionalLit(_, _)
| SomeLit(_)
| Merge(_, _, _)
| Annot(_, _)
@@ -189,8 +175,6 @@ impl<S: Clone, A: Display + Clone> Expr<S, A> {
a.phase(PrintPhase::BinOp(op)),
b.phase(PrintPhase::BinOp(op)),
),
- EmptyListLit(t) => EmptyListLit(t.phase(Import)),
- OldOptionalLit(x, t) => OldOptionalLit(x, t.phase(Import)),
SomeLit(e) => SomeLit(e.phase(Import)),
ExprF::App(f, a) => ExprF::App(f.phase(Import), a.phase(Import)),
Field(a, b) => Field(a.phase(Primitive), b),
@@ -305,6 +289,7 @@ impl Display for BinOp {
ImportAlt => "?",
RightBiasedRecordMerge => "⫽",
ListAppend => "#",
+ Equivalence => "≡",
})
}
}
@@ -445,6 +430,7 @@ impl Display for Import {
match self.mode {
Code => {}
RawText => write!(f, " as Text")?,
+ Location => write!(f, " as Location")?,
}
Ok(())
}
@@ -469,6 +455,7 @@ impl Display for Builtin {
NaturalOdd => "Natural/odd",
NaturalToInteger => "Natural/toInteger",
NaturalShow => "Natural/show",
+ NaturalSubtract => "Natural/subtract",
IntegerToDouble => "Integer/toDouble",
IntegerShow => "Integer/show",
DoubleShow => "Double/show",