Skip to content

Commit dc48911

Browse files
authored
Fix formatting of T.Some (#2608)
Fixes #2601 According to the standard the `Some` needs to be escaped when used as a field accessor because the `any-label` grammar rule kicks in, which specifically does not permit `Some`.
1 parent 40d0d39 commit dc48911

File tree

7 files changed

+93
-23
lines changed

7 files changed

+93
-23
lines changed

dhall-lsp-server/src/Dhall/LSP/Backend/Completion.hs

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Dhall.Context (Context, empty, insert, toList)
77
import Dhall.LSP.Backend.Diagnostics (Position, positionToOffset)
88
import Dhall.LSP.Backend.Parsing (holeExpr)
99
import Dhall.Parser (Src, exprFromText)
10+
import Dhall.Pretty (UnescapedLabel(..))
1011
import Dhall.TypeCheck (typeOf, typeWithA)
1112
import System.Directory (doesDirectoryExist, listDirectory)
1213
import System.Environment (getEnvironment)
@@ -186,9 +187,9 @@ completeProjections (CompletionContext context values) expr =
186187
-- complete a union constructor by inspecting the union value
187188
completeUnion _A (Union m) =
188189
let constructor (k, Nothing) =
189-
Completion (Dhall.Pretty.escapeLabel True k) (Just _A)
190+
Completion (Dhall.Pretty.escapeLabel AnyLabelOrSome k) (Just _A)
190191
constructor (k, Just v) =
191-
Completion (Dhall.Pretty.escapeLabel True k) (Just (Pi mempty k v _A))
192+
Completion (Dhall.Pretty.escapeLabel AnyLabelOrSome k) (Just (Pi mempty k v _A))
192193
in map constructor (Dhall.Map.toList m)
193194
completeUnion _ _ = []
194195

@@ -197,5 +198,5 @@ completeProjections (CompletionContext context values) expr =
197198
completeRecord (Record m) = map toCompletion (Dhall.Map.toList $ recordFieldValue <$> m)
198199
where
199200
toCompletion (name, typ) =
200-
Completion (Dhall.Pretty.escapeLabel True name) (Just typ)
201+
Completion (Dhall.Pretty.escapeLabel AnyLabel name) (Just typ)
201202
completeRecord _ = []

dhall/src/Dhall/Pretty.hs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module Dhall.Pretty
1515
, Dhall.Pretty.Internal.layoutOpts
1616

1717
, escapeEnvironmentVariable
18+
, UnescapedLabel(..)
1819
, escapeLabel
1920

2021
, temporalToText

dhall/src/Dhall/Pretty/Internal.hs

+35-16
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ module Dhall.Pretty.Internal (
3131
, prettyEnvironmentVariable
3232

3333
, prettyConst
34+
, UnescapedLabel(..)
3435
, escapeLabel
3536
, prettyLabel
3637
, prettyAnyLabel
@@ -518,26 +519,44 @@ headCharacter c = alpha c || c == '_'
518519
tailCharacter :: Char -> Bool
519520
tailCharacter c = alphaNum c || c == '_' || c == '-' || c == '/'
520521

522+
-- | The set of labels which do not need to be escaped
523+
data UnescapedLabel
524+
= NonReservedLabel
525+
-- ^ This corresponds to the `nonreserved-label` rule in the grammar
526+
| AnyLabel
527+
-- ^ This corresponds to the `any-label` rule in the grammar
528+
| AnyLabelOrSome
529+
-- ^ This corresponds to the `any-label-or-some` rule in the grammar
530+
521531
-- | Escape a label if it is not valid when unquoted
522-
escapeLabel :: Bool -> Text -> Text
523-
escapeLabel allowReserved l =
532+
escapeLabel :: UnescapedLabel -> Text -> Text
533+
escapeLabel allowedLabel l =
524534
case Text.uncons l of
525535
Just (h, t)
526-
| headCharacter h && Text.all tailCharacter t && (notReservedIdentifier || (allowReserved && someOrNotLanguageKeyword)) && l /= "?"
536+
| headCharacter h && Text.all tailCharacter t && allowed && l /= "?"
527537
-> l
528538
_ -> "`" <> l <> "`"
529-
where
530-
notReservedIdentifier = not (Data.HashSet.member l reservedIdentifiers)
531-
someOrNotLanguageKeyword = l == "Some" || not (Data.HashSet.member l reservedKeywords)
539+
where
540+
allowed = case allowedLabel of
541+
NonReservedLabel -> notReservedIdentifier
542+
AnyLabel -> notReservedKeyword
543+
AnyLabelOrSome -> notReservedKeyword || l == "Some"
544+
545+
notReservedIdentifier = not (Data.HashSet.member l reservedIdentifiers)
532546

533-
prettyLabelShared :: Bool -> Text -> Doc Ann
547+
notReservedKeyword = not (Data.HashSet.member l reservedKeywords)
548+
549+
prettyLabelShared :: UnescapedLabel -> Text -> Doc Ann
534550
prettyLabelShared b l = label (Pretty.pretty (escapeLabel b l))
535551

536552
prettyLabel :: Text -> Doc Ann
537-
prettyLabel = prettyLabelShared False
553+
prettyLabel = prettyLabelShared NonReservedLabel
538554

539555
prettyAnyLabel :: Text -> Doc Ann
540-
prettyAnyLabel = prettyLabelShared True
556+
prettyAnyLabel = prettyLabelShared AnyLabel
557+
558+
prettyAnyLabelOrSome :: Text -> Doc Ann
559+
prettyAnyLabelOrSome = prettyLabelShared AnyLabelOrSome
541560

542561
prettyKeys
543562
:: Foldable list
@@ -571,7 +590,7 @@ prettyKeys prettyK keys = Pretty.group (Pretty.flatAlt long short)
571590
prettyLabels :: [Text] -> Doc Ann
572591
prettyLabels a
573592
| null a = lbrace <> rbrace
574-
| otherwise = braces (map (duplicate . prettyAnyLabel) a)
593+
| otherwise = braces (map (duplicate . prettyAnyLabelOrSome) a)
575594

576595
prettyNumber :: Integer -> Doc Ann
577596
prettyNumber = literal . Pretty.pretty
@@ -846,7 +865,7 @@ prettyPrinters characterSet =
846865
prettyKeyValue prettyKey prettyOperatorExpression equals
847866
(makeKeyValue b c)
848867

849-
prettyKey (WithLabel text) = prettyAnyLabel text
868+
prettyKey (WithLabel text) = prettyAnyLabelOrSome text
850869
prettyKey WithQuestion = syntax "?"
851870
prettyExpression (Assert a) =
852871
Pretty.group (Pretty.flatAlt long short)
@@ -1558,7 +1577,7 @@ prettyPrinters characterSet =
15581577
prettyRecord :: Pretty a => Map Text (RecordField Src a) -> Doc Ann
15591578
prettyRecord =
15601579
( braces
1561-
. map (prettyKeyValue prettyAnyLabel prettyExpression colon . adapt)
1580+
. map (prettyKeyValue prettyAnyLabelOrSome prettyExpression colon . adapt)
15621581
. Map.toList
15631582
)
15641583
where
@@ -1615,14 +1634,14 @@ prettyPrinters characterSet =
16151634
| Var (V key' 0) <- Dhall.Syntax.shallowDenote val
16161635
, key == key'
16171636
, not (containsComment mSrc2) ->
1618-
duplicate (prettyKeys prettyAnyLabel [(mSrc0, key, mSrc1)])
1637+
duplicate (prettyKeys prettyAnyLabelOrSome [(mSrc0, key, mSrc1)])
16191638
_ ->
1620-
prettyKeyValue prettyAnyLabel prettyExpression equals kv
1639+
prettyKeyValue prettyAnyLabelOrSome prettyExpression equals kv
16211640

16221641
prettyAlternative (key, Just val) =
1623-
prettyKeyValue prettyAnyLabel prettyExpression colon (makeKeyValue (pure key) val)
1642+
prettyKeyValue prettyAnyLabelOrSome prettyExpression colon (makeKeyValue (pure key) val)
16241643
prettyAlternative (key, Nothing) =
1625-
duplicate (prettyAnyLabel key)
1644+
duplicate (prettyAnyLabelOrSome key)
16261645

16271646
prettyUnion :: Pretty a => Map Text (Maybe (Expr Src a)) -> Doc Ann
16281647
prettyUnion =

dhall/src/Dhall/TypeCheck.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import Dhall.Eval
4747
, Val (..)
4848
, (~>)
4949
)
50-
import Dhall.Pretty (Ann)
50+
import Dhall.Pretty (Ann, UnescapedLabel(..))
5151
import Dhall.Src (Src)
5252
import Lens.Family (over)
5353
import Prettyprinter (Doc, Pretty (..), vsep)
@@ -2915,7 +2915,7 @@ prettyTypeMessage (InvalidDuplicateField k expr0 expr1) =
29152915
\ \n\
29162916
\... which is not a record type \n"
29172917
where
2918-
txt0 = insert (Dhall.Pretty.Internal.escapeLabel True k)
2918+
txt0 = insert (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome k)
29192919
txt1 = insert expr0
29202920
txt2 = insert expr1
29212921

@@ -3073,7 +3073,7 @@ prettyTypeMessage (DuplicateFieldCannotBeMerged ks) = ErrorMessages {..}
30733073
\ \n\
30743074
\" <> txt1 <> "\n"
30753075
where
3076-
txt0 = insert (Dhall.Pretty.Internal.escapeLabel True (NonEmpty.head ks))
3076+
txt0 = insert (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome (NonEmpty.head ks))
30773077

30783078
txt1 = insert (toPath ks)
30793079

@@ -5055,7 +5055,7 @@ checkContext context =
50555055
toPath :: (Functor list, Foldable list) => list Text -> Text
50565056
toPath ks =
50575057
Text.intercalate "."
5058-
(Foldable.toList (fmap (Dhall.Pretty.Internal.escapeLabel True) ks))
5058+
(Foldable.toList (fmap (Dhall.Pretty.Internal.escapeLabel AnyLabelOrSome) ks))
50595059

50605060
duplicateElement :: Ord a => [a] -> Maybe a
50615061
duplicateElement = go Data.Set.empty

dhall/tests/format/issue2601A.dhall

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
let T = < Some | Type >
2+
3+
let t
4+
: T
5+
= T.`Some`
6+
7+
let x
8+
: T
9+
= T.Type
10+
11+
in True

dhall/tests/format/issue2601B.dhall

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
let T = < Some | Type >
2+
3+
let t
4+
: T
5+
= T.`Some`
6+
7+
let x
8+
: T
9+
= T.Type
10+
11+
in True

nix/packages/lsp-test.nix

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{ mkDerivation, aeson, aeson-pretty, ansi-terminal, async, base
2+
, bytestring, co-log-core, conduit, conduit-parse, containers
3+
, data-default, Diff, directory, exceptions, extra, filepath, Glob
4+
, hspec, lens, lib, lsp, lsp-types, mtl, parser-combinators
5+
, process, row-types, some, text, time, transformers, unix
6+
, unliftio
7+
}:
8+
mkDerivation {
9+
pname = "lsp-test";
10+
version = "0.15.0.1";
11+
sha256 = "ad5be9baa344337b87958dfeb765e3edceca47c4ada57fb1ffeccf4056c57ad8";
12+
libraryHaskellDepends = [
13+
aeson aeson-pretty ansi-terminal async base bytestring co-log-core
14+
conduit conduit-parse containers data-default Diff directory
15+
exceptions filepath Glob lens lsp lsp-types mtl parser-combinators
16+
process row-types some text time transformers unix
17+
];
18+
testHaskellDepends = [
19+
aeson base co-log-core containers data-default directory filepath
20+
hspec lens lsp mtl parser-combinators process text unliftio
21+
];
22+
testToolDepends = [ lsp ];
23+
benchmarkHaskellDepends = [ base extra lsp process ];
24+
homepage = "https://github.com/haskell/lsp/blob/master/lsp-test/README.md";
25+
description = "Functional test framework for LSP servers";
26+
license = lib.licenses.bsd3;
27+
}

0 commit comments

Comments
 (0)