1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Canonicalize
7 , DuplicatePatternContext(..)
16import qualified Data.Char as Char
17import Data.Text (Text)
19import qualified AST.Canonical as Can
20import qualified AST.Source as Src
21import qualified Data.Index as Index
22import qualified Elm.Name as N
23import qualified Reporting.Annotation as A
24import qualified Reporting.Region as R
25import qualified Reporting.Render.Code as Code
26import qualified Reporting.Render.Type as RenderType
27import qualified Reporting.Report as Report
28import qualified Reporting.Helpers as H
29import Reporting.Helpers ( Doc, (<>) )
33-- CANONICALIZATION ERRORS
38 | AnnotationTooShort R.Region N.Name Index.ZeroBased Int
39 | BadArity R.Region BadArityContext N.Name Int Int
40 | Binop R.Region N.Name N.Name
41 | DuplicateDecl N.Name R.Region R.Region
42 | DuplicateType N.Name R.Region R.Region
43 | DuplicateCtor N.Name R.Region R.Region
44 | DuplicateBinop N.Name R.Region R.Region
45 | DuplicateField N.Name R.Region R.Region
46 | DuplicateAliasArg N.Name N.Name R.Region R.Region
47 | DuplicateUnionArg N.Name N.Name R.Region R.Region
48 | DuplicatePattern DuplicatePatternContext N.Name R.Region R.Region
49 | EffectNotFound R.Region N.Name
50 | EffectFunctionNotFound R.Region N.Name
51 | ExportDuplicate N.Name R.Region R.Region
52 | ExportNotFound R.Region VarKind N.Name [N.Name]
53 | ExportOpenAlias R.Region N.Name
54 | ImportCtorByName R.Region N.Name N.Name
55 | ImportNotFound R.Region N.Name [N.Name]
56 | ImportOpenAlias R.Region N.Name
57 | ImportExposingNotFound R.Region N.Name N.Name [N.Name]
58 | PatternHasRecordCtor R.Region N.Name
59 | PortPayloadInvalid R.Region N.Name Can.Type InvalidPayload
60 | PortTypeInvalid R.Region N.Name Can.Type
61 | RecursiveAlias R.Region N.Name [N.Name] Src.Type [N.Name]
62 | RecursiveDecl [Can.Def]
63 | RecursiveLet (A.Located N.Name) [N.Name]
64 | Shadowing N.Name R.Region R.Region
65 | TupleLargerThanThree R.Region
66 | TypeVarsUnboundInUnion R.Region N.Name [N.Name] [A.Located N.Name]
67 | TypeVarsMessedUpInAlias R.Region N.Name [N.Name] [A.Located N.Name] [A.Located N.Name]
75data DuplicatePatternContext
87 | UnsupportedType N.Name
98 , _problem :: VarProblem
99 , _suggestions :: [Text]
105 | UnknownQualifier Text Text
106 | QualifiedUnknown Text Text
110variable :: VarKind -> Text -> VarProblem -> [Text] -> Error
111variable kind name problem suggestions =
112 Var (VarError kind name problem suggestions)
126toKindInfo :: VarKind -> N.Name -> ( Doc, Doc, Doc )
127toKindInfo kind name =
130 ( "an", "operator", "(" <> H.nameToDoc name <> ")" )
133 ( "a", "value", "`" <> H.nameToDoc name <> "`" )
136 ( "a", "pattern", "`" <> H.nameToDoc name <> "`" )
139 ( "a", "type", "`" <> H.nameToDoc name <> "`" )
146toReport :: Code.Source -> RenderType.Localizer -> Error -> Report.Report
147toReport source localizer err =
150 error "TODO" varError
152 AnnotationTooShort region name index leftovers ->
154 numTypeArgs = Index.toHuman index
155 numDefArgs = numTypeArgs + leftovers
157 Report.Report "BAD TYPE ANNOTATION" region [] $
158 Report.toCodeSnippet source region Nothing
161 "The type annotation for `" <> N.toString name <> "` says it can accept "
162 <> H.args numTypeArgs <> ", but the definition says it has "
163 <> H.args numDefArgs <> ":"
166 "Is the type annotation missing something? Should some argument"
167 <> (if leftovers == 1 then "" else "s")
168 <> " be deleted? Maybe some parentheses are missing?"
171 BadArity region badArityContext name expected actual ->
174 case badArityContext of
176 PatternArity -> "constructor"
178 if actual < expected then
179 Report.Report "TOO FEW ARGS" region [] $
180 Report.toCodeSnippet source region Nothing
183 "The `" <> N.toString name <> "` " <> thing <> " needs "
184 <> H.args expected <> ", but I only see " <> show actual <> ":"
186 "What is missing? Is there some typo?"
190 Report.Report "TOO MANY ARGS" region [] $
191 Report.toCodeSnippet source region Nothing
194 "The `" <> N.toString name <> "` " <> thing <> " needs "
195 <> H.args expected <> ", but I see " <> show actual <> " instead:"
197 if actual - expected == 1 then
198 "Which is the extra one? Maybe some parentheses are missing?"
200 "Which are the extra ones? Maybe some parentheses are missing?"
203 Binop region op1 op2 ->
204 Report.Report "INFIX PROBLEM" region [] $
205 Report.toCodeSnippet source region Nothing
208 "You cannot mix (" <> N.toString op1 <> ") and (" <> N.toString op2 <> ") without parentheses."
211 "I do not know how to group these expressions. Add parentheses for me!"
214 DuplicateDecl name r1 r2 ->
215 nameClash source r1 r2 $
216 "This file has multiple `" <> N.toString name <> "` declarations."
218 DuplicateType name r1 r2 ->
219 nameClash source r1 r2 $
220 "This file defines multiple `" <> N.toString name <> "` types."
222 DuplicateCtor name r1 r2 ->
223 nameClash source r1 r2 $
224 "This file defines multiple `" <> N.toString name <> "` type constructors."
226 DuplicateBinop name r1 r2 ->
227 nameClash source r1 r2 $
228 "This file defines multiple (" <> N.toString name <> ") operators."
230 DuplicateField name r1 r2 ->
231 nameClash source r1 r2 $
232 "This record has multiple `" <> N.toString name <> "` fields."
234 DuplicateAliasArg typeName name r1 r2 ->
235 nameClash source r1 r2 $
236 "The `" <> N.toString typeName <> "` type alias has multilpe `" <> N.toString name <> "` type variables."
238 DuplicateUnionArg typeName name r1 r2 ->
239 nameClash source r1 r2 $
240 "The `" <> N.toString typeName <> "` type has multilpe `" <> N.toString name <> "` type variables."
242 DuplicatePattern context name r1 r2 ->
243 nameClash source r1 r2 $
246 "This anonymous function has multiple `" <> N.toString name <> "` arguments."
248 DPFuncArgs funcName ->
249 "The `" <> N.toString funcName <> "` function has multiple `" <> N.toString name <> "` arguments."
252 "This `case` pattern has multiple `" <> N.toString name <> "` variables."
255 "This `let` expression defines `" <> N.toString name <> "` more than once!"
258 "This pattern contains multiple `" <> N.toString name <> "` variables."
260 EffectNotFound _ _ ->
261 error "TODO EffectNotFound"
263 EffectFunctionNotFound _ _ ->
264 error "TODO EffectFunctionNotFound"
266 ExportDuplicate name r1 r2 ->
268 messageThatEndsWithPunctuation =
269 "You are trying to expose `" <> N.toString name <> "` multiple times!"
271 Report.Report "REDUNDANT EXPORT" r2 [] $
272 Report.toCodePair source r1 r2
274 H.reflow messageThatEndsWithPunctuation
276 "Remove one of them and you should be all set!"
279 H.reflow (messageThatEndsWithPunctuation <> " Once here:")
281 "And again right here:"
283 "Remove one of them and you should be all set!"
286 ExportNotFound region kind rawName suggestions ->
287 Report.Report "UNKNOWN EXPORT" region suggestions $
288 let (a, thing, name) = toKindInfo kind rawName in
291 ["You","are","trying","to","expose",a,thing,"named"
292 ,name,"but","I","cannot","find","its","definition."
294 , H.maybeYouWant Nothing suggestions
297 ExportOpenAlias region name ->
298 error "TODO" region name
300 ImportCtorByName region ctor tipe ->
301 Report.Report "BAD IMPORT" region [] $
302 Report.toCodeSnippet source region Nothing
305 "You are trying to import the `" <> N.toString ctor
306 <> "` type constructor by name:"
309 ["Try","importing",H.green (H.nameToDoc tipe <> "(..)"),"instead."
310 ,"The","dots","mean","“expose","the",H.nameToDoc tipe,"type","and"
311 ,"all","its","constructors”","so","it","gives","you","access","to"
312 , H.nameToDoc ctor <> "."
316 ImportNotFound region name suggestions ->
317 Report.Report "UNKNOWN IMPORT" region suggestions $
318 Report.toCodeSnippet source region Nothing
321 "I could not find a `" <> N.toString name <> "` module to import!"
323 H.maybeYouWant Nothing suggestions
326 ImportOpenAlias region name ->
327 Report.Report "BAD IMPORT" region [] $
328 Report.toCodeSnippet source region Nothing
331 "The `" <> N.toString name <> "` type alias cannot be followed by (..) like this:"
334 [ "Remove the (..) and it should work."
336 "The distinction between `type` and `type alias` is important here. Read"
337 "types-vs-type-aliases"
342 ImportExposingNotFound region name value suggestions ->
343 Report.Report "BAD IMPORT" region suggestions $
344 Report.toCodeSnippet source region Nothing
347 "The `" <> N.toString name
348 <> "` module does not expose `"
349 <> N.toString value <> "`:"
351 H.maybeYouWant Nothing suggestions
354 PatternHasRecordCtor region name ->
355 Report.Report "BAD PATTERN" region [] $
356 Report.toCodeSnippet source region Nothing
359 "You can construct records by using `" <> N.toString name
360 <> "` as a function, but it is not available in pattern matching like this:"
363 "I recommend matching matching the record as a variable and unpacking it later."
366 PortPayloadInvalid region portName badType invalidPayload ->
368 (aBadKindOfThing, elaboration) =
369 case invalidPayload of
375 "The exact shape of the record must be known at compile time. No type variables!"
383 "Functions cannot be sent in and out ports. If we allowed functions in from JS\
384 \ they may perform some side-effects. If we let functions out, they could produce\
385 \ incorrect results because Elm optimizations assume there are no side-effects."
391 "an unspecified type"
394 "Type variables like `" <> N.toString name <> "` cannot flow through ports because\
395 \ the marshalling code needs to know the exact data that it is going to process."
398 UnsupportedType name ->
400 "a `" <> N.toString name <> "` value"
403 [ H.reflow $ "The types that can flow in and out of Elm include:"
406 "Ints, Floats, Bools, Strings, Maybes, Lists, Arrays,\
407 \ tuples, records, and JSON values."
409 "Since JSON values can flow through, you can use JSON encoders and decoders\
410 \ to allow other types through as well. More advanced users often just do\
411 \ everything with encoders and decoders for more control and better errors."
415 Report.Report "PORT ERROR" region [] $
416 Report.toCodeSnippet source region Nothing
419 "The `" <> N.toString portName <> "` port is trying to transmit " <> aBadKindOfThing <> ":"
422 [ error "TODO" badType
425 "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
427 "to learn how to use ports effectively."
431 PortTypeInvalid region name badType ->
432 Report.Report "BAD PORT" region [] $
433 Report.toCodeSnippet source region Nothing
436 "Port `" <> N.toString name <> "` has an invalid type."
438 error "TODO PortTypeInvalid" badType
441 RecursiveAlias region name args tipe others ->
442 aliasRecursionReport source localizer region name args tipe others
444 RecursiveDecl cyclicValueDefs ->
445 error "TODO" cyclicValueDefs
447 RecursiveLet (A.At region name) names ->
448 Report.Report "CYCLIC VALUE" region [] $
449 Report.toCodeSnippet source region Nothing $
454 "The `" <> N.toString name <> "` value has a direct use of `" <> N.toString name <> "` in its definition."
458 "To know what `" <> N.toString name
459 <> "` is, I need to know what `" <> N.toString name
460 <> "` is. Let me recursively figure that out. Hmm, I need to know what `"
461 <> N.toString name <> "` is..."
463 "The root problem is often a typo in some variable name, but I recommend reading"
465 "for more detailed advice, especially if you actually do need a recursive value."
472 "I do not allow cyclic values in `let` expressions."
476 "The `" <> N.toString name
477 <> "` value depends on itself through the following chain of definitions:"
478 , H.indent 4 $ H.drawCycle (name:names)
480 "The root problem is often a typo in some variable name, but I recommend reading"
482 "for more detailed advice, especially if you actually do want mutually recursive values."
486 Shadowing name r1 r2 ->
487 Report.Report "SHADOWING" r2 [] $
488 Report.toCodePair source r1 r2
489 ( "These variables cannot have the same name:"
492 ( H.reflow $ "The name `" <> N.toString name <> "` is first defined here:"
493 , "But then it is defined AGAIN over here:"
500 "Think of a more helpful name for one of them and you should be all set!"
502 "Linters advise against shadowing, so Elm makes “best practices” the default. Read"
504 "for more details on this choice."
507 TupleLargerThanThree region ->
508 Report.Report "BAD TUPLE" region [] $
509 Report.toCodeSnippet source region Nothing
511 "I only accept tuples with two or three items. This has too many:"
515 "I recommend switching to records. Each item will be named, and you can use\
516 \ the `point.x` syntax to access them."
518 , H.link "Note" "Read" "tuples"
519 "for more comprehensive advice on working with large chunks of data in Elm."
523 TypeVarsUnboundInUnion _ _ _ _ ->
524 error "TODO TypeVarsUnboundInUnion"
526 TypeVarsMessedUpInAlias _ _ _ _ _ ->
527 error "TODO TypeVarsMessedUpInAlias"
532-- UnboundTypeVarsInUnion typeName givenVars unbound ->
533-- unboundTypeVars "type" typeName givenVars unbound
535-- UnboundTypeVarsInAlias typeName givenVars unbound ->
536-- unboundTypeVars "type alias" typeName givenVars unbound
538-- UnusedTypeVarsInAlias typeName givenVars unused ->
540-- "UNUSED TYPE VARIABLES"
542-- ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
543-- <> H.commaSep unused
546-- [ text "You probably need to change the declaration like this:"
547-- , H.dullyellow $ hsep $
548-- map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
552-- MessyTypeVarsInAlias typeName givenVars unused unbound ->
554-- "TYPE VARIABLE PROBLEMS"
556-- ( "Type alias `" <> typeName <> "` has some problems with type variables."
560-- "The declaration says it uses certain type variables ("
561-- <> H.commaSep unused <> ") but they do not appear in the aliased type. "
562-- <> "Furthermore, the aliased type says it uses type variables ("
563-- <> H.commaSep unbound
564-- <> ") that do not appear in the declaration."
565-- , text "You probably need to change the declaration like this:"
566-- , H.dullyellow $ hsep $
567-- map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
572--unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
573--unboundTypeVars declKind typeName givenVars unboundVars =
575-- "UNBOUND TYPE VARIABLES"
577-- ( H.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
578-- <> H.commaSep unboundVars
581-- [ text "You probably need to change the declaration like this:"
583-- map text (declKind : typeName : givenVars)
584-- ++ map (H.dullyellow . text) unboundVars
585-- ++ map text ["=", "..."]
587-- "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
588-- "` is an Int and another where it is a Bool. When we explicitly list the type\
589-- \ variables, the type checker can see that they are actually different types."
598nameClash :: Code.Source -> R.Region -> R.Region -> String -> Report.Report
599nameClash source r1 r2 messageThatEndsWithPunctuation =
600 Report.Report "NAME CLASH" r2 [] $
601 Report.toCodePair source r1 r2
603 H.reflow messageThatEndsWithPunctuation
605 "How can I know which one you want? Rename one of them!"
608 H.reflow (messageThatEndsWithPunctuation <> " One here:")
610 "And another one here:"
612 "How can I know which one you want? Rename one of them!"
620varErrorToReport :: VarError -> Report.Report
621varErrorToReport (VarError kind name problem suggestions) =
625 orMaybe <> " `import` works different than you expect? Learn all about it here: "
626 <> H.hintLink "imports"
628 namingError overview maybeStarter specializedSuggestions =
629 Report.reportDoc "NAMING ERROR" Nothing overview $
630 case H.maybeYouWant' maybeStarter specializedSuggestions of
634 H.stack [ doc, learnMore "Or maybe" ]
636 specialNamingError specialHint =
637 Report.reportDoc "NAMING ERROR" Nothing (cannotFind kind name) (H.hsep specialHint)
641 namingError (ambiguous kind name) Nothing suggestions
643 UnknownQualifier qualifier localName ->
645 (cannotFind kind name)
646 (Just $ text $ "No module called `" <> qualifier <> "` has been imported.")
647 (map (\modul -> modul <> "." <> localName) suggestions)
649 QualifiedUnknown qualifier localName ->
651 (cannotFind kind name)
652 (Just $ text $ "`" <> qualifier <> "` does not expose `" <> localName <> "`.")
653 (map (\v -> qualifier <> "." <> v) suggestions)
657 "!=" -> specialNamingError (notEqualsHint name)
658 "!==" -> specialNamingError (notEqualsHint name)
659 "===" -> specialNamingError equalsHint
660 "%" -> specialNamingError modHint
661 _ -> namingError (cannotFind kind name) Nothing suggestions
664cannotFind :: VarKind -> Text -> [Doc]
665cannotFind kind rawName =
666 let ( a, thing, name ) = toKindInfo kind rawName in
667 [ "Cannot", "find", a, thing, "named", H.dullyellow name <> ":" ]
670ambiguous :: VarKind -> Text -> [Doc]
671ambiguous kind rawName =
672 let ( _a, thing, name ) = toKindInfo kind rawName in
673 [ "This", "usage", "of", "the", H.dullyellow name, thing, "is", "ambiguous." ]
676notEqualsHint :: Text -> [Doc]
678 [ "Looking", "for", "the", "“not", "equal”", "operator?", "The", "traditional"
679 , H.dullyellow $ text $ "(" <> op <> ")"
680 , "is", "replaced", "by", H.green "(/=)", "in", "Elm.", "It", "is", "meant"
681 , "to", "look", "like", "the", "“not", "equal”", "sign", "from", "math!", "(≠)"
687 [ "A", "special", H.dullyellow "(===)", "operator", "is", "not", "needed"
688 , "in", "Elm.", "We", "use", H.green "(==)", "for", "everything!"
694 [ "Rather", "than", "a", H.dullyellow "(%)", "operator,"
695 , "Elm", "has", "a", H.green "modBy", "function."
696 , "Learn", "more", "here:"
697 , "<https://package.elm-lang.org/packages/elm-lang/core/latest/Basics#modBy>"
707_argMismatchReport :: Code.Source -> R.Region -> String -> N.Name -> Int -> Int -> Report.Report
708_argMismatchReport source region kind name expected actual =
712 <> (if actual < expected then "few" else "many")
715 Report.Report (map Char.toUpper numArgs) region [] $
716 Report.toCodeSnippet source region Nothing
719 kind <> " " <> N.toString name <> " has " <> numArgs <> "."
722 "Expecting " <> show expected <> ", but got " <> show actual <> "."
727-- BAD ALIAS RECURSION
730aliasRecursionReport :: Code.Source -> RenderType.Localizer -> R.Region -> N.Name -> [N.Name] -> Src.Type -> [N.Name] -> Report.Report
731aliasRecursionReport source localizer region name args tipe others =
734 Report.Report "ALIAS PROBLEM" region [] $
735 Report.toCodeSnippet source region Nothing
737 "This type alias is recursive, forming an infinite type!"
741 "When I expand a recursive type alias, it just keeps getting bigger and bigger.\
742 \ So dealiasing results in an infinitely large type! Try this instead:"
744 RenderType.decl localizer name args [(name, [error "TODO" tipe])]
746 "This is kind of a subtle distinction. I suggested the naive fix, but I recommend reading"
748 "for ideas on how to do better."
753 Report.Report "ALIAS PROBLEM" region [] $
754 Report.toCodeSnippet source region Nothing
756 "This type alias is part of a mutually recursive set of type aliases."
759 [ "It is part of this cycle of type aliases:"
760 , H.indent 4 (H.drawCycle (name:others))
762 "You need to convert at least one of these type aliases into a `type`."
763 , H.link "Note" "Read" "recursive-alias"
764 "to learn why this `type` vs `type alias` distinction matters. It is subtle but important!"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list