* Speed up type-checking large expressions bound with let
In #69, `let` was changed to substitute in the value of the bound
variable. However, if that value was large (e.g., the `constructor` of
a 300-constructor union), this has a very adverse impact on
performance where that value has to be re-typechecked at each use
rather than once when it is bound, leading to #412.
We can do better. #69 only changed anything when a type is being
bound. So we can check the type of the type being bound and change
strategy depending on whether it is `Type` or `Kind`: if it is a
`Type` we can get away with treating it like the pre-#69 behaviour; in
other cases, we fall back to substituting the value in.
* Remove a slow toList call in a hot-spot.
toList from insert-ordered-containers does some work to ensure that
the elements do follow insertion order. In this instance, insertion
order doesn't matter: we only need to peek at each element to make
sure it is well-typed. If there are multiple type errors, it does not
matter which gets reported first here.
This is less of a win than the previous commit, but it is still a
significant performance improvement.
* Omit re-typechecking variables at use sites.
* Benchmark Prelude files
* Add issue 108 example
* Some cleaning up
* Remove printing of files
* Add bounds
* Clean cabal formatting
* Using strict Text instead of lazy Text
* Fixing compilation errors
* Update tests
* Cleanup
* Revert benchmark merge
* Update comments to replace the mention of Builder to Text
* Benchmark Prelude files
* Add issue 108 example
* Some cleaning up
* Remove printing of files
* Add bounds
* Clean cabal formatting
* Add benchmark examples to extra source files
* Add Nix support for benchmarks
* This doesn't (yet) run or build the benchmarks in CI due to the long time
to execute all of them, but this does add them to the `shell.nix` so that
they can be run using local development
Fixes#402
The simplest way to summarize this bug is the following incorrect behavior
before this change:
```
>>> Dhall.Import.canonicalize (Directory {components = ["..",".."]})
Directory {components = []}
```
After this change the behavior is correct
```
>>> Dhall.Import.canonicalize (Directory {components = ["..",".."]})
Directory {components = ["..",".."]}
```
The standard specifies a depth-first import algorithm for resolving
imports but the Haskell implementation was using a breadth-first import
algorithm, which this change fixes
In tests on Dhall configs we use at work, I saw speedups between 33–90% on
extremely complicated configs with this change.
It mostly just adds a line calling `normalize`, but also threads the Normalizer
through a bunch of places to make sure we normalize properly for the context.
Hydra doesn't update a pull request if the derivation hasn't changed
since the last revision (i.e. a cache hit). This change adds a `pwd`
derivation which depends trivially on the current directory to force a
cache miss and status update
This is one step in a series of commits to update the Haskell
implementation to match the import semantics standardized in:
https://github.com/dhall-lang/dhall-lang/pull/127
This is a BREAKING CHANGE mostly due to restricting the grammar for
valid file paths and URLs. However, in practice most existing code
should still work after these changes.
Specifically, this change:
* Updates the grammar for file paths and URLs
* Simplifies and cleans up the semantics for canonicalizing paths (and
chains of paths)
The main difference in the grammar is that file paths and URL paths are
unified to have the same syntax and they are both more restricted than
before.
For example, the following URLs are no longer valid:
* `http://example.com` (missing a path to a file)
* `http://example.com/()` (invalid path characters)
... and the following paths are no longer valid:
* `/?#` (invalid path characters)
Note that this actually deviates from the standard in one way: file
paths no longer permit `?` and `#` characters (whereas the standard
allows them). However, in the course of testing these changes I
realized that if file paths permit `?` and `#` characters and you unify
URLs to also permit them then you get an ambiguous grammar where a `?`
or `#` in a URL could be interpreted as either part of a path component
or part of a query parameter or fragment.
The semantics for canonicalizing paths is a straightforward translation
of the standard to Haskell code.
Relevant to #362.
Previously, if an import contained additional imports, it wouldn’t get
cached. This fixes that, with a couple related changes:
- type checking happens in the failed-lookup branch, rather than having to
return a `cached` boolean,
- the normalized form of the import is used more consistently (although this
doesn’t fix the related normalization problem around `../`)
Not sure if this is a change you’re interested in. IMO, it’s nice for stack
users even if they don’t use Nix, since it makes the dependencies explicit.
Dhall used to support importing a directory, which would default to
importing a file named `@` underneath that directory (similar to how
`default.nix` works in Nix). This change drops support for that since
there is no plan to standardize that feature. I view this as sort of
a mis-feature that Dhall inherited from Morte because it it confusing
magic that deteriorates error messages when importing files. Support
for `@` also complicates the standardization of the import system, so
I prefer to just drop support for it to keep things simple.
Fixes#383
Dhall has a standard way to report where hash mismatch failure occur but
I forgot to use this reporting system when implementing the hash
mismatch failure.
For example, using this file:
```bash
$ cat example.dhall
./Prelude/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ae
```
... the error message you would get before this change was:
```bash
$ dhall <<< './example.dhall'
Error: Import integrity check failed
Expected hash:
↳ b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ae
Actual hash:
↳ b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
```
... and the error message you get after this change is:
```bash
$ dist/build/dhall/dhall <<< './example.dhall'
↳ ./example.dhall
↳ ./Prelude/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ae
Error: Import integrity check failed
Expected hash:
↳ b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ae
Actual hash:
↳ b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
```
... as standardized in https://github.com/dhall-lang/dhall-lang/pull/141
Now `Natural`s no longer require a leading `+` and non-negative `Integer`s
require a leading `+`
This also adds a `doctest` test suite to prevent regressions in haddock
examples
This updates the data types to match the terminology used in the
standard. Specifically, "path" specifically refers to a directory or
file, whereas "import" is a broader term encapsulating URLs and
environment variables.
This is a breaking change but an easy one to adapt to. Most downstream
consumers of the API just use the `Path` type, and this change includes
a `Path` type synonym for backwards compatibility.
The `GeneralizedNewtypeDeriving` extension was not being used at all
The `BangPatterns` extension was not necessary because the argument `n` was
already being forced before each modification
This adds new `dhall version`, `dhall resolve`, `dhall type`, and
`dhall normalize` subcommands. The latter three subcommands can be used
to run just one phase of the interpreter.
If you omit the subcommand then the executable behaves the same as
before.
Related to #346
This fixes the `GenericInject` instance for a sum type with two
constructors to include the type of the alternative constructor. For
example, before this change you would get the following incorrect
conversion:
```
$ cabal repl lib:dhall
>>> :set -XDeriveGeneric
>>> :set -XDeriveAnyClass
>>> data Amount = Debit Scientific | Credit Scientific deriving (Show, Generic, Inject, Interpret)
>>> Dhall.Core.pretty (embed inject (Debit 5.45))
"< Debit = { _1 = 5.45 } >"
```
... which is missing the `Credit` alternative.
After this change you get the correct result:
```
< Debit = { _1 = 5.45 } | Credit : { _1 : Double } >
```
This fixes the `Buildable` instance for `Src` to use
`Text.Megaparsec.sourcePosPretty` instead of `Show` to give a
nicer-looking file/line/column position for error messages
Fixes#207
This expands Dhall's error messages to include concise "type diffs"
whenever an actual type doesn't match an expected type. For example,
here is an example diff for some small changes to a very large (6,159
lines) type:
```
dhall <<< '../dhall-to-cabal/dhall-to-cabal.dhall : ./type.dhall'
Use "dhall --explain" for detailed errors
Error: Expression doesn't match annotation
{ - license2 : …
, + license : …
, library : …
( ∀(… : { arch : ∀(… : < S390 : - Bool
+ {}
| …
>
)
→ …
, …
}
)
→ { build-tools : …
{ - version2 : …
, + version : …
, …
}
, default-extensions : …
< - NamedWildCards2 : …
| - UnboxedSums : …
| + DataKinds : …
| + NamedWildCards : …
| …
>
, …
}
)
, …
}
../dhall-to-cabal/dhall-to-cabal.dhall : ./type.dhall
```
These type diffs are always emitted (i.e. present even if the user does
not supply the `--explain` flag).
The long-term motivation for this change is so that we can eventually use a
separate `attoparsec`-based lexing step to greatly increase parsing speed since
the `trifecta`/`parsers` API doesn't allow tokens other than `Char`.
The secondary motivation for this is that `megaparsec` is a smaller dependency
that is more actively maintained.