1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Canonicalize where
5import Control.Arrow ((***))
6import qualified Data.Char as Char
7import qualified Data.Text as Text
10import qualified AST.Declaration as Decl
11import qualified AST.Expression.Canonical as Canonical
12import qualified AST.Module.Name as ModuleName
13import qualified AST.Pattern as P
14import qualified AST.Type as Type
15import qualified AST.Variable as Var
16import qualified Reporting.Annotation as A
17import qualified Reporting.Region as Region
18import qualified Reporting.Render.Type as RenderType
19import qualified Reporting.Report as Report
20import qualified Reporting.Helpers as Help
21import Reporting.Helpers
22 ( Doc, (<>), dullyellow, fillSep, i2t, indent, maybeYouWant, reflowParagraph, text
27-- CANONICALIZATION ERRORS
32 | BadRecursion Region.Region Canonical.Def [Canonical.Def]
33 | BadInfix Region.Region Int Var.Canonical Decl.Assoc Var.Canonical Decl.Assoc
34 | Pattern PatternError
36 | Import ModuleName.Raw ImportError
38 | DuplicateExport Text
40 | BadPort Text Type.Canonical
51 , varProblem :: VarProblem
52 , varSuggestions :: [Text]
58 | UnknownQualifier Text Text
59 | QualifiedUnknown Text Text
63variable :: Text -> Text -> VarProblem -> [Text] -> Error
64variable kind name problem suggestions =
65 Var (VarError kind name problem suggestions)
73 = PatternArgMismatch Var.Canonical Int Int
76argMismatch :: Var.Canonical -> Int -> Int -> Error
77argMismatch name expected actual =
78 Pattern (PatternArgMismatch name expected actual)
86 = ModuleNotFound [ModuleName.Raw]
87 | ValueNotFound Text [Text]
90moduleNotFound :: ModuleName.Raw -> [ModuleName.Raw] -> Error
91moduleNotFound name possibilities =
92 Import name (ModuleNotFound possibilities)
95valueNotFound :: ModuleName.Raw -> Text -> [Text] -> Error
96valueNotFound name value possibilities =
97 Import name (ValueNotFound value possibilities)
105 = ArgMismatch Var.Canonical Int Int
106 | SelfRecursive Text [Text] Type.Raw
107 | MutuallyRecursive [(Region.Region, Text, [Text], Type.Raw)]
110alias :: Var.Canonical -> Int -> Int -> Error
111alias name expected actual =
112 Alias (ArgMismatch name expected actual)
122 , portType :: Type.Canonical
123 , portMessage :: Maybe Text
127port :: Text -> Type.Canonical -> Maybe Text -> Error
128port name tipe maybeMessage =
129 Port (PortError name tipe maybeMessage)
136namingError :: Text -> Text -> Report.Report
137namingError pre post =
138 Report.report "NAMING ERROR" Nothing pre (text post)
141toReport :: RenderType.Localizer -> Error -> Report.Report
142toReport localizer err =
144 Var (VarError kind name problem suggestions) ->
145 let var = kind <> " `" <> name <> "`"
150 ("This usage of " <> var <> " is ambiguous.")
151 (maybeYouWant suggestions)
153 UnknownQualifier qualifier localName ->
155 ("Cannot find " <> var <> ".")
156 ( "No module called `" <> qualifier <> "` has been imported. "
157 <> maybeYouWant (map (\modul -> modul <> "." <> localName) suggestions)
160 QualifiedUnknown qualifier localName ->
162 ("Cannot find " <> var <> ".")
163 ( "`" <> qualifier <> "` does not expose `" <> localName <> "`. "
164 <> maybeYouWant (map (\v -> qualifier <> "." <> v) suggestions)
169 ("Cannot find " <> var)
170 (maybeYouWant suggestions)
172 BadRecursion region def defs ->
175 badSelfRecursion region (defToText def)
178 badMutualRecursion region (defToText def) (map (defToText) defs)
180 BadInfix region _prec (Var.Canonical _ name1) _assoc1 (Var.Canonical _ name2) _assoc2 ->
184 ("You cannot mix (" <> name1 <> ") and (" <> name2 <> ") without parentheses." )
188 "I do not know how to group these expressions. Add parentheses for me!"
192 Pattern patternError ->
194 PatternArgMismatch var expected actual ->
195 argMismatchReport "Pattern" var expected actual
199 ArgMismatch var expected actual ->
200 argMismatchReport "Type" var expected actual
202 SelfRecursive name tvars tipe ->
206 "This type alias is recursive, forming an infinite type!"
210 "When I expand a recursive type alias, it just keeps getting bigger and bigger.\
211 \ So dealiasing results in an infinitely large type! Try this instead:"
213 RenderType.decl localizer name tvars [(name, [unsafePromote tipe])]
215 "This is kind of a subtle distinction. I suggested the naive fix, but you can\n"
216 <> "often do something a bit nicer. So I would recommend reading more at:\n"
217 <> Help.hintLink "recursive-alias"
221 MutuallyRecursive aliases ->
225 "This type alias is part of a mutually recursive set of type aliases."
227 [ text "The following type aliases are mutually recursive:"
228 , indent 4 (Help.drawCycle (map (\(_, name, _, _) -> name) aliases))
230 "You need to convert at least one `type alias` into a `type`. This is a kind of\
231 \ subtle distinction, so definitely read up on this before you make a fix: "
232 <> Help.hintLink "recursive-alias"
236 Import name importError ->
237 let moduleName = ModuleName.toText name
240 ModuleNotFound suggestions ->
242 ("Could not find a module named `" <> moduleName <> "`")
243 (maybeYouWant suggestions)
245 ValueNotFound value suggestions ->
247 ("Module `" <> moduleName <> "` does not expose `" <> value <> "`")
248 (maybeYouWant suggestions)
250 Export name suggestions ->
252 ("Could not export `" <> name <> "` which is not defined in this module.")
253 (maybeYouWant suggestions)
255 DuplicateExport name ->
257 ("You are trying to export `" <> name <> "` multiple times!")
258 "Remove duplicates until there is only one listed."
260 Port (PortError name tipe maybeMessage) ->
263 maybe "" (" the following " <> ) maybeMessage
268 ("Port `" <> name <> "` is trying to communicate an unsupported type."
271 [ text ("The specific unsupported type is" <> context <> ":")
272 , indent 4 (RenderType.toDoc localizer tipe)
273 , text "The types of values that can flow through in and out of Elm include:"
274 , indent 4 $ reflowParagraph $
275 "Ints, Floats, Bools, Strings, Maybes, Lists, Arrays,\
276 \ Tuples, Json.Values, and concrete records."
277 -- TODO add a note about custom decoders and encoders when they exist!
285 ("Port `" <> name <> "` has an invalid type."
288 [ text ("You are saying it should be:")
289 , indent 4 (RenderType.toDoc localizer tipe)
291 "But you need to use the particular format described here:\
292 \ <http://guide.elm-lang.org/interop/javascript.html#ports>"
297argMismatchReport :: Text -> Var.Canonical -> Int -> Int -> Report.Report
298argMismatchReport kind var expected actual =
302 <> (if actual < expected then "few" else "many")
306 (Text.map Char.toUpper numArgs)
308 ( kind <> " " <> Var.toText var <> " has " <> numArgs <> "."
311 "Expecting " <> i2t expected <> ", but got " <> i2t actual <> "."
316extractSuggestions :: Error -> Maybe [Text]
317extractSuggestions err =
319 Var (VarError _ _ _ suggestions) ->
322 BadRecursion _ _ _ ->
325 BadInfix _ _ _ _ _ _ ->
334 Import _ importError ->
336 ModuleNotFound suggestions ->
337 Just (map ModuleName.toText suggestions)
339 ValueNotFound _ suggestions ->
342 Export _ suggestions ->
355unsafePromote :: Type.Raw -> Type.Canonical
356unsafePromote (A.A _ rawType) =
358 Type.RLambda arg result ->
359 Type.Lambda (unsafePromote arg) (unsafePromote result)
364 Type.RType (Var.Raw name) ->
365 Type.Type (Var.local name)
367 Type.RApp func args ->
368 Type.App (unsafePromote func) (map unsafePromote args)
370 Type.RRecord fields ext ->
371 Type.Record (map (A.drop *** unsafePromote) fields) (fmap unsafePromote ext)
378badSelfRecursion :: Region.Region -> Text -> Report.Report
379badSelfRecursion region name =
382 Help.functionName name <> " is defined directly in terms of itself, causing an infinite loop."
384 Report.report "BAD RECURSION" (Just region) header $
386 [ badSelfRecursionHelp "Maybe you are trying to mutate a variable?" $
387 "Elm does not have mutation, so when I see " <> Help.functionName name
388 <> " defined in terms of " <> Help.functionName name
389 <> ", I treat it as a recursive definition. Try giving the new value a new name!"
390 , badSelfRecursionHelp "Maybe you DO want a recursive value?" $
391 "To define " <> Help.functionName name <> " we need to know what " <> Help.functionName name
392 <> " is, so let’s expand it. Wait, but now we need to know what " <> Help.functionName name
393 <> " is, so let’s expand it... This will keep going infinitely!"
394 , badSelfRecursionHelp "To really learn what is going on and how to fix it, check out:" $
395 Help.hintLink "bad-recursion"
399badSelfRecursionHelp :: Text -> Text -> Doc
400badSelfRecursionHelp intro body =
402 map (dullyellow . text) (Text.words intro)
403 ++ map text (Text.words body)
406badMutualRecursion :: Region.Region -> Text -> [Text] -> Report.Report
407badMutualRecursion region name names =
410 Help.functionName name <> " is defined in terms of itself in a sneaky way, causing an infinite loop."
412 Report.report "BAD RECURSION" (Just region) header $
415 "The following definitions depend directly on each other:"
416 , indent 4 $ Help.drawCycle (name : names)
418 "You seem to have a fairly tricky case, so I very highly recommend reading this: "
419 <> Help.hintLink "bad-recursion"
420 <> " It will help you really understand the problem and how to fix it. Read it!"
424defToText :: Canonical.Def -> Text
425defToText (Canonical.Def _ pattern _ _) =
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