@@ -2,35 +2,25 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Type
3module Reporting.Error.Type
4 ( Error(..)
4 ( Error(..)
5− , Mismatch(..)
5+ , Origin(..)
10− , PatternCategory(..)
11 , toReport
6 , toReport
16−import Control.Arrow (second)
10+
17−import qualified Data.Map as Map
11+import Prelude hiding (round)
18−import qualified Data.Text as Text
19−import Data.Text (Text)
20import Data.Monoid ((<>))
12import Data.Monoid ((<>))
22−import qualified AST.Module.Name as ModuleName
14+import qualified AST.Canonical as Can
23−import qualified AST.Type as Type
15+import qualified AST.Utils.Type as Type
24−import qualified AST.Variable as Var
16+import qualified Data.Index as Index
25import qualified Elm.Name as N
17import qualified Elm.Name as N
18+import qualified Reporting.Helpers as H
26import qualified Reporting.Region as R
19import qualified Reporting.Region as R
27−import qualified Reporting.Render.Type as RenderType
20+import qualified Reporting.Render.Code as Code
21+import qualified Reporting.Render.Type as Type
28import qualified Reporting.Report as Report
22import qualified Reporting.Report as Report
29−import qualified Reporting.Helpers as Help
23+import qualified Type.Constraint as C
30−import Reporting.Helpers
31− ( Doc, capitalize, dullyellow, functionName, i2t
32− , indent, ordinalize, reflowParagraph, stack, text
@@ -38,1138 +28,981 @@ import Reporting.Helpers
41− = Mismatch Mismatch
31+ = Mismatch Origin (C.Expected Can.Type)
42− | BadMain Type.Canonical
32+ | BadPattern R.Region C.PCategory Can.Type (C.PExpected Can.Type)
43− | BadFlags Type.Canonical (Maybe Text)
44− | InfiniteType (Either Hint Text) Type.Canonical
33+ | InfiniteType Can.Type
50− , _leftType :: Type.Canonical
51− , _rightType :: Type.Canonical
53− , _reason :: Maybe Reason
57−data Reason
36+data Origin
58− = BadFields [(Text, Maybe Reason)]
37+ = BadExpr R.Region C.Category Can.Type
59− | MessyFields [Text] [Text] [Text]
38+ | BadLocal R.Region N.Name Can.Type
60− | IntFloat
39+ | BadForeign R.Region N.Name Can.Type
62− | RigidClash Text Text
63− | NotPartOfSuper Type.Super
64− | RigidVarTooGeneric Text SpecificThing
65− | RigidSuperTooGeneric Type.Super Text SpecificThing
69− = SpecificSuper Type.Super
70− | SpecificType N.Name
78− = CaseBranch Int R.Region
82− | MultiIfBranch Int R.Region
85− | ListElement Int R.Region
86− | BinopLeft ModuleName.Canonical N.Name R.Region
87− | BinopRight ModuleName.Canonical N.Name R.Region
88− | Binop ModuleName.Canonical N.Name
89− | Function (Maybe Var.Canonical)
90− | UnexpectedArg (Maybe Var.Canonical) Int Int R.Region
91− | FunctionArity (Maybe Var.Canonical) Int Int R.Region
92− | ReturnType Text Int Int R.Region
95− | Pattern PatternContext PatternCategory
100− | Access (Maybe Text) Text
104− -- effect manager problems
111− = PatternArg N.Name Int
126-- TO REPORT
43-- TO REPORT
129−toReport :: RenderType.Localizer -> Error -> Report.Report
46+toReport :: Code.Source -> Type.Localizer -> Error -> Report.Report
130−toReport localizer err =
47+toReport source localizer err =
131 case err of
48 case err of
132− Mismatch info ->
49+ Mismatch origin expected ->
133− mismatchToReport localizer info
50+ case origin of
134−
51+ BadForeign region name tipe ->
135− InfiniteType context overallType ->
52+ toMismatchReport source localizer region (Var name) tipe expected
136− infiniteTypeToReport localizer context overallType
142− "The `main` value has an unsupported type."
145− "I need Html, Svg, or a Program so I have something to render on\
146− \ screen, but you gave me:"
147− , indent 4 (RenderType.toDoc localizer tipe)
151− BadFlags tipe maybeMessage ->
54+ BadLocal region name tipe ->
152− let
55+ toMismatchReport source localizer region (Var name) tipe expected
154− maybe "" (" the following " <> ) maybeMessage
159− ("Your `main` is demanding an unsupported type as a flag."
162− [ text ("The specific unsupported type is" <> context <> ":")
163− , indent 4 (RenderType.toDoc localizer tipe)
164− , text "The types of values that can flow through in and out of Elm include:"
165− , indent 4 $ reflowParagraph $
166− "Ints, Floats, Bools, Strings, Maybes, Lists, Arrays,\
167− \ Tuples, Json.Values, and concrete records."
57+ BadExpr region category tipe ->
58+ toMismatchReport source localizer region (Category category) tipe expected
60+ BadPattern region category tipe expected ->
61+ error "TODO" region category tipe expected
173−-- TYPE MISMATCHES
63+ InfiniteType overallType ->
64+ error "TODO" source localizer overallType
176−mismatchToReport :: RenderType.Localizer -> Mismatch -> Report.Report
177−mismatchToReport localizer (MismatchInfo hint leftType rightType decoders maybeReason) =
180− Report.report "TYPE MISMATCH"
182− typicalHints =
68+-- HELPERS
183− maybe id (:) (reasonToDoc <$> maybeReason) $
184− if decoders then [ jsonDecoderHint ] else []
186− cmpHint leftWords rightWords extraHints =
187− comparisonHint localizer leftType rightType leftWords rightWords
188− (typicalHints <> map Help.toSimpleHint extraHints)
191− CaseBranch branchNumber region ->
194− ( "The " <> ordinalPair branchNumber
195− <> " branches of this `case` produce different types of values."
198− ("The " <> ordinalize (branchNumber - 1) <> " branch has this type:")
199− ("But the " <> ordinalize branchNumber <> " is:")
200− [ "All branches in a `case` must have the same type. So no matter\
201− \ which one we take, we always get back the same type of value."
205− Case ->
71+data Thing
206− report
72+ = Var N.Name
207− Nothing
73+ | Category C.Category
208− ( "All the branches of this case-expression are consistent, but the overall\n"
209− <> "type does not match how it is used elsewhere."
212− "The `case` evaluates to something of type:"
213− "Which is fine, but the surrounding context wants it to be:"
220− "This condition does not evaluate to a boolean value, True or False."
222− "You have given me a condition with this type:"
223− "But I need it to be:"
224− [ "Elm does not have \"truthiness\" such that ints and strings and lists\
225− \ are automatically converted to booleans. Do that conversion explicitly."
229− IfBranches ->
76+typeComparison :: Type.Localizer -> Can.Type -> Can.Type -> ( String, String, [H.Doc] ) -> H.Doc
230− report
77+typeComparison localizer actual expected ( iAmSeeing, insteadOf, soHereAreSomeThoughts ) =
231− Nothing
78+ H.stack $
232− "The branches of this `if` produce different types of values."
79+ [ H.reflow iAmSeeing
233− ( cmpHint
80+ , H.indent 4 (Type.toDoc localizer actual)
234− "The `then` branch has type:"
81+ , H.reflow insteadOf
235− "But the `else` branch is:"
82+ , H.indent 4 (Type.toDoc localizer expected)
236− [ "These need to match so that no matter which branch we take, we\
83+ ]
237− \ always get back the same type of value."
84+ ++ soHereAreSomeThoughts
240−
87+toDescription :: Thing -> String -> String
241− MultiIfBranch branchNumber region ->
88+toDescription thing thatThingIs =
242− report
89+ case thing of
243− (Just region)
90+ Var name ->
244− ( "The " <> ordinalPair branchNumber
91+ "This `" <> N.toString name <> "` value has type:"
245− <> " branches of this `if` produce different types of values."
92+
246− )
93+ Category category ->
247− ( cmpHint
94+ case category of
248− ("The " <> ordinalize (branchNumber - 1) <> " branch has this type:")
95+ C.List -> thatThingIs <> " a list of type:"
249− ("But the "<> ordinalize branchNumber <> " is:")
96+ C.Number -> thatThingIs <> " a number of type:"
250− [ "All the branches of an `if` need to match so that no matter which\
97+ C.Float -> thatThingIs <> " a float of type:"
251− \ one we take, we get back the same type of value overall."
98+ C.String -> thatThingIs <> " a string of type:"
99+ C.Char -> thatThingIs <> " a character of type:"
100+ C.If -> "This `if` expression produces a value of type:"
101+ C.Case -> "This `case` expression produces a value of type:"
102+ C.Lambda -> thatThingIs <> " an anonymous function of type:"
103+ C.Accessor field -> "This ." <> N.toString field <> " field access function has type of type:"
104+ C.Access field -> "The value at ." <> N.toString field <> " has type of type:"
105+ C.Record -> thatThingIs <> " a record of type:"
106+ C.Tuple -> thatThingIs <> " a tuple of type:"
107+ C.Unit -> thatThingIs <> " a unit value:"
108+ C.Shader -> thatThingIs <> " a GLSL shader of type:"
109+ C.Effects -> thatThingIs <> " a thing for CORE LIBRARIES ONLY."
110+ C.CallResult maybeName ->
112+ C.NoName -> thatThingIs <> ":"
113+ C.FuncName name -> "This `" <> N.toString name <> "` call produces:"
114+ C.CtorName name -> "This `" <> N.toString name <> "` call produces:"
115+ C.OpName _ -> thatThingIs <> ":"
119+-- TO MISMATCH REPORT
122+toMismatchReport :: Code.Source -> Type.Localizer -> R.Region -> Thing -> Can.Type -> C.Expected Can.Type -> Report.Report
123+toMismatchReport source localizer exprRegion thing tipe expected =
124+ Report.Report "TYPE MISMATCH" exprRegion [] $
126+ C.NoExpectation expectedType ->
127+ Report.toCodeSnippet source exprRegion Nothing
129+ "This expression is being used in an unexpected way:"
131+ typeComparison localizer tipe expectedType
133+ toDescription thing "It is"
135+ "But you are trying to use it as:"
258− "All the branches of this `if` are consistent, but the overall\
259− \ type does not match how it is used elsewhere."
261− "The `if` evaluates to something of type:"
262− "Which is fine, but the surrounding context wants it to be:"
266− ListElement elementNumber region ->
143+ C.FromAnnotation name arity subContext expectedType ->
267− report
144+ Report.toCodeSnippet source exprRegion Nothing
269− ("The " <> ordinalPair elementNumber <> " entries in this list are different types of values.")
146+ H.reflow $
270− ( cmpHint
147+ case subContext of
271− ("The " <> ordinalize (elementNumber - 1) <> " entry has this type:")
148+ C.TypedIfBranch index ->
272− ("But the "<> ordinalize elementNumber <> " is:")
149+ "Something is off with the " <> H.ordinalize (Index.toHuman index) <> " branch of this `if` experssion:"
273− [ "Every entry in a list needs to be the same type of value.\
150+
274− \ This way you never run into unexpected values partway through.\
151+ C.TypedCaseBranch index ->
275− \ To mix different types in a single list, create a \"union type\" as\
152+ "Something is off with the " <> H.ordinalize (Index.toHuman index) <> " branch of this `case` expression:"
276− \ described in: <http://guide.elm-lang.org/types/union_types.html>"
153+
155+ "Something is off with the body of the `" <> N.toString name <> "` definition:"
157+ typeComparison localizer tipe expectedType
159+ toDescription thing $
161+ C.TypedIfBranch index ->
162+ "The " <> H.ordinalize (Index.toHuman index) <> " branch is"
164+ C.TypedCaseBranch index ->
165+ "The " <> H.ordinalize (Index.toHuman index) <> " branch is"
170+ "But the type annotation on `" <> N.toString name <> "` says it should be:"
172+ [ error "TODO check for arity issues. Suggest that an arg is unlisted." arity
283− ( "All the elements in this list are the same type, but the overall\
284− \ type does not match how it is used elsewhere."
287− "The list has type:"
288− "Which is fine, but the surrounding context wants it to be:"
292− BinopLeft home op region ->
295− ("The left argument of (" <> op <> ") is causing a type mismatch.")
297− ("(" <> op <> ") is expecting the left argument to be a:")
298− "But the left argument is:"
299− (binopHint home op leftType rightType)
302− BinopRight home op region ->
305− ("The right side of (" <> op <> ") is causing a type mismatch.")
307− ("(" <> op <> ") is expecting the right side to be a:")
308− "But the right side is:"
309− ( binopHint home op leftType rightType
311− [ "With operators like (" <> op <> ") I always check the left\
312− \ side first. If it seems fine, I assume it is correct and check the right\
313− \ side. So the problem may be in how the left and right arguments interact."
321− ( "The two arguments to (" <> op <>
322− ") are fine, but the overall type of this expression\
323− \ does not match how it is used elsewhere."
326− "The result of this binary operation is:"
327− "Which is fine, but the surrounding context wants it to be:"
331− Function maybeName ->
334− ( "The return type of " <> maybeFuncName maybeName <> " is being used in unexpected ways."
337− "The function results in this type of value:"
338− "Which is fine, but the surrounding context wants it to be:"
342− UnexpectedArg maybeName 1 1 region ->
345− ("The argument to " <> maybeFuncName maybeName <> " is causing a mismatch.")
347− (capitalize (maybeFuncName maybeName) <> " is expecting the argument to be:")
352− UnexpectedArg maybeName index _totalArgs region ->
178+ C.FromContext region context expectedType ->
353− report
179+ case context of
354− (Just region)
180+ C.ListEntry index ->
355− ( "The " <> ordinalize index <> " argument to " <> maybeFuncName maybeName
356− <> " is causing a mismatch."
359− ( capitalize (maybeFuncName maybeName) <> " is expecting the "
360− <> ordinalize index <> " argument to be:"
363− ( if index == 1 then
181+ if Index.toHuman index == 2 then
364− []
182+ error "TODO 1st vs 2nd list entry"
366− [ "I always figure out the type of arguments from left to right. If an argument\
184+ Report.toCodeSnippet source region (Just exprRegion)
367− \ is acceptable when I check it, I assume it is \"correct\" in subsequent checks.\
185+ (
368− \ So the problem may actually be in how previous arguments interact with the "
186+ H.reflow $
369− <> ordinalize index <> "."
187+ "The " <> H.ordinalize (Index.toHuman index) <> " element of this list does not match all the previous elements:"
189+ typeComparison localizer tipe expectedType
191+ toDescription thing $
192+ "The " <> H.ordinalize (Index.toHuman index) <> " element is"
194+ "But all the previous elements in the list are:"
197+ "Everything in the list needs to be the same type of value.\
198+ \ This way you never run into unexpected values partway through.\
199+ \ To mix different types in a single list, create a \"union type\" as\
200+ \ described in: <http://guide.elm-lang.org/types/union_types.html>"
374− FunctionArity maybeName 0 actual region ->
206+ C.Negate ->
375− let
207+ Report.toCodeSnippet source region (Just exprRegion)
377− if actual == 1 then "an argument" else i2t actual <> " arguments"
209+ "I do not know how to negate this type of value:"
379− preHint =
211+ H.stack
380− case maybeName of
212+ [ H.reflow $ toDescription thing "It is"
381− Nothing ->
213+ , Type.toDoc localizer tipe
382− "You are giving " <> args <> " to something that is not a function!"
214+ , H.fillSep
383−
215+ ["But","I","only","now","how","to","negate"
384− Just name ->
216+ ,H.dullyellow "Int","and",H.dullyellow "Float","values."
385− varName name <> " is not a function, but you are giving it " <> args <> "!"
217+ ]
390− (text "Maybe you forgot some parentheses? Or a comma?")
222+ C.OpLeft op ->
391−
223+ Report.toCodeSnippet source region (Just exprRegion) $
392− FunctionArity maybeName expected actual region ->
224+ opLeftToDocs localizer thing op tipe expectedType
394− (Just region)
226+ C.OpRight op ->
395− ( capitalize (maybeFuncName maybeName) <> " is expecting "
227+ Report.toCodeSnippet source region (Just exprRegion) $
396− <> Help.args expected <> ", but was given " <> i2t actual <> "."
228+ opRightToDocs localizer thing op tipe expectedType
398− (text "Maybe you forgot some parentheses? Or a comma?")
230+ C.IfCondition ->
399−
231+ Report.toCodeSnippet source region (Just exprRegion)
400− ReturnType name typeArity argArity region ->
232+ (
401− if typeArity == 0 || argArity == 0 then
233+ "This `if` condition does not evaluate to a boolean value, True or False."
403− (Just region)
235+ H.stack
404− ("The definition of " <> functionName name <> " does not match its type annotation.")
236+ [ H.reflow $ toDescription thing "It is"
405− ( cmpHint
237+ , Type.toDoc localizer tipe
406− ( "The type annotation for " <> functionName name <> " says it is a:"
238+ , H.fillSep ["But","I","need","this","`if`","condition","to","be","a",H.dullyellow "Bool","value."]
240+ "Elm does not have “truthiness” such that ints and strings and lists\
241+ \ are automatically converted to booleans. Do that conversion explicitly!"
246+ if Index.toHuman index == 2 then
247+ error "TODO 1st vs 2nd if branches"
248+ -- error "TODO if with no chaining"
250+ Report.toCodeSnippet source region (Just exprRegion)
253+ "The " <> H.ordinalize (Index.toHuman index) <> " branch of this `if` does not match all the previous branches:"
255+ typeComparison localizer tipe expectedType
257+ toDescription thing $
258+ "The " <> H.ordinalize (Index.toHuman index) <> " branch is"
260+ "But all the previous branches result in:"
263+ "All branches in an `if` must produce the same type of values. This way, no\
264+ \ matter which branch we take, the result is always a consistent shape. Read"
266+ "to learn how to “mix” types."
408− "But the definition (shown above) is a:"
409− (arityHint typeArity argArity)
272+ C.CaseBranch index ->
273+ if Index.toHuman index == 2 then
274+ error "TODO 1st vs 2nd case branches"
413− report
276+ Report.toCodeSnippet source region (Just exprRegion)
415− ("The definition of " <> functionName name <> " does not match its type annotation.")
278+ H.reflow $
416− ( cmpHint
279+ "The " <> H.ordinalize (Index.toHuman index) <> " branch of this `case` does not match all the previous branches:"
417− ( "The type annotation for " <> functionName name <> " says it always returns:"
280+ ,
281+ typeComparison localizer tipe expectedType
283+ toDescription thing $
284+ "The " <> H.ordinalize (Index.toHuman index) <> " branch is"
286+ "But all the previous branches result in:"
289+ "All branches in a `case` must produce the same type of values. This way, no\
290+ \ matter which branch we take, the result is always a consistent shape. Read"
292+ "to learn how to “mix” types."
419− "But the returned value (shown above) is a:"
420− (arityHint typeArity argArity)
430− (name <> " is being used in an unexpected way.")
432− ("Based on its definition, " <> name <> " has this type:")
433− "But you are trying to use it as:"
440− ( "This " <> name <> " value is being used as if it is some other type of value."
443− ("The " <> name <> " definitely has this type:")
444− ("But it is being used as:")
448− Pattern context category ->
298+ C.CallArg maybeFuncName index ->
449− let (overview, lineOne, lineTwo) = toPatternMessage context category in
299+ let
450− report Nothing overview (cmpHint lineOne lineTwo [])
300+ thisFunction =
451−
301+ case maybeFuncName of
452− PatternCons ->
302+ C.NoName ->
453− report Nothing "This list pattern is mixing types:" $
303+ "this function"
455− "The head of the list matches this type of value:"
305+ C.FuncName name ->
456− "But the tail of the list matches:"
306+ "`" <> N.toString name <> "`"
458−
308+ C.CtorName name ->
459− Shader ->
309+ "`" <> N.toString name <> "`"
461− Nothing
311+ C.OpName op ->
462− "There is some problem with this GLSL shader."
312+ "(" <> N.toString op <> ")"
464− "The shader block has this type:"
314+ in
465− "Which is fine, but the surrounding context wants it to be:"
315+ Report.toCodeSnippet source region (Just exprRegion)
318+ "The " <> H.ordinalize (Index.toHuman index) <> " argument to " <> thisFunction <> " is not what I expect:"
320+ typeComparison localizer tipe expectedType
322+ toDescription thing "This argument is"
324+ "But " <> thisFunction <> " needs the " <> H.ordinalize (Index.toHuman index)
325+ <> " argument to be:"
327+ if Index.toHuman index == 1 then
331+ "I always figure out the argument types from left to right. If an argument\
332+ \ is acceptable, I assume it is “correct” and move on. So the problem may\
333+ \ actually be in one of the previous arguments!"
338+ C.TooManyArgs maybeName numGivenArgs ->
339+ case length (Type.delambda tipe) - 1 of
341+ Report.toCodeSnippet source region (Just exprRegion)
346+ "You are giving " <> H.args numGivenArgs <> " to something that is not a function!"
349+ "`" <> N.toString name <> "` is not a function, but you are giving it " <> H.args numGivenArgs <> "!"
352+ "`" <> N.toString name <> "` is not a function, but you are giving it " <> H.args numGivenArgs <> "!"
355+ "(" <> N.toString op <> ") is not a function, but you are giving it " <> H.args numGivenArgs <> "!"
357+ typeComparison localizer tipe expectedType
361+ "It is a value of type:"
364+ "`" <> N.toString name <> "` is a value of type:"
367+ "`" <> N.toString name <> "` is a constructor of type:"
370+ "(" <> N.toString op <> ") is a value of type:"
372+ "But you are giving it " <> H.args numGivenArgs <> " as if its type was:"
374+ [ "Maybe you forgot some parentheses? Or a comma?"
387+ "The `" <> N.toString name <> "` function"
390+ "The `" <> N.toString name <> "` constructor"
393+ "The (" <> N.toString op <> ") function"
395+ Report.toCodeSnippet source region (Just exprRegion)
398+ thisFunction <> " is getting too many arguments:"
400+ typeComparison localizer tipe expectedType
402+ thisFunction <> " is expecting to get " <> H.args numExpectedArgs <> " like this:"
404+ "But you are giving it " <> H.args numGivenArgs <> " as if its type was:"
406+ [ "Maybe you forgot some parentheses? Or a comma?"
408+ "I am not good at figuring out which arguments are extra myself. The\
409+ \ problem may even be that the FUNCTION is defined funny, and the arguments are\
410+ \ actually fine. Anyway, I hope I gave enough info to help you figure it out!"
470− report
415+ C.RecordAccess field ->
471− Nothing
416+ Report.toCodeSnippet source region (Just exprRegion) $
472− "This function is being used in an unexpected way."
417+ case Type.deepDealias tipe of
473− ( cmpHint
418+ Can.TRecord _ _ ->
474− "The function has type:"
419+ (
475− "But you are trying to use it as:"
420+ H.reflow $
421+ "This record does not have a `" <> N.toString field <> "` field:"
425+ "It is a record with this type:"
426+ , Type.toDoc localizer tipe
428+ "So maybe the ." <> N.toString field <> " field access is misspelled?"
431+ case error "TODO closeNames" of
437+ ["It","may","also","be","a","typo","in","the","record","itself."
438+ ,"Perhaps","the",H.dullyellow name,"field","is","misspelled?"
444+ ["It","may","also","be","a","typo","in","the","record","itself."
447+ ++ H.commaSep "or" H.dullyellow names
448+ ++ ["field","is","misspelled?"]
455+ "I cannot access field `" <> N.toString field <> "` of this " <> whatever <> ":"
459+ "The " <> whatever <> " is not a record! It is actually a function:"
460+ , Type.toDoc localizer tipe
461+ , H.toSimpleHint "Maybe it is missing some arguments?"
468+ "I cannot access field `" <> N.toString field <> "` of this " <> whatever <> ":"
472+ "The " <> whatever <> " is not a record though! It is a:"
473+ , Type.toDoc localizer tipe
478+ case Type.deepDealias tipe of
480+ Report.toCodeSnippet source region Nothing
483+ "I think there is a typo in one of these field names:"
485+ error "TODO record update field name typo"
489+ Report.toCodeSnippet source region (Just exprRegion)
491+ "The record update syntax does not work with this value:"
495+ "I can only update records, but this appears to be a " <> whatever <> ":"
496+ , Type.toDoc localizer tipe
501+ error "TODO Destructure"
508+opLeftToDocs :: Type.Localizer -> Thing -> N.Name -> Can.Type -> Can.Type -> (H.Doc, H.Doc)
509+opLeftToDocs localizer thing op tipe expectedType =
512+ | isString tipe -> badStringAdd
513+ | isList tipe -> badListAdd localizer "left" tipe
514+ | otherwise -> badMath localizer "Addition" "left" "+" tipe []
517+ | isList tipe -> badListMul localizer "left" tipe
518+ | otherwise -> badMath localizer "Multiplication" "left" "*" tipe []
520+ "-" -> badMath localizer "Subtraction" "left" "-" tipe []
521+ "^" -> badMath localizer "Exponentiation" "left" "^" tipe []
522+ "/" -> badFDiv localizer "left" tipe
523+ "//" -> badIDiv localizer "left" tipe
524+ "&&" -> badBool localizer "&&" "left" tipe
525+ "||" -> badBool localizer "||" "left" tipe
526+ "<" -> badCompArg localizer thing "<" "left" tipe
527+ ">" -> badCompArg localizer thing ">" "left" tipe
528+ "<=" -> badCompArg localizer thing "<=" "left" tipe
529+ ">=" -> badCompArg localizer thing ">=" "left" tipe
532+ ( "The left side of (<|) needs to be a function so I can pipe arguments to it!"
536+ "Instead of a function, I am seeing " <> whatever <> ":"
537+ , Type.toDoc localizer tipe
542+ "Maybe you gave " <> funcName <> " too many arguments already?"
479− Accessor field ->
550+ _ ->
480− report Nothing
551+ (
481− ("The ." <> field <> " accessor is being used in an unexpected way.")
552+ H.reflow $
482− ( cmpHint
553+ "The left argument of (" <> N.toString op <> ") is causing problems:"
483− "It has type:"
554+ ,
484− "But you are trying to use it as:"
555+ typeComparison localizer tipe expectedType
557+ toDescription thing "The left argument is"
559+ "But (" <> N.toString op <> ") needs the left argument to be:"
488− Access (Just body) field ->
490− header = "`" <> body <> "` does not have a field named `" <> field <> "`."
492− report Nothing header $ stack $
493− [ reflowParagraph $ "The type of `" <> body <> "` is:"
494− , indent 4 $ dullyellow $ RenderType.toDoc localizer leftType
495− , reflowParagraph $ "Which does not contain a field named `" <> field <> "`."
499− Access Nothing field ->
501− header = "Cannot access a field named `" <> field <> "`."
503− report Nothing header $ stack $
504− [ reflowParagraph $ "You are trying to get `" <> field <> "` from a value with this type:"
505− , indent 4 $ dullyellow $ RenderType.toDoc localizer leftType
506− , reflowParagraph $ "It is not in there!"
513− "This record is being used in an unexpected way."
515− "The record has type:"
516− "But you are trying to use it as:"
523− "This “unit” value is being used in an unexpected way."
526− "But you are trying to use it as:"
533− "This tuple is being used in an unexpected way."
535− "The tuple has type:"
536− "But you are trying to use it as:"
540− Manager name ->
567+-- OP RIGHT
543− ("The `" <> name <> "` in your effect manager has a weird type.")
570+opRightToDocs :: Type.Localizer -> Thing -> N.Name -> Can.Type -> Can.Type -> (H.Doc, H.Doc)
544− ( cmpHint
571+opRightToDocs localizer thing op tipe expectedType =
545− ("Your `" <> name <> "` function has this type:")
572+ case op of
546− "But it needs to have a type like this:"
573+ "+"
547− [ "You can read more about setting up effect managers properly here:\
574+ | isInt tipe -> badCast op FloatInt
548− \ <http://guide.elm-lang.org/effect_managers/>"
575+ | isFloat tipe -> badCast op IntFloat
576+ | isString tipe -> badStringAdd
577+ | isList tipe -> badListAdd localizer "right" tipe
578+ | otherwise -> badMath localizer "Addition" "right" "+" tipe []
581+ | isInt tipe -> badCast op FloatInt
582+ | isFloat tipe -> badCast op IntFloat
583+ | isList tipe -> badListMul localizer "right" tipe
584+ | otherwise -> badMath localizer "Multiplication" "right" "*" tipe []
587+ | isInt tipe -> badCast op FloatInt
588+ | isFloat tipe -> badCast op IntFloat
589+ | otherwise -> badMath localizer "Subtraction" "right" "-" tipe []
592+ | isInt tipe -> badCast op FloatInt
593+ | isFloat tipe -> badCast op IntFloat
594+ | otherwise -> badMath localizer "Exponentiation" "right" "^" tipe []
596+ "/" -> badFDiv localizer "right" tipe
597+ "//" -> badIDiv localizer "right" tipe
598+ "&&" -> badBool localizer "&&" "right" tipe
599+ "||" -> badBool localizer "||" "right" tipe
600+ "<" -> badCompRight localizer thing "<" tipe expectedType
601+ ">" -> badCompRight localizer thing ">" tipe expectedType
602+ "<=" -> badCompRight localizer thing "<=" tipe expectedType
603+ ">=" -> badCompRight localizer thing ">=" tipe expectedType
604+ "==" -> badEquality localizer "==" tipe expectedType
605+ "/=" -> badEquality localizer "/=" tipe expectedType
610+ "I cannot pipe this " <> whatever <> " in as the final argument:"
612+ typeComparison localizer tipe expectedType
614+ toDescription thing "You are providing"
616+ "But (<|) is piping it a function that expects:"
618+ [ "Maybe an argument is missing?"
552− State name ->
624+ "|>" ->
553− report
625+ case (tipe, expectedType) of
626+ (Can.TLambda expectedArgType _, Can.TLambda argType _) ->
628+ "I cannot pipe the argument through to this function:"
630+ typeComparison localizer argType expectedArgType
632+ "You are providing an argument of type:"
634+ "But (|>) is piping it a function that expects its next argument to be:"
554− Nothing
637+ Nothing ->
555− ( "Your effect manager creates a certain type of state with `init`, but your `"
638+ "But (|>) is piping it a function that expects the next argument to be:"
556− <> name <> "` function expects a different kind of state."
639+
557− )
640+ Just (C.FuncName name) ->
558− ( cmpHint
641+ "But (|>) is piping it to `" <> N.toString name <> "` which expects the next argument to be:"
559− "The state created by `init` has this type:"
642+
560− ("But `" <> name <> "` expects state of this type:")
643+ Just (C.OpName op) ->
561− [ "Make the two state types match and you should be all set! More info here:\
644+ "But (|>) is piping it to (" <> N.toString op <> ") which expects the next argument to be:"
562− \ <http://guide.elm-lang.org/effect_managers/>"
645+ -}
647+ [ "Maybe an argument is missing?"
655+ "The right side of (|>) needs to be a function so I can pipe arguments to it!"
659+ "Instead of a function, I am seeing " <> whatever <> ":"
660+ , Type.toDoc localizer tipe
665+ "Maybe you gave " <> funcName <> " too many arguments already?"
568− Nothing
675+ H.reflow $
569− "Effect managers can send messages to themselves, but `onEffects` and `onSelfMsg` are defined for different types of self messages."
676+ "The right argument of (" <> N.toString op <> ") is causing problems."
571− "The `onEffects` function can send this type of message:"
678+ typeComparison localizer tipe expectedType
572− "But the `onSelfMsg` function receives this type:"
679+ (
573− [ "Make the two message types match and you should be all set! More info here:\
680+ toDescription thing "The right argument is"
574− \ <http://guide.elm-lang.org/effect_managers/>"
681+ ,
682+ "But (" <> N.toString op <> ") needs the right argument to be:"
687+ , binopHint home op leftType rightType
695+isInt :: Can.Type -> Bool
697+ error "TODO isInt" tipe
583−toPatternMessage :: PatternContext -> PatternCategory -> (Text, Text, Text)
584−toPatternMessage context category =
586− PatternArg name index ->
587− toPatternHelp category $
588− "But as the " <> ordinalize index
589− <> " value of a `" <> name <> "` pattern, it must be:"
591− PatternTail ->
700+isFloat :: Can.Type -> Bool
592− toPatternHelp category $
701+isFloat tipe =
593− "But as the pattern after a (::), it must be a list like: "
702+ error "TODO isFloat" tipe
595− PatternList index ->
596− ( "The patterns in this list match different types of values:"
597− , "The " <> ordinalize index <> " pattern matches type:"
598− , "But all the previous patterns in the list match:"
601− PatternUnknown ->
705+isString :: Can.Type -> Bool
602− toPatternHelp category $
706+isString tipe =
603− "But the values flowing through here need to be:"
707+ error "TODO isString" tipe
606−toPatternHelp :: PatternCategory -> Text -> (Text, Text, Text)
710+isList :: Can.Type -> Bool
607−toPatternHelp category lineTwo =
711+isList tipe =
608− case category of
712+ error "TODO isList" tipe
610− ( "This record pattern will cause problems:"
611− , "It matches record values with this type:"
616− ( "This “unit” pattern will cause problems:"
617− , "It matches unit values with this type:"
621− PTuple ->
715+whatever :: String
622− ( "This tuple pattern will cause problems:"
716+whatever =
623− , "It matches tuples with this type:"
717+ error "TODO whatever"
628− ( "This list pattern will cause problems:"
629− , "It matches lists with this type:"
634− ( "This `" <> name <> "` value will cause problems:"
635− , "It matches `" <> name <> "` values with this type:"
641−-- COMPARISON HINT
724+data ThisThenThat = FloatInt | IntFloat
645− :: RenderType.Localizer
652−comparisonHint localizer leftType rightType leftWords rightWords finalHints =
654− (leftDoc, rightDoc) =
655− RenderType.diffToDocs localizer leftType rightType
658− [ reflowParagraph leftWords
660− , reflowParagraph rightWords
727+badCast :: N.Name -> ThisThenThat -> (H.Doc, H.Doc)
728+badCast op thisThenThat =
731+ "I need both sides of (" <> N.toString op <> ") to be the exact same type. Both Int or both Float."
734+ anInt = ["an", H.dullyellow "Int"]
735+ aFloat = ["a", H.dullyellow "Float"]
736+ toFloat = H.green "toFloat"
737+ round = H.green "round"
739+ case thisThenThat of
741+ badCastHelp aFloat anInt round toFloat
668−-- JSON DECODER HINT
743+ IntFloat ->
669−
744+ badCastHelp anInt aFloat toFloat round
671−jsonDecoderHint :: Doc
674− "New to JSON decoders? They are tough at first, so DEFINITELY learn more here: "
675− <> Help.hintLink "json-decoders"
748+badCastHelp :: [H.Doc] -> [H.Doc] -> H.Doc -> H.Doc -> H.Doc
749+badCastHelp anInt aFloat toFloat round =
754+ ++ ["on","the","left","and"]
756+ ++ ["on","the","right."]
758+ ["Use",toFloat,"on","the","left","(or",round,"on"
759+ ,"the","right)","to","make","both","sides","match!"
761+ , H.link "Note" "Read" "implicit-casts" "to learn why Elm does not implicitly convert Ints to Floats."
682−binopHint :: ModuleName.Canonical -> N.Name -> Type.Canonical -> Type.Canonical -> [Text]
683−binopHint home op leftType rightType =
685− leftString = show (RenderType.toDoc Map.empty leftType)
686− rightString = show (RenderType.toDoc Map.empty rightType)
688− if home == ModuleName.basics && op == "+" && elem "String" [leftString, rightString] then
689− [ "To append strings in Elm, you need to use the (++) operator, not (+).\
690− \ <http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#++>"
693− else if home == ModuleName.basics && op == "/" && elem "Int" [leftString, rightString] then
765+badStringAdd :: (H.Doc, H.Doc)
694− [ "The (/) operator is specifically for floating point division, and (//) is\
766+badStringAdd =
695− \ for integer division. You may need to do some conversions between ints and\
767+ (
696− \ floats to get both arguments matching the division operator you want."
768+ H.fillSep ["I","cannot","do","addition","with",H.dullyellow "String","values","like","this","one:"]
772+ ["The","(+)","operator","only","works","with",H.dullyellow "Int","and",H.dullyellow "Float","values."
775+ ["Switch","to","the",H.green "(++)","operator","to","append","strings!"
781+badListAdd :: Type.Localizer -> String -> Can.Type -> (H.Doc, H.Doc)
782+badListAdd localizer direction tipe =
784+ "I cannot do addition with lists:"
788+ "The " <> direction <> " side of (+) is " <> whatever <> ":"
789+ , Type.toDoc localizer tipe
791+ ["But","(+)","only","works","with",H.dullyellow "Int","and",H.dullyellow "Float","values."
794+ ["Switch","to","the",H.green "(++)","operator","to","append","lists!"
707−arityHint :: Int -> Int -> [Text]
708−arityHint typeArity argArity =
709− if typeArity == argArity then
712− else
800+badListMul :: Type.Localizer -> String -> Can.Type -> (H.Doc, H.Doc)
713− [ "The type annotation says there " <> sayArgs typeArity <>
801+badListMul localizer direction tipe =
714− ", but there " <> sayArgs argArity <>
802+ badMath localizer "Multiplication" direction "*" tipe
715− " named in the definition. It is best practice for each argument\
803+ [
716− \ in the type to correspond to a named argument in the definition,\
804+ H.toFancyHint
717− \ so try that first!"
805+ [ "Maybe", "you", "want"
806+ , H.green "List.repeat"
807+ , "to", "build","a","list","of","repeated","values?"
721−sayArgs :: Int -> Text
812+badMath :: Type.Localizer -> String -> String -> String -> Can.Type -> [H.Doc] -> (H.Doc, H.Doc)
722−sayArgs n =
813+badMath localizer operation direction op tipe otherHints =
725− "are NO arguments"
816+ operation ++ " does not work with this value:"
728− "is 1 argument"
819+ [ H.reflow $
729−
820+ "The " <> direction <> " side of (" <> op <> ") is a " <> whatever <> ":"
730− _ ->
821+ , Type.toDoc localizer tipe
731− "are " <> i2t n <> " arguments"
822+ , H.fillSep
732−
823+ ["But","(" <> H.text op <> ")","only","works","with"
733−
824+ ,H.dullyellow "Int","and",H.dullyellow "Float","values."
735−-- MISMATCH HELPERS
826+ , error "TODO check for missing arguments"
738−ordinalPair :: Int -> Text
829+ )
740− ordinalize (number - 1) <> " and " <> ordinalize number
743−varName :: Var.Canonical -> Text
744−varName (Var.Canonical _ opName) =
748−maybeFuncName :: Maybe Var.Canonical -> Text
749−maybeFuncName maybeVar =
755− "function " <> varName var
762−flipReason :: Reason -> Reason
766− BadFields (map (second (fmap flipReason)) fields)
768− MessyFields both left right ->
769− MessyFields both right left
780− NotPartOfSuper super ->
781− NotPartOfSuper super
783− RigidVarTooGeneric name specific ->
784− RigidVarTooGeneric name specific
786− RigidSuperTooGeneric super name specific ->
787− RigidSuperTooGeneric super name specific
790−reasonToDoc :: Reason -> Doc
792− case collectFields reason of
795− (firstLine, details) =
796− reasonToDocHelp reason
798− Help.vcat $ Help.toSimpleHint firstLine : map (indent 4) details
800− Just (fields, maybeDeepReason) ->
802− recordHint elaboration =
803− [ "Problem", "in", "the", dullyellow (text (Text.intercalate "." fields)) <> "field." ]
805− map text (Text.words elaboration)
807− case reasonToDocHelp <$> maybeDeepReason of
809− Help.toFancyHint (recordHint badFieldElaboration)
811− Just (firstLine, details) ->
812− Help.vcat $ Help.toFancyHint (recordHint firstLine) : map (indent 4) details
819−collectFields :: Reason -> Maybe ([Text], Maybe Reason)
820−collectFields reason =
822− BadFields [(field, maybeReason)] ->
823− Just (collectFieldsHelp [field] maybeReason)
829−collectFieldsHelp :: [Text] -> Maybe Reason -> ([Text], Maybe Reason)
830−collectFieldsHelp revFields maybeReason =
832− Just (BadFields [(field, deeperReason)]) ->
833− collectFieldsHelp (field : revFields) deeperReason
836− ( reverse revFields, maybeReason )
839−reasonToDocHelp :: Reason -> (Text, [Doc])
840−reasonToDocHelp reason =
848− "I am seeing issues with the "
849− <> Help.commaSep (map fst fields) <> " fields. "
850− <> badFieldElaboration
852− MessyFields both leftOnly rightOnly ->
853− messyFieldsHelp both leftOnly rightOnly
857− "Elm does not automatically convert between Ints and Floats. Use\
858− \ `toFloat` and `round` to do specific conversions.\
859− \ <http://package.elm-lang.org/packages/elm-lang/core/latest/Basics#toFloat>"
863− "It looks like a function needs " <> Help.moreArgs num <> "."
865− RigidClash name1 name2 ->
867− "Your type annotation uses `" <> name1 <> "` and `" <> name2 <>
868− "` as DIFFERENT type variables. By using separate names, you are\
869− \ claiming the values can be different, but the code suggests that\
870− \ they must be the SAME based on how they are used. Maybe these two\
871− \ type variables in your type annotation should just be one? Maybe\
872− \ your code uses them in a weird way? More help at: "
873− <> Help.hintLink "type-annotations"
875− NotPartOfSuper Type.Number ->
876− simpleDoc "Only ints and floats are numbers."
878− NotPartOfSuper Type.Comparable ->
879− simpleDoc "Only ints, floats, chars, strings, lists, and tuples are comparable."
881− NotPartOfSuper Type.Appendable ->
882− simpleDoc "Only strings and lists are appendable."
884− NotPartOfSuper Type.CompAppend ->
885− simpleDoc "Only strings and lists are both comparable and appendable."
887− RigidVarTooGeneric name specific ->
888− simpleDoc $ rigidTooGenericHelp "ANY type of value" name specific
890− RigidSuperTooGeneric Type.Number name specific ->
891− simpleDoc $ rigidTooGenericHelp "BOTH Ints and Floats" name specific
893− RigidSuperTooGeneric Type.Comparable name specific ->
894− simpleDoc $ rigidTooGenericHelp "ANY comparable value" name specific
896− RigidSuperTooGeneric Type.Appendable name specific ->
897− simpleDoc $ rigidTooGenericHelp "BOTH Strings and Lists" name specific
899− RigidSuperTooGeneric Type.CompAppend name specific ->
900− simpleDoc $ rigidTooGenericHelp "Strings and ANY comparable List" name specific
903−rigidTooGenericHelp :: Text -> Text -> SpecificThing -> Text
904−rigidTooGenericHelp manyTypesOfValues name specific =
905− "The type variable `" <> name <> "` in your type annotation suggests that"
906− <> manyTypesOfValues <> " can flow through, but the code suggests that it must be "
907− <> specificThingToText specific <> " based on how it is used. Maybe make your\
908− \ type annotation more specific? Maybe the code has a problem? More help at: "
909− <> Help.hintLink "type-annotations"
912−specificThingToText :: SpecificThing -> Text
913−specificThingToText specific =
915− SpecificSuper Type.Number ->
918− SpecificSuper Type.Comparable ->
921− SpecificSuper Type.Appendable ->
924− SpecificSuper Type.CompAppend ->
925− "comparable AND appendable"
927− SpecificType name ->
928− if Text.isInfixOf (Text.take 1 name) "AEIOU" then
832+badFDiv :: Type.Localizer -> H.Doc -> Can.Type -> (H.Doc, H.Doc)
833+badFDiv localizer direction tipe =
836+ "The (/) operator is specifically for floating-point division:"
841+ ["The",direction,"side","of","(/)","must","be","a"
842+ ,H.dullyellow "Float" <> ","
843+ ,"but","I","am","seeing","an",H.dullyellow "Int" <> "."
847+ [ H.green "toFloat" <> " for explicit conversions " <> H.black "(toFloat 5 / 2) == 2.5"
848+ , H.green "(//) " <> " for integer division " <> H.black "(5 // 2) == 2"
850+ , H.link "Note" "Read" "implicit-casts" "to learn why Elm does not implicitly convert Ints to Floats."
932− "a " <> name
854+ H.stack
856+ ["The",direction,"side","of","(/)","must","be","a"
857+ ,H.dullyellow "Float" <> ","
858+ ,"but","instead","I","am","seeing:"
860+ , Type.toDoc localizer tipe
937− SpecificFunction ->
865+badIDiv :: Type.Localizer -> H.Doc -> Can.Type -> (H.Doc, H.Doc)
938− "a function"
866+badIDiv localizer direction tipe =
869+ "The (//) operator is specifically for integer division:"
871+ if isFloat tipe then
874+ ["The",direction,"side","of","(//)","must","be","an"
875+ ,H.dullyellow "Int" <> ","
876+ ,"but","I","am","seeing","a",H.dullyellow "Float" <> "."
877+ ,"I","recommend","doing","the","conversion","explicitly"
878+ ,"with","one","of","these","functions:"
881+ [ H.green "round" <> " 3.5 == 4"
882+ , H.green "floor" <> " 3.5 == 3"
883+ , H.green "ceiling" <> " 3.5 == 4"
884+ , H.green "truncate" <> " 3.5 == 3"
886+ , H.link "Note" "Read" "implicit-casts" "to learn why Elm does not implicitly convert Ints to Floats."
891+ ["The",direction,"side","of","(//)","must","be","an"
892+ ,H.dullyellow "Int" <> ","
893+ ,"but","instead","I","am","seeing:"
895+ , Type.toDoc localizer tipe
947−badFieldElaboration :: Text
948−badFieldElaboration =
949− "I always figure out field types in alphabetical order. If a field\
950− \ seems fine, I assume it is “correct” in subsequent checks.\
951− \ So the problem may actually be a weird interaction with previous fields."
904+badBool :: Type.Localizer -> H.Doc -> H.Doc -> Can.Type -> (H.Doc, H.Doc)
905+badBool localizer op direction tipe =
908+ "I am struggling with this boolean operation:"
912+ ["Both","sides","of","(" <> op <> ")","must","be"
913+ ,H.dullyellow "Bool","values,","but","the",direction,"side","is:"
915+ , Type.toDoc localizer tipe
917+ "Elm does not have “truthiness” such that ints and strings and lists are\
918+ \ automatically converted to booleans. Do that conversion explicitly!"
954−messyFieldsHelp :: [Text] -> [Text] -> [Text] -> (Text, [Doc])
955−messyFieldsHelp both leftOnly rightOnly =
956− error "TODO messyFieldsHelp" both leftOnly rightOnly
959− case (leftOnly, rightOnly) of
960− ([], [missingField]) ->
961− oneMissingField both missingField
963− ([missingField], []) ->
924+-- BAD COMPARISON
964− oneMissingField both missingField
966− ([], missingFields) ->
967− manyMissingFields both missingFields
969− (missingFields, []) ->
927+badCompRight :: Type.Localizer -> Thing -> String -> Can.Type -> Can.Type -> (H.Doc, H.Doc)
970− manyMissingFields both missingFields
928+badCompRight localizer thing op tipe expectedType =
930+ Can.TVar name | N.startsWith "comparable" name ->
931+ badCompArg localizer thing op "right" tipe
973− let
934+ badCompMix localizer op tipe expectedType
975− case Help.findTypoPairs leftOnly rightOnly of
936+
976− [] ->
937+badCompArg :: Type.Localizer -> Thing -> String -> String -> Can.Type -> (H.Doc, H.Doc)
977− Help.findTypoPairs (both ++ leftOnly) (both ++ rightOnly)
938+badCompArg localizer thing op direction tipe =
979− pairs ->
940+ H.reflow $
980− pairs
941+ "I cannot do a comparison with this value:"
982− if null typoPairs then
943+ H.stack
983− ( "The record fields do not match up. One has "
944+ [ H.reflow $ toDescription thing $
984− <> Help.commaSep leftOnly <> ". The other has "
945+ "The " <> direction <> " side of (" <> op <> ") is"
985− <> Help.commaSep rightOnly <> "."
946+ , Type.toDoc localizer tipe
986− , []
947+ , H.fillSep
987− )
948+ ["But","(" <> H.text op <> ")","only","works","on"
988−
949+ ,H.dullyellow "Int" <> ","
989− else
950+ ,H.dullyellow "Float" <> ","
990− ( "The record fields do not match up. Maybe you made one of these typos?"
951+ ,H.dullyellow "Char" <> ","
991− , typoDocs "<->" typoPairs
952+ ,"and"
992− )
953+ ,H.dullyellow "String"
993−
954+ ,"values.","If","you","want","to","get","crazy,","it","will","work","on"
994−
955+ ,"lists","and","tuples","of","comparable","values","as","well."
995−oneMissingField :: [Text] -> Text -> ( Text, [Doc] )
956+ ]
996−oneMissingField knownFields missingField =
957+ ]
997− case Help.findPotentialTypos knownFields missingField of
958+ )
999− ( "Looks like a record is missing the `" <> missingField <> "` field."
1004− ( "Looks like a record is missing the `" <> missingField
1005− <> "` field. Maybe it is a typo?"
1006− , typoDocs "->" [(missingField, typo)]
1010− ( "Looks like a record is missing the `" <> missingField
1011− <> "` field. It is close to names like "
1012− <> Help.commaSep typos <> " so maybe it is a typo?"
1017−manyMissingFields :: [Text] -> [Text] -> (Text, [Doc])
1018−manyMissingFields knownFields missingFields =
1019− case Help.findTypoPairs missingFields knownFields of
1021− ( "Looks like a record is missing these fields: "
1022− <> Help.commaSep missingFields
1026− typoPairs ->
961+badCompMix :: Type.Localizer -> String -> Can.Type -> Can.Type -> (H.Doc, H.Doc)
1027− ( "Looks like a record is missing these fields: "
962+badCompMix localizer op tipe expectedType =
1028− <> Help.commaSep missingFields
963+ (
1029− <> ". Potential typos include:"
964+ H.reflow $
1030− , typoDocs "->" typoPairs
965+ "I need both sides of (" <> op <> ") to be the same type:"
967+ typeComparison localizer expectedType tipe
969+ "The left side of is:"
971+ "But the right side is:"
974+ "I cannot compare different types though! Which side of (" <> op <> ") is the problem?"
1034−typoDocs :: Text -> [(Text, Text)] -> [Doc]
1035−typoDocs arrow typoPairs =
1038− maximum (map (Text.length . fst) typoPairs)
1040− text "" : map (padTypo arrow maxLen) typoPairs
1043−padTypo :: Text -> Int -> (Text, Text) -> Doc
1044−padTypo arrow maxLen (missingField, knownField) =
1045− text (Text.replicate (maxLen - Text.length missingField) " ")
1046− <> dullyellow (text missingField)
1048− <+> dullyellow (text knownField)
1052−-- INFINITE TYPES
981+-- BAD EQUALITY
1055−infiniteTypeToReport :: RenderType.Localizer -> Either Hint Text -> Type.Canonical -> Report.Report
984+badEquality :: Type.Localizer -> String -> Can.Type -> Can.Type -> (H.Doc, H.Doc)
1056−infiniteTypeToReport localizer context overallType =
985+badEquality localizer op tipe expectedType =
1058− (maybeRegion, description) =
987+ H.reflow $
1059− case context of
988+ "I need both sides of (" <> op <> ") to be the same type:"
1060− Right name ->
989+ ,
1061− ( Nothing, functionName name )
990+ typeComparison localizer expectedType tipe
1063− infiniteHint hint
992+ "The left side of is:"
1065− Report.report
994+ "But the right side is:"
1066− "INFINITE TYPE"
995+ ,
1067− maybeRegion
996+ if isFloat tipe || isFloat expectedType then
1068− ( "I am inferring a weird self-referential type for " <> description <> ":"
997+ [ H.toSimpleNote $
1069− )
998+ "Equality on floats is not 100% reliable due to the design of IEEE 754. I\
1070− ( stack
999+ \ recommend a check like (abs (x - y) < 0.0001) instead."
1071− [ reflowParagraph $
1072− "Here is my best effort at writing down the type. You will see ∞ for\
1073− \ parts of the type that repeat something already printed out infinitely."
1074− , indent 4 (RenderType.toDoc localizer overallType)
1075− , reflowParagraph $
1076− "Usually staring at the type is not so helpful in these cases, so definitely\
1077− \ read the debugging hints for ideas on how to figure this out: "
1078− <> Help.hintLink "infinite-type"
1003+ "Different types can never be equal though! Which side is messed up?"
1006+-- error "TODO detect problems here instead?"
1083−infiniteHint :: Hint -> (Maybe R.Region, Text)
1086− CaseBranch n region ->
1087− ( Just region, "the " <> ordinalize n <> " `case` branch" )
1090− ( Nothing, "this `case` expression" )
1093− ( Nothing, "the `if` condition" )
1096− ( Nothing, "the `if` branches" )
1098− MultiIfBranch n region ->
1099− ( Just region, "the " <> ordinalize n <> " `if` branch" )
1102− ( Nothing, "this `if` expression" )
1105− ( Nothing, "this list" )
1107− ListElement n region ->
1108− ( Just region, "the " <> ordinalize n <> " list entry" )
1110− BinopLeft _ _ region ->
1111− ( Just region, "the left argument" )
1113− BinopRight _ _ region ->
1114− ( Just region, "the right argument" )
1117− ( Nothing, "this expression" )
1119− Function maybeName ->
1120− ( Nothing, maybeFuncName maybeName )
1122− UnexpectedArg maybeName 1 1 region ->
1123− ( Just region, "the argument to " <> maybeFuncName maybeName )
1125− UnexpectedArg maybeName index _total region ->
1126− ( Just region, "the " <> ordinalize index <> " argument to " <> maybeFuncName maybeName )
1128− FunctionArity maybeName _ _ region ->
1129− ( Just region, maybeFuncName maybeName )
1131− ReturnType name _ _ region ->
1132− ( Just region, functionName name )
1135− ( Nothing, functionName name )
1141− ( Nothing, "this pattern" )
1144− ( Nothing, "this pattern" )
1147− ( Nothing, "this shader" )
1150− ( Nothing, "this function" )
1153− ( Nothing, "this record accessor" )
1156− ( Nothing, "this field access" )
1159− ( Nothing, "this record" )
1162− ( Nothing, "this “unit” value" )
1165− ( Nothing, "this tuple" )
1167− -- effect manager problems
1169− ( Nothing, functionName name )
1172− ( Nothing, functionName name )
1175− ( Nothing, "this code" )