Repository: tweag/nickel
Pull request #739 (2022-06-20 13:22:55)

Correct the type of UnaryOp::ToStr
This should be straightforward enough; most probably a typo.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index ad98cd45..db293c6f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -28,6 +28,15 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "aho-corasick"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "0.7.18"
@@ -37,6 +46,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "ansi_term"
 version = "0.12.1"
@@ -48,9 +66,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.57"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
+checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
 
 [[package]]
 name = "arrayvec"
@@ -101,15 +119,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.65"
+version = "0.3.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
+checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
 dependencies = [
  "addr2line",
  "cc",
  "cfg-if",
  "libc",
- "miniz_oxide",
+ "miniz_oxide 0.4.4",
  "object",
  "rustc-demangle",
 ]
@@ -122,9 +140,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
 
 [[package]]
 name = "beef"
-version = "0.5.2"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
+checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736"
 
 [[package]]
 name = "bincode"
@@ -152,9 +170,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
 
 [[package]]
 name = "bitflags"
-version = "1.3.2"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
 [[package]]
 name = "block-buffer"
@@ -170,9 +188,9 @@ dependencies = [
 
 [[package]]
 name = "block-buffer"
-version = "0.10.2"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
 dependencies = [
  "generic-array 0.14.5",
 ]
@@ -200,9 +218,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.10.0"
+version = "3.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
+checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
 
 [[package]]
 name = "byte-tools"
@@ -212,9 +230,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
 
 [[package]]
 name = "bytemuck"
-version = "1.9.1"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
+checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead"
 
 [[package]]
 name = "byteorder"
@@ -249,7 +267,7 @@ version = "2.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
 dependencies = [
- "ansi_term",
+ "ansi_term 0.12.1",
  "atty",
  "bitflags",
  "strsim",
@@ -258,17 +276,6 @@ dependencies = [
  "vec_map",
 ]
 
-[[package]]
-name = "clipboard-win"
-version = "4.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f3e1238132dc01f081e1cbb9dace14e5ef4c3a51ee244bd982275fb514605db"
-dependencies = [
- "error-code",
- "str-buf",
- "winapi",
-]
-
 [[package]]
 name = "codespan"
 version = "0.11.1"
@@ -310,7 +317,7 @@ dependencies = [
  "lazy_static",
  "pest",
  "pest_derive",
- "regex",
+ "regex 1.5.5",
  "shell-words",
  "syntect",
  "twoway",
@@ -325,15 +332,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 
-[[package]]
-name = "coolor"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaebeb52e38d53b890ebcb723ff23462f39353d4e73db48284591e6395a1c25e"
-dependencies = [
- "crossterm",
-]
-
 [[package]]
 name = "cpp_demangle"
 version = "0.3.5"
@@ -345,9 +343,9 @@ dependencies = [
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.2"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
 dependencies = [
  "libc",
 ]
@@ -378,7 +376,7 @@ dependencies = [
  "oorandom",
  "plotters",
  "rayon",
- "regex",
+ "regex 1.5.5",
  "serde",
  "serde_cbor",
  "serde_derive",
@@ -413,9 +411,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.4"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
+checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -434,11 +432,10 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.8"
+version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
 dependencies = [
- "autocfg",
  "cfg-if",
  "crossbeam-utils",
  "lazy_static",
@@ -448,9 +445,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.3.5"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
+checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -458,9 +455,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
 dependencies = [
  "cfg-if",
  "lazy_static",
@@ -468,15 +465,15 @@ dependencies = [
 
 [[package]]
 name = "crossterm"
-version = "0.22.1"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c"
+checksum = "486d44227f71a1ef39554c0dc47e44b9f4139927c75043312690c3f476d1d788"
 dependencies = [
  "bitflags",
  "crossterm_winapi",
  "libc",
  "mio",
- "parking_lot 0.11.2",
+ "parking_lot",
  "signal-hook",
  "signal-hook-mio",
  "winapi",
@@ -484,9 +481,9 @@ dependencies = [
 
 [[package]]
 name = "crossterm_winapi"
-version = "0.9.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
+checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
 dependencies = [
  "winapi",
 ]
@@ -497,16 +494,6 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 
-[[package]]
-name = "crypto-common"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
-dependencies = [
- "generic-array 0.14.5",
- "typenum",
-]
-
 [[package]]
 name = "csv"
 version = "1.1.6"
@@ -529,16 +516,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "ctor"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
-dependencies = [
- "quote",
- "syn",
-]
-
 [[package]]
 name = "debugid"
 version = "0.7.3"
@@ -567,6 +544,12 @@ version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
 
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
 [[package]]
 name = "digest"
 version = "0.8.1"
@@ -578,12 +561,11 @@ dependencies = [
 
 [[package]]
 name = "digest"
-version = "0.10.3"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
 dependencies = [
- "block-buffer 0.10.2",
- "crypto-common",
+ "generic-array 0.14.5",
 ]
 
 [[package]]
@@ -616,9 +598,9 @@ dependencies = [
 
 [[package]]
 name = "dirs-sys"
-version = "0.3.7"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
 dependencies = [
  "libc",
  "redox_users",
@@ -651,12 +633,6 @@ dependencies = [
  "log",
 ]
 
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
 [[package]]
 name = "entities"
 version = "1.0.1"
@@ -672,41 +648,10 @@ dependencies = [
  "atty",
  "humantime",
  "log",
- "regex",
+ "regex 1.5.5",
  "termcolor",
 ]
 
-[[package]]
-name = "errno"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "error-code"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
-dependencies = [
- "libc",
- "str-buf",
-]
-
 [[package]]
 name = "fake-simd"
 version = "0.1.2"
@@ -722,43 +667,22 @@ dependencies = [
  "instant",
 ]
 
-[[package]]
-name = "fd-lock"
-version = "3.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46e245f4c8ec30c6415c56cb132c07e69e74f1942f6b4a4061da748b49f486ca"
-dependencies = [
- "cfg-if",
- "rustix",
- "windows-sys 0.30.0",
-]
-
-[[package]]
-name = "findshlibs"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
-dependencies = [
- "cc",
- "lazy_static",
- "libc",
- "winapi",
-]
-
 [[package]]
 name = "fixedbitset"
-version = "0.4.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
 
 [[package]]
 name = "flate2"
-version = "1.0.24"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
 dependencies = [
+ "cfg-if",
  "crc32fast",
- "miniz_oxide",
+ "libc",
+ "miniz_oxide 0.5.1",
 ]
 
 [[package]]
@@ -777,6 +701,16 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.12.4"
@@ -798,9 +732,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.6"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
+checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
 dependencies = [
  "cfg-if",
  "libc",
@@ -862,9 +796,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.8.2"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
 dependencies = [
  "autocfg",
  "hashbrown",
@@ -872,14 +806,14 @@ dependencies = [
 
 [[package]]
 name = "inferno"
-version = "0.11.4"
+version = "0.10.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a3cb215599901c8f491666421d44ffaed08d6872b4c7ced6f425683b951271e"
+checksum = "de3886428c6400486522cf44b8626e7b94ad794c14390290f2a274dcf728a58f"
 dependencies = [
  "ahash",
  "atty",
  "indexmap",
- "itoa 1.0.2",
+ "itoa 1.0.1",
  "lazy_static",
  "log",
  "num-format",
@@ -897,12 +831,6 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "io-lifetimes"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9448015e586b611e5d322f6703812bbca2f1e709d5773ecd38ddb4e3bb649504"
-
 [[package]]
 name = "itertools"
 version = "0.10.3"
@@ -920,9 +848,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
 
 [[package]]
 name = "itoa"
-version = "1.0.2"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
 
 [[package]]
 name = "js-sys"
@@ -935,9 +863,9 @@ dependencies = [
 
 [[package]]
 name = "lalrpop"
-version = "0.19.8"
+version = "0.19.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823"
+checksum = "852b75a095da6b69da8c5557731c3afd06525d4f655a4fc1c799e2ec8bc4dce4"
 dependencies = [
  "ascii-canvas",
  "atty",
@@ -948,8 +876,8 @@ dependencies = [
  "lalrpop-util",
  "petgraph",
  "pico-args",
- "regex",
- "regex-syntax",
+ "regex 1.5.5",
+ "regex-syntax 0.6.25",
  "string_cache",
  "term",
  "tiny-keccak",
@@ -958,11 +886,11 @@ dependencies = [
 
 [[package]]
 name = "lalrpop-util"
-version = "0.19.8"
+version = "0.19.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4"
+checksum = "d6d265705249fe209280676d8f68887859fa42e1d34f342fc05bd47726a5e188"
 dependencies = [
- "regex",
+ "regex 1.5.5",
 ]
 
 [[package]]
@@ -979,9 +907,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.126"
+version = "0.2.119"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
 
 [[package]]
 name = "line-wrap"
@@ -998,27 +926,20 @@ version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
 
-[[package]]
-name = "linux-raw-sys"
-version = "0.0.46"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
-
 [[package]]
 name = "lock_api"
-version = "0.4.7"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
+checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
 dependencies = [
- "autocfg",
  "scopeguard",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.17"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 dependencies = [
  "cfg-if",
 ]
@@ -1042,16 +963,16 @@ dependencies = [
  "fnv",
  "proc-macro2",
  "quote",
- "regex-syntax",
+ "regex-syntax 0.6.25",
  "syn",
  "utf8-ranges",
 ]
 
 [[package]]
 name = "lsp-server"
-version = "0.6.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f70570c1c29cf6654029b8fe201a5507c153f0d85be6f234d471d756bc36775a"
+checksum = "c351c75989da23b355226dc188dc2b52538a7f4f218d70fd7393c6b62b110444"
 dependencies = [
  "crossbeam-channel",
  "log",
@@ -1086,18 +1007,20 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
 
 [[package]]
 name = "md-5"
-version = "0.10.1"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582"
+checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
 dependencies = [
- "digest 0.10.3",
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.5.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
 [[package]]
 name = "memmap2"
@@ -1128,9 +1051,19 @@ dependencies = [
 
 [[package]]
 name = "miniz_oxide"
-version = "0.5.3"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
 dependencies = [
  "adler",
 ]
@@ -1163,20 +1096,11 @@ version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
 
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
 [[package]]
 name = "nickel-lang"
 version = "0.1.0"
 dependencies = [
- "ansi_term",
+ "ansi_term 0.12.1",
  "assert_matches",
  "codespan",
  "codespan-reporting",
@@ -1192,14 +1116,14 @@ dependencies = [
  "pprof",
  "pretty",
  "pretty_assertions",
- "regex",
+ "regex 0.2.11",
  "rustyline",
  "rustyline-derive",
  "serde",
  "serde_json",
  "serde_repr",
  "serde_yaml",
- "sha-1 0.10.0",
+ "sha-1 0.9.8",
  "sha2",
  "similar",
  "simple-counter",
@@ -1246,26 +1170,27 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.23.1"
+version = "0.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
+checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2"
 dependencies = [
  "bitflags",
  "cc",
  "cfg-if",
  "libc",
- "memoffset",
 ]
 
 [[package]]
 name = "nix"
-version = "0.24.1"
+version = "0.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9"
+checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945"
 dependencies = [
  "bitflags",
+ "cc",
  "cfg-if",
  "libc",
+ "memoffset",
 ]
 
 [[package]]
@@ -1295,9 +1220,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.15"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
 dependencies = [
  "autocfg",
 ]
@@ -1323,18 +1248,18 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.28.4"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.12.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
 name = "onig"
@@ -1371,13 +1296,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 
 [[package]]
-name = "output_vt100"
-version = "0.1.3"
+name = "opaque-debug"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
-dependencies = [
- "winapi",
-]
+checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
 
 [[package]]
 name = "parking_lot"
@@ -1387,17 +1309,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
 dependencies = [
  "instant",
  "lock_api",
- "parking_lot_core 0.8.5",
-]
-
-[[package]]
-name = "parking_lot"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
-dependencies = [
- "lock_api",
- "parking_lot_core 0.9.3",
+ "parking_lot_core",
 ]
 
 [[package]]
@@ -1414,19 +1326,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "parking_lot_core"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-sys 0.36.1",
-]
-
 [[package]]
 name = "percent-encoding"
 version = "2.1.0"
@@ -1478,9 +1377,9 @@ dependencies = [
 
 [[package]]
 name = "petgraph"
-version = "0.6.2"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
 dependencies = [
  "fixedbitset",
  "indexmap",
@@ -1551,21 +1450,18 @@ dependencies = [
 
 [[package]]
 name = "pprof"
-version = "0.9.1"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97149c0eacaa6b8f8cedea99f68bb3a0517fa20f8de8d8c24c1a810f38d235d"
+checksum = "d78fcdebc1569625891b4fefed7ece660af53082529d03d9c6e8d01b3880ab92"
 dependencies = [
  "backtrace",
- "cfg-if",
  "criterion",
- "findshlibs",
  "inferno",
+ "lazy_static",
  "libc",
  "log",
- "nix 0.24.1",
- "once_cell",
- "parking_lot 0.12.1",
- "smallvec",
+ "nix 0.20.2",
+ "parking_lot",
  "symbolic-demangle",
  "tempfile",
  "thiserror",
@@ -1579,9 +1475,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "pretty"
-version = "0.11.3"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83f3aa1e3ca87d3b124db7461265ac176b40c277f37e503eaa29c9c75c037846"
+checksum = "29afd15870fab34b2a8884481a68f052b3d720cfb29666d7ae0ac2a42ea10289"
 dependencies = [
  "arrayvec 0.5.2",
  "log",
@@ -1591,14 +1487,12 @@ dependencies = [
 
 [[package]]
 name = "pretty_assertions"
-version = "1.2.1"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
+checksum = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
 dependencies = [
- "ansi_term",
- "ctor",
- "diff",
- "output_vt100",
+ "ansi_term 0.11.0",
+ "difference",
 ]
 
 [[package]]
@@ -1627,46 +1521,36 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.39"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
 dependencies = [
- "unicode-ident",
+ "unicode-xid",
 ]
 
 [[package]]
 name = "quick-xml"
-version = "0.23.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9279fbdacaad3baf559d8cabe0acc3d06e30ea14931af31af79578ac0946decc"
+checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.18"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
 dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
 [[package]]
 name = "rayon"
-version = "1.5.3"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
 dependencies = [
  "autocfg",
  "crossbeam-deque",
@@ -1676,45 +1560,58 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.9.3"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
  "crossbeam-utils",
+ "lazy_static",
  "num_cpus",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.13"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "redox_users"
-version = "0.4.3"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
 dependencies = [
  "getrandom",
  "redox_syscall",
- "thiserror",
 ]
 
 [[package]]
 name = "regex"
-version = "1.5.6"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
+checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
 dependencies = [
- "aho-corasick",
+ "aho-corasick 0.6.10",
  "memchr",
- "regex-syntax",
+ "regex-syntax 0.5.6",
+ "thread_local",
+ "utf8-ranges",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+dependencies = [
+ "aho-corasick 0.7.18",
+ "memchr",
+ "regex-syntax 0.6.25",
 ]
 
 [[package]]
@@ -1725,9 +1622,18 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.26"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
+checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
+dependencies = [
+ "ucd-util",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 
 [[package]]
 name = "remove_dir_all"
@@ -1762,20 +1668,6 @@ dependencies = [
  "semver",
 ]
 
-[[package]]
-name = "rustix"
-version = "0.34.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2079c267b8394eb529872c3cf92e181c378b41fea36e68130357b52493701d2e"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "winapi",
-]
-
 [[package]]
 name = "rustversion"
 version = "1.0.6"
@@ -1784,22 +1676,19 @@ checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
 
 [[package]]
 name = "rustyline"
-version = "9.1.2"
+version = "7.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039"
+checksum = "8227301bfc717136f0ecbd3d064ba8199e44497a0bdd46bb01ede4387cfd2cec"
 dependencies = [
  "bitflags",
  "cfg-if",
- "clipboard-win",
  "dirs-next",
- "fd-lock",
+ "fs2",
  "libc",
  "log",
  "memchr",
- "nix 0.23.1",
- "radix_trie",
+ "nix 0.19.1",
  "scopeguard",
- "smallvec",
  "unicode-segmentation",
  "unicode-width",
  "utf8parse",
@@ -1808,9 +1697,9 @@ dependencies = [
 
 [[package]]
 name = "rustyline-derive"
-version = "0.6.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb35a55ab810b5c0fe31606fe9b47d1354e4dc519bec0a102655f78ea2b38057"
+checksum = "db9dfbf470021de34cfaf6983067f460ea19164934a7c2d4b92eec0968eb95f1"
 dependencies = [
  "quote",
  "syn",
@@ -1818,9 +1707,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.10"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
+checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 
 [[package]]
 name = "safemem"
@@ -1845,15 +1734,15 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "semver"
-version = "1.0.9"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
+checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
 
 [[package]]
 name = "serde"
-version = "1.0.137"
+version = "1.0.136"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
+checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
 dependencies = [
  "serde_derive",
 ]
@@ -1870,9 +1759,9 @@ dependencies = [
 
 [[package]]
 name = "serde_derive"
-version = "1.0.137"
+version = "1.0.136"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
+checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1881,20 +1770,20 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.81"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
+checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
 dependencies = [
- "itoa 1.0.2",
+ "itoa 1.0.1",
  "ryu",
  "serde",
 ]
 
 [[package]]
 name = "serde_repr"
-version = "0.1.8"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
+checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1903,9 +1792,9 @@ dependencies = [
 
 [[package]]
 name = "serde_yaml"
-version = "0.8.24"
+version = "0.8.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
+checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
 dependencies = [
  "indexmap",
  "ryu",
@@ -1922,29 +1811,33 @@ dependencies = [
  "block-buffer 0.7.3",
  "digest 0.8.1",
  "fake-simd",
- "opaque-debug",
+ "opaque-debug 0.2.3",
 ]
 
 [[package]]
 name = "sha-1"
-version = "0.10.0"
+version = "0.9.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
+checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
 dependencies = [
+ "block-buffer 0.9.0",
  "cfg-if",
  "cpufeatures",
- "digest 0.10.3",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
 ]
 
 [[package]]
 name = "sha2"
-version = "0.10.2"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
 dependencies = [
+ "block-buffer 0.9.0",
  "cfg-if",
  "cpufeatures",
- "digest 0.10.3",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
 ]
 
 [[package]]
@@ -1955,9 +1848,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
 
 [[package]]
 name = "signal-hook"
-version = "0.3.14"
+version = "0.3.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
+checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
 dependencies = [
  "libc",
  "signal-hook-registry",
@@ -1965,9 +1858,9 @@ dependencies = [
 
 [[package]]
 name = "signal-hook-mio"
-version = "0.2.3"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
+checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
 dependencies = [
  "libc",
  "mio",
@@ -2013,12 +1906,6 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
-[[package]]
-name = "str-buf"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
-
 [[package]]
 name = "str_stack"
 version = "0.1.0"
@@ -2027,13 +1914,13 @@ checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
 
 [[package]]
 name = "string_cache"
-version = "0.8.4"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08"
+checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26"
 dependencies = [
+ "lazy_static",
  "new_debug_unreachable",
- "once_cell",
- "parking_lot 0.12.1",
+ "parking_lot",
  "phf_shared",
  "precomputed-hash",
 ]
@@ -2070,9 +1957,9 @@ dependencies = [
 
 [[package]]
 name = "symbolic-common"
-version = "8.7.3"
+version = "8.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c276d5b296f30f0fb30d2128b6be6f9804be7669f1edef46c4d8c017de4c77c3"
+checksum = "52ca6f4079d985e79702d1cce708bdd03ac570e220bcf87105d86f5a8ebb26be"
 dependencies = [
  "debugid",
  "memmap2",
@@ -2082,9 +1969,9 @@ dependencies = [
 
 [[package]]
 name = "symbolic-demangle"
-version = "8.7.3"
+version = "8.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b096bd4794e4d05584144dc9536a4fde8844da73f84cdb7652ed78b59e37a218"
+checksum = "7bd7f5075d8bbe9b00eaa9cb47e788fe9405f3306f7497b617b62e5f65ec619a"
 dependencies = [
  "cpp_demangle",
  "rustc-demangle",
@@ -2093,13 +1980,13 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.95"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
+checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
 dependencies = [
  "proc-macro2",
  "quote",
- "unicode-ident",
+ "unicode-xid",
 ]
 
 [[package]]
@@ -2116,7 +2003,7 @@ dependencies = [
  "lazycell",
  "onig",
  "plist",
- "regex-syntax",
+ "regex-syntax 0.6.25",
  "serde",
  "serde_derive",
  "serde_json",
@@ -2160,11 +2047,10 @@ dependencies = [
 
 [[package]]
 name = "termimad"
-version = "0.20.1"
+version = "0.16.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c14caf224b3f3d43d93d0532098f9e4906bd79e0978a2e10951f17aab7898b"
+checksum = "d88221817ef21964ccccf7d8ccc35fed3bae3066a177d1fcda72d694a016a47d"
 dependencies = [
- "coolor",
  "crossbeam",
  "crossterm",
  "minimad",
@@ -2183,31 +2069,40 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.31"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.31"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
+[[package]]
+name = "thread_local"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
+dependencies = [
+ "lazy_static",
+]
+
 [[package]]
 name = "time"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd"
 dependencies = [
- "itoa 1.0.2",
+ "itoa 1.0.1",
  "libc",
  "num_threads",
 ]
@@ -2233,9 +2128,9 @@ dependencies = [
 
 [[package]]
 name = "tinyvec"
-version = "1.6.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -2248,9 +2143,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 
 [[package]]
 name = "toml"
-version = "0.5.9"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
 dependencies = [
  "serde",
 ]
@@ -2289,6 +2184,12 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "ucd-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236"
+
 [[package]]
 name = "unchecked-index"
 version = "0.2.2"
@@ -2297,15 +2198,9 @@ checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.0"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
+checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
 
 [[package]]
 name = "unicode-normalization"
@@ -2330,9 +2225,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.3"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
 [[package]]
 name = "unicode_categories"
@@ -2355,9 +2250,9 @@ dependencies = [
 
 [[package]]
 name = "utf8-ranges"
-version = "1.0.5"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
+checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
 
 [[package]]
 name = "utf8parse"
@@ -2503,92 +2398,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
-[[package]]
-name = "windows-sys"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "030b7ff91626e57a05ca64a07c481973cbb2db774e4852c9c7ca342408c6a99a"
-dependencies = [
- "windows_aarch64_msvc 0.30.0",
- "windows_i686_gnu 0.30.0",
- "windows_i686_msvc 0.30.0",
- "windows_x86_64_gnu 0.30.0",
- "windows_x86_64_msvc 0.30.0",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
-dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
-]
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.30.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
 [[package]]
 name = "xdg"
 version = "2.4.1"
diff --git a/Cargo.toml b/Cargo.toml
index ad5b165f..99d2f95e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,40 +30,40 @@ lalrpop = "0.19.6"
 
 [dependencies]
 lalrpop-util = "0.19.6"
-regex = "1.5"
+regex = "0.2.1"
 simple-counter = "0.1.0"
 codespan = "0.11"
 codespan-reporting = "0.11"
 logos = "0.12.0"
-serde = { version = "1.0.137", features = ["derive"] }
-serde_json = "1.0.81"
-serde_yaml = "0.8.24"
-toml = "0.5.9"
+serde = { version = "1.0.117", features = ["derive"] }
+serde_json = "1.0.59"
+serde_yaml = "0.8.15"
+toml = "0.5.8"
 structopt = "0.3"
 void = "1"
-sha-1 = "0.10.0"
-sha2 = "0.10.2"
-md-5 = "0.10.1"
+sha-1 = "0.9.3"
+sha2 = "0.9.3"
+md-5 = "0.9.1"
 directories = "4.0.1"
 
-termimad = { version = "0.20.1", optional = true }
+termimad = { version = "0.16.2", optional = true }
 ansi_term = { version = "0.12", optional = true }
 
-rustyline = { version = "9.1.2", optional = true}
-rustyline-derive = { version = "0.6.0", optional = true }
+rustyline = { version = "7.1.0", optional = true}
+rustyline-derive = { version = "0.4.0", optional = true }
 
 wasm-bindgen = { version = "=0.2.74", optional = true, features = ["serde-serialize"] }
 js-sys = { version = "0.3", optional = true }
 serde_repr = { version = "0.1", optional = true }
-pretty = "0.11.3"
+pretty = "0.11.2"
 
 comrak = { version = "0.12.1", optional = true, features = [] }
 
 [dev-dependencies]
-pretty_assertions = "1.2.1"
-assert_matches = "1.5.0"
+pretty_assertions = "0.5.1"
+assert_matches = "1.4.0"
 criterion = "0.3"
-pprof = { version = "0.9.1", features = ["criterion", "flamegraph"] }
+pprof = { version = "0.4.4", features = ["criterion", "flamegraph"] }
 nickel-lang-utilities = {path = "utilities", version = "0.1.0"}
 similar = "2.1.0"
 
diff --git a/README.md b/README.md
index 700e0d28..02b768f4 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
 # Nickel
 
 [![Continuous integration](https://github.com/tweag/nickel/workflows/Continuous%20integration/badge.svg)](https://github.com/tweag/nickel/actions?query=branch%3Amaster)
-[![Website](https://img.shields.io/website-up-down-green-red/http/cv.lbesson.qc.to.svg)](https://nickel-lang.org)
 
 Nickel is the cheap configuration language.
 
@@ -72,12 +71,6 @@ abstractions or just feel ad hoc. Nickel buys you more for less.
 
 ## Getting started
 
-Please follow the getting started guide for Nickel users on the [nickel-lang
-website](https://nickel-lang.org/getting-started). The instructions below are
-either reproduced for this document to be relatively self-sufficient, or because
-they are aimed toward hacking on the Nickel interpreter itself (e.g. building
-the `nickel-lang` crate documentation).
-
 ### Run
 
 1. Start Nickel
@@ -162,12 +155,6 @@ $ cargo test
 
 ### Documentation
 
-The user manual is available [on the nickel-lang.org
-website](https://nickel-lang.org/user-manual/introduction), and in this
-repository as a collection of Markdown files in `doc/manual`.
-
-To get the documentation of the `nickel-lang` codebase itself:
-
 1. Build the doc:
   ```console
   $ cargo doc --no-deps
diff --git a/doc/manual/syntax.md b/doc/manual/syntax.md
index cd1f2283..3fcf5969 100644
--- a/doc/manual/syntax.md
+++ b/doc/manual/syntax.md
@@ -4,10 +4,6 @@ slug: syntax
 
 # Nickel Syntax
 
-## Identifiers
-
-Nickel identifiers start with an alphabetic character, followed by zero or more alphanumeric characters, `_` (underscores) or `'` (single quotes). For example, `this-isn't-invalid` is a valid identifier.
-
 ## Simple values
 
 There are four basic kind of values in Nickel :
diff --git a/lsp/nls/Cargo.toml b/lsp/nls/Cargo.toml
index 3427cd7c..607dfb5c 100644
--- a/lsp/nls/Cargo.toml
+++ b/lsp/nls/Cargo.toml
@@ -21,12 +21,12 @@ lalrpop-util = "0.19.6"
 codespan = "0.11"
 codespan-reporting = "0.11"
 codespan-lsp = "0.11"
-serde = { version = "1.0.137", features = ["derive"] }
-serde_json = "1.0.81"
+serde = { version = "1.0.117", features = ["derive"] }
+serde_json = "1.0.59"
 structopt = "0.3"
 
 
-lsp-server = "0.6"
+lsp-server = "0.5"
 lsp-types = "0.88"
 log = "0.4"
 env_logger = "0.9"
@@ -37,5 +37,5 @@ lazy_static = "1"
 csv = "1"
 
 [dev-dependencies]
-pretty_assertions = "1.2.1"
-assert_matches = "1.5.0"
+pretty_assertions = "0.5.1"
+assert_matches = "1.4.0"
diff --git a/lsp/nls/src/files.rs b/lsp/nls/src/files.rs
index b1211d29..db295d1e 100644
--- a/lsp/nls/src/files.rs
+++ b/lsp/nls/src/files.rs
@@ -82,7 +82,7 @@ fn typecheck(server: &mut Server, file_id: FileId) -> Result<CacheOp<()>, Vec<Di
 fn parse_and_typecheck(server: &mut Server, uri: Url, file_id: FileId) -> Result<()> {
     let diagnostics = server
         .cache
-        .parse_lax(file_id)
+        .parse(file_id)
         .map_err(|parse_err| parse_err.to_diagnostic(server.cache.files_mut(), None))
         .map(|parse_errs| {
             // Parse errors are not fatal
diff --git a/lsp/nls/src/linearization/completed.rs b/lsp/nls/src/linearization/completed.rs
index d3b01e75..21cd5d04 100644
--- a/lsp/nls/src/linearization/completed.rs
+++ b/lsp/nls/src/linearization/completed.rs
@@ -3,7 +3,7 @@ use std::collections::HashMap;
 use codespan::ByteIndex;
 use nickel_lang::{
     term::MetaValue,
-    typecheck::linearization::{LinearizationState, Scope},
+    typecheck::linearization::{LinearizationState, Scope, ScopeId},
 };
 
 use super::{
diff --git a/src/bin/nickel.rs b/src/bin/nickel.rs
index c6d7fec4..dfd0b285 100644
--- a/src/bin/nickel.rs
+++ b/src/bin/nickel.rs
@@ -139,7 +139,7 @@ fn main() {
                     query_print::write_query_result(&mut std::io::stdout(), &term, attrs).unwrap()
                 })
             }
-            Some(Command::Typecheck) => program.typecheck(),
+            Some(Command::Typecheck) => program.typecheck().map(|_| ()),
             Some(Command::Repl { .. }) => unreachable!(),
             #[cfg(feature = "doc")]
             Some(Command::Doc { .. }) => program.output_doc(),
diff --git a/src/cache.rs b/src/cache.rs
index abac08a3..02cf32e1 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -6,7 +6,7 @@ use crate::position::TermPos;
 use crate::stdlib as nickel_stdlib;
 use crate::term::{RichTerm, SharedTerm, Term};
 use crate::transform::import_resolution;
-use crate::typecheck::{self, TypeCheckingOutput, Wildcards};
+use crate::typecheck;
 use crate::typecheck::{linearization::StubHost, type_check};
 use crate::types::UnboundTypeVariableError;
 use crate::{eval, parser, transform};
@@ -68,8 +68,6 @@ pub struct Cache {
     terms: HashMap<FileId, CachedTerm>,
     /// The list of ids corresponding to the stdlib modules
     stdlib_ids: Option<Vec<FileId>>,
-    /// The inferred type of wildcards for each `FileId`.
-    wildcards: HashMap<FileId, Wildcards>,
 
     #[cfg(debug_assertions)]
     /// Skip loading the stdlib, used for debugging purpose
@@ -207,7 +205,6 @@ impl Cache {
             files: Files::new(),
             file_ids: HashMap::new(),
             terms: HashMap::new(),
-            wildcards: HashMap::new(),
             imports: HashMap::new(),
             stdlib_ids: None,
 
@@ -338,12 +335,8 @@ impl Cache {
     }
 
     /// Parse a source and populate the corresponding entry in the cache, or do nothing if the
-    /// entry has already been parsed. This function is error tolerant: parts of the source which
-    /// result in parse errors are parsed as [`crate::term::RichTerm::Error`] and the
-    /// corresponding error messages are collected and returned.
-    ///
-    /// The `Err` part of the result corresponds to non-recoverable errors.
-    pub fn parse_lax(&mut self, file_id: FileId) -> Result<CacheOp<ParseErrors>, ParseError> {
+    /// entry has already been parsed.
+    pub fn parse(&mut self, file_id: FileId) -> Result<CacheOp<ParseErrors>, ParseError> {
         if let Some(CachedTerm { parse_errs, .. }) = self.terms.get(&file_id) {
             Ok(CacheOp::Cached(parse_errs.clone()))
         } else {
@@ -360,17 +353,6 @@ impl Cache {
         }
     }
 
-    /// Parse a source and populate the corresponding entry in the cache, or do nothing if the
-    /// entry has already been parsed. This function is not error tolerant and returns `Err` if at
-    /// least one parse error has been encountered.
-    pub fn parse(&mut self, file_id: FileId) -> Result<CacheOp<()>, ParseErrors> {
-        match self.parse_lax(file_id)? {
-            CacheOp::Done(e) | CacheOp::Cached(e) if !e.no_errors() => Err(e),
-            CacheOp::Done(_) => Ok(CacheOp::Done(())),
-            CacheOp::Cached(_) => Ok(CacheOp::Cached(())),
-        }
-    }
-
     /// Parse a source and populate the corresponding entry in the cache, or do nothing if the
     /// entry has already been parsed. Support multiple formats.
     pub fn parse_multi(
@@ -409,8 +391,8 @@ impl Cache {
 
         match format {
             InputFormat::Nickel => {
-                let (t, parse_errs) =
-                    parser::grammar::TermParser::new().parse_term_lax(file_id, Lexer::new(buf))?;
+                let (t, parse_errs) = parser::grammar::TermParser::new()
+                    .parse_term_tolerant(file_id, Lexer::new(buf))?;
 
                 Ok((t, parse_errs))
             }
@@ -440,10 +422,8 @@ impl Cache {
             }
             Some(CachedTerm { term, state, .. }) if *state >= EntryState::Parsed => {
                 if *state < EntryState::Typechecking {
-                    let (TypeCheckingOutput { wildcards, .. }, _) =
-                        type_check(term, global_env, self, StubHost::<(), (), _>::new())?;
+                    type_check(term, global_env, self, StubHost::<(), (), _>::new())?;
                     self.update_state(file_id, EntryState::Typechecking);
-                    self.wildcards.insert(file_id, wildcards);
                 }
 
                 if let Some(imports) = self.imports.get(&file_id).cloned() {
@@ -474,7 +454,7 @@ impl Cache {
                     let CachedTerm {
                         term, parse_errs, ..
                     } = self.terms.remove(&file_id).unwrap();
-                    let term = transform::transform(term, self.wildcards.get(&file_id))?;
+                    let term = transform::transform(term)?;
                     self.terms.insert(
                         file_id,
                         CachedTerm {
@@ -525,7 +505,6 @@ impl Cache {
                     state,
                     parse_errs,
                 } = self.terms.remove(&file_id).unwrap();
-                let wildcards = self.wildcards.get(&file_id);
 
                 if state < EntryState::Transforming {
                     let pos = term.pos;
@@ -534,7 +513,7 @@ impl Cache {
                         Term::Record(ref mut map, _) => {
                             let map_res: Result<_, UnboundTypeVariableError> = std::mem::take(map)
                                 .into_iter()
-                                .map(|(id, t)| Ok((id, transform::transform(t, wildcards)?)))
+                                .map(|(id, t)| Ok((id, transform::transform(t)?)))
                                 .collect();
                             *map = map_res.map_err(|err| {
                                 CacheError::Error(ImportError::ParseErrors(err.into(), pos))
@@ -543,17 +522,14 @@ impl Cache {
                         Term::RecRecord(ref mut map, ref mut dyn_fields, ..) => {
                             let map_res: Result<_, UnboundTypeVariableError> = std::mem::take(map)
                                 .into_iter()
-                                .map(|(id, t)| Ok((id, transform::transform(t, wildcards)?)))
+                                .map(|(id, t)| Ok((id, transform::transform(t)?)))
                                 .collect();
 
                             let dyn_fields_res: Result<_, UnboundTypeVariableError> =
                                 std::mem::take(dyn_fields)
                                     .into_iter()
                                     .map(|(id_t, t)| {
-                                        Ok((
-                                            transform::transform(id_t, wildcards)?,
-                                            transform::transform(t, wildcards)?,
-                                        ))
+                                        Ok((transform::transform(id_t)?, transform::transform(t)?))
                                     })
                                     .collect();
 
@@ -643,9 +619,13 @@ impl Cache {
     ) -> Result<CacheOp<()>, Error> {
         let mut result = CacheOp::Cached(());
 
-        if self.parse(file_id)? == CacheOp::Done(()) {
-            result = CacheOp::Done(());
-        }
+        match self.parse(file_id)? {
+            CacheOp::Done(e) | CacheOp::Cached(e) if !e.no_errors() => return Err(e.into()),
+            CacheOp::Done(_) => {
+                result = CacheOp::Done(());
+            }
+            _ => {}
+        };
 
         let import_res = self.resolve_imports(file_id).map_err(|cache_err| {
             cache_err.unwrap_error(
@@ -698,10 +678,8 @@ impl Cache {
             return Err(Error::ParseErrors(errs));
         }
         let (term, pending) = import_resolution::resolve_imports(term, self)?;
-        let (TypeCheckingOutput { wildcards, .. }, _) =
-            type_check(&term, global_env, self, StubHost::<(), (), _>::new())?;
-        let term = transform::transform(term, Some(&wildcards))
-            .map_err(|err| Error::ParseErrors(err.into()))?;
+        type_check(&term, global_env, self, StubHost::<(), (), _>::new())?;
+        let term = transform::transform(term).map_err(|err| Error::ParseErrors(err.into()))?;
         Ok((term, pending))
     }
 
@@ -805,7 +783,10 @@ impl Cache {
             .collect();
 
         for file_id in file_ids.iter() {
-            self.parse(*file_id)?;
+            let errs = self.parse(*file_id)?.inner();
+            if !errs.no_errors() {
+                return Err(errs.into());
+            }
         }
         self.stdlib_ids.replace(file_ids);
         Ok(CacheOp::Done(()))
diff --git a/src/eval/merge.rs b/src/eval/merge.rs
index 5c511fde..f31b2f30 100644
--- a/src/eval/merge.rs
+++ b/src/eval/merge.rs
@@ -223,7 +223,7 @@ pub fn merge(
                 ))
             }
         }
-        (Term::Array(arr1, _attrs1), Term::Array(arr2, _attrs2))
+        (Term::Array(arr1, attrs1), Term::Array(arr2, _attrs2))
             if arr1.is_empty() && arr2.is_empty() =>
         {
             Ok(Closure::atomic_closure(RichTerm::new(
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index a9a0f8f7..77a18131 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -687,190 +687,204 @@ fn update_thunks(stack: &mut Stack, closure: &Closure) {
 
 /// Recursively substitute each variable occurrence of a term for its value in the environment.
 pub fn subst(rt: RichTerm, global_env: &Environment, env: &Environment) -> RichTerm {
-    let RichTerm { term, pos } = rt;
-
-    match term.into_owned() {
-        Term::Var(id) => env
-            .get(&id)
-            .or_else(|| global_env.get(&id))
-            .map(|thunk| {
-                let closure = thunk.get_owned();
-                subst(closure.body, global_env, &closure.env)
-            })
-            .unwrap_or_else(|| RichTerm::new(Term::Var(id), pos)),
-        v @ Term::Null
-        | v @ Term::ParseError
-        | v @ Term::Bool(_)
-        | v @ Term::Num(_)
-        | v @ Term::Str(_)
-        // Do not substitute under lambdas: mutually recursive function could cause an infinite
-        // loop. Although avoidable, this requires some care and is not currently needed.
-        | v @ Term::Fun(..)
-        | v @ Term::Lbl(_)
-        | v @ Term::Sym(_)
-        | v @ Term::Enum(_)
-        | v @ Term::Import(_)
-        | v @ Term::ResolvedImport(_) => RichTerm::new(v, pos),
-        Term::Let(id, t1, t2, attrs) => {
-            let t1 = subst(t1, global_env, env);
-            let t2 = subst(t2, global_env, env);
-
-            RichTerm::new(Term::Let(id, t1, t2, attrs), pos)
-        }
-        p @ Term::LetPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
-        p @ Term::FunPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
-        Term::App(t1, t2) => {
-            let t1 = subst(t1, global_env, env);
-            let t2 = subst(t2, global_env, env);
-
-            RichTerm::new(Term::App(t1, t2), pos)
-        }
-        Term::Switch(t, cases, default) => {
-            let default =
-                default.map(|d| subst(d, global_env, env));
-            let cases = cases
-                .into_iter()
-                .map(|(id, t)| {
-                    (
-                        id,
-                        subst(t, global_env, env),
-                    )
+    use std::borrow::Cow;
+    use std::collections::HashSet;
+
+    // Maintain an additional set of variables bound by abstractions (`fun x => ..`), that must not
+    // be substituted.
+    fn subst_(
+        rt: RichTerm,
+        global_env: &Environment,
+        env: &Environment,
+        bound: Cow<HashSet<Ident>>,
+    ) -> RichTerm {
+        let RichTerm { term, pos } = rt;
+        match term.into_owned() {
+            Term::Var(id) if !bound.as_ref().contains(&id) => env
+                .get(&id)
+                .or_else(|| global_env.get(&id))
+                .map(|thunk| {
+                    let closure = thunk.get_owned();
+                    subst_(closure.body, global_env, &closure.env, bound)
                 })
-                .collect();
-            let t = subst(t, global_env, env);
+                .unwrap_or_else(|| RichTerm::new(Term::Var(id), pos)),
+            v @ Term::Null
+            | v @ Term::ParseError
+            | v @ Term::Bool(_)
+            | v @ Term::Num(_)
+            | v @ Term::Str(_)
+            // Do not substitute under lambdas: mutually recursive function could cause an infinite
+            // loop. Although avoidable, this requires some care and is not currently needed.
+            | v @ Term::Fun(..)
+            | v @ Term::Lbl(_)
+            | v @ Term::Sym(_)
+            | v @ Term::Var(_)
+            | v @ Term::Enum(_)
+            | v @ Term::Import(_)
+            | v @ Term::ResolvedImport(_) => RichTerm::new(v, pos),
+            Term::Let(id, t1, t2, attrs) => {
+                let t1 = subst_(t1, global_env, env, Cow::Borrowed(bound.as_ref()));
+                let t2 = subst_(t2, global_env, env, bound);
+
+                RichTerm::new(Term::Let(id, t1, t2, attrs), pos)
+            }
+            p @ Term::LetPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
+            p @ Term::FunPattern(..) => panic!("Pattern {:?} has not been transformed before evaluation", p),
+            Term::App(t1, t2) => {
+                let t1 = subst_(t1, global_env, env, Cow::Borrowed(bound.as_ref()));
+                let t2 = subst_(t2, global_env, env, bound);
 
-            RichTerm::new(Term::Switch(t, cases, default), pos)
-        }
-        Term::Op1(op, t) => {
-            let t = subst(t, global_env, env);
+                RichTerm::new(Term::App(t1, t2), pos)
+            }
+            Term::Switch(t, cases, default) => {
+                let default =
+                    default.map(|d| subst_(d, global_env, env, Cow::Borrowed(bound.as_ref())));
+                let cases = cases
+                    .into_iter()
+                    .map(|(id, t)| {
+                        (
+                            id,
+                            subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                        )
+                    })
+                    .collect();
+                let t = subst_(t, global_env, env, bound);
 
-            RichTerm::new(Term::Op1(op, t), pos)
-        }
-        Term::Op2(op, t1, t2) => {
-            let t1 = subst(t1, global_env, env);
-            let t2 = subst(t2, global_env, env);
+                RichTerm::new(Term::Switch(t, cases, default), pos)
+            }
+            Term::Op1(op, t) => {
+                let t = subst_(t, global_env, env, bound);
 
-            RichTerm::new(Term::Op2(op, t1, t2), pos)
-        }
-        Term::OpN(op, ts) => {
-            let ts = ts
-                .into_iter()
-                .map(|t| subst(t, global_env, env))
-                .collect();
+                RichTerm::new(Term::Op1(op, t), pos)
+            }
+            Term::Op2(op, t1, t2) => {
+                let t1 = subst_(t1, global_env, env, Cow::Borrowed(bound.as_ref()));
+                let t2 = subst_(t2, global_env, env, bound);
 
-            RichTerm::new(Term::OpN(op, ts), pos)
-        }
-        Term::Wrapped(i, t) => {
-            let t = subst(t, global_env, env);
+                RichTerm::new(Term::Op2(op, t1, t2), pos)
+            }
+            Term::OpN(op, ts) => {
+                let ts = ts
+                    .into_iter()
+                    .map(|t| subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())))
+                    .collect();
 
-            RichTerm::new(Term::Wrapped(i, t), pos)
-        }
-        Term::Record(map, attrs) => {
-            let map = map
-                .into_iter()
-                .map(|(id, t)| {
-                    (
-                        id,
-                        subst(t, global_env, env),
-                    )
-                })
-                .collect();
+                RichTerm::new(Term::OpN(op, ts), pos)
+            }
+            Term::Wrapped(i, t) => {
+                let t = subst_(t, global_env, env, bound);
 
-            RichTerm::new(Term::Record(map, attrs), pos)
-        }
-        Term::RecRecord(map, dyn_fields, attrs, deps) => {
-            let map = map
-                .into_iter()
-                .map(|(id, t)| {
-                    (
-                        id,
-                        subst(t, global_env, env),
-                    )
-                })
-                .collect();
+                RichTerm::new(Term::Wrapped(i, t), pos)
+            }
+            Term::Record(map, attrs) => {
+                let map = map
+                    .into_iter()
+                    .map(|(id, t)| {
+                        (
+                            id,
+                            subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                        )
+                    })
+                    .collect();
 
-            let dyn_fields = dyn_fields
-                .into_iter()
-                .map(|(id_t, t)| {
-                    (
-                        subst(id_t, global_env, env),
-                        subst(t, global_env, env),
-                    )
-                })
-                .collect();
+                RichTerm::new(Term::Record(map, attrs), pos)
+            }
+            Term::RecRecord(map, dyn_fields, attrs, deps) => {
+                let map = map
+                    .into_iter()
+                    .map(|(id, t)| {
+                        (
+                            id,
+                            subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                        )
+                    })
+                    .collect();
 
-            RichTerm::new(Term::RecRecord(map, dyn_fields, attrs, deps), pos)
-        }
-        Term::Array(ts, attrs) => {
-            let ts = ts
-                .into_iter()
-                .map(|t| subst(t, global_env, env))
-                .collect();
+                let dyn_fields = dyn_fields
+                    .into_iter()
+                    .map(|(id_t, t)| {
+                        (
+                            subst_(id_t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                            subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                        )
+                    })
+                    .collect();
 
-            RichTerm::new(Term::Array(ts, attrs), pos)
-        }
-        Term::StrChunks(chunks) => {
-            let chunks = chunks
-                .into_iter()
-                .map(|chunk| match chunk {
-                    chunk @ StrChunk::Literal(_) => chunk,
-                    StrChunk::Expr(t, indent) => StrChunk::Expr(
-                        subst(t, global_env, env),
-                        indent,
-                    ),
-                })
-                .collect();
+                RichTerm::new(Term::RecRecord(map, dyn_fields, attrs, deps), pos)
+            }
+            Term::Array(ts, attrs) => {
+                let ts = ts
+                    .into_iter()
+                    .map(|t| subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())))
+                    .collect();
 
-            RichTerm::new(Term::StrChunks(chunks), pos)
-        }
-        Term::MetaValue(meta) => {
-            // Currently, there is no interest in replacing variables inside contracts, thus we
-            // limit the work of `subst`. If this is needed at some point, just uncomment the
-            // following code.
-
-            // let contracts: Vec<_> = meta
-            //     .contracts
-            //     .into_iter()
-            //     .map(|ctr| {
-            //         let types = match ctr.types {
-            //             Types(AbsType::Flat(t)) => Types(AbsType::Flat(subst(
-            //                 t,
-            //                 global_env,
-            //                 env,
-            //                 Cow::Borrowed(bound.as_ref()),
-            //             ))),
-            //             ty => ty,
-            //         };
-            //
-            //         Contract { types, ..ctr }
-            //     })
-            //     .collect();
-            //
-            // let types = meta.types.map(|ctr| {
-            //     let types = match ctr.types {
-            //         Types(AbsType::Flat(t)) => Types(AbsType::Flat(subst(
-            //             t,
-            //             global_env,
-            //             env,
-            //             Cow::Borrowed(bound.as_ref()),
-            //         ))),
-            //         ty => ty,
-            //     };
-            //
-            //     Contract { types, ..ctr }
-            // });
-
-            let value = meta.value.map(|t| subst(t, global_env, env));
-
-            let meta = MetaValue {
-                doc: meta.doc,
-                value,
-                ..meta
-            };
-
-            RichTerm::new(Term::MetaValue(meta), pos)
+                RichTerm::new(Term::Array(ts, attrs), pos)
+            }
+            Term::StrChunks(chunks) => {
+                let chunks = chunks
+                    .into_iter()
+                    .map(|chunk| match chunk {
+                        chunk @ StrChunk::Literal(_) => chunk,
+                        StrChunk::Expr(t, indent) => StrChunk::Expr(
+                            subst_(t, global_env, env, Cow::Borrowed(bound.as_ref())),
+                            indent,
+                        ),
+                    })
+                    .collect();
+
+                RichTerm::new(Term::StrChunks(chunks), pos)
+            }
+            Term::MetaValue(meta) => {
+                // Currently, there is no interest in replacing variables inside contracts, thus we
+                // limit the work of `subst`. If this is needed at some point, just uncomment the
+                // following code.
+
+                // let contracts: Vec<_> = meta
+                //     .contracts
+                //     .into_iter()
+                //     .map(|ctr| {
+                //         let types = match ctr.types {
+                //             Types(AbsType::Flat(t)) => Types(AbsType::Flat(subst_(
+                //                 t,
+                //                 global_env,
+                //                 env,
+                //                 Cow::Borrowed(bound.as_ref()),
+                //             ))),
+                //             ty => ty,
+                //         };
+                //
+                //         Contract { types, ..ctr }
+                //     })
+                //     .collect();
+                //
+                // let types = meta.types.map(|ctr| {
+                //     let types = match ctr.types {
+                //         Types(AbsType::Flat(t)) => Types(AbsType::Flat(subst_(
+                //             t,
+                //             global_env,
+                //             env,
+                //             Cow::Borrowed(bound.as_ref()),
+                //         ))),
+                //         ty => ty,
+                //     };
+                //
+                //     Contract { types, ..ctr }
+                // });
+
+                let value = meta.value.map(|t| subst_(t, global_env, env, bound));
+
+                let meta = MetaValue {
+                    doc: meta.doc,
+                    value,
+                    ..meta
+                };
+
+                RichTerm::new(Term::MetaValue(meta), pos)
+            }
         }
     }
+
+    subst_(rt, global_env, env, Cow::Owned(HashSet::new()))
 }
 
 #[cfg(test)]
diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop
index 16093a2c..2e2cd478 100644
--- a/src/grammar.lalrpop
+++ b/src/grammar.lalrpop
@@ -66,11 +66,7 @@ use crate::{
     label::Label,
 };
 
-grammar<'input, 'err, 'wcard>(
-    src_id: FileId,
-    errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, ParseError>>,
-    next_wildcard_id: &'wcard mut usize,
-);
+grammar<'input, 'err>(src_id: FileId, errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, ParseError>>);
 
 WithPos<Rule>: Rule = <l: @L> <t: Rule> <r: @R> => t.with_pos(mk_pos(src_id, l, r));
 
@@ -766,11 +762,6 @@ TypeAtom: Types = {
         Types(AbsType::Enum(Box::new(ty)))
     },
     "{" "_" ":" <Types> "}" => Types(AbsType::DynRecord(Box::new(<>))),
-    "_" => {
-        let id = *next_wildcard_id;
-        *next_wildcard_id += 1;
-        Types(AbsType::Wildcard(id))
-    },
 }
 
 extern {
diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs
index 17e9e857..54a9ef2d 100644
--- a/src/parser/lexer.rs
+++ b/src/parser/lexer.rs
@@ -40,7 +40,7 @@ pub enum NormalToken<'input> {
     #[error]
     Error,
 
-    #[regex("_?[a-zA-Z][_a-zA-Z0-9-']*")]
+    #[regex("_?[a-zA-Z][_a-zA-Z0-9-]*")]
     Identifier(&'input str),
     #[regex("[0-9]*\\.?[0-9]+", |lex| lex.slice().parse())]
     NumLiteral(f64),
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 7483a48e..5f311556 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -37,9 +37,8 @@ impl grammar::ExtendedTermParser {
         lexer: lexer::Lexer,
     ) -> Result<(ExtendedTerm, ParseErrors), ParseError> {
         let mut parse_errors = Vec::new();
-        let mut next_wildcard_id = 0;
         let result = self
-            .parse(file_id, &mut parse_errors, &mut next_wildcard_id, lexer)
+            .parse(file_id, &mut parse_errors, lexer)
             .map_err(|err| ParseError::from_lalrpop(err, file_id));
 
         let parse_errors = ParseErrors::from_recoverable(parse_errors, file_id);
@@ -63,18 +62,14 @@ impl grammar::ExtendedTermParser {
 }
 
 impl grammar::TermParser {
-    /// Parse a term from a token stream in an error tolerant way: parse errors are accumulated and
-    /// returned, instead of returning an error. The `Err` variant corresponds to a non-recoverable
-    /// error.
-    pub fn parse_term_lax(
+    pub fn parse_term_tolerant(
         &self,
         file_id: FileId,
         lexer: lexer::Lexer,
     ) -> Result<(RichTerm, ParseErrors), ParseError> {
         let mut parse_errors = Vec::new();
-        let mut wildcard_id = 0;
         let result = self
-            .parse(file_id, &mut parse_errors, &mut wildcard_id, lexer)
+            .parse(file_id, &mut parse_errors, lexer)
             .map_err(|err| ParseError::from_lalrpop(err, file_id));
 
         let parse_errors = ParseErrors::from_recoverable(parse_errors, file_id);
@@ -89,7 +84,7 @@ impl grammar::TermParser {
         file_id: FileId,
         lexer: lexer::Lexer,
     ) -> Result<RichTerm, ParseErrors> {
-        match self.parse_term_lax(file_id, lexer) {
+        match self.parse_term_tolerant(file_id, lexer) {
             Ok((t, e)) if e.no_errors() => Ok(t),
             Ok((_, e)) => Err(e),
             Err(e) => Err(e.into()),
diff --git a/src/parser/uniterm.rs b/src/parser/uniterm.rs
index 7e5c4f0a..e09d9951 100644
--- a/src/parser/uniterm.rs
+++ b/src/parser/uniterm.rs
@@ -352,8 +352,7 @@ pub fn fix_type_vars(ty: &mut Types) {
             | AbsType::Str()
             | AbsType::Sym()
             | AbsType::Flat(_)
-            | AbsType::RowEmpty()
-            | AbsType::Wildcard(_) => (),
+            | AbsType::RowEmpty() => (),
             AbsType::Arrow(ref mut s, ref mut t) => {
                 fix_type_vars_aux(s.as_mut(), Cow::Borrowed(bound_vars.as_ref()));
                 fix_type_vars_aux(t.as_mut(), bound_vars);
diff --git a/src/pretty.rs b/src/pretty.rs
index 176d24c4..db252420 100644
--- a/src/pretty.rs
+++ b/src/pretty.rs
@@ -782,7 +782,6 @@ where
                     .append(allocator.space())
                     .append(codom.pretty(allocator)),
             },
-            Wildcard(_) => allocator.text("_"),
         }
     }
 }
diff --git a/src/program.rs b/src/program.rs
index 652736ae..e90cc3f8 100644
--- a/src/program.rs
+++ b/src/program.rs
@@ -150,7 +150,7 @@ impl Program {
 
         let rt = cache.parse_nocache(*main_id)?.0;
         let rt = if apply_transforms {
-            crate::transform::transform(rt, None).unwrap()
+            crate::transform::transform(rt).unwrap()
         } else {
             rt
         };
@@ -369,7 +369,6 @@ mod tests {
     use crate::parser::{grammar, lexer};
     use crate::position::TermPos;
     use crate::term::SharedTerm;
-    use assert_matches::assert_matches;
     use codespan::Files;
     use std::io::Cursor;
 
@@ -395,18 +394,6 @@ mod tests {
         p.eval_full()
     }
 
-    fn typecheck(s: &str) -> Result<(), Error> {
-        let src = Cursor::new(s);
-
-        let mut p = Program::new_from_source(src, "<test>").map_err(|io_err| {
-            Error::EvalError(EvalError::Other(
-                format!("IO error: {}", io_err),
-                TermPos::None,
-            ))
-        })?;
-        p.typecheck()
-    }
-
     #[test]
     fn evaluation_full() {
         use crate::mk_record;
@@ -450,14 +437,4 @@ mod tests {
         // that this test fails.
         eval_full("{y = fun x => x, x = fun y => y}").unwrap();
     }
-
-    #[test]
-    // Regression test for issue 715 (https://github.com/tweag/nickel/issues/715)
-    // Check that program::typecheck() fail on parse error
-    fn typecheck_invalid_input() {
-        assert_matches!(
-            typecheck("{foo = 1 + `, bar : Str = \"a\"}"),
-            Err(Error::ParseErrors(_))
-        );
-    }
 }
diff --git a/src/repl/mod.rs b/src/repl/mod.rs
index 49522d35..12d2aa6e 100644
--- a/src/repl/mod.rs
+++ b/src/repl/mod.rs
@@ -12,7 +12,6 @@ use crate::identifier::Ident;
 use crate::parser::{grammar, lexer, ExtendedTerm};
 use crate::term::{RichTerm, Term};
 use crate::transform::import_resolution;
-use crate::typecheck::TypeCheckingOutput;
 use crate::types::Types;
 use crate::{eval, transform, typecheck};
 use codespan::FileId;
@@ -135,8 +134,7 @@ impl ReplImpl {
                 repl_impl.cache.resolve_imports(*id).unwrap();
             }
 
-            let TypeCheckingOutput { wildcards, .. } =
-                typecheck::type_check_in_env(&t, &repl_impl.env.type_env, &repl_impl.cache)?;
+            typecheck::type_check_in_env(&t, &repl_impl.env.type_env, &repl_impl.cache)?;
 
             if let Some(id) = id {
                 typecheck::Envs::env_add(
@@ -156,8 +154,7 @@ impl ReplImpl {
                     })?;
             }
 
-            let t = transform::transform(t, Some(&wildcards))
-                .map_err(|err| Error::ParseErrors(err.into()))?;
+            let t = transform::transform(t).map_err(|err| Error::ParseErrors(err.into()))?;
             for id in &pending {
                 repl_impl
                     .cache
@@ -233,21 +230,7 @@ impl Repl for ReplImpl {
         for id in &pending {
             self.cache.resolve_imports(*id).unwrap();
         }
-        let TypeCheckingOutput { wildcards, .. } =
-            typecheck::type_check_in_env(&term, &self.env.type_env, &self.cache)?;
-        // Substitute the wildcard types for their inferred types
-        // We need to `traverse` the term, in case the type depends on inner terms that also contain wildcards
-        let term = term
-            .traverse(
-                &mut |rt: RichTerm, _| -> Result<RichTerm, std::convert::Infallible> {
-                    Ok(transform::substitute_wildcards::transform_one(
-                        rt, &wildcards,
-                    ))
-                },
-                &mut (),
-                crate::term::TraverseOrder::TopDown,
-            )
-            .unwrap();
+        typecheck::type_check_in_env(&term, &self.env.type_env, &self.cache)?;
 
         Ok(typecheck::apparent_type(
             term.as_ref(),
diff --git a/src/repl/query_print.rs b/src/repl/query_print.rs
index 5fe43348..cc6b5b6a 100644
--- a/src/repl/query_print.rs
+++ b/src/repl/query_print.rs
@@ -65,12 +65,6 @@ impl MarkdownRenderer {
 fn termimad_to_io(err: termimad::Error) -> io::Error {
     match err {
         termimad::Error::IO(err) => err,
-        // Not an IO error per se, but creating a new error type and chaning the signatures of the
-        // query printer functions just for this variant that is specific to the termimad backend
-        // doesn't seem to worth it.
-        termimad::Error::InsufficientWidth(err) => {
-            io::Error::new(io::ErrorKind::Other, format!("{}", err))
-        }
     }
 }
 
diff --git a/src/transform/free_vars.rs b/src/transform/free_vars.rs
index 99bd9d94..1a69031f 100644
--- a/src/transform/free_vars.rs
+++ b/src/transform/free_vars.rs
@@ -178,8 +178,7 @@ fn collect_type_free_vars(ty: &mut Types, set: &mut HashSet<Ident>) {
         | AbsType::Str()
         | AbsType::Sym()
         | AbsType::Var(_)
-        | AbsType::RowEmpty()
-        | AbsType::Wildcard(_) => (),
+        | AbsType::RowEmpty() => (),
         AbsType::Forall(_, ty)
         | AbsType::Enum(ty)
         | AbsType::StaticRecord(ty)
diff --git a/src/transform/mod.rs b/src/transform/mod.rs
index 0e5e90ef..bc3c3fad 100644
--- a/src/transform/mod.rs
+++ b/src/transform/mod.rs
@@ -4,7 +4,6 @@ use crate::{
     eval::{lazy::Thunk, Closure, Environment, IdentKind},
     identifier::Ident,
     term::{Contract, RichTerm, Term, TraverseOrder},
-    typecheck::Wildcards,
     types::{AbsType, Types, UnboundTypeVariableError},
 };
 
@@ -17,7 +16,6 @@ pub mod desugar_destructuring;
 pub mod free_vars;
 pub mod import_resolution;
 pub mod share_normal_form;
-pub mod substitute_wildcards;
 
 /// Apply all program transformations, excepted import resolution that is currently performed
 /// earlier, as it needs to be done before typechecking.
@@ -25,25 +23,15 @@ pub mod substitute_wildcards;
 /// Do not perform transformations on the imported files. If needed, either do it yourself using
 /// pending imports returned by [`resolve_imports`][import_resolution::resolve_imports] or use the
 /// [cache][crate::cache::Cache].
-pub fn transform(
-    mut rt: RichTerm,
-    wildcards: Option<&Wildcards>,
-) -> Result<RichTerm, UnboundTypeVariableError> {
+pub fn transform(mut rt: RichTerm) -> Result<RichTerm, UnboundTypeVariableError> {
     free_vars::transform(&mut rt);
-    transform_no_free_vars(rt, wildcards)
+    transform_no_free_vars(rt)
 }
 
 /// Same as [`transform`], but doesn't apply the free vars transformation.
-pub fn transform_no_free_vars(
-    rt: RichTerm,
-    wildcards: Option<&Wildcards>,
-) -> Result<RichTerm, UnboundTypeVariableError> {
+pub fn transform_no_free_vars(rt: RichTerm) -> Result<RichTerm, UnboundTypeVariableError> {
     let rt = rt.traverse(
-        &mut |mut rt: RichTerm, _| -> Result<RichTerm, UnboundTypeVariableError> {
-            // Start by substituting any wildcard with its inferred type
-            if let Some(wildcards) = wildcards {
-                rt = substitute_wildcards::transform_one(rt, wildcards);
-            }
+        &mut |rt: RichTerm, _| -> Result<RichTerm, UnboundTypeVariableError> {
             // before anything, we have to desugar the syntax
             let rt = desugar_destructuring::transform_one(rt);
             // We need to do contract generation before wrapping stuff in variables
diff --git a/src/transform/substitute_wildcards.rs b/src/transform/substitute_wildcards.rs
deleted file mode 100644
index 9a3eb82b..00000000
--- a/src/transform/substitute_wildcards.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-//! Substitute wildcard types with their inferred type.
-//!
-//! During type checking, wildcard types are treated as type variables that may end up unified
-//! with a concrete type.  If this is the case, this pass will substitute these wildcards with
-//! the type inferred during type checking.  Otherwise, wildcards will be substituted with
-//! `Dyn`.
-use std::{convert::Infallible, rc::Rc};
-
-use crate::{
-    label::Label,
-    match_sharedterm,
-    term::{Contract, MetaValue, RichTerm, Term, TraverseOrder},
-    typecheck::Wildcards,
-    types::{AbsType, Types},
-};
-
-/// If the top-level node of the AST is a meta-value with a wildcard type annotation, replace
-/// both the type annotation and the label's type with the inferred type.
-pub fn transform_one(rt: RichTerm, wildcards: &Wildcards) -> RichTerm {
-    let pos = rt.pos;
-    match_sharedterm! {rt.term,
-        with {
-            Term::MetaValue(meta @ MetaValue {
-                types: Some(_),
-                ..
-            }) => {
-                let mut meta = meta;
-                let Contract { types, label } = meta.types.take().unwrap();  // Safe, we know there's a type
-
-                // Replace the type annotation and the blame label
-                let types = substitute_wildcards_recursively(types, wildcards);
-                let label_types = substitute_wildcards_recursively(label.types.as_ref().clone(), wildcards);
-
-                let label = Label {
-                    types: Rc::new(label_types),
-                    ..label
-                };
-                meta.types = Some(Contract { types, label });
-
-                RichTerm::new(Term::MetaValue(meta), pos)
-            }
-        } else rt
-    }
-}
-
-/// Get the inferred type for a wildcard, or Dyn if no type was inferred.
-fn get_wildcard_type(wildcards: &Wildcards, id: usize) -> Types {
-    wildcards.get(id).cloned().unwrap_or(Types(AbsType::Dyn()))
-}
-
-/// Recursively substitutes wildcards for their inferred type inside a given type.
-fn substitute_wildcards_recursively(ty: Types, wildcards: &Wildcards) -> Types {
-    ty.traverse::<_, _, Infallible>(
-        &mut |ty, _| {
-            if let Types(AbsType::Wildcard(id)) = ty {
-                Ok(get_wildcard_type(wildcards, id))
-            } else {
-                Ok(ty)
-            }
-        },
-        &mut (),
-        TraverseOrder::TopDown,
-    )
-    .unwrap()
-}
diff --git a/src/typecheck/mod.rs b/src/typecheck/mod.rs
index 584341f0..7b184bc8 100644
--- a/src/typecheck/mod.rs
+++ b/src/typecheck/mod.rs
@@ -44,7 +44,7 @@ use crate::cache::ImportResolver;
 use crate::environment::Environment as GenericEnvironment;
 use crate::error::TypecheckError;
 use crate::identifier::Ident;
-use crate::term::{Contract, MetaValue, RichTerm, StrChunk, Term, TraverseOrder};
+use crate::term::{Contract, MetaValue, RichTerm, StrChunk, Term};
 use crate::types::{AbsType, Types};
 use crate::{mk_tyw_arrow, mk_tyw_enum, mk_tyw_enum_row, mk_tyw_record, mk_tyw_row};
 use std::collections::{HashMap, HashSet};
@@ -65,9 +65,6 @@ use operation::{get_bop_type, get_nop_type, get_uop_type};
 /// The typing environment.
 pub type Environment = GenericEnvironment<Ident, TypeWrapper>;
 
-/// Mapping from wildcard ID to inferred type
-pub type Wildcards = Vec<Types>;
-
 /// A structure holding the two typing environments, the global and the local.
 ///
 /// The global typing environment is constructed from the global term environment (see
@@ -178,16 +175,6 @@ pub struct State<'a> {
     ///
     /// Used for error reporting.
     names: &'a mut HashMap<usize, Ident>,
-    /// A mapping from wildcard ID to unification variable.
-    wildcard_vars: &'a mut Vec<TypeWrapper>,
-}
-
-/// The result of type checking a term.
-pub struct TypeCheckingOutput {
-    /// Inferred type of the term.
-    pub types: Types,
-    /// Inferred types of wildcards within the term.
-    pub wildcards: Wildcards,
 }
 
 /// Typecheck a term.
@@ -202,14 +189,13 @@ pub fn type_check<LL>(
     global_env: &Environment,
     resolver: &impl ImportResolver,
     mut linearizer: LL,
-) -> Result<(TypeCheckingOutput, LL::Completed), TypecheckError>
+) -> Result<(Types, LL::Completed), TypecheckError>
 where
     LL: Linearizer<CompletionExtra = (UnifTable, HashMap<usize, Ident>)>,
 {
     let (mut table, mut names) = (UnifTable::new(), HashMap::new());
     let mut building = Linearization::new(LL::Building::default());
     let ty = table.fresh_unif_var();
-    let mut wildcard_vars = vec![];
 
     {
         let mut state: State = State {
@@ -217,7 +203,6 @@ where
             table: &mut table,
             constr: &mut RowConstr::new(),
             names: &mut names,
-            wildcard_vars: &mut wildcard_vars,
         };
 
         type_check_(
@@ -231,10 +216,7 @@ where
         )?;
     }
 
-    let result = TypeCheckingOutput {
-        types: to_type(&table, ty),
-        wildcards: wildcard_vars_to_type(wildcard_vars, &table),
-    };
+    let result = to_type(&table, ty);
     let lin = linearizer.complete(building, (table, names)).into_inner();
 
     Ok((result, lin))
@@ -254,35 +236,25 @@ pub fn type_check_in_env(
     t: &RichTerm,
     global: &Environment,
     resolver: &dyn ImportResolver,
-) -> Result<TypeCheckingOutput, TypecheckError> {
-    let mut table = UnifTable::new();
-    let ty = table.fresh_unif_var();
-    let mut wildcard_vars = vec![];
-
-    {
-        let mut state: State = State {
-            resolver,
-            table: &mut table,
-            constr: &mut RowConstr::new(),
-            names: &mut HashMap::new(),
-            wildcard_vars: &mut wildcard_vars,
-        };
-
-        type_check_(
-            &mut state,
-            Envs::from_global(global),
-            &mut Linearization::new(()),
-            StubHost::<()>::new(),
-            false,
-            t,
-            ty.clone(),
-        )?;
-    }
-
-    Ok(TypeCheckingOutput {
-        types: to_type(&table, ty),
-        wildcards: wildcard_vars_to_type(wildcard_vars, &table),
-    })
+) -> Result<Types, TypecheckError> {
+    let mut state = State {
+        resolver,
+        table: &mut UnifTable::new(),
+        constr: &mut RowConstr::new(),
+        names: &mut HashMap::new(),
+    };
+    let ty = state.table.fresh_unif_var();
+    type_check_(
+        &mut state,
+        Envs::from_global(global),
+        &mut Linearization::new(()),
+        StubHost::<()>::new(),
+        false,
+        t,
+        ty.clone(),
+    )?;
+
+    Ok(to_type(state.table, ty))
 }
 
 /// Typecheck a term against a specific type.
@@ -420,14 +392,7 @@ fn type_check_<L: Linearizer>(
                 .map_err(|err| err.into_typecheck_err(state, rt.pos))
         }
         Term::Let(x, re, rt, attrs) => {
-            let ty_let = binding_type(
-                re.as_ref(),
-                &envs,
-                state.table,
-                state.wildcard_vars,
-                strict,
-                state.resolver,
-            );
+            let ty_let = binding_type(re.as_ref(), &envs, state.table, strict, state.resolver);
             if attrs.rec {
                 envs.insert(x.clone(), ty_let.clone());
             }
@@ -449,14 +414,7 @@ fn type_check_<L: Linearizer>(
             type_check_(state, envs, lin, linearizer, strict, rt, ty)
         }
         Term::LetPattern(x, pat, re, rt) => {
-            let ty_let = binding_type(
-                re.as_ref(),
-                &envs,
-                state.table,
-                state.wildcard_vars,
-                strict,
-                state.resolver,
-            );
+            let ty_let = binding_type(re.as_ref(), &envs, state.table, strict, state.resolver);
             type_check_(
                 state,
                 envs.clone(),
@@ -569,14 +527,7 @@ fn type_check_<L: Linearizer>(
             // Fields defined by interpolation are ignored.
             if let Term::RecRecord(..) = t.as_ref() {
                 for (id, rt) in stat_map {
-                    let tyw = binding_type(
-                        rt.as_ref(),
-                        &envs,
-                        state.table,
-                        state.wildcard_vars,
-                        strict,
-                        state.resolver,
-                    );
+                    let tyw = binding_type(rt.as_ref(), &envs, state.table, strict, state.resolver);
                     envs.insert(id.clone(), tyw.clone());
                     linearizer.retype_ident(lin, id, tyw);
                 }
@@ -772,44 +723,21 @@ fn type_check_<L: Linearizer>(
 ///       associated to `bound_exp`.
 /// As this function is always called in a context where an `ImportResolver` is present, expect
 /// it passed in arguments.
-///
-/// If the annotated type contains any wildcard:
-///     * in non strict mode, wildcards are assigned `Dyn`.
-///     * in strict mode, the wildcard is typechecked, and we return the unification variable
-///       corresponding to it.
 fn binding_type(
     t: &Term,
     envs: &Envs,
     table: &mut UnifTable,
-    wildcard_vars: &mut Vec<TypeWrapper>,
     strict: bool,
     resolver: &dyn ImportResolver,
 ) -> TypeWrapper {
     let ty_apt = apparent_type(t, Some(envs), Some(resolver));
 
     match ty_apt {
-        ApparentType::Annotated(ty) if strict => {
-            replace_wildcards_with_var(table, wildcard_vars, ty)
-        }
         ApparentType::Approximated(_) if strict => table.fresh_unif_var(),
         ty_apt => ty_apt.into(),
     }
 }
 
-/// Substitute wildcards in a type for their unification variable.
-fn replace_wildcards_with_var(
-    table: &mut UnifTable,
-    wildcard_vars: &mut Vec<TypeWrapper>,
-    ty: Types,
-) -> TypeWrapper {
-    match ty.0 {
-        AbsType::Wildcard(i) => get_wildcard_var(table, wildcard_vars, i),
-        _ => TypeWrapper::Concrete(
-            ty.0.map(|ty| Box::new(replace_wildcards_with_var(table, wildcard_vars, *ty))),
-        ),
-    }
-}
-
 /// Different kinds of apparent types (see [`apparent_type`]).
 ///
 /// Indicate the nature of an apparent type. In particular, when in strict mode, the typechecker
@@ -817,7 +745,6 @@ fn replace_wildcards_with_var(
 /// generating a fresh unification variable.  In non-strict mode, however, the approximation is the
 /// best we can do. This type allows the caller of `apparent_type` to determine which situation it
 /// is.
-#[derive(Debug)]
 pub enum ApparentType {
     /// The apparent type is given by a user-provided annotation, such as an `Assume`, a `Promise`,
     /// or a metavalue.
@@ -834,7 +761,6 @@ pub enum ApparentType {
 impl From<ApparentType> for Types {
     fn from(at: ApparentType) -> Self {
         match at {
-            ApparentType::Annotated(ty) if has_wildcards(&ty) => Types(AbsType::Dyn()),
             ApparentType::Annotated(ty)
             | ApparentType::Inferred(ty)
             | ApparentType::Approximated(ty) => ty,
@@ -846,9 +772,6 @@ impl From<ApparentType> for Types {
 impl From<ApparentType> for TypeWrapper {
     fn from(at: ApparentType) -> TypeWrapper {
         match at {
-            ApparentType::Annotated(ty) if has_wildcards(&ty) => {
-                TypeWrapper::Concrete(AbsType::Dyn())
-            }
             ApparentType::Annotated(ty)
             | ApparentType::Inferred(ty)
             | ApparentType::Approximated(ty) => ty.into(),
@@ -865,7 +788,7 @@ impl From<ApparentType> for TypeWrapper {
 ///
 /// The role of `apparent_type` is precisely to determine the type of `bound_exp`:
 /// - if `bound_exp` is annotated by an `Assume`, a `Promise` or a metavalue, return the
-///   user-provided type, unless that type is a wildcard.
+///   user-provided type.
 /// - if `bound_exp` is a constant (string, number, boolean or symbol) which type can be deduced
 ///   directly without unfolding the expression further, return the corresponding exact type.
 /// - if `bound_exp` is an array, return `Array Dyn`.
@@ -938,24 +861,6 @@ pub fn infer_type(t: &Term) -> TypeWrapper {
     }
 }
 
-/// Deeply check whether a type contains a wildcard.
-fn has_wildcards(ty: &Types) -> bool {
-    let mut has_wildcard = false;
-    ty.clone()
-        .traverse::<_, _, std::convert::Infallible>(
-            &mut |ty, has_wildcard| {
-                if ty.0.is_wildcard() {
-                    *has_wildcard = true;
-                }
-                Ok(ty)
-            },
-            &mut has_wildcard,
-            TraverseOrder::TopDown,
-        )
-        .unwrap();
-    has_wildcard
-}
-
 /// The types on which the unification algorithm operates, which may be either a concrete type, a
 /// type constant or a unification variable.
 #[derive(Clone, PartialEq, Debug)]
@@ -1028,7 +933,6 @@ impl TypeWrapper {
                 Concrete(AbsType::DynRecord(Box::new(def_ty.subst(id, to))))
             }
             Concrete(AbsType::Array(ty)) => Concrete(AbsType::Array(Box::new(ty.subst(id, to)))),
-            Concrete(AbsType::Wildcard(i)) => Concrete(AbsType::Wildcard(i)),
             Constant(x) => Constant(x),
             Ptr(x) => Ptr(x),
         }
@@ -1135,12 +1039,6 @@ pub fn unify_(
 
     // t1 and t2 are roots of the type
     match (t1, t2) {
-        // If either type is a wildcard, unify with the associated type var
-        (TypeWrapper::Concrete(AbsType::Wildcard(id)), ty2)
-        | (ty2, TypeWrapper::Concrete(AbsType::Wildcard(id))) => {
-            let ty1 = get_wildcard_var(state.table, state.wildcard_vars, id);
-            unify_(state, ty1, ty2)
-        }
         (TypeWrapper::Concrete(s1), TypeWrapper::Concrete(s2)) => match (s1, s2) {
             (AbsType::Dyn(), AbsType::Dyn()) => Ok(()),
             (AbsType::Num(), AbsType::Num()) => Ok(()),
@@ -1509,8 +1407,7 @@ fn constrain_var(state: &mut State, tyw: &TypeWrapper, p: usize) {
                 | AbsType::Sym()
                 | AbsType::Flat(_)
                 | AbsType::RowEmpty()
-                | AbsType::Var(_)
-                | AbsType::Wildcard(_) => (),
+                | AbsType::Var(_) => (),
                 AbsType::Array(tyw) => constrain_var_(state, HashSet::new(), tyw.as_ref(), p),
                 AbsType::RowExtend(id, tyw, rest) => {
                     constr.insert(id.clone());
@@ -1580,24 +1477,3 @@ pub fn constr_unify(
         Ok(())
     }
 }
-
-/// Get the typevar associated with a given wildcard ID.
-fn get_wildcard_var(
-    table: &mut UnifTable,
-    wildcard_vars: &mut Vec<TypeWrapper>,
-    id: usize,
-) -> TypeWrapper {
-    // If `id` is not in `wildcard_vars`, populate it with fresh vars up to `id`
-    if id >= wildcard_vars.len() {
-        wildcard_vars.extend((wildcard_vars.len()..=id).map(|_| table.fresh_unif_var()));
-    }
-    wildcard_vars[id].clone()
-}
-
-/// Convert a mapping from wildcard ID to type var, into a mapping from wildcard ID to concrete type.
-fn wildcard_vars_to_type(wildcard_vars: Vec<TypeWrapper>, table: &UnifTable) -> Wildcards {
-    wildcard_vars
-        .into_iter()
-        .map(|var| to_type(&table, var))
-        .collect()
-}
diff --git a/src/typecheck/operation.rs b/src/typecheck/operation.rs
index dd727248..572493b2 100644
--- a/src/typecheck/operation.rs
+++ b/src/typecheck/operation.rs
@@ -164,7 +164,7 @@ pub fn get_uop_type(
         // Str -> Num
         UnaryOp::StrLength() => (mk_typewrapper::str(), mk_typewrapper::num()),
         // Dyn -> Str
-        UnaryOp::ToStr() => (mk_typewrapper::dynamic(), mk_typewrapper::num()),
+        UnaryOp::ToStr() => (mk_typewrapper::dynamic(), mk_typewrapper::str()),
         // Str -> Num
         UnaryOp::NumFromStr() => (mk_typewrapper::str(), mk_typewrapper::num()),
         // Str -> < | Dyn>
diff --git a/src/types.rs b/src/types.rs
index 2bed8147..3ccc4f1f 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -100,8 +100,6 @@ pub enum AbsType<Ty> {
     DynRecord(Ty /*, Ty  Row */),
     /// A parametrized array.
     Array(Ty),
-    /// A type wildcard, wrapping an ID unique within a given file.
-    Wildcard(usize),
 }
 
 impl<Ty> AbsType<Ty> {
@@ -132,7 +130,6 @@ impl<Ty> AbsType<Ty> {
             AbsType::StaticRecord(t) => Ok(AbsType::StaticRecord(f(t)?)),
             AbsType::DynRecord(t) => Ok(AbsType::DynRecord(f(t)?)),
             AbsType::Array(t) => Ok(AbsType::Array(f(t)?)),
-            AbsType::Wildcard(i) => Ok(AbsType::Wildcard(i)),
         }
     }
 
@@ -151,10 +148,6 @@ impl<Ty> AbsType<Ty> {
             AbsType::RowExtend(..) | AbsType::RowEmpty() | AbsType::Dyn()
         )
     }
-
-    pub fn is_wildcard(&self) -> bool {
-        matches!(self, AbsType::Wildcard(_))
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -320,7 +313,6 @@ impl Types {
             AbsType::DynRecord(ref ty) => {
                 mk_app!(contract::dyn_record(), ty.subcontract(h, pol, sy)?)
             }
-            AbsType::Wildcard(_) => contract::dynamic(),
         };
 
         Ok(ctr)
@@ -400,8 +392,7 @@ impl Types {
             | AbsType::Sym()
             | AbsType::Var(_)
             | AbsType::RowEmpty()
-            | AbsType::Flat(_)
-            | AbsType::Wildcard(_) => Ok(ty.0),
+            | AbsType::Flat(_) => Ok(ty.0),
             AbsType::Forall(id, ty_inner) => (*ty_inner)
                 .traverse(f, state, order)
                 .map(|ty| AbsType::Forall(id, Box::new(ty))),
@@ -494,7 +485,6 @@ impl fmt::Display for Types {
                 AbsType::Arrow(_, _) => write!(f, "({}) -> {}", dom, codom),
                 _ => write!(f, "{} -> {}", dom, codom),
             },
-            AbsType::Wildcard(_) => write!(f, "_"),
         }
     }
 }
@@ -561,10 +551,5 @@ mod test {
         assert_format_eq("Num -> Array (Array Str) -> Num");
         assert_format_eq("Array (Num -> Num)");
         assert_format_eq("Array (Array (Array Dyn) -> Num)");
-
-        assert_format_eq("_");
-        assert_format_eq("_ -> _");
-        assert_format_eq("{x: _, y: Bool}");
-        assert_format_eq("{_: _}");
     }
 }
diff --git a/stdlib/string.ncl b/stdlib/string.ncl
index c392b3ea..73a785a8 100644
--- a/stdlib/string.ncl
+++ b/stdlib/string.ncl
@@ -75,6 +75,29 @@
       else
         %blame% (%tag% "not a string" l),
 
+    Ident
+    | doc m%"
+      Contract to enforce the value is a valid Nickel identifier. Can be used in conjunction with the record field
+      function (e.g. `has_field`).
+
+      For example:
+      ```nickel
+        record.has_field ("hello" | Ident) { hello = "hi!" } =>
+          true
+        record.has_field ("9" | Ident) { hello = "hi!" } =>
+          error (invalid enum tag)
+      ```
+      "%m
+    = fun l s =>
+      let pattern = m%"_?[a-zA-Z][_a-zA-Z0-9]*"%m in
+      if %is_str% s then
+        if %str_is_match% s pattern then
+            s
+          else
+            %blame% (%tag% "invalid enum tag" l)
+      else
+        %blame% (%tag% "not a string" l),
+
     NonEmpty
     | doc m%"
       Contract to enforce the value is a non-empty string.
@@ -388,8 +411,8 @@
       "%m
     = fun s => s == "true",
 
-    # to_enum | Str -> < | Dyn> = fun s => %enum_from_str% s,
-    to_enum | Str -> Dyn
+    # to_enum | Ident -> < | Dyn> = fun s => %enum_from_str% s,
+    to_enum | Ident -> Dyn
     | doc m%"
       Converts any string that represents an enum variant to that enum variant.
 


Test patch:
diff --git a/tests/pass.rs b/tests/pass.rs
index 4d0cfb66..91b51ec9 100644
--- a/tests/pass.rs
+++ b/tests/pass.rs
@@ -122,8 +122,3 @@ fn overriding() {
 fn recursive_let() {
     check_file("recursive_let.ncl");
 }
-
-#[test]
-fn quote_in_indentifier() {
-    check_file("quote_in_identifier.ncl")
-}
diff --git a/tests/pass/quote_in_identifier.ncl b/tests/pass/quote_in_identifier.ncl
deleted file mode 100644
index 241cc7ae..00000000
--- a/tests/pass/quote_in_identifier.ncl
+++ /dev/null
@@ -1,3 +0,0 @@
-let Assert = fun l x => x || %blame% l in
-
-let this-isn't-invalid = true in this-isn't-invalid | Assert
diff --git a/tests/pass/typechecking.ncl b/tests/pass/typechecking.ncl
index 3afe8a3c..9ffe18a8 100644
--- a/tests/pass/typechecking.ncl
+++ b/tests/pass/typechecking.ncl
@@ -192,11 +192,6 @@ let typecheck = [
   (string.split ".") : Str -> Array Str,
   (array.length [] == 0) : Bool,
   (array.map (fun x => x ++ "1") ["a", "b", "c"]) : Array Str,
-
-  # wildcards
-  ("hello" : _) : Str,
-  ((fun x => x + 1) : _ -> Num) : Num -> Num,
-  ({"foo" = 1} : {foo : _}) : {foo: Num}
 ] in
 
 true
diff --git a/tests/query.rs b/tests/query.rs
index 5596511c..ebdd4563 100644
--- a/tests/query.rs
+++ b/tests/query.rs
@@ -1,5 +1,5 @@
 use nickel_lang::program::Program;
-use nickel_lang::term::{MetaValue, SharedTerm, Term};
+use nickel_lang::term::{SharedTerm, Term};
 
 #[test]
 pub fn test_query_metadata_basic() {
@@ -31,57 +31,3 @@ pub fn test_query_metadata_from_func() {
         panic!();
     }
 }
-
-#[test]
-pub fn test_query_with_wildcard() {
-    /// Checks whether `lhs` and `rhs` both evaluate to terms with the same static type
-    fn assert_types_eq(lhs: &str, rhs: &str) {
-        let term1 = Program::new_from_source(lhs.as_bytes(), "regr_tests")
-            .unwrap()
-            .query(None)
-            .unwrap();
-        let term2 = Program::new_from_source(rhs.as_bytes(), "regr_tests")
-            .unwrap()
-            .query(None)
-            .unwrap();
-        if let (
-            Term::MetaValue(MetaValue {
-                types: Some(contract1),
-                ..
-            }),
-            Term::MetaValue(MetaValue {
-                types: Some(contract2),
-                ..
-            }),
-        ) = (term1, term2)
-        {
-            assert_eq!(contract1.types, contract2.types);
-            assert_eq!(
-                contract1.label.types.as_ref(),
-                contract2.label.types.as_ref()
-            );
-        } else {
-            panic!();
-        }
-    }
-
-    // Without wildcard, the result has no type annotation
-    let mut program = Program::new_from_source("10".as_bytes(), "regr_tests").unwrap();
-    let result = program.query(None).unwrap();
-    assert!(!matches!(result, Term::MetaValue(_)));
-
-    // With a wildcard, there is a type annotation, inferred to be Num
-    assert_types_eq("10 : _", "10 : Num");
-
-    // Wildcard infers record type
-    assert_types_eq(
-        r#"{foo: Str = "quux"} : _"#,
-        r#"{foo: Str = "quux"} : {foo: Str}"#,
-    );
-
-    // Wildcard infers function type, infers inside `let`
-    assert_types_eq(
-        r#"let f : _ = fun x => x + 1 in f"#,
-        r#"(fun x => x + 1) : Num -> Num"#,
-    );
-}
diff --git a/tests/typecheck_fail.rs b/tests/typecheck_fail.rs
index 2117dec3..08c62f34 100644
--- a/tests/typecheck_fail.rs
+++ b/tests/typecheck_fail.rs
@@ -4,12 +4,11 @@ use nickel_lang::cache::resolvers::DummyResolver;
 use nickel_lang::error::TypecheckError;
 use nickel_lang::parser::{grammar, lexer};
 use nickel_lang::term::RichTerm;
-use nickel_lang::typecheck::{type_check_in_env, Environment, TypeCheckingOutput};
-use nickel_lang::types::{AbsType, Types};
+use nickel_lang::typecheck::{type_check_in_env, Environment};
+use nickel_lang::types::Types;
 
 fn type_check(rt: &RichTerm) -> Result<Types, TypecheckError> {
     type_check_in_env(rt, &Environment::new(), &mut DummyResolver {})
-        .map(|TypeCheckingOutput { types, .. }| types)
 }
 
 fn type_check_expr(s: impl std::string::ToString) -> Result<Types, TypecheckError> {
@@ -231,7 +230,6 @@ fn piecewise_signature() {
         Err(TypecheckError::TypeMismatch(..))
     );
 }
-
 #[test]
 fn recursive_let() {
     assert_matches!(
@@ -239,42 +237,3 @@ fn recursive_let() {
         Err(TypecheckError::TypeMismatch(..))
     );
 }
-
-#[test]
-fn fails_only_with_wildcard() {
-    // Without a wildcard annotation, this type checks
-    assert_matches!(
-        type_check_expr("let head = fun l => %head% l in head 10"),
-        Ok(_)
-    );
-    // However, with one, we get a type error
-    assert_matches!(
-        type_check_expr("(let head = fun l => %head% l in (head 10)) : _"),
-        Err(TypecheckError::TypeMismatch(..))
-    );
-    // With an actual array, this passes
-    assert_matches!(
-        type_check_expr("(let head = fun l => %head% l in (head [10])) : _"),
-        Ok(_)
-    );
-}
-
-#[test]
-fn wildcards_apparent_type_is_dyn() {
-    // Wildcard-inferred types don't leak outside of the strict block.
-    // Therefore, even though the body of `g` could type check, `f` has type
-    // `Dyn`, exactly as if there were no wildcards, and the type checker
-    // rejects the expression.
-    assert_matches!(
-        type_check_expr(
-            r#"let f : _ -> _ = fun x => x + 1 in
-let g : Num = f 0 in
-g"#
-        ),
-        Err(TypecheckError::TypeMismatch(
-            Types(AbsType::Arrow(_, _)),
-            Types(AbsType::Dyn()),
-            _
-        ))
-    );
-}