1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
6 , Problem(..), Theory(..)
8 , ContextStack, Context(..)
14import qualified Data.Set as Set
15import qualified Data.Text as Text
16import Data.Text (Text)
18import qualified Reporting.Render.Type as RenderType
19import qualified Reporting.Region as R
20import qualified Reporting.Report as Report
21import qualified Reporting.Helpers as Help
22import Reporting.Helpers ((<>), dullyellow, green, hsep, i2t, reflowParagraph, text)
30 = Parse (Maybe R.Region) Problem
36 | SettingsOnNormalModule
37 | SettingsOnPortModule
38 | DuplicateSettingOnEffectModule Text
39 | BadSettingOnEffectModule Text
40 | NoSettingsOnEffectModule
41 | MissingManagerOnEffectModule Text
44 | TypeWithoutDefinition Text
46 | DuplicateArgument Text Text
47 | DuplicateFieldName R.Region Text
48 | DuplicateValueDeclaration Text
49 | DuplicateTypeDeclaration Text
50 | DuplicateDefinition Text
51 | UnboundTypeVarsInUnion Text [Text] [Text]
52 | UnboundTypeVarsInAlias Text [Text] [Text]
53 | UnusedTypeVarsInAlias Text [Text] [Text]
54 | MessyTypeVarsInAlias Text [Text] [Text] [Text]
61data ParseError = ParseError !Int !Int !Problem
69 | EndOfFile_MultiString
73 | BadEscape Int EscapeProblem
82 | BadOp BadOp ContextStack
83 | Theories ContextStack [Theory]
90 | UnicodeLength Int Text
93data BadOp = HasType | Equals | Arrow | Pipe | Dot
121type ContextStack = [(Context, R.Position)]
149 deriving (Eq, Ord, Show)
156toReport :: RenderType.Localizer -> Error -> Report.Report
157toReport _localizer err =
159 Parse subRegion problem ->
160 problemToReport subRegion problem
162 BadFunctionName arity ->
164 "BAD FUNCTION DEFINITION"
166 "Complex patterns cannot be used as function names."
168 "This function definition has " <> i2t arity <> " arguments, but instead\
169 \ of a normal name like `add` or `reverse` it has a pattern. There is no\
170 \ way to \"deconstruct\" a function with pattern matching, so this needs to\
171 \ be changed to a normal name."
178 ("The free variable `" <> name <> "` appears more than once in this pattern.")
180 [ text "Rename the variables so there are no duplicates."
182 "In Elm, pattern matching works by binding these free variables to subsections\
183 \ of the matching value. It does not make sense to have the same name for two\
184 \ different subsections though! When you say `" <> name <> "` in some code, there\
185 \ is no way for me to know which subsection you mean!"
193 ("This documentation comment is not followed by anything.")
195 "All documentation comments need to be right above the declaration they\
196 \ describe. Maybe some code got deleted or commented out by accident? Or\
197 \ maybe this comment is here by accident?"
200 SettingsOnNormalModule ->
202 "BAD MODULE DECLARATION"
204 "A normal module can expose values, but not settings like this."
206 "If you want a normal module, just remove this stuff. If you want to create\
207 \ an `effect module` you forgot to use the `effect` keyword. In that\
208 \ case, change `module` to `effect module` and you should be headed in\
209 \ the right direction!"
212 SettingsOnPortModule ->
214 "BAD MODULE DECLARATION"
216 "A port module can expose values, but not have settings like this."
218 "If you want a port module, just remove this stuff. If you want to create\
219 \ a custom effect module instead (which is rare) change `port module`\
220 \ to `effect module` and you should be headed in the right direction!"
223 DuplicateSettingOnEffectModule name ->
225 "EFFECT MODULE PROBLEM"
227 ("You have defined " <> Help.functionName name <> " multiple times.")
229 "There can only be one " <> Help.functionName name
230 <> " though! Remove until there is one left."
233 BadSettingOnEffectModule name ->
235 "EFFECT MODULE PROBLEM"
237 ("Setting " <> Help.functionName name <> " is not recognized.")
239 "Remove this entry and you should be all set!"
242 NoSettingsOnEffectModule ->
244 "EFFECT MODULE PROBLEM"
246 ("You are defining an effect module, but it has no settings.")
248 "If you just wanted a normal module, change the keywords `effect module`\
249 \ to `module` and you should be all set. If you want a proper effect module,\
250 \ you need to specify your commands and/or subscriptions. Read more about this\
251 \ here: <http://guide.elm-lang.org/effect_managers/>"
254 MissingManagerOnEffectModule name ->
256 "EFFECT MODULE PROBLEM"
258 ("You are defining an effect module, but there is no " <> Help.functionName name <> " defined.")
260 "There is a small set of top-level functions and values that must be defined\
261 \ in any complete effect module. The best thing is probably to just read more\
262 \ about effect modules here:\
263 \ <http://guide.elm-lang.org/effect_managers/>"
266 UnexpectedPort name ->
270 ("You are declaring port " <> Help.functionName name <> " in a normal module.")
272 "All ports must be defined in a `port module`. You should probably have only\
273 \ one of these for your project. This way all of your foreign interactions\
274 \ stay relatively organized."
277 TypeWithoutDefinition valueName ->
281 ("There is a type annotation for `" <> valueName <> "` but there"
282 <> " is no corresponding definition!"
285 "Directly below the type annotation, put a definition like:\n\n"
286 <> " " <> valueName <> " = 42"
289 DuplicateArgument funcName argName ->
293 ( "The name `" <> argName
294 <> "` is used more than once in the arguments of "
295 <> Help.functionName funcName <> "."
298 "Rename things until `" <> argName <> "` is used only once.\
299 \ Otherwise how can we tell which one you want when you\
300 \ say `" <> argName <> "` it in the body of your function?"
303 DuplicateFieldName region name ->
307 ("This record has more than one field named `" <> name <> "`.")
308 (text "There can only be one. Do some renaming to make sure the names are distinct!")
310 DuplicateValueDeclaration name ->
312 "DUPLICATE DEFINITION"
314 ( "Naming multiple top-level values " <> Help.functionName name <> " makes things\n"
315 <> "ambiguous. When you say " <> Help.functionName name <> " which one do you want?"
318 "Find all the top-level values named " <> Help.functionName name
319 <> " and do some renaming. Make sure the names are distinct!"
322 DuplicateTypeDeclaration name ->
324 "DUPLICATE DEFINITION"
326 ( "There are multiple types named `" <> name <> "` in this module."
329 "Search through this module, find all the types named `"
330 <> name <> "`, and give each of them a unique name."
333 DuplicateDefinition name ->
335 "DUPLICATE DEFINITION"
337 ("There are multiple values named `" <> name <> "` in this let-expression."
340 "Search through this let-expression, find all the values named `"
341 <> name <> "`, and give each of them a unique name."
344 UnboundTypeVarsInUnion typeName givenVars unbound ->
345 unboundTypeVars "type" typeName givenVars unbound
347 UnboundTypeVarsInAlias typeName givenVars unbound ->
348 unboundTypeVars "type alias" typeName givenVars unbound
350 UnusedTypeVarsInAlias typeName givenVars unused ->
352 "UNUSED TYPE VARIABLES"
354 ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
355 <> Help.commaSep unused
358 [ text "You probably need to change the declaration like this:"
359 , dullyellow $ hsep $
360 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
364 MessyTypeVarsInAlias typeName givenVars unused unbound ->
366 "TYPE VARIABLE PROBLEMS"
368 ( "Type alias `" <> typeName <> "` has some problems with type variables."
372 "The declaration says it uses certain type variables ("
373 <> Help.commaSep unused <> ") but they do not appear in the aliased type. "
374 <> "Furthermore, the aliased type says it uses type variables ("
375 <> Help.commaSep unbound
376 <> ") that do not appear in the declaration."
377 , text "You probably need to change the declaration like this:"
378 , dullyellow $ hsep $
379 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
384unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
385unboundTypeVars declKind typeName givenVars unboundVars =
387 "UNBOUND TYPE VARIABLES"
389 ( Help.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
390 <> Help.commaSep unboundVars
393 [ text "You probably need to change the declaration like this:"
395 map text (declKind : typeName : givenVars)
396 ++ map (dullyellow . text) unboundVars
397 ++ map text ["=", "..."]
399 "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
400 "` is an Int and another where it is a Bool. When we explicitly list the type\
401 \ variables, the type checker can see that they are actually different types."
407-- PARSE ERROR TO REPORT
410makeParseReport :: Maybe R.Region -> Text -> Help.Doc -> Report.Report
411makeParseReport subRegion pre post =
412 Report.report "PARSE ERROR" subRegion pre post
415problemToReport :: Maybe R.Region -> Problem -> Report.Report
416problemToReport subRegion problem =
417 let parseReport = makeParseReport subRegion in
421 "I ran into a tab, but tabs are not allowed in Elm files."
422 (reflowParagraph "Replace the tab with spages.")
426 "I got to the end of the file while parsing a multi-line comment."
429 "Multi-line comments look like {- comment -}, and it looks like\
430 \ you are missing the closing marker."
432 "Nested multi-line comments like {- this {- and this -} -} are allowed.\
433 \ That means the opening and closing markers must be balanced, just\
434 \ like parentheses in normal code. Maybe that is the problem?"
440 "I got to the end of the file while parsing a GLSL block."
442 "A shader should be defined in a block like this: [glsl| ... |]"
447 "I got to the end of the file while parsing a string."
449 "Strings look like \"this\" with double quotes on each end.\
450 \ So the closing double quote seems to be missing."
453 EndOfFile_MultiString ->
455 "I got to the end of the file while parsing a multi-line string."
457 "Multi-line strings begin and end with three double quotes in a\
458 \ row, like \"\"\"this\"\"\". So the closing marker seems\
464 "I got to the end of the file while parsing a character."
466 "Characters look like 'x' with single quotes on each end.\
467 \ So the closing single quote seems to be missing."
472 "This string is missing the closing quote."
475 "Elm strings must start and end with a double quote, like \"this\"."
477 "If you want a string that can contain newlines, use three double quotes in a\
478 \ row, like \"\"\"this\"\"\"."
484 "This character is missing the closing quote."
486 "Elm characters must start and end with a single quote, like 'a' and 'b'"
489 BadEscape _ escapeProblem ->
490 uncurry parseReport (escapeProblemToReport escapeProblem)
494 "Ran into a bad use of single quotes."
497 "If you want to create a string, switch to double quotes:"
499 dullyellow (text "'this'")
501 <> green (text "\"this\"")
503 "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
504 \ and individual characters like 'A' and '3'. If you really do want\
505 \ a character though, something went wrong and I did not find the\
506 \ closing single quote."
512 "Numbers cannot end with a decimal points."
514 "Leave it off or add some digits after it, like or 3 or 3.0"
519 "Numbers cannot have letters or underscores in them."
521 "Maybe a space is missing between a number and a variable?"
526 "If you put the letter E in a number, it should followed by more digits."
528 "If you want to say 1000, you can also say 1e3.\
529 \ You cannot just end it with an E though!"
534 "I see the start of a hex number, but not the end."
536 "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal digits (i.e. 0123456789abcdefABCDEF)"
541 "Normal numbers cannot start with a zero. Take the zeros off the front."
543 "Only numbers like 0x0040 or 0.25 can start with a zero."
548 "I ran into a problem while parsing this GLSL block."
549 (reflowParagraph msg)
551 BadUnderscore char ->
553 ("An underscore cannot be immediately followed by `" <> Text.singleton char <> "`.")
555 "Variable names cannot start with an underscore in Elm. You can\
556 \ use an underscore as a \"wildcard\" that matches anything\
557 \ though. So maybe you forgot a space after the underscore?"
563 badOp subRegion stack "A" "\"has type\" operator"
564 "type annotations and record types"
565 "Maybe you want :: instead? Or maybe something is indented too much?"
568 badEquals subRegion stack
571 if isCaseRelated stack then
573 "I ran into a stray arrow while parsing this `case` expression."
575 "All branches in a `case` must be indented the exact\
576 \ same amount, so the patterns are vertically\
577 \ aligned. Maybe this branch is indented too much?"
581 badOp subRegion stack "An" "arrow"
582 "cases expressions and anonymous functions"
583 "Maybe you want > or >= instead?"
586 badOp subRegion stack "A" "vertical bar"
588 "Maybe you want || instead?"
592 "I was not expecting this dot."
594 "Dots are for record access and decimal points, so\
595 \ they cannot float around on their own. Maybe\
596 \ there is some extra whitespace?"
599 Theories stack allTheories ->
602 "Something went wrong while parsing "
603 <> contextToText "your code" "" stack
606 parseReport starter $
607 case Set.toList (Set.fromList allTheories) of
611 "I do not have any suggestions though!"
613 "Can you get it down to a <http://sscce.org> and share it at\
614 \ <https://github.com/elm-lang/error-message-catalog/issues>?\
615 \ That way we can figure out how to give better advice!"
620 "I was expecting to see "
621 <> addPeriod (theoryToText stack theory)
625 [ text "I was expecting:"
628 ++ map (bullet . theoryToText stack) theories
631escapeProblemToReport :: EscapeProblem -> ( Text, Help.Doc )
632escapeProblemToReport escapeProblem =
633 case escapeProblem of
635 ( "A backslash starts an escaped character, but I do not recognize this one:"
637 [ "Maybe there is some typo?"
638 , Help.toSimpleHint "Valid escape characters include:"
639 , Help.indent 4 $ Help.vcat $
648 "The last one lets encode ANY character by its Unicode code\
649 \ point, so there are no other escape characters in Elm."
654 ( "I ran into an invalid Unicode escape character:"
656 [ "Here are some examples of valid Unicode escape characters:"
657 , Help.indent 4 $ Help.vcat $
664 "Notice that the code point is always surrounded by curly\
665 \ braces. They are required!"
670 ( "This is not a real Unicode code point:"
671 , "All valid Unicode code points are between 0 and 10FFFF."
674 UnicodeLength numDigits badCode ->
677 if numDigits < 4 then "more" else "fewer"
680 Text.justifyRight 4 '0' $ Text.dropWhile (== '0') badCode
685 , dullyellow $ text $ "\\u{" <> goodCode <> "}"
689 ( "This Unicode code point needs " <> moreOrFewer <> " digits:"
698bullet :: Text -> Help.Doc
700 Help.hang 4 (" - " <> reflowParagraph point)
703addPeriod :: Text -> Text
705 if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
711badOp :: Maybe R.Region -> ContextStack -> Text -> Text -> Text -> Text -> Report.Report
712badOp subRegion stack article opName setting hint =
715 "I was not expecting this " <> opName
716 <> contextToText "" " while parsing " stack <> "."
718 makeParseReport subRegion pre $
720 article <> " " <> opName <> " should only appear in "
721 <> setting <> ". " <> hint
724badEquals :: Maybe R.Region -> ContextStack -> Report.Report
725badEquals subRegion stack =
728 "I was not expecting this equals sign"
729 <> contextToText "" " while parsing " stack <> "."
731 makeParseReport subRegion pre (badEqualsHelp stack)
734badEqualsHelp :: ContextStack -> Help.Doc
739 "Maybe you want == instead? Or maybe something is indented too much?"
741 (ExprRecord, _) : _ ->
743 "Records look like { x = 3, y = 4 } with the equals sign right\
744 \ after the field name. Maybe you forgot a comma?"
746 (Definition _, _) : rest ->
748 "Maybe this is supposed to be a separate definition? If so, it\
749 \ is indented too far. "
751 if any ((==) ExprLet . fst) rest then
752 "All definitions in a `let` expression must be vertically aligned."
754 "Spaces are not allowed before top-level definitions."
760contextToText :: Text -> Text -> ContextStack -> Text
761contextToText defaultText prefixText stack =
766 (context, _) : rest ->
767 let anchor = getAnchor rest in
770 ExprIf -> "an `if`" <> anchor
771 ExprLet -> "a `let`" <> anchor
772 ExprFunc -> "an anonymous function" <> anchor
773 ExprCase -> "a `case`" <> anchor
774 ExprList -> "a list" <> anchor
775 ExprTuple -> "an expression (in parentheses)" <> anchor
776 ExprRecord -> "a record" <> anchor
777 Definition name -> name <> "'s definition"
778 Annotation name -> name <> "'s type annotation"
779 TypeTuple -> "a type (in parentheses)" <> anchor
780 TypeRecord -> "a record type" <> anchor
781 PatternList -> "a list pattern" <> anchor
782 PatternTuple -> "a pattern (in parentheses)" <> anchor
783 PatternRecord -> "a record pattern" <> anchor
784 Module -> "a module declaration"
785 Import -> "an import"
786 TypeUnion -> "a union type"
787 TypeAlias -> "a type alias"
788 Infix -> "an infix declaration"
789 Port -> "a port declaration"
792getAnchor :: ContextStack -> Text
798 (context, _) : rest ->
801 " in " <> name <> "'s definition"
804 " in " <> name <> "'s type annotation"
810isCaseRelated :: ContextStack -> Bool
816 (context, _) : rest ->
817 context == ExprCase || isCaseRelated rest
820theoryToText :: ContextStack -> Theory -> Text
821theoryToText context theory =
824 "the `" <> keyword <> "` keyword"
828 "=" -> equalsTheory context
829 "->" -> "an arrow (->) followed by an expression"
830 ":" -> "the \"has type\" symbol (:) followed by a type"
832 "|" -> barTheory context
833 "::" -> "the cons operator (::) followed by more list elements"
835 "-" -> "a minus sign (-)"
836 "_" -> "an underscore"
837 "(" -> "a left paren, for grouping or starting tuples"
838 ")" -> "a closing paren"
839 "[" -> "a left square bracket, for starting lists"
840 "]" -> "a right square bracket, to end a list"
841 "{" -> "a left curly brace, for starting records"
842 "}" -> "a right curly brace, to end a record"
843 "{-|" -> "a doc comment, like {-| example -}"
844 _ -> "the (" <> symbol <> ") symbol"
847 "a lower-case variable, like `x` or `user`"
850 "an upper-case variable, like `Maybe` or `Just`"
853 "an infix operator, like (+) or (==)"
856 "a digit from 0 to 9"
863 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
864 Expr -> "an expression, like x or 42"
865 AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
866 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
867 Arg -> "an argument, like `name` or `total`"
868 Pattern -> "a pattern, like `name` or (Just x)"
869 Type -> "a type, like Int or (List String)"
870 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
871 Exposing -> "something like `exposing (..)`"
874equalsTheory :: ContextStack -> Text
880 (context, _) : rest ->
882 ExprRecord -> "an equals sign (=) followed by an expression"
883 Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
884 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
885 TypeAlias -> "an equals sign (=) followed by the aliased type"
886 _ -> equalsTheory rest
889barTheory :: ContextStack -> Text
895 (context, _) : rest ->
897 ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
898 TypeRecord -> "a vertical bar (|) followed by some record field types"
899 TypeUnion -> "a vertical bar (|) followed by more union type constructors"
903badSpace :: ContextStack -> Text
907 "more indentation? I was not done with that last thing yet."
909 (context, _) : rest ->
911 ExprIf -> "the end of that `if`" <> badSpaceExprEnd rest
912 ExprLet -> "the end of that `let`" <> badSpaceExprEnd rest
913 ExprFunc -> badSpace rest
914 ExprCase -> "more of that `case`" <> badSpaceExprEnd rest
915 ExprList -> "the end of that list" <> badSpaceExprEnd rest
916 ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
917 ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
918 Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceExprEnd stack
919 Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
920 TypeTuple -> "a closing paren" <> badSpaceEnd
921 TypeRecord -> "the end of that record" <> badSpaceEnd
922 PatternList -> "the end of that list" <> badSpaceEnd
923 PatternTuple -> "a closing paren" <> badSpaceEnd
924 PatternRecord -> "the end of that record" <> badSpaceEnd
925 Module -> "something like `module Main exposing (..)`"
926 Import -> "something like `import Html exposing (..)`"
927 TypeUnion -> "more of that union type" <> badSpaceEnd
928 TypeAlias -> "more of that type alias" <> badSpaceEnd
929 Infix -> "more of that infix declaration" <> badSpaceEnd
930 Port -> "more of that port declaration" <> badSpaceEnd
935 ". Maybe you forgot some code? Or you need more indentation?"
938badSpaceExprEnd :: ContextStack -> Text
939badSpaceExprEnd stack =
944 (Definition name, R.Position _ column) : _ ->
950 "more indentation? (Try " <> i2t (column + 1) <> "+ spaces.)"
952 ". Maybe you forgot some code? Or maybe the body of `" <> name
953 <> "` needs " <> ending
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