on master help sign in
Improve canonicalization hints and add JSON decoder hint
70865f5Evan Czaplicki
src/AST/Variable.hs+6−1
@@ -9,7 +9,7 @@ module AST.Variable
9 , int, float, char, string, tuple
9 , int, float, char, string, tuple
10 , list, cons, nil
10 , list, cons, nil
11 , bool, true, false
11 , bool, true, false
12− , never, task, cmd, sub, router, shader
12+ , never, task, cmd, sub, router, shader, decoder
13 , isLocalHome, isCons
13 , isLocalHome, isCons
14 , is, isJson, isMaybe, isArray, isTask, isList
14 , is, isJson, isMaybe, isArray, isTask, isList
15 , isKernel, isTuple, isPrim, isLocal
15 , isKernel, isTuple, isPrim, isLocal
@@ -192,6 +192,11 @@ shader =
192 fromModule (ModuleName.Canonical Pkg.webgl "WebGL") "Shader"
192 fromModule (ModuleName.Canonical Pkg.webgl "WebGL") "Shader"
193
193
194
194
195+decoder :: Canonical
196+decoder =
197+ inCore "Json.Decode" "Decoder"
198+
199+
195
200
196-- VARIABLE RECOGNIZERS
201-- VARIABLE RECOGNIZERS
197
202
src/Canonicalize/Variable.hs+9−9
@@ -68,18 +68,18 @@ variable region env var =
68 logVar v
68 logVar v
69
69
70 Just vs ->
70 Just vs ->
71− preferLocals region env "variable" vs var
71+ preferLocals region env Error.BadValue vs var
72
72
73 Nothing ->
73 Nothing ->
74− notFound region "variable" (Map.keys (Env._values env)) var
74+ notFound region Error.BadValue (Map.keys (Env._values env)) var
75
75
76
76
77tvar :: R.Region -> Env.Env -> Text -> Result (Either Var.Canonical (Var.Canonical, [Text], Type.Canonical))
77tvar :: R.Region -> Env.Env -> Text -> Result (Either Var.Canonical (Var.Canonical, [Text], Type.Canonical))
78tvar region env var =
78tvar region env var =
79 case unions ++ aliases of
79 case unions ++ aliases of
80− [] -> notFound region "type" (Map.keys (Env._unions env) ++ Map.keys (Env._aliases env)) var
80+ [] -> notFound region Error.BadType (Map.keys (Env._unions env) ++ Map.keys (Env._aliases env)) var
81 [v] -> logVarWith extract v
81 [v] -> logVarWith extract v
82− vs -> preferLocals' region env extract "type" vs var
82+ vs -> preferLocals' region env extract Error.BadType vs var
83 where
83 where
84 unions =
84 unions =
85 map Left (maybe [] Set.toList (Map.lookup var (Env._unions env)))
85 map Left (maybe [] Set.toList (Map.lookup var (Env._unions env)))
@@ -100,10 +100,10 @@ pvar region env var actualArgs =
100 foundArgCheck value
100 foundArgCheck value
101
101
102 Just values ->
102 Just values ->
103− foundArgCheck =<< preferLocals' region env fst "pattern" values var
103+ foundArgCheck =<< preferLocals' region env fst Error.BadPattern values var
104
104
105 Nothing ->
105 Nothing ->
106− notFound region "pattern" (Map.keys (Env._patterns env)) var
106+ notFound region Error.BadPattern (Map.keys (Env._patterns env)) var
107 where
107 where
108 foundArgCheck (name, expectedArgs) =
108 foundArgCheck (name, expectedArgs) =
109 if actualArgs == expectedArgs then
109 if actualArgs == expectedArgs then
@@ -117,7 +117,7 @@ pvar region env var actualArgs =
117-- FOUND
117-- FOUND
118
118
119
119
120−preferLocals :: R.Region -> Env.Env -> Text -> [Var.Canonical] -> Text -> Result Var.Canonical
120+preferLocals :: R.Region -> Env.Env -> Error.VarKind -> [Var.Canonical] -> Text -> Result Var.Canonical
121preferLocals region env =
121preferLocals region env =
122 preferLocals' region env id
122 preferLocals' region env id
123
123
@@ -126,7 +126,7 @@ preferLocals'
126 :: R.Region
126 :: R.Region
127 -> Env.Env
127 -> Env.Env
128 -> (a -> Var.Canonical)
128 -> (a -> Var.Canonical)
129− -> Text
129+ -> Error.VarKind
130 -> [a]
130 -> [a]
131 -> Text
131 -> Text
132 -> Result a
132 -> Result a
@@ -217,7 +217,7 @@ isOp name =
217-- NOT FOUND
217-- NOT FOUND
218
218
219
219
220−notFound :: R.Region -> Text -> [Text] -> Text -> Result a
220+notFound :: R.Region -> Error.VarKind -> [Text] -> Text -> Result a
221notFound region kind possibilities var =
221notFound region kind possibilities var =
222 let name =
222 let name =
223 toVarName var
223 toVarName var
src/Reporting/Error/Canonicalize.hs+206−110
@@ -1,6 +1,20 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−module Reporting.Error.Canonicalize where
3+module Reporting.Error.Canonicalize
4+ ( Error(..)
5+ , variable
6+ , VarKind(..)
7+ , VarProblem(..)
8+ , argMismatch
9+ , moduleNotFound
10+ , valueNotFound
11+ , AliasError(..)
12+ , alias
13+ , port
14+ , toReport
15+ , extractSuggestions
16+ )
17+ where
4
18
5import Control.Arrow ((***))
19import Control.Arrow ((***))
6import qualified Data.Char as Char
20import qualified Data.Char as Char
@@ -9,6 +23,7 @@ import Data.Text (Text)
9
23
10import qualified AST.Declaration as Decl
24import qualified AST.Declaration as Decl
11import qualified AST.Expression.Canonical as Canonical
25import qualified AST.Expression.Canonical as Canonical
26+import qualified AST.Helpers as Help (isOp)
12import qualified AST.Module.Name as ModuleName
27import qualified AST.Module.Name as ModuleName
13import qualified AST.Pattern as P
28import qualified AST.Pattern as P
14import qualified AST.Type as Type
29import qualified AST.Type as Type
@@ -18,9 +33,7 @@ import qualified Reporting.Region as Region
18import qualified Reporting.Render.Type as RenderType
33import qualified Reporting.Render.Type as RenderType
19import qualified Reporting.Report as Report
34import qualified Reporting.Report as Report
20import qualified Reporting.Helpers as Help
35import qualified Reporting.Helpers as Help
21−import Reporting.Helpers
22− ( Doc, (<>), dullyellow, fillSep, i2t, indent, reflowParagraph, text
36+import Reporting.Helpers ( Doc, (<>), dullyellow, fillSep, green, i2t, indent, reflowParagraph, text )
23− )
24
37
25
38
26
39
@@ -46,26 +59,52 @@ data Error
46
59
47data VarError =
60data VarError =
48 VarError
61 VarError
49− { varKind :: Text
62+ { _kind :: VarKind
50− , varName :: Text
63+ , _name :: Text
51− , varProblem :: VarProblem
64+ , _problem :: VarProblem
52− , varSuggestions :: [Text]
65+ , _suggestions :: [Text]
53 }
66 }
54
67
55
68
56data VarProblem
69data VarProblem
57− = Ambiguous
70+ = Ambiguous
58− | UnknownQualifier Text Text
71+ | UnknownQualifier Text Text
59− | QualifiedUnknown Text Text
72+ | QualifiedUnknown Text Text
60− | ExposedUnknown
73+ | ExposedUnknown
61
74
62
75
63−variable :: Text -> Text -> VarProblem -> [Text] -> Error
76+variable :: VarKind -> Text -> VarProblem -> [Text] -> Error
64variable kind name problem suggestions =
77variable kind name problem suggestions =
65 Var (VarError kind name problem suggestions)
78 Var (VarError kind name problem suggestions)
66
79
67
80
68
81
82+-- KIND
83+
84+
85+data VarKind
86+ = BadValue
87+ | BadPattern
88+ | BadType
89+
90+
91+toKindInfo :: VarKind -> Text -> ( Doc, Doc, Doc )
92+toKindInfo kind name =
93+ case kind of
94+ BadValue ->
95+ if Help.isOp name then
96+ ( "an", "operator", text $ "(" <> name <> ")" )
97+ else
98+ ( "a", "value", text name )
99+
100+ BadPattern ->
101+ ( "a", "pattern", text name )
102+
103+ BadType ->
104+ ( "a", "type", text name )
105+
106+
107+
69-- PATTERN
108-- PATTERN
70
109
71
110
@@ -118,9 +157,9 @@ alias name expected actual =
118
157
119data PortError =
158data PortError =
120 PortError
159 PortError
121− { portName :: Text
160+ { _portName :: Text
122− , portType :: Type.Canonical
161+ , _portType :: Type.Canonical
123− , portMessage :: Maybe Text
162+ , _portMessage :: Maybe Text
124 }
163 }
125
164
126
165
@@ -130,54 +169,57 @@ port name tipe maybeMessage =
130
169
131
170
132
171
172+-- EXTRACT SUGGESTIONS
173+
174+
175+extractSuggestions :: Error -> Maybe [Text]
176+extractSuggestions err =
177+ case err of
178+ Var (VarError _ _ _ suggestions) ->
179+ Just suggestions
180+
181+ BadRecursion _ _ _ ->
182+ Nothing
183+
184+ BadInfix _ _ _ _ _ _ ->
185+ Nothing
186+
187+ Pattern _ ->
188+ Nothing
189+
190+ Alias _ ->
191+ Nothing
192+
193+ Import _ importError ->
194+ case importError of
195+ ModuleNotFound suggestions ->
196+ Just (map ModuleName.toText suggestions)
197+
198+ ValueNotFound _ suggestions ->
199+ Just suggestions
200+
201+ Export _ suggestions ->
202+ Just suggestions
203+
204+ DuplicateExport _ ->
205+ Nothing
206+
207+ Port _ ->
208+ Nothing
209+
210+ BadPort _ _ ->
211+ Nothing
212+
213+
214+
133-- TO REPORT
215-- TO REPORT
134
216
135
217
136toReport :: RenderType.Localizer -> Error -> Report.Report
218toReport :: RenderType.Localizer -> Error -> Report.Report
137toReport localizer err =
219toReport localizer err =
138 case err of
220 case err of
139− Var (VarError kind name problem suggestions) ->
221+ Var varError ->
140− let
222+ varErrorToReport varError
141− variableName =
142− kind <> " `" <> name <> "`"
143−
144− learnMore orMaybe =
145− Help.reflowParagraph $
146− orMaybe <> " `import` works different than you expect? Learn all about it here: "
147− <> Help.hintLink "imports"
148−
149− namingError overview maybeStarter specializedSuggestions =
150− Report.report "NAMING ERROR" Nothing overview $
151− case Help.maybeYouWant' maybeStarter specializedSuggestions of
152− Nothing ->
153− learnMore "Maybe"
154− Just doc ->
155− Help.stack [ doc, learnMore "Or maybe" ]
156− in
157− case problem of
158− Ambiguous ->
159− namingError
160− ("This usage of " <> variableName <> " is ambiguous.")
161− Nothing
162− suggestions
163−
164− UnknownQualifier qualifier localName ->
165− namingError
166− ("Cannot find " <> variableName)
167− (Just $ text $ "No module called `" <> qualifier <> "` has been imported.")
168− (map (\modul -> modul <> "." <> localName) suggestions)
169−
170− QualifiedUnknown qualifier localName ->
171− namingError
172− ("Cannot find " <> variableName)
173− (Just $ text $ "`" <> qualifier <> "` does not expose `" <> localName <> "`.")
174− (map (\v -> qualifier <> "." <> v) suggestions)
175−
176− ExposedUnknown ->
177− namingError
178− ("Cannot find " <> variableName)
179− Nothing
180− suggestions
181
223
182 BadRecursion region def defs ->
224 BadRecursion region def defs ->
183 case defs of
225 case defs of
@@ -302,78 +344,111 @@ toReport localizer err =
302 )
344 )
303
345
304
346
305−argMismatchReport :: Text -> Var.Canonical -> Int -> Int -> Report.Report
347+
306−argMismatchReport kind var expected actual =
348+-- VAR ERROR
349+
350+
351+varErrorToReport :: VarError -> Report.Report
352+varErrorToReport (VarError kind name problem suggestions) =
307 let
353 let
308− numArgs =
354+ learnMore orMaybe =
309− "too "
355+ Help.reflowParagraph $
310− <> (if actual < expected then "few" else "many")
356+ orMaybe <> " `import` works different than you expect? Learn all about it here: "
311− <> " arguments"
357+ <> Help.hintLink "imports"
358+
359+ namingError overview maybeStarter specializedSuggestions =
360+ Report.reportDoc "NAMING ERROR" Nothing overview $
361+ case Help.maybeYouWant' maybeStarter specializedSuggestions of
362+ Nothing ->
363+ learnMore "Maybe"
364+ Just doc ->
365+ Help.stack [ doc, learnMore "Or maybe" ]
366+
367+ specialNamingError specialHint =
368+ Report.reportDoc "NAMING ERROR" Nothing (cannotFind kind name) (Help.hsep specialHint)
312 in
369 in
313− Report.report
370+ case problem of
314− (Text.map Char.toUpper numArgs)
371+ Ambiguous ->
315− Nothing
372+ namingError (ambiguous kind name) Nothing suggestions
316− ( kind <> " " <> Var.toText var <> " has " <> numArgs <> "."
317− )
318− ( text $
319− "Expecting " <> i2t expected <> ", but got " <> i2t actual <> "."
320− )
321
373
374+ UnknownQualifier qualifier localName ->
375+ namingError
376+ (cannotFind kind name)
377+ (Just $ text $ "No module called `" <> qualifier <> "` has been imported.")
378+ (map (\modul -> modul <> "." <> localName) suggestions)
322
379
380+ QualifiedUnknown qualifier localName ->
381+ namingError
382+ (cannotFind kind name)
383+ (Just $ text $ "`" <> qualifier <> "` does not expose `" <> localName <> "`.")
384+ (map (\v -> qualifier <> "." <> v) suggestions)
323
385
324−extractSuggestions :: Error -> Maybe [Text]
386+ ExposedUnknown ->
325−extractSuggestions err =
326− case err of
387+ case name of
327− Var (VarError _ _ _ suggestions) ->
388+ "!=" -> specialNamingError (notEqualsHint name)
328− Just suggestions
389+ "!==" -> specialNamingError (notEqualsHint name)
390+ "===" -> specialNamingError equalsHint
391+ "%" -> specialNamingError modHint
392+ _ -> namingError (cannotFind kind name) Nothing suggestions
329
393
330− BadRecursion _ _ _ ->
331− Nothing
332
394
333− BadInfix _ _ _ _ _ _ ->
395+cannotFind :: VarKind -> Text -> [Doc]
334− Nothing
396+cannotFind kind rawName =
397+ let ( a, thing, name ) = toKindInfo kind rawName in
398+ [ "Cannot", "find", a, thing, "named", dullyellow name <> ":" ]
335
399
336− Pattern _ ->
337− Nothing
338
400
339− Alias _ ->
401+ambiguous :: VarKind -> Text -> [Doc]
340− Nothing
402+ambiguous kind rawName =
403+ let ( _a, thing, name ) = toKindInfo kind rawName in
404+ [ "This", "usage", "of", "the", dullyellow name, thing, "is", "ambiguous." ]
341
405
342− Import _ importError ->
343− case importError of
344− ModuleNotFound suggestions ->
345− Just (map ModuleName.toText suggestions)
346
406
347− ValueNotFound _ suggestions ->
407+notEqualsHint :: Text -> [Doc]
348− Just suggestions
408+notEqualsHint op =
409+ [ "Looking", "for", "the", "“not", "equal”", "operator?", "The", "traditional"
410+ , dullyellow $ text $ "(" <> op <> ")"
411+ , "is", "replaced", "by", green "(/=)", "in", "Elm.", "It", "is", "meant"
412+ , "to", "look", "like", "the", "“not", "equal”", "sign", "from", "math!", "(≠)"
413+ ]
349
414
350− Export _ suggestions ->
351− Just suggestions
352
415
353− DuplicateExport _ ->
416+equalsHint :: [Doc]
354− Nothing
417+equalsHint =
418+ [ "A", "special", dullyellow "(===)", "operator", "is", "not", "needed"
419+ , "in", "Elm.", "We", "use", green "(==)", "for", "everything!"
420+ ]
355
421
356− Port _ ->
357− Nothing
358
422
359− BadPort _ _ ->
423+modHint :: [Doc]
360− Nothing
424+modHint =
425+ [ "Rather", "than", "a", dullyellow "(%)", "operator,"
426+ , "Elm", "has", "a", green "modBy", "function."
427+ , "Learn", "more", "here:"
428+ , "<https://package.elm-lang.org/packages/elm-lang/core/latest/Basics#modBy>"
429+ ]
361
430
362
431
363−unsafePromote :: Type.Raw -> Type.Canonical
364−unsafePromote (A.A _ rawType) =
365− case rawType of
366− Type.RLambda arg result ->
367− Type.Lambda (unsafePromote arg) (unsafePromote result)
368
432
369− Type.RVar x ->
433+-- ARG MISMATCH
370− Type.Var x
371
434
372− Type.RType (A.A _ (Var.Raw name)) args ->
373− Type.Type (Var.local name) (map unsafePromote args)
374
435
375− Type.RRecord fields ext ->
436+argMismatchReport :: Text -> Var.Canonical -> Int -> Int -> Report.Report
376− Type.Record (map (A.drop *** unsafePromote) fields) (fmap unsafePromote ext)
437+argMismatchReport kind var expected actual =
438+ let
439+ numArgs =
440+ "too "
441+ <> (if actual < expected then "few" else "many")
442+ <> " arguments"
443+ in
444+ Report.report
445+ (Text.map Char.toUpper numArgs)
446+ Nothing
447+ ( kind <> " " <> Var.toText var <> " has " <> numArgs <> "."
448+ )
449+ ( text $
450+ "Expecting " <> i2t expected <> ", but got " <> i2t actual <> "."
451+ )
377
452
378
453
379
454
@@ -429,3 +504,24 @@ badMutualRecursion region name names =
429defToText :: Canonical.Def -> Text
504defToText :: Canonical.Def -> Text
430defToText (Canonical.Def _ pattern _ _) =
505defToText (Canonical.Def _ pattern _ _) =
431 P.toText pattern
506 P.toText pattern
507+
508+
509+
510+-- TYPE COERCION
511+
512+
513+unsafePromote :: Type.Raw -> Type.Canonical
514+unsafePromote (A.A _ rawType) =
515+ case rawType of
516+ Type.RLambda arg result ->
517+ Type.Lambda (unsafePromote arg) (unsafePromote result)
518+
519+ Type.RVar x ->
520+ Type.Var x
521+
522+ Type.RType (A.A _ (Var.Raw name)) args ->
523+ Type.Type (Var.local name) (map unsafePromote args)
524+
525+ Type.RRecord fields ext ->
526+ Type.Record (map (A.drop *** unsafePromote) fields) (fmap unsafePromote ext)
527+
src/Reporting/Error/Syntax.hs+1−1
@@ -635,7 +635,7 @@ escapeProblemToReport escapeProblem =
635 ( "A backslash starts an escaped character, but I do not recognize this one:"
635 ( "A backslash starts an escaped character, but I do not recognize this one:"
636 , Help.stack
636 , Help.stack
637 [ "Maybe there is some typo?"
637 [ "Maybe there is some typo?"
638− , Help.toHint $ "Valid escape characters include:"
638+ , Help.toSimpleHint "Valid escape characters include:"
639 , Help.indent 4 $ Help.vcat $
639 , Help.indent 4 $ Help.vcat $
640 [ "\\n"
640 [ "\\n"
641 , "\\t"
641 , "\\t"
src/Reporting/Error/Type.hs+153−142
@@ -10,11 +10,11 @@ module Reporting.Error.Type
10 )
10 )
11 where
11 where
12
12
13−import Control.Arrow (first, second)
13+import Control.Arrow (second)
14import qualified Data.Map as Map
14import qualified Data.Map as Map
15−import qualified Data.Maybe as Maybe
16import qualified Data.Text as Text
15import qualified Data.Text as Text
17import Data.Text (Text)
16import Data.Text (Text)
17+import Data.Monoid ((<>))
18
18
19import qualified AST.Helpers as Help
19import qualified AST.Helpers as Help
20import qualified AST.Type as Type
20import qualified AST.Type as Type
@@ -24,8 +24,8 @@ import qualified Reporting.Render.Type as RenderType
24import qualified Reporting.Report as Report
24import qualified Reporting.Report as Report
25import qualified Reporting.Helpers as Help
25import qualified Reporting.Helpers as Help
26import Reporting.Helpers
26import Reporting.Helpers
27− ( Doc, (<>), (<+>), capitalize, dullyellow, functionName
27+ ( Doc, (<+>), capitalize, dullyellow, functionName, i2t
28− , i2t, indent, ordinalize, reflowParagraph, stack, text, toHint, vcat
28+ , indent, ordinalize, reflowParagraph, stack, text
29 )
29 )
30
30
31
31
@@ -34,30 +34,32 @@ import Reporting.Helpers
34
34
35
35
36data Error
36data Error
37− = Mismatch Mismatch
37+ = Mismatch Mismatch
38− | BadMain Type.Canonical
38+ | BadMain Type.Canonical
39− | BadFlags Type.Canonical (Maybe Text)
39+ | BadFlags Type.Canonical (Maybe Text)
40− | InfiniteType (Either Hint Text) Type.Canonical
40+ | InfiniteType (Either Hint Text) Type.Canonical
41
41
42
42
43−data Mismatch = MismatchInfo
43+data Mismatch =
44+ MismatchInfo
44 { _hint :: Hint
45 { _hint :: Hint
45 , _leftType :: Type.Canonical
46 , _leftType :: Type.Canonical
46 , _rightType :: Type.Canonical
47 , _rightType :: Type.Canonical
48+ , _decoders :: Bool
47 , _reason :: Maybe Reason
49 , _reason :: Maybe Reason
48 }
50 }
49
51
50
52
51data Reason
53data Reason
52− = BadFields [(Text, Maybe Reason)]
54+ = BadFields [(Text, Maybe Reason)]
53− | MessyFields [Text] [Text] [Text]
55+ | MessyFields [Text] [Text] [Text]
54− | IntFloat
56+ | IntFloat
55− | TooLongComparableTuple Int
57+ | TooLongComparableTuple Int
56− | MissingArgs Int
58+ | MissingArgs Int
57− | RigidClash Text Text
59+ | RigidClash Text Text
58− | NotPartOfSuper Type.Super
60+ | NotPartOfSuper Type.Super
59− | RigidVarTooGeneric Text SpecificThing
61+ | RigidVarTooGeneric Text SpecificThing
60− | RigidSuperTooGeneric Type.Super Text SpecificThing
62+ | RigidSuperTooGeneric Type.Super Text SpecificThing
61
63
62
64
63data SpecificThing
65data SpecificThing
@@ -68,39 +70,39 @@ data SpecificThing
68
70
69
71
70data Hint
72data Hint
71− = CaseBranch Int Region.Region
73+ = CaseBranch Int Region.Region
72− | Case
74+ | Case
73− | IfCondition
75+ | IfCondition
74− | IfBranches
76+ | IfBranches
75− | MultiIfBranch Int Region.Region
77+ | MultiIfBranch Int Region.Region
76− | If
78+ | If
77− | List
79+ | List
78− | ListElement Int Region.Region
80+ | ListElement Int Region.Region
79− | BinopLeft Var.Canonical Region.Region
81+ | BinopLeft Var.Canonical Region.Region
80− | BinopRight Var.Canonical Region.Region
82+ | BinopRight Var.Canonical Region.Region
81− | Binop Var.Canonical
83+ | Binop Var.Canonical
82− | Function (Maybe Var.Canonical)
84+ | Function (Maybe Var.Canonical)
83− | UnexpectedArg (Maybe Var.Canonical) Int Int Region.Region
85+ | UnexpectedArg (Maybe Var.Canonical) Int Int Region.Region
84− | FunctionArity (Maybe Var.Canonical) Int Int Region.Region
86+ | FunctionArity (Maybe Var.Canonical) Int Int Region.Region
85− | ReturnType Text Int Int Region.Region
87+ | ReturnType Text Int Int Region.Region
86− | Instance Text
88+ | Instance Text
87− | Literal Text
89+ | Literal Text
88− | Pattern Pattern
90+ | Pattern Pattern
89− | Shader
91+ | Shader
90− | Lambda
92+ | Lambda
91− | Access (Maybe Text) Text
93+ | Access (Maybe Text) Text
92− | Record
94+ | Record
93− -- effect manager problems
95+ -- effect manager problems
94− | Manager Text
96+ | Manager Text
95− | State Text
97+ | State Text
96− | SelfMsg
98+ | SelfMsg
97
99
98
100
99data Pattern
101data Pattern
100− = PVar Text
102+ = PVar Text
101− | PAlias Text
103+ | PAlias Text
102− | PCtor Var.Canonical
104+ | PCtor Var.Canonical
103− | PRecord
105+ | PRecord
104
106
105
107
106
108
@@ -155,17 +157,18 @@ toReport localizer err =
155
157
156
158
157mismatchToReport :: RenderType.Localizer -> Mismatch -> Report.Report
159mismatchToReport :: RenderType.Localizer -> Mismatch -> Report.Report
158−mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
160+mismatchToReport localizer (MismatchInfo hint leftType rightType decoders maybeReason) =
159 let
161 let
160 report =
162 report =
161 Report.report "TYPE MISMATCH"
163 Report.report "TYPE MISMATCH"
162
164
163 typicalHints =
165 typicalHints =
164− Maybe.maybeToList (reasonToString =<< maybeReason)
166+ maybe id (:) (reasonToDoc <$> maybeReason) $
167+ if decoders then [ jsonDecoderHint ] else []
165
168
166 cmpHint leftWords rightWords extraHints =
169 cmpHint leftWords rightWords extraHints =
167 comparisonHint localizer leftType rightType leftWords rightWords
170 comparisonHint localizer leftType rightType leftWords rightWords
168− (typicalHints <> map toHint extraHints)
171+ (typicalHints <> map Help.toSimpleHint extraHints)
169 in
172 in
170 case hint of
173 case hint of
171 CaseBranch branchNumber region ->
174 CaseBranch branchNumber region ->
@@ -548,6 +551,8 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
548
551
549
552
550
553
554+-- COMPARISON HINT
555+
551
556
552comparisonHint
557comparisonHint
553 :: RenderType.Localizer
558 :: RenderType.Localizer
@@ -573,6 +578,17 @@ comparisonHint localizer leftType rightType leftWords rightWords finalHints =
573
578
574
579
575
580
581+-- JSON DECODER HINT
582+
583+
584+jsonDecoderHint :: Doc
585+jsonDecoderHint =
586+ Help.toSimpleHint $
587+ "New to JSON decoders? They are tough at first, so DEFINITELY learn more here: "
588+ <> Help.hintLink "json-decoders"
589+
590+
591+
576-- BINOP HINTS
592-- BINOP HINTS
577
593
578
594
@@ -709,62 +725,64 @@ flipReason reason =
709 RigidSuperTooGeneric super name specific
725 RigidSuperTooGeneric super name specific
710
726
711
727
712−reasonToString :: Reason -> Maybe Doc
728+reasonToDoc :: Reason -> Doc
713−reasonToString reason =
729+reasonToDoc reason =
714− let
715− (fields, maybeDeepReason) =
716− collectFields reason
730+ case collectFields reason of
717−
731+ Nothing ->
718− maybeDocs =
732+ let
719− reasonToStringHelp =<< maybeDeepReason
733+ (firstLine, details) =
720−
734+ reasonToDocHelp reason
721− starter =
735+ in
722− case fields of
736+ Help.vcat $ Help.toSimpleHint firstLine : map (indent 4) details
723− [] ->
724− Nothing
725
737
726− [field] ->
738+ Just (fields, maybeDeepReason) ->
739+ let
740+ recordHint elaboration =
727− Just $ "Problem in the `" <> field <> "` field. "
741+ [ "Problem", "in", "the", dullyellow (text (Text.intercalate "." fields)) <> "field." ]
742+ ++
743+ map text (Text.words elaboration)
744+ in
745+ case reasonToDocHelp <$> maybeDeepReason of
746+ Nothing ->
747+ Help.toFancyHint (recordHint badFieldElaboration)
728
748
729− _ ->
749+ Just (firstLine, details) ->
730− Just $ "Problem at `" <> Text.intercalate "." fields <> "`. "
750+ Help.vcat $ Help.toFancyHint (recordHint firstLine) : map (indent 4) details
731− in
732− case (starter, maybeDocs) of
733− (Nothing, Nothing) ->
734− Nothing
735
751
736− (Just msg, Nothing) ->
737− Just $ toHint (msg <> badFieldElaboration)
738
752
739− (_, Just (firstLine, docs)) ->
740− Just $ vcat $
741− toHint (maybe firstLine (<> firstLine) starter)
742− : map (indent 4) docs
743
753
754+-- COLLECT FIELDS
744
755
745
756
746−collectFields :: Reason -> ([Text], Maybe Reason)
757+collectFields :: Reason -> Maybe ([Text], Maybe Reason)
747collectFields reason =
758collectFields reason =
748 case reason of
759 case reason of
749− BadFields [(field, Nothing)] ->
760+ BadFields [(field, maybeReason)] ->
761+ Just (collectFieldsHelp [field] maybeReason)
762+
763+ _ ->
750− ([field], Nothing)
764+ Nothing
751
765
766+
767+collectFieldsHelp :: [Text] -> Maybe Reason -> ([Text], Maybe Reason)
768+collectFieldsHelp revFields maybeReason =
769+ case maybeReason of
752− BadFields [(field, Just subReason)] ->
770+ Just (BadFields [(field, deeperReason)]) ->
753− first (field:) (collectFields subReason)
771+ collectFieldsHelp (field : revFields) deeperReason
754
772
755 _ ->
773 _ ->
756− ([], Just reason)
774+ ( reverse revFields, maybeReason )
757
775
758
776
759−reasonToStringHelp :: Reason -> Maybe (Text, [Doc])
777+reasonToDocHelp :: Reason -> (Text, [Doc])
760−reasonToStringHelp reason =
778+reasonToDocHelp reason =
761 let
779 let
762− go msg =
780+ simpleDoc msg =
763− Just (msg, [])
781+ ( msg, [] )
764 in
782 in
765 case reason of
783 case reason of
766 BadFields fields ->
784 BadFields fields ->
767− go $
785+ simpleDoc $
768 "I am seeing issues with the "
786 "I am seeing issues with the "
769 <> Help.commaSep (map fst fields) <> " fields. "
787 <> Help.commaSep (map fst fields) <> " fields. "
770 <> badFieldElaboration
788 <> badFieldElaboration
@@ -773,22 +791,22 @@ reasonToStringHelp reason =
773 messyFieldsHelp both leftOnly rightOnly
791 messyFieldsHelp both leftOnly rightOnly
774
792
775 IntFloat ->
793 IntFloat ->
776− go $
794+ simpleDoc $
777 "Elm does not automatically convert between Ints and Floats. Use\
795 "Elm does not automatically convert between Ints and Floats. Use\
778 \ `toFloat` and `round` to do specific conversions.\
796 \ `toFloat` and `round` to do specific conversions.\
779 \ <http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#toFloat>"
797 \ <http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#toFloat>"
780
798
781 TooLongComparableTuple len ->
799 TooLongComparableTuple len ->
782− go $
800+ simpleDoc $
783 "Although tuples are comparable, this is currently only supported\
801 "Although tuples are comparable, this is currently only supported\
784 \ for tuples with 6 or fewer entries, not " <> i2t len <> "."
802 \ for tuples with 6 or fewer entries, not " <> i2t len <> "."
785
803
786 MissingArgs num ->
804 MissingArgs num ->
787− go $
805+ simpleDoc $
788 "It looks like a function needs " <> Help.moreArgs num <> "."
806 "It looks like a function needs " <> Help.moreArgs num <> "."
789
807
790 RigidClash name1 name2 ->
808 RigidClash name1 name2 ->
791− go $
809+ simpleDoc $
792 "Your type annotation uses `" <> name1 <> "` and `" <> name2 <>
810 "Your type annotation uses `" <> name1 <> "` and `" <> name2 <>
793 "` as DIFFERENT type variables. By using separate names, you are\
811 "` as DIFFERENT type variables. By using separate names, you are\
794 \ claiming the values can be different, but the code suggests that\
812 \ claiming the values can be different, but the code suggests that\
@@ -798,31 +816,31 @@ reasonToStringHelp reason =
798 <> Help.hintLink "type-annotations"
816 <> Help.hintLink "type-annotations"
799
817
800 NotPartOfSuper Type.Number ->
818 NotPartOfSuper Type.Number ->
801− go "Only ints and floats are numbers."
819+ simpleDoc "Only ints and floats are numbers."
802
820
803 NotPartOfSuper Type.Comparable ->
821 NotPartOfSuper Type.Comparable ->
804− go "Only ints, floats, chars, strings, lists, and tuples are comparable."
822+ simpleDoc "Only ints, floats, chars, strings, lists, and tuples are comparable."
805
823
806 NotPartOfSuper Type.Appendable ->
824 NotPartOfSuper Type.Appendable ->
807− go "Only strings and lists are appendable."
825+ simpleDoc "Only strings and lists are appendable."
808
826
809 NotPartOfSuper Type.CompAppend ->
827 NotPartOfSuper Type.CompAppend ->
810− go "Only strings and lists are both comparable and appendable."
828+ simpleDoc "Only strings and lists are both comparable and appendable."
811
829
812 RigidVarTooGeneric name specific ->
830 RigidVarTooGeneric name specific ->
813− go $ rigidTooGenericHelp "ANY type of value" name specific
831+ simpleDoc $ rigidTooGenericHelp "ANY type of value" name specific
814
832
815 RigidSuperTooGeneric Type.Number name specific ->
833 RigidSuperTooGeneric Type.Number name specific ->
816− go $ rigidTooGenericHelp "BOTH Ints and Floats" name specific
834+ simpleDoc $ rigidTooGenericHelp "BOTH Ints and Floats" name specific
817
835
818 RigidSuperTooGeneric Type.Comparable name specific ->
836 RigidSuperTooGeneric Type.Comparable name specific ->
819− go $ rigidTooGenericHelp "ANY comparable value" name specific
837+ simpleDoc $ rigidTooGenericHelp "ANY comparable value" name specific
820
838
821 RigidSuperTooGeneric Type.Appendable name specific ->
839 RigidSuperTooGeneric Type.Appendable name specific ->
822− go $ rigidTooGenericHelp "BOTH Strings and Lists" name specific
840+ simpleDoc $ rigidTooGenericHelp "BOTH Strings and Lists" name specific
823
841
824 RigidSuperTooGeneric Type.CompAppend name specific ->
842 RigidSuperTooGeneric Type.CompAppend name specific ->
825− go $ rigidTooGenericHelp "Strings and ANY comparable List" name specific
843+ simpleDoc $ rigidTooGenericHelp "Strings and ANY comparable List" name specific
826
844
827
845
828rigidTooGenericHelp :: Text -> Text -> SpecificThing -> Text
846rigidTooGenericHelp :: Text -> Text -> SpecificThing -> Text
@@ -869,11 +887,11 @@ specificThingToText specific =
869badFieldElaboration :: Text
887badFieldElaboration :: Text
870badFieldElaboration =
888badFieldElaboration =
871 "I always figure out field types in alphabetical order. If a field\
889 "I always figure out field types in alphabetical order. If a field\
872− \ seems fine, I assume it is \"correct\" in subsequent checks.\
890+ \ seems fine, I assume it is “correct” in subsequent checks.\
873 \ So the problem may actually be a weird interaction with previous fields."
891 \ So the problem may actually be a weird interaction with previous fields."
874
892
875
893
876−messyFieldsHelp :: [Text] -> [Text] -> [Text] -> Maybe (Text, [Doc])
894+messyFieldsHelp :: [Text] -> [Text] -> [Text] -> (Text, [Doc])
877messyFieldsHelp both leftOnly rightOnly =
895messyFieldsHelp both leftOnly rightOnly =
878 case (leftOnly, rightOnly) of
896 case (leftOnly, rightOnly) of
879 ([], [missingField]) ->
897 ([], [missingField]) ->
@@ -899,62 +917,55 @@ messyFieldsHelp both leftOnly rightOnly =
899 pairs
917 pairs
900 in
918 in
901 if null typoPairs then
919 if null typoPairs then
902− Just
903− ( "The record fields do not match up. One has "
920+ ( "The record fields do not match up. One has "
904− <> Help.commaSep leftOnly <> ". The other has "
921+ <> Help.commaSep leftOnly <> ". The other has "
905− <> Help.commaSep rightOnly <> "."
922+ <> Help.commaSep rightOnly <> "."
906− , []
923+ , []
907− )
924+ )
908
925
909 else
926 else
910− Just
911− ( "The record fields do not match up. Maybe you made one of these typos?"
927+ ( "The record fields do not match up. Maybe you made one of these typos?"
912− , typoDocs "<->" typoPairs
928+ , typoDocs "<->" typoPairs
913− )
929+ )
914
930
915
931
916−oneMissingField :: [Text] -> Text -> Maybe (Text, [Doc])
932+oneMissingField :: [Text] -> Text -> ( Text, [Doc] )
917oneMissingField knownFields missingField =
933oneMissingField knownFields missingField =
918 case Help.findPotentialTypos knownFields missingField of
934 case Help.findPotentialTypos knownFields missingField of
919 [] ->
935 [] ->
920− Just
921− ( "Looks like a record is missing the `" <> missingField <> "` field."
936+ ( "Looks like a record is missing the `" <> missingField <> "` field."
922− , []
937+ , []
923− )
938+ )
924
939
925 [typo] ->
940 [typo] ->
926− Just
927− ( "Looks like a record is missing the `" <> missingField
941+ ( "Looks like a record is missing the `" <> missingField
928− <> "` field. Maybe it is a typo?"
942+ <> "` field. Maybe it is a typo?"
929− , typoDocs "->" [(missingField, typo)]
943+ , typoDocs "->" [(missingField, typo)]
930− )
944+ )
931
945
932 typos ->
946 typos ->
933− Just
934− ( "Looks like a record is missing the `" <> missingField
947+ ( "Looks like a record is missing the `" <> missingField
935− <> "` field. It is close to names like "
948+ <> "` field. It is close to names like "
936− <> Help.commaSep typos <> " so maybe it is a typo?"
949+ <> Help.commaSep typos <> " so maybe it is a typo?"
937− , []
950+ , []
938− )
951+ )
939
952
940
953
941−manyMissingFields :: [Text] -> [Text] -> Maybe (Text, [Doc])
954+manyMissingFields :: [Text] -> [Text] -> (Text, [Doc])
942manyMissingFields knownFields missingFields =
955manyMissingFields knownFields missingFields =
943 case Help.findTypoPairs missingFields knownFields of
956 case Help.findTypoPairs missingFields knownFields of
944 [] ->
957 [] ->
945− Just
946− ( "Looks like a record is missing these fields: "
958+ ( "Looks like a record is missing these fields: "
947− <> Help.commaSep missingFields
959+ <> Help.commaSep missingFields
948− , []
960+ , []
949− )
961+ )
950
962
951 typoPairs ->
963 typoPairs ->
952− Just
953− ( "Looks like a record is missing these fields: "
964+ ( "Looks like a record is missing these fields: "
954− <> Help.commaSep missingFields
965+ <> Help.commaSep missingFields
955− <> ". Potential typos include:"
966+ <> ". Potential typos include:"
956− , typoDocs "->" typoPairs
967+ , typoDocs "->" typoPairs
957− )
968+ )
958
969
959
970
960typoDocs :: Text -> [(Text, Text)] -> [Doc]
971typoDocs :: Text -> [(Text, Text)] -> [Doc]
src/Reporting/Helpers.hs+10−8
@@ -8,7 +8,8 @@ module Reporting.Helpers
8 -- custom helpers
8 -- custom helpers
9 , i2t
9 , i2t
10 , functionName, args, moreArgs
10 , functionName, args, moreArgs
11+ , toSimpleHint, toFancyHint, hintLink
11− , toHint, hintLink, stack, reflowParagraph
12+ , stack, reflowParagraph
12 , commaSep, capitalize, ordinalize, drawCycle
13 , commaSep, capitalize, ordinalize, drawCycle
13 , findPotentialTypos, findTypoPairs, vetTypos
14 , findPotentialTypos, findTypoPairs, vetTypos
14 , nearbyNames, distance, maybeYouWant, maybeYouWant'
15 , nearbyNames, distance, maybeYouWant, maybeYouWant'
@@ -81,13 +82,14 @@ moreArgs n =
81-- HINTS
82-- HINTS
82
83
83
84
84−toHint :: Text -> Doc
85+toSimpleHint :: Text -> Doc
85−toHint txt =
86+toSimpleHint txt =
86− let
87+ toFancyHint (map text (Text.words txt))
87− hint =
88+
89+
90+toFancyHint :: [Doc] -> Doc
91+toFancyHint chunks =
88− underline (text "Hint") <> ":"
92+ fillSep (underline (text "Hint") <> ":" : chunks)
89− in
90− fillSep (hint : map text (Text.words txt))
91
93
92
94
93hintLink :: Text -> Text
95hintLink :: Text -> Text
src/Reporting/Report.hs+8−1
@@ -3,6 +3,7 @@
3module Reporting.Report
3module Reporting.Report
4 ( Report
4 ( Report
5 , report
5 , report
6+ , reportDoc
6 , toDoc
7 , toDoc
7 , toJson
8 , toJson
8 )
9 )
@@ -23,7 +24,8 @@ import qualified Reporting.Render.Code as Code
23-- BUILD REPORTS
24-- BUILD REPORTS
24
25
25
26
26−data Report = Report
27+data Report =
28+ Report
27 { _title :: Text
29 { _title :: Text
28 , _highlight :: Maybe R.Region
30 , _highlight :: Maybe R.Region
29 , _preHint :: Doc
31 , _preHint :: Doc
@@ -36,6 +38,11 @@ report title highlight pre post =
36 Report title highlight (Help.reflowParagraph pre) post
38 Report title highlight (Help.reflowParagraph pre) post
37
39
38
40
41+reportDoc :: Text -> Maybe R.Region -> [Doc] -> Doc -> Report
42+reportDoc title highlight pre post =
43+ Report title highlight (Help.hsep pre) post
44+
45+
39
46
40-- REPORT TO JSON
47-- REPORT TO JSON
41
48
src/Type/Unify.hs+48−54
@@ -19,7 +19,7 @@ import qualified Type.UnionFind as UF
19
19
20
20
21
21
22−-- KICK OFF UNIFICATION
22+-- UNIFY
23
23
24
24
25unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
25unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
@@ -36,13 +36,9 @@ unify hint region expected actual =
36 liftIO $ mergeHelp expected actual (Error "?") noRank
36 liftIO $ mergeHelp expected actual (Error "?") noRank
37 TS.addError region $
37 TS.addError region $
38 case problem of
38 case problem of
39− Typical ->
39+ Reason hasDecoder maybeReason ->
40 Error.Mismatch $
40 Error.Mismatch $
41− Error.MismatchInfo hint expectedSrcType actualSrcType Nothing
41+ Error.MismatchInfo hint expectedSrcType actualSrcType hasDecoder maybeReason
42−
43− Special reason ->
44− Error.Mismatch $
45− Error.MismatchInfo hint expectedSrcType actualSrcType (Just reason)
46
42
47 Infinite ->
43 Infinite ->
48 Error.InfiniteType (Left hint) expectedSrcType
44 Error.InfiniteType (Left hint) expectedSrcType
@@ -66,7 +62,9 @@ data Context =
66 }
62 }
67
63
68
64
69−data Orientation = ExpectedActual | ActualExpected
65+data Orientation
66+ = ExpectedActual
67+ | ActualExpected
70
68
71
69
72reorient :: Context -> Context
70reorient :: Context -> Context
@@ -85,8 +83,7 @@ reorient (Context orientation var1 desc1 var2 desc2) =
85
83
86
84
87data Problem
85data Problem
88− = Typical
89− | Special Error.Reason
86+ = Reason Bool (Maybe Error.Reason)
90 | Infinite
87 | Infinite
91
88
92
89
@@ -95,34 +92,49 @@ mismatch context@(Context orientation var1 _ var2 _) maybeReason =
95 do anyInfinite <- liftIO $ liftM2 (||) (Occurs.occurs var1) (Occurs.occurs var2)
92 do anyInfinite <- liftIO $ liftM2 (||) (Occurs.occurs var1) (Occurs.occurs var2)
96 when anyInfinite $ throwError Infinite
93 when anyInfinite $ throwError Infinite
97
94
98− args1 <- liftIO $ collectArgs var1
95+ args1 <- liftIO $ collectArgs [] var1
99− args2 <- liftIO $ collectArgs var2
96+ args2 <- liftIO $ collectArgs [] var2
100
97
101− let numArgs1 = length args1
98+ hasDecoder <- liftIO $ or <$> traverse detectDecoder (args1 ++ args2)
102− let numArgs2 = length args2
103
99
104− if numArgs1 == numArgs2
100+ if length args1 /= length args2
105 then
101 then
106− throwError $ reasonToProblem orientation maybeReason
107− else
108 do lift $ zipWithM_ (\a1 a2 -> runExceptT $ subUnify context a1 a2) args1 args2
102 do lift $ zipWithM_ (\a1 a2 -> runExceptT $ subUnify context a1 a2) args1 args2
109− throwError $ reasonToProblem orientation $ Just $
103+ throwError $ Reason hasDecoder $ Just $
110− Error.MissingArgs $ abs (numArgs2 - numArgs1)
104+ Error.MissingArgs (abs (length args2 - length args1))
105+ else
106+ throwError $ Reason hasDecoder $
107+ case orientation of
108+ ExpectedActual ->
109+ maybeReason
111
110
111+ ActualExpected ->
112+ fmap Error.flipReason maybeReason
112
113
113−reasonToProblem :: Orientation -> Maybe Error.Reason -> Problem
114−reasonToProblem orientation maybeReason =
115− case maybeReason of
116− Nothing ->
117− Typical
118
114
119− Just reason ->
120− case orientation of
121− ExpectedActual ->
122− Special reason
123
115
124− ActualExpected ->
116+
125− Special (Error.flipReason reason)
117+
118+collectArgs :: [Variable] -> Variable -> IO [Variable]
119+collectArgs revArgs variable =
120+ do (Descriptor content _ _ _) <- UF.descriptor variable
121+ case content of
122+ Structure (Fun1 arg returnType) ->
123+ collectArgs (arg : revArgs) returnType
124+
125+ _ ->
126+ return $ variable : revArgs
127+
128+
129+detectDecoder :: Variable -> IO Bool
130+detectDecoder variable =
131+ do (Descriptor content _ _ _) <- UF.descriptor variable
132+ case content of
133+ Structure (App1 name [_]) | Var.decoder == name ->
134+ return True
135+
136+ _ ->
137+ return False
126
138
127
139
128
140
@@ -445,22 +457,6 @@ unifyComparableRecursive orientation var =
445 guardedUnify orientation compVar var
457 guardedUnify orientation compVar var
446
458
447
459
448−collectArgs :: Variable -> IO [Variable]
449−collectArgs variable =
450− collectArgsHelp [] variable
451−
452−
453−collectArgsHelp :: [Variable] -> Variable -> IO [Variable]
454−collectArgsHelp revArgs variable =
455− do (Descriptor content _ _ _) <- UF.descriptor variable
456− case content of
457− Structure (Fun1 arg returnType) ->
458− collectArgsHelp (arg : revArgs) returnType
459−
460− _ ->
461− return $ variable : revArgs
462−
463−
464
460
465-- UNIFY ALIASES
461-- UNIFY ALIASES
466
462
@@ -638,11 +634,8 @@ unifyField context (field, (expected, actual)) =
638 Left problem ->
634 Left problem ->
639 return $ Just $ (,) field $
635 return $ Just $ (,) field $
640 case problem of
636 case problem of
641− Typical ->
642− Nothing
643−
644− Special reason ->
637+ Reason _ reason ->
645− Just reason
638+ reason
646
639
647 Infinite ->
640 Infinite ->
648 Nothing
641 Nothing
@@ -652,7 +645,8 @@ unifyField context (field, (expected, actual)) =
652-- GATHER RECORD STRUCTURE
645-- GATHER RECORD STRUCTURE
653
646
654
647
655−data RecordStructure = RecordStructure
648+data RecordStructure =
649+ RecordStructure
656 { _fields :: Map.Map Text Variable
650 { _fields :: Map.Map Text Variable
657 , _extVar :: Variable
651 , _extVar :: Variable
658 , _extStruct :: ExtensionStructure
652 , _extStruct :: ExtensionStructure
@@ -660,8 +654,8 @@ data RecordStructure = RecordStructure
660
654
661
655
662data ExtensionStructure
656data ExtensionStructure
663− = Empty
657+ = Empty
664− | Extension
658+ | Extension
665
659
666
660
667gatherFields :: Context -> Map.Map Text Variable -> Variable -> IO RecordStructure
661gatherFields :: Context -> Map.Map Text Variable -> Variable -> IO RecordStructure