on master help sign in
Do a better job with typos in record access and update
2801245Evan Czaplicki
compiler/src/Reporting/Error/Type.hs+98−33
@@ -26,13 +26,13 @@ import Data.Monoid ((<>))
26import qualified AST.Canonical as Can
26import qualified AST.Canonical as Can
27import qualified Data.Index as Index
27import qualified Data.Index as Index
28import qualified Elm.Name as N
28import qualified Elm.Name as N
29−import qualified Reporting.Annotation as A
30import qualified Reporting.Doc as D
29import qualified Reporting.Doc as D
31import qualified Reporting.Region as R
30import qualified Reporting.Region as R
32import qualified Reporting.Render.Code as Code
31import qualified Reporting.Render.Code as Code
33import qualified Reporting.Render.Type as RT
32import qualified Reporting.Render.Type as RT
34import qualified Reporting.Render.Type.Localizer as L
33import qualified Reporting.Render.Type.Localizer as L
35import qualified Reporting.Report as Report
34import qualified Reporting.Report as Report
35+import qualified Reporting.Suggest as Suggest
36import qualified Type.Error as T
36import qualified Type.Error as T
37
37
38
38
@@ -429,8 +429,6 @@ problemsToHint problems =
429problemToHint :: T.Problem -> [D.Doc]
429problemToHint :: T.Problem -> [D.Doc]
430problemToHint problem =
430problemToHint problem =
431 case problem of
431 case problem of
432− T.FieldMismatch _ _ -> [] -- TODO do a better job?
433−
434 T.IntFloat ->
432 T.IntFloat ->
435 [ D.fancyLink "Note" ["Read"] "implicit-casts"
433 [ D.fancyLink "Note" ["Read"] "implicit-casts"
436 ["to","learn","why","Elm","does","not","implicitly","convert"
434 ["to","learn","why","Elm","does","not","implicitly","convert"
@@ -845,17 +843,28 @@ toExprReport source localizer exprRegion category tipe expected =
845 )
843 )
846
844
847 RecordAccess field ->
845 RecordAccess field ->
848− badType $
849− case T.getFields tipe of
846+ case T.iteratedDealias tipe of
850− Just _fields ->
847+ T.Record fields ext ->
851− ( Just exprRegion
848+ custom (Just exprRegion)
849+ ( D.reflow $
852− , "This record does not have a `" <> N.toString field <> "` field:"
850+ "This record does not have a `" <> N.toString field <> "` field:"
853− , "It is"
851+ , case Suggest.sort (N.toString field) (N.toString . fst) (Map.toList fields) of
854− , [ -- TODO suggest what the typo is!
852+ [] ->
853+ D.reflow "In fact, it is a record with NO fields!"
854+
855+ f:fs ->
856+ D.stack
857+ [ addAlias "record" tipe (\noun -> "It is a " <> noun <> " with fields:")
858+ , toNearbyRecord localizer f fs ext
859+ , D.fillSep
860+ ["So","instead","of",D.dullyellow (D.fromName field) <> ","
861+ ,"maybe","you","want",D.green (D.fromName (fst f)) <> "?"
862+ ]
855− ]
863+ ]
856− )
864+ )
857
865
858− Nothing ->
866+ _ ->
867+ badType
859 ( Just exprRegion
868 ( Just exprRegion
860 , "This is not a record, so it has no fields to access!"
869 , "This is not a record, so it has no fields to access!"
861 , "It is"
870 , "It is"
@@ -867,8 +876,46 @@ toExprReport source localizer exprRegion category tipe expected =
867 )
876 )
868
877
869 RecordUpdateKeys record expectedFields ->
878 RecordUpdateKeys record expectedFields ->
870− case T.getFields tipe of
879+ case T.iteratedDealias tipe of
880+ T.Record actualFields ext ->
881+ case Map.lookupMin (Map.difference expectedFields actualFields) of
871− Nothing ->
882+ Nothing ->
883+ mismatch
884+ ( Nothing
885+ , "Something is off with this record update:"
886+ , "The `" <> N.toString record <> "` record is"
887+ , \_ -> "But this update needs it to be compatable with:"
888+ , [ D.reflow
889+ "Do you mind creating an <http://sscce.org/> that produces this error message and\
890+ \ sharing it at <https://github.com/elm-lang/error-message-catalog/issues> so we\
891+ \ can try to give better advice here?"
892+ ]
893+ )
894+
895+ Just (field, Can.FieldUpdate fieldRegion _) ->
896+ let
897+ rStr = "`" <> N.toString record <> "`"
898+ fStr = "`" <> N.toString field <> "`"
899+ in
900+ custom (Just fieldRegion)
901+ ( D.reflow $
902+ "The " <> rStr <> " record does not have a " <> fStr <> " field:"
903+ , case Suggest.sort (N.toString field) (N.toString . fst) (Map.toList actualFields) of
904+ [] ->
905+ D.reflow $ "In fact, " <> rStr <> " is a record with NO fields!"
906+
907+ f:fs ->
908+ D.stack
909+ [ addAlias "record" tipe (\noun -> rStr <> " is a " <> noun <> " with fields:")
910+ , toNearbyRecord localizer f fs ext
911+ , D.fillSep
912+ ["So","instead","of",D.dullyellow (D.fromName field) <> ","
913+ ,"maybe","you","want",D.green (D.fromName (fst f)) <> "?"
914+ ]
915+ ]
916+ )
917+
918+ _ ->
872 badType
919 badType
873 ( Just exprRegion
920 ( Just exprRegion
874 , "This is not a record, so it has no fields to update!"
921 , "This is not a record, so it has no fields to update!"
@@ -877,21 +924,6 @@ toExprReport source localizer exprRegion category tipe expected =
877 ]
924 ]
878 )
925 )
879
926
880− Just actualFields ->
881− case Map.foldrWithKey addLocatedField [] (Map.difference expectedFields actualFields) of
882− [] ->
883− error "TODO RecordUpdateKeys"
884−
885− A.At fieldRegion field : _ ->
886− badType
887− ( Just fieldRegion
888− , "The `" <> N.toString record <> "` record does not have a `" <> N.toString field <> "` field:"
889− , "The `" <> N.toString record <> "` is"
890− , [ D.reflow $ "So maybe you want one of these fields instead? TODO make suggestions!"
891− -- TODO suggest what the typo is!
892− ]
893− )
894−
895 RecordUpdateValue field ->
927 RecordUpdateValue field ->
896 mismatch
928 mismatch
897 ( Just exprRegion
929 ( Just exprRegion
@@ -928,9 +960,42 @@ countArgs tipe =
928 0
960 0
929
961
930
962
931−addLocatedField :: N.Name -> Can.FieldUpdate -> [A.Located N.Name] -> [A.Located N.Name]
963+addAlias :: String -> T.Type -> (String -> String) -> D.Doc
932−addLocatedField name (Can.FieldUpdate region _) names =
964+addAlias noun tipe toMessage =
933− A.At region name : names
965+ case tipe of
966+ T.Alias _ name _ _ ->
967+ D.reflow (toMessage ("`" <> N.toString name <> "`"))
968+
969+ _ ->
970+ D.reflow (toMessage noun)
971+
972+
973+
974+-- FIELD NAME HELPERS
975+
976+
977+toNearbyRecord :: L.Localizer -> (N.Name, T.Type) -> [(N.Name, T.Type)] -> T.Extension -> D.Doc
978+toNearbyRecord localizer f fs ext =
979+ D.indent 4 $
980+ if length fs <= 3 then
981+ RT.record (map (fieldToDocs localizer) (f:fs)) (extToDoc ext)
982+ else
983+ RT.recordSnippet (fieldToDocs localizer f) (map (fieldToDocs localizer) (take 3 fs))
984+
985+
986+fieldToDocs :: L.Localizer -> (N.Name, T.Type) -> (D.Doc, D.Doc)
987+fieldToDocs localizer (name, tipe) =
988+ ( D.fromName name
989+ , T.toDoc localizer RT.None tipe
990+ )
991+
992+
993+extToDoc :: T.Extension -> Maybe D.Doc
994+extToDoc ext =
995+ case ext of
996+ T.Closed -> Nothing
997+ T.FlexOpen x -> Just (D.fromName x)
998+ T.RigidOpen x -> Just (D.fromName x)
934
999
935
1000
936
1001