@@ -1,10 +1,9 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Type where
2module Reporting.Error.Type where
4−import qualified Data.Char as Char
4+import qualified Data.Maybe as Maybe
5−import qualified Data.List as List
5+import Text.PrettyPrint.ANSI.Leijen (Doc, (<+>), equals, indent, text)
7−import qualified AST.Helpers as AstHelp
8import qualified AST.Type as Type
7import qualified AST.Type as Type
9import qualified AST.Variable as Var
8import qualified AST.Variable as Var
10import qualified Reporting.Error.Helpers as Help
9import qualified Reporting.Error.Helpers as Help
@@ -85,62 +84,52 @@ toReport localizer err =
85 Mismatch info ->
84 Mismatch info ->
86 mismatchToReport localizer info
85 mismatchToReport localizer info
88− InfiniteType name var tipe ->
87+ InfiniteType name overallType infiniteType ->
89− let
88+ infiniteTypeToReport localizer name overallType infiniteType
91− error "TODO P.pretty localizer False var"
93− prettyType =
90+ BadMain tipe ->
94− error "TODO P.pretty localizer False tipe"
91+ Report.report
95− in
92+ "BAD MAIN TYPE"
96− Report.simple "INFINITE TYPE"
93+ Nothing
97− ( "I am inferring weird self-referential type for `" ++ name ++ "`"
94+ "The 'main' value has an unsupported type."
99− ( "TODO - do a better job\n\n"
96+ [ Help.reflowParagraph $
100− ++ "The bit of the type that is self-referential looks like this:\n\n"
97+ "I need an Element, Html, (Signal Element), or (Signal Html) so I can render it\
101− ++ error "TODO P.render (P.nest 4 (prettyVar <+> P.equals <+> prettyType))"
98+ \ on screen, but you gave me:"
102− ++ "\n\nThe cause is often that the usage of `" ++ name ++ "` is flipped around.\n\n"
99+ , indent 4 (RenderType.toDoc localizer tipe)
103− ++ "Maybe you are inserting a data structure into an element? Maybe you are giving\n"
100+ ]
104− ++ "a function to an argument? Either way, something is probably backwards!\n\n"
105− ++ "Try breaking the code related to `" ++ name ++ "` into smaller pieces.\n"
106− ++ "Give each piece a name and try to write down its type."
110− Report.simple "BAD MAIN TYPE" "The 'main' value has an unsupported type." $
104+
111− "I need an Element, Html, (Signal Element), or (Signal Html) so I can render it\n"
105+-- TYPE MISMATCHES
112− ++ "on screen, but you gave me:\n\n"
113− ++ RenderType.tipe localizer tipe
116mismatchToReport :: RenderType.Localizer -> Mismatch -> Report.Report
108mismatchToReport :: RenderType.Localizer -> Mismatch -> Report.Report
117mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
109mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
120− Report.Report "TYPE MISMATCH"
112+ Report.report "TYPE MISMATCH"
115+ Maybe.maybeToList (fmap reasonToString maybeReason)
122− pretty tipe =
117+ cmpHint leftWords rightWords extraHints =
123− "\n\n"
118+ comparisonHint localizer leftType rightType leftWords rightWords (extraHints ++ reasonHints)
124− ++ RenderType.tipe localizer tipe
127 case hint of
120 case hint of
128 CaseBranch branchNumber region ->
121 CaseBranch branchNumber region ->
130 (Just region)
123 (Just region)
131− ( "The " ++ ordinalize (branchNumber -1) ++ " and " ++ ordinalize branchNumber
124+ ( "The " ++ ordinalPair branchNumber
132− ++ " branches of this `case` result in different types of values."
125+ ++ " branches of this `case` produce different types of values."
134− ( "The " ++ ordinalize (branchNumber -1) ++ " branch results in this type of value:\n"
128+ ("The " ++ Help.ordinalize (branchNumber -1) ++ " branch has this type:")
138− ++ "And the " ++ ordinalize branchNumber ++ " branch results in this type:\n"
129+ ("But the " ++ Help.ordinalize branchNumber ++ " is:")
139−
130+ [ "All branches in a `case` must have the same type. So no matter\
142− ++ "These branches should match so that no matter which one we take, we always get\n"
143− ++ "back the same type of value."
131+ \ which one we take, we always get back the same type of value."
@@ -155,72 +144,62 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
155 IfCondition ->
144 IfCondition ->
158− ( "This condition does not evaluate to a boolean value, True or False."
147+ "This condition does not evaluate to a boolean value, True or False."
160− ( "Instead of Bool, it is resulting in:\n"
149+ "You have given me an condition with this type:"
161−
150+ "But I need it to be:"
164− ++ "Note: Elm does not have \"truthiness\" such that ints and strings and lists\n"
151+ [ "Elm does not have \"truthiness\" such that ints and strings and lists\
165− ++ "are automatically converted to booleans. Do that conversion explicitly."
152+ \ are automatically converted to booleans. Do that conversion explicitly."
168 IfBranches ->
156 IfBranches ->
171− ( "The branches of this `if` result in different types of values."
159+ "The branches of this `if` produce different types of values."
173− ( "The `then` branch results in:\n"
161+ "The `then` branch has type:"
177− ++ "And the `else` branch results in:\n"
162+ "But the `else` branch is:"
181− ++ "These need to match so that no matter which one we take, we always get\n"
163+ [ "These need to match so that no matter which branch we take, we\
182− ++ "back the same type of value."
164+ \ always get back the same type of value."
185 MultiIfBranch branchNumber region ->
168 MultiIfBranch branchNumber region ->
187 (Just region)
170 (Just region)
188− ( "The " ++ ordinalize branchNumber ++ " branch of this `if` results in an unexpected type of value."
171+ ( "The " ++ ordinalPair branchNumber
172+ ++ " branches of this `if` produce different types of values."
190− ( "The " ++ ordinalize (branchNumber - 1) ++ " branch results in:\n"
175+ ("The " ++ Help.ordinalize (branchNumber - 1) ++ " branch has this type:")
194− ++ "And the "++ ordinalize branchNumber ++ " branch results in:\n"
176+ ("But the "++ Help.ordinalize branchNumber ++ " is:")
198− ++ "All branches should match so that no matter which one we take, we always get\n"
177+ [ "All the branches of an `if` need to match so that no matter which\
199− ++ "back the same type of value."
178+ \ one we take, we get back the same type of value overall."
205− ( "All the branches of this if-expression are consistent, but the overall\n"
185+ "All the branches of this `if` are consistent, but the overall\
206− ++ "type does not match how it is used elsewhere."
186+ \ type does not match how it is used elsewhere."
208− ( "The `if` evaluates to something of type:\n"
188+ "The `if` evaluates to something of type:"
212− ++ "Which is fine, but the surrounding context wants it to be:\n"
189+ "Which is fine, but the surrounding context wants it to be:"
218 ListElement elementNumber region ->
193 ListElement elementNumber region ->
220 (Just region)
195 (Just region)
196+ ("The " ++ ordinalPair elementNumber ++ " elements are different types of values.")
221− ( "The " ++ ordinalize elementNumber ++ " element of this list is an unexpected type of value."
198+ ("The " ++ Help.ordinalize (elementNumber - 1) ++ " element has this type:")
222− )
199+ ("But the "++ Help.ordinalize elementNumber ++ " is:")
223− ( "All elements should be the same type of value so that we can iterate over the\nlist without running into unexpected values."
200+ [ "All elements should be the same type of value so that we can\
201+ \ iterate through the list without running into unexpected values."
@@ -229,56 +208,43 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
229 ( "All the elements in this list are the same type, but the overall\n"
208 ( "All the elements in this list are the same type, but the overall\n"
230 ++ "type does not match how it is used elsewhere."
209 ++ "type does not match how it is used elsewhere."
232− ( "The list has type:\n"
212+ "The list has type:"
236− ++ "Which is fine, but the surrounding context wants it to be:\n"
213+ "Which is fine, but the surrounding context wants it to be:"
241 BinopLeft op region ->
217 BinopLeft op region ->
243 (Just region)
219 (Just region)
244− ("The left argument of " ++ prettyOperator op ++ " is causing a type mismatch.")
220+ ("The left argument of " ++ prettyName op ++ " is causing a type mismatch.")
245− ( prettyOperator op ++ " is expecting:"
221+ ( cmpHint
246−
222+ (prettyName op ++ " is expecting the left argument to be a:")
247− ++ pretty leftType
223+ "But the left argument is:"
249− ++ "But the value on the left has this type:"
254 BinopRight op region ->
227 BinopRight op region ->
256 (Just region)
229 (Just region)
257− ( "The right argument of " ++ prettyOperator op ++ " is causing a type mismatch."
230+ ("The right argument of " ++ prettyName op ++ " is causing a type mismatch.")
259− ( prettyOperator op ++ " is expecting:"
232+ (prettyName op ++ " is expecting the right argument to be a:")
263− ++ "But the value on the right has this type:"
233+ "But the right argument is:"
268 Binop op ->
237 Binop op ->
240+ ( "The two arguments to " ++ prettyName op ++
271− ( "The two arguments to " ++ prettyOperator op ++ " are fine, but the overall type of this expression\n"
241+ " are fine, but the overall type of this expression\
272− ++ "does not match how it is used elsewhere."
242+ \ does not match how it is used elsewhere."
274− ( "The result of this binary operation is:\n"
245+ "The result of this binary operation is:"
278− ++ "Which is fine, but the surrounding context wants it to be:\n"
246+ "Which is fine, but the surrounding context wants it to be:"
284 Function maybeName ->
250 Function maybeName ->
@@ -286,30 +252,24 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
287 ( "The return type of " ++ funcName maybeName ++ " is being used in unexpected ways."
253 ( "The return type of " ++ funcName maybeName ++ " is being used in unexpected ways."
289− ( "The function results in a value with type:\n"
256+ "The function results in this type of value:"
293− ++ "Which is fine, but the surrounding context wants it to be:\n"
257+ "Which is fine, but the surrounding context wants it to be:"
298 UnexpectedArg maybeName index region ->
261 UnexpectedArg maybeName index region ->
300 (Just region)
263 (Just region)
301− ( "The " ++ ordinalize index ++ " argument to " ++ funcName maybeName
264+ ( "The " ++ Help.ordinalize index ++ " argument to " ++ funcName maybeName
302 ++ " is causing a mismatch."
265 ++ " is causing a mismatch."
268+ ( Help.capitalize (funcName maybeName) ++ " is expecting the "
304− ( "The " ++ ordinalize index ++ " to " ++ funcName maybeName ++ " should be:"
269+ ++ Help.ordinalize index ++ " argument to be:"
308− ++ "But it is:"
271+ "But it is:"
312− ++ maybe "" reasonToString maybeReason
315 FunctionArity maybeName expected actual region ->
275 FunctionArity maybeName expected actual region ->
@@ -318,34 +278,29 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
320 (Just region)
280 (Just region)
321− ( capitalize (funcName maybeName) ++ " is expecting " ++ show expected
281+ ( Help.capitalize (funcName maybeName) ++ " is expecting " ++ show expected
322 ++ " argument" ++ s ++ ", but was given " ++ show actual ++ "."
282 ++ " argument" ++ s ++ ", but was given " ++ show actual ++ "."
324− ( error "TODO are the types interesting here?"
284+ (text "Maybe you forgot some parentheses somewhere?")
327 BadTypeAnnotation name ->
286 BadTypeAnnotation name ->
330− ( "The type annotation for `" ++ name ++ "` does not match its definition."
289+ ("The type annotation for " ++ Help.functionName name ++ " does not match its definition.")
332− ( "Based on the actual definition, the type should be:\n"
291+ "The type annotation is saying:"
333−
292+ "But I am inferring that the definition has this type:"
334− ++ pretty rightType
293+ []
337 Instance name ->
296 Instance name ->
340− ( "This usage of `" ++ name ++ "` is causing a type mismatch."
299+ (Help.functionName name ++ " is being used in an unexpected way.")
342− ( "Based on its definition, `" ++ name ++ "` has this type:"
301+ ("Based on its definition, " ++ Help.functionName name ++ " has this type:")
346− ++ "But you are trying to use it as:"
302+ "But you are trying to use it as:"
351 Literal name ->
306 Literal name ->
@@ -353,9 +308,10 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
354 ( "This " ++ name ++ " value is being used as if it is some other type of value."
309 ( "This " ++ name ++ " value is being used as if it is some other type of value."
356− ( "You are trying to use this " ++ name ++ " as this type:"
311+ ( cmpHint
357−
312+ ("The " ++ name ++ " definitely has this type:")
358− ++ pretty rightType
313+ ("But it is being used as:")
361 Pattern patErr ->
317 Pattern patErr ->
@@ -364,71 +320,87 @@ mismatchToReport localizer (MismatchInfo hint leftType rightType maybeReason) =
364 case patErr of
320 case patErr of
365 PVar name -> "variable `" ++ name ++ "`"
321 PVar name -> "variable `" ++ name ++ "`"
366 PAlias name -> "alias `" ++ name ++ "`"
322 PAlias name -> "alias `" ++ name ++ "`"
367− PData name -> "`" ++ name ++ "`"
323+ PData name -> "tag `" ++ name ++ "`"
368 PRecord -> "a record"
324 PRecord -> "a record"
372− ( "Problem with " ++ thing ++ " in this pattern match."
328+ ( Help.capitalize thing ++ " is causing problems in this pattern match."
374− ( "This pattern matches things of type:"
331+ "This pattern matches things of type:"
378− ++ "But the values it will actually be trying to match are:"
332+ "But the values it will actually be trying to match are:"
383 Shader ->
336 Shader ->
386− ( "There is some problem with this GLSL shader."
339+ "There is some problem with this GLSL shader."
388 ( error "TODO generic error"
340 ( error "TODO generic error"
394− ( "The low and high members of this list range are not the same type of value."
346+ "The low and high members of this list range are not the same type of value."
396− ( "The low end of the range has type:"
348+ "The low end of the range has type:"
400− ++ "But the high end is:"
349+ "But the high end is:"
405 Lambda ->
353 Lambda ->
408− ( "This anonymous function is being used in an unexpected way."
356+ "This anonymous function is being used in an unexpected way."
410− ( "The anonymous function has type:"
358+ "The anonymous function has type:"
414− ++ "But you are trying to use it as:"
359+ "But you are trying to use it as:"
419 Record ->
363 Record ->
422− ( "This record is being used in an unexpected way."
366+ "This record is being used in an unexpected way."
424− ( "The record has type:"
368+ "The record has type:"
369+ "But you are trying to use it as:"
375+ :: RenderType.Localizer
382+comparisonHint localizer leftType rightType leftWords rightWords finalHints =
384+ (leftDoc, rightDoc) =
385+ RenderType.diffToDocs localizer RenderType.Elide leftType rightType
388+ [ Help.reflowParagraph leftWords
390+ , Help.reflowParagraph rightWords
394+ map Help.reflowParagraph finalHints
428− ++ "But you are trying to use it as:"
397+ordinalPair :: Int -> String
399+ Help.ordinalize (number -1 ) ++ " and " ++ Help.ordinalize number
430− ++ pretty rightType
402+
431− )
403+-- MISMTACH REASONS
434reasonToString :: Reason -> String
406reasonToString :: Reason -> String
@@ -445,12 +417,12 @@ reasonToString reason =
446 "These records look pretty different."
418 "These records look pretty different."
448− [(exp,act)] ->
420+ [(ex,ac)] ->
449− "Looks like a misspelling between field " ++ exp ++ " and " ++ act ++ "."
421+ "Looks like a misspelling between field " ++ ex ++ " and " ++ ac ++ "."
451 potentialTypos ->
423 potentialTypos ->
452 "There are some potential typos in the record field names.\n"
424 "There are some potential typos in the record field names.\n"
453− ++ concatMap (\(exp,act) -> "\n " ++ exp ++ " <=> " ++ act) potentialTypos
425+ ++ concatMap (\(ex,ac) -> "\n " ++ ex ++ " <=> " ++ ac) potentialTypos
455 NotRecord ->
427 NotRecord ->
456 "A record cannot be merged with other types of values."
428 "A record cannot be merged with other types of values."
@@ -467,29 +439,15 @@ similarNames otherKeys key =
467 map ((,) key) (filter (\key' -> Help.distance key key' == 1) otherKeys)
439 map ((,) key) (filter (\key' -> Help.distance key key' == 1) otherKeys)
471genericMissingFieldsMessage :: String -> [String] -> String
442genericMissingFieldsMessage :: String -> [String] -> String
472genericMissingFieldsMessage latterOrFormer fields =
443genericMissingFieldsMessage latterOrFormer fields =
473− "A record in the " ++ latterOrFormer ++ " type is missing "
444+ "A record in the " ++ latterOrFormer ++ " type is missing field"
474− ++
445+ ++ Help.commaSep fields
477− "field `" ++ key ++ "`"
480− "fields " ++ key1 ++ " and " ++ key2
483− "fields " ++ List.intercalate ", " (init keys) ++ ", and " ++ last keys
486−prettyOperator :: Var.Canonical -> String
448+prettyName :: Var.Canonical -> String
487−prettyOperator (Var.Canonical _ opName) =
449+prettyName (Var.Canonical _ opName) =
488− if AstHelp.isOp opName then
489− "(" ++ opName ++ ")"
492− "`" ++ opName ++ "`"
450+ Help.functionName opName
495funcName :: Maybe Var.Canonical -> String
453funcName :: Maybe Var.Canonical -> String
@@ -499,33 +457,62 @@ funcName maybeVar =
499 "this function"
457 "this function"
501 Just var ->
459 Just var ->
502− "function " ++ prettyOperator var
460+ "function " ++ prettyName var
468+ :: RenderType.Localizer
505−capitalize :: String -> String
469+ -> String
506−capitalize string =
470+ -> Type.Canonical
507− case string of
471+ -> Type.Canonical
508− [] -> []
472+ -> Report.Report
509− c : cs ->
473+infiniteTypeToReport localizer name overallType infiniteType =
510− Char.toUpper c : cs
474+ Report.report
513−ordinalize :: Int -> String
477+ ( "I am inferring a weird self-referential type for " ++ Help.functionName name
514−ordinalize number =
478+ )
480+ explainInfiniteType localizer name overallType infiniteType
483+ "This can be very tricky to figure out, so definitely read the debugging hints:\n"
484+ ++ Help.hintLink "infinite-type"
490+ :: RenderType.Localizer
495+explainInfiniteType localizer name overallType infiniteType =
516− remainder10 =
497+ selfReference =
517− number `mod` 10
498+ text "?" <+> equals <+> RenderType.toDoc localizer infiniteType
523− | remainder100 `elem` [11..13] = "th"
524− | remainder10 == 1 = "st"
525− | remainder10 == 2 = "nd"
526− | remainder10 == 3 = "rd"
529− show number ++ ending
500+ case overallType of
531−
502+ [ Help.reflowParagraph $
503+ "I cannot write down the actual type of " ++ Help.functionName name ++
504+ " because it is infinitely large (that's the problem!) so here it\
505+ \ is as an equation where `?` represents the type:"
506+ , indent 4 selfReference
510+ [ Help.reflowParagraph $
511+ "I am inferring that " ++ Help.functionName name ++ " has this type:"
512+ , indent 4 (RenderType.toDoc localizer overallType)
513+ , Help.reflowParagraph $
514+ "The problem is in the `?` which seems to contain itself. I cannot show\
515+ \ you that type directly (because it is infinitely large!) so here it is\
517+ , indent 4 selfReference