Commit Graph

1125 Commits

Author SHA1 Message Date
Simon Jakobi
b2cbc8227f Remove usage of legacy Optional syntax (#1091)
* Remove usage of legacy Optional syntax

* Dhall.JSON: Use multilet in examples

* Update dhall-json/src/Dhall/JSON.hs

Co-Authored-By: Gabriel Gonzalez <Gabriel439@gmail.com>

* Update dhall-json/src/Dhall/JSON.hs

Co-Authored-By: Gabriel Gonzalez <Gabriel439@gmail.com>

* Update dhall-json/src/Dhall/JSON.hs

Co-Authored-By: Gabriel Gonzalez <Gabriel439@gmail.com>

* Update dhall-nix/src/Dhall/Nix.hs

Co-Authored-By: Gabriel Gonzalez <Gabriel439@gmail.com>

* Update dhall-nix/src/Dhall/Nix.hs

Co-Authored-By: Gabriel Gonzalez <Gabriel439@gmail.com>

* Revert changes to travis.yml

* Lint travis.dhall
2019-07-14 18:36:41 +00:00
Gabriel Gonzalez
e49710166e
Add dhall-json support for unions as keys (#1094)
This is inspired by this StackOverflow question:

https://stackoverflow.com/questions/56967374/dynamic-records-key-type
2019-07-12 22:25:46 -07:00
Gabriel Gonzalez
e0bd21e25d
Update web page (#1079)
The main improvements are:

* Add one-line summary of what Dhall is

  This is based on user feedback that some people could not tell what
  Dhall was based on the home page

* Replace "Tough on messes" section with "Integration friendly" section

  This is based on user feedback that the nethack example wasn't working
  for them and also because of a large number of questions in online
  discussions about how to integrate Dhall

* Fix tutorial examples to put public/private keys under `~/.ssh`

* Link to newly-added Wiki pages
2019-07-09 11:15:07 -07:00
Gabriel Gonzalez
90b62ee9d7 Replace dhall-to-text with dhall text subcommand (#1090)
Fixes #1087
2019-07-08 17:18:09 +00:00
Frederik Ramcke
8ae7b603fe
dhall-lsp-server: Fix cache to correctly invalidate transitive dependencies (#1069)
* Move "Dot" import graph generation to Dhall.Main

Previously `Dhall.Import` would generate the import graph in "dot"
format while resolving imports. This change simplifies `Dhall.Import` to
only keep track of the adjacency list representing the import graph,
moving the logic for generating "dot" files to Dhall.Main.

This change will allow us to implement proper cache invalidation for
`dhall-lsp-server`.

* Correctly invalidate transitive dependencies

Fixes dhall-lsp-server`s caching behaviour to correctly invalidate
cached imports that (possibly indirectly) depend on the changed file.

Example:

Suppose we have the following three files:
{- In A.dhall -} 2 : ./B.dhall
{- In B.dhall -} ./C.dhall
{- In C.dhall -} Natural

Previously, changing C.dhall to `Text` would not cause `A.dhall` to stop
type-checking, since the old version of `B.dhall` (which evaluated to
`Natural`) would still have been in the cache. This change fixes that
behaviour.

* Make edges of import graph self-documenting

As suggested by @Gabriel439

* Don't cache expressions manually

After computing the diagnostics for a given file we added its normal
form to the cache, but forgot to add its dependencies to the dependency
graph. This bug points out that keeping the import graph consistent
manually is probably not a good idea. With this commit we never mess
with the import cache manually; this means that files are only cached
once they are depended upon by some other file, potentially causing us
to duplicate work (but no more than once).

* Fix left-overs from previous commit
2019-07-08 10:55:15 +00:00
Gabriel Gonzalez
aff138e192 Handle empty alternatives when converting from JSON (#1083)
* Handle empty alternatives when converting from JSON

Fixes https://github.com/dhall-lang/dhall-haskell/issues/1074

`dhall-to-{json,yaml}` treat empty alternatives as strings of the
same name, but `{json,yaml}-to-dhall` were missing the corresponding
logic to decode strings to empty alternatives, which this change
fixes.

This also ensures that the conversion logic contains no more
`undefined`s, by making the union conversion branch total.

* Clarify successful cases for union handling

Co-Authored-By: Simon Jakobi <simon.jakobi@gmail.com>

* Add missing trailing newline

... as caught by @sjakobi
2019-07-08 03:09:24 +00:00
Simon Jakobi
5339f1893d
Mergify: Add "merged" condition for "delete_head_branch" action (#1089)
I came accross https://medium.com/mergify/keep-your-repository-clean-delete-your-merged-branches-4b779f4848ae
which points out that I need a condition here!
2019-07-08 04:20:47 +02:00
Simon Jakobi
22428f9e1f
Reapply "Mergify: Delete head branch after merge (#1064)" (#1086)
This reverts commit 4004d62f28.
2019-07-07 19:56:39 +02:00
Gabriel Gonzalez
635a4489d2 Fix unexpected decoding successes in tests (#1088)
Fixes https://github.com/dhall-lang/dhall-haskell/issues/1082

All of the successes are due to accepting expressions that would not
have been produced by a compliant encoder, such as:

* Expressions that use a variable name of `_` that could have been
  encoded more compactly

* An expression tagged as a `Natural` number storing a negative number

* An expression encoding a function appled to 0 arguments
2019-07-07 17:22:53 +00:00
Simon Jakobi
f1234c4efa Don't typecheck the head of a list twice. (#1085) 2019-07-07 16:50:06 +00:00
Simon Jakobi
e40d0bc624 Simplify typechecking of Combine and CombineTypes (#1067)
Also add Dhall.Map.outerJoin, inspired by Semialign.align.
2019-07-07 16:00:25 +00:00
Simon Jakobi
d7114a32de Simplify normalization of record projection (#1071)
…via new functions Dhall.Map.{keysSet,restrictKeys} and
Dhall.Set.fromSet.

Also apply these functions in a few more cases.
2019-07-07 14:33:07 +00:00
Gabriel Gonzalez
462f82a0f8 Build against optparse-applicative-0.15 (#1081)
Related to https://github.com/commercialhaskell/stackage/issues/4693
2019-07-07 11:49:11 +00:00
Simon Jakobi
f873b0d66e Increase coverage of acceptance tests (#1072)
* dhall:tasty: Unskip a few tests

These remain broken:

- tests/parser/failure/annotation
- tests/parser/failure/missingSpace
- tests/parser/failure/unit/ImportEnvWrongEscape
- tests/parser/failure/unit/ListLitEmptyAnnotation
- tests/parser/failure/unit/ListLitEmptyPrecedence
- tests/parser/success/unit/MergeParenAnnotation

* Typo

* Add binary-decode failure tests

A few pass, but these are broken:

- tests/binary-decode/failure/unit/ApplyNoArgs
- tests/binary-decode/failure/unit/LambdaExplicitlyNamedUnderscore
- tests/binary-decode/failure/unit/NaturalNegativeOne
- tests/binary-decode/failure/unit/PiExplicitlyNamedUnderscore
- tests/binary-decode/failure/unit/VariableExplicitlyNamedUnderscore

* dhall:tasty: Add semantic-hash tests
2019-07-07 11:00:55 +00:00
Gabriel Gonzalez
b8e19d614a Fix dhall-json's support for preserving alternative names (#1080)
* Fix `dhall-json`'s support for preserving alternative names

... as caught by @sjakobi in the course of #1077

The code has to be updated to reflect the new normal forms for
union literals

* Add tests

... as suggested by @sjakobi
2019-07-07 10:27:54 +00:00
Simon Jakobi
3b4f826eda Dhall.Map: Remove the keys list when sorting (#1066)
Also add the unorderedSingleton and unorderedFromList functions.

This speeds up the "issue 412" benchmark by ~9% and "union performance"
by ~2%.
2019-07-07 07:21:04 +00:00
Gabriel Gonzalez
c116207663 Update to latest dhall-lang (#1084)
* Update to latest `dhall-lang`

The main updates are to support the following two changes to the
standard:

* https://github.com/dhall-lang/dhall-lang/pull/604
* https://github.com/dhall-lang/dhall-lang/pull/611

* `s/fields/fails/`

... as caught by @sjakobi

Co-Authored-By: Simon Jakobi <simon.jakobi@gmail.com>
2019-07-07 06:08:58 +00:00
Frederik Ramcke
2cd4ed948f dhall-lsp-server: Improve type-on-hover behaviour over binders (#1062)
* Improve type-on-hover behaviour over binders

Dhall's parser does not generate `Src` annotations for the names in
binders, which means that it's not quite as straight-forward to check
whether the user meant to hover over it and see its type as one would
hope. As a result, the current "naive" implementation sometimes behaves
slightly unintuitively and returns the type of the entire expression,
rather than the type of the bound variable. E.g.
  let x = 2 in "text"
      ~
would result in the type `Text` being displayed, rather than `Natural`
as one would expect. Since the language server also marks the expression
whose type is being displayed, the behaviour isn't quite that bad in
practice (we aren't falsely led to believe that `x` has type `Text`).

This change recovers the `Src` information describing the bound variable
names and handles those cases in a way that should be more in line with
the expectations of the user.

* Fix exprAt not handling multi-lets correctly

* Fix merge left-overs
2019-07-06 23:17:52 +00:00
Simon Jakobi
76efe630b2 Remove cruft related to the removed 'constructors' keyword (#1077) 2019-07-06 22:38:02 +00:00
Simon Jakobi
9a2e25b92d Dhall.Map.fromList: Fix docs (#1078)
Closes #1052.
2019-07-06 20:58:32 +00:00
Simon Jakobi
28fc9e1870 Dhall.Eval.eqMapsBy: Compare map sizes before contents (#1065)
Data.Map.size is O(1), so we expose it via Dhall.Map.
2019-07-05 04:04:08 +00:00
Frederik Ramcke
53e1967754
dhall-lsp-server: Normalize types before displaying them to the user (#1060)
* Normalize types before displaying them to the user

Previously, the type displayed when hovering over the arrow in a lambda
(or forall) binder would not always be normal, e.g.
  \(n : {Left = Natural, Right = Natural}.Left) -> n + n
                                                ~
would result in
  forall (n : {Left = Natural, Right = Natural}.Left) -> Natural
being displayed.

The (expected) normal type would be:
  forall (n : Natural) -> Natural

This fix normalises types before displaying them to the user (fixes both
the type-on-hover and annotate-let behaviour).

* Move normalisation from typeAt' to typeAt

This way we only have to worry about it one place, rather than  in each
clause of `typeAt'`.
2019-07-05 03:58:44 +00:00
Simon Jakobi
4004d62f28
Revert "Mergify: Delete head branch after merge (#1064)" (#1070)
Context: https://github.com/dhall-lang/dhall-haskell/pull/1064#issuecomment-508552667

This reverts commit 817c833643.
2019-07-04 22:23:14 +02:00
Simon Jakobi
6afbba449d Let Mergify handle one PR at a time (#1068)
Docs: https://doc.mergify.io/actions.html#merge
2019-07-04 08:05:50 -07:00
Simon Jakobi
817c833643
Mergify: Delete head branch after merge (#1064)
Docs: https://doc.mergify.io/examples.html#deleting-merged-branch
2019-07-04 09:11:34 +02:00
Simon Jakobi
c7e48bf497 Skip re-typechecking the first non-empty union alternative (#1057)
For the deep-nested-large-record benchmark, this results in a
speedup of about 0.5–1%.
2019-07-03 16:57:05 +00:00
Simon Jakobi
e061f35c4c Simplify Dhall.Parser.Combinators.toMap (#1053)
This changes the parsing error for some cases.

Previously:

    ⊢ {b=1, a=1, b=1, a=1}

    Error: Invalid input

    (stdin):1:20:
      |
    1 | {b=1, a=1, b=1, a=1}
      |                    ^
    duplicate field: b

Now:

    ⊢ {b=1, a=1, b=1, a=1}

    Error: Invalid input

    (stdin):1:20:
      |
    1 | {b=1, a=1, b=1, a=1}
      |                    ^
    duplicate field: a

Also add a new function to Dhall.Map: fromListWithKey
2019-07-03 15:46:13 +00:00
Gabriel Gonzalez
d559662f50
Enable Mergify support (#1059)
Related to https://github.com/dhall-lang/dhall-haskell/issues/1058

This is an attempt to test drive the Mergify GitHub app.  Unfortunately, the
only way to know for sure if the app works is to merge this configuration
into `master`, but if it does not work out then I will follow up with a pull
request to revert this change.
2019-07-03 07:58:30 -07:00
Frederik Ramcke
3a120d277f
Change rangeFromDhall to exclude trailing whitespace (#1046)
This gets rid of the separate `santiseRange` utility function that we
used to exclude trailing whitespace from source code ranges. As a result
of this change, we no longer have to carry around the original source
code everywhere to be able to santise ranges after the fact.
2019-07-03 09:25:24 +00:00
Gabriel Gonzalez
af0e77ce00
Consistently format multi-line strings (#1056)
Fixes #973

The formatter was behaving inconsistently for multi-line strings
depending on whether or not they were at the top level or nested as
a subexpression.  For example, the same multi-line string would be
rendered in multi-line form if it was at the top level and rendered
compactly if nested within another expression.

The root cause was that the pretty-printing logic was missing a top-level
`Pretty.group` call (which is the function responsible for enabling
compact representations if they fit), which this change fixes.
2019-07-02 13:54:54 -07:00
Simon Jakobi
51a020e3e4
Dhall.Map: Reflect original key ordering in Ord instance (#1050) 2019-07-02 19:44:33 +02:00
Gabriel Gonzalez
f5819dd6d6 Improve performance of type-checking record literals (#1048)
While benchmarking the example from #769 I saw that a significant
amount of time was spent benchmarking record literals.  When I looked
at the code more closely I saw that the first key in the record literal
was being type-checked twice (once to figure out the record's associated
type-checking constant and once as part of the `process` loop).

This change fixes that, which speeds up interpretation of the large
example by 9%:

Before:

```
time                 18.13 s    (18.11 s .. 18.16 s)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 18.09 s    (18.07 s .. 18.11 s)
std dev              21.92 ms   (10.66 ms .. 29.76 ms)
variance introduced by outliers: 19% (moderately inflated)
```

After:

```
time                 16.53 s    (16.49 s .. 16.60 s)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 16.59 s    (16.56 s .. 16.64 s)
std dev              43.65 ms   (6.227 ms .. 56.35 ms)
variance introduced by outliers: 19% (moderately inflated)
```
2019-07-02 18:42:05 +02:00
Simon Jakobi
0057901e58 Dhall.Map: Change Foldable and Traversable instances to respect the key ordering (#1051) 2019-07-02 07:47:41 -07:00
Gabriel Gonzalez
92bdd56a34
Switch Var to use an Int (#1044)
Related to: https://github.com/dhall-lang/dhall-haskell/issues/1039

We'll probably never see indices that exceed the space of an `Int` and
the interpreter would probably not be able to handle 9223372036854775807
nested binders anyway.
2019-07-01 17:24:13 -07:00
Frederik Ramcke
41161aa390
dhall-lsp-server: Implement caching (#1040)
* Rewriting Dhall.LSP.Backend.Dhall: Implement new API

The old "backend" consisted of a random collection of ways to invoke
Dhall:
- runDhall :: FilePath -> Text -> IO (Expr Src X)
- runDhallSafe :: FilePath -> Text -> IO (Maybe (Expr Src X))
- loadDhallExprSafe :: FilePath -> Text -> IO (Maybe (Expr Src X))

The new backend exposes a slightly more though-out API. This also lays
the foundation for performance improvements in the dhall lsp server via
caching.

* Reorder code in Dhall.LSP.Backend.Dhall

* Remove unused constructor

* Rewrite and document Backend.Formatting

* Refactor Dhall.LSP.Backend.Linting

* Refactor Dhall.LSP.Backend.ToJSON

* Adapt Diagnostics backend to the new Dhall API

* Remove old Dhall backend API

* Implement caching; revamp LSP frontend

This commit implements caching of Dhall expressions: we only need to
fetch, typecheck and normalise each import once per session, unless they
change! This means that `dhall-lsp-server` is now viable for non-trivial
Dhall projects, for example probing around in `dhall-nethack` everything
feels near-instantaneous once the imports have been resolved.

This implementation currently has a bug: we don't invalidate imports
transitively, i.e. if A.dhall loads B.dhall and B.dhall changes we do
not discard the cached version of A.dhall. This should be reasonably
easy to fix given some time with Dhall's import graph. Furthermore,
there is some cleaning up left to do:
  - Fix warnings
  - Reorganise things in a less ad-hoc way
  - Make the code a bit prettier

* Fix caching of errors

* Use `bimap` instead of `first` and `second`

* Re-export `Dhall.lint` rather than aliasing

Rids us of some boilderplate

* Use MVar instead of TVar for server state

The main benefit is that we get to use `modifyMVar_` which does updating
of the shared state for us (and gracefully handles any uncaught
exceptions).

* Don't invalidate hashed imports

Fixes a misinterpretation on my end of the correct behaviour regarding
the caching of imports. Quoting @Gabriel439:

> A hashed import is valid indefinitely once it is successfully
> resolved, even when the underlying import later becomes broken. That's
> why missing sha256:… works so long as the cache has that import cached
> (and this behavior is part of the standard).

* Cleanup Dhall.LSP.Backend.Dhall a little bit

* Add note about fixing cache invalidation

* Use TemplateHaskell to generate state lenses

* Make types of `typeAt` and `annotateLet` more expressive

Both assume the input to be well-typed; by using `WellTyped` rather than
`Expr Src X` as the type of their input we can make this explicit.

This change exposed a bug (also fixed in this commit) in the
type-on-hover functionality: we run `typeAt` only if the input was
well-typed _the last time we checked it_ (which was at the last save);
this means that if the code changed without being written to disk we
would happily try to normalise (in `typeAt`) non-well-typed code...

* Fix type of typecheck

Typecheck returned the well-typed _type_ of a given expression, while I
was assuming it would certify the input to be well-typed. Silly indeed.

* Remove `checkDhall` from Dhall.Backend.Diagnostics

Removes the left-over stub from the change to the new Dhall backend.

* Update comments and remove TODO note

* Remove superfluous parentheses

* Simplify MonadState code via lens combinators

* Use `guard` instead of matching on True

* Remove more superfluous parentheses
2019-07-01 17:30:32 +00:00
Simon Jakobi
15e981f61c
Fix benchmarks, run them on AppVeyor (#1033)
Since we only want to ensure that the benchmarks continue to
work, we use the following benchmark arguments to run them
as quickly as possible:

- `--quick` ensures that gauge runs only a single sample.
- `--min-duration=0` sets the number of iterations per sample to 1.
- `--include-first-iter` causes gauge to accept that one iteration
  instead of discarding it and running a second one.

This also removes the dhall-command benchmark:

This was a non-standard benchmark that failed when run
without input from stdin. To replace this profiling tool,
I have added instructions for profiling the main executables
to the README.
2019-07-01 12:52:43 +02:00
Fabrizio Ferrai
04d82120a4 Implement importing as Location (#1019) 2019-06-30 22:00:14 -07:00
Simon Jakobi
7647adba1a
Speed up Dhall.Map.unorderedTraverseWithKey_ (#1036)
This reduces the runtime of the `deep-nested-large-record` benchmark by about 50%.

Note that previously, contrary to its name and documentation, this function traversed a Dhall.Map in insertion order due to its use of Dhall.Map.toList! With this change, the traversal is changed to ascending key order.

Also:
- Fix the deep-nested-large-record benchmark

- Remove the map-operations benchmark: This benchmark actually reports a ~20% loss of performance for the unorderedTraverseWithKey_ change.  Since we eventually care about dhall's performance we it's better not to be mislead by a questionable micro-benchmark.
2019-06-30 19:54:13 +02:00
Dmitry Dolgov
0bf4e41020 Fix appveyor tests (#1037)
Fixes #1034

Fixes the `import/success/hashFromCache`  test on Windows

Disables currently broken dhall-lsp-server tests
2019-06-30 14:35:55 +02:00
Simon Jakobi
157c36b8a1 dhall-json: Use Dhall.Optics instead of lens (#1042)
This removes the following packages from `dhall-json`'s dependencies:

- adjunctions
- call-stack
- free
- invariant
- kan-extensions
- lens
- parallel
- reflection
- transformers-base
- void

* Fix bound on dhall
2019-06-29 14:58:17 -07:00
Gabriel Gonzalez
bb365dd0f3
Remove prettyDiff internal helper (#1038)
... as suggested by @sjakobi in https://github.com/dhall-lang/dhall-haskell/pull/1027#issuecomment-506516607

After some internal refactors, `prettyDiff` is now just an
alias for `Dhall.Diff.diffNormalized`, so it's no longer
necessary.
2019-06-28 07:30:15 -07:00
Gabriel Gonzalez
250fdfc348
Reject record projection when there is a field type mismatch (#1027)
Fixes https://github.com/dhall-lang/dhall-haskell/issues/1020

This also includes small fixes to the `MissingField` error message,
which I found along the way.
2019-06-27 21:55:09 -07:00
Gabriel Gonzalez
09016735fa
Use vertical bars for the left margin of source spans (#1030)
This separates the source from the line numbers using vertical bars
instead of colons.  The main reason for this is to more clearly
delimit the two and to also prevent the old colon from being confused
as a type annotation.
2019-06-27 20:37:10 -07:00
Gabriel Gonzalez
484182b74e
Remove the InvalidField error constructor (#1026)
Fixes https://github.com/dhall-lang/dhall-haskell/issues/1025

There were two error constructors related to invalid field types:

* `InvalidField`: for field types whose types were invalid type-checking
  constants
* `InvalidFieldType`: for all other invalid field types

As @sjakobi noted, there are no invalid field types for the former
category, so we can remove that category of error entirely.

Note that `InvalidField` was still being used in a few places, but each
of those uses should actually have been using `InvalidFieldType`
instead, which this change also fixes.
2019-06-27 13:19:16 -07:00
Simon Jakobi
57aab91241 Replace criterion with gauge (#1035)
This reduces build times for the benchmarks.
2019-06-27 09:41:42 -07:00
Simon Jakobi
79e33b46f3
Misc cleanup in Dhall.Map (#1029) 2019-06-27 09:15:51 +02:00
Simon Jakobi
8285625156
Add type-inference tests (#1023)
Closes #1021.
2019-06-27 07:23:24 +02:00
Simon Jakobi
634f1f3d9a
Allow Sort as type annotation (#1024)
Standardized in https://github.com/dhall-lang/dhall-lang/pull/507.
2019-06-27 05:59:53 +02:00
Clément Delafargue
b9aeb345e4 Make the type of extract richer (#1011)
see #387
2019-06-24 07:22:35 -07:00
Gabriel Gonzalez
c4de94224c
Improve error message for unsaturated merge (#1015)
This improves the error message when users attempt to apply `merge` to only
one argument, as suggested by:

https://github.com/dhall-lang/dhall-lang/issues/106#issuecomment-503523358

For example:

```
$ dhall <<< 'merge { Foo = True }'

Error: Invalid input

(stdin):2:1:
  |
2 | <empty line>
  | ^
unexpected end of input
expecting '.', second argument to ❰merge❱, or whitespace
```
2019-06-22 10:02:28 -07:00