on master help sign in
Better errors for large record types

Before, we just went until any field caused a problem. If it was an early field, there may be 10 more that all match, but have not been unified. The result was that the *looked* different in the type diff, but it was all visual noise. So this version unifies all fields no matter what. In simple cases, this makes the type errors much more specific. I can imagine it getting things “wrong” in more complex scenarios if a wrong field is taken as true, causing an error in a subsequent field. Then that gets cut out of the diff or something. Maybe should make a note about that possibility.

commitdd084ff95777191db4079ccb5921f829fc007948 authorEvan Czaplicki <evancz@users.noreply.github.com> dateMon 8 Aug 2016, 18:07 (10 years ago) parentecd68b3
2 files changed+36−2
src/Reporting/Error/Type.hs+11−1 src/Type/Unify.hs+25−1
src/Reporting/Error/Type.hs+11−1
@@ -36,7 +36,8 @@ data Mismatch = MismatchInfo
3636
3737
3838data Reason
39− = MessyFields [String] [String]
39+ = BadFields [String]
40+ | MessyFields [String] [String]
4041 | IntFloat
4142 | TooLongComparableTuple Int
4243 | MissingArgs Int
@@ -583,6 +584,9 @@ funcName maybeVar =
583584flipReason :: Reason -> Reason
584585flipReason reason =
585586 case reason of
587+ BadFields fields ->
588+ BadFields fields
589+
586590 MessyFields leftOnly rightOnly ->
587591 MessyFields rightOnly leftOnly
588592
@@ -606,6 +610,12 @@ reasonToString reason =
606610 Just (toHint msg)
607611 in
608612 case reason of
613+ BadFields [field] ->
614+ go $ "It looks like a problem with the `" ++ field ++ "` field."
615+
616+ BadFields fields ->
617+ go $ "I found problems in these fields: " ++ Help.commaSep fields
618+
609619 MessyFields leftOnly rightOnly ->
610620 do let typos = Help.findPotentialTypos leftOnly rightOnly
611621 _ <- Help.vetTypos typos
src/Type/Unify.hs+25−1
@@ -4,6 +4,7 @@ module Type.Unify (unify) where
44import Control.Monad (zipWithM_)
55import Control.Monad.Except (ExceptT, lift, liftIO, throwError, runExceptT)
66import qualified Data.Map as Map
7+import qualified Data.Maybe as Maybe
78import qualified Data.UnionFind.IO as UF
89
910import qualified AST.Variable as Var
@@ -616,7 +617,7 @@ unifyRecord context firstStructure secondStructure =
616617 -- looking into whether the particular field types match.
617618 let unifySharedFields otherFields ext =
618619 do let sharedFields = Map.intersectionWith (,) expFields actFields
619− _ <- traverse (uncurry (subUnify context)) sharedFields
620+ unifySharedFieldsHelp context sharedFields
620621 let allFields = Map.union (Map.map fst sharedFields) otherFields
621622 merge context (Structure (Record1 allFields ext))
622623
@@ -655,6 +656,29 @@ unifyRecord context firstStructure secondStructure =
655656
656657
657658
659+unifySharedFieldsHelp :: Context -> Map.Map String (Variable, Variable) -> Unify ()
660+unifySharedFieldsHelp context sharedFields =
661+ do maybeBadFields <- traverse (unifyField context) (Map.toList sharedFields)
662+ case Maybe.catMaybes maybeBadFields of
663+ [] ->
664+ return ()
665+
666+ badFields ->
667+ mismatch context (Just (Error.BadFields (reverse badFields)))
668+
669+
670+unifyField :: Context -> (String, (Variable, Variable)) -> Unify (Maybe String)
671+unifyField context (field, (expected, actual)) =
672+ do result <- lift $ runExceptT $ subUnify context expected actual
673+ case result of
674+ Right () ->
675+ return $ Nothing
676+
677+ Left _ ->
678+ return $ Just field
679+
680+
681+
658682-- GATHER RECORD STRUCTURE
659683
660684