on master help sign in
Make some progress on type error messages!
0bdfd73Evan Czaplicki
src/Reporting/Error/Type.hs+430−184
@@ -307,7 +307,7 @@ toPatternReport source localizer patternRegion category tipe expected =
307
307
308
308
309patternTypeComparison :: T.Localizer -> T.Type -> T.Type -> ( String, String, [H.Doc] ) -> H.Doc
309patternTypeComparison :: T.Localizer -> T.Type -> T.Type -> ( String, String, [H.Doc] ) -> H.Doc
310−patternTypeComparison localizer actual expected ( iAmSeeing, insteadOf, soHereAreSomeThoughts ) =
310+patternTypeComparison localizer actual expected ( iAmSeeing, insteadOf, contextHints ) =
311 let
311 let
312 (actualDoc, expectedDoc, problems) =
312 (actualDoc, expectedDoc, problems) =
313 T.toDiffDocs localizer actual expected
313 T.toDiffDocs localizer actual expected
@@ -318,8 +318,8 @@ patternTypeComparison localizer actual expected ( iAmSeeing, insteadOf, soHereAr
318 , H.reflow insteadOf
318 , H.reflow insteadOf
319 , H.indent 4 expectedDoc
319 , H.indent 4 expectedDoc
320 ]
320 ]
321− ++ soHereAreSomeThoughts
321+ ++ problemsToHint problems
322− ++ map problemToHints problems
322+ ++ contextHints
323
323
324
324
325toPatternDescription :: PCategory -> String -> String
325toPatternDescription :: PCategory -> String -> String
@@ -341,7 +341,7 @@ toPatternDescription category iAmTryingToMatch =
341
341
342
342
343typeComparison :: T.Localizer -> T.Type -> T.Type -> ( String, String, [H.Doc] ) -> H.Doc
343typeComparison :: T.Localizer -> T.Type -> T.Type -> ( String, String, [H.Doc] ) -> H.Doc
344−typeComparison localizer actual expected ( iAmSeeing, insteadOf, soHereAreSomeThoughts ) =
344+typeComparison localizer actual expected ( iAmSeeing, insteadOf, contextHints ) =
345 let
345 let
346 (actualDoc, expectedDoc, problems) =
346 (actualDoc, expectedDoc, problems) =
347 T.toDiffDocs localizer actual expected
347 T.toDiffDocs localizer actual expected
@@ -352,13 +352,22 @@ typeComparison localizer actual expected ( iAmSeeing, insteadOf, soHereAreSomeTh
352 , H.reflow insteadOf
352 , H.reflow insteadOf
353 , H.indent 4 expectedDoc
353 , H.indent 4 expectedDoc
354 ]
354 ]
355− ++ soHereAreSomeThoughts
355+ ++ problemsToHint problems
356− ++ map problemToHints problems
356+ ++ contextHints
357
357
358
358
359−indentType :: T.Localizer -> T.Type -> H.Doc
359+loneType :: T.Localizer -> T.Type -> T.Type -> ( H.Doc, [H.Doc] ) -> H.Doc
360−indentType localizer tipe =
360+loneType localizer actual expected ( iAmSeeing, furtherDetails ) =
361− H.indent 4 (H.dullyellow (T.toDoc localizer RT.None tipe))
361+ let
362+ (actualDoc, _, problems) =
363+ T.toDiffDocs localizer actual expected
364+ in
365+ H.stack $
366+ [ iAmSeeing
367+ , H.indent 4 actualDoc
368+ ]
369+ ++ furtherDetails
370+ ++ problemsToHint problems
362
371
363
372
364toDescription :: Category -> String -> String
373toDescription :: Category -> String -> String
@@ -389,19 +398,189 @@ toDescription category thatThingIs =
389 OpName _ -> thatThingIs <> ":"
398 OpName _ -> thatThingIs <> ":"
390
399
391
400
392−-- TODO be sure to avoid duplicate Problems (e.g. two instances of BadRigidVar)
401+problemsToHint :: [T.Problem] -> [H.Doc]
393−--
402+problemsToHint problems =
403+ case problems of
404+ [] ->
405+ []
406+
407+ problem : _ ->
408+ problemToHint problem
409+
410+
394−problemToHints :: T.Problem -> H.Doc
411+problemToHint :: T.Problem -> [H.Doc]
395−problemToHints problem =
412+problemToHint problem =
396 case problem of
413 case problem of
397− T.FieldMismatch leftOnly rightOnly -> error "TODO FieldMismatch" leftOnly rightOnly
414+ T.FieldMismatch _ _ -> [] -- TODO do a better job?
398− T.IntFloat -> error "TODO IntFloat"
415+
399− T.MissingArgs numMissing -> error "TODO MissingArgs" numMissing
416+ T.IntFloat ->
400− T.ReturnMismatch -> error "TODO ReturnMismatch"
417+ [ H.fancyLink "Note" ["Read"] "implicit-casts"
401− T.TupleMismatch -> error "TODO TupleMismatch"
418+ ["to","learn","why","Elm","does","not","implicitly","convert"
402− T.BadFlexSuper x tipe -> error "TODO BadFlexSuper" x tipe
419+ ,"Ints","to","Floats.","Use",H.green "toFloat","and"
403− T.BadRigidVar x tipe -> error "TODO BadRigidVar" x tipe
420+ ,H.green "round","to","do","explicit","conversions."
404− T.BadRigidSuper x tipe -> error "TODO BadRigidSuper" x tipe
421+ ]
422+ ]
423+
424+ T.StringFromInt ->
425+ [ H.toFancyHint
426+ ["Want","to","convert","an","Int","into","a","String?"
427+ ,"Use","the",H.green "String.fromInt","function!"
428+ ]
429+ ]
430+
431+ T.StringFromFloat ->
432+ [ H.toFancyHint
433+ ["Want","to","convert","a","Float","into","a","String?"
434+ ,"Use","the",H.green "String.fromFloat","function!"
435+ ]
436+ ]
437+
438+ T.StringToInt ->
439+ [ H.toFancyHint
440+ ["Want","to","convert","a","String","into","an","Int?"
441+ ,"Use","the",H.green "String.toInt","function!"
442+ ]
443+ ]
444+
445+ T.StringToFloat ->
446+ [ H.toFancyHint
447+ ["Want","to","convert","a","String","into","a","Float?"
448+ ,"Use","the",H.green "String.toFloat","function!"
449+ ]
450+ ]
451+
452+ T.AnythingToBool ->
453+ [ H.toSimpleHint $
454+ "Elm does not have “truthiness” such that ints and strings and lists\
455+ \ are automatically converted to booleans. Do that conversion explicitly!"
456+ ]
457+
458+ T.AnythingFromMaybe ->
459+ [ H.toFancyHint
460+ ["Use",H.green "Maybe.withDefault","to","handle","possible","errors."
461+ ,"Longer","term,","it","is","usually","better","to","write","out","the"
462+ ,"full","`case`","though!"
463+ ]
464+ ]
465+
466+ T.AnythingToList ->
467+ [ H.toSimpleHint "Did you forget to add [] around it?"
468+ ]
469+
470+ T.MissingArgs _ -> []
471+ T.ReturnMismatch -> []
472+
473+ T.BadFlexSuper super _ tipe ->
474+ case tipe of
475+ T.Lambda _ _ _ -> badFlexSuper super
476+ T.Infinite -> []
477+ T.Error -> []
478+ T.FlexVar _ -> []
479+ T.FlexSuper s _ -> badDoubleFlexSuper super s
480+ T.RigidVar _y -> error "TODO"
481+ T.RigidSuper _s _y -> error "TODO"
482+ T.Type _ _ _ -> badFlexSuper super
483+ T.Record _ _ -> badFlexSuper super
484+ T.Unit -> badFlexSuper super
485+ T.Tuple _ _ _ -> badFlexSuper super
486+ T.Alias _ _ _ _ -> badFlexSuper super
487+
488+ T.BadRigidVar x tipe ->
489+ case tipe of
490+ T.Lambda _ _ _ -> badRigidVar x "a function"
491+ T.Infinite -> []
492+ T.Error -> []
493+ T.FlexVar _ -> []
494+ T.FlexSuper _s _y -> error "TODO"
495+ T.RigidVar y -> badDoubleRigid x y
496+ T.RigidSuper _ y -> badDoubleRigid x y
497+ T.Type _ name _ -> badRigidVar x ("a `" ++ N.toString name ++ "` value")
498+ T.Record _ _ -> badRigidVar x "a record"
499+ T.Unit -> badRigidVar x "a unit value"
500+ T.Tuple _ _ _ -> badRigidVar x "a tuple"
501+ T.Alias _ name _ _ -> badRigidVar x ("a `" ++ N.toString name ++ "` value")
502+
503+ T.BadRigidSuper super x tipe ->
504+ case tipe of
505+ T.Lambda _ _ _ -> badRigidSuper super "a function"
506+ T.Infinite -> []
507+ T.Error -> []
508+ T.FlexVar _ -> []
509+ T.FlexSuper _s _y -> error "TODO"
510+ T.RigidVar y -> badDoubleRigid x y
511+ T.RigidSuper _ y -> badDoubleRigid x y
512+ T.Type _ name _ -> badRigidSuper super ("a `" ++ N.toString name ++ "` value")
513+ T.Record _ _ -> badRigidSuper super "a record"
514+ T.Unit -> badRigidSuper super "a unit value"
515+ T.Tuple _ _ _ -> badRigidSuper super "a tuple"
516+ T.Alias _ name _ _ -> badRigidSuper super ("a `" ++ N.toString name ++ "` value")
517+
518+
519+badFlexSuper :: T.Super -> [H.Doc]
520+badFlexSuper super =
521+ case super of
522+ T.Comparable -> [ H.toSimpleHint "Only ints, floats, chars, strings, lists, and tuples are comparable." ]
523+ T.Appendable -> [ H.toSimpleHint "Only strings and lists are appendable." ]
524+ T.CompAppend -> [ H.toSimpleHint "Only strings and lists are both comparable and appendable." ]
525+ T.Number ->
526+ [ H.toFancyHint ["Only",H.green "Int","and",H.green "Float","values","work","as","numbers."]
527+ ]
528+
529+
530+badRigidVar :: N.Name -> String -> [H.Doc]
531+badRigidVar name aThing =
532+ [ H.toSimpleHint $
533+ "Your type annotation uses type variable `" ++ N.toString name ++
534+ "` which means ANY type of value can flow through, but your code is saying it specifically wants "
535+ ++ aThing ++ ". Maybe change your type annotation to\
536+ \ be more specific? Maybe change the code to be more general?"
537+ , H.reflowLink "Read" "type-annotations" "for more advice!"
538+ ]
539+
540+
541+badDoubleFlexSuper :: T.Super -> T.Super -> [H.Doc]
542+badDoubleFlexSuper s1 s2 =
543+ let
544+ whatever =
545+ [ H.toSimpleHint $
546+ "There are no "
547+ ]
548+ in
549+ case s1 of
550+ T.Number -> error "TODO" whatever s1 s2
551+ T.Comparable -> error "TODO" whatever s1 s2
552+ T.Appendable -> error "TODO" whatever s1 s2
553+ T.CompAppend -> error "TODO" whatever s1 s2
554+
555+
556+badRigidSuper :: T.Super -> String -> [H.Doc]
557+badRigidSuper super aThing =
558+ let
559+ (superType, manyThings) =
560+ case super of
561+ T.Number -> ("number", "ints AND floats")
562+ T.Comparable -> ("comparable", "ints, floats, chars, strings, lists, and tuples")
563+ T.Appendable -> ("appendable", "strings AND lists")
564+ T.CompAppend -> ("compappend", "strings AND lists")
565+ in
566+ [ H.toSimpleHint $
567+ "The `" ++ superType ++ "` in your type annotation is saying that " ++
568+ manyThings ++ " can flow through, but your code is saying it specifically wants "
569+ ++ aThing ++ ". Maybe change your type annotation to\
570+ \ be more specific? Maybe change the code to be more general?"
571+ , H.reflowLink "Read" "type-annotations" "for more advice!"
572+ ]
573+
574+
575+badDoubleRigid :: N.Name -> N.Name -> [H.Doc]
576+badDoubleRigid x y =
577+ [ H.toSimpleHint $
578+ "Your type annotation uses `" ++ N.toString x ++ "` and `" ++ N.toString y ++
579+ "` as separate type variables. Your code seems to be saying they are the\
580+ \ same though! Maybe they should be the same in your type annotation?\
581+ \ Maybe your code uses them in a weird way?"
582+ , H.reflowLink "Read" "type-annotations" "for more advice!"
583+ ]
405
584
406
585
407
586
@@ -423,9 +602,7 @@ toExprReport source localizer exprRegion category tipe expected =
423 ,
602 ,
424 "But you are trying to use it as:"
603 "But you are trying to use it as:"
425 ,
604 ,
426− [
605+ []
427− -- problem
428− ]
429 )
606 )
430 )
607 )
431
608
@@ -491,15 +668,16 @@ toExprReport source localizer exprRegion category tipe expected =
491 (
668 (
492 "I do not know how to negate this type of value:"
669 "I do not know how to negate this type of value:"
493 ,
670 ,
494− H.stack
671+ loneType localizer tipe expectedType
672+ (
495− [ H.reflow $ toDescription category "It is"
673+ H.reflow $ toDescription category "It is"
496− , indentType localizer tipe
674+ ,
497− , H.fillSep
675+ [ H.fillSep
498− ["But","I","only","now","how","to","negate"
676+ ["But","I","only","now","how","to","negate"
499− ,H.dullyellow "Int","and",H.dullyellow "Float","values."
677+ ,H.dullyellow "Int","and",H.dullyellow "Float","values."
500− ]
678+ ]
501− --, problem
679+ ]
502− ]
680+ )
503 )
681 )
504
682
505 OpLeft op ->
683 OpLeft op ->
@@ -519,14 +697,13 @@ toExprReport source localizer exprRegion category tipe expected =
519 (
697 (
520 "This `if` condition does not evaluate to a boolean value, True or False."
698 "This `if` condition does not evaluate to a boolean value, True or False."
521 ,
699 ,
522− H.stack
700+ loneType localizer tipe expectedType
701+ (
523− [ H.reflow $ toDescription category "It is"
702+ H.reflow $ toDescription category "It is"
524− , indentType localizer tipe
703+ ,
525− , H.fillSep ["But","I","need","this","`if`","condition","to","be","a",H.dullyellow "Bool","value."]
704+ [ H.fillSep ["But","I","need","this","`if`","condition","to","be","a",H.dullyellow "Bool","value."]
526− , H.toSimpleHint $
705+ ]
527− "Elm does not have “truthiness” such that ints and strings and lists\
706+ )
528− \ are automatically converted to booleans. Do that conversion explicitly!"
529− ]
530 )
707 )
531
708
532 IfBranch index ->
709 IfBranch index ->
@@ -698,13 +875,16 @@ toExprReport source localizer exprRegion category tipe expected =
698 H.reflow $
875 H.reflow $
699 "This record does not have a `" <> N.toString field <> "` field:"
876 "This record does not have a `" <> N.toString field <> "` field:"
700 ,
877 ,
701− H.stack $
878+ loneType localizer tipe expectedType
702− [ H.reflow $
879+ (
703− "It is a record with this type:"
880+ H.reflow $ "It is a record with this type:"
704− , indentType localizer tipe
881+ ,
705− , H.reflow $
882+ [ H.fillSep
883+ ["Is","the",H.dullyellow ("." <> H.nameToDoc field)
706− "So maybe the ." <> N.toString field <> " field access is misspelled?"
884+ ,"field","access","is","misspelled?"
707− ]
885+ ]
886+ ]
887+ )
708 )
888 )
709
889
710 _ ->
890 _ ->
@@ -712,12 +892,14 @@ toExprReport source localizer exprRegion category tipe expected =
712 H.reflow $
892 H.reflow $
713 "This is not a record, so it has no fields to access!"
893 "This is not a record, so it has no fields to access!"
714 ,
894 ,
715− H.stack
895+ loneType localizer tipe expectedType
716− [ H.reflow $ toDescription category "It is"
896+ ( H.reflow $ toDescription category "It is"
717− , indentType localizer tipe
718− , H.fillSep
897+ , [ H.fillSep
898+ ["But","I","need","a","record","with","a"
719− ["But","I","need","a","record","with","a",H.dullyellow (H.nameToDoc field),"field!"]
899+ ,H.dullyellow (H.nameToDoc field),"field!"
900+ ]
720− ]
901+ ]
902+ )
721 )
903 )
722
904
723 RecordUpdate ->
905 RecordUpdate ->
@@ -744,11 +926,11 @@ toExprReport source localizer exprRegion category tipe expected =
744 (
926 (
745 "The record update syntax does not work with this value:"
927 "The record update syntax does not work with this value:"
746 ,
928 ,
747− H.stack
929+ loneType localizer tipe expectedType
748− [ H.reflow $ toDescription category "It is"
930+ ( H.reflow $ toDescription category "It is"
749− , indentType localizer tipe
750− , H.reflow $ "But I need some kind of record here!"
931+ , [ H.reflow $ "But I need some kind of record here!"
751− ]
932+ ]
933+ )
752 )
934 )
753
935
754 Destructure ->
936 Destructure ->
@@ -787,36 +969,38 @@ countArgs tipe =
787
969
788
970
789opLeftToDocs :: T.Localizer -> Category -> N.Name -> T.Type -> T.Type -> (H.Doc, H.Doc)
971opLeftToDocs :: T.Localizer -> Category -> N.Name -> T.Type -> T.Type -> (H.Doc, H.Doc)
790−opLeftToDocs localizer category op tipe expectedType =
972+opLeftToDocs localizer category op tipe expected =
791 case op of
973 case op of
792 "+"
974 "+"
793 | isString tipe -> badStringAdd
975 | isString tipe -> badStringAdd
794− | isList tipe -> badListAdd localizer category "left" tipe
976+ | isList tipe -> badListAdd localizer category "left" tipe expected
795− | otherwise -> badMath localizer category "Addition" "left" "+" tipe []
977+ | otherwise -> badMath localizer category "Addition" "left" "+" tipe expected []
796
978
797 "*"
979 "*"
798− | isList tipe -> badListMul localizer category "left" tipe
980+ | isList tipe -> badListMul localizer category "left" tipe expected
799− | otherwise -> badMath localizer category "Multiplication" "left" "*" tipe []
981+ | otherwise -> badMath localizer category "Multiplication" "left" "*" tipe expected []
800−
982+
801− "-" -> badMath localizer category "Subtraction" "left" "-" tipe []
983+ "-" -> badMath localizer category "Subtraction" "left" "-" tipe expected []
802− "^" -> badMath localizer category "Exponentiation" "left" "^" tipe []
984+ "^" -> badMath localizer category "Exponentiation" "left" "^" tipe expected []
803− "/" -> badFDiv localizer "left" tipe
985+ "/" -> badFDiv localizer "left" tipe expected
804− "//" -> badIDiv localizer "left" tipe
986+ "//" -> badIDiv localizer "left" tipe expected
805− "&&" -> badBool localizer "&&" "left" tipe
987+ "&&" -> badBool localizer "&&" "left" tipe expected
806− "||" -> badBool localizer "||" "left" tipe
988+ "||" -> badBool localizer "||" "left" tipe expected
807− "<" -> badCompLeft localizer category "<" "left" tipe
989+ "<" -> badCompLeft localizer category "<" "left" tipe expected
808− ">" -> badCompLeft localizer category ">" "left" tipe
990+ ">" -> badCompLeft localizer category ">" "left" tipe expected
809− "<=" -> badCompLeft localizer category "<=" "left" tipe
991+ "<=" -> badCompLeft localizer category "<=" "left" tipe expected
810− ">=" -> badCompLeft localizer category ">=" "left" tipe
992+ ">=" -> badCompLeft localizer category ">=" "left" tipe expected
993+
994+ "++" -> badAppend localizer category "left" tipe expected
811
995
812 "<|" ->
996 "<|" ->
813 ( "The left side of (<|) needs to be a function so I can pipe arguments to it!"
997 ( "The left side of (<|) needs to be a function so I can pipe arguments to it!"
814 ,
998 ,
815− H.stack
999+ loneType localizer tipe expected
816− [ H.reflow $ toDescription category "I am seeing"
1000+ ( H.reflow $ toDescription category "I am seeing"
817− , indentType localizer tipe
818− , H.reflow $ "This needs to be some kind of function though!"
1001+ , [ H.reflow $ "This needs to be some kind of function though!"
819− ]
1002+ ]
1003+ )
820 )
1004 )
821
1005
822 _ ->
1006 _ ->
@@ -824,7 +1008,7 @@ opLeftToDocs localizer category op tipe expectedType =
824 H.reflow $
1008 H.reflow $
825 "The left argument of (" <> N.toString op <> ") is causing problems:"
1009 "The left argument of (" <> N.toString op <> ") is causing problems:"
826 ,
1010 ,
827− typeComparison localizer tipe expectedType
1011+ typeComparison localizer tipe expected
828 (
1012 (
829 toDescription category "The left argument is"
1013 toDescription category "The left argument is"
830 ,
1014 ,
@@ -845,41 +1029,46 @@ data RightDocs
845
1029
846
1030
847opRightToDocs :: T.Localizer -> Category -> N.Name -> T.Type -> T.Type -> RightDocs
1031opRightToDocs :: T.Localizer -> Category -> N.Name -> T.Type -> T.Type -> RightDocs
848−opRightToDocs localizer category op tipe expectedType =
1032+opRightToDocs localizer category op tipe expected =
849 case op of
1033 case op of
850 "+"
1034 "+"
851− | isInt tipe -> badCast op FloatInt
1035+ | isFloat expected && isInt tipe -> badCast op FloatInt
852− | isFloat tipe -> badCast op IntFloat
1036+ | isInt expected && isFloat tipe -> badCast op IntFloat
853 | isString tipe -> EmphRight $ badStringAdd
1037 | isString tipe -> EmphRight $ badStringAdd
854− | isList tipe -> EmphRight $ badListAdd localizer category "right" tipe
1038+ | isList tipe -> EmphRight $ badListAdd localizer category "right" tipe expected
855− | otherwise -> EmphRight $ badMath localizer category "Addition" "right" "+" tipe []
1039+ | otherwise -> EmphRight $ badMath localizer category "Addition" "right" "+" tipe expected []
856
1040
857 "*"
1041 "*"
858− | isInt tipe -> badCast op FloatInt
1042+ | isFloat expected && isInt tipe -> badCast op FloatInt
859− | isFloat tipe -> badCast op IntFloat
1043+ | isInt expected && isFloat tipe -> badCast op IntFloat
860− | isList tipe -> EmphRight $ badListMul localizer category "right" tipe
1044+ | isList tipe -> EmphRight $ badListMul localizer category "right" tipe expected
861− | otherwise -> EmphRight $ badMath localizer category "Multiplication" "right" "*" tipe []
1045+ | otherwise -> EmphRight $ badMath localizer category "Multiplication" "right" "*" tipe expected []
862
1046
863 "-"
1047 "-"
864− | isInt tipe -> badCast op FloatInt
1048+ | isFloat expected && isInt tipe -> badCast op FloatInt
865− | isFloat tipe -> badCast op IntFloat
1049+ | isInt expected && isFloat tipe -> badCast op IntFloat
1050+ | otherwise ->
866− | otherwise -> EmphRight $ badMath localizer category "Subtraction" "right" "-" tipe []
1051+ EmphRight $ badMath localizer category "Subtraction" "right" "-" tipe expected []
867
1052
868 "^"
1053 "^"
869− | isInt tipe -> badCast op FloatInt
1054+ | isFloat expected && isInt tipe -> badCast op FloatInt
870− | isFloat tipe -> badCast op IntFloat
1055+ | isInt expected && isFloat tipe -> badCast op IntFloat
1056+ | otherwise ->
871− | otherwise -> EmphRight $ badMath localizer category "Exponentiation" "right" "^" tipe []
1057+ EmphRight $ badMath localizer category "Exponentiation" "right" "^" tipe expected []
872−
1058+
873− "/" -> EmphRight $ badFDiv localizer "right" tipe
1059+ "/" -> EmphRight $ badFDiv localizer "right" tipe expected
874− "//" -> EmphRight $ badIDiv localizer "right" tipe
1060+ "//" -> EmphRight $ badIDiv localizer "right" tipe expected
875− "&&" -> EmphRight $ badBool localizer "&&" "right" tipe
1061+ "&&" -> EmphRight $ badBool localizer "&&" "right" tipe expected
876− "||" -> EmphRight $ badBool localizer "||" "right" tipe
1062+ "||" -> EmphRight $ badBool localizer "||" "right" tipe expected
877− "<" -> badCompRight localizer "<" tipe expectedType
1063+ "<" -> badCompRight localizer "<" tipe expected
878− ">" -> badCompRight localizer ">" tipe expectedType
1064+ ">" -> badCompRight localizer ">" tipe expected
879− "<=" -> badCompRight localizer "<=" tipe expectedType
1065+ "<=" -> badCompRight localizer "<=" tipe expected
880− ">=" -> badCompRight localizer ">=" tipe expectedType
1066+ ">=" -> badCompRight localizer ">=" tipe expected
881− "==" -> badEquality localizer "==" tipe expectedType
1067+ "==" -> badEquality localizer "==" tipe expected
882− "/=" -> badEquality localizer "/=" tipe expectedType
1068+ "/=" -> badEquality localizer "/=" tipe expected
1069+
1070+ "::" -> error "TODO"
1071+ "++" -> EmphRight $ badAppend localizer category "right" tipe expected
883
1072
884 "<|" ->
1073 "<|" ->
885 EmphRight
1074 EmphRight
@@ -887,7 +1076,7 @@ opRightToDocs localizer category op tipe expectedType =
887 H.reflow $
1076 H.reflow $
888 "I cannot send this through the (<|) pipe:"
1077 "I cannot send this through the (<|) pipe:"
889 ,
1078 ,
890− typeComparison localizer tipe expectedType
1079+ typeComparison localizer tipe expected
891 (
1080 (
892 toDescription category "You are providing"
1081 toDescription category "You are providing"
893 ,
1082 ,
@@ -898,7 +1087,7 @@ opRightToDocs localizer category op tipe expectedType =
898 )
1087 )
899
1088
900 "|>" ->
1089 "|>" ->
901− case (tipe, expectedType) of
1090+ case (tipe, expected) of
902 (T.Lambda expectedArgType _ _, T.Lambda argType _ _) ->
1091 (T.Lambda expectedArgType _ _, T.Lambda argType _ _) ->
903 EmphRight
1092 EmphRight
904 (
1093 (
@@ -919,11 +1108,11 @@ opRightToDocs localizer category op tipe expectedType =
919 (
1108 (
920 "The right side of (|>) needs to be a function so I can pipe arguments to it!"
1109 "The right side of (|>) needs to be a function so I can pipe arguments to it!"
921 ,
1110 ,
922− H.stack
1111+ loneType localizer tipe expected
923− [ H.reflow $ toDescription category $
1112+ ( H.reflow $ toDescription category $
924− "Instead of a function, I am seeing "
1113+ "But instead of a function, I am seeing "
925− , indentType localizer tipe
926− ]
1114+ , []
1115+ )
927 )
1116 )
928
1117
929 _ ->
1118 _ ->
@@ -932,7 +1121,7 @@ opRightToDocs localizer category op tipe expectedType =
932 H.reflow $
1121 H.reflow $
933 "The right argument of (" <> N.toString op <> ") is causing problems."
1122 "The right argument of (" <> N.toString op <> ") is causing problems."
934 ,
1123 ,
935− typeComparison localizer tipe expectedType
1124+ typeComparison localizer tipe expected
936 (
1125 (
937 toDescription category "The right argument is"
1126 toDescription category "The right argument is"
938 ,
1127 ,
@@ -989,6 +1178,57 @@ isList tipe =
989
1178
990
1179
991
1180
1181+-- BAD APPEND
1182+
1183+
1184+badAppend :: T.Localizer -> Category -> String -> T.Type -> T.Type -> (H.Doc, H.Doc)
1185+badAppend localizer category direction tipe expected =
1186+ let
1187+ maybeDetails =
1188+ case tipe of
1189+ T.Type home name []
1190+ | ModuleName.basics == home && name == N.int -> Just ("ints", "String.fromInt")
1191+ | ModuleName.basics == home && name == N.float -> Just ("floats", "String.fromFloat")
1192+
1193+ T.FlexSuper T.Number _ ->
1194+ Just ("numbers", "String.fromInt")
1195+
1196+ _ ->
1197+ Nothing
1198+ in
1199+ case maybeDetails of
1200+ Just (things, stringFromThing) ->
1201+ (
1202+ H.fillSep
1203+ ["The","(++)","operator","is","for","appending",H.dullyellow "List","and"
1204+ ,H.dullyellow "String","values,","not",H.dullyellow things,"like","this:"
1205+ ]
1206+ ,
1207+ H.fillSep
1208+ ["Try","using",H.green stringFromThing,"to","turn","it","into","a"
1209+ ,H.dullyellow "String" <> "?"
1210+ ]
1211+ )
1212+
1213+ Nothing ->
1214+ (
1215+ H.reflow $
1216+ "The (++) operator cannot append this type of value:"
1217+ ,
1218+ loneType localizer tipe expected
1219+ ( H.reflow $ toDescription category $
1220+ "The " <> direction <> " side of (++) is"
1221+ ,
1222+ [ H.fillSep
1223+ ["But","the","(++)","operator","is","only","for","appending"
1224+ ,H.dullyellow "List","and",H.dullyellow "String","values."
1225+ ]
1226+ ]
1227+ )
1228+ )
1229+
1230+
1231+
992-- BAD MATH
1232-- BAD MATH
993
1233
994
1234
@@ -1050,28 +1290,30 @@ badStringAdd =
1050 )
1290 )
1051
1291
1052
1292
1053−badListAdd :: T.Localizer -> Category -> String -> T.Type -> (H.Doc, H.Doc)
1293+badListAdd :: T.Localizer -> Category -> String -> T.Type -> T.Type -> (H.Doc, H.Doc)
1054−badListAdd localizer category direction tipe =
1294+badListAdd localizer category direction tipe expected =
1055 (
1295 (
1056 "I cannot do addition with lists:"
1296 "I cannot do addition with lists:"
1057 ,
1297 ,
1058− H.stack
1298+ loneType localizer tipe expected
1299+ (
1059− [ H.reflow $ toDescription category $
1300+ H.reflow $ toDescription category $
1060 "The " <> direction <> " side of (+) is"
1301 "The " <> direction <> " side of (+) is"
1061− , indentType localizer tipe
1302+ ,
1062− , H.fillSep
1303+ [ H.fillSep
1063− ["But","(+)","only","works","with",H.dullyellow "Int","and",H.dullyellow "Float","values."
1304+ ["But","(+)","only","works","with",H.dullyellow "Int","and",H.dullyellow "Float","values."
1064− ]
1305+ ]
1065− , H.toFancyHint
1306+ , H.toFancyHint
1066− ["Switch","to","the",H.green "(++)","operator","to","append","lists!"
1307+ ["Switch","to","the",H.green "(++)","operator","to","append","lists!"
1067− ]
1308+ ]
1068− ]
1309+ ]
1310+ )
1069 )
1311 )
1070
1312
1071
1313
1072−badListMul :: T.Localizer -> Category -> String -> T.Type -> (H.Doc, H.Doc)
1314+badListMul :: T.Localizer -> Category -> String -> T.Type -> T.Type -> (H.Doc, H.Doc)
1073−badListMul localizer category direction tipe =
1315+badListMul localizer category direction tipe expected =
1074− badMath localizer category "Multiplication" direction "*" tipe
1316+ badMath localizer category "Multiplication" direction "*" tipe expected
1075 [
1317 [
1076 H.toFancyHint
1318 H.toFancyHint
1077 [ "Maybe", "you", "want"
1319 [ "Maybe", "you", "want"
@@ -1081,27 +1323,28 @@ badListMul localizer category direction tipe =
1081 ]
1323 ]
1082
1324
1083
1325
1084−badMath :: T.Localizer -> Category -> String -> String -> String -> T.Type -> [H.Doc] -> (H.Doc, H.Doc)
1326+badMath :: T.Localizer -> Category -> String -> String -> String -> T.Type -> T.Type -> [H.Doc] -> (H.Doc, H.Doc)
1085−badMath localizer category operation direction op tipe otherHints =
1327+badMath localizer category operation direction op tipe expected otherHints =
1086 (
1328 (
1087 H.reflow $
1329 H.reflow $
1088 operation ++ " does not work with this value:"
1330 operation ++ " does not work with this value:"
1089 ,
1331 ,
1090− H.stack $
1332+ loneType localizer tipe expected
1091− [ H.reflow $ toDescription category $
1333+ ( H.reflow $ toDescription category $
1092 "The " <> direction <> " side of (" <> op <> ") is"
1334 "The " <> direction <> " side of (" <> op <> ") is"
1093− , indentType localizer tipe
1335+ ,
1094− , H.fillSep
1336+ [ H.fillSep
1095− ["But","(" <> H.text op <> ")","only","works","with"
1337+ ["But","(" <> H.text op <> ")","only","works","with"
1096− ,H.dullyellow "Int","and",H.dullyellow "Float","values."
1338+ ,H.dullyellow "Int","and",H.dullyellow "Float","values."
1097− ]
1339+ ]
1098− ]
1340+ ]
1099− ++ otherHints
1341+ ++ otherHints
1342+ )
1100 )
1343 )
1101
1344
1102
1345
1103−badFDiv :: T.Localizer -> H.Doc -> T.Type -> (H.Doc, H.Doc)
1346+badFDiv :: T.Localizer -> H.Doc -> T.Type -> T.Type -> (H.Doc, H.Doc)
1104−badFDiv localizer direction tipe =
1347+badFDiv localizer direction tipe expected =
1105 (
1348 (
1106 H.reflow $
1349 H.reflow $
1107 "The (/) operator is specifically for floating-point division:"
1350 "The (/) operator is specifically for floating-point division:"
@@ -1122,19 +1365,20 @@ badFDiv localizer direction tipe =
1122 ]
1365 ]
1123
1366
1124 else
1367 else
1125− H.stack
1368+ loneType localizer tipe expected
1369+ (
1126− [ H.fillSep
1370+ H.fillSep
1127 ["The",direction,"side","of","(/)","must","be","a"
1371 ["The",direction,"side","of","(/)","must","be","a"
1128 ,H.dullyellow "Float" <> ","
1372 ,H.dullyellow "Float" <> ","
1129 ,"but","instead","I","am","seeing:"
1373 ,"but","instead","I","am","seeing:"
1130 ]
1374 ]
1131− , indentType localizer tipe
1375+ , []
1132− ]
1376+ )
1133 )
1377 )
1134
1378
1135
1379
1136−badIDiv :: T.Localizer -> H.Doc -> T.Type -> (H.Doc, H.Doc)
1380+badIDiv :: T.Localizer -> H.Doc -> T.Type -> T.Type -> (H.Doc, H.Doc)
1137−badIDiv localizer direction tipe =
1381+badIDiv localizer direction tipe expected =
1138 (
1382 (
1139 H.reflow $
1383 H.reflow $
1140 "The (//) operator is specifically for integer division:"
1384 "The (//) operator is specifically for integer division:"
@@ -1157,14 +1401,15 @@ badIDiv localizer direction tipe =
1157 , H.link "Note" "Read" "implicit-casts" "to learn why Elm does not implicitly convert Ints to Floats."
1401 , H.link "Note" "Read" "implicit-casts" "to learn why Elm does not implicitly convert Ints to Floats."
1158 ]
1402 ]
1159 else
1403 else
1160− H.stack
1404+ loneType localizer tipe expected
1405+ (
1161− [ H.fillSep
1406+ H.fillSep
1162 ["The",direction,"side","of","(//)","must","be","an"
1407 ["The",direction,"side","of","(//)","must","be","an"
1163 ,H.dullyellow "Int" <> ","
1408 ,H.dullyellow "Int" <> ","
1164 ,"but","instead","I","am","seeing:"
1409 ,"but","instead","I","am","seeing:"
1165 ]
1410 ]
1166− , indentType localizer tipe
1411+ , []
1167− ]
1412+ )
1168 )
1413 )
1169
1414
1170
1415
@@ -1172,22 +1417,21 @@ badIDiv localizer direction tipe =
1172-- BAD BOOLS
1417-- BAD BOOLS
1173
1418
1174
1419
1175−badBool :: T.Localizer -> H.Doc -> H.Doc -> T.Type -> (H.Doc, H.Doc)
1420+badBool :: T.Localizer -> H.Doc -> H.Doc -> T.Type -> T.Type -> (H.Doc, H.Doc)
1176−badBool localizer op direction tipe =
1421+badBool localizer op direction tipe expected =
1177 (
1422 (
1178 H.reflow $
1423 H.reflow $
1179 "I am struggling with this boolean operation:"
1424 "I am struggling with this boolean operation:"
1180 ,
1425 ,
1181− H.stack
1426+ loneType localizer tipe expected
1427+ (
1182− [ H.fillSep
1428+ H.fillSep
1183 ["Both","sides","of","(" <> op <> ")","must","be"
1429 ["Both","sides","of","(" <> op <> ")","must","be"
1184 ,H.dullyellow "Bool","values,","but","the",direction,"side","is:"
1430 ,H.dullyellow "Bool","values,","but","the",direction,"side","is:"
1185 ]
1431 ]
1186− , indentType localizer tipe
1432+ ,
1187− , H.toSimpleHint
1188− "Elm does not have “truthiness” such that ints and strings and lists are\
1189− \ automatically converted to booleans. Do that conversion explicitly!"
1190− ]
1433+ []
1434+ )
1191 )
1435 )
1192
1436
1193
1437
@@ -1195,38 +1439,40 @@ badBool localizer op direction tipe =
1195-- BAD COMPARISON
1439-- BAD COMPARISON
1196
1440
1197
1441
1198−badCompLeft :: T.Localizer -> Category -> String -> String -> T.Type -> (H.Doc, H.Doc)
1442+badCompLeft :: T.Localizer -> Category -> String -> String -> T.Type -> T.Type -> (H.Doc, H.Doc)
1199−badCompLeft localizer category op direction tipe =
1443+badCompLeft localizer category op direction tipe expected =
1200 (
1444 (
1201 H.reflow $
1445 H.reflow $
1202 "I cannot do a comparison with this value:"
1446 "I cannot do a comparison with this value:"
1203 ,
1447 ,
1204− H.stack
1448+ loneType localizer tipe expected
1449+ (
1205− [ H.reflow $ toDescription category $
1450+ H.reflow $ toDescription category $
1206 "The " <> direction <> " side of (" <> op <> ") is"
1451 "The " <> direction <> " side of (" <> op <> ") is"
1207− , indentType localizer tipe
1452+ ,
1208− , H.fillSep
1453+ [ H.fillSep
1209− ["But","(" <> H.text op <> ")","only","works","on"
1454+ ["But","(" <> H.text op <> ")","only","works","on"
1210− ,H.dullyellow "Int" <> ","
1455+ ,H.dullyellow "Int" <> ","
1211− ,H.dullyellow "Float" <> ","
1456+ ,H.dullyellow "Float" <> ","
1212− ,H.dullyellow "Char" <> ","
1457+ ,H.dullyellow "Char" <> ","
1213− ,"and"
1458+ ,"and"
1214− ,H.dullyellow "String"
1459+ ,H.dullyellow "String"
1215− ,"values.","If","you","want","to","get","crazy,","it","will","work","on"
1460+ ,"values.","If","you","want","to","get","crazy,","it","will","work","on"
1216− ,"lists","and","tuples","of","comparable","values","as","well."
1461+ ,"lists","and","tuples","of","comparable","values","as","well."
1217− ]
1462+ ]
1218− ]
1463+ ]
1464+ )
1219 )
1465 )
1220
1466
1221
1467
1222badCompRight :: T.Localizer -> String -> T.Type -> T.Type -> RightDocs
1468badCompRight :: T.Localizer -> String -> T.Type -> T.Type -> RightDocs
1223−badCompRight localizer op tipe expectedType =
1469+badCompRight localizer op tipe expected =
1224 EmphBoth
1470 EmphBoth
1225 (
1471 (
1226 H.reflow $
1472 H.reflow $
1227 "I need both sides of (" <> op <> ") to be the same type:"
1473 "I need both sides of (" <> op <> ") to be the same type:"
1228 ,
1474 ,
1229− typeComparison localizer expectedType tipe
1475+ typeComparison localizer expected tipe
1230 (
1476 (
1231 "The left side of is:"
1477 "The left side of is:"
1232 ,
1478 ,
@@ -1244,19 +1490,19 @@ badCompRight localizer op tipe expectedType =
1244
1490
1245
1491
1246badEquality :: T.Localizer -> String -> T.Type -> T.Type -> RightDocs
1492badEquality :: T.Localizer -> String -> T.Type -> T.Type -> RightDocs
1247−badEquality localizer op tipe expectedType =
1493+badEquality localizer op tipe expected =
1248 EmphBoth
1494 EmphBoth
1249 (
1495 (
1250 H.reflow $
1496 H.reflow $
1251 "I need both sides of (" <> op <> ") to be the same type:"
1497 "I need both sides of (" <> op <> ") to be the same type:"
1252 ,
1498 ,
1253− typeComparison localizer expectedType tipe
1499+ typeComparison localizer expected tipe
1254 (
1500 (
1255 "The left side of is:"
1501 "The left side of is:"
1256 ,
1502 ,
1257 "But the right side is:"
1503 "But the right side is:"
1258 ,
1504 ,
1259− if isFloat tipe || isFloat expectedType then
1505+ if isFloat tipe || isFloat expected then
1260 [ H.toSimpleNote $
1506 [ H.toSimpleNote $
1261 "Equality on floats is not 100% reliable due to the design of IEEE 754. I\
1507 "Equality on floats is not 100% reliable due to the design of IEEE 754. I\
1262 \ recommend a check like (abs (x - y) < 0.0001) instead."
1508 \ recommend a check like (abs (x - y) < 0.0001) instead."
@@ -1285,7 +1531,7 @@ toInfiniteReport source localizer region name overallType =
1285 [ H.reflow $
1531 [ H.reflow $
1286 "Here is my best effort at writing down the type. You will see ∞ for\
1532 "Here is my best effort at writing down the type. You will see ∞ for\
1287 \ parts of the type that repeat something already printed out infinitely."
1533 \ parts of the type that repeat something already printed out infinitely."
1288− , indentType localizer overallType
1534+ , H.indent 4 (H.dullyellow (T.toDoc localizer RT.None overallType))
1289 , H.reflowLink
1535 , H.reflowLink
1290 "Staring at the type is usually not so helpful, so I recommend reading the hints at"
1536 "Staring at the type is usually not so helpful, so I recommend reading the hints at"
1291 "infinite-type"
1537 "infinite-type"
src/Reporting/Helpers.hs+7−1
@@ -5,7 +5,7 @@ module Reporting.Helpers
5 , nameToDoc
5 , nameToDoc
6 , args, moreArgs
6 , args, moreArgs
7 , toSimpleNote, toSimpleHint, toFancyHint
7 , toSimpleNote, toSimpleHint, toFancyHint
8− , link, reflowLink, makeLink
8+ , link, fancyLink, reflowLink, makeLink
9 , stack, reflow
9 , stack, reflow
10 , commaSep, capitalize, ordinalize, drawCycle
10 , commaSep, capitalize, ordinalize, drawCycle
11 , findPotentialTypos, findTypoPairs, vetTypos
11 , findPotentialTypos, findTypoPairs, vetTypos
@@ -87,6 +87,12 @@ link word before fileName after =
87 : map text (words after)
87 : map text (words after)
88
88
89
89
90+fancyLink :: Doc -> [Doc] -> String -> [Doc] -> Doc
91+fancyLink word before fileName after =
92+ fillSep $
93+ (underline word <> ":") : before ++ P.text (makeLink fileName) : after
94+
95+
90makeLink :: String -> String
96makeLink :: String -> String
91makeLink fileName =
97makeLink fileName =
92 "<https://elm-lang.org/hints/" <> Pkg.versionToString Compiler.version <> "/" <> fileName <> ">"
98 "<https://elm-lang.org/hints/" <> Pkg.versionToString Compiler.version <> "/" <> fileName <> ">"
src/Type/Error.hs+102−43
@@ -2,6 +2,7 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Type.Error
3module Type.Error
4 ( Type(..)
4 ( Type(..)
5+ , Super(..)
5 , Extension(..)
6 , Extension(..)
6 , iteratedDealias
7 , iteratedDealias
7 , Localizer
8 , Localizer
@@ -32,9 +33,9 @@ data Type
32 | Infinite
33 | Infinite
33 | Error
34 | Error
34 | FlexVar N.Name
35 | FlexVar N.Name
35− | FlexSuper N.Name
36+ | FlexSuper Super N.Name
36 | RigidVar N.Name
37 | RigidVar N.Name
37− | RigidSuper N.Name
38+ | RigidSuper Super N.Name
38 | Type ModuleName.Canonical N.Name [Type]
39 | Type ModuleName.Canonical N.Name [Type]
39 | Record (Map.Map N.Name Type) Extension
40 | Record (Map.Map N.Name Type) Extension
40 | Unit
41 | Unit
@@ -42,6 +43,13 @@ data Type
42 | Alias ModuleName.Canonical N.Name [(N.Name, Type)] Type
43 | Alias ModuleName.Canonical N.Name [(N.Name, Type)] Type
43
44
44
45
46+data Super
47+ = Number
48+ | Comparable
49+ | Appendable
50+ | CompAppend
51+
52+
45data Extension
53data Extension
46 = Closed
54 = Closed
47 | FlexOpen N.Name
55 | FlexOpen N.Name
@@ -93,13 +101,13 @@ toDoc dict ctx tipe =
93 FlexVar name ->
101 FlexVar name ->
94 H.nameToDoc name
102 H.nameToDoc name
95
103
96− FlexSuper name ->
104+ FlexSuper _ name ->
97 H.nameToDoc name
105 H.nameToDoc name
98
106
99 RigidVar name ->
107 RigidVar name ->
100 H.nameToDoc name
108 H.nameToDoc name
101
109
102− RigidSuper name ->
110+ RigidSuper _ name ->
103 H.nameToDoc name
111 H.nameToDoc name
104
112
105 Type home name args ->
113 Type home name args ->
@@ -121,7 +129,6 @@ toDoc dict ctx tipe =
121 FlexOpen x -> Just (H.nameToDoc x)
129 FlexOpen x -> Just (H.nameToDoc x)
122 RigidOpen x -> Just (H.nameToDoc x)
130 RigidOpen x -> Just (H.nameToDoc x)
123
131
124−
125 Unit ->
132 Unit ->
126 "()"
133 "()"
127
134
@@ -187,12 +194,18 @@ instance Applicative Diff where
187data Problem
194data Problem
188 = FieldMismatch [N.Name] [N.Name]
195 = FieldMismatch [N.Name] [N.Name]
189 | IntFloat
196 | IntFloat
197+ | StringFromInt
198+ | StringFromFloat
199+ | StringToInt
200+ | StringToFloat
201+ | AnythingToBool
202+ | AnythingFromMaybe
203+ | AnythingToList
190 | MissingArgs Int
204 | MissingArgs Int
191 | ReturnMismatch
205 | ReturnMismatch
192− | TupleMismatch
193− | BadFlexSuper N.Name Type
206+ | BadFlexSuper Super N.Name Type
194 | BadRigidVar N.Name Type
207 | BadRigidVar N.Name Type
195− | BadRigidSuper N.Name Type
208+ | BadRigidSuper Super N.Name Type
196
209
197
210
198
211
@@ -202,10 +215,10 @@ data Problem
202diff :: Localizer -> RT.Context -> Type -> Type -> Diff H.Doc
215diff :: Localizer -> RT.Context -> Type -> Type -> Diff H.Doc
203diff dict ctx tipe1 tipe2 =
216diff dict ctx tipe1 tipe2 =
204 case (tipe1, tipe2) of
217 case (tipe1, tipe2) of
205− (FlexVar x, FlexVar y) | x == y -> pure (H.nameToDoc x)
218+ (FlexVar x, FlexVar y) | x == y -> pure (H.nameToDoc x)
206− (FlexSuper x, FlexSuper y) | x == y -> pure (H.nameToDoc x)
219+ (FlexSuper _ x, FlexSuper _ y) | x == y -> pure (H.nameToDoc x)
207− (RigidVar x, RigidVar y) | x == y -> pure (H.nameToDoc x)
220+ (RigidVar x, RigidVar y) | x == y -> pure (H.nameToDoc x)
208− (RigidSuper x, RigidSuper y) | x == y -> pure (H.nameToDoc x)
221+ (RigidSuper _ x, RigidSuper _ y) | x == y -> pure (H.nameToDoc x)
209
222
210 (Infinite, Infinite) -> pure "∞"
223 (Infinite, Infinite) -> pure "∞"
211 (Error, Error) -> pure "?"
224 (Error, Error) -> pure "?"
@@ -218,8 +231,8 @@ diff dict ctx tipe1 tipe2 =
218 <*>
231 <*>
219 case (maybeC, maybeZ) of
232 case (maybeC, maybeZ) of
220 (Nothing, Nothing) -> pure []
233 (Nothing, Nothing) -> pure []
221− (Just c , Nothing) -> Different [H.dullyellow (toDoc dict RT.None c)] [] (Bag.one TupleMismatch)
234+ (Just c , Nothing) -> Different [H.dullyellow (toDoc dict RT.None c)] [] Bag.empty
222− (Nothing, Just z ) -> Different [] [H.dullyellow (toDoc dict RT.None z)] (Bag.one TupleMismatch)
235+ (Nothing, Just z ) -> Different [] [H.dullyellow (toDoc dict RT.None z)] Bag.empty
223 (Just c , Just z ) -> (:[]) <$> diff dict RT.None c z
236 (Just c , Just z ) -> (:[]) <$> diff dict RT.None c z
224
237
225 (Record fields1 ext1, Record fields2 ext2) -> diffRecord dict fields1 ext1 fields2 ext2
238 (Record fields1 ext1, Record fields2 ext2) -> diffRecord dict fields1 ext1 fields2 ext2
@@ -243,35 +256,81 @@ diff dict ctx tipe1 tipe2 =
243 (other, FlexVar x) -> Similar (toDoc dict ctx other) (H.nameToDoc x)
256 (other, FlexVar x) -> Similar (toDoc dict ctx other) (H.nameToDoc x)
244
257
245 pair ->
258 pair ->
259+ case pair of
260+ (Type home name [t1], t2) | isMaybe home name && isSimilar t1 t2 ->
261+ Different (yellowApply dict ctx home name t1) (toDoc dict ctx t2) (Bag.one AnythingFromMaybe)
262+
263+ (t1, Type home name [t2]) | isList home name && isSimilar t1 t2 ->
264+ Different (toDoc dict ctx t1) (yellowApply dict ctx home name t2) (Bag.one AnythingToList)
265+
266+ _ ->
246− let
267+ let
247− doc1 = H.dullyellow (toDoc dict ctx tipe1)
268+ doc1 = H.dullyellow (toDoc dict ctx tipe1)
248− doc2 = H.dullyellow (toDoc dict ctx tipe2)
269+ doc2 = H.dullyellow (toDoc dict ctx tipe2)
249− in
270+ in
250− Different doc1 doc2 $
271+ Different doc1 doc2 $
251− case pair of
272+ case pair of
252− (RigidVar x, other) -> Bag.one $ BadRigidVar x other
273+ (RigidVar x, other) -> Bag.one $ BadRigidVar x other
253− (FlexSuper x, other) -> Bag.one $ BadFlexSuper x other
274+ (FlexSuper s x, other) -> Bag.one $ BadFlexSuper s x other
254− (RigidSuper x, other) -> Bag.one $ BadRigidSuper x other
275+ (RigidSuper s x, other) -> Bag.one $ BadRigidSuper s x other
255− (other, RigidVar x) -> Bag.one $ BadRigidVar x other
276+ (other, RigidVar x) -> Bag.one $ BadRigidVar x other
256− (other, FlexSuper x) -> Bag.one $ BadFlexSuper x other
277+ (other, FlexSuper s x) -> Bag.one $ BadFlexSuper s x other
257− (other, RigidSuper x) -> Bag.one $ BadRigidSuper x other
278+ (other, RigidSuper s x) -> Bag.one $ BadRigidSuper s x other
258−
279+
280+ (Type home1 name1 [], Type home2 name2 [])
281+ | isInt home1 name1 && isFloat home2 name2 -> Bag.one IntFloat
259− (Type home1 name1 [], Type home2 name2 []) | isIntFloat home1 name1 home2 name2 -> Bag.one IntFloat
282+ | isFloat home1 name1 && isInt home2 name2 -> Bag.one IntFloat
260−
283+ | isInt home1 name1 && isString home2 name2 -> Bag.one StringFromInt
261− (_, _) -> Bag.empty
284+ | isFloat home1 name1 && isString home2 name2 -> Bag.one StringFromFloat
262−
263−
264−isIntFloat :: ModuleName.Canonical -> N.Name -> ModuleName.Canonical -> N.Name -> Bool
265−isIntFloat home1 name1 home2 name2 =
285+ | isString home1 name1 && isInt home2 name2 -> Bag.one StringToInt
266− home1 == ModuleName.basics
286+ | isString home1 name1 && isFloat home2 name2 -> Bag.one StringToFloat
267− &&
287+ | isBool home2 name2 -> Bag.one AnythingToBool
268− home2 == ModuleName.basics
288+
269− &&
289+ (_, _) -> Bag.empty
270− (
290+
271− (name1 == N.int && name2 == N.float)
291+
272− ||
292+isBool :: ModuleName.Canonical -> N.Name -> Bool
273− (name1 == N.float && name2 == N.int)
293+isBool home name =
274− )
294+ home == ModuleName.basics && name == N.bool
295+
296+
297+isInt :: ModuleName.Canonical -> N.Name -> Bool
298+isInt home name =
299+ home == ModuleName.basics && name == N.int
300+
301+
302+isFloat :: ModuleName.Canonical -> N.Name -> Bool
303+isFloat home name =
304+ home == ModuleName.basics && name == N.float
305+
306+
307+isString :: ModuleName.Canonical -> N.Name -> Bool
308+isString home name =
309+ home == ModuleName.string && name == N.string
310+
311+
312+isMaybe :: ModuleName.Canonical -> N.Name -> Bool
313+isMaybe home name =
314+ home == ModuleName.maybe && name == N.maybe
315+
316+
317+isList :: ModuleName.Canonical -> N.Name -> Bool
318+isList home name =
319+ home == ModuleName.list && name == N.list
320+
321+
322+isSimilar :: Type -> Type -> Bool
323+isSimilar tipe1 tipe2 =
324+ case diff Map.empty RT.None tipe1 tipe2 of
325+ Similar _ _ -> True
326+ Different _ _ _ -> False
327+
328+
329+yellowApply :: Localizer -> RT.Context -> ModuleName.Canonical -> N.Name -> Type -> H.Doc
330+yellowApply dict ctx home name tipe =
331+ RT.apply ctx
332+ (H.dullyellow (nameToDoc dict home name))
333+ [toDoc dict RT.App tipe]
275
334
276
335
277
336
src/Type/Type.hs+13−4
@@ -473,18 +473,18 @@ contentToErrorType variable content =
473 FlexSuper super maybeName ->
473 FlexSuper super maybeName ->
474 case maybeName of
474 case maybeName of
475 Just name ->
475 Just name ->
476− return (ET.FlexSuper name)
476+ return (ET.FlexSuper (superToSuper super) name)
477
477
478 Nothing ->
478 Nothing ->
479 do name <- getFreshSuperName super
479 do name <- getFreshSuperName super
480 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
480 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
481− return (ET.FlexSuper name)
481+ return (ET.FlexSuper (superToSuper super) name)
482
482
483 RigidVar name ->
483 RigidVar name ->
484 return (ET.RigidVar name)
484 return (ET.RigidVar name)
485
485
486− RigidSuper _ name ->
486+ RigidSuper super name ->
487− return (ET.RigidSuper name)
487+ return (ET.RigidSuper (superToSuper super) name)
488
488
489 Alias home name args realVariable ->
489 Alias home name args realVariable ->
490 do errArgs <- traverse (traverse variableToErrorType) args
490 do errArgs <- traverse (traverse variableToErrorType) args
@@ -495,6 +495,15 @@ contentToErrorType variable content =
495 return ET.Error
495 return ET.Error
496
496
497
497
498+superToSuper :: SuperType -> ET.Super
499+superToSuper super =
500+ case super of
501+ Number -> ET.Number
502+ Comparable -> ET.Comparable
503+ Appendable -> ET.Appendable
504+ CompAppend -> ET.CompAppend
505+
506+
498termToErrorType :: FlatType -> StateT NameState IO ET.Type
507termToErrorType :: FlatType -> StateT NameState IO ET.Type
499termToErrorType term =
508termToErrorType term =
500 case term of
509 case term of