summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock87
-rw-r--r--README.md2
-rw-r--r--abnf_to_pest/Cargo.toml4
-rw-r--r--abnf_to_pest/src/lib.rs110
m---------dhall-lang0
-rw-r--r--dhall/Cargo.toml2
-rw-r--r--dhall/build.rs185
-rw-r--r--dhall/src/dhall.pest.visibility7
-rw-r--r--dhall/src/error/mod.rs5
-rw-r--r--dhall/src/semantics/phase/normalize.rs155
-rw-r--r--dhall/src/semantics/phase/typecheck.rs30
-rw-r--r--dhall/src/syntax/ast/expr.rs4
-rw-r--r--dhall/src/syntax/ast/visitor.rs7
-rw-r--r--dhall/src/syntax/binary/decode.rs5
-rw-r--r--dhall/src/syntax/binary/encode.rs1
-rw-r--r--dhall/src/syntax/text/parser.rs81
-rw-r--r--dhall/src/syntax/text/printer.rs31
-rw-r--r--dhall/tests/type-errors/mixedUnions.txt2
-rw-r--r--dhall/tests/type-errors/recordOfKind.txt2
-rw-r--r--dhall/tests/type-errors/unit/AnnotationRecordWrongFieldName.txt2
-rw-r--r--dhall/tests/type-errors/unit/AnnotationRecordWrongFieldType.txt2
-rw-r--r--dhall/tests/type-errors/unit/AssertDoubleZeros.txt1
-rw-r--r--dhall/tests/type-errors/unit/AssertNotEquivalence.txt2
-rw-r--r--dhall/tests/type-errors/unit/AssertTriviallyFalse.txt2
-rw-r--r--dhall/tests/type-errors/unit/EquivalenceNotSameType.txt2
-rw-r--r--dhall/tests/type-errors/unit/EquivalenceNotTerms.txt2
-rw-r--r--dhall/tests/type-errors/unit/FunctionTypeKindSort.txt2
-rw-r--r--dhall/tests/type-errors/unit/FunctionTypeTypeSort.txt2
-rw-r--r--dhall/tests/type-errors/unit/IfBranchesNotMatch.txt2
-rw-r--r--dhall/tests/type-errors/unit/IfBranchesNotType.txt2
-rw-r--r--dhall/tests/type-errors/unit/IfNotBool.txt2
-rw-r--r--dhall/tests/type-errors/unit/LetWithWrongAnnotation.txt2
-rw-r--r--dhall/tests/type-errors/unit/ListLiteralNotType.txt2
-rw-r--r--dhall/tests/type-errors/unit/ListLiteralTypesNotMatch.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeAlternativeHasNoHandler.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeAnnotationMismatch.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeAnnotationNotType.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation1.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation2.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeEmptyWithoutAnnotation.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeHandlerFreeVar.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeHandlerNotInUnion.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeHandlersWithDifferentType.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeLhsNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeMissingHandler1.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeMissingHandler2.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeRhsNotUnion.txt2
-rw-r--r--dhall/tests/type-errors/unit/MergeUnusedHandler.txt1
-rw-r--r--dhall/tests/type-errors/unit/OperatorAndNotBool.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorEqualNotBool.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorListConcatenateLhsNotList.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorListConcatenateListsNotMatch.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorListConcatenateNotListsButMatch.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorListConcatenateRhsNotList.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorNotEqualNotBool.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorOrNotBool.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorPlusNotNatural.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorTextConcatenateLhsNotText.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorTextConcatenateRhsNotText.txt2
-rw-r--r--dhall/tests/type-errors/unit/OperatorTimesNotNatural.txt2
-rw-r--r--dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxAbsent.txt2
-rw-r--r--dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxPresent.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordLitDuplicateFields.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordMixedKinds3.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordProjectionDuplicateFields.txt1
-rw-r--r--dhall/tests/type-errors/unit/RecordProjectionEmpty.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordProjectionNotPresent.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordProjectionNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordSelectionEmpty.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordSelectionNotPresent.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordSelectionNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordSelectionTypeNotUnionType.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordTypeDuplicateFields.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecordTypeValueMember.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordMergeLhsNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordMergeOverlapping.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordMergeRhsNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordTypeMergeLhsNotRecordType.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordTypeMergeOverlapping.txt2
-rw-r--r--dhall/tests/type-errors/unit/RecursiveRecordTypeMergeRhsNotRecordType.txt2
-rw-r--r--dhall/tests/type-errors/unit/RightBiasedRecordMergeLhsNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds2.txt2
-rw-r--r--dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds3.txt2
-rw-r--r--dhall/tests/type-errors/unit/RightBiasedRecordMergeRhsNotRecord.txt2
-rw-r--r--dhall/tests/type-errors/unit/SomeNotType.txt2
-rw-r--r--dhall/tests/type-errors/unit/Sort.txt2
-rw-r--r--dhall/tests/type-errors/unit/TextLiteralInterpolateNotText.txt2
-rw-r--r--dhall/tests/type-errors/unit/TypeAnnotationWrong.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionConstructorFieldNotPresent.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeDuplicateVariants1.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeDuplicateVariants2.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeMixedKinds.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeMixedKinds2.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeMixedKinds3.txt2
-rw-r--r--dhall/tests/type-errors/unit/UnionTypeNotType.txt2
95 files changed, 507 insertions, 362 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b27c167..46b00dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,17 +2,17 @@
# It is not intended for manual editing.
[[package]]
name = "abnf"
-version = "0.1.3"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "abnf_to_pest"
-version = "0.1.2"
+version = "0.2.0"
dependencies = [
- "abnf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "abnf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -27,6 +27,14 @@ dependencies = [
]
[[package]]
+name = "arrayvec"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -61,6 +69,11 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "ctor"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -73,7 +86,7 @@ dependencies = [
name = "dhall"
version = "0.1.1"
dependencies = [
- "abnf_to_pest 0.1.2",
+ "abnf_to_pest 0.2.0",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -167,6 +180,18 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "lexical-core"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,10 +202,16 @@ version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "nodrop"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "nom"
-version = "4.2.3"
+version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
+ "lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -310,6 +341,19 @@ dependencies = [
]
[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "same-file"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -318,6 +362,19 @@ dependencies = [
]
[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "serde"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -371,6 +428,11 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "static_assertions"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "syn"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -448,13 +510,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
-"checksum abnf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d972ae01fad2d4693b272854546bd763966c95575a4f1d6333dc95b85ff182db"
+"checksum abnf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e065019cf2f9438a593954cc8e774925656b86701b72720b82ec3141e682ac14"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
@@ -466,9 +530,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
-"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
+"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
@@ -483,12 +549,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45cd6d95391b16cd57e88b68be41d504183b7faae22030c0cc3b3f73dd57b2fd"
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
+"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
"checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
diff --git a/README.md b/README.md
index bf8fb07..413da63 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ assert_eq!(deserialized_map, expected_map);
## Standard-compliance
This implementation currently supports partially the [Dhall
-standard](https://github.com/dhall-lang/dhall-lang) version `10.0`.
+standard](https://github.com/dhall-lang/dhall-lang) version `12.0.0`.
Only local imports are supported, but otherwise the main features are
implemented. See
diff --git a/abnf_to_pest/Cargo.toml b/abnf_to_pest/Cargo.toml
index 93ec829..780010e 100644
--- a/abnf_to_pest/Cargo.toml
+++ b/abnf_to_pest/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "abnf_to_pest"
-version = "0.1.2" # remember to update html_root_url
+version = "0.2.0" # remember to update html_root_url
authors = ["Nadrieril <nadrieril@users.noreply.github.com>"]
license = "MIT OR Apache-2.0"
edition = "2018"
@@ -12,7 +12,7 @@ repository = "https://github.com/Nadrieril/dhall-rust"
doctest = false
[dependencies]
-abnf = "0.1.2"
+abnf = "0.6.0"
indexmap = "1.0.2"
itertools = "0.8.0"
pretty = "0.5.2"
diff --git a/abnf_to_pest/src/lib.rs b/abnf_to_pest/src/lib.rs
index d460bf9..8615fc2 100644
--- a/abnf_to_pest/src/lib.rs
+++ b/abnf_to_pest/src/lib.rs
@@ -1,4 +1,4 @@
-#![doc(html_root_url = "https://docs.rs/abnf_to_pest/0.1.1")]
+#![doc(html_root_url = "https://docs.rs/abnf_to_pest/0.2.0")]
//! A tiny crate that helps convert ABNF grammars to [pest][pest].
//!
@@ -21,10 +21,7 @@
//!
//! [pest]: https://pest.rs
-use abnf::abnf::Rule;
-pub use abnf::abnf::{
- Alternation, Concatenation, Element, Range, Repeat, Repetition,
-};
+use abnf::types::{Node, NumVal, Repeat, Rule};
use indexmap::map::IndexMap;
use itertools::Itertools;
use pretty::{BoxDoc, Doc};
@@ -33,40 +30,41 @@ trait Pretty {
fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>>;
}
-impl Pretty for Alternation {
+impl Pretty for Node {
fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- Doc::intersperse(
- self.concatenations
- .iter()
- .map(|x| x.pretty().nest(2).group()),
- Doc::space().append(Doc::text("| ")),
- )
- }
-}
-
-impl Pretty for Concatenation {
- fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- Doc::intersperse(
- self.repetitions.iter().map(Repetition::pretty),
- Doc::space().append(Doc::text("~ ")),
- )
- }
-}
-
-impl Pretty for Repetition {
- fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- self.element.pretty().append(
- self.repeat
- .as_ref()
- .map(Repeat::pretty)
- .unwrap_or_else(Doc::nil),
- )
+ use Node::*;
+ match self {
+ Alternation(nodes) => Doc::intersperse(
+ nodes.iter().map(|x| x.pretty().nest(2).group()),
+ Doc::space().append(Doc::text("| ")),
+ ),
+ Concatenation(nodes) => Doc::intersperse(
+ nodes.iter().map(|x| x.pretty()),
+ Doc::space().append(Doc::text("~ ")),
+ ),
+ Repetition(rep) => {
+ rep.get_node().pretty().append(rep.get_repeat().pretty())
+ }
+ Rulename(s) => Doc::text(escape_rulename(s)),
+ Group(n) => Doc::text("(")
+ .append(n.pretty().nest(4).group())
+ .append(Doc::text(")")),
+ Optional(n) => Doc::text("(")
+ .append(n.pretty().nest(4).group())
+ .append(Doc::text(")?")),
+ CharVal(s) => Doc::text(format!(
+ "^\"{}\"",
+ s.replace("\"", "\\\"").replace("\\", "\\\\")
+ )),
+ NumVal(r) => r.pretty(),
+ ProseVal(_) => unimplemented!(),
+ }
}
}
impl Pretty for Repeat {
fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- Doc::text(match (self.min.unwrap_or(0), self.max) {
+ Doc::text(match (self.get_min().unwrap_or(0), self.get_max()) {
(0, None) => "*".into(),
(1, None) => "+".into(),
(0, Some(1)) => "?".into(),
@@ -77,35 +75,14 @@ impl Pretty for Repeat {
}
}
-impl Pretty for Element {
- fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- use abnf::abnf::Element::*;
- match self {
- Rulename(s) => Doc::text(escape_rulename(s)),
- Group(g) => Doc::text("(")
- .append((g.alternation).pretty().nest(4).group())
- .append(Doc::text(")")),
- Option(o) => Doc::text("(")
- .append((o.alternation).pretty().nest(4).group())
- .append(Doc::text(")?")),
- CharVal(s) => Doc::text(format!(
- "^\"{}\"",
- s.replace("\"", "\\\"").replace("\\", "\\\\")
- )),
- NumVal(r) => r.pretty(),
- ProseVal(_) => unimplemented!(),
- }
- }
-}
-
-impl Pretty for Range {
+impl Pretty for NumVal {
fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
- use abnf::abnf::Range::*;
+ use NumVal::*;
Doc::text(match self {
Range(x, y) => {
format!("'{}'..'{}'", format_char(*x), format_char(*y))
}
- OneOf(v) => {
+ Terminal(v) => {
format!("\"{}\"", v.iter().map(|x| format_char(*x)).join(""))
}
})
@@ -154,17 +131,18 @@ fn format_char(x: u32) -> String {
#[derive(Debug, Clone)]
pub struct PestyRule {
pub silent: bool,
- pub elements: Alternation,
+ pub node: Node,
}
impl Pretty for (String, PestyRule) {
fn pretty(&self) -> Doc<'static, BoxDoc<'static, ()>> {
+ let (name, rule) = self;
Doc::nil()
- .append(Doc::text(self.0.clone()))
+ .append(Doc::text(name.clone()))
.append(Doc::text(" = "))
- .append(Doc::text(if self.1.silent { "_" } else { "" }))
+ .append(Doc::text(if rule.silent { "_" } else { "" }))
.append(Doc::text("{"))
- .append(Doc::space().append(self.1.elements.pretty()).nest(2))
+ .append(Doc::space().append(rule.node.pretty()).nest(2))
.append(Doc::space())
.append(Doc::text("}"))
.group()
@@ -173,21 +151,19 @@ impl Pretty for (String, PestyRule) {
/// Parse an abnf file. Returns a map of rules.
pub fn parse_abnf(
- data: &[u8],
+ data: &str,
) -> Result<IndexMap<String, PestyRule>, std::io::Error> {
let make_err =
|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e));
- let rules: Vec<Rule> =
- abnf::abnf::rulelist_comp(&data).map_err(make_err)?.1;
+ let rules: Vec<Rule> = abnf::rulelist(data).map_err(make_err)?;
Ok(rules
.into_iter()
.map(|rule| {
- let name = escape_rulename(&rule.name);
(
- name.clone(),
+ escape_rulename(rule.get_name()),
PestyRule {
silent: false,
- elements: rule.elements.clone(),
+ node: rule.get_node().clone(),
},
)
})
diff --git a/dhall-lang b/dhall-lang
-Subproject 781961f4694667667f093d28e7b35569c67678c
+Subproject 0c99dc6f53919fc2df6b965877c355b62cf6ba0
diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml
index 34cf444..8674f44 100644
--- a/dhall/Cargo.toml
+++ b/dhall/Cargo.toml
@@ -26,7 +26,7 @@ pretty_assertions = "0.6.1"
[build-dependencies]
walkdir = "2"
-abnf_to_pest = { version = "0.1.2", path = "../abnf_to_pest" }
+abnf_to_pest = { version = "0.2.0", path = "../abnf_to_pest" }
pest_generator = "2.1"
quote = "1.0"
diff --git a/dhall/build.rs b/dhall/build.rs
index 3021f03..9b00684 100644
--- a/dhall/build.rs
+++ b/dhall/build.rs
@@ -1,7 +1,7 @@
use std::env;
use std::ffi::OsString;
-use std::fs::File;
-use std::io::{BufRead, BufReader, Read, Write};
+use std::fs::{read_to_string, File};
+use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
@@ -51,8 +51,7 @@ fn dhall_files_in_dir<'a>(
})
}
-#[derive(Debug, Clone)]
-struct TestFeature<F> {
+struct TestFeature {
/// Name of the module, used in the output of `cargo test`
module_name: &'static str,
/// Directory containing the tests files
@@ -60,7 +59,7 @@ struct TestFeature<F> {
/// Relevant variant of `dhall::tests::Test`
variant: &'static str,
/// Given a file name, whether to exclude it
- path_filter: F,
+ path_filter: Box<dyn FnMut(&str) -> bool>,
/// Type of the input file
input_type: FileType,
/// Type of the output file, if any
@@ -69,7 +68,7 @@ struct TestFeature<F> {
fn make_test_module(
w: &mut impl Write, // Where to output the generated code
- mut feature: TestFeature<impl FnMut(&str) -> bool>,
+ mut feature: TestFeature,
) -> std::io::Result<()> {
let tests_dir = feature.directory;
writeln!(w, "mod {} {{", feature.module_name)?;
@@ -113,15 +112,13 @@ fn generate_tests() -> std::io::Result<()> {
let parser_tests_path = Path::new(&out_dir).join("spec_tests.rs");
let spec_tests_dir = Path::new("../dhall-lang/tests/");
- let mut file = File::create(parser_tests_path)?;
- make_test_module(
- &mut file,
+ let tests = vec![
TestFeature {
module_name: "parser_success",
directory: spec_tests_dir.join("parser/success/"),
variant: "ParserSuccess",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
// Too slow in debug mode
|| path == "largeExpression"
@@ -131,31 +128,25 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/import/urls/emptyPath0"
|| path == "unit/import/urls/emptyPath1"
|| path == "unit/import/urls/emptyPathSegment"
- },
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ || path == "preferMissingNoSpaces"
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Binary),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "parser_failure",
directory: spec_tests_dir.join("parser/failure/"),
variant: "ParserFailure",
- path_filter: |_path: &str| false,
+ path_filter: Box::new(|_path: &str| false),
input_type: FileType::Text,
output_type: None,
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "printer",
directory: spec_tests_dir.join("parser/success/"),
variant: "Printer",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
// Too slow in debug mode
|| path == "largeExpression"
@@ -163,19 +154,17 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/import/urls/emptyPath0"
|| path == "unit/import/urls/emptyPath1"
|| path == "unit/import/urls/emptyPathSegment"
- },
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ || path == "preferMissingNoSpaces"
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Binary),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "binary_encoding",
directory: spec_tests_dir.join("parser/success/"),
variant: "BinaryEncoding",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
// Too slow in debug mode
|| path == "largeExpression"
@@ -189,43 +178,39 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/import/urls/emptyPath0"
|| path == "unit/import/urls/emptyPath1"
|| path == "unit/import/urls/emptyPathSegment"
- },
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ || path == "preferMissingNoSpaces"
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Binary),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "binary_decoding_success",
directory: spec_tests_dir.join("binary-decode/success/"),
variant: "BinaryDecodingSuccess",
- path_filter: |_path: &str| false,
+ path_filter: Box::new(|path: &str| {
+ false
+ // We don't support bignums
+ || path == "unit/IntegerBigNegative"
+ || path == "unit/IntegerBigPositive"
+ || path == "unit/NaturalBig"
+ }),
input_type: FileType::Binary,
output_type: Some(FileType::Text),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "binary_decoding_failure",
directory: spec_tests_dir.join("binary-decode/failure/"),
variant: "BinaryDecodingFailure",
- path_filter: |_path: &str| false,
+ path_filter: Box::new(|_path: &str| false),
input_type: FileType::Binary,
output_type: None,
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "import_success",
directory: spec_tests_dir.join("import/success/"),
variant: "ImportSuccess",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
|| path == "alternativeEnvNatural"
|| path == "alternativeEnvSimple"
@@ -236,38 +221,31 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "hashFromCache"
|| path == "headerForwarding"
|| path == "noHeaderForwarding"
- },
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Text),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "import_failure",
directory: spec_tests_dir.join("import/failure/"),
variant: "ImportFailure",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
|| path == "alternativeEnv"
|| path == "alternativeEnvMissing"
|| path == "hashMismatch"
|| path == "missing"
|| path == "referentiallyInsane"
- },
+ || path == "customHeadersUsingBoundVariable"
+ }),
input_type: FileType::Text,
output_type: None,
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "beta_normalize",
directory: spec_tests_dir.join("normalization/success/"),
variant: "Normalization",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
// We don't support bignums
path == "simple/integerToDouble"
// Too slow
@@ -301,34 +279,32 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/RightBiasedMergeEquivalentArguments"
|| path == "unit/NestedRecordProjection"
|| path == "unit/NestedRecordProjectionByType"
- },
+ // TODO: record completion
+ || path == "simple/completion"
+ || path == "unit/Completion"
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ || path == "unit/MergeNone"
+ || path == "unit/MergeSome"
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Text),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "alpha_normalize",
directory: spec_tests_dir.join("alpha-normalization/success/"),
variant: "AlphaNormalization",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
// This test doesn't typecheck
path == "unit/FunctionNestedBindingXXFree"
- },
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Text),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "type_inference_success",
directory: spec_tests_dir.join("type-inference/success/"),
variant: "TypeInferenceSuccess",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
// Too slow
|| path == "prelude"
@@ -339,24 +315,24 @@ fn generate_tests() -> std::io::Result<()> {
// TODO: toMap
|| path == "unit/ToMap"
|| path == "unit/ToMapAnnotated"
+ || path == "unit/ToMapInferTypeFromRecord"
|| path == "simple/toMapEmptyNormalizeAnnotation"
- },
+ // TODO: record completion
+ || path == "simple/completion"
+ || path == "unit/Completion"
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ || path == "unit/MergeNone"
+ || path == "unit/MergeSome"
+ }),
input_type: FileType::Text,
output_type: Some(FileType::Text),
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "type_inference_failure",
directory: spec_tests_dir.join("type-inference/failure/"),
variant: "TypeInferenceFailure",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
- // TODO: Enable imports in typecheck tests
- || path == "importBoundary"
- || path == "customHeadersUsingBoundVariable"
// TODO: projection by expression
|| path == "unit/RecordProjectionByTypeFieldTypeMismatch"
|| path == "unit/RecordProjectionByTypeNotPresent"
@@ -368,24 +344,23 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/MistypedToMap3"
|| path == "unit/MistypedToMap4"
|| path == "unit/NonRecordToMap"
+ || path == "unit/ToMapEmptyInvalidAnnotation"
|| path == "unit/ToMapWrongKind"
- },
+ // TODO: record completion
+ || path == "unit/CompletionMissingRequiredField"
+ || path == "unit/CompletionWithWrongDefaultType"
+ || path == "unit/CompletionWithWrongFieldName"
+ || path == "unit/CompletionWithWrongOverridenType"
+ }),
input_type: FileType::Text,
output_type: None,
},
- )?;
-
- make_test_module(
- &mut file,
TestFeature {
module_name: "type_error",
directory: spec_tests_dir.join("type-inference/failure/"),
variant: "TypeError",
- path_filter: |path: &str| {
+ path_filter: Box::new(|path: &str| {
false
- // TODO: Enable imports in typecheck tests
- || path == "importBoundary"
- || path == "customHeadersUsingBoundVariable"
// TODO: projection by expression
|| path == "unit/RecordProjectionByTypeFieldTypeMismatch"
|| path == "unit/RecordProjectionByTypeNotPresent"
@@ -397,12 +372,23 @@ fn generate_tests() -> std::io::Result<()> {
|| path == "unit/MistypedToMap3"
|| path == "unit/MistypedToMap4"
|| path == "unit/NonRecordToMap"
+ || path == "unit/ToMapEmptyInvalidAnnotation"
|| path == "unit/ToMapWrongKind"
- },
+ // TODO: record completion
+ || path == "unit/CompletionMissingRequiredField"
+ || path == "unit/CompletionWithWrongDefaultType"
+ || path == "unit/CompletionWithWrongFieldName"
+ || path == "unit/CompletionWithWrongOverridenType"
+ }),
input_type: FileType::Text,
output_type: None,
},
- )?;
+ ];
+
+ let mut file = File::create(parser_tests_path)?;
+ for test in tests {
+ make_test_module(&mut file, test)?;
+ }
Ok(())
}
@@ -415,10 +401,9 @@ fn convert_abnf_to_pest() -> std::io::Result<()> {
println!("cargo:rerun-if-changed={}", abnf_path);
println!("cargo:rerun-if-changed={}", visibility_path);
- let mut file = File::open(abnf_path)?;
- let mut data = Vec::new();
- file.read_to_end(&mut data)?;
- data.push('\n' as u8);
+ let mut data = read_to_string(abnf_path)?;
+ data.push('\n');
+ let data = data.replace('∀', ""); // TODO: waiting for abnf 0.6.1
let mut rules = abnf_to_pest::parse_abnf(&data)?;
for line in BufReader::new(File::open(visibility_path)?).lines() {
@@ -435,6 +420,24 @@ fn convert_abnf_to_pest() -> std::io::Result<()> {
rules.remove("url_path");
writeln!(&mut file, "url_path = _{{ path }}")?;
+ // Work around some greediness issue in the grammar.
+ rules.remove("missing");
+ writeln!(
+ &mut file,
+ r#"missing = {{ "missing" ~ !simple_label_next_char }}"#
+ )?;
+
+ // Prefer my nice error message to illegible parse errors.
+ rules.remove("unicode_escape");
+ rules.remove("unbraced_escape");
+ rules.remove("braced_escape");
+ rules.remove("braced_codepoint");
+ rules.remove("unicode_suffix");
+ writeln!(
+ &mut file,
+ r#"unicode_escape = _{{ HEXDIG{{4}} | "{{" ~ HEXDIG+ ~ "}}" }}"#
+ )?;
+
rules.remove("simple_label");
writeln!(
&mut file,
diff --git a/dhall/src/dhall.pest.visibility b/dhall/src/dhall.pest.visibility
index 17c1edc..03a000b 100644
--- a/dhall/src/dhall.pest.visibility
+++ b/dhall/src/dhall.pest.visibility
@@ -21,9 +21,14 @@ quoted_label
# label
# nonreserved_label
# any_label
+any_label_or_some
double_quote_chunk
double_quote_escaped
# unicode_escape
+# unicode_suffix
+# unbraced_escape
+# braced_codepoint
+# braced_escape
double_quote_char
double_quote_literal
single_quote_continue
@@ -91,6 +96,7 @@ prefer
lambda
forall
arrow
+# complete
# exponent
numeric_double_literal
minus_infinity_literal
@@ -161,6 +167,7 @@ equivalent_expression
application_expression
first_application_expression
# import_expression
+completion_expression
selector_expression
selector
labels
diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs
index 1288c12..6e7be64 100644
--- a/dhall/src/error/mod.rs
+++ b/dhall/src/error/mod.rs
@@ -67,7 +67,7 @@ pub(crate) enum TypeMessage {
BinOpTypeMismatch(BinOp, Value),
InvalidTextInterpolation(Value),
Merge1ArgMustBeRecord(Value),
- Merge2ArgMustBeUnion(Value),
+ Merge2ArgMustBeUnionOrOptional(Value),
MergeEmptyNeedsAnnotation,
MergeHandlerMissingVariant(Label),
MergeVariantMissingHandler(Label),
@@ -76,6 +76,7 @@ pub(crate) enum TypeMessage {
MergeHandlerReturnTypeMustNotBeDependent,
ProjectionMustBeRecord,
ProjectionMissingEntry,
+ ProjectionDuplicateField,
Sort,
RecordTypeDuplicateField,
RecordTypeMergeRequiresRecordType(Value),
@@ -124,7 +125,7 @@ impl std::fmt::Display for TypeError {
y
))
}
- _ => "Type error: Unhandled error".to_string(),
+ _ => format!("Type error: Unhandled error: {:?}", self.message),
};
write!(f, "{}", msg)
}
diff --git a/dhall/src/semantics/phase/normalize.rs b/dhall/src/semantics/phase/normalize.rs
index d81a910..459eaf1 100644
--- a/dhall/src/semantics/phase/normalize.rs
+++ b/dhall/src/semantics/phase/normalize.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use std::convert::TryInto;
use crate::semantics::core::value::Value;
use crate::semantics::core::value::ValueKind;
@@ -141,6 +142,16 @@ pub(crate) fn apply_builtin(
}
_ => Ret::DoneAsIs,
},
+ (IntegerNegate, [n]) => match &*n.as_whnf() {
+ IntegerLit(n) => Ret::ValueKind(IntegerLit(-n)),
+ _ => Ret::DoneAsIs,
+ },
+ (IntegerClamp, [n]) => match &*n.as_whnf() {
+ IntegerLit(n) => {
+ Ret::ValueKind(NaturalLit((*n).try_into().unwrap_or(0)))
+ }
+ _ => Ret::DoneAsIs,
+ },
(DoubleShow, [n]) => {
match &*n.as_whnf() {
DoubleLit(n) => Ret::ValueKind(TextLit(vec![
@@ -259,37 +270,23 @@ pub(crate) fn apply_builtin(
_ => Ret::DoneAsIs,
}
}
- (ListBuild, [t, f]) => match &*f.as_whnf() {
- // fold/build fusion
- ValueKind::AppliedBuiltin(ListFold, args) => {
- if args.len() >= 2 {
- Ret::Value(args[1].clone())
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => {
- let list_t = Value::from_builtin(List).app(t.clone());
- Ret::Value(
- f.app(list_t.clone())
- .app({
- // Move `t` under new variables
- let t1 = t.under_binder(Label::from("x"));
- let t2 = t1.under_binder(Label::from("xs"));
- make_closure!(
- λ(x : #t) ->
- λ(xs : List #t1) ->
- [ var(x, 1, #t2) ] # var(xs, 0, List #t2)
- )
- })
- .app(
- EmptyListLit(t.clone())
- .into_value_with_type(list_t),
- ),
- )
- }
- },
+ (ListBuild, [t, f]) => {
+ let list_t = Value::from_builtin(List).app(t.clone());
+ Ret::Value(
+ f.app(list_t.clone())
+ .app({
+ // Move `t` under new variables
+ let t1 = t.under_binder(Label::from("x"));
+ let t2 = t1.under_binder(Label::from("xs"));
+ make_closure!(
+ λ(x : #t) ->
+ λ(xs : List #t1) ->
+ [ var(x, 1, #t2) ] # var(xs, 0, List #t2)
+ )
+ })
+ .app(EmptyListLit(t.clone()).into_value_with_type(list_t)),
+ )
+ }
(ListFold, [_, l, _, cons, nil, r @ ..]) => match &*l.as_whnf() {
EmptyListLit(_) => Ret::ValueWithRemainingArgs(r, nil.clone()),
NEListLit(xs) => {
@@ -301,31 +298,20 @@ pub(crate) fn apply_builtin(
}
_ => Ret::DoneAsIs,
},
- (OptionalBuild, [t, f]) => match &*f.as_whnf() {
- // fold/build fusion
- ValueKind::AppliedBuiltin(OptionalFold, args) => {
- if args.len() >= 2 {
- Ret::Value(args[1].clone())
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => {
- let optional_t = Value::from_builtin(Optional).app(t.clone());
- Ret::Value(
- f.app(optional_t.clone())
- .app({
- let t1 = t.under_binder(Label::from("x"));
- make_closure!(λ(x: #t) -> Some(var(x, 0, #t1)))
- })
- .app(
- EmptyOptionalLit(t.clone())
- .into_value_with_type(optional_t),
- ),
- )
- }
- },
+ (OptionalBuild, [t, f]) => {
+ let optional_t = Value::from_builtin(Optional).app(t.clone());
+ Ret::Value(
+ f.app(optional_t.clone())
+ .app({
+ let t1 = t.under_binder(Label::from("x"));
+ make_closure!(λ(x: #t) -> Some(var(x, 0, #t1)))
+ })
+ .app(
+ EmptyOptionalLit(t.clone())
+ .into_value_with_type(optional_t),
+ ),
+ )
+ }
(OptionalFold, [_, v, _, just, nothing, r @ ..]) => match &*v.as_whnf()
{
EmptyOptionalLit(_) => {
@@ -336,27 +322,17 @@ pub(crate) fn apply_builtin(
}
_ => Ret::DoneAsIs,
},
- (NaturalBuild, [f]) => match &*f.as_whnf() {
- // fold/build fusion
- ValueKind::AppliedBuiltin(NaturalFold, args) => {
- if !args.is_empty() {
- Ret::Value(args[0].clone())
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => Ret::Value(
- f.app(Value::from_builtin(Natural))
- .app(make_closure!(
- λ(x : Natural) -> 1 + var(x, 0, Natural)
- ))
- .app(
- NaturalLit(0)
- .into_value_with_type(Value::from_builtin(Natural)),
- ),
- ),
- },
+ (NaturalBuild, [f]) => Ret::Value(
+ f.app(Value::from_builtin(Natural))
+ .app(make_closure!(
+ λ(x : Natural) -> 1 + var(x, 0, Natural)
+ ))
+ .app(
+ NaturalLit(0)
+ .into_value_with_type(Value::from_builtin(Natural)),
+ ),
+ ),
+
(NaturalFold, [n, t, succ, zero, r @ ..]) => match &*n.as_whnf() {
NaturalLit(0) => Ret::ValueWithRemainingArgs(r, zero.clone()),
NaturalLit(n) => {
@@ -614,8 +590,8 @@ pub(crate) fn normalize_one_layer(
ty: &Value,
) -> ValueKind {
use ValueKind::{
- AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, IntegerLit,
- NEListLit, NEOptionalLit, NaturalLit, RecordLit, TextLit,
+ AppliedBuiltin, BoolLit, DoubleLit, EmptyListLit, EmptyOptionalLit,
+ IntegerLit, NEListLit, NEOptionalLit, NaturalLit, RecordLit, TextLit,
UnionConstructor, UnionLit, UnionType,
};
@@ -741,6 +717,7 @@ pub(crate) fn normalize_one_layer(
ExprKind::ProjectionByExpr(_, _) => {
unimplemented!("selection by expression")
}
+ ExprKind::Completion(_, _) => unimplemented!("record completion"),
ExprKind::Merge(ref handlers, ref variant, _) => {
let handlers_borrow = handlers.as_whnf();
@@ -762,6 +739,26 @@ pub(crate) fn normalize_one_layer(
Ret::Expr(expr)
}
},
+ (RecordLit(kvs), EmptyOptionalLit(_)) => {
+ match kvs.get(&"None".into()) {
+ Some(h) => Ret::Value(h.clone()),
+ None => {
+ drop(handlers_borrow);
+ drop(variant_borrow);
+ Ret::Expr(expr)
+ }
+ }
+ }
+ (RecordLit(kvs), NEOptionalLit(v)) => {
+ match kvs.get(&"Some".into()) {
+ Some(h) => Ret::Value(h.app(v.clone())),
+ None => {
+ drop(handlers_borrow);
+ drop(variant_borrow);
+ Ret::Expr(expr)
+ }
+ }
+ }
_ => {
drop(handlers_borrow);
drop(variant_borrow);
diff --git a/dhall/src/semantics/phase/typecheck.rs b/dhall/src/semantics/phase/typecheck.rs
index c439f74..97502d4 100644
--- a/dhall/src/semantics/phase/typecheck.rs
+++ b/dhall/src/semantics/phase/typecheck.rs
@@ -1,3 +1,4 @@
+use std::borrow::Cow;
use std::cmp::max;
use std::collections::HashMap;
@@ -235,6 +236,9 @@ fn type_of_builtin<E>(b: Builtin) -> Expr<E> {
IntegerToDouble => make_type!(Integer -> Double),
IntegerShow => make_type!(Integer -> Text),
+ IntegerNegate => make_type!(Integer -> Integer),
+ IntegerClamp => make_type!(Integer -> Natural),
+
DoubleShow => make_type!(Double -> Text),
TextShow => make_type!(Text -> Text),
@@ -692,8 +696,19 @@ fn type_last_layer(
let union_type = union.get_type()?;
let union_borrow = union_type.as_whnf();
let variants = match &*union_borrow {
- ValueKind::UnionType(kts) => kts,
- _ => return mkerr(Merge2ArgMustBeUnion(union.clone())),
+ ValueKind::UnionType(kts) => Cow::Borrowed(kts),
+ ValueKind::AppliedBuiltin(syntax::Builtin::Optional, args)
+ if args.len() == 1 =>
+ {
+ let ty = &args[0];
+ let mut kts = HashMap::new();
+ kts.insert("None".into(), None);
+ kts.insert("Some".into(), Some(ty.clone()));
+ Cow::Owned(kts)
+ }
+ _ => {
+ return mkerr(Merge2ArgMustBeUnionOrOptional(union.clone()))
+ }
};
let mut inferred_type = None;
@@ -774,7 +789,15 @@ fn type_last_layer(
for l in labels {
match kts.get(l) {
None => return mkerr(ProjectionMissingEntry),
- Some(t) => new_kts.insert(l.clone(), t.clone()),
+ Some(t) => {
+ use std::collections::hash_map::Entry;
+ match new_kts.entry(l.clone()) {
+ Entry::Occupied(_) => {
+ return mkerr(ProjectionDuplicateField)
+ }
+ Entry::Vacant(e) => e.insert(t.clone()),
+ }
+ }
};
}
@@ -784,6 +807,7 @@ fn type_last_layer(
))
}
ProjectionByExpr(_, _) => unimplemented!("selection by expression"),
+ Completion(_, _) => unimplemented!("record completion"),
};
Ok(match ret {
diff --git a/dhall/src/syntax/ast/expr.rs b/dhall/src/syntax/ast/expr.rs
index 48c48d8..68cb524 100644
--- a/dhall/src/syntax/ast/expr.rs
+++ b/dhall/src/syntax/ast/expr.rs
@@ -79,6 +79,8 @@ pub enum Builtin {
NaturalSubtract,
IntegerToDouble,
IntegerShow,
+ IntegerNegate,
+ IntegerClamp,
DoubleShow,
ListBuild,
ListFold,
@@ -163,6 +165,8 @@ pub enum ExprKind<SubExpr, Embed> {
Projection(SubExpr, DupTreeSet<Label>),
/// `e.(t)`
ProjectionByExpr(SubExpr, SubExpr),
+ /// `x::y`
+ Completion(SubExpr, SubExpr),
/// `./some/path`
Import(Import<SubExpr>),
/// Embeds the result of resolving an import
diff --git a/dhall/src/syntax/ast/visitor.rs b/dhall/src/syntax/ast/visitor.rs
index b557995..424048b 100644
--- a/dhall/src/syntax/ast/visitor.rs
+++ b/dhall/src/syntax/ast/visitor.rs
@@ -164,6 +164,9 @@ where
ProjectionByExpr(e, x) => {
ProjectionByExpr(v.visit_subexpr(e)?, v.visit_subexpr(x)?)
}
+ Completion(e, x) => {
+ Completion(v.visit_subexpr(e)?, v.visit_subexpr(x)?)
+ }
Assert(e) => Assert(v.visit_subexpr(e)?),
Import(i) => Import(i.traverse_ref(|e| v.visit_subexpr(e))?),
Embed(a) => Embed(v.visit_embed(a)?),
@@ -281,6 +284,10 @@ where
v.visit_subexpr(e)?;
v.visit_subexpr(x)?;
}
+ Completion(x, y) => {
+ v.visit_subexpr(x)?;
+ v.visit_subexpr(y)?;
+ }
Assert(e) => v.visit_subexpr(e)?,
Import(i) => i.traverse_mut(|e| v.visit_subexpr(e))?,
Embed(a) => v.visit_embed(a)?,
diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs
index 254ab07..c18deb5 100644
--- a/dhall/src/syntax/binary/decode.rs
+++ b/dhall/src/syntax/binary/decode.rs
@@ -98,6 +98,11 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> {
let l = Label::from(l.as_str());
Pi(l, x, y)
}
+ [U64(3), U64(13), x, y] => {
+ let x = cbor_value_to_dhall(&x)?;
+ let y = cbor_value_to_dhall(&y)?;
+ Completion(x, y)
+ }
[U64(3), U64(n), x, y] => {
let x = cbor_value_to_dhall(&x)?;
let y = cbor_value_to_dhall(&y)?;
diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs
index 25a545c..5e79f2d 100644
--- a/dhall/src/syntax/binary/encode.rs
+++ b/dhall/src/syntax/binary/encode.rs
@@ -164,6 +164,7 @@ where
ProjectionByExpr(x, y) => {
ser_seq!(ser; tag(10), expr(x), vec![expr(y)])
}
+ Completion(x, y) => ser_seq!(ser; tag(3), tag(13), expr(x), expr(y)),
Import(import) => serialize_import(ser, import),
Embed(_) => unimplemented!(
"An expression with resolved imports cannot be binary-encoded"
diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs
index 832472b..feaa2a5 100644
--- a/dhall/src/syntax/text/parser.rs
+++ b/dhall/src/syntax/text/parser.rs
@@ -57,6 +57,8 @@ impl crate::syntax::Builtin {
"Natural/subtract" => Some(NaturalSubtract),
"Integer/toDouble" => Some(IntegerToDouble),
"Integer/show" => Some(IntegerShow),
+ "Integer/negate" => Some(IntegerNegate),
+ "Integer/clamp" => Some(IntegerClamp),
"Double/show" => Some(DoubleShow),
"List/build" => Some(ListBuild),
"List/fold" => Some(ListFold),
@@ -181,6 +183,15 @@ impl DhallParser {
Ok(Label::from(input.as_str()))
}
+ // TODO: waiting for https://github.com/dhall-lang/dhall-lang/pull/871
+ // #[alias(label)]
+ // fn any_label_or_some(input: ParseInput) -> ParseResult<Label> {
+ // Ok(match_nodes!(input.into_children();
+ // [label(l)] => l,
+ // [Some_(_)] => Label::from("Some"),
+ // ))
+ // }
+
fn double_quote_literal(input: ParseInput) -> ParseResult<ParsedText> {
Ok(match_nodes!(input.into_children();
[double_quote_chunk(chunks)..] => {
@@ -215,19 +226,18 @@ impl DhallParser {
"t" => "\t".to_owned(),
// "uXXXX" or "u{XXXXX}"
s => {
- use std::convert::{TryFrom, TryInto};
+ use std::convert::TryInto;
let s = &s[1..];
let s = if &s[0..1] == "{" {
&s[1..s.len() - 1]
} else {
- &s[0..s.len()]
+ s
};
if s.len() > 8 {
Err(input.error(format!(
- "Escape sequences can't have more than 8 chars: \"{}\"",
- s
+ "Escape sequences can't have more than 8 chars"
)))?
}
@@ -240,12 +250,10 @@ impl DhallParser {
// `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(input.error(format!("Escape sequences can't contain surrogate pairs: \"{}\"", c_ecapsed)))?
- }
+ 0xD800..=0xDFFF => Err(input.error(format!(
+ "Escape sequences can't contain surrogate pairs"
+ )))?,
0x0FFFE..=0x0FFFF
| 0x1FFFE..=0x1FFFF
| 0x2FFFE..=0x2FFFF
@@ -262,12 +270,12 @@ impl DhallParser {
| 0xDFFFE..=0xDFFFF
| 0xEFFFE..=0xEFFFF
| 0xFFFFE..=0xFFFFF
- | 0x10_FFFE..=0x10_FFFF => {
- let c_ecapsed = c.escape_unicode();
- Err(input.error(format!("Escape sequences can't contain non-characters: \"{}\"", c_ecapsed)))?
- }
+ | 0x10_FFFE..=0x10_FFFF => Err(input.error(format!(
+ "Escape sequences can't contain non-characters"
+ )))?,
_ => {}
}
+ let c: char = i.try_into().unwrap();
std::iter::once(c).collect()
}
})
@@ -384,19 +392,27 @@ impl DhallParser {
}
fn natural_literal(input: ParseInput) -> ParseResult<Natural> {
- input
- .as_str()
- .trim()
- .parse()
- .map_err(|e| input.error(format!("{}", e)))
+ let s = input.as_str().trim();
+ if s.starts_with("0x") {
+ let without_prefix = s.trim_start_matches("0x");
+ usize::from_str_radix(without_prefix, 16)
+ .map_err(|e| input.error(format!("{}", e)))
+ } else {
+ s.parse().map_err(|e| input.error(format!("{}", e)))
+ }
}
fn integer_literal(input: ParseInput) -> ParseResult<Integer> {
- input
- .as_str()
- .trim()
- .parse()
- .map_err(|e| input.error(format!("{}", e)))
+ let s = input.as_str().trim();
+ let (sign, rest) = (&s[0..1], &s[1..]);
+ if rest.starts_with("0x") {
+ let without_prefix =
+ sign.to_owned() + rest.trim_start_matches("0x");
+ isize::from_str_radix(&without_prefix, 16)
+ .map_err(|e| input.error(format!("{}", e)))
+ } else {
+ s.parse().map_err(|e| input.error(format!("{}", e)))
+ }
}
#[alias(expression, shortcut = true)]
@@ -766,6 +782,25 @@ impl DhallParser {
}
#[alias(expression, shortcut = true)]
+ fn completion_expression(input: ParseInput) -> ParseResult<Expr> {
+ Ok(match_nodes!(input.children();
+ [expression(e)] => e,
+ [expression(first), expression(rest)..] => {
+ rest.fold(
+ first,
+ |acc, e| {
+ spanned_union(
+ acc.span(),
+ e.span(),
+ Completion(acc, e),
+ )
+ }
+ )
+ },
+ ))
+ }
+
+ #[alias(expression, shortcut = true)]
fn selector_expression(input: ParseInput) -> ParseResult<Expr> {
Ok(match_nodes!(input.children();
[expression(e)] => e,
diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs
index 78942ed..96f4c2a 100644
--- a/dhall/src/syntax/text/printer.rs
+++ b/dhall/src/syntax/text/printer.rs
@@ -64,6 +64,9 @@ impl<E: Display + Clone> UnspannedExpr<E> {
Field(a, b) => Field(a.phase(Primitive), b),
Projection(e, ls) => Projection(e.phase(Primitive), ls),
ProjectionByExpr(a, b) => ProjectionByExpr(a.phase(Primitive), b),
+ Completion(a, b) => {
+ Completion(a.phase(Primitive), b.phase(Primitive))
+ }
e => e,
}
}
@@ -89,9 +92,10 @@ impl<E: Display + Clone> UnspannedExpr<E> {
// Precedence is magically handled by the ordering of BinOps.
ExprKind::BinOp(op, _, _) => phase > PrintPhase::BinOp(*op),
ExprKind::App(_, _) => phase > PrintPhase::App,
- Field(_, _) | Projection(_, _) | ProjectionByExpr(_, _) => {
- phase > PrintPhase::Import
- }
+ Field(_, _)
+ | Projection(_, _)
+ | ProjectionByExpr(_, _)
+ | Completion(_, _) => phase > PrintPhase::Import,
_ => false,
};
@@ -189,13 +193,6 @@ impl<SE: Display + Clone, E: Display> Display for ExprKind<SE, E> {
Field(a, b) => {
write!(f, "{}.{}", a, b)?;
}
- Projection(e, ls) => {
- write!(f, "{}.", e)?;
- fmt_list("{ ", ", ", " }", ls, f, Display::fmt)?;
- }
- ProjectionByExpr(a, b) => {
- write!(f, "{}.({})", a, b)?;
- }
Var(a) => a.fmt(f)?,
Const(k) => k.fmt(f)?,
Builtin(v) => v.fmt(f)?,
@@ -224,6 +221,16 @@ impl<SE: Display + Clone, E: Display> Display for ExprKind<SE, E> {
}
Ok(())
})?,
+ Projection(e, ls) => {
+ write!(f, "{}.", e)?;
+ fmt_list("{ ", ", ", " }", ls, f, Display::fmt)?;
+ }
+ ProjectionByExpr(a, b) => {
+ write!(f, "{}.({})", a, b)?;
+ }
+ Completion(a, b) => {
+ write!(f, "{}::{}", a, b)?;
+ }
Import(a) => a.fmt(f)?,
Embed(a) => a.fmt(f)?,
}
@@ -322,6 +329,8 @@ impl Display for NaiveDouble {
f.write_str("-Infinity")
} else if v.is_nan() {
f.write_str("NaN")
+ } else if v == 0.0 && v.is_sign_negative() {
+ f.write_str("-0.0")
} else {
let s = format!("{}", v);
if s.contains('e') || s.contains('.') {
@@ -459,6 +468,8 @@ impl Display for Builtin {
NaturalShow => "Natural/show",
NaturalSubtract => "Natural/subtract",
IntegerToDouble => "Integer/toDouble",
+ IntegerNegate => "Integer/negate",
+ IntegerClamp => "Integer/clamp",
IntegerShow => "Integer/show",
DoubleShow => "Double/show",
ListBuild => "List/build",
diff --git a/dhall/tests/type-errors/mixedUnions.txt b/dhall/tests/type-errors/mixedUnions.txt
index 4b68fea..30fcdf8 100644
--- a/dhall/tests/type-errors/mixedUnions.txt
+++ b/dhall/tests/type-errors/mixedUnions.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("Right"), Type)
diff --git a/dhall/tests/type-errors/recordOfKind.txt b/dhall/tests/type-errors/recordOfKind.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/recordOfKind.txt
+++ b/dhall/tests/type-errors/recordOfKind.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldName.txt b/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldName.txt
index 4b68fea..e15da48 100644
--- a/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldName.txt
+++ b/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldName.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AnnotMismatch(Value@Unevaled { value: PartialExpr(RecordLit(DupTreeMap { map: {Label("x"): [Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type } }]}, size: 1 })), type: Value@WHNF { value: RecordType({Label("x"): Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type }}), type: Type } }, Value@WHNF { value: RecordType({Label("y"): Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type }}), type: Type })
diff --git a/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldType.txt b/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldType.txt
index 4b68fea..16b2d83 100644
--- a/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldType.txt
+++ b/dhall/tests/type-errors/unit/AnnotationRecordWrongFieldType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AnnotMismatch(Value@Unevaled { value: PartialExpr(RecordLit(DupTreeMap { map: {Label("x"): [Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } }]}, size: 1 })), type: Value@WHNF { value: RecordType({Label("x"): Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type }}), type: Type } }, Value@WHNF { value: RecordType({Label("x"): Value@WHNF { value: AppliedBuiltin(Text, []), type: Type }}), type: Type })
diff --git a/dhall/tests/type-errors/unit/AssertDoubleZeros.txt b/dhall/tests/type-errors/unit/AssertDoubleZeros.txt
new file mode 100644
index 0000000..d9df5c7
--- /dev/null
+++ b/dhall/tests/type-errors/unit/AssertDoubleZeros.txt
@@ -0,0 +1 @@
+Type error: Unhandled error: AssertMismatch(Value@WHNF { value: DoubleLit(NaiveDouble(-0.0)), type: Value@WHNF { value: AppliedBuiltin(Double, []), type: Type } }, Value@WHNF { value: DoubleLit(NaiveDouble(0.0)), type: Value@WHNF { value: AppliedBuiltin(Double, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/AssertNotEquivalence.txt b/dhall/tests/type-errors/unit/AssertNotEquivalence.txt
index 4b68fea..537d31a 100644
--- a/dhall/tests/type-errors/unit/AssertNotEquivalence.txt
+++ b/dhall/tests/type-errors/unit/AssertNotEquivalence.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AssertMustTakeEquivalence
diff --git a/dhall/tests/type-errors/unit/AssertTriviallyFalse.txt b/dhall/tests/type-errors/unit/AssertTriviallyFalse.txt
index 4b68fea..c7bbf8d 100644
--- a/dhall/tests/type-errors/unit/AssertTriviallyFalse.txt
+++ b/dhall/tests/type-errors/unit/AssertTriviallyFalse.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AssertMismatch(Value@WHNF { value: NaturalLit(1), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } }, Value@WHNF { value: NaturalLit(2), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/EquivalenceNotSameType.txt b/dhall/tests/type-errors/unit/EquivalenceNotSameType.txt
index 4b68fea..4dbe2ad 100644
--- a/dhall/tests/type-errors/unit/EquivalenceNotSameType.txt
+++ b/dhall/tests/type-errors/unit/EquivalenceNotSameType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: EquivalenceTypeMismatch(Value@Unevaled { value: PartialExpr(BoolLit(false)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } }, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/EquivalenceNotTerms.txt b/dhall/tests/type-errors/unit/EquivalenceNotTerms.txt
index 4b68fea..dbce067 100644
--- a/dhall/tests/type-errors/unit/EquivalenceNotTerms.txt
+++ b/dhall/tests/type-errors/unit/EquivalenceNotTerms.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: EquivalenceArgumentMustBeTerm(true, Value@Unevaled { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/FunctionTypeKindSort.txt b/dhall/tests/type-errors/unit/FunctionTypeKindSort.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/FunctionTypeKindSort.txt
+++ b/dhall/tests/type-errors/unit/FunctionTypeKindSort.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/FunctionTypeTypeSort.txt b/dhall/tests/type-errors/unit/FunctionTypeTypeSort.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/FunctionTypeTypeSort.txt
+++ b/dhall/tests/type-errors/unit/FunctionTypeTypeSort.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/IfBranchesNotMatch.txt b/dhall/tests/type-errors/unit/IfBranchesNotMatch.txt
index 4b68fea..262e54f 100644
--- a/dhall/tests/type-errors/unit/IfBranchesNotMatch.txt
+++ b/dhall/tests/type-errors/unit/IfBranchesNotMatch.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: IfBranchMismatch(Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } }, Value@Unevaled { value: PartialExpr(TextLit(InterpolatedText { head: "", tail: [] })), type: Value@WHNF { value: AppliedBuiltin(Text, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/IfBranchesNotType.txt b/dhall/tests/type-errors/unit/IfBranchesNotType.txt
index 4b68fea..8ef3a40 100644
--- a/dhall/tests/type-errors/unit/IfBranchesNotType.txt
+++ b/dhall/tests/type-errors/unit/IfBranchesNotType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: IfBranchMustBeTerm(true, Type)
diff --git a/dhall/tests/type-errors/unit/IfNotBool.txt b/dhall/tests/type-errors/unit/IfNotBool.txt
index 4b68fea..64c0465 100644
--- a/dhall/tests/type-errors/unit/IfNotBool.txt
+++ b/dhall/tests/type-errors/unit/IfNotBool.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidPredicate(Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/LetWithWrongAnnotation.txt b/dhall/tests/type-errors/unit/LetWithWrongAnnotation.txt
index 4b68fea..0862162 100644
--- a/dhall/tests/type-errors/unit/LetWithWrongAnnotation.txt
+++ b/dhall/tests/type-errors/unit/LetWithWrongAnnotation.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AnnotMismatch(Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } }, Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/ListLiteralNotType.txt b/dhall/tests/type-errors/unit/ListLiteralNotType.txt
index 4b68fea..99b95a3 100644
--- a/dhall/tests/type-errors/unit/ListLiteralNotType.txt
+++ b/dhall/tests/type-errors/unit/ListLiteralNotType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidListType(Type)
diff --git a/dhall/tests/type-errors/unit/ListLiteralTypesNotMatch.txt b/dhall/tests/type-errors/unit/ListLiteralTypesNotMatch.txt
index 4b68fea..7916dbb 100644
--- a/dhall/tests/type-errors/unit/ListLiteralTypesNotMatch.txt
+++ b/dhall/tests/type-errors/unit/ListLiteralTypesNotMatch.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidListElement(1, Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type }, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/MergeAlternativeHasNoHandler.txt b/dhall/tests/type-errors/unit/MergeAlternativeHasNoHandler.txt
index 4b68fea..d4e9024 100644
--- a/dhall/tests/type-errors/unit/MergeAlternativeHasNoHandler.txt
+++ b/dhall/tests/type-errors/unit/MergeAlternativeHasNoHandler.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeVariantMissingHandler(Label("x"))
diff --git a/dhall/tests/type-errors/unit/MergeAnnotationMismatch.txt b/dhall/tests/type-errors/unit/MergeAnnotationMismatch.txt
index 4b68fea..823f2f7 100644
--- a/dhall/tests/type-errors/unit/MergeAnnotationMismatch.txt
+++ b/dhall/tests/type-errors/unit/MergeAnnotationMismatch.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeAnnotMismatch
diff --git a/dhall/tests/type-errors/unit/MergeAnnotationNotType.txt b/dhall/tests/type-errors/unit/MergeAnnotationNotType.txt
index 4b68fea..7da5cb9 100644
--- a/dhall/tests/type-errors/unit/MergeAnnotationNotType.txt
+++ b/dhall/tests/type-errors/unit/MergeAnnotationNotType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Merge2ArgMustBeUnionOrOptional(Value@Unevaled { value: UnionType({}), type: Type })
diff --git a/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation1.txt b/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation1.txt
index 4b68fea..563b3bf 100644
--- a/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation1.txt
+++ b/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation1.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeEmptyNeedsAnnotation
diff --git a/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation2.txt b/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation2.txt
index 4b68fea..563b3bf 100644
--- a/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation2.txt
+++ b/dhall/tests/type-errors/unit/MergeEmptyNeedsDirectAnnotation2.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeEmptyNeedsAnnotation
diff --git a/dhall/tests/type-errors/unit/MergeEmptyWithoutAnnotation.txt b/dhall/tests/type-errors/unit/MergeEmptyWithoutAnnotation.txt
index 4b68fea..7da5cb9 100644
--- a/dhall/tests/type-errors/unit/MergeEmptyWithoutAnnotation.txt
+++ b/dhall/tests/type-errors/unit/MergeEmptyWithoutAnnotation.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Merge2ArgMustBeUnionOrOptional(Value@Unevaled { value: UnionType({}), type: Type })
diff --git a/dhall/tests/type-errors/unit/MergeHandlerFreeVar.txt b/dhall/tests/type-errors/unit/MergeHandlerFreeVar.txt
index 4b68fea..de9e256 100644
--- a/dhall/tests/type-errors/unit/MergeHandlerFreeVar.txt
+++ b/dhall/tests/type-errors/unit/MergeHandlerFreeVar.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeHandlerReturnTypeMustNotBeDependent
diff --git a/dhall/tests/type-errors/unit/MergeHandlerNotInUnion.txt b/dhall/tests/type-errors/unit/MergeHandlerNotInUnion.txt
index 4b68fea..7da5cb9 100644
--- a/dhall/tests/type-errors/unit/MergeHandlerNotInUnion.txt
+++ b/dhall/tests/type-errors/unit/MergeHandlerNotInUnion.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Merge2ArgMustBeUnionOrOptional(Value@Unevaled { value: UnionType({}), type: Type })
diff --git a/dhall/tests/type-errors/unit/MergeHandlersWithDifferentType.txt b/dhall/tests/type-errors/unit/MergeHandlersWithDifferentType.txt
index 4b68fea..8b729a4 100644
--- a/dhall/tests/type-errors/unit/MergeHandlersWithDifferentType.txt
+++ b/dhall/tests/type-errors/unit/MergeHandlersWithDifferentType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeHandlerTypeMismatch
diff --git a/dhall/tests/type-errors/unit/MergeLhsNotRecord.txt b/dhall/tests/type-errors/unit/MergeLhsNotRecord.txt
index 4b68fea..da600de 100644
--- a/dhall/tests/type-errors/unit/MergeLhsNotRecord.txt
+++ b/dhall/tests/type-errors/unit/MergeLhsNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Merge1ArgMustBeRecord(Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/MergeMissingHandler1.txt b/dhall/tests/type-errors/unit/MergeMissingHandler1.txt
index 4b68fea..d4e9024 100644
--- a/dhall/tests/type-errors/unit/MergeMissingHandler1.txt
+++ b/dhall/tests/type-errors/unit/MergeMissingHandler1.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeVariantMissingHandler(Label("x"))
diff --git a/dhall/tests/type-errors/unit/MergeMissingHandler2.txt b/dhall/tests/type-errors/unit/MergeMissingHandler2.txt
index 4b68fea..d583de7 100644
--- a/dhall/tests/type-errors/unit/MergeMissingHandler2.txt
+++ b/dhall/tests/type-errors/unit/MergeMissingHandler2.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MergeVariantMissingHandler(Label("y"))
diff --git a/dhall/tests/type-errors/unit/MergeRhsNotUnion.txt b/dhall/tests/type-errors/unit/MergeRhsNotUnion.txt
index 4b68fea..db93650 100644
--- a/dhall/tests/type-errors/unit/MergeRhsNotUnion.txt
+++ b/dhall/tests/type-errors/unit/MergeRhsNotUnion.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Merge2ArgMustBeUnionOrOptional(Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/MergeUnusedHandler.txt b/dhall/tests/type-errors/unit/MergeUnusedHandler.txt
new file mode 100644
index 0000000..b7eefdd
--- /dev/null
+++ b/dhall/tests/type-errors/unit/MergeUnusedHandler.txt
@@ -0,0 +1 @@
+Type error: Unhandled error: MergeHandlerMissingVariant(Label("y"))
diff --git a/dhall/tests/type-errors/unit/OperatorAndNotBool.txt b/dhall/tests/type-errors/unit/OperatorAndNotBool.txt
index 4b68fea..a4346f2 100644
--- a/dhall/tests/type-errors/unit/OperatorAndNotBool.txt
+++ b/dhall/tests/type-errors/unit/OperatorAndNotBool.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(BoolAnd, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorEqualNotBool.txt b/dhall/tests/type-errors/unit/OperatorEqualNotBool.txt
index 4b68fea..57f9095 100644
--- a/dhall/tests/type-errors/unit/OperatorEqualNotBool.txt
+++ b/dhall/tests/type-errors/unit/OperatorEqualNotBool.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(BoolEQ, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorListConcatenateLhsNotList.txt b/dhall/tests/type-errors/unit/OperatorListConcatenateLhsNotList.txt
index 4b68fea..2bcb4fc 100644
--- a/dhall/tests/type-errors/unit/OperatorListConcatenateLhsNotList.txt
+++ b/dhall/tests/type-errors/unit/OperatorListConcatenateLhsNotList.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(ListAppend, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorListConcatenateListsNotMatch.txt b/dhall/tests/type-errors/unit/OperatorListConcatenateListsNotMatch.txt
index 4b68fea..e314702 100644
--- a/dhall/tests/type-errors/unit/OperatorListConcatenateListsNotMatch.txt
+++ b/dhall/tests/type-errors/unit/OperatorListConcatenateListsNotMatch.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(ListAppend, Value@Unevaled { value: PartialExpr(NEListLit([Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } }])), type: Value@WHNF { value: AppliedBuiltin(List, [Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type }]), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorListConcatenateNotListsButMatch.txt b/dhall/tests/type-errors/unit/OperatorListConcatenateNotListsButMatch.txt
index 4b68fea..2bcb4fc 100644
--- a/dhall/tests/type-errors/unit/OperatorListConcatenateNotListsButMatch.txt
+++ b/dhall/tests/type-errors/unit/OperatorListConcatenateNotListsButMatch.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(ListAppend, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorListConcatenateRhsNotList.txt b/dhall/tests/type-errors/unit/OperatorListConcatenateRhsNotList.txt
index 4b68fea..2bcb4fc 100644
--- a/dhall/tests/type-errors/unit/OperatorListConcatenateRhsNotList.txt
+++ b/dhall/tests/type-errors/unit/OperatorListConcatenateRhsNotList.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(ListAppend, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorNotEqualNotBool.txt b/dhall/tests/type-errors/unit/OperatorNotEqualNotBool.txt
index 4b68fea..32b3549 100644
--- a/dhall/tests/type-errors/unit/OperatorNotEqualNotBool.txt
+++ b/dhall/tests/type-errors/unit/OperatorNotEqualNotBool.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(BoolNE, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorOrNotBool.txt b/dhall/tests/type-errors/unit/OperatorOrNotBool.txt
index 4b68fea..f91bd83 100644
--- a/dhall/tests/type-errors/unit/OperatorOrNotBool.txt
+++ b/dhall/tests/type-errors/unit/OperatorOrNotBool.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(BoolOr, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorPlusNotNatural.txt b/dhall/tests/type-errors/unit/OperatorPlusNotNatural.txt
index 4b68fea..9194f3a 100644
--- a/dhall/tests/type-errors/unit/OperatorPlusNotNatural.txt
+++ b/dhall/tests/type-errors/unit/OperatorPlusNotNatural.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(NaturalPlus, Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorTextConcatenateLhsNotText.txt b/dhall/tests/type-errors/unit/OperatorTextConcatenateLhsNotText.txt
index 4b68fea..e67e9e5 100644
--- a/dhall/tests/type-errors/unit/OperatorTextConcatenateLhsNotText.txt
+++ b/dhall/tests/type-errors/unit/OperatorTextConcatenateLhsNotText.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(TextAppend, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorTextConcatenateRhsNotText.txt b/dhall/tests/type-errors/unit/OperatorTextConcatenateRhsNotText.txt
index 4b68fea..e67e9e5 100644
--- a/dhall/tests/type-errors/unit/OperatorTextConcatenateRhsNotText.txt
+++ b/dhall/tests/type-errors/unit/OperatorTextConcatenateRhsNotText.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(TextAppend, Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OperatorTimesNotNatural.txt b/dhall/tests/type-errors/unit/OperatorTimesNotNatural.txt
index 4b68fea..8146ba9 100644
--- a/dhall/tests/type-errors/unit/OperatorTimesNotNatural.txt
+++ b/dhall/tests/type-errors/unit/OperatorTimesNotNatural.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: BinOpTypeMismatch(NaturalTimes, Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxAbsent.txt b/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxAbsent.txt
index 4b68fea..c319c81 100644
--- a/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxAbsent.txt
+++ b/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxAbsent.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidListType(Value@WHNF { value: AppliedBuiltin(Optional, [Value@Unevaled { value: AppliedBuiltin(Bool, []), type: Type }]), type: Type })
diff --git a/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxPresent.txt b/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxPresent.txt
index 4b68fea..99df27c 100644
--- a/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxPresent.txt
+++ b/dhall/tests/type-errors/unit/OptionalDeprecatedSyntaxPresent.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AnnotMismatch(Value@Unevaled { value: PartialExpr(NEListLit([Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type } }])), type: Value@WHNF { value: AppliedBuiltin(List, [Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type }]), type: Type } }, Value@WHNF { value: AppliedBuiltin(Optional, [Value@Unevaled { value: AppliedBuiltin(Natural, []), type: Type }]), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecordLitDuplicateFields.txt b/dhall/tests/type-errors/unit/RecordLitDuplicateFields.txt
index 4b68fea..4fc4a50 100644
--- a/dhall/tests/type-errors/unit/RecordLitDuplicateFields.txt
+++ b/dhall/tests/type-errors/unit/RecordLitDuplicateFields.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeDuplicateField
diff --git a/dhall/tests/type-errors/unit/RecordMixedKinds3.txt b/dhall/tests/type-errors/unit/RecordMixedKinds3.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/RecordMixedKinds3.txt
+++ b/dhall/tests/type-errors/unit/RecordMixedKinds3.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/RecordProjectionDuplicateFields.txt b/dhall/tests/type-errors/unit/RecordProjectionDuplicateFields.txt
new file mode 100644
index 0000000..0d2e83e
--- /dev/null
+++ b/dhall/tests/type-errors/unit/RecordProjectionDuplicateFields.txt
@@ -0,0 +1 @@
+Type error: Unhandled error: ProjectionDuplicateField
diff --git a/dhall/tests/type-errors/unit/RecordProjectionEmpty.txt b/dhall/tests/type-errors/unit/RecordProjectionEmpty.txt
index 4b68fea..ddbe5e4 100644
--- a/dhall/tests/type-errors/unit/RecordProjectionEmpty.txt
+++ b/dhall/tests/type-errors/unit/RecordProjectionEmpty.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: ProjectionMissingEntry
diff --git a/dhall/tests/type-errors/unit/RecordProjectionNotPresent.txt b/dhall/tests/type-errors/unit/RecordProjectionNotPresent.txt
index 4b68fea..ddbe5e4 100644
--- a/dhall/tests/type-errors/unit/RecordProjectionNotPresent.txt
+++ b/dhall/tests/type-errors/unit/RecordProjectionNotPresent.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: ProjectionMissingEntry
diff --git a/dhall/tests/type-errors/unit/RecordProjectionNotRecord.txt b/dhall/tests/type-errors/unit/RecordProjectionNotRecord.txt
index 4b68fea..cb4b52f 100644
--- a/dhall/tests/type-errors/unit/RecordProjectionNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RecordProjectionNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: ProjectionMustBeRecord
diff --git a/dhall/tests/type-errors/unit/RecordSelectionEmpty.txt b/dhall/tests/type-errors/unit/RecordSelectionEmpty.txt
index 4b68fea..1770faa 100644
--- a/dhall/tests/type-errors/unit/RecordSelectionEmpty.txt
+++ b/dhall/tests/type-errors/unit/RecordSelectionEmpty.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MissingRecordField(Label("x"), Value@Unevaled { value: PartialExpr(RecordLit(DupTreeMap { map: {}, size: 0 })), type: Value@WHNF { value: RecordType({}), type: Type } })
diff --git a/dhall/tests/type-errors/unit/RecordSelectionNotPresent.txt b/dhall/tests/type-errors/unit/RecordSelectionNotPresent.txt
index 4b68fea..9211e05 100644
--- a/dhall/tests/type-errors/unit/RecordSelectionNotPresent.txt
+++ b/dhall/tests/type-errors/unit/RecordSelectionNotPresent.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MissingRecordField(Label("x"), Value@Unevaled { value: PartialExpr(RecordLit(DupTreeMap { map: {Label("y"): [Value@Unevaled { value: PartialExpr(RecordLit(DupTreeMap { map: {}, size: 0 })), type: Value@Unevaled { value: RecordType({}), type: Type } }]}, size: 1 })), type: Value@WHNF { value: RecordType({Label("y"): Value@Unevaled { value: RecordType({}), type: Type }}), type: Type } })
diff --git a/dhall/tests/type-errors/unit/RecordSelectionNotRecord.txt b/dhall/tests/type-errors/unit/RecordSelectionNotRecord.txt
index 4b68fea..27db6a2 100644
--- a/dhall/tests/type-errors/unit/RecordSelectionNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RecordSelectionNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: NotARecord(Label("x"), Value@WHNF { value: BoolLit(true), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/RecordSelectionTypeNotUnionType.txt b/dhall/tests/type-errors/unit/RecordSelectionTypeNotUnionType.txt
index 4b68fea..36c8e28 100644
--- a/dhall/tests/type-errors/unit/RecordSelectionTypeNotUnionType.txt
+++ b/dhall/tests/type-errors/unit/RecordSelectionTypeNotUnionType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: NotARecord(Label("x"), Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecordTypeDuplicateFields.txt b/dhall/tests/type-errors/unit/RecordTypeDuplicateFields.txt
index 4b68fea..4fc4a50 100644
--- a/dhall/tests/type-errors/unit/RecordTypeDuplicateFields.txt
+++ b/dhall/tests/type-errors/unit/RecordTypeDuplicateFields.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeDuplicateField
diff --git a/dhall/tests/type-errors/unit/RecordTypeValueMember.txt b/dhall/tests/type-errors/unit/RecordTypeValueMember.txt
index 4b68fea..72d4316 100644
--- a/dhall/tests/type-errors/unit/RecordTypeValueMember.txt
+++ b/dhall/tests/type-errors/unit/RecordTypeValueMember.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("x"), Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordMergeLhsNotRecord.txt b/dhall/tests/type-errors/unit/RecursiveRecordMergeLhsNotRecord.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordMergeLhsNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordMergeLhsNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordMergeOverlapping.txt b/dhall/tests/type-errors/unit/RecursiveRecordMergeOverlapping.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordMergeOverlapping.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordMergeOverlapping.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordMergeRhsNotRecord.txt b/dhall/tests/type-errors/unit/RecursiveRecordMergeRhsNotRecord.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordMergeRhsNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordMergeRhsNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeLhsNotRecordType.txt b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeLhsNotRecordType.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeLhsNotRecordType.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeLhsNotRecordType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeOverlapping.txt b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeOverlapping.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeOverlapping.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeOverlapping.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeRhsNotRecordType.txt b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeRhsNotRecordType.txt
index 4b68fea..42cdf65 100644
--- a/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeRhsNotRecordType.txt
+++ b/dhall/tests/type-errors/unit/RecursiveRecordTypeMergeRhsNotRecordType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: RecordTypeMergeRequiresRecordType(Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/RightBiasedRecordMergeLhsNotRecord.txt b/dhall/tests/type-errors/unit/RightBiasedRecordMergeLhsNotRecord.txt
index 4b68fea..9a2913b 100644
--- a/dhall/tests/type-errors/unit/RightBiasedRecordMergeLhsNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RightBiasedRecordMergeLhsNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MustCombineRecord(Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds2.txt b/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds2.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds2.txt
+++ b/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds2.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds3.txt b/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds3.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds3.txt
+++ b/dhall/tests/type-errors/unit/RightBiasedRecordMergeMixedKinds3.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/RightBiasedRecordMergeRhsNotRecord.txt b/dhall/tests/type-errors/unit/RightBiasedRecordMergeRhsNotRecord.txt
index 4b68fea..9a2913b 100644
--- a/dhall/tests/type-errors/unit/RightBiasedRecordMergeRhsNotRecord.txt
+++ b/dhall/tests/type-errors/unit/RightBiasedRecordMergeRhsNotRecord.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MustCombineRecord(Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/SomeNotType.txt b/dhall/tests/type-errors/unit/SomeNotType.txt
index 4b68fea..43581a0 100644
--- a/dhall/tests/type-errors/unit/SomeNotType.txt
+++ b/dhall/tests/type-errors/unit/SomeNotType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidOptionalType(Type)
diff --git a/dhall/tests/type-errors/unit/Sort.txt b/dhall/tests/type-errors/unit/Sort.txt
index 4b68fea..5b88ff7 100644
--- a/dhall/tests/type-errors/unit/Sort.txt
+++ b/dhall/tests/type-errors/unit/Sort.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: Sort
diff --git a/dhall/tests/type-errors/unit/TextLiteralInterpolateNotText.txt b/dhall/tests/type-errors/unit/TextLiteralInterpolateNotText.txt
index 4b68fea..ba2aecd 100644
--- a/dhall/tests/type-errors/unit/TextLiteralInterpolateNotText.txt
+++ b/dhall/tests/type-errors/unit/TextLiteralInterpolateNotText.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidTextInterpolation(Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } })
diff --git a/dhall/tests/type-errors/unit/TypeAnnotationWrong.txt b/dhall/tests/type-errors/unit/TypeAnnotationWrong.txt
index 4b68fea..77ff57f 100644
--- a/dhall/tests/type-errors/unit/TypeAnnotationWrong.txt
+++ b/dhall/tests/type-errors/unit/TypeAnnotationWrong.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: AnnotMismatch(Value@Unevaled { value: PartialExpr(NaturalLit(1)), type: Value@WHNF { value: AppliedBuiltin(Natural, []), type: Type } }, Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/UnionConstructorFieldNotPresent.txt b/dhall/tests/type-errors/unit/UnionConstructorFieldNotPresent.txt
index 4b68fea..7b2e610 100644
--- a/dhall/tests/type-errors/unit/UnionConstructorFieldNotPresent.txt
+++ b/dhall/tests/type-errors/unit/UnionConstructorFieldNotPresent.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: MissingUnionField(Label("y"), Value@WHNF { value: UnionType({Label("x"): Some(Value@Unevaled { value: AppliedBuiltin(Bool, []), type: Type })}), type: Type })
diff --git a/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants1.txt b/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants1.txt
index 4b68fea..27c6cbe 100644
--- a/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants1.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants1.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: UnionTypeDuplicateField
diff --git a/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants2.txt b/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants2.txt
index 4b68fea..27c6cbe 100644
--- a/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants2.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeDuplicateVariants2.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: UnionTypeDuplicateField
diff --git a/dhall/tests/type-errors/unit/UnionTypeMixedKinds.txt b/dhall/tests/type-errors/unit/UnionTypeMixedKinds.txt
index 4b68fea..07604ba 100644
--- a/dhall/tests/type-errors/unit/UnionTypeMixedKinds.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeMixedKinds.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("y"), Type)
diff --git a/dhall/tests/type-errors/unit/UnionTypeMixedKinds2.txt b/dhall/tests/type-errors/unit/UnionTypeMixedKinds2.txt
index 4b68fea..07604ba 100644
--- a/dhall/tests/type-errors/unit/UnionTypeMixedKinds2.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeMixedKinds2.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("y"), Type)
diff --git a/dhall/tests/type-errors/unit/UnionTypeMixedKinds3.txt b/dhall/tests/type-errors/unit/UnionTypeMixedKinds3.txt
index 4b68fea..83fc426 100644
--- a/dhall/tests/type-errors/unit/UnionTypeMixedKinds3.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeMixedKinds3.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("y"), Value@Unevaled { value: AppliedBuiltin(Bool, []), type: Type })
diff --git a/dhall/tests/type-errors/unit/UnionTypeNotType.txt b/dhall/tests/type-errors/unit/UnionTypeNotType.txt
index 4b68fea..72d4316 100644
--- a/dhall/tests/type-errors/unit/UnionTypeNotType.txt
+++ b/dhall/tests/type-errors/unit/UnionTypeNotType.txt
@@ -1 +1 @@
-Type error: Unhandled error
+Type error: Unhandled error: InvalidFieldType(Label("x"), Value@Unevaled { value: PartialExpr(BoolLit(true)), type: Value@WHNF { value: AppliedBuiltin(Bool, []), type: Type } })