@@ -2,17 +2,23 @@
2module Reporting.Error.Type where
2module Reporting.Error.Type where
4import qualified Data.Char as Char
4import qualified Data.Char as Char
5+import qualified Data.List as List
5import Text.PrettyPrint ((<+>))
6import Text.PrettyPrint ((<+>))
6import qualified Text.PrettyPrint as P
7import qualified Text.PrettyPrint as P
8−import qualified AST.Helpers as Help
9+import qualified AST.Helpers as AstHelp
9import qualified AST.Type as Type
10import qualified AST.Type as Type
10import qualified AST.Variable as Var
11import qualified AST.Variable as Var
12+import qualified Reporting.Error.Helpers as Help
11import qualified Reporting.PrettyPrint as P
13import qualified Reporting.PrettyPrint as P
12import qualified Reporting.Region as Region
14import qualified Reporting.Region as Region
13import qualified Reporting.Report as Report
15import qualified Reporting.Report as Report
17 = Mismatch Mismatch
23 = Mismatch Mismatch
18 | BadMain Type.Canonical
24 | BadMain Type.Canonical
@@ -25,7 +31,6 @@ data Error
26data Mismatch = MismatchInfo
32data Mismatch = MismatchInfo
27 { _hint :: Hint
33 { _hint :: Hint
28− , _rootType :: Type.Canonical
29 , _leftType :: Type.Canonical
34 , _leftType :: Type.Canonical
30 , _rightType :: Type.Canonical
35 , _rightType :: Type.Canonical
31 , _reason :: Maybe Reason
36 , _reason :: Maybe Reason
@@ -34,8 +39,6 @@ data Mismatch = MismatchInfo
35data Reason
40data Reason
36 = MessyFields [String] [String]
41 = MessyFields [String] [String]
37− | ExpectedFields [String]
38− | ActualFields [String]
39 | NotRecord
42 | NotRecord
40 | TooLongComparableTuple Int
43 | TooLongComparableTuple Int
41 | Rigid (Maybe String)
44 | Rigid (Maybe String)
@@ -81,21 +84,8 @@ data Pattern
81toReport :: P.Dealiaser -> Error -> Report.Report
84toReport :: P.Dealiaser -> Error -> Report.Report
82toReport dealiaser err =
85toReport dealiaser err =
83 case err of
86 case err of
84− Mismatch (MismatchInfo hint rootType leftType rightType maybeReason) ->
87+ Mismatch info ->
85− let
88+ mismatchToReport dealiaser info
86− (subRegion, preHint, maybePostHint) = hintToString hint
89− "TODO explain what went wrong!\n\n" ++ show maybeReason ++ "\n\n"
90− ++ maybe "" (++"\n\n") maybePostHint
91− ++ P.render (P.nest 4 (P.pretty dealiaser False rootType)) ++ "\n\n"
92− ++ "As I infer the types of values flowing through your program, I see a conflict\n"
93− ++ "between these two types:\n\n"
94− ++ P.render (P.nest 4 (P.pretty dealiaser False leftType))
96− ++ P.render (P.nest 4 (P.pretty dealiaser False rightType))
98− Report.Report "TYPE MISMATCH" subRegion preHint postHint
100 InfiniteType name var tipe ->
90 InfiniteType name var tipe ->
@@ -125,119 +115,250 @@ toReport dealiaser err =
125 ++ P.render (P.nest 4 (P.pretty dealiaser False tipe))
115 ++ P.render (P.nest 4 (P.pretty dealiaser False tipe))
128−hintToString :: Hint -> (Maybe Region.Region, String, Maybe String)
118+mismatchToReport :: P.Dealiaser -> Mismatch -> Report.Report
129−hintToString hint =
119+mismatchToReport dealiaser (MismatchInfo hint leftType rightType maybeReason) =
122+ Report.Report "TYPE MISMATCH"
126+ ++ P.render (P.nest 4 (P.pretty dealiaser False tipe))
130 case hint of
129 case hint of
131 CaseBranch branchNumber region ->
130 CaseBranch branchNumber region ->
132− ( Just region
132+ (Just region)
133− , "The " ++ ordinalize branchNumber ++ " branch of this `case` results in an unexpected type of value."
133+ ( "The " ++ ordinalize (branchNumber -1) ++ " and " ++ ordinalize branchNumber
134+ ++ " branches of this `case` result in different types of values."
136+ ( "The " ++ ordinalize (branchNumber -1) ++ " branch results in this type of value:\n"
140+ ++ "And the " ++ ordinalize branchNumber ++ " branch results in this type:\n"
134− , Just "All branches should match so that no matter which one we take, we always get\nback the same type of value."
144+ ++ "These branches should match so that no matter which one we take, we always get\n"
145+ ++ "back the same type of value."
138− ( Nothing
150+ Nothing
139− , "All the branches of this case-expression are consistent, but the overall\n"
151+ ( "All the branches of this case-expression are consistent, but the overall\n"
140− ++ "type does not match how it is used elsewhere."
152+ ++ "type does not match how it is used elsewhere."
154+ ( error "TODO generic error"
144 IfCondition ->
157 IfCondition ->
145− ( Nothing
159+ Nothing
146− , "This condition does not evaluate to a boolean value, True or False."
160+ ( "This condition does not evaluate to a boolean value, True or False."
162+ ( "Instead of Bool, it is resulting in:\n"
147− , Just "Elm does not have \"truthiness\" such that ints and strings and lists are\nautomatically converted to booleans. Do that conversion explicitly."
166+ ++ "Note: Elm does not have \"truthiness\" such that ints and strings and lists\n"
167+ ++ "are automatically converted to booleans. Do that conversion explicitly."
150 IfBranches ->
170 IfBranches ->
151− ( Nothing
172+ Nothing
152− , "The branches of this `if` result in different types of values."
173+ ( "The branches of this `if` result in different types of values."
175+ ( "The `then` branch results in:\n"
179+ ++ "And the `else` branch results in:\n"
153− , Just "All branches should match so that no matter which one we take, we always get\nback the same type of value."
183+ ++ "These need to match so that no matter which one we take, we always get\n"
184+ ++ "back the same type of value."
156 MultiIfBranch branchNumber region ->
187 MultiIfBranch branchNumber region ->
157− ( Just region
189+ (Just region)
158− , "The " ++ ordinalize branchNumber ++ " branch of this `if` results in an unexpected type of value."
190+ ( "The " ++ ordinalize branchNumber ++ " branch of this `if` results in an unexpected type of value."
192+ ( "The " ++ ordinalize (branchNumber - 1) ++ " branch results in:\n"
196+ ++ "And the "++ ordinalize branchNumber ++ " branch results in:\n"
159− , Just "All branches should match so that no matter which one we take, we always get\nback the same type of value."
200+ ++ "All branches should match so that no matter which one we take, we always get\n"
201+ ++ "back the same type of value."
163− ( Nothing
206+ Nothing
164− , "All the branches of this if-expression are consistent, but the overall\n"
207+ ( "All the branches of this if-expression are consistent, but the overall\n"
165− ++ "type does not match how it is used elsewhere."
208+ ++ "type does not match how it is used elsewhere."
210+ ( "The `if` evaluates to something of type:\n"
214+ ++ "Which is fine, but the surrounding context wants it to be:\n"
169 ListElement elementNumber region ->
220 ListElement elementNumber region ->
170− ( Just region
222+ (Just region)
171− , "The " ++ ordinalize elementNumber ++ " element of this list is an unexpected type of value."
223+ ( "The " ++ ordinalize elementNumber ++ " element of this list is an unexpected type of value."
172− , Just "All elements should be the same type of value so that we can iterate over the\nlist without running into unexpected values."
225+ ( "All elements should be the same type of value so that we can iterate over the\nlist without running into unexpected values."
176− ( Nothing
230+ Nothing
177− , "All the elements in this list are the same type, but the overall\n"
231+ ( "All the elements in this list are the same type, but the overall\n"
178− ++ "type does not match how it is used elsewhere."
232+ ++ "type does not match how it is used elsewhere."
234+ ( "The list has type:\n"
238+ ++ "Which is fine, but the surrounding context wants it to be:\n"
182 BinopLeft op region ->
243 BinopLeft op region ->
183− ( Just region
245+ (Just region)
184− , "The left argument of " ++ prettyOperator op ++ " is causing a type mismatch."
246+ ("The left argument of " ++ prettyOperator op ++ " is causing a type mismatch.")
185− , Nothing
247+ ( prettyOperator op ++ " is expecting:"
251+ ++ "But the value on the left has this type:"
188 BinopRight op region ->
256 BinopRight op region ->
189− ( Just region
258+ (Just region)
190− , "The right argument of " ++ prettyOperator op ++ " is causing a type mismatch."
259+ ( "The right argument of " ++ prettyOperator op ++ " is causing a type mismatch."
261+ ( prettyOperator op ++ " is expecting:"
265+ ++ "But the value on the right has this type:"
194 Binop op ->
270 Binop op ->
195− ( Nothing
272+ Nothing
196− , "The two arguments to " ++ prettyOperator op ++ " are fine, but the overall type of this expression\n"
273+ ( "The two arguments to " ++ prettyOperator op ++ " are fine, but the overall type of this expression\n"
197− ++ "does not match how it is used elsewhere."
274+ ++ "does not match how it is used elsewhere."
276+ ( "The result of this binary operation is:\n"
280+ ++ "Which is fine, but the surrounding context wants it to be:\n"
201 Function maybeName ->
286 Function maybeName ->
202− ( Nothing
288+ Nothing
203− , "The return type of " ++ funcName maybeName ++ " is being used in unexpected ways."
289+ ( "The return type of " ++ funcName maybeName ++ " is being used in unexpected ways."
291+ ( "The function results in a value with type:\n"
295+ ++ "Which is fine, but the surrounding context wants it to be:\n"
207 UnexpectedArg maybeName index region ->
300 UnexpectedArg maybeName index region ->
208− ( Just region
302+ (Just region)
209− , "The " ++ ordinalize index ++ " argument to " ++ funcName maybeName
303+ ( "The " ++ ordinalize index ++ " argument to " ++ funcName maybeName
210− ++ " has an unexpected type."
304+ ++ " is causing a mismatch."
306+ ( "The " ++ ordinalize index ++ " to " ++ funcName maybeName ++ " should be:"
314+ ++ maybe "" reasonToString maybeReason
214 FunctionArity maybeName expected actual region ->
317 FunctionArity maybeName expected actual region ->
216 s = if expected <= 1 then "" else "s"
319 s = if expected <= 1 then "" else "s"
218− ( Just region
322+ (Just region)
219− , capitalize (funcName maybeName) ++ " is expecting " ++ show expected
323+ ( capitalize (funcName maybeName) ++ " is expecting " ++ show expected
220− ++ " argument" ++ s ++ ", but was given " ++ show actual ++ "."
324+ ++ " argument" ++ s ++ ", but was given " ++ show actual ++ "."
326+ ( error "TODO are the types interesting here?"
224 BadTypeAnnotation name ->
329 BadTypeAnnotation name ->
225− ( Nothing
331+ Nothing
226− , "The type annotation for `" ++ name ++ "` does not match its definition."
332+ ( "The type annotation for `" ++ name ++ "` does not match its definition."
334+ ( "Based on the actual definition, the type should be:\n"
230 Instance name ->
339 Instance name ->
231− ( Nothing
341+ Nothing
232− , "Given how `" ++ name ++ "` is defined, this use will not work out."
342+ ( "This usage of `" ++ name ++ "` is causing a type mismatch."
344+ ( "Based on its definition, `" ++ name ++ "` has this type:"
348+ ++ "But you are trying to use it as:"
236 Literal name ->
353 Literal name ->
237− ( Nothing
355+ Nothing
238− , "This " ++ name ++ " value is being used as if it is some other type of value."
356+ ( "This " ++ name ++ " value is being used as if it is some other type of value."
358+ ( "You are trying to use this " ++ name ++ " as this type:"
242 Pattern patErr ->
363 Pattern patErr ->
@@ -248,41 +369,129 @@ hintToString hint =
248 PData name -> "`" ++ name ++ "`"
369 PData name -> "`" ++ name ++ "`"
249 PRecord -> "a record"
370 PRecord -> "a record"
251− ( Nothing
373+ Nothing
252− , "Problem with " ++ thing ++ " in this pattern match."
374+ ( "Problem with " ++ thing ++ " in this pattern match."
376+ ( "This pattern matches things of type:"
380+ ++ "But the values it will actually be trying to match are:"
256 Shader ->
385 Shader ->
257− ( Nothing
387+ Nothing
258− , "There is some problem with this GLSL shader."
388+ ( "There is some problem with this GLSL shader."
390+ ( error "TODO generic error"
263− ( Nothing
395+ Nothing
264− , "The low and high members of this list range are not the same type of value."
396+ ( "The low and high members of this list range are not the same type of value."
398+ ( "The low end of the range has type:"
402+ ++ "But the high end is:"
268 Lambda ->
407 Lambda ->
269− ( Nothing
409+ Nothing
270− , "This anonymous function is being used in an unexpected way."
410+ ( "This anonymous function is being used in an unexpected way."
412+ ( "The anonymous function has type:"
416+ ++ "But you are trying to use it as:"
274 Record ->
421 Record ->
275− ( Nothing
423+ Nothing
276− , "This record is being used in an unexpected way."
424+ ( "This record is being used in an unexpected way."
278− )
426+ ( "The record has type:"
430+ ++ "But you are trying to use it as:"
436+reasonToString :: Reason -> String
437+reasonToString reason =
439+ MessyFields expecteds [] ->
440+ genericMissingFieldsMessage "former" expecteds
442+ MessyFields [] actuals ->
443+ genericMissingFieldsMessage "latter" actuals
445+ MessyFields expecteds actuals ->
446+ case concatMap (similarNames actuals) expecteds of
448+ "These records look pretty different."
451+ "Looks like a misspelling between field " ++ exp ++ " and " ++ act ++ "."
454+ "There are some potential typos in the record field names.\n"
455+ ++ concatMap (\(exp,act) -> "\n " ++ exp ++ " <=> " ++ act) potentialTypos
458+ "A record cannot be merged with other types of values."
460+ TooLongComparableTuple len ->
467+similarNames :: [String] -> String -> [(String,String)]
468+similarNames otherKeys key =
469+ map ((,) key) (filter (\key' -> Help.distance key key' == 1) otherKeys)
473+genericMissingFieldsMessage :: String -> [String] -> String
474+genericMissingFieldsMessage latterOrFormer fields =
475+ "A record in the " ++ latterOrFormer ++ " type is missing "
479+ "field `" ++ key ++ "`"
482+ "fields " ++ key1 ++ " and " ++ key2
485+ "fields " ++ List.intercalate ", " (init keys) ++ ", and " ++ last keys
281prettyOperator :: Var.Canonical -> String
488prettyOperator :: Var.Canonical -> String
282prettyOperator (Var.Canonical _ opName) =
489prettyOperator (Var.Canonical _ opName) =
283− if Help.isOp opName
490+ if AstHelp.isOp opName then
284− then "(" ++ opName ++ ")"
491+ "(" ++ opName ++ ")"
285− else "`" ++ opName ++ "`"
494+ "`" ++ opName ++ "`"
288funcName :: Maybe Var.Canonical -> String
497funcName :: Maybe Var.Canonical -> String