on master help sign in
Do a better job with typos in record access and update

Show the record type in a custom way, and suggest the closest field available.

commit28012458533df109f6c6d007b5d908cca2252c56 authorEvan Czaplicki <evancz@users.noreply.github.com> dateTue 24 Apr 2018, 00:12 (9 years ago) parentcce1029
1 file changed+98−33
compiler/src/Reporting/Error/Type.hs+98−33
compiler/src/Reporting/Error/Type.hs+98−33
@@ -26,13 +26,13 @@ import Data.Monoid ((<>))
2626import qualified AST.Canonical as Can
2727import qualified Data.Index as Index
2828import qualified Elm.Name as N
29−import qualified Reporting.Annotation as A
3029import qualified Reporting.Doc as D
3130import qualified Reporting.Region as R
3231import qualified Reporting.Render.Code as Code
3332import qualified Reporting.Render.Type as RT
3433import qualified Reporting.Render.Type.Localizer as L
3534import qualified Reporting.Report as Report
35+import qualified Reporting.Suggest as Suggest
3636import qualified Type.Error as T
3737
3838
@@ -429,8 +429,6 @@ problemsToHint problems =
429429problemToHint :: T.Problem -> [D.Doc]
430430problemToHint problem =
431431 case problem of
432− T.FieldMismatch _ _ -> [] -- TODO do a better job?
433−
434432 T.IntFloat ->
435433 [ D.fancyLink "Note" ["Read"] "implicit-casts"
436434 ["to","learn","why","Elm","does","not","implicitly","convert"
@@ -845,17 +843,28 @@ toExprReport source localizer exprRegion category tipe expected =
845843 )
846844
847845 RecordAccess field ->
848− badType $
849− case T.getFields tipe of
850− Just _fields ->
851− ( Just exprRegion
852− , "This record does not have a `" <> N.toString field <> "` field:"
853− , "It is"
854− , [ -- TODO suggest what the typo is!
855− ]
856− )
846+ case T.iteratedDealias tipe of
847+ T.Record fields ext ->
848+ custom (Just exprRegion)
849+ ( D.reflow $
850+ "This record does not have a `" <> N.toString field <> "` field:"
851+ , case Suggest.sort (N.toString field) (N.toString . fst) (Map.toList fields) of
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+ ]
863+ ]
864+ )
857865
858− Nothing ->
866+ _ ->
867+ badType
859868 ( Just exprRegion
860869 , "This is not a record, so it has no fields to access!"
861870 , "It is"
@@ -867,8 +876,46 @@ toExprReport source localizer exprRegion category tipe expected =
867876 )
868877
869878 RecordUpdateKeys record expectedFields ->
870− case T.getFields tipe of
871− Nothing ->
879+ case T.iteratedDealias tipe of
880+ T.Record actualFields ext ->
881+ case Map.lookupMin (Map.difference expectedFields actualFields) of
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+ _ ->
872919 badType
873920 ( Just exprRegion
874921 , "This is not a record, so it has no fields to update!"
@@ -877,21 +924,6 @@ toExprReport source localizer exprRegion category tipe expected =
877924 ]
878925 )
879926
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−
895927 RecordUpdateValue field ->
896928 mismatch
897929 ( Just exprRegion
@@ -928,9 +960,42 @@ countArgs tipe =
928960 0
929961
930962
931−addLocatedField :: N.Name -> Can.FieldUpdate -> [A.Located N.Name] -> [A.Located N.Name]
932−addLocatedField name (Can.FieldUpdate region _) names =
933− A.At region name : names
963+addAlias :: String -> T.Type -> (String -> String) -> D.Doc
964+addAlias noun tipe toMessage =
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)
934999
9351000
9361001