packages feed

dhall 1.29.0 → 1.30.0

raw patch · 102 files changed

+1416/−507 lines, 102 filesdep +parser-combinatorsdep ~basedep ~directorydep ~lens-family-corePVP ok

version bump matches the API change (PVP)

Dependencies added: parser-combinators

Dependency ranges changed: base, directory, lens-family-core, template-haskell

API changes (from Hackage documentation)

- Dhall.Format: Check :: Input -> FormatMode
- Dhall.Format: Modify :: Input -> FormatMode
- Dhall.Format: [formatMode] :: Format -> FormatMode
- Dhall.Format: [inplace] :: FormatMode -> Input
- Dhall.Format: [path] :: FormatMode -> Input
- Dhall.Format: data FormatMode
- Dhall.Format: instance GHC.Exception.Type.Exception Dhall.Format.NotFormatted
- Dhall.Format: instance GHC.Show.Show Dhall.Format.NotFormatted
- Dhall.Main: [formatMode] :: Mode -> FormatMode
- Dhall.Main: [inplace] :: Mode -> Input
+ Dhall: substitutions :: (Functor f, HasEvaluateSettings s) => LensLike' f s (Substitutions Src Void)
+ Dhall.Format: [input] :: Format -> Input
+ Dhall.Format: [outputMode] :: Format -> OutputMode
+ Dhall.Import: [_substitutions] :: Status -> Substitutions Src Void
+ Dhall.Import: substitutions :: Functor f => LensLike' f Status (Substitutions Src Void)
+ Dhall.Lint: removeLetInLet :: Expr s a -> Maybe (Expr s a)
+ Dhall.Lint: replaceOptionalBuildFold :: Expr s a -> Maybe (Expr s a)
+ Dhall.Lint: replaceSaturatedOptionalFold :: Expr s a -> Maybe (Expr s a)
+ Dhall.Main: [outputMode] :: Mode -> OutputMode
+ Dhall.Substitution: empty :: Substitutions s a
+ Dhall.Substitution: substitute :: Expr s a -> Substitutions s a -> Expr s a
+ Dhall.Substitution: type Substitutions s a = Map Text (Expr s a)
+ Dhall.TH: MultipleConstructors :: Text -> code -> HaskellType code
+ Dhall.TH: SingleConstructor :: Text -> Text -> code -> HaskellType code
+ Dhall.TH: [code] :: HaskellType code -> code
+ Dhall.TH: [constructorName] :: HaskellType code -> Text
+ Dhall.TH: [typeName] :: HaskellType code -> Text
+ Dhall.TH: data HaskellType code
+ Dhall.TH: instance Data.Foldable.Foldable Dhall.TH.HaskellType
+ Dhall.TH: instance Data.Traversable.Traversable Dhall.TH.HaskellType
+ Dhall.TH: instance GHC.Base.Functor Dhall.TH.HaskellType
+ Dhall.TH: makeHaskellTypes :: [HaskellType Text] -> Q [Dec]
+ Dhall.TypeCheck: DuplicateFieldCannotBeMerged :: NonEmpty Text -> TypeMessage s a
+ Dhall.TypeCheck: FieldTypeCollision :: NonEmpty Text -> TypeMessage s a
+ Dhall.TypeCheck: InvalidDuplicateField :: Text -> Expr s a -> Expr s a -> TypeMessage s a
+ Dhall.Util: Check :: OutputMode
+ Dhall.Util: CheckFailed :: Text -> Text -> CheckFailed
+ Dhall.Util: Write :: OutputMode
+ Dhall.Util: [command] :: CheckFailed -> Text
+ Dhall.Util: [modified] :: CheckFailed -> Text
+ Dhall.Util: data CheckFailed
+ Dhall.Util: data OutputMode
+ Dhall.Util: instance GHC.Exception.Type.Exception Dhall.Util.CheckFailed
+ Dhall.Util: instance GHC.Show.Show Dhall.Util.CheckFailed
- Dhall.Core: Combine :: Expr s a -> Expr s a -> Expr s a
+ Dhall.Core: Combine :: Maybe Text -> Expr s a -> Expr s a -> Expr s a
- Dhall.Format: Format :: CharacterSet -> Censor -> FormatMode -> Format
+ Dhall.Format: Format :: CharacterSet -> Censor -> Input -> OutputMode -> Format
- Dhall.Freeze: freeze :: Input -> Scope -> Intent -> CharacterSet -> Censor -> IO ()
+ Dhall.Freeze: freeze :: OutputMode -> Input -> Scope -> Intent -> CharacterSet -> Censor -> IO ()
- Dhall.Import: Status :: NonEmpty Chained -> [Depends] -> Map Chained ImportSemantics -> Maybe Manager -> (URL -> StateT Status IO Text) -> Maybe (ReifiedNormalizer Void) -> Context (Expr Src Void) -> SemanticCacheMode -> Status
+ Dhall.Import: Status :: NonEmpty Chained -> [Depends] -> Map Chained ImportSemantics -> Maybe Manager -> (URL -> StateT Status IO Text) -> Substitutions Src Void -> Maybe (ReifiedNormalizer Void) -> Context (Expr Src Void) -> SemanticCacheMode -> Status
- Dhall.Main: Format :: FormatMode -> Mode
+ Dhall.Main: Format :: Input -> OutputMode -> Mode
- Dhall.Main: Freeze :: Input -> Bool -> Bool -> Mode
+ Dhall.Main: Freeze :: Input -> Bool -> Bool -> OutputMode -> Mode
- Dhall.Main: Lint :: Input -> Mode
+ Dhall.Main: Lint :: Input -> OutputMode -> Mode
- Dhall.TypeCheck: FieldCollision :: Text -> TypeMessage s a
+ Dhall.TypeCheck: FieldCollision :: NonEmpty Text -> TypeMessage s a

Files

CHANGELOG.md view
@@ -1,3 +1,44 @@+1.30.0++* [Supports version 14.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0)+* BREAKING CHANGE TO THE API: [Add `--check` flag to `dhall {lint,freeze}`](https://github.com/dhall-lang/dhall-haskell/pull/1636)+    * You can now use the `--check` flag to verify that a file has already been+      linted or frozen+    * This is a breaking change to the types used by the `Dhall.Format` module+* BREAKING CHANGE TO THE LANGUAGE: [Disallow `Natural` literals with leading zeros](https://github.com/dhall-lang/dhall-haskell/pull/1658)+    * Now a literal like `042` is no longer valid+    * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* BUG FIX: [Fix parsing of `Double` literal trailing whitespace](https://github.com/dhall-lang/dhall-haskell/pull/1647)+    * Certain expressions using `Double` literals would fail to parse, which this+      change fixes+* BUG FIX: [Use `DeriveLift` instead of GHC Generics to derive `Lift` ](https://github.com/dhall-lang/dhall-haskell/pull/1640)+    * This fixes a build failure on GHC 8.10+* [Drop support for GHC 7.10.3](https://github.com/dhall-lang/dhall-haskell/pull/1649)+    * GHC 8.0.2 is now the earliest supported version+* [Add support for dotted field syntax](https://github.com/dhall-lang/dhall-haskell/pull/1651)+    * `{ x.y.z = 1 }` now legal syntax for nested fields+    * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* [Add support for duplicate record fields](https://github.com/dhall-lang/dhall-haskell/pull/1643)+    * This combines with the previous feature to let you write+      `{ x.y = 1, x.z = True }`, which is equivalent to+      `{ x = { y = 1, z = True } }`+    * See the [changelog for standard version 14.0.0](https://github.com/dhall-lang/dhall-lang/releases/tag/v14.0.0) for more details+* [Add `dhall lint` support for deprecating `Optional/{fold,build}`](https://github.com/dhall-lang/dhall-haskell/pull/1628)+    * The `Optional/{fold,build}` built-ins are deprecated and can be implemented+      in terms of other language features+    * `Optional/fold` can be implemented in terms of `merge` (which now works on+      `Optional` values)+    * `Optional/build` could always be implemented using `Some`/`None`+    * `dhall lint` now transforms the deprecated built-ins to use their+      equivalent built-in-free versions+* [Support Template Haskell for multiple datatypes](https://github.com/dhall-lang/dhall-haskell/pull/1664)+    * This extends the Template Haskell support added in the previous release to+      work for datatypes that refer to one another+* [Add support for custom substitutions](https://github.com/dhall-lang/dhall-haskell/pull/1650)+    * You can now add custom substitutions, which are like `let` bindings that+      propagate to transitive imports+* [Small formatting fixes](https://github.com/dhall-lang/dhall-haskell/pull/1652)+ 1.29.0  * [Supports version 13.0.0 of the standard](https://github.com/dhall-lang/dhall-lang/releases/tag/v13.0.0)
dhall-lang/Prelude/JSON/package.dhall view
@@ -2,7 +2,7 @@         ./render sha256:f7c372fcc954bfbbc7f83deec2006608a48efa2b08e8753bfdf73dc0aa7b4faf       ? ./render   , renderYAML =-        ./renderYAML sha256:0949b834275fb231023ea80831d830352e0b89a15f4081f043cb83e745fdb6e8+        ./renderYAML sha256:b3a9d9b0349c90af9a4985c615c60ac4a85031a7bf9de78f2883126481d35aa0       ? ./renderYAML   , omitNullFields =         ./omitNullFields sha256:e6850e70094540b75edeb46f4d6038324a62def8d63544a1e9541f79739db6f0
dhall-lang/Prelude/JSON/renderYAML view
@@ -33,7 +33,7 @@       ? ../List/concatMap  let Optional/map =-        ../Optional/map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d+        ../Optional/map sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa       ? ../Optional/map  let NonEmpty@@ -81,12 +81,9 @@     : Block → List Block → Block     =   λ(ifEmpty : Block)       → λ(blocks : List Block)-      → Optional/fold-          (NonEmpty Block)+      → merge+          { Some = concatNonEmpty Text, None = ifEmpty }           (uncons Block blocks)-          Block-          (concatNonEmpty Text)-          ifEmpty  let singleLine     : Text → Block
dhall-lang/Prelude/List/default view
@@ -6,7 +6,7 @@     : ∀(a : Type) → Optional (List a) → List a     =   λ(a : Type)       → λ(o : Optional (List a))-      → Optional/fold (List a) o (List a) (λ(l : List a) → l) ([] : List a)+      → merge { Some = λ(l : List a) → l, None = [] : List a } o  let example0 = assert : default Bool (None (List Bool)) ≡ ([] : List Bool) 
dhall-lang/Prelude/List/package.dhall view
@@ -14,7 +14,7 @@       ./concatMap sha256:3b2167061d11fda1e4f6de0522cbe83e0d5ac4ef5ddf6bb0b2064470c5d3fb64     ? ./concatMap , default =-      ./default sha256:0ed2a04df6c1d55c08bcdbad82b30980af9ac40d2df7a1628f3663e3e8b4fe01+      ./default sha256:fd77809e497227403f42848ffcda05a3efab442d961027c34f3e31d5d24e6379     ? ./default , drop =       ./drop sha256:af983ba3ead494dd72beed05c0f3a17c36a4244adedf7ced502c6512196ed0cf
dhall-lang/Prelude/Natural/listMax view
@@ -7,7 +7,7 @@       ? ./max  let Optional/map =-        ../Optional/map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d+        ../Optional/map sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa       ? ../Optional/map  let listMax
dhall-lang/Prelude/Natural/listMin view
@@ -7,7 +7,7 @@       ? ./min  let Optional/map =-        ../Optional/map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d+        ../Optional/map sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa       ? ../Optional/map  let listMin
dhall-lang/Prelude/Natural/package.dhall view
@@ -53,13 +53,13 @@       ./max sha256:1f3b18da330223ab039fad11693da72c7e68d516f50502c73f41a89a097b62f7     ? ./max , listMin =-      ./listMin sha256:89e0d9c23750efd8a8a2a6945579f21e46bd503b0655d4bfdd0e0e51e39c37cc+      ./listMin sha256:ee70b0d010bbca6012162e8ae1f6e9d9bd10a152675509b0f23145b98b5d43c6     ? ./listMin , listMax =-      ./listMax sha256:30917e8ca230ea6044c6d8ea6e72bcf6f76437aaecc347f790e8a5946c6aa0e5+      ./listMax sha256:20906ffcc9970f740106d4516cb7868b43d75ff8c9f00ff8a9680ae68c48a472     ? ./listMax , sort =-      ./sort sha256:ed2eb5a33c5c96ac9227b0b4c77bdbf8911026d721c603ac897ae84b2bfb5dcd+      ./sort sha256:36ce8b3e5538454763987ca904d8d7c5ba34c2147434a19eddd51f684432b260     ? ./sort , subtract =       ./subtract sha256:b9277ac637d09142a3a3ac79137ef5955c42f8b33b6746d59db2c9d75ccdd745
dhall-lang/Prelude/Natural/sort view
@@ -6,7 +6,7 @@       ? ./greaterThanEqual  let listMin =-        ./listMin sha256:89e0d9c23750efd8a8a2a6945579f21e46bd503b0655d4bfdd0e0e51e39c37cc+        ./listMin sha256:ee70b0d010bbca6012162e8ae1f6e9d9bd10a152675509b0f23145b98b5d43c6       ? ./listMin  let List/partition =@@ -17,12 +17,12 @@  let partitionMinima =         λ(xs : List Natural)-      → Optional/fold-          Natural+      → merge+          { Some =+              λ(m : Natural) → List/partition Natural (greaterThanEqual m) xs+          , None = { true = [] : List Natural, false = [] : List Natural }+          }           (listMin xs)-          { true : List Natural, false : List Natural }-          (λ(m : Natural) → List/partition Natural (greaterThanEqual m) xs)-          { true = [] : List Natural, false = [] : List Natural }  let test0 =         assert
dhall-lang/Prelude/Optional/all view
@@ -7,7 +7,7 @@     =   λ(a : Type)       → λ(f : a → Bool)       → λ(xs : Optional a)-      → Optional/fold a xs Bool f True+      → merge { Some = f, None = True } xs  let example0 = assert : all Natural Natural/even (Some 3) ≡ False 
dhall-lang/Prelude/Optional/any view
@@ -7,7 +7,7 @@     =   λ(a : Type)       → λ(f : a → Bool)       → λ(xs : Optional a)-      → Optional/fold a xs Bool f False+      → merge { Some = f, None = False } xs  let example0 = assert : any Natural Natural/even (Some 2) ≡ True 
dhall-lang/Prelude/Optional/build view
@@ -9,7 +9,14 @@           → optional         )       → Optional a-    = Optional/build+    =   λ(a : Type)+      → λ ( build+          :   ∀(optional : Type)+            → ∀(some : a → optional)+            → ∀(none : optional)+            → optional+          )+      → build (Optional a) (λ(x : a) → Some x) (None a)  let example0 =         assert
dhall-lang/Prelude/Optional/concat view
@@ -5,12 +5,7 @@     : ∀(a : Type) → Optional (Optional a) → Optional a     =   λ(a : Type)       → λ(x : Optional (Optional a))-      → Optional/fold-          (Optional a)-          x-          (Optional a)-          (λ(y : Optional a) → y)-          (None a)+      → merge { Some = λ(y : Optional a) → y, None = None a } x  let example0 = assert : concat Natural (Some (Some 1)) ≡ Some 1 
dhall-lang/Prelude/Optional/default view
@@ -6,7 +6,7 @@     =   λ(a : Type)       → λ(default : a)       → λ(o : Optional a)-      → Optional/fold a o a (λ(x : a) → x) default+      → merge { Some = λ(x : a) → x, None = default } o  let example0 = assert : default Bool False (None Bool) ≡ False 
dhall-lang/Prelude/Optional/filter view
@@ -6,17 +6,22 @@     =   λ(a : Type)       → λ(f : a → Bool)       → λ(xs : Optional a)-      → Optional/build+      → (   λ(a : Type)+          → λ ( build+              :   ∀(optional : Type)+                → ∀(some : a → optional)+                → ∀(none : optional)+                → optional+              )+          → build (Optional a) (λ(x : a) → Some x) (None a)+        )           a           (   λ(optional : Type)             → λ(some : a → optional)             → λ(none : optional)-            → Optional/fold-                a+            → merge+                { Some = λ(x : a) → if f x then some x else none, None = none }                 xs-                optional-                (λ(x : a) → if f x then some x else none)-                none           )  let example0 = assert : filter Natural Natural/even (Some 2) ≡ Some 2
dhall-lang/Prelude/Optional/fold view
@@ -8,7 +8,12 @@       → ∀(some : a → optional)       → ∀(none : optional)       → optional-    = Optional/fold+    =   λ(a : Type)+      → λ(o : Optional a)+      → λ(optional : Type)+      → λ(some : a → optional)+      → λ(none : optional)+      → merge { Some = some, None = none } o  let example0 = assert : fold Natural (Some 2) Natural (λ(x : Natural) → x) 0 ≡ 2 
dhall-lang/Prelude/Optional/head view
@@ -11,7 +11,7 @@           (Optional a)           (   λ(l : Optional a)             → λ(r : Optional a)-            → Optional/fold a l (Optional a) (λ(x : a) → Some x) r+            → merge { Some = λ(x : a) → Some x, None = r } l           )           (None a) 
dhall-lang/Prelude/Optional/last view
@@ -11,7 +11,7 @@           (Optional a)           (   λ(l : Optional a)             → λ(r : Optional a)-            → Optional/fold a r (Optional a) (λ(x : a) → Some x) l+            → merge { Some = λ(x : a) → Some x, None = l } r           )           (None a) 
dhall-lang/Prelude/Optional/length view
@@ -5,7 +5,7 @@     : ∀(a : Type) → Optional a → Natural     =   λ(a : Type)       → λ(xs : Optional a)-      → Optional/fold a xs Natural (λ(_ : a) → 1) 0+      → merge { Some = λ(_ : a) → 1, None = 0 } xs  let example0 = assert : length Natural (Some 2) ≡ 1 
dhall-lang/Prelude/Optional/map view
@@ -7,7 +7,7 @@       → λ(b : Type)       → λ(f : a → b)       → λ(o : Optional a)-      → Optional/fold a o (Optional b) (λ(x : a) → Some (f x)) (None b)+      → merge { Some = λ(x : a) → Some (f x), None = None b } o  let example0 = assert : map Natural Bool Natural/even (Some 3) ≡ Some False 
dhall-lang/Prelude/Optional/null view
@@ -5,7 +5,7 @@     : ∀(a : Type) → Optional a → Bool     =   λ(a : Type)       → λ(xs : Optional a)-      → Optional/fold a xs Bool (λ(_ : a) → False) True+      → merge { Some = λ(_ : a) → False, None = True } xs  let example0 = assert : null Natural (Some 2) ≡ False 
dhall-lang/Prelude/Optional/package.dhall view
@@ -1,43 +1,43 @@ { all =-      ./all sha256:b9b015fe8be14da940901aa1510ee1d5e205df37ee651c32ac975a799782c410+      ./all sha256:a303004b6def0a2a05bf5f0a8d54e84dd45d8bef581789186ac04924956a1695     ? ./all , any =-      ./any sha256:0a637c0f2cc7d30b8f0bca021d2ee1ad1213fb9d9712c669b29feab66a590eaf+      ./any sha256:96a5cf4f31b3c598b09161dd3082f0a09f4328a4cefda6a7e09894b37b17b435     ? ./any , build =-      ./build sha256:f331299d1279cfb88dd25a5acfdd64130900991b6154239ad343a2883f6eb50c+      ./build sha256:28e61294bf2dd59dc57cf74f719d1568e60b5ba46c28eac586bc937eff4a2af1     ? ./build , concat =-      ./concat sha256:b49a3b7dc49eb83d150977caa5ae347be1cbbe14e3b6d0e07349bd2e5f707d69+      ./concat sha256:b7736bd3ebeab14c3912dfb534d0c970a025b001d06c2d5461d4b0e289e3cb7a     ? ./concat , default =-      ./default sha256:8f802473931b605422b545d7b81de20dbecb38f2ae63950c13f5381865a7f012+      ./default sha256:5bd665b0d6605c374b3c4a7e2e2bd3b9c1e39323d41441149ed5e30d86e889ad     ? ./default , filter =-      ./filter sha256:b3d5e19a6cec592a76c12167a9e5e1e76649e776229d70a11c77b76cd29f617e+      ./filter sha256:54f0a487d578801819613fe000050c038c632edf1f9ccc57677e98ae0ef56b83     ? ./filter , fold =-      ./fold sha256:62139ff410ca84302acebe763a8a1794420dd472d907384c7fb80df2a2180302+      ./fold sha256:c5b9d72f6f62bdaa0e196ac1c742cc175cd67a717b880fb8aec1333a5a4132cf     ? ./fold , head =-      ./head sha256:b0b5d257294515f1de35f24fa83e54d7f1d5ebca9c3c1fc903a80ab40e19b3a6+      ./head sha256:4f256c9338b60a1933f41f2a8fafd861930a1e41770a644cdbac0622676fa34c     ? ./head , last =-      ./last sha256:f839221a8a04adae6c501458eb264e7f4e375a1facb294cb80caacfd012a6765+      ./last sha256:50400771ae19e9b75efa6581feec318ae1ade0b6a60e215df428c66c4b052707     ? ./last , length =-      ./length sha256:722a3754a411c053f006a32c506a6d1b14869c2ab799169df9cdac346edf07d3+      ./length sha256:f168337c5244ded68c05ecf32ce068b6b87158881d07e87b8cb6853fc6982a85     ? ./length , map =-      ./map sha256:e7f44219250b89b094fbf9996e04b5daafc0902d864113420072ae60706ac73d+      ./map sha256:501534192d988218d43261c299cc1d1e0b13d25df388937add784778ab0054fa     ? ./map , null =-      ./null sha256:efc43103e49b56c5bf089db8e0365bbfc455b8a2f0dc6ee5727a3586f85969fd+      ./null sha256:3871180b87ecaba8b53fffb2a8b52d3fce98098fab09a6f759358b9e8042eedc     ? ./null , toList =-      ./toList sha256:390fe99619e9a25e71a253a2b33011f9e5fa26a7d990795205543d1edd72ce5b+      ./toList sha256:d78f160c619119ef12389e48a629ce293d69f7624c8d016b7a4767ab400344c4     ? ./toList , unzip =-      ./unzip sha256:7b517bc2a8a4dbec044c6bea5e059cafde5a0cb1d3a5e7d13d346c9327a00f30+      ./unzip sha256:d016c01ba91657a2f35609aa29087963d0f506bab0f41d5e8b7cd289dff39708     ? ./unzip }
dhall-lang/Prelude/Optional/toList view
@@ -5,7 +5,7 @@     : ∀(a : Type) → Optional a → List a     =   λ(a : Type)       → λ(o : Optional a)-      → Optional/fold a o (List a) (λ(x : a) → [ x ] : List a) ([] : List a)+      → merge { Some = λ(x : a) → [ x ] : List a, None = [] : List a } o  let example0 = assert : toList Natural (Some 1) ≡ [ 1 ] 
dhall-lang/Prelude/Optional/unzip view
@@ -10,19 +10,13 @@       → λ(b : Type)       → λ(xs : Optional { _1 : a, _2 : b })       → { _1 =-            Optional/fold-              { _1 : a, _2 : b }+            merge+              { Some = λ(x : { _1 : a, _2 : b }) → Some x._1, None = None a }               xs-              (Optional a)-              (λ(x : { _1 : a, _2 : b }) → Some x._1)-              (None a)         , _2 =-            Optional/fold-              { _1 : a, _2 : b }+            merge+              { Some = λ(x : { _1 : a, _2 : b }) → Some x._2, None = None b }               xs-              (Optional b)-              (λ(x : { _1 : a, _2 : b }) → Some x._2)-              (None b)         }  let example0 =
dhall-lang/Prelude/Text/default view
@@ -3,7 +3,7 @@ -} let default     : Optional Text → Text-    = λ(o : Optional Text) → Optional/fold Text o Text (λ(t : Text) → t) ""+    = λ(o : Optional Text) → merge { Some = λ(t : Text) → t, None = "" } o  let example0 = assert : default (Some "ABC") ≡ "ABC" 
dhall-lang/Prelude/Text/defaultMap view
@@ -6,7 +6,7 @@     =   λ(a : Type)       → λ(f : a → Text)       → λ(o : Optional a)-      → Optional/fold a o Text f ""+      → merge { Some = f, None = "" } o  let example0 = assert : defaultMap Natural Natural/show (Some 0) ≡ "0" 
dhall-lang/Prelude/Text/package.dhall view
@@ -11,10 +11,10 @@       ./concatSep sha256:e4401d69918c61b92a4c0288f7d60a6560ca99726138ed8ebc58dca2cd205e58     ? ./concatSep , default =-      ./default sha256:e26d120fe57a4b61259d1149d938a66d335e1eb263196c30311c117073e4f92f+      ./default sha256:f532c8891b1e427d90a6cc07cf7e793a4c84b0765e1bfe69f186ee2ec91c1edf     ? ./default , defaultMap =-      ./defaultMap sha256:a35c0e1db25e9223223b0beba0fcefeba7cd06a0edfa3994ccc9f82f6b86ff79+      ./defaultMap sha256:3a3fa1264f6198800c27483cb144de2c5366484876d60b9c739a710ce0288588     ? ./defaultMap , show =       ./show sha256:c9dc5de3e5f32872dbda57166804865e5e80785abe358ff61f1d8ac45f1f4784
dhall-lang/Prelude/package.dhall view
@@ -11,7 +11,7 @@       ./Integer/package.dhall sha256:d1a572ca3a764781496847e4921d7d9a881c18ffcfac6ae28d0e5299066938a0     ? ./Integer/package.dhall , List =-      ./List/package.dhall sha256:f0fdab7ab30415c128d89424589c42a15c835338be116fa14484086e4ba118d7+      ./List/package.dhall sha256:67899380860ce07a2d5d9530dc502800f2c11c73c2d64e8c827f4920b5473887     ? ./List/package.dhall , Location =       ./Location/package.dhall sha256:0eb4e4a60814018009c720f6820aaa13cf9491eb1b09afb7b832039c6ee4d470@@ -23,16 +23,16 @@       ./Monoid sha256:26fafa098600ef7a54ef9dba5ada416bbbdd21df1af306c052420c61553ad4af     ? ./Monoid , Natural =-      ./Natural/package.dhall sha256:e230d4ee318826ab9517ae5d6f38d1a9359d7cff815cc32912cc6b991656bb1a+      ./Natural/package.dhall sha256:ee9ed2b28a417ed4e9a0c284801b928bf91b3fbdc1a68616347678c1821f1ddf     ? ./Natural/package.dhall , Optional =-      ./Optional/package.dhall sha256:7608f2d38dabee8bfe6865b4adc11289059984220f422d2b023b15b3908f7a4c+      ./Optional/package.dhall sha256:4324b2bf84ded40f67485f14355e4cb7b237a8f173e713c791ec44cebebc552c     ? ./Optional/package.dhall , JSON =-      ./JSON/package.dhall sha256:7533c6c457353bde410a57a5c1d82c6097c8d4dbf9f55a0d926ab56f4ffce77c+      ./JSON/package.dhall sha256:88c358783defee9bbd65aea224cdac56c7666ba367b0dd5f7f6d56de73911292     ? ./JSON/package.dhall , Text =-      ./Text/package.dhall sha256:0a0ad9f649aed94c2680491efb384925b5b2bb5b353f1b8a7eb134955c1ffe45+      ./Text/package.dhall sha256:3a5e3acde76fe5f90bd296e6c9d2e43e6ae81c56f804029b39352d2f1664b769     ? ./Text/package.dhall , XML =       ./XML/package.dhall sha256:137e7b106b2e9743970e5d37b21a165f2e40f56ab593a4dd10605c9acd686fc6
+ dhall-lang/tests/normalization/success/unit/RecordLitDottedFieldsA.dhall view
@@ -0,0 +1,1 @@+{ x.y.z = True }
+ dhall-lang/tests/normalization/success/unit/RecordLitDottedFieldsB.dhall view
@@ -0,0 +1,1 @@+{ x = { y = { z = True } } }
+ dhall-lang/tests/normalization/success/unit/RecordLitDuplicateFieldsNoCollisionsA.dhall view
@@ -0,0 +1,9 @@+{-  This expression desugars to:++        { x = { y = 0 } ∧ { z = 0 } }++    ... which then β-normalizes to:++        { x = { y = 0, z = 0 } }+-}+{ x = { y = 0 }, x = { z = 0 } }
+ dhall-lang/tests/normalization/success/unit/RecordLitDuplicateFieldsNoCollisionsB.dhall view
@@ -0,0 +1,1 @@+{ x = { y = 0, z = 0 } }
+ dhall-lang/tests/normalization/success/unit/RecordLitNixLikeA.dhall view
@@ -0,0 +1,4 @@+{- The purpose of this test is to verify that the Nix-like idiom of setting+   multiple overlapping dotted fields works correctly+-}+{ x.y = 1, x.z = True }
+ dhall-lang/tests/normalization/success/unit/RecordLitNixLikeB.dhall view
@@ -0,0 +1,1 @@+{ x = { y = 1, z = True } }
+ dhall-lang/tests/normalization/success/unit/RecordLitTriplicateFieldsA.dhall view
@@ -0,0 +1,7 @@+{-  This test ensures that an implementation handles more than one duplicate+    field correctly and combines them with the correct order and associativity+-}+  λ(a : { x : Natural })+→ λ(b : { y : Natural })+→ λ(c : { z : Natural })+→ { k = a, k = b, k = c }
+ dhall-lang/tests/normalization/success/unit/RecordLitTriplicateFieldsB.dhall view
@@ -0,0 +1,4 @@+  λ(a : { x : Natural })+→ λ(b : { y : Natural })+→ λ(c : { z : Natural })+→ { k = a ∧ b ∧ c }
dhall-lang/tests/parser/success/naturalA.dhall view
@@ -1,1 +1,1 @@-[ 0, 1, 01, 10 ]+[ 0, 1, 10 ]
dhall-lang/tests/parser/success/naturalB.dhallb view

binary file changed (15 → 12 bytes)

+ dhall-lang/tests/parser/success/unit/RecordLitDottedA.dhall view
@@ -0,0 +1,7 @@+{-  The purpose of this test is to illustrate that dotted fields are syntactic+    sugar that does not survive the parsing stage.  The underlying expression is+    actually represented and encoded as:++    { x = { y = { z = 1 } } }+-}+{ x.y.z = 1 }
+ dhall-lang/tests/parser/success/unit/RecordLitDottedB.dhallb view
@@ -0,0 +1,1 @@+‚¡ax‚¡ay‚¡az‚
+ dhall-lang/tests/parser/success/unit/RecordLitDottedEscapeA.dhall view
@@ -0,0 +1,1 @@+{ `x.y`.z = 1 }
+ dhall-lang/tests/parser/success/unit/RecordLitDottedEscapeB.dhallb view
@@ -0,0 +1,1 @@+‚¡cx.y‚¡az‚
+ dhall-lang/tests/parser/success/unit/RecordLitDuplicatesA.dhall view
@@ -0,0 +1,7 @@+{-  The purpose of this test is to illustrate that duplicate fields are+    syntactic sugar that does not survive the parsing stage.  The underlying+    expression is actually represented and encoded as:++    { x = { y = 1 } ∧ { z = 1 } }+-}+{ x = { y = 1 }, x = { z = 1 } }
+ dhall-lang/tests/parser/success/unit/RecordLitDuplicatesB.dhallb view
@@ -0,0 +1,1 @@+‚¡ax„‚¡ay‚‚¡az‚
+ dhall-lang/tests/parser/success/unit/RecordLitNixLikeA.dhall view
@@ -0,0 +1,5 @@+{- The purpose of this test is to verify that the combination of the dotted+   field notation and the duplicate record fields desugar to the desired syntax+   tree+-}+{ x.y = 1, x.z = True }
+ dhall-lang/tests/parser/success/unit/RecordLitNixLikeB.dhallb view
@@ -0,0 +1,1 @@+‚¡ax„‚¡ay‚‚¡azõ
dhall-lang/tests/type-inference/success/preludeB.dhall view
@@ -402,21 +402,22 @@     , any : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Bool     , build :           ∀(a : Type)-        → (   ∀(optional : Type)-            → ∀(just : a → optional)-            → ∀(nothing : optional)-            → optional-          )+        → ∀ ( build+            :   ∀(optional : Type)+              → ∀(some : a → optional)+              → ∀(none : optional)+              → optional+            )         → Optional a     , concat : ∀(a : Type) → ∀(x : Optional (Optional a)) → Optional a     , default : ∀(a : Type) → ∀(default : a) → ∀(o : Optional a) → a     , filter : ∀(a : Type) → ∀(f : a → Bool) → ∀(xs : Optional a) → Optional a     , fold :           ∀(a : Type)-        → Optional a+        → ∀(o : Optional a)         → ∀(optional : Type)-        → ∀(just : a → optional)-        → ∀(nothing : optional)+        → ∀(some : a → optional)+        → ∀(none : optional)         → optional     , head : ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a     , last : ∀(a : Type) → ∀(xs : List (Optional a)) → Optional a
+ dhall-lang/tests/type-inference/success/unit/MergeOptionalA.dhall view
@@ -0,0 +1,1 @@+λ(x : Optional Bool) → merge { None = 0, Some = λ(_ : Bool) → 1 } x
+ dhall-lang/tests/type-inference/success/unit/MergeOptionalB.dhall view
@@ -0,0 +1,1 @@+∀(x : Optional Bool) → Natural
+ dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsA.dhall view
@@ -0,0 +1,1 @@+{ x.y.z = 1 }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsB.dhall view
@@ -0,0 +1,1 @@+{ x : { y : { z : Natural } } }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsMergeA.dhall view
@@ -0,0 +1,14 @@+{-  This example verifies that a Dhall interpreter correctly handles a corner+    case that other languages sometimes misbehave on++    The expression should desugar like this:++        λ(r : { z : Natural }) → { x.y = 1, x = r }++        λ(r : { z : Natural }) → { x = { y = 1 }, x = r }++        λ(r : { z : Natural }) → { x = { y = 1 } ∧ r }++    ... which type-checks since `{ y = 1 }` and `r` do not collide+-}+λ(r : { z : Natural }) → { x.y = 1, x = r }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDottedFieldsMergeB.dhall view
@@ -0,0 +1,1 @@+∀(r : { z : Natural }) → { x : { y : Natural, z : Natural } }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsAbstractA.dhall view
@@ -0,0 +1,12 @@+{-  This test illustrates that duplicate fields need not be literals in order+    to be properly normalized.  One or both of the duplicate fields can be+    abstract because field duplication delegates its behavior to the ∧ operator++    This particular example succeeds because it desugars to:++        λ(r : { z : Natural }) → { x = { y = 1 } ∧ r }++    ... and the `∧` operator can infer the absence of conflicts due to knowing+    the type of `r`+-}+λ(r : { z : Natural }) → { x = { y = 1 }, x = r }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsAbstractB.dhall view
@@ -0,0 +1,1 @@+∀(r : { z : Natural }) → { x : { y : Natural, z : Natural } }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsNoCollisionsA.dhall view
@@ -0,0 +1,12 @@+{-  This type-checks because the expression desugars to:++        { x = { y = 0 } ∧ { z = 0 } }++    ... which in turn type-checks due to the absence of a field collision.++    This expression is analogous to the following common Nix/TOML/Cue idiom,+    which we would like to support:++        { x.y = 0, x.z = 0 }+-}+{ x = { y = 0 }, x = { z = 0 } }
+ dhall-lang/tests/type-inference/success/unit/RecordLitDuplicateFieldsNoCollisionsB.dhall view
@@ -0,0 +1,1 @@+{ x : { y : Natural, z : Natural } }
dhall.cabal view
@@ -1,8 +1,8 @@ Name: dhall-Version: 1.29.0+Version: 1.30.0 Cabal-Version: >=1.10 Build-Type: Simple-Tested-With: GHC == 7.10.3, GHC == 8.4.3, GHC == 8.6.1+Tested-With: GHC == 8.0.2, GHC == 8.4.3, GHC == 8.6.1 License: BSD3 License-File: LICENSE Copyright: 2017 Gabriel Gonzalez@@ -427,7 +427,7 @@ Library     Hs-Source-Dirs: src     Build-Depends:-        base                        >= 4.8.2.0  && < 5   ,+        base                        >= 4.9.1.0  && < 5   ,         aeson                       >= 1.0.0.0  && < 1.5 ,         aeson-pretty                               < 0.9 ,         ansi-terminal               >= 0.6.3.1  && < 0.11,@@ -441,12 +441,12 @@         data-fix                                   < 0.3 ,         deepseq                                    < 1.5 ,         Diff                        >= 0.2      && < 0.5 ,-        directory                   >= 1.2.2.0  && < 1.4 ,+        directory                   >= 1.3.0.0  && < 1.4 ,         dotgen                      >= 0.4.2    && < 0.5 ,         either                      >= 5        && < 5.1,         exceptions                  >= 0.8.3    && < 0.11,         filepath                    >= 1.4      && < 1.5 ,-        haskeline                   >= 0.7.2.1  && < 0.8 ,+        haskeline                   >= 0.7.2.1  && < 0.9 ,         hashable                    >= 1.2      && < 1.4 ,         lens-family-core            >= 1.0.0    && < 2.1 ,         megaparsec                  >= 7        && < 8.1 ,@@ -455,14 +455,15 @@         network-uri                 >= 2.6      && < 2.7 ,         optparse-applicative        >= 0.14.0.0 && < 0.16,         parsers                     >= 0.12.4   && < 0.13,-        prettyprinter               >= 1.5.1    && < 1.6 ,+        parser-combinators                               ,+        prettyprinter               >= 1.5.1    && < 1.7 ,         prettyprinter-ansi-terminal >= 1.1.1    && < 1.2 ,         pretty-simple                              < 4   ,         profunctors                 >= 3.1.2    && < 5.6 ,         repline                     >= 0.2.1.0  && < 0.3 ,         serialise                   >= 0.2.0.0  && < 0.3 ,         scientific                  >= 0.3.0.0  && < 0.4 ,-        template-haskell                           < 2.16,+        template-haskell            >= 2.11.1.0 && < 2.16,         text                        >= 0.11.1.0 && < 1.3 ,         th-lift-instances           >= 0.1.13   && < 0.2 ,         transformers                >= 0.2.0.0  && < 0.6 ,@@ -542,6 +543,7 @@         Dhall.Repl         Dhall.Set         Dhall.Src+        Dhall.Substitution         Dhall.Tags         Dhall.Tutorial         Dhall.TypeCheck@@ -593,6 +595,7 @@         Dhall.Test.QuickCheck         Dhall.Test.Regression         Dhall.Test.SemanticHash+        Dhall.Test.Substitution         Dhall.Test.TH         Dhall.Test.Tutorial         Dhall.Test.TypeInference
src/Dhall.hs view
@@ -33,6 +33,7 @@     , rootDirectory     , sourceName     , startingContext+    , substitutions     , normalizer     , defaultInputSettings     , InputSettings@@ -178,6 +179,7 @@ import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty.Internal+import qualified Dhall.Substitution import qualified Dhall.TypeCheck import qualified Dhall.Util import qualified Lens.Family@@ -335,7 +337,8 @@  -- | @since 1.16 data EvaluateSettings = EvaluateSettings-  { _startingContext :: Dhall.Context.Context (Expr Src Void)+  { _substitutions   :: Dhall.Substitution.Substitutions Src Void+  , _startingContext :: Dhall.Context.Context (Expr Src Void)   , _normalizer      :: Maybe (Dhall.Core.ReifiedNormalizer Void)   } @@ -345,7 +348,8 @@ -- @since 1.16 defaultEvaluateSettings :: EvaluateSettings defaultEvaluateSettings = EvaluateSettings-  { _startingContext = Dhall.Context.empty+  { _substitutions   = Dhall.Substitution.empty+  , _startingContext = Dhall.Context.empty   , _normalizer      = Nothing   } @@ -361,6 +365,18 @@       => LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src Void))     l k s = fmap (\x -> s { _startingContext = x}) (k (_startingContext s)) +-- | Access the custom substitutions.+--+-- @since 1.30+substitutions+  :: (Functor f, HasEvaluateSettings s)+  => LensLike' f s (Dhall.Substitution.Substitutions Src Void)+substitutions = evaluateSettings . l+  where+    l :: (Functor f)+      => LensLike' f EvaluateSettings (Dhall.Substitution.Substitutions Src Void)+    l k s = fmap (\x -> s { _substitutions = x }) (k (_substitutions s))+ -- | Access the custom normalizer. -- -- @since 1.16@@ -428,31 +444,17 @@     -> IO a     -- ^ The decoded value in Haskell inputWithSettings settings (Decoder {..}) txt = do-    expr  <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)--    let InputSettings {..} = settings--    let EvaluateSettings {..} = _evaluateSettings--    let transform =-               Lens.Family.set Dhall.Import.normalizer      _normalizer-            .  Lens.Family.set Dhall.Import.startingContext _startingContext--    let status = transform (Dhall.Import.emptyStatus _rootDirectory)--    expr' <- State.evalStateT (Dhall.Import.loadWith expr) status-     let suffix = Dhall.Pretty.Internal.prettyToStrictText expected-    let annot = case expr' of+    let annotate substituted = case substituted of             Note (Src begin end bytes) _ ->-                Note (Src begin end bytes') (Annot expr' expected)+                Note (Src begin end bytes') (Annot substituted expected)               where                 bytes' = bytes <> " : " <> suffix             _ ->-                Annot expr' expected-    _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)-    let normExpr = Dhall.Core.normalizeWith (view normalizer settings) expr'+                Annot substituted expected +    normExpr <- inputHelper annotate settings txt+     case extract normExpr  of         Success x  -> return x         Failure e -> Control.Exception.throwIO e@@ -521,7 +523,20 @@     -- ^ The Dhall program     -> IO (Expr Src Void)     -- ^ The fully normalized AST-inputExprWithSettings settings txt = do+inputExprWithSettings = inputHelper id++{-| Helper function for the input* function family++@since 1.30+-}+inputHelper+    :: (Expr Src Void -> Expr Src Void)+    -> InputSettings+    -> Text+    -- ^ The Dhall program+    -> IO (Expr Src Void)+    -- ^ The fully normalized AST+inputHelper annotate settings txt = do     expr  <- Dhall.Core.throws (Dhall.Parser.exprFromText (view sourceName settings) txt)      let InputSettings {..} = settings@@ -529,15 +544,18 @@     let EvaluateSettings {..} = _evaluateSettings      let transform =-               Lens.Family.set Dhall.Import.normalizer      _normalizer+               Lens.Family.set Dhall.Import.substitutions   _substitutions+            .  Lens.Family.set Dhall.Import.normalizer      _normalizer             .  Lens.Family.set Dhall.Import.startingContext _startingContext      let status = transform (Dhall.Import.emptyStatus _rootDirectory)      expr' <- State.evalStateT (Dhall.Import.loadWith expr) status -    _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) expr')-    pure (Dhall.Core.normalizeWith (view normalizer settings) expr')+    let substituted = Dhall.Substitution.substitute expr' $ view substitutions settings+    let annot = annotate substituted+    _ <- Dhall.Core.throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)+    pure (Dhall.Core.normalizeWith (view normalizer settings) substituted)  -- | Use this function to extract Haskell values directly from Dhall AST. --   The intended use case is to allow easy extraction of Dhall values for
src/Dhall/Binary.hs view
@@ -305,7 +305,7 @@                                     5  -> return NaturalTimes                                     6  -> return TextAppend                                     7  -> return ListAppend-                                    8  -> return Combine+                                    8  -> return (Combine Nothing)                                     9  -> return Prefer                                     10 -> return CombineTypes                                     11 -> return ImportAlt@@ -756,7 +756,7 @@         ListAppend l r ->             encodeOperator 7 l r -        Combine l r ->+        Combine _ l r ->             encodeOperator 8 l r          Prefer l r ->
src/Dhall/Diff.hs view
@@ -882,7 +882,7 @@ diffCombineExpression l@(Combine {}) r@(Combine {}) =     enclosed' "  " (operator "∧" <> " ") (docs l r)   where-    docs (Combine aL bL) (Combine aR bR) =+    docs (Combine _ aL bL) (Combine _ aR bR) =         Data.List.NonEmpty.cons (diffPreferExpression aL aR) (docs bL bR)     docs aL aR =         pure (diffPreferExpression aL aR)
src/Dhall/Eval.hs view
@@ -216,7 +216,7 @@     | VRecord !(Map Text (Val a))     | VRecordLit !(Map Text (Val a))     | VUnion !(Map Text (Maybe (Val a)))-    | VCombine !(Val a) !(Val a)+    | VCombine !(Maybe Text) !(Val a) !(Val a)     | VCombineTypes !(Val a) !(Val a)     | VPrefer !(Val a) !(Val a)     | VMerge !(Val a) !(Val a) !(Maybe (Val a))@@ -288,17 +288,17 @@             VPrefer t' u' {-# INLINE vPrefer #-} -vCombine :: Val a -> Val a -> Val a-vCombine t u =+vCombine :: Maybe Text -> Val a -> Val a -> Val a+vCombine mk t u =     case (t, u) of         (VRecordLit m, u') | null m ->             u'         (t', VRecordLit m) | null m ->             t'         (VRecordLit m, VRecordLit m') ->-            VRecordLit (Map.unionWith vCombine m m')+            VRecordLit (Map.unionWith (vCombine Nothing) m m')         (t', u') ->-            VCombine t' u'+            VCombine mk t' u'  vCombineTypes :: Val a -> Val a -> Val a vCombineTypes t u =@@ -356,11 +356,11 @@         VPrefer l (VRecordLit m) -> case Map.lookup k m of             Just v -> v             Nothing -> go l-        VCombine (VRecordLit m) r -> case Map.lookup k m of-            Just v -> VField (VCombine (singletonVRecordLit v) r) k+        VCombine mk (VRecordLit m) r -> case Map.lookup k m of+            Just v -> VField (VCombine mk (singletonVRecordLit v) r) k             Nothing -> go r-        VCombine l (VRecordLit m) -> case Map.lookup k m of-            Just v -> VField (VCombine l (singletonVRecordLit v)) k+        VCombine mk l (VRecordLit m) -> case Map.lookup k m of+            Just v -> VField (VCombine mk l (singletonVRecordLit v)) k             Nothing -> go l         t -> VField t k @@ -684,8 +684,8 @@             VRecordLit (Map.sort (fmap (eval env) kts))         Union kts ->             VUnion (Map.sort (fmap (fmap (eval env)) kts))-        Combine t u ->-            vCombine (eval env t) (eval env u)+        Combine mk t u ->+            vCombine mk (eval env t) (eval env u)         CombineTypes t u ->             vCombineTypes (eval env t) (eval env u)         Prefer t u ->@@ -924,7 +924,7 @@             eqMapsBy (conv env) m m'         (VUnion m, VUnion m') ->             eqMapsBy (eqMaybeBy (conv env)) m m'-        (VCombine t u, VCombine t' u') ->+        (VCombine _ t u, VCombine _ t' u') ->             conv env t t' && conv env u u'         (VCombineTypes t u, VCombineTypes t' u') ->             conv env t t' && conv env u u'@@ -1112,8 +1112,8 @@             RecordLit (fmap (quote env) m)         VUnion m ->             Union (fmap (fmap (quote env)) m)-        VCombine t u ->-            Combine (quote env t) (quote env u)+        VCombine mk t u ->+            Combine mk (quote env t) (quote env u)         VCombineTypes t u ->             CombineTypes (quote env t) (quote env u)         VPrefer t u ->@@ -1292,8 +1292,8 @@                 RecordLit (fmap go kts)             Union kts ->                 Union (fmap (fmap go) kts)-            Combine t u ->-                Combine (go t) (go u)+            Combine m t u ->+                Combine m (go t) (go u)             CombineTypes t u ->                 CombineTypes (go t) (go u)             Prefer t u ->
src/Dhall/Format.hs view
@@ -7,15 +7,20 @@ module Dhall.Format     ( -- * Format       Format(..)-    , FormatMode(..)     , format     ) where -import Control.Exception (Exception) import Data.Monoid ((<>)) import Dhall.Pretty (CharacterSet(..), annToAnsiStyle)-import Dhall.Util (Censor, Input(..), Header(..)) +import Dhall.Util+    ( Censor+    , CheckFailed(..)+    , Header(..)+    , Input(..)+    , OutputMode(..)+    )+ import qualified Data.Text.Prettyprint.Doc                 as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty.Terminal import qualified Data.Text.Prettyprint.Doc.Render.Text     as Pretty.Text@@ -27,30 +32,16 @@ import qualified System.Console.ANSI import qualified System.IO -data NotFormatted = NotFormatted-    deriving (Exception)--instance Show NotFormatted where-    show _ = ""- -- | Arguments to the `format` subcommand data Format = Format     { characterSet :: CharacterSet     , censor       :: Censor-    , formatMode   :: FormatMode+    , input        :: Input+    , outputMode   :: OutputMode     } -{-| The `format` subcommand can either `Modify` its input or simply `Check`-    that the input is already formatted--}-data FormatMode-    = Modify { inplace :: Input }-    | Check  { path :: Input }- -- | Implementation of the @dhall format@ subcommand-format-    :: Format-    -> IO ()+format :: Format -> IO () format (Format {..}) = do     let layoutHeaderAndExpr (Header header, expr) =             Dhall.Pretty.layout@@ -58,16 +49,16 @@                 <>  Dhall.Pretty.prettyCharacterSet characterSet expr                  <>  "\n") -    let layoutInput input = do+    let layoutInput = do             headerAndExpr <- Dhall.Util.getExpressionAndHeader censor input              return (layoutHeaderAndExpr headerAndExpr) -    case formatMode of-        Modify {..} -> do-            docStream <- layoutInput inplace+    case outputMode of+        Write -> do+            docStream <- layoutInput -            case inplace of+            case input of                 InputFile file -> do                     AtomicWrite.LazyText.atomicWriteFile                         file@@ -82,13 +73,13 @@                             then (fmap annToAnsiStyle docStream)                             else (Pretty.unAnnotateS docStream)) -        Check {..} -> do-            originalText <- case path of+        Check -> do+            originalText <- case input of                 InputFile file -> Data.Text.IO.readFile file                 StandardInput  -> Data.Text.IO.getContents -            docStream <- case path of-                InputFile _    -> layoutInput path+            docStream <- case input of+                InputFile _    -> layoutInput                 StandardInput  -> do                     headerAndExpr <- Dhall.Util.getExpressionAndHeaderFromStdinText censor originalText                     return (layoutHeaderAndExpr headerAndExpr)@@ -97,4 +88,9 @@              if originalText == formattedText                 then return ()-                else Control.Exception.throwIO NotFormatted+                else do+                    let command = "format"++                    let modified = "formatted"++                    Control.Exception.throwIO CheckFailed{..}
src/Dhall/Freeze.hs view
@@ -15,25 +15,34 @@     , Intent(..)     ) where +import Data.Bifunctor (first) import Data.Monoid ((<>)) import Data.Text import Dhall.Parser (Src) import Dhall.Pretty (CharacterSet) import Dhall.Syntax (Expr(..), Import(..), ImportHashed(..), ImportType(..))-import Dhall.Util (Censor, Input(..))+import Dhall.Util+    ( Censor+    , CheckFailed(..)+    , Header(..)+    , Input(..)+    , OutputMode(..)+    ) import System.Console.ANSI (hSupportsANSI) -import qualified Control.Exception+import qualified Control.Exception                         as Exception import qualified Control.Monad.Trans.State.Strict          as State+import qualified Data.Text.IO                              as Text.IO import qualified Data.Text.Prettyprint.Doc                 as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Text     as Pretty.Text import qualified Dhall.Core                                as Core import qualified Dhall.Import import qualified Dhall.Optics+import qualified Dhall.Parser                              as Parser import qualified Dhall.Pretty import qualified Dhall.TypeCheck-import qualified Dhall.Util+import qualified Dhall.Util                                as Util import qualified System.AtomicWrite.Writer.LazyText        as AtomicWrite.LazyText import qualified System.FilePath import qualified System.IO@@ -58,7 +67,7 @@     expression <- State.evalStateT (Dhall.Import.loadWith (Embed unprotectedImport)) status      case Dhall.TypeCheck.typeOf expression of-        Left  exception -> Control.Exception.throwIO exception+        Left  exception -> Exception.throwIO exception         Right _         -> return ()      let normalizedExpression = Core.alphaNormalize (Core.normalize expression)@@ -86,7 +95,7 @@         _         -> return import_  writeExpr :: Input -> (Text, Expr Src Import) -> CharacterSet -> IO ()-writeExpr inplace (header, expr) characterSet = do+writeExpr input (header, expr) characterSet = do     let doc =  Pretty.pretty header             <> Dhall.Pretty.prettyCharacterSet characterSet expr             <> "\n"@@ -95,7 +104,7 @@      let unAnnotated = Pretty.unAnnotateS stream -    case inplace of+    case input of         InputFile file ->             AtomicWrite.LazyText.atomicWriteFile                 file@@ -129,20 +138,18 @@  -- | Implementation of the @dhall freeze@ subcommand freeze-    :: Input+    :: OutputMode+    -> Input     -> Scope     -> Intent     -> CharacterSet     -> Censor     -> IO ()-freeze inplace scope intent characterSet censor = do-    let directory = case inplace of+freeze outputMode input scope intent characterSet censor = do+    let directory = case input of             StandardInput  -> "."             InputFile file -> System.FilePath.takeDirectory file -    (Dhall.Util.Header header, parsedExpression) <--        Dhall.Util.getExpressionAndHeader censor inplace-     let freezeScope =             case scope of                 AllImports        -> freezeImport@@ -194,6 +201,42 @@                         cache                         expression -    frozenExpression <- rewrite parsedExpression+    case outputMode of+        Write -> do+            (Header header, parsedExpression) <- do+                Util.getExpressionAndHeader censor input -    writeExpr inplace (header, frozenExpression) characterSet+            frozenExpression <- rewrite parsedExpression++            writeExpr input (header, frozenExpression) characterSet++        Check -> do+            originalText <- case input of+                InputFile file -> Text.IO.readFile file+                StandardInput  -> Text.IO.getContents++            let name = case input of+                    InputFile file -> file+                    StandardInput  -> "(stdin)"++            (Header header, parsedExpression) <- do+                Core.throws (first Parser.censor (Parser.exprAndHeaderFromText name originalText))++            frozenExpression <- rewrite parsedExpression++            let doc =  Pretty.pretty header+                    <> Dhall.Pretty.prettyCharacterSet characterSet frozenExpression+                    <> "\n"++            let stream = Dhall.Pretty.layout doc++            let modifiedText = Pretty.Text.renderStrict stream++            if originalText == modifiedText+                then return ()+                else do+                    let command = "freeze"++                    let modified = "frozen"++                    Exception.throwIO CheckFailed{..}
src/Dhall/Import.hs view
@@ -122,6 +122,7 @@     , graph     , remote     , toHeaders+    , substitutions     , normalizer     , startingContext     , chainImport@@ -150,10 +151,6 @@ import Data.Semigroup (Semigroup(..)) import Data.Text (Text) import Data.Void (Void, absurd)-#if MIN_VERSION_base(4,8,0)-#else-import Data.Traversable (traverse)-#endif import Data.Typeable (Typeable) import System.FilePath ((</>)) import Dhall.Binary (StandardVersion(..))@@ -198,6 +195,7 @@ import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty.Internal+import qualified Dhall.Substitution import qualified Dhall.TypeCheck import qualified System.AtomicWrite.Writer.ByteString.Binary as AtomicWrite.Binary import qualified System.Environment@@ -607,9 +605,11 @@             return importSemantics          Nothing -> do-            betaNormal <- case Dhall.TypeCheck.typeWith _startingContext resolvedExpr of-                Left  err -> throwMissingImport (Imported _stack err)-                Right _ -> return (Dhall.Core.normalizeWith _normalizer resolvedExpr)+            betaNormal <- do+                let substitutedExpr = Dhall.Substitution.substitute resolvedExpr _substitutions+                case Dhall.TypeCheck.typeWith _startingContext substitutedExpr of+                    Left  err -> throwMissingImport (Imported _stack err)+                    Right _ -> return (Dhall.Core.normalizeWith _normalizer resolvedExpr)              let bytes = encodeExpression NoVersion betaNormal             lift $ writeToSemisemanticCache semisemanticHash bytes@@ -1078,7 +1078,7 @@   Record a             -> Record <$> mapM loadWith a   RecordLit a          -> RecordLit <$> mapM loadWith a   Union a              -> Union <$> mapM (mapM loadWith) a-  Combine a b          -> Combine <$> loadWith a <*> loadWith b+  Combine m a b        -> Combine m <$> loadWith a <*> loadWith b   CombineTypes a b     -> CombineTypes <$> loadWith a <*> loadWith b   Prefer a b           -> Prefer <$> loadWith a <*> loadWith b   RecordCompletion a b -> RecordCompletion <$> loadWith a <*> loadWith b
src/Dhall/Import/Types.hs view
@@ -36,6 +36,7 @@  import qualified Dhall.Context import qualified Dhall.Map     as Map+import qualified Dhall.Substitution import qualified Data.Text  -- | A fully 'chained' import, i.e. if it contains a relative path that path is@@ -90,6 +91,8 @@     , _remote :: URL -> StateT Status IO Data.Text.Text     -- ^ The remote resolver, fetches the content at the given URL. +    , _substitutions :: Dhall.Substitution.Substitutions Src Void+     , _normalizer :: Maybe (ReifiedNormalizer Void)      , _startingContext :: Context (Expr Src Void)@@ -110,6 +113,8 @@      _manager = Nothing +    _substitutions = Dhall.Substitution.empty+     _normalizer = Nothing      _startingContext = Dhall.Context.empty@@ -149,6 +154,11 @@ remote     :: Functor f => LensLike' f Status (URL -> StateT Status IO Data.Text.Text) remote k s = fmap (\x -> s { _remote = x }) (k (_remote s))++-- | Lens from a `Status` to its `_substitutions` field+substitutions :: Functor f => LensLike' f Status (Dhall.Substitution.Substitutions Src Void)+substitutions k s =+    fmap (\x -> s { _substitutions = x }) (k (_substitutions s))  -- | Lens from a `Status` to its `_normalizer` field normalizer :: Functor f => LensLike' f Status (Maybe (ReifiedNormalizer Void))
src/Dhall/Lint.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE NamedFieldPuns    #-}+{-# LANGUAGE OverloadedLists   #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternGuards     #-} {-# LANGUAGE RecordWildCards   #-}@@ -12,12 +13,16 @@     , removeUnusedBindings     , fixAssert     , fixParentPath+    , removeLetInLet+    , replaceOptionalBuildFold+    , replaceSaturatedOptionalFold     ) where  import Control.Applicative ((<|>))  import Dhall.Syntax     ( Binding(..)+    , Const(..)     , Directory(..)     , Expr(..)     , File(..)@@ -42,16 +47,21 @@     * fixes @let a = x ≡ y@ to be @let a = assert : x ≡ y@     * consolidates nested @let@ bindings to use a multiple-@let@ binding with 'removeLetInLet'     * fixes paths of the form @.\/..\/foo@ to @..\/foo@+    * Replaces deprecated @Optional\/fold@ and @Optional\/build@ built-ins -} lint :: Expr s Import -> Expr s Import-lint = Dhall.Optics.rewriteOf subExpressions rewrite+lint =  Dhall.Optics.rewriteOf subExpressions lowerPriorityRewrite+    .   Dhall.Optics.rewriteOf subExpressions higherPriorityRewrite   where-    rewrite e =-            fixAssert            e-        <|> removeUnusedBindings e-        <|> fixParentPath        e-        <|> removeLetInLet       e+    lowerPriorityRewrite e =+            fixAssert                e+        <|> removeUnusedBindings     e+        <|> fixParentPath            e+        <|> removeLetInLet           e+        <|> replaceOptionalBuildFold e +    higherPriorityRewrite = replaceSaturatedOptionalFold+ -- | Remove unused `Let` bindings. removeUnusedBindings :: Eq a => Expr s a -> Maybe (Expr s a) -- Don't remove assertions!@@ -102,7 +112,7 @@ isOrContainsAssert (Assert _) = True isOrContainsAssert e = Lens.Family.anyOf subExpressions isOrContainsAssert e --- The difference between+-- | The difference between -- -- > let x = 1 let y = 2 in x + y --@@ -117,3 +127,65 @@ removeLetInLet :: Expr s a -> Maybe (Expr s a) removeLetInLet (Let binding (Note _ l@Let{})) = Just (Let binding l) removeLetInLet _ = Nothing++-- | This replaces @Optional/fold@ and @Optional/build@, both of which can be+-- implemented within the language+replaceOptionalBuildFold :: Expr s a -> Maybe (Expr s a)+replaceOptionalBuildFold OptionalBuild =+    Just+        (Lam "a" (Const Type)+            (Lam "build"+                (Pi "optional" (Const Type)+                    (Pi "some" (Pi "_" "a" "optional")+                        (Pi "none" "optional" "optional")+                    )+                )+                (App (App (App "build" (App Optional "a")) (Lam "x" "a" (Some "x"))) (App None "a"))+            )+        )+replaceOptionalBuildFold OptionalFold =+    Just+        (Lam "a" (Const Type)+            (Lam "o" (App Optional "a")+                (Lam "optional" (Const Type)+                    (Lam "some" (Pi "_" "a" "optional")+                        (Lam "none" "optional"+                            (Merge+                                (RecordLit+                                    [ ("Some", "some")+                                    , ("None", "none")+                                    ]+                                )+                                "o"+                                Nothing+                            )+                        )+                    )+                )+            )+        )+replaceOptionalBuildFold _ =+    Nothing++-- | This replaces a saturated @Optional/fold@ with the equivalent @merge@+-- expression+replaceSaturatedOptionalFold :: Expr s a -> Maybe (Expr s a)+replaceSaturatedOptionalFold+    (App+        (Core.shallowDenote -> App+            (Core.shallowDenote -> App+                (Core.shallowDenote -> App+                    (Core.shallowDenote -> App+                        (Core.shallowDenote -> OptionalFold)+                        _+                    )+                    o+                )+                _+            )+            some+        )+        none+    ) = Just (Merge (RecordLit [ ("Some", some), ("None", none) ]) o Nothing)+replaceSaturatedOptionalFold _ =+    Nothing
src/Dhall/Main.hs view
@@ -16,38 +16,47 @@     , parserInfoOptions        -- * Execution-    , command+    , Dhall.Main.command     , main     ) where  import Control.Applicative (optional, (<|>)) import Control.Exception (Handler(..), SomeException) import Control.Monad (when)+import Data.Bifunctor (first) import Data.List.NonEmpty (NonEmpty(..)) import Data.Monoid ((<>)) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty) import Data.Void (Void)-import Dhall.Core-    ( Expr(Annot)-    , Import(..)-    , ImportHashed(..)-    , ImportType(..)-    , URL(..)-    , pretty-    ) import Dhall.Freeze (Intent(..), Scope(..)) import Dhall.Import (Imported(..), Depends(..), SemanticCacheMode(..), _semanticCacheMode) import Dhall.Parser (Src) import Dhall.Pretty (Ann, CharacterSet(..), annToAnsiStyle) import Dhall.TypeCheck (Censored(..), DetailedTypeError(..), TypeError)-import Dhall.Util (Censor(..), Header (..), Input(..), Output(..)) import Dhall.Version (dhallVersionString) import Options.Applicative (Parser, ParserInfo) import System.Exit (ExitCode, exitFailure) import System.IO (Handle) import Text.Dot ((.->.)) +import Dhall.Core+    ( Expr(Annot)+    , Import(..)+    , ImportHashed(..)+    , ImportType(..)+    , URL(..)+    , pretty+    )+import Dhall.Util+    ( Censor(..)+    , CheckFailed(..)+    , Header (..)+    , Input(..)+    , OutputMode(..)+    , Output(..)+    )+ import qualified Codec.CBOR.JSON import qualified Codec.CBOR.Read import qualified Codec.CBOR.Write@@ -73,6 +82,7 @@ import qualified Dhall.Import import qualified Dhall.Import.Types import qualified Dhall.Lint+import qualified Dhall.Parser                              as Parser import qualified Dhall.Map import qualified Dhall.Tags import qualified Dhall.Pretty@@ -127,11 +137,11 @@           }     | Normalize { file :: Input , alpha :: Bool }     | Repl-    | Format { formatMode :: Dhall.Format.FormatMode }-    | Freeze { inplace :: Input, all_ :: Bool, cache :: Bool }+    | Format { input :: Input, outputMode :: OutputMode }+    | Freeze { input :: Input, all_ :: Bool, cache :: Bool, outputMode :: OutputMode }     | Hash { file :: Input }     | Diff { expr1 :: Text, expr2 :: Text }-    | Lint { inplace :: Input }+    | Lint { input :: Input, outputMode :: OutputMode }     | Tags           { input :: Input           , output :: Output@@ -224,7 +234,7 @@     <|> subcommand             "lint"             "Improve Dhall code by using newer language features and removing dead code"-            (Lint <$> parseInplace)+            (Lint <$> parseInplace <*> parseCheck)     <|> subcommand             "tags"             "Generate etags file"@@ -232,11 +242,11 @@     <|> subcommand             "format"             "Standard code formatter for the Dhall language"-            (Format <$> parseFormatMode)+            (Format <$> parseInplace <*> parseCheck)     <|> subcommand             "freeze"             "Add integrity checks to remote import statements of an expression"-            (Freeze <$> parseInplace <*> parseAllFlag <*> parseCacheFlag)+            (Freeze <$> parseInplace <*> parseAllFlag <*> parseCacheFlag <*> parseCheck)     <|> subcommand             "encode"             "Encode a Dhall expression to binary"@@ -415,12 +425,17 @@         <>  Options.Applicative.help "Add fallback unprotected imports when using integrity checks purely for caching purposes"         ) -    parseCheck =-        Options.Applicative.switch-        (   Options.Applicative.long "check"-        <>  Options.Applicative.help "Only check if the input is formatted"-        )+    parseCheck = fmap adapt switch+      where+        adapt True  = Check+        adapt False = Write +        switch =+            Options.Applicative.switch+            (   Options.Applicative.long "check"+            <>  Options.Applicative.help "Only check if the input is formatted"+            )+     parseDirectoryTreeOutput =         Options.Applicative.strOption             (   Options.Applicative.long "output"@@ -428,11 +443,6 @@             <>  Options.Applicative.metavar "PATH"             ) -    parseFormatMode = adapt <$> parseCheck <*> parseInplace-      where-        adapt True  path    = Dhall.Format.Check {..}-        adapt False inplace = Dhall.Format.Modify {..}- -- | `ParserInfo` for the `Options` type parserInfoOptions :: ParserInfo Options parserInfoOptions =@@ -686,7 +696,7 @@              let intent = if cache then Cache else Secure -            Dhall.Freeze.freeze inplace scope intent characterSet censor+            Dhall.Freeze.freeze outputMode input scope intent characterSet censor          Hash {..} -> do             expression <- getExpression file@@ -702,18 +712,49 @@             Data.Text.IO.putStrLn (Dhall.Import.hashExpressionToCode normalizedExpression)          Lint {..} -> do-            (Header header, expression) <- getExpressionAndHeader inplace+            case outputMode of+                Write -> do+                    (Header header, expression) <- do+                        getExpressionAndHeader input -            let lintedExpression = Dhall.Lint.lint expression+                    let lintedExpression = Dhall.Lint.lint expression -            let doc =   Pretty.pretty header-                    <>  Dhall.Pretty.prettyCharacterSet characterSet lintedExpression+                    let doc =   Pretty.pretty header+                            <>  Dhall.Pretty.prettyCharacterSet characterSet lintedExpression -            case inplace of-                InputFile file -> writeDocToFile file doc+                    case input of+                        InputFile file -> writeDocToFile file doc -                StandardInput -> renderDoc System.IO.stdout doc+                        StandardInput -> renderDoc System.IO.stdout doc +                Check -> do+                    originalText <- case input of+                        InputFile file -> Data.Text.IO.readFile file+                        StandardInput  -> Data.Text.IO.getContents++                    let name = case input of+                            InputFile file -> file+                            StandardInput  -> "(stdin)"++                    (Header header, expression) <- do+                        Dhall.Core.throws (first Parser.censor (Parser.exprAndHeaderFromText name originalText))++                    let lintedExpression = Dhall.Lint.lint expression++                    let doc =   Pretty.pretty header+                            <>  Dhall.Pretty.prettyCharacterSet characterSet lintedExpression++                    let stream = Dhall.Pretty.layout doc++                    let modifiedText = Pretty.Text.renderStrict stream <> "\n"++                    if originalText == modifiedText+                        then return ()+                        else do+                            let modified = "linted"++                            Control.Exception.throwIO CheckFailed{ command = "lint", ..}+         Encode {..} -> do             expression <- getExpression file @@ -813,4 +854,5 @@ main :: IO () main = do     options <- Options.Applicative.execParser parserInfoOptions-    command options++    Dhall.Main.command options
src/Dhall/Map.hs view
@@ -80,6 +80,7 @@ import qualified Data.Map import qualified Data.Set import qualified GHC.Exts+import qualified Language.Haskell.TH.Syntax as Syntax import qualified Prelude  {-| A `Map` that remembers the original ordering of keys@@ -92,14 +93,16 @@ data Map k v = Map (Data.Map.Map k v) (Keys k)     deriving (Data, Generic, NFData) -instance (Data k, Data v, Lift k, Lift v, Ord k) => Lift (Map k v)+instance (Data k, Data v, Lift k, Lift v, Ord k) => Lift (Map k v) where+    lift = Syntax.liftData  data Keys a     = Sorted     | Original [a]     deriving (Data, Generic, NFData) -instance (Data a, Lift a) => Lift (Keys a)+instance (Data a, Lift a) => Lift (Keys a) where+    lift = Syntax.liftData  instance (Ord k, Eq v) => Eq (Map k v) where   m1 == m2 =
src/Dhall/Normalize.hs view
@@ -232,10 +232,10 @@ shift d v (Union a) = Union a'   where     a' = fmap (fmap (shift d v)) a-shift d v (Combine a b) = Combine a' b'+shift d v (Combine a b c) = Combine a b' c'   where-    a' = shift d v a     b' = shift d v b+    c' = shift d v c shift d v (CombineTypes a b) = CombineTypes a' b'   where     a' = shift d v a@@ -407,10 +407,10 @@ subst x e (Union kts) = Union kts'   where     kts' = fmap (fmap (subst x e)) kts-subst x e (Combine a b) = Combine a' b'+subst x e (Combine a b c) = Combine a b' c'   where-    a' = subst x e a     b' = subst x e b+    c' = subst x e c subst x e (CombineTypes a b) = CombineTypes a' b'   where     a' = subst x e a@@ -864,7 +864,7 @@     Union kts -> Union . Dhall.Map.sort <$> kts'       where         kts' = traverse (traverse loop) kts-    Combine x y -> decide <$> loop x <*> loop y+    Combine mk x y -> decide <$> loop x <*> loop y       where         decide (RecordLit m) r | Data.Foldable.null m =             r@@ -873,7 +873,7 @@         decide (RecordLit m) (RecordLit n) =             RecordLit (Dhall.Map.unionWith decide m n)         decide l r =-            Combine l r+            Combine mk l r     CombineTypes x y -> decide <$> loop x <*> loop y       where         decide (Record m) r | Data.Foldable.null m =@@ -972,11 +972,11 @@             Prefer l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of                 Just v -> pure v                 Nothing -> loop (Field l x)-            Combine (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of-                Just v -> pure (Field (Combine (singletonRecordLit v) r_) x)+            Combine m (RecordLit kvs) r_ -> case Dhall.Map.lookup x kvs of+                Just v -> pure (Field (Combine m (singletonRecordLit v) r_) x)                 Nothing -> loop (Field r_ x)-            Combine l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of-                Just v -> pure (Field (Combine l (singletonRecordLit v)) x)+            Combine m l (RecordLit kvs) -> case Dhall.Map.lookup x kvs of+                Just v -> pure (Field (Combine m l (singletonRecordLit v)) x)                 Nothing -> loop (Field l x)             _ -> pure (Field r' x)     Project x (Left fields)-> do@@ -1180,7 +1180,7 @@       Record kts -> Dhall.Map.isSorted kts && all loop kts       RecordLit kvs -> Dhall.Map.isSorted kvs && all loop kvs       Union kts -> Dhall.Map.isSorted kts && all (all loop) kts-      Combine x y -> loop x && loop y && decide x y+      Combine _ x y -> loop x && loop y && decide x y         where           decide (RecordLit m) _ | Data.Foldable.null m = False           decide _ (RecordLit n) | Data.Foldable.null n = False@@ -1215,8 +1215,8 @@           Project _ _ -> False           Prefer (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r           Prefer _ (RecordLit _) -> False-          Combine (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r-          Combine _ (RecordLit m) -> Dhall.Map.keys m == [k] && loop r+          Combine _ (RecordLit m) _ -> Dhall.Map.keys m == [k] && loop r+          Combine _ _ (RecordLit m) -> Dhall.Map.keys m == [k] && loop r           _ -> loop r       Project r p -> loop r &&           case p of
src/Dhall/Parser.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP             #-} {-# LANGUAGE RecordWildCards #-}  -- | This module contains Dhall's parsing logic
src/Dhall/Parser/Combinators.hs view
@@ -257,3 +257,11 @@      err k _v1 _v2 = Text.Parser.Combinators.unexpected                         ("duplicate field: " ++ Data.Text.unpack k)++toMapWith+    :: (Text -> Parser a -> Parser a -> Parser a)+    -> [(Text, a)]+    -> Parser (Map Text a)+toMapWith combine kvs = sequence m+  where+    m = Dhall.Map.fromListWithKey combine (map (\(k, v) -> (k, pure v)) kvs)
src/Dhall/Parser/Expression.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP                 #-} {-# LANGUAGE NamedFieldPuns      #-} {-# LANGUAGE RecordWildCards     #-} {-# LANGUAGE OverloadedLists     #-}@@ -8,7 +7,7 @@ -- | Parsing Dhall expressions. module Dhall.Parser.Expression where -import Control.Applicative (Alternative(..), optional)+import Control.Applicative (liftA2, Alternative(..), optional) import Data.ByteArray.Encoding (Base(..)) import Data.Foldable (foldl') import Data.Functor (void)@@ -20,11 +19,12 @@ import Text.Parser.Combinators (choice, try, (<?>))  import qualified Control.Monad+import qualified Control.Monad.Combinators.NonEmpty as Combinators.NonEmpty import qualified Data.ByteArray.Encoding import qualified Data.ByteString-import qualified Data.Char               as Char+import qualified Data.Char                          as Char import qualified Data.List-import qualified Data.List.NonEmpty+import qualified Data.List.NonEmpty                 as NonEmpty import qualified Data.Sequence import qualified Data.Text import qualified Data.Text.Encoding@@ -184,7 +184,7 @@                      return (Binding (Just src0) c (Just src1) d (Just src3) f) -            as <- Data.List.NonEmpty.some1 binding+            as <- NonEmpty.some1 binding              try (_in *> nonemptyWhitespace) @@ -277,19 +277,19 @@      operatorParsers :: [Parser (Expr s a -> Expr s a -> Expr s a)]     operatorParsers =-        [ ImportAlt    <$ _importAlt    <* nonemptyWhitespace-        , BoolOr       <$ _or           <* whitespace-        , NaturalPlus  <$ _plus         <* nonemptyWhitespace-        , TextAppend   <$ _textAppend   <* whitespace-        , ListAppend   <$ _listAppend   <* whitespace-        , BoolAnd      <$ _and          <* whitespace-        , Combine      <$ _combine      <* whitespace-        , Prefer       <$ _prefer       <* whitespace-        , CombineTypes <$ _combineTypes <* whitespace-        , NaturalTimes <$ _times        <* whitespace-        , BoolEQ       <$ _doubleEqual  <* whitespace-        , BoolNE       <$ _notEqual     <* whitespace-        , Equivalent   <$ _equivalent   <* whitespace+        [ ImportAlt       <$ _importAlt    <* nonemptyWhitespace+        , BoolOr          <$ _or           <* whitespace+        , NaturalPlus     <$ _plus         <* nonemptyWhitespace+        , TextAppend      <$ _textAppend   <* whitespace+        , ListAppend      <$ _listAppend   <* whitespace+        , BoolAnd         <$ _and          <* whitespace+        , Combine Nothing <$ _combine      <* whitespace+        , Prefer          <$ _prefer       <* whitespace+        , CombineTypes    <$ _combineTypes <* whitespace+        , NaturalTimes    <$ _times        <* whitespace+        , BoolEQ          <$ _doubleEqual  <* whitespace+        , BoolNE          <$ _notEqual     <* whitespace+        , Equivalent      <$ _equivalent   <* whitespace         ]      applicationExpression = do@@ -695,12 +695,8 @@             alternative2 = return (Record mempty)      nonEmptyRecordTypeOrLiteral = do-            a <- anyLabel--            whitespace-             let nonEmptyRecordType = do-                    _colon+                    a <- try (anyLabel <* whitespace <* _colon)                      nonemptyWhitespace @@ -731,35 +727,45 @@                      return (Record m) -            let nonEmptyRecordLiteral = do-                    _equal+            let keysValue = do+                    keys <- Combinators.NonEmpty.sepBy1 anyLabel (try (whitespace *> _dot) *> whitespace)                      whitespace -                    b <- expression+                    _equal                      whitespace -                    e <- Text.Megaparsec.many (do-                        _comma+                    value <- expression -                        whitespace+                    whitespace -                        c <- anyLabel+                    let cons key (key', values) =+                            (key, RecordLit [ (key', values) ]) -                        whitespace+                    let nil = (NonEmpty.last keys, value) -                        _equal+                    return (foldr cons nil (NonEmpty.init keys)) -                        whitespace+            let nonEmptyRecordLiteral = do+                    (a, b) <- keysValue -                        d <- expression+                    e <- Text.Megaparsec.many (do+                        _comma                          whitespace +                        (c, d) <- keysValue+                         return (c, d) ) -                    m <- toMap ((a, b) : e)+                    {- The `flip` is necessary because `toMapWith` is internally+                       based on `Data.Map.fromListWithKey` which combines keys+                       in reverse order+                    -}+                    let combine k = liftA2 (flip (Combine (Just k)))++                    m <- toMapWith combine ((a, b) : e)                      return (RecordLit m) 
src/Dhall/Parser/Token.hs view
@@ -111,7 +111,7 @@  import Control.Applicative (Alternative(..), optional) import Data.Bits ((.&.))-import Data.Functor (void)+import Data.Functor (void, ($>)) import Data.Semigroup (Semigroup(..)) import Data.Text (Text) import Dhall.Syntax@@ -121,6 +121,7 @@  import qualified Control.Monad import qualified Data.Char                  as Char+import qualified Data.Foldable import qualified Data.HashSet import qualified Data.List.NonEmpty import qualified Data.Text@@ -134,8 +135,6 @@ import Numeric.Natural (Natural) import Prelude hiding (const, pi) -import qualified Text.Parser.Token- -- | Returns `True` if the given `Int` is a valid Unicode codepoint validCodepoint :: Int -> Bool validCodepoint c =@@ -191,7 +190,7 @@ doubleLiteral :: Parser Double doubleLiteral = (do     sign <- signPrefix <|> pure id-    a <- Text.Parser.Token.double+    a <- Text.Megaparsec.Char.Lexer.float     return (sign a) ) <?> "literal"  {-| Parse a signed @Infinity@@@ -223,8 +222,29 @@ naturalLiteral :: Parser Natural naturalLiteral = (do     a <-    try (char '0' >> char 'x' >> Text.Megaparsec.Char.Lexer.hexadecimal)-        <|> Text.Megaparsec.Char.Lexer.decimal+        <|> decimal+        <|> (char '0' $> 0)     return a ) <?> "literal"+  where+    decimal = do+        n <- headDigit+        ns <- many tailDigit+        return (mkNum (n:ns))+      where+        headDigit = decimalDigit nonZeroDigit <?> "non-zero digit"+          where+            nonZeroDigit c = '1' <= c && c <= '9'++        tailDigit = decimalDigit digit <?> "digit"++        decimalDigit predicate = do+            c <- Text.Parser.Char.satisfy predicate+            return (fromIntegral (Char.ord c - Char.ord '0'))++        mkNum = Data.Foldable.foldl' step 0+          where+            step acc x = acc * 10 + x+  {-| Parse an identifier (i.e. a variable or built-in) 
src/Dhall/Pretty/Internal.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP               #-} {-# LANGUAGE LambdaCase        #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards   #-}@@ -64,11 +63,8 @@     , rparen     ) where -#if MIN_VERSION_base(4,8,0)-#else-import Control.Applicative (Applicative(..), (<$>))-#endif import Data.Foldable+import Data.List.NonEmpty (NonEmpty) import Data.Monoid ((<>)) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty, space)@@ -83,12 +79,13 @@ import qualified Data.Char import qualified Data.HashSet import qualified Data.List+import qualified Data.List.NonEmpty                      as NonEmpty import qualified Data.Set import qualified Data.Text                               as Text import qualified Data.Text.Prettyprint.Doc               as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Text   as Pretty import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty-import qualified Dhall.Map+import qualified Dhall.Map                               as Map import qualified Dhall.Set  {-| Annotation type used to tag elements in a pretty-printed document for@@ -441,6 +438,10 @@ prettyAnyLabel :: Text -> Doc Ann prettyAnyLabel = prettyLabelShared True +prettyAnyLabels :: NonEmpty Text -> Doc Ann+prettyAnyLabels =+    mconcat . Pretty.punctuate dot . fmap prettyAnyLabel . toList+ prettyLabels :: Set Text -> Doc Ann prettyLabels a     | Data.Set.null (Dhall.Set.toSet a) =@@ -810,12 +811,12 @@        prettyCombineExpression a0      prettyCombineExpression :: Pretty a => Expr Src a -> Doc Ann-    prettyCombineExpression a0@(Combine _ _) =+    prettyCombineExpression a0@(Combine _ _ _) =         prettyOperator (combine characterSet) (docs a0)       where-        docs (Combine a b) = prettyPreferExpression b : docs a-        docs (Note    _ b) = docs b-        docs            b  = [ prettyPreferExpression b ]+        docs (Combine _ a b) = prettyPreferExpression b : docs a+        docs (Note      _ b) = docs b+        docs              b  = [ prettyPreferExpression b ]     prettyCombineExpression (Note _ a) =         prettyCombineExpression a     prettyCombineExpression a0 =@@ -1053,8 +1054,9 @@          short = lparen <> prettyExpression a <> rparen -    prettyKeyValue :: Pretty a => Doc Ann -> (Text, Expr Src a) -> (Doc Ann, Doc Ann)-    prettyKeyValue separator (key, val) =+    prettyKeyValue+        :: Pretty a => (k -> Doc Ann) -> Doc Ann -> (k, Expr Src a) -> (Doc Ann, Doc Ann)+    prettyKeyValue prettyKey separator (key, val) =         duplicate (Pretty.group (Pretty.flatAlt long short))       where         completion _T r =@@ -1067,25 +1069,38 @@                     _ ->                         prettySelectorExpression r -        short = prettyAnyLabel key+        short = prettyKey key             <>  " "             <>  separator             <>  " "             <>  prettyExpression val          long =-                prettyAnyLabel key+                prettyKey key             <>  " "             <>  separator             <>  case shallowDenote val of                     Some val' ->-                            " Some"+                            " " <> builtin "Some"                         <>  case shallowDenote val' of                                 RecordCompletion _T r ->                                     completion _T r+                                ListLit _ xs+                                    | not (null xs) ->+                                            Pretty.hardline+                                        <>  "  "+                                        <>  prettyExpression val'                                 _ ->    Pretty.hardline                                     <>  "    "                                     <>  prettyImportExpression val'+                    ToMap val' Nothing ->+                            " " <> keyword "toMap"+                        <>  case shallowDenote val' of+                                RecordCompletion _T r ->+                                    completion _T r+                                _ ->    Pretty.hardline+                                    <>  "    "+                                    <>  prettyImportExpression val'                     RecordCompletion _T r ->                         completion _T r                     ListLit _ xs@@ -1100,29 +1115,37 @@      prettyRecord :: Pretty a => Map Text (Expr Src a) -> Doc Ann     prettyRecord =-        braces . map (prettyKeyValue colon) . Dhall.Map.toList+        braces . map (prettyKeyValue prettyAnyLabel colon) . Map.toList      prettyRecordLit :: Pretty a => Map Text (Expr Src a) -> Doc Ann     prettyRecordLit a         | Data.Foldable.null a =             lbrace <> equals <> rbrace         | otherwise =-            braces (map (prettyKeyValue equals) (Dhall.Map.toList a))+            braces (map prettyRecordEntry (Map.toList consolidated))+      where+        consolidated = consolidateRecordLiteral a +        prettyRecordEntry = prettyKeyValue prettyAnyLabels equals+     prettyCompletionLit         :: Pretty a => Int -> Map Text (Expr Src a) -> Doc Ann     prettyCompletionLit n a         | Data.Foldable.null a =             lbrace <> equals <> rbrace         | otherwise =-            hangingBraces n (map (prettyKeyValue equals) (Dhall.Map.toList a))+            hangingBraces n (map prettyRecordEntry (Map.toList consolidated))+      where+        consolidated = consolidateRecordLiteral a -    prettyAlternative (key, Just val) = prettyKeyValue colon (key, val)+        prettyRecordEntry = prettyKeyValue prettyAnyLabels equals++    prettyAlternative (key, Just val) = prettyKeyValue prettyAnyLabel colon (key, val)     prettyAlternative (key, Nothing ) = duplicate (prettyAnyLabel key)      prettyUnion :: Pretty a => Map Text (Maybe (Expr Src a)) -> Doc Ann     prettyUnion =-        angles . map prettyAlternative . Dhall.Map.toList+        angles . map prettyAlternative . Map.toList      prettyChunks :: Pretty a => Chunks Src a -> Doc Ann     prettyChunks chunks@(Chunks a b)@@ -1281,6 +1304,25 @@ -- | Pretty-print a value pretty_ :: Pretty a => a -> Text pretty_ = prettyToStrictText++{- This utility function converts+   `{ x = { y = { z = 1 } } }` to `{ x.y.z. = 1 }`+-}+consolidateRecordLiteral+    :: Map Text (Expr s a) -> Map (NonEmpty Text) (Expr s a)+consolidateRecordLiteral = Map.fromList . fmap adapt . Map.toList+  where+    adapt :: (Text, Expr s a) -> (NonEmpty Text, Expr s a)+    adapt (key, expression) =+        case shallowDenote expression of+            RecordLit m ->+                case fmap adapt (Map.toList m) of+                    [ (keys, expression') ] ->+                        (NonEmpty.cons key keys, expression')+                    _ ->+                        (pure key, RecordLit m)+            _ ->+                (pure key, expression)  -- | Escape a `Text` literal using Dhall's escaping rules for single-quoted --   @Text@
src/Dhall/Repl.hs view
@@ -124,7 +124,7 @@   :: MonadIO m => String -> m ( Dhall.Expr Dhall.Src Void)  parseAndLoad src = do   parsed <--    case Dhall.exprFromText "(stdin)" ( Text.pack src ) of+    case Dhall.exprFromText "(stdin)" (Text.pack src <> "\n") of       Left e ->         liftIO ( throwIO e ) 
src/Dhall/Set.hs view
@@ -36,6 +36,7 @@ import qualified Data.Set import qualified Data.Sequence import qualified Data.Foldable+import qualified Language.Haskell.TH.Syntax as Syntax  {-| This is a variation on @"Data.Set".`Data.Set.Set`@ that remembers the     original order of elements.  This ensures that ordering is not lost when@@ -53,7 +54,8 @@     compare (Set _ x) (Set _ y) = compare x y     {-# INLINABLE compare #-} -instance (Data a, Lift a, Ord a) => Lift (Set a)+instance (Data a, Lift a, Ord a) => Lift (Set a) where+    lift = Syntax.liftData  instance Foldable Set where     foldMap f (Set _ x) = foldMap f x
+ src/Dhall/Substitution.hs view
@@ -0,0 +1,34 @@+{- | This module provides types and functions used in the substitution step+     which is done before type checking and normalization.+-}++module Dhall.Substitution where++import Data.Text (Text)+import Dhall.Normalize (subst)+import Dhall.Syntax (Expr, Var(..))++import qualified Dhall.Map++{- | Substitutions map variables to arbitrary Dhall expressions.+     Note that we use "Dhall.Map.Map" as an underlying structure. Hence we respect insertion order.+-}+type Substitutions s a = Dhall.Map.Map Text (Expr s a)++{- | An empty substitution map.+-}+empty :: Substitutions s a+empty = Dhall.Map.empty++-- | @substitute expr s@ replaces all variables in @expr@ (or its subexpression) with their substitute.+--   For example, if the substitution map maps the variable @Foo@ to the text \"Foo\" all occurrences of @Foo@ with the text \"Foo\".+--+--   The substitutions will be done in the order they are inserted into the substitution map:+--+--   > {-# LANGUAGE OverloadedStrings #-}+--   >+--   > substitute (Dhall.Core.Var "Foo") (Dhall.Map.fromList [("Foo", Dhall.Core.Var "Bar"), ("Bar", Dhall.Core.Var "Baz")])+--+--   results in @Dhall.Core.Var \"Baz\"@ since we first substitute \"Foo\" with \"Bar\" and then the resulting \"Bar\" with the final \"Baz\".+substitute :: Expr s a -> Substitutions s a -> Expr s a+substitute expr = foldl (\memo (k, v) -> subst (V k 0) v memo) expr . Dhall.Map.toList
src/Dhall/Syntax.hs view
@@ -93,9 +93,10 @@ import qualified Data.HashSet import qualified Data.List.NonEmpty import qualified Data.Text-import qualified Data.Text.Prettyprint.Doc    as Pretty+import qualified Data.Text.Prettyprint.Doc  as Pretty import qualified Dhall.Crypto-import qualified Network.URI                  as URI+import qualified Language.Haskell.TH.Syntax as Syntax+import qualified Network.URI                as URI  {-| Constants for a pure type system @@ -119,7 +120,8 @@ data Const = Type | Kind | Sort     deriving (Show, Eq, Ord, Data, Bounded, Enum, Generic, NFData) -instance Lift Const+instance Lift Const where+    lift = Syntax.liftData  instance Pretty Const where     pretty = Pretty.unAnnotate . prettyConst@@ -159,7 +161,8 @@ data Var = V Text !Int     deriving (Data, Generic, Eq, Ord, Show, NFData) -instance Lift Var+instance Lift Var where+    lift = Syntax.liftData  instance IsString Var where     fromString str = V (fromString str) 0@@ -238,7 +241,8 @@ data Chunks s a = Chunks [(Text, Expr s a)] Text     deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Ord, Data, NFData) -instance (Lift s, Lift a, Data s, Data a) => Lift (Chunks s a)+instance (Lift s, Lift a, Data s, Data a) => Lift (Chunks s a) where+    lift = Syntax.liftData  instance Data.Semigroup.Semigroup (Chunks s a) where     Chunks xysL zL <> Chunks         []    zR =@@ -415,8 +419,13 @@     | RecordLit (Map Text (Expr s a))     -- | > Union        [(k1, Just t1), (k2, Nothing)] ~  < k1 : t1 | k2 >     | Union     (Map Text (Maybe (Expr s a)))-    -- | > Combine x y                              ~  x ∧ y-    | Combine (Expr s a) (Expr s a)+    -- | > Combine Nothing x y                      ~  x ∧ y+    --+    -- The first field is a `Just` when the `Combine` operator is introduced+    -- as a result of desugaring duplicate record fields:+    --+    --   > RecordLit [ (k, Combine (Just k) x y) ]  ~ { k = x, k = y }+    | Combine (Maybe Text) (Expr s a) (Expr s a)     -- | > CombineTypes x y                         ~  x ⩓ y     | CombineTypes (Expr s a) (Expr s a)     -- | > Prefer x y                               ~  x ⫽ y@@ -461,7 +470,8 @@ -- | Note that this 'Ord' instance inherits `DhallDouble`'s defects. deriving instance (Ord s, Ord a) => Ord (Expr s a) -instance (Lift s, Lift a, Data s, Data a) => Lift (Expr s a)+instance (Lift s, Lift a, Data s, Data a) => Lift (Expr s a) where+    lift = Syntax.liftData  -- This instance is hand-written due to the fact that deriving -- it does not give us an INLINABLE pragma. We annotate this fmap@@ -525,7 +535,7 @@   fmap f (Record r) = Record (fmap (fmap f) r)   fmap f (RecordLit r) = RecordLit (fmap (fmap f) r)   fmap f (Union u) = Union (fmap (fmap (fmap f)) u)-  fmap f (Combine e1 e2) = Combine (fmap f e1) (fmap f e2)+  fmap f (Combine m e1 e2) = Combine m (fmap f e1) (fmap f e2)   fmap f (CombineTypes e1 e2) = CombineTypes (fmap f e1) (fmap f e2)   fmap f (Prefer e1 e2) = Prefer (fmap f e1) (fmap f e2)   fmap f (RecordCompletion e1 e2) = RecordCompletion (fmap f e1) (fmap f e2)@@ -610,7 +620,7 @@     Record    a          >>= k = Record (fmap (>>= k) a)     RecordLit a          >>= k = RecordLit (fmap (>>= k) a)     Union     a          >>= k = Union (fmap (fmap (>>= k)) a)-    Combine a b          >>= k = Combine (a >>= k) (b >>= k)+    Combine a b c        >>= k = Combine a (b >>= k) (c >>= k)     CombineTypes a b     >>= k = CombineTypes (a >>= k) (b >>= k)     Prefer a b           >>= k = Prefer (a >>= k) (b >>= k)     RecordCompletion a b >>= k = RecordCompletion (a >>= k) (b >>= k)@@ -682,7 +692,7 @@     first k (Record a            ) = Record (fmap (first k) a)     first k (RecordLit a         ) = RecordLit (fmap (first k) a)     first k (Union a             ) = Union (fmap (fmap (first k)) a)-    first k (Combine a b         ) = Combine (first k a) (first k b)+    first k (Combine a b c       ) = Combine a (first k b) (first k c)     first k (CombineTypes a b    ) = CombineTypes (first k a) (first k b)     first k (Prefer a b          ) = Prefer (first k a) (first k b)     first k (RecordCompletion a b) = RecordCompletion (first k a) (first k b)@@ -815,7 +825,7 @@ subExpressions f (Record a) = Record <$> traverse f a subExpressions f ( RecordLit a ) = RecordLit <$> traverse f a subExpressions f (Union a) = Union <$> traverse (traverse f) a-subExpressions f (Combine a b) = Combine <$> f a <*> f b+subExpressions f (Combine a b c) = Combine a <$> f b <*> f c subExpressions f (CombineTypes a b) = CombineTypes <$> f a <*> f b subExpressions f (Prefer a b) = Prefer <$> f a <*> f b subExpressions f (RecordCompletion a b) = RecordCompletion <$> f a <*> f b@@ -1121,7 +1131,7 @@ denote (Record a            ) = Record (fmap denote a) denote (RecordLit a         ) = RecordLit (fmap denote a) denote (Union a             ) = Union (fmap (fmap denote) a)-denote (Combine a b         ) = Combine (denote a) (denote b)+denote (Combine _ b c       ) = Combine Nothing (denote b) (denote c) denote (CombineTypes a b    ) = CombineTypes (denote a) (denote b) denote (Prefer a b          ) = Prefer (denote a) (denote b) denote (RecordCompletion a b) = RecordCompletion (denote a) (denote b)
src/Dhall/TH.hs view
@@ -1,5 +1,7 @@-{-# LANGUAGE CPP               #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards     #-}+{-# LANGUAGE RecordWildCards   #-} {-# LANGUAGE TemplateHaskell   #-}  -- | Template Haskell utilities@@ -7,6 +9,8 @@     ( -- * Template Haskell       staticDhallExpression     , makeHaskellTypeFromUnion+    , makeHaskellTypes+    , HaskellType(..)     ) where  import Data.Monoid ((<>))@@ -21,19 +25,17 @@     , Exp(..)     , Q     , Type(..)-#if MIN_VERSION_template_haskell(2,11,0)     , Bang(..)     , SourceStrictness(..)     , SourceUnpackedness(..)-#else-    , Strict(..)-#endif     ) +import qualified Data.List                               as List import qualified Data.Text                               as Text import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty import qualified Data.Typeable                           as Typeable import qualified Dhall+import qualified Dhall.Core                              as Core import qualified Dhall.Map import qualified Dhall.Pretty import qualified Dhall.Util@@ -79,11 +81,22 @@     liftText = fmap (AppE (VarE 'Text.pack)) . Syntax.lift . Text.unpack  {-| Convert a Dhall type to a Haskell type that does not require any new-    data declarations+    data declarations beyond the data declarations supplied as the first+    argument -}-toSimpleHaskellType :: Pretty a => Expr s a -> Q Type-toSimpleHaskellType dhallType =-    case dhallType of+toNestedHaskellType+    :: (Eq a, Pretty a)+    => [HaskellType (Expr s a)]+    -- ^ All Dhall-derived data declarations+    --+    -- Used to replace complex types with references to one of these+    -- data declarations when the types match+    -> Expr s a+    -- ^ Dhall expression to convert to a simple Haskell type+    -> Q Type+toNestedHaskellType haskellTypes = loop+  where+    loop dhallType = case dhallType of         Bool -> do             return (ConT ''Bool) @@ -100,23 +113,27 @@             return (ConT ''Text)          App List dhallElementType -> do-            haskellElementType <- toSimpleHaskellType dhallElementType+            haskellElementType <- loop dhallElementType              return (AppT (ConT ''[]) haskellElementType)          App Optional dhallElementType -> do-            haskellElementType <- toSimpleHaskellType dhallElementType+            haskellElementType <- loop dhallElementType              return (AppT (ConT ''Maybe) haskellElementType) -        _ -> do+        _   | Just haskellType <- List.find predicate haskellTypes -> do+                let name = Syntax.mkName (Text.unpack (typeName haskellType))++                return (ConT name) +            | otherwise -> do             let document =                     mconcat-                    [ "Unsupported simple type\n"+                    [ "Unsupported nested type\n"                     , "                                                                                \n"-                    , "Explanation: Not all Dhall alternative types can be converted to Haskell        \n"-                    , "constructor types.  Specifically, only the following simple Dhall types are     \n"-                    , "supported as an alternative type or a field of an alternative type:             \n"+                    , "Explanation: Not all Dhall types can be nested within Haskell datatype          \n"+                    , "declarations.  Specifically, only the following simple Dhall types are supported\n"+                    , "as a nested type inside of a data declaration:                                  \n"                     , "                                                                                \n"                     , "• ❰Bool❱                                                                        \n"                     , "• ❰Double❱                                                                      \n"@@ -125,34 +142,102 @@                     , "• ❰Text❱                                                                        \n"                     , "• ❰List a❱     (where ❰a❱ is also a simple type)                                \n"                     , "• ❰Optional a❱ (where ❰a❱ is also a simple type)                                \n"+                    , "• Another matching datatype declaration                                         \n"                     , "                                                                                \n"-                    , "The Haskell datatype generation logic encountered the following complex         \n"-                    , "Dhall type:                                                                     \n"+                    , "The Haskell datatype generation logic encountered the following Dhall type:     \n"                     , "                                                                                \n"                     , " " <> Dhall.Util.insert dhallType <> "\n"                     , "                                                                                \n"-                    , "... where a simpler type was expected."+                    , "... which did not fit any of the above criteria."                     ]              let message = Pretty.renderString (Dhall.Pretty.layout document)              fail message+          where+            predicate haskellType =+                Core.judgmentallyEqual (code haskellType) dhallType --- | Convert a Dhall type to the corresponding Haskell constructor type-toConstructor :: Pretty a => (Text, Maybe (Expr s a)) -> Q Con-toConstructor (constructorName, maybeAlternativeType) = do+-- | Convert a Dhall type to the corresponding Haskell datatype declaration+toDeclaration+    :: (Eq a, Pretty a)+    => [HaskellType (Expr s a)]+    -> HaskellType (Expr s a)+    -> Q Dec+toDeclaration haskellTypes MultipleConstructors{..} = do+    case code of+        Union kts -> do+            let name = Syntax.mkName (Text.unpack typeName)++            constructors <- traverse (toConstructor haskellTypes) (Dhall.Map.toList kts )++            return (DataD [] name [] Nothing constructors [])++        _ -> do+            let document =+                    mconcat+                    [ "Dhall.TH.makeHaskellTypes: Not a union type\n"+                    , "                                                                                \n"+                    , "Explanation: This function expects the ❰code❱ field of ❰MultipleConstructors❱ to\n"+                    , "evaluate to a union type.                                                       \n"+                    , "                                                                                \n"+                    , "For example, this is a valid Dhall union type that this function would accept:  \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "    ┌──────────────────────────────────────────────────────────────────┐        \n"+                    , "    │ Dhall.TH.makeHaskellTypes (MultipleConstructors \"T\" \"< A | B >\") │        \n"+                    , "    └──────────────────────────────────────────────────────────────────┘        \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "... which corresponds to this Haskell type declaration:                         \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "    ┌────────────────┐                                                          \n"+                    , "    │ data T = A | B │                                                          \n"+                    , "    └────────────────┘                                                          \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "... but the following Dhall type is rejected due to being a bare record type:   \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "    ┌──────────────────────────────────────────────┐                            \n"+                    , "    │ Dhall.TH.makeHaskellTypes \"T\" \"{ x : Bool }\" │  Not valid                 \n"+                    , "    └──────────────────────────────────────────────┘                            \n"+                    , "                                                                                \n"+                    , "                                                                                \n"+                    , "The Haskell datatype generation logic encountered the following Dhall type:     \n"+                    , "                                                                                \n"+                    , " " <> Dhall.Util.insert code <> "\n"+                    , "                                                                                \n"+                    , "... which is not a union type."+                    ]++            let message = Pretty.renderString (Dhall.Pretty.layout document)++            fail message+toDeclaration haskellTypes SingleConstructor{..} = do+    let name = Syntax.mkName (Text.unpack typeName)++    constructor <- toConstructor haskellTypes (constructorName, Just code)++    return (DataD [] name [] Nothing [constructor] [])++-- | Convert a Dhall type to the corresponding Haskell constructor+toConstructor+    :: (Eq a, Pretty a)+    => [HaskellType (Expr s a)]+    -> (Text, Maybe (Expr s a))+    -- ^ @(constructorName, fieldType)@+    -> Q Con+toConstructor haskellTypes (constructorName, maybeAlternativeType) = do     let name = Syntax.mkName (Text.unpack constructorName) -#if MIN_VERSION_template_haskell(2,11,0)     let bang = Bang NoSourceUnpackedness NoSourceStrictness-#else-    let bang = NotStrict-#endif      case maybeAlternativeType of         Just (Record kts) -> do             let process (key, dhallFieldType) = do-                    haskellFieldType <- toSimpleHaskellType dhallFieldType+                    haskellFieldType <- toNestedHaskellType haskellTypes dhallFieldType                      return (Syntax.mkName (Text.unpack key), bang, haskellFieldType) @@ -161,7 +246,7 @@             return (RecC name varBangTypes)          Just dhallAlternativeType -> do-            haskellAlternativeType <- toSimpleHaskellType dhallAlternativeType+            haskellAlternativeType <- toNestedHaskellType haskellTypes dhallAlternativeType              return (NormalC name [ (bang, haskellAlternativeType) ]) @@ -171,10 +256,6 @@ -- | Generate a Haskell datatype declaration from a Dhall union type where -- each union alternative corresponds to a Haskell constructor ----- This comes in handy if you need to keep a Dhall type and Haskell type in--- sync.  You make the Dhall type the source of truth and use Template Haskell--- to generate the matching Haskell type declaration from the Dhall type.--- -- For example, this Template Haskell splice: -- -- > Dhall.TH.makeHaskellTypeFromUnion "T" "< A : { x : Bool } | B >"@@ -183,12 +264,78 @@ -- -- > data T = A {x :: GHC.Types.Bool} | B ----- If you are starting from an existing record type that you want to convert to--- a Haskell type, wrap the record type in a union with one alternative, like--- this:+-- This is a special case of `Dhall.TH.makeHaskellTypes`: ----- > Dhall.TH.makeHaskellTypeFromUnion "T" "< A : ./recordType.dhall >"+-- > makeHaskellTypeFromUnion typeName code =+-- >     makeHaskellTypes [ MultipleConstructors{..} ]+makeHaskellTypeFromUnion+    :: Text+    -- ^ Name of the generated Haskell type+    -> Text+    -- ^ Dhall code that evaluates to a union type+    -> Q [Dec]+makeHaskellTypeFromUnion typeName code =+    makeHaskellTypes [ MultipleConstructors{..} ]++-- | Used by `makeHaskellTypes` to specify how to generate Haskell types+data HaskellType code+    -- | Generate a Haskell type with more than one constructor from a Dhall+    -- union type+    = MultipleConstructors+        { typeName :: Text+        -- ^ Name of the generated Haskell type+        , code :: code+        -- ^ Dhall code that evaluates to a union type+        }+    -- | Generate a Haskell type with one constructor from any Dhall type+    --+    -- To generate a constructor with multiple named fields, supply a Dhall+    -- record type.  This does not support more than one anonymous field.+    | SingleConstructor+        { typeName :: Text+        -- ^ Name of the generated Haskell type+        , constructorName :: Text+        -- ^ Name of the constructor+        , code :: code+        -- ^ Dhall code that evaluates to a type+        }+    deriving (Functor, Foldable, Traversable)++-- | Generate a Haskell datatype declaration with one constructor from a Dhall+-- type --+-- This comes in handy if you need to keep Dhall types and Haskell types in+-- sync.  You make the Dhall types the source of truth and use Template Haskell+-- to generate the matching Haskell type declarations from the Dhall types.+--+-- For example, given this Dhall code:+--+-- > -- ./Department.dhall+-- > < Sales | Engineering | Marketing >+--+-- > -- ./Employee.dhall+-- > { name : Text, department : ./Department.dhall }+--+-- ... this Template Haskell splice:+--+-- > Dhall.TH.makeHaskellTypes+-- >     [ MultipleConstructors "Department" "./tests/th/Department.dhall"+-- >     , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+-- >     ]+--+-- ... generates this Haskell code:+--+-- > data Department = Engineering | Marketing | Sales+-- >+-- > data Employee+-- >   = MakeEmployee {department :: Department,+-- >                   name :: Data.Text.Internal.Text}+--+-- Carefully note that the conversion makes a best-effort attempt to+-- auto-detect when a Dhall type (like @./Employee.dhall@) refers to another+-- Dhall type (like @./Department.dhall@) and replaces that reference with the+-- corresponding Haskell type.+-- -- To add any desired instances (such as `Dhall.FromDhall`/`Dhall.ToDhall`), -- you can use the `StandaloneDeriving` language extension, like this: --@@ -198,85 +345,20 @@ -- > {-# LANGUAGE StandaloneDeriving #-} -- > {-# LANGUAGE TemplateHaskell    #-} -- >--- > Dhall.TH.makeHaskellTypeFromUnion  "T" "< A : { x : Bool } | B >"--- > --- > deriving instance Generic   T--- > deriving instance FromDhall T-makeHaskellTypeFromUnion-    :: Text-    -- ^ Name of the generated Haskell type-    -> Text-    -- ^ Dhall code that evaluates to a union type-    -> Q [Dec]-makeHaskellTypeFromUnion typeName text = do+-- > Dhall.TH.makeHaskellTypes+-- >     [ MultipleConstructors "Department" "./tests/th/Department.dhall"+-- >     , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+-- >     ]+-- >+-- > deriving instance Generic   Department+-- > deriving instance FromDhall Department+-- >+-- > deriving instance Generic   Employee+-- > deriving instance FromDhall Employee+makeHaskellTypes :: [HaskellType Text] -> Q [Dec]+makeHaskellTypes haskellTypes = do     Syntax.runIO (GHC.IO.Encoding.setLocaleEncoding System.IO.utf8) -    expression <- Syntax.runIO (Dhall.inputExpr text)--    case expression of-        Union kts -> do-            let name = Syntax.mkName (Text.unpack typeName)--            constructors <- traverse toConstructor (Dhall.Map.toList kts )--            let declaration = DataD [] name []-#if MIN_VERSION_template_haskell(2,11,0)-                    Nothing-#else-#endif-                    constructors []--            return [ declaration ]--        _ -> do-            let document =-                    mconcat-                    [ "Dhall.TH.makeHaskellTypeFromUnion: Unsupported Dhall type\n"-                    , "                                                                                \n"-                    , "Explanation: This function only coverts Dhall union types to Haskell datatype   \n"-                    , "declarations.                                                                   \n"-                    , "                                                                                \n"-                    , "For example, this is a valid Dhall union type that this function would accept:  \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "    ┌──────────────────────────────────────────────────────────────────┐        \n"-                    , "    │ Dhall.TH.makeHaskellTypeFromUnion \"T\" \"< A : { x : Bool } | B >\" │        \n"-                    , "    └──────────────────────────────────────────────────────────────────┘        \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "... which corresponds to this Haskell type declaration:                         \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "    ┌──────────────────────────────────────┐                                    \n"-                    , "    │ data T = A {x :: GHC.Types.Bool} | B │                                    \n"-                    , "    └──────────────────────────────────────┘                                    \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "... but the following Dhall type is rejected due to being a bare record type:   \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "    ┌──────────────────────────────────────────────────────┐                    \n"-                    , "    │ Dhall.TH.makeHaskellTypeFromUnion \"T\" \"{ x : Bool }\" │  Not valid         \n"-                    , "    └──────────────────────────────────────────────────────┘                    \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "If you are starting from a file containing only a record type and you want to   \n"-                    , "generate a Haskell type from that, then wrap the record type in a union with one\n"-                    , "alternative, like this:                                                         \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "    ┌──────────────────────────────────────────────────────────────────┐        \n"-                    , "    │ Dhall.TH.makeHaskellTypeFromUnion \"T\" \"< A : ./recordType.dhall >\" │      \n"-                    , "    └──────────────────────────────────────────────────────────────────┘        \n"-                    , "                                                                                \n"-                    , "                                                                                \n"-                    , "The Haskell datatype generation logic encountered the following Dhall type:     \n"-                    , "                                                                                \n"-                    , " " <> Dhall.Util.insert expression <> "\n"-                    , "                                                                                \n"-                    , "... which is not a union type."-                    ]--            let message = Pretty.renderString (Dhall.Pretty.layout document)+    haskellTypes' <- traverse (traverse (Syntax.runIO . Dhall.inputExpr)) haskellTypes -            fail message+    traverse (toDeclaration haskellTypes') haskellTypes'
src/Dhall/Tags.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE LambdaCase #-} @@ -37,9 +36,9 @@ -}  data LineColumn = LC -    { lcLine :: Int+    { _lcLine :: Int       -- ^ line number, starting from 1, where to find the tag-    , lcColumn :: Int+    , _lcColumn :: Int       -- ^ column of line where tag is     } deriving (Eq, Ord, Show) @@ -269,11 +268,4 @@                                    concat <$> mapM (go . (</>) p) contents                      else return [p | matchingSuffix || p == path]                where matchingSuffix = maybe True (any (`isSuffixOf` p)) suffixes-                     isSymLink = -#if MIN_VERSION_directory(1,3,0)-                                 SD.pathIsSymbolicLink p-#elif MIN_VERSION_directory(1,2,6)-                                 SD.isSymbolicLink pa-#else-                                 return False-#endif+                     isSymLink = SD.pathIsSymbolicLink p
src/Dhall/Tutorial.hs view
@@ -74,6 +74,9 @@     -- ** Extending the language     -- $extending +    -- ** Substitutions+    -- $substitutions+     -- * Prelude     -- $prelude @@ -1915,6 +1918,64 @@ -- * Keep built-ins easy to implement across language bindings -- * Prefer general purpose built-ins or built-ins appropriate for the task of program configuration -- * Design built-ins to catch errors as early as possible (i.e. when type-checking the configuration)++-- $substitutions+--+-- Substitutions are another way to extend the language.+-- Suppose we have the following Haskell datatype:+--+-- > data Result = Failure Integer | Success String+-- >     deriving (Eq, Generic, Show)+-- >+-- > instance FromDhall Result+--+-- We can use it in Dhall like that:+--+-- > -- example.dhall+-- >+-- > let Result = < Failure : Integer | Success Text >+-- > in Result.Failure 1+--+-- Right now it is quite easy to keep these two definitions (the one in Haskell source and the one in the Dhall file) synchronized:+-- If we implement a new feature in the Haskell source we update the corresponding type in the Dhall file.+-- But what happens if our application is growing and our Result type contains e.g. 10 unions with possible types embedded in it?+-- Maintaining the code will get tedious. Luckily we can extract the correct Dhall type from the Haskell definition:+--+-- > resultDecoder :: Dhall.Decoder Result+-- > resultDecoder = Dhall.auto+-- >+-- > resultType :: Expr Src Void+-- > resultType = Dhall.expected resultDecoder+-- >+-- > resultTypeString :: String+-- > resultTypeString = show $ pretty resultType+--+-- Now we just have to inject that type into the Dhall code and we are done. One common way to do that is to wrap the import of example.dhall in a let expression:+--+-- > Dhall.input (Dhall.auto :: Dhall.Decoder Result) ("let Result = " ++ Data.Text.pack resultTypeString ++ " in ./example.dhall")+--+-- Now we can omit the definition of Result in our example.dhall file. While this will work perfectly Dhall provides a cleaner solution for our \"injection problem\":+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > myexample :: IO Result+-- > myexample = let+-- >    evaluateSettings = Lens.over Dhall.substitutions (Dhall.Map.insert "Result" resultType) Dhall.defaultEvaluateSettings+-- >    in Dhall.inputFileWithSettings evaluateSettings resultDecoder "example.dhall"+--+-- Substitutions are a simple 'Dhall.Map.Map' mapping variables to expressions. The application of these substitutions reflect the order of the insertions in the substitution map:+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- >+-- > substitute (Dhall.Core.Var "Foo") (Dhall.Map.fromList [("Foo", Dhall.Core.Var "Bar"), ("Bar", Dhall.Core.BoolLit True)])+--+-- results in @Dhall.Core.Var \"Baz\"@ since we first substitute \"Foo\" with \"Bar\" and then the resulting \"Bar\" with the final @True@.+--+-- Notable differences to the other extensions of the builtin language:+--+--  * This approach works well with the inputFile/inputFileWithSettings functions while the let-wrapping will not.+--+--  * In contrast to the custom built-ins described above substitutions are made BEFORE the type-checking.  -- $prelude --
src/Dhall/TypeCheck.hs view
@@ -32,6 +32,7 @@ import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Writer.Strict (execWriterT, tell) import Data.Monoid (Endo(..), First(..))+import Data.List.NonEmpty (NonEmpty(..)) import Data.Semigroup (Max(..), Semigroup(..)) import Data.Sequence (Seq, ViewL(..)) import Data.Set (Set)@@ -48,6 +49,7 @@ import Lens.Family (over)  import qualified Data.Foldable+import qualified Data.List.NonEmpty                      as NonEmpty import qualified Data.Map import qualified Data.Sequence import qualified Data.Set@@ -803,7 +805,7 @@                     Dhall.Map.unorderedTraverseWithKey_ process (Dhall.Map.delete x₀ xTs)                      return (VConst c₀)-        Combine l r -> do+        Combine mk l r -> do             _L' <- loop ctx l              xLs' <- case _L' of@@ -813,7 +815,9 @@                 _ -> do                     let _L'' = quote names _L' -                    die (MustCombineARecord '∧' l _L'')+                    case mk of+                        Nothing -> die (MustCombineARecord '∧' l _L'')+                        Just t  -> die (InvalidDuplicateField t l _L'')              _R' <- loop ctx r @@ -824,14 +828,18 @@                 _ -> do                     let _R'' = quote names _R' -                    die (MustCombineARecord '∧' r _R'')+                    case mk of+                        Nothing -> die (MustCombineARecord '∧' r _R'')+                        Just t  -> die (InvalidDuplicateField t r _R'') -            let combineTypes xLs₀' xRs₀' = do-                    let combine _ (VRecord xLs₁') (VRecord xRs₁') =-                            combineTypes xLs₁' xRs₁'+            let combineTypes xs xLs₀' xRs₀' = do+                    let combine x (VRecord xLs₁') (VRecord xRs₁') =+                            combineTypes (x : xs) xLs₁' xRs₁'                          combine x _ _ = do-                            die (FieldCollision x)+                            case mk of+                                Nothing -> die (FieldCollision (NonEmpty.reverse (x :| xs)))+                                Just t  -> die (DuplicateFieldCannotBeMerged (t :| reverse (x : xs)))                      let xEs =                             Dhall.Map.outerJoin Right Right combine xLs₀' xRs₀'@@ -840,7 +848,7 @@                      return (VRecord xTs) -            combineTypes xLs' xRs'+            combineTypes [] xLs' xRs'          CombineTypes l r -> do             _L' <- loop ctx l@@ -873,19 +881,19 @@                 VRecord xRs' -> return xRs'                 _            -> die (CombineTypesRequiresRecordType r r'') -            let combineTypes xLs₀' xRs₀' = do-                    let combine _ (VRecord xLs₁') (VRecord xRs₁') =-                            combineTypes xLs₁' xRs₁'+            let combineTypes xs xLs₀' xRs₀' = do+                    let combine x (VRecord xLs₁') (VRecord xRs₁') =+                            combineTypes (x : xs) xLs₁' xRs₁'                          combine x _ _ =-                            die (FieldCollision x)+                            die (FieldTypeCollision (NonEmpty.reverse (x :| xs)))                      let mL = Dhall.Map.toMap xLs₀'                     let mR = Dhall.Map.toMap xRs₀'                      Data.Foldable.sequence_ (Data.Map.intersectionWithKey combine mL mR) -            combineTypes xLs' xRs'+            combineTypes [] xLs' xRs'              return (VConst c) @@ -1308,11 +1316,14 @@     | AlternativeAnnotationMismatch Text (Expr s a) Const Text (Expr s a) Const     | ListAppendMismatch (Expr s a) (Expr s a)     | MustCombineARecord Char (Expr s a) (Expr s a)+    | InvalidDuplicateField Text (Expr s a) (Expr s a)     | InvalidRecordCompletion Text (Expr s a)     | CompletionSchemaMustBeARecord (Expr s a) (Expr s a)     | CombineTypesRequiresRecordType (Expr s a) (Expr s a)     | RecordTypeMismatch Const Const (Expr s a) (Expr s a)-    | FieldCollision Text+    | DuplicateFieldCannotBeMerged (NonEmpty Text)+    | FieldCollision (NonEmpty Text)+    | FieldTypeCollision (NonEmpty Text)     | MustMergeARecord (Expr s a) (Expr s a)     | MustMergeUnionOrOptional (Expr s a) (Expr s a)     | MustMapARecord (Expr s a) (Expr s a)@@ -2808,6 +2819,72 @@         txt0 = insert expr0         txt1 = insert expr1 +prettyTypeMessage (InvalidDuplicateField k expr0 expr1) =+    ErrorMessages {..}+  where+    short = "Invalid duplicate field: " <> Dhall.Pretty.Internal.prettyLabel k++    long =+        "Explanation: You can specify a field twice if both fields are themselves        \n\+        \records, like this:                                                             \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────────────────────────────────────────────┐                \n\+        \    │ { ssh = { enable = True }, ssh = { forwardX11 = True } } │                \n\+        \    └──────────────────────────────────────────────────────────┘                \n\+        \                                                                                \n\+        \                                                                                \n\+        \... because the language automatically merges two occurrences of a field using  \n\+        \the ❰∧❱ operator, and the above example is equivalent to:                       \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌─────────────────────────────────────────────────────┐                     \n\+        \    │ { ssh = { enable = True } ∧ { forwardX11 = True } } │                     \n\+        \    └─────────────────────────────────────────────────────┘                     \n\+        \                                                                                \n\+        \                                                                                \n\+        \... which is in turn equivalent to:                                             \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌────────────────────────────────────────────────┐                          \n\+        \    │ { ssh = { enable = True, forwardX11 = True } } │                          \n\+        \    └────────────────────────────────────────────────┘                          \n\+        \                                                                                \n\+        \                                                                                \n\+        \However, this implies that both fields must be records since the ❰∧❱ operator   \n\+        \cannot merge non-record values.  For example, these expressions are not valid:  \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────┐                                                        \n\+        \    │ { x = 0, x = 0 } │  Invalid: Neither field is a record                    \n\+        \    └──────────────────┘                                                        \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────────────┐                                                \n\+        \    │ { x = 0, x = { y = 0 } } │  Invalid: The first ❰x❱ field is not a record  \n\+        \    └──────────────────────────┘                                                \n\+        \                                                                                \n\+        \                                                                                \n\+        \────────────────────────────────────────────────────────────────────────────────\n\+        \                                                                                \n\+        \You specified more than one field named:                                        \n\+        \                                                                                \n\+        \" <> txt0 <> "\n\+        \                                                                                \n\+        \... but one of the fields had this value:                                       \n\+        \                                                                                \n\+        \" <> txt1 <> "\n\+        \                                                                                \n\+        \... with this type:                                                             \n\+        \                                                                                \n\+        \" <> txt2 <> "\n\+        \                                                                                \n\+        \... which is not a record type                                                  \n"+      where+        txt0 = insert (Dhall.Pretty.Internal.escapeLabel True k)+        txt1 = insert expr0+        txt2 = insert expr1+ prettyTypeMessage (CombineTypesRequiresRecordType expr0 expr1) =     ErrorMessages {..}   where@@ -2898,82 +2975,172 @@         txt2 = insert const0         txt3 = insert const1 -prettyTypeMessage (FieldCollision k) = ErrorMessages {..}+prettyTypeMessage (DuplicateFieldCannotBeMerged ks) = ErrorMessages {..}   where-    short = "Field collision on: " <> Dhall.Pretty.Internal.prettyLabel k+    short = "Duplicate field cannot be merged: " <> pretty (toPath ks)      long =-        "Explanation: You can combine records or record types if they don't share any    \n\-        \fields in common, like this:                                                    \n\+        "Explanation: Duplicate fields are only allowed if they are both records and if  \n\+        \the two records can be recursively merged without collisions.                   \n\         \                                                                                \n\+        \Specifically, an expression like:                                               \n\         \                                                                                \n\-        \    ┌───────────────────────────────────────────┐                               \n\-        \    │ { foo = 1, bar = \"ABC\" } ∧ { baz = True } │                             \n\-        \    └───────────────────────────────────────────┘                               \n\         \                                                                                \n\+        \    ┌──────────────────┐                                                        \n\+        \    │ { x = a, x = b } │                                                        \n\+        \    └──────────────────┘                                                        \n\         \                                                                                \n\-        \    ┌─────────────────────────────────┐                                         \n\-        \    │ { foo : Text } ⩓ { bar : Bool } │                                         \n\-        \    └─────────────────────────────────┘                                         \n\         \                                                                                \n\+        \... is syntactic sugar for:                                                     \n\         \                                                                                \n\-        \    ┌────────────────────────────────────────┐                                  \n\-        \    │ λ(r : { baz : Bool}) → { foo = 1 } ∧ r │                                  \n\-        \    └────────────────────────────────────────┘                                  \n\         \                                                                                \n\+        \    ┌───────────────┐                                                           \n\+        \    │ { x = a ∧ b } │                                                           \n\+        \    └───────────────┘                                                           \n\         \                                                                                \n\-        \... but you cannot merge two records that share the same field unless the field \n\-        \is a record on both sides.                                                      \n\         \                                                                                \n\-        \For example, the following expressions are " <> _NOT <> " valid:                \n\+        \... which is rejected if ❰a ∧ b❱ does not type-check.  One way this can happen  \n\+        \is if ❰a❱ and ❰b❱ share a field in common that is not a record, which is known  \n\+        \as a \"collision\".                                                               \n\         \                                                                                \n\+        \For example, the following expression is " <> _NOT <> " valid:                  \n\         \                                                                                \n\-        \    ┌───────────────────────────────────────────┐                               \n\-        \    │ { foo = 1, bar = \"ABC\" } ∧ { foo = True } │  Invalid: Colliding ❰foo❱   \n\-        \    └───────────────────────────────────────────┘  fields                       \n\         \                                                                                \n\+        \    ┌──────────────────────────────────┐                                        \n\+        \    │ { x = { y = 0 }, x = { y = 1 } } │ Invalid: The two ❰x.y❱ fields \"collide\"\n\+        \    └──────────────────────────────────┘                                        \n\         \                                                                                \n\-        \    ┌─────────────────────────────────┐                                         \n\-        \    │ { foo : Bool } ∧ { foo : Text } │  Invalid: Colliding ❰foo❱ fields        \n\-        \    └─────────────────────────────────┘                                         \n\         \                                                                                \n\+        \... whereas the following expression is valid:                                  \n\         \                                                                                \n\-        \... but the following expressions are valid:                                    \n\         \                                                                                \n\+        \    ┌──────────────────────────────────┐                                        \n\+        \    │ { x = { y = 0 }, x = { z = 1 } } │ Valid: the two ❰x❱ fields don't collide\n\+        \    └──────────────────────────────────┘ because they can be recursively merged \n\         \                                                                                \n\-        \    ┌──────────────────────────────────────────────────┐                        \n\-        \    │ { foo = { bar = True } } ∧ { foo = { baz = 1 } } │  Valid: Both ❰foo❱     \n\-        \    └──────────────────────────────────────────────────┘  fields are records    \n\         \                                                                                \n\+        \Some common reasons why you might get this error:                               \n\         \                                                                                \n\-        \    ┌─────────────────────────────────────────────────────┐                     \n\-        \    │ { foo : { bar : Bool } } ⩓ { foo : { baz : Text } } │  Valid: Both ❰foo❱  \n\-        \    └─────────────────────────────────────────────────────┘  fields are records \n\+        \● You specified the same field twice by mistake                                 \n\         \                                                                                \n\+        \────────────────────────────────────────────────────────────────────────────────\n\         \                                                                                \n\+        \You specified the following field twice:                                        \n\+        \                                                                                \n\+        \" <> txt0 <> "\n\+        \                                                                                \n\+        \... which collided on the following path:                                       \n\+        \                                                                                \n\+        \" <> txt1 <> "\n"+      where+        txt0 = insert (Dhall.Pretty.Internal.escapeLabel True (NonEmpty.head ks))++        txt1 = insert (toPath ks)++prettyTypeMessage (FieldCollision ks) = ErrorMessages {..}+  where+    short = "Field collision on: " <> pretty (toPath ks)++    long =+        "Explanation: You can recursively merge records using the ❰∧❱ operator:          \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌───────────────────────┐                                                   \n\+        \    │ { x = a } ∧ { y = b } │                                                   \n\+        \    └───────────────────────┘                                                   \n\+        \                                                                                \n\+        \... but two records cannot be merged in this way if they share a field that is  \n\+        \not a record.                                                                   \n\+        \                                                                                \n\+        \For example, the following expressions are " <> _NOT <> " valid:                \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────────────┐                                                \n\+        \    │ { x = 1 } ∧ { x = True } │  Invalid: The ❰x❱ fields \"collide\" because they\n\+        \    └──────────────────────────┘  are not records that can be merged            \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────────────────────┐                                        \n\+        \    │ { x = 1 } ∧ { x = { y = True } } │  Invalid: One of the two ❰x❱ fields is \n\+        \    └──────────────────────────────────┘  still not a record                    \n\+        \                                                                                \n\+        \                                                                                \n\+        \... but the following expression is valid:                                      \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌──────────────────────────────────────────┐  Valid: The two ❰x❱ fields     \n\+        \    │ { x = { y = True } } ∧ { x = { z = 1 } } │  don't collide because they can\n\+        \    └──────────────────────────────────────────┘  be recursively merged         \n\+        \                                                                                \n\+        \                                                                                \n\         \Some common reasons why you might get this error:                               \n\         \                                                                                \n\         \● You tried to use ❰∧❱ to update a field's value, like this:                    \n\         \                                                                                \n\         \                                                                                \n\         \    ┌────────────────────────────────────────┐                                  \n\-        \    │ { foo = 1, bar = \"ABC\" } ∧ { foo = 2 } │                                \n\+        \    │ { foo = 1, bar = \"ABC\" } ∧ { foo = 2 } │                                  \n\         \    └────────────────────────────────────────┘                                  \n\         \                                   ⇧                                            \n\         \                                  Invalid attempt to update ❰foo❱'s value to ❰2❱\n\         \                                                                                \n\-        \  Field updates are intentionally not allowed as the Dhall language discourages \n\-        \  patch-oriented programming                                                    \n\         \                                                                                \n\+        \  You probably meant to use ❰⫽❱ / ❰//❱  instead:                                \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌────────────────────────────────────────┐                                  \n\+        \    │ { foo = 1, bar = \"ABC\" } ⫽ { foo = 2 } │                                  \n\+        \    └────────────────────────────────────────┘                                  \n\+        \                                                                                \n\+        \                                                                                \n\         \────────────────────────────────────────────────────────────────────────────────\n\         \                                                                                \n\-        \You combined two records that share the following field:                        \n\+        \You tried to merge two records which collided on the following path:            \n\         \                                                                                \n\-        \" <> txt0 <> "\n\+        \" <> txt0 <> "\n"+      where+        txt0 = insert (toPath ks)++prettyTypeMessage (FieldTypeCollision ks) = ErrorMessages {..}+  where+    short = "Field type collision on: " <> pretty (toPath ks)++    long =+        "Explanation: You can recursively merge record types using the ❰⩓❱ operator, like\n\+        \this:                                                                           \n\         \                                                                                \n\-        \... which is not allowed                                                        \n"+        \                                                                                \n\+        \    ┌───────────────────────┐                                                   \n\+        \    │ { x : A } ⩓ { y : B } │                                                   \n\+        \    └───────────────────────┘                                                   \n\+        \                                                                                \n\+        \                                                                                \n\+        \... but you cannot merge record types if two field types collide that are not   \n\+        \both record types.                                                              \n\+        \                                                                                \n\+        \For example, the following expression is " <> _NOT <> " valid:                  \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌────────────────────────────────┐                                          \n\+        \    │ { x : Natural } ⩓ { x : Bool } │  Invalid: The ❰x❱ fields \"collide\"       \n\+        \    └────────────────────────────────┘  because they cannot be merged           \n\+        \                                                                                \n\+        \                                                                                \n\+        \... but the following expression is valid:                                      \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌────────────────────────────────────────────────┐  Valid: The ❰x❱ field    \n\+        \    │ { x : { y : Bool } } ⩓ { x : { z : Natural } } │  types don't collide and \n\+        \    └────────────────────────────────────────────────┘  can be merged           \n\+        \                                                                                \n\+        \                                                                                \n\+        \────────────────────────────────────────────────────────────────────────────────\n\+        \                                                                                \n\+        \You tried to merge two record types which collided on the following path:       \n\+        \                                                                                \n\+        \" <> txt0 <> "\n"       where-        txt0 = insert k+        txt0 = insert (toPath ks)  prettyTypeMessage (MustMergeARecord expr0 expr1) = ErrorMessages {..}   where@@ -4429,6 +4596,8 @@         AlternativeAnnotationMismatch <$> pure a <*> f b <*> pure c <*> pure d <*> f e <*> pure g     ListAppendMismatch a b ->         ListAppendMismatch <$> f a <*> f b+    InvalidDuplicateField a b c ->+        InvalidDuplicateField a <$> f b <*> f c     MustCombineARecord a b c ->         MustCombineARecord <$> pure a <*> f b <*> f c     InvalidRecordCompletion a l -> @@ -4439,8 +4608,12 @@         CombineTypesRequiresRecordType <$> f a <*> f b     RecordTypeMismatch a b c d ->         RecordTypeMismatch <$> pure a <*> pure b <*> f c <*> f d+    DuplicateFieldCannotBeMerged a ->+        pure (DuplicateFieldCannotBeMerged a)     FieldCollision a ->-        FieldCollision <$> pure a+        pure (FieldCollision a)+    FieldTypeCollision a ->+        pure (FieldTypeCollision a)     MustMergeARecord a b ->         MustMergeARecord <$> f a <*> f b     MustMergeUnionOrOptional a b ->@@ -4569,3 +4742,10 @@             let shiftedContext = fmap (Dhall.Core.shift (-1) (V x 0)) context'             _ <- typeWith shiftedContext shiftedV             return ()++toPath :: (Functor list, Foldable list) => list Text -> Text+toPath ks =+    Text.intercalate "."+        (Data.Foldable.toList+            (fmap (Dhall.Pretty.Internal.escapeLabel True) ks)+        )
src/Dhall/Util.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}  -- | Shared utility functions @@ -9,11 +10,13 @@     , _ERROR     , Censor(..)     , Input(..)+    , OutputMode(..)     , Output(..)     , getExpression     , getExpressionAndHeader     , getExpressionAndHeaderFromStdinText     , Header(..)+    , CheckFailed(..)     ) where  import Control.Exception (Exception(..))@@ -98,7 +101,11 @@ _ERROR :: IsString string => string _ERROR = "\ESC[1;31mError\ESC[0m" -get :: (String -> Text -> Either ParseError a) -> Censor -> InputOrTextFromStdin -> IO a+get+    :: (String -> Text -> Either ParseError a)+    -> Censor+    -> InputOrTextFromStdin+    -> IO a get parser censor input = do     inText <- do         case input of@@ -140,15 +147,40 @@ -- | Path to output data Output = StandardOutput | OutputFile FilePath +{-| Some command-line subcommands can either `Write` their input or `Check`+    that the input has already been modified.  This type is shared between them+    to record that choice.+-}+data OutputMode = Write | Check++-- | Exception thrown when the @--check@ flag to a command-line subcommand fails+data CheckFailed = CheckFailed { command :: Text, modified :: Text }++instance Exception CheckFailed++instance Show CheckFailed where+    show CheckFailed{..} =+         _ERROR <> ": ❰dhall " <> command_ <> " --check❱ failed\n\+        \\n\+        \You ran ❰dhall " <> command_ <> " --check❱, but the input appears to have not\n\+        \been " <> modified_ <> " before, or was changed since the last time the input\n\+        \was " <> modified_ <> ".\n"+      where+        modified_ = Data.Text.unpack modified++        command_ = Data.Text.unpack command+ -- | Convenient utility for retrieving an expression getExpression :: Censor -> Input -> IO (Expr Src Import) getExpression censor = get Dhall.Parser.exprFromText censor . Input_  -- | Convenient utility for retrieving an expression along with its header getExpressionAndHeader :: Censor -> Input -> IO (Header, Expr Src Import)-getExpressionAndHeader censor = get Dhall.Parser.exprAndHeaderFromText censor . Input_+getExpressionAndHeader censor =+    get Dhall.Parser.exprAndHeaderFromText censor . Input_  -- | Convenient utility for retrieving an expression along with its header from -- | text already read from STDIN (so it's not re-read) getExpressionAndHeaderFromStdinText :: Censor -> Text -> IO (Header, Expr Src Import)-getExpressionAndHeaderFromStdinText censor = get Dhall.Parser.exprAndHeaderFromText censor . StdinText+getExpressionAndHeaderFromStdinText censor =+    get Dhall.Parser.exprAndHeaderFromText censor . StdinText
tests/Dhall/Test/QuickCheck.hs view
@@ -324,6 +324,7 @@ standardizedExpression (ListLit  Nothing  xs) = not (Data.Sequence.null xs) standardizedExpression (ListLit (Just _ ) xs) = Data.Sequence.null xs standardizedExpression (Note _ _            ) = False+standardizedExpression (Combine (Just _) _ _) = False standardizedExpression  _                     = True  instance Arbitrary File where
tests/Dhall/Test/Regression.hs view
@@ -43,6 +43,7 @@         , issue1131b         , issue1341         , issue1584+        , issue1646         , parsing0         , typeChecking0         , typeChecking1@@ -186,6 +187,13 @@     -- This test ensures that we can parse variables with keyword prefixes     -- (e.g. `ifX`)     _ <- Util.code "./tests/regression/issue1584.dhall"+    return () )++issue1646 :: TestTree+issue1646 = Test.Tasty.HUnit.testCase "Issue #1646" (do+    -- This test ensures that the parser doesn't eagerly consume trailing+    -- whitespace after a `Double`+    _ <- Util.code "./tests/regression/issue1646.dhall"     return () )  parsing0 :: TestTree
+ tests/Dhall/Test/Substitution.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Test.Substitution where++import Data.Void (Void)+import Dhall.Core (Expr(BoolLit, Var))+import Dhall.Src (Src)++import qualified Dhall+import qualified Dhall.Map+import qualified Lens.Family   as Lens++data Result = Failure Integer | Success String+    deriving (Eq, Dhall.Generic, Show)++instance Dhall.FromDhall Result++substituteResult :: FilePath -> IO Result+substituteResult fp = let+    evaluateSettings = Lens.over Dhall.substitutions (Dhall.Map.insert "Result" resultType) Dhall.defaultEvaluateSettings+    in Dhall.inputFileWithSettings evaluateSettings resultDecoder fp++resultDecoder :: Dhall.Decoder Result+resultDecoder = Dhall.auto++resultType :: Expr Src Void+resultType = Dhall.expected resultDecoder++substituteFoo :: FilePath -> IO Bool+substituteFoo fp = let+    evaluateSettings = Lens.set Dhall.substitutions (Dhall.Map.fromList [("Foo", Var "Bar"), ("Bar", BoolLit True)]) Dhall.defaultEvaluateSettings+    in Dhall.inputFileWithSettings evaluateSettings Dhall.auto fp
tests/Dhall/Test/TH.hs view
@@ -7,6 +7,7 @@ module Dhall.Test.TH where  import Dhall (FromDhall(..))+import Dhall.TH (HaskellType(..)) import GHC.Generics import Test.Tasty (TestTree) @@ -22,6 +23,21 @@ deriving instance Generic   T deriving instance FromDhall T +Dhall.TH.makeHaskellTypes+    [ MultipleConstructors "Department" "./tests/th/Department.dhall"+    , SingleConstructor "Employee" "MakeEmployee" "./tests/th/Employee.dhall"+    ]++deriving instance Eq        Department+deriving instance Show      Department+deriving instance Generic   Department+deriving instance FromDhall Department++deriving instance Eq        Employee+deriving instance Show      Employee+deriving instance Generic   Employee+deriving instance FromDhall Employee+ tests :: TestTree tests = Tasty.testGroup "Template Haskell" [ makeHaskellTypeFromUnion ] @@ -38,3 +54,7 @@     t2 <- Dhall.input Dhall.auto "let T = ./tests/th/example.dhall in T.C"      Tasty.HUnit.assertEqual "" t2 C++    employee <- Dhall.input Dhall.auto "let Department = ./tests/th/Department.dhall in { name = \"John\", department = Department.Marketing }"++    Tasty.HUnit.assertEqual "" employee MakeEmployee{ name = "John", department = Marketing }
tests/Dhall/Test/Tutorial.hs view
@@ -6,7 +6,8 @@  import qualified Data.Vector import qualified Dhall-import qualified Dhall.Test.Util as Util+import qualified Dhall.Test.Substitution as Substitution+import qualified Dhall.Test.Util         as Util import qualified Test.Tasty import qualified Test.Tasty.HUnit @@ -35,6 +36,17 @@             , example 1 "./tests/tutorial/unions1A.dhall" "./tests/tutorial/unions1B.dhall"             , example 3 "./tests/tutorial/unions3A.dhall" "./tests/tutorial/unions3B.dhall"             , example 4 "./tests/tutorial/unions4A.dhall" "./tests/tutorial/unions4B.dhall"+            ]+        , Test.Tasty.testGroup "Substitutions"+            [ Test.Tasty.HUnit.testCase "substitution1.dhall" $ do+                res <- Substitution.substituteResult "tests/tutorial/substitution1.dhall"+                res @?= Substitution.Failure 1+            , Test.Tasty.HUnit.testCase "substitution2.dhall" $ do+                res <- Substitution.substituteResult "tests/tutorial/substitution2.dhall"+                res @?= Substitution.Failure 1+            , Test.Tasty.HUnit.testCase "substitution3.dhall" $ do+                res <- Substitution.substituteFoo "tests/tutorial/substitution3.dhall"+                res @?= True             ]         ] 
tests/Dhall/Test/TypeInference.hs view
@@ -80,11 +80,11 @@  failureTest :: Text -> TestTree failureTest prefix = do-    let expectedFailures = [ typeInferenceDirectory </> "failure/unit/MergeEmptyNeedsDirectAnnotation1"+    let expectedFailures =+               [ typeInferenceDirectory </> "failure/unit/MergeEmptyNeedsDirectAnnotation1"                 -- Duplicate fields are incorrectly caught during parsing:                -- https://github.com/dhall-lang/dhall-haskell/issues/772-               , typeInferenceDirectory </> "failure/unit/RecordLitDuplicateFields"                , typeInferenceDirectory </> "failure/unit/RecordProjectionDuplicateFields"                , typeInferenceDirectory </> "failure/unit/RecordTypeDuplicateFields"                , typeInferenceDirectory </> "failure/unit/UnionTypeDuplicateVariants1"
tests/format/applicationMultilineA.dhall view
@@ -15,6 +15,9 @@ , some =     Some       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+, someList =+    Some+      [ aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccc, dddddddddddddd ] , merge =     merge       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
tests/format/applicationMultilineB.dhall view
@@ -14,6 +14,12 @@       dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd , some = Some     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+, someList = Some+  [ aaaaaaaaaaaaaaaaaaaaaaaaaa+  , bbbbbbbbbbbbbbbbbbbb+  , cccccccccccccccccccccccc+  , dddddddddddddd+  ] , merge =     merge       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@@ -23,7 +29,6 @@       a       b       ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc-, toMap =-    toMap-      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+, toMap = toMap+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa }
+ tests/format/dottedFieldsA.dhall view
@@ -0,0 +1,1 @@+{ x = { y = { a = { b = 1 }, c = { d = 2 } } } }
+ tests/format/dottedFieldsB.dhall view
@@ -0,0 +1,1 @@+{ x.y = { a.b = 1, c.d = 2 } }
+ tests/lint/success/optionalFoldBuildA.dhall view
@@ -0,0 +1,4 @@+{ example0 = Optional/fold+, example1 = Optional/build+, example2 = Optional/fold Natural (Some 1) Bool Natural/even False+}
+ tests/lint/success/optionalFoldBuildB.dhall view
@@ -0,0 +1,18 @@+{ example0 =+      λ(a : Type)+    → λ(o : Optional a)+    → λ(optional : Type)+    → λ(some : a → optional)+    → λ(none : optional)+    → merge { Some = some, None = none } o+, example1 =+      λ(a : Type)+    → λ ( build+        :   ∀(optional : Type)+          → ∀(some : a → optional)+          → ∀(none : optional)+          → optional+        )+    → build (Optional a) (λ(x : a) → Some x) (None a)+, example2 = merge { Some = Natural/even, None = False } (Some 1)+}
+ tests/regression/issue1646.dhall view
@@ -0,0 +1,1 @@+let f = \(d : Double) -> \(i : Integer) -> {=} in f 3.1 -1
+ tests/th/Department.dhall view
@@ -0,0 +1,1 @@+< Sales | Engineering | Marketing >
+ tests/th/Employee.dhall view
@@ -0,0 +1,1 @@+{ name : Text, department : ./Department.dhall }
+ tests/tutorial/substitution1.dhall view
@@ -0,0 +1,1 @@+Result.Failure +1
+ tests/tutorial/substitution2.dhall view
@@ -0,0 +1,1 @@+./substitution1.dhall
+ tests/tutorial/substitution3.dhall view
@@ -0,0 +1,1 @@+Foo