@@ -1,438 +1,655 @@
1+{-# OPTIONS_GHC -Wall #-}
1module Type.Unify (unify) where
2module Type.Unify (unify) where
3−import Control.Applicative ((<|>))
4+import Control.Monad (zipWithM_)
4−import Control.Monad.Except (ExceptT, throwError, runExceptT)
5+import Control.Monad.Except (ExceptT, lift, liftIO, throwError, runExceptT)
5−import Control.Monad.State as State
6−import qualified Data.List as List
7import qualified Data.Map as Map
6import qualified Data.Map as Map
8import qualified Data.UnionFind.IO as UF
7import qualified Data.UnionFind.IO as UF
9−import Text.PrettyPrint (render)
11−import qualified AST.Type as AstType
12import qualified AST.Variable as Var
9import qualified AST.Variable as Var
13import qualified Reporting.Region as R
10import qualified Reporting.Region as R
14import qualified Reporting.Error.Type as Error
11import qualified Reporting.Error.Type as Error
15import qualified Type.State as TS
12import qualified Type.State as TS
16import Type.Type as Type
13import Type.Type as Type
17−import Type.PrettyPrint
14+
18−import Elm.Utils ((|>))
15+
20−
17+-- KICK OFF UNIFICATION
23− -> R.Region
20+unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
26− -> StateT TS.SolverState IO ()
27−unify hint region variable1 variable2 =
21+unify hint region expected actual =
28− do result <- runExceptT (unifyHelp variable1 variable2)
22+ do result <- runExceptT (guardedUnify ExpectedActual expected actual)
29 case result of
23 case result of
30 Right state ->
24 Right state ->
31 return state
25 return state
33− Left (RawMismatch (leftType, rightType, note)) ->
27+ Left (Mismatch subExpected subActual maybeReason) ->
30+ do expectedSrcType <- Type.toSrcType expected
31+ actualSrcType <- Type.toSrcType actual
32+ mergeHelp expected actual Error
33+ let info = Error.MismatchInfo hint expectedSrcType actualSrcType maybeReason
34+ return (Error.Mismatch info)
34− TS.addError region $ Error.Mismatch $
36+ TS.addError region =<< liftIO mkError
35− Error.MismatchInfo hint leftType rightType note
37+
38−-- ACTUALLY UNIFY STUFF
40+-- UNIFICATION HELPERS
40type Unify =
43type Unify =
41− ExceptT RawMismatch (StateT TS.SolverState IO)
44+ ExceptT Mismatch TS.Solver
47+data Context = Context
48+ { _orientation :: Orientation
50+ , _firstDesc :: Descriptor
51+ , _second :: Variable
52+ , _secondDesc :: Descriptor
56+data Orientation = ExpectedActual | ActualExpected
59+reorient :: Context -> Context
60+reorient (Context orientation var1 desc1 var2 desc2) =
64+ ExpectedActual -> ActualExpected
65+ ActualExpected -> ExpectedActual
67+ Context otherOrientation var2 desc2 var1 desc1
75+ = Mismatch Variable Variable (Maybe Error.Reason)
78+mismatch :: Context -> Maybe Error.Reason -> Unify a
79+mismatch (Context orientation first _ second _) maybeReason =
81+ (expected, actual, orientedReason) =
84+ (first, second, maybeReason)
87+ (second, first, Error.flipReason <$> maybeReason)
89+ throwError (Mismatch expected actual orientedReason)
44−newtype RawMismatch =
92+badRigid :: Maybe String -> Error.Reason
45− RawMismatch (AstType.Canonical, AstType.Canonical, Maybe String)
93+badRigid maybeName =
94+ Error.BadVar (Just (Error.Rigid maybeName)) Nothing
48−typeError
97+badSuper :: Super -> Error.Reason
49− :: UF.Point Descriptor
98+badSuper super =
50− -> UF.Point Descriptor
99+ Error.BadVar (Just (errorSuper super)) Nothing
53−typeError leftType rightType note =
54− do leftSrcType <- liftIO (Type.toSrcType leftType)
55− rightSrcType <- liftIO (Type.toSrcType rightType)
57− UF.setDescriptor leftType (Type.descriptor Error)
58− UF.setDescriptor rightType (Type.descriptor Error)
59− throwError (RawMismatch (leftSrcType, rightSrcType, note))
102+doubleBad :: Error.VarType -> Error.VarType -> Error.Reason
104+ Error.BadVar (Just vt1) (Just vt2)
107+errorSuper :: Super -> Error.VarType
127+merge :: Context -> Content -> Unify ()
128+merge (Context _ first _ second _) content =
129+ liftIO $ mergeHelp first second content
62−unifyHelp :: Variable -> Variable -> Unify ()
132+mergeHelp :: Variable -> Variable -> Content -> IO ()
63−unifyHelp variable1 variable2 =
133+mergeHelp first second content =
134+ UF.union' first second $ \desc1 desc2 ->
137+ { _content = content
138+ , _rank = min (_rank desc1) (_rank desc2)
144+fresh :: Context -> Content -> Unify Variable
145+fresh (Context _ _ desc1 _ desc2) content =
149+ { _content = content
150+ , _rank = min (_rank desc1) (_rank desc2)
154+ lift (TS.register freshVariable)
158+-- ACTUALLY UNIFY THINGS
161+guardedUnify :: Orientation -> Variable -> Variable -> Unify ()
162+guardedUnify orientation left right =
64− do equivalent <- liftIO $ UF.equivalent variable1 variable2
163+ do equivalent <- liftIO $ UF.equivalent left right
65 if equivalent
164 if equivalent
66− then return ()
165+ then return ()
67− else actuallyUnify variable1 variable2
166+ else
70−actuallyUnify :: Variable -> Variable -> Unify ()
71−actuallyUnify variable1 variable2 = do
72− desc1 <- liftIO $ UF.descriptor variable1
167+ do leftDesc <- liftIO $ UF.descriptor left
73− desc2 <- liftIO $ UF.descriptor variable2
168+ rightDesc <- liftIO $ UF.descriptor right
74− let (name', flex', rank', alias') = combinedDescriptors desc1 desc2
169+ actuallyUnify (Context orientation left leftDesc right rightDesc)
79− if rank desc1 < rank desc2
80− then UF.union variable2 variable1
81− else UF.union variable1 variable2
82− UF.modifyDescriptor variable1 $ \desc ->
83− desc { structure = structure desc1
92− if rank desc1 < rank desc2
93− then UF.union variable2 variable1
94− else UF.union variable1 variable2
95− UF.modifyDescriptor variable2 $ \desc ->
96− desc { structure = structure desc2
103− if rank desc1 < rank desc2 then merge1 else merge2
105− fresh :: Maybe (Term1 Variable) -> Unify Variable
107− do v <- liftIO . UF.fresh $ Descriptor
108− { structure = structure
116− lift (TS.register v)
119− do liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
120− unifyHelp variable1 variable2
122− unifyNumber svar (Var.Canonical home name) =
124− Var.BuiltIn | name `elem` ["Int","Float"] ->
127− Var.Local | List.isPrefixOf "number" name ->
130− Var.TopLevel _ | List.isPrefixOf "number" name ->
134− typeError variable1 variable2 Nothing
136− comparableError maybeHint =
137− typeError variable1 variable2 $ Just $
138− "Note: comparable types include Int, Float, Char, String, lists, and tuples."
139− ++ maybe "" ("\n"++) maybeHint
142− typeError variable1 variable2 $ Just $
143− "Note: appendable types include only Strings, Lists, and Text."
145− unifyComparable v (Var.Canonical home name) =
147− Var.BuiltIn | name `elem` ["Int","Float","Char","String"] ->
149− Var.Local | List.isPrefixOf "comparable" name ->
152− comparableError Nothing
154− unifyComparableStructure varSuper varFlex =
155− do struct <- liftIO $ collectApps varFlex
158− comparableError Nothing
161− do flexAndUnify varSuper
162− unifyHelp v =<< liftIO (variable $ Is Comparable)
165− if length vs > 6 then
166− comparableError $ Just $
167− "Furthermore, it cannot be a tuple with more than 6 elements."
169− do flexAndUnify varSuper
170− cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
171− zipWithM_ unifyHelp vs cmpVars
173− unifyAppendable v cvar@(Var.Canonical home name) =
176− Var.isPrim "String" cvar
178− || Var.isLocal (List.isPrefixOf "comparable") cvar
179− || Var.isLocal (List.isPrefixOf "appendable") cvar
186− unifyAppendableStructure varSuper varFlex =
187− do struct <- liftIO $ collectApps varFlex
189− List _ -> flexAndUnify varSuper
190− _ -> appendableError
193− typeError variable1 variable2 $ Just $
194− rigidErrorMessage (render (pretty Never var))
197− case (flex desc1, flex desc2, name desc1, name desc2) of
198− (Is super1, Is super2, _, _)
199− | super1 == super2 -> merge
200− (Is Number, Is Comparable, _, _) -> merge1
201− (Is Comparable, Is Number, _, _) -> merge2
203− (Is Number, _, _, Just name) -> unifyNumber variable1 name
204− (_, Is Number, Just name, _) -> unifyNumber variable2 name
206− (Is Appendable, _, _, Just name) -> unifyAppendable variable1 name
207− (_, Is Appendable, Just name, _) -> unifyAppendable variable2 name
208− (Is Appendable, _, _, _) -> unifyAppendableStructure variable1 variable2
209− (_, Is Appendable, _, _) -> unifyAppendableStructure variable2 variable1
211− (Is Comparable, _, _, Just name) -> unifyComparable variable1 name
212− (_, Is Comparable, Just name, _) -> unifyComparable variable2 name
213− (Is Comparable, _, _, _) -> unifyComparableStructure variable1 variable2
214− (_, Is Comparable, _, _) -> unifyComparableStructure variable2 variable1
216− (Rigid, _, _, _) -> rigidError variable1
217− (_, Rigid, _, _) -> rigidError variable2
218− _ -> typeError variable1 variable2 Nothing
220− case (structure desc1, structure desc2) of
222− | flex desc1 == Flexible && flex desc1 == Flexible ->
226− | flex desc1 == Flexible -> merge2
227− | flex desc1 == Error -> return ()
230− | flex desc2 == Flexible -> merge1
231− | flex desc2 == Error -> return ()
233− (Just (Var1 v), _) ->
234− unifyHelp v variable2
236− (_, Just (Var1 v)) ->
237− unifyHelp variable1 v
245− (Just type1, Just type2) ->
246− case (type1,type2) of
247− (App1 term1 term2, App1 term1' term2') ->
249− unifyHelp term1 term1'
250− unifyHelp term2 term2'
251− (Fun1 term1 term2, Fun1 term1' term2') ->
253− unifyHelp term1 term1'
254− unifyHelp term2 term2'
256− (EmptyRecord1, EmptyRecord1) ->
171+
257− return ()
172+subUnify :: Context -> Variable -> Variable -> Unify ()
258−
173+subUnify context var1 var2 =
259− (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp ext variable2
174+ guardedUnify (_orientation context) var1 var2
260− (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp variable1 ext
175+
262− (Record1 _ _, Record1 _ _) ->
177+actuallyUnify :: Context -> Unify ()
263− recordUnify fresh variable1 variable2
178+actuallyUnify context@(Context _ _ firstDesc _ secondDesc) =
265− _ -> typeError variable1 variable2 Nothing
180+ secondContent = _content secondDesc
270−rigidErrorMessage :: String -> String
271−rigidErrorMessage var =
272− "Could not unify user provided type variable `" ++ var ++ "`. The most likely cases are:\n\n"
273− ++ " 1. The type you wrote down is too general. It says any type can go through\n"
274− ++ " but in fact only a certain type can.\n"
275− ++ " 2. A type variable is probably being shared between two type annotations.\n"
276− ++ " They are treated as different things in the current implementation, so\n"
277− ++ " Try commenting out some type annotations and see what happens."
280−-- RECORD UNIFICATION
283− :: (Maybe (Term1 Variable) -> Unify Variable)
287−recordUnify fresh variable1 variable2 =
288− do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
289− (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
291− unifyOverlappingFields fields1 fields2
293− let freshRecord fields ext =
294− fresh (Just (Record1 fields ext))
296− let uniqueFields1 = diffFields fields1 fields2
297− let uniqueFields2 = diffFields fields2 fields1
299− let addFieldMismatchError missingFields =
300− typeError variable1 variable2 $ Just $
301− fieldMismatchError missingFields
303− case (ext1, ext2) of
304− (Empty _, Empty _) ->
305− case Map.null uniqueFields1 && Map.null uniqueFields2 of
307− False -> typeError variable1 variable2 Nothing
309− (Empty var1, Extension var2) ->
310− case (Map.null uniqueFields1, Map.null uniqueFields2) of
311− (_, False) -> addFieldMismatchError uniqueFields2
312− (True, True) -> unifyHelp var1 var2
314− do subRecord <- freshRecord uniqueFields1 var1
315− unifyHelp subRecord var2
317− (Extension var1, Empty var2) ->
318− case (Map.null uniqueFields1, Map.null uniqueFields2) of
319− (False, _) -> addFieldMismatchError uniqueFields1
320− (True, True) -> unifyHelp var1 var2
322− do subRecord <- freshRecord uniqueFields2 var2
323− unifyHelp var1 subRecord
325− (Extension var1, Extension var2) ->
326− case (Map.null uniqueFields1, Map.null uniqueFields2) of
331− do subRecord <- freshRecord uniqueFields2 var2
332− unifyHelp var1 subRecord
335− do subRecord <- freshRecord uniqueFields1 var1
336− unifyHelp subRecord var2
339− do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
340− record2' <- freshRecord uniqueFields2 =<< fresh Nothing
341− unifyHelp record1' var2
342− unifyHelp var1 record2'
345−unifyOverlappingFields
346− :: Map.Map String [Variable]
347− -> Map.Map String [Variable]
349−unifyOverlappingFields fields1 fields2 =
350− Map.intersectionWith (zipWith unifyHelp) fields1 fields2
356−diffFields :: Map.Map String [a] -> Map.Map String [a] -> Map.Map String [a]
357−diffFields fields1 fields2 =
358− let eat (_:xs) (_:ys) = eat xs ys
361− Map.union (Map.intersectionWith eat fields1 fields2) fields1
182+ case _content firstDesc of
362− |> Map.filter (not . null)
183+ Error ->
184+ -- If there was an error, just pretend it is okay. This lets us avoid
185+ -- "cascading" errors where one problem manifests as multiple message.
188+ Var Flex Nothing _ ->
189+ unifyFlex context secondContent
191+ Var Flex (Just super) _ ->
192+ unifySuper context super secondContent
194+ Var Rigid maybeSuper maybeName ->
195+ unifyRigid context maybeSuper maybeName secondContent
198+ unifyAtom context name secondContent
200+ Alias name args realVar ->
201+ unifyAlias context name args realVar secondContent
204+ unifyStructure context term secondContent
208+-- UNIFY FLEXIBLE VARIABLES
211+unifyFlex :: Context -> Content -> Unify ()
212+unifyFlex context otherContent =
213+ case otherContent of
218+ merge context otherContent
221+ merge context otherContent
224+ merge context otherContent
227+ merge context otherContent
230+ merge context otherContent
234+-- UNIFY RIGID VARIABLES
237+unifyRigid :: Context -> Maybe Super -> Maybe String -> Content -> Unify ()
238+unifyRigid context maybeSuper maybeName otherContent =
239+ case otherContent of
243+ Var Flex otherMaybeSuper _ ->
244+ if maybeSuper == otherMaybeSuper then
245+ merge context (Var Rigid maybeSuper maybeName)
247+ mismatch context (Just (badRigid maybeName))
249+ Var Rigid _ otherMaybeName ->
250+ mismatch context $ Just $
251+ doubleBad (Error.Rigid maybeName) (Error.Rigid otherMaybeName)
254+ mismatch context (Just (badRigid maybeName))
257+ mismatch context (Just (badRigid maybeName))
260+ mismatch context (Just (badRigid maybeName))
263+-- UNIFY SUPER VARIABLES
266+unifySuper :: Context -> Super -> Content -> Unify ()
267+unifySuper context super otherContent =
268+ case otherContent of
270+ unifySuperStructure context super term
273+ if atomMatchesSuper super name then
274+ merge context otherContent
276+ mismatch context (Just (badSuper super))
278+ Var Rigid Nothing maybeName ->
279+ mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
281+ Var Rigid (Just otherSuper) maybeName ->
282+ if super == otherSuper then
283+ merge context otherContent
285+ mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
287+ Var Flex Nothing _ ->
288+ merge context (Var Flex (Just super) Nothing)
290+ Var Flex (Just otherSuper) _ ->
291+ case combineSupers super otherSuper of
293+ mismatch context (Just reason)
296+ merge context (Var Flex (Just newSuper) Nothing)
298+ Alias _ _ realVar ->
299+ subUnify context (_first context) realVar
305+combineSupers :: Super -> Super -> Either Error.Reason Super
306+combineSupers firstSuper secondSuper =
307+ case (firstSuper, secondSuper) of
308+ (Number , Number ) -> Right Number
309+ (Comparable, Number ) -> Right Number
310+ (Number , Comparable) -> Right Number
312+ (Comparable, Comparable) -> Right Comparable
313+ (Appendable, Appendable) -> Right Appendable
315+ (Appendable, Comparable) -> Right CompAppend
316+ (Comparable, Appendable) -> Right CompAppend
318+ (CompAppend, CompAppend) -> Right CompAppend
319+ (CompAppend, Comparable) -> Right CompAppend
320+ (Comparable, CompAppend) -> Right CompAppend
321+ (CompAppend, Appendable) -> Right CompAppend
322+ (Appendable, CompAppend) -> Right CompAppend
325+ Left $ doubleBad (errorSuper firstSuper) (errorSuper secondSuper)
328+isPrimitiveFrom :: [String] -> Var.Canonical -> Bool
329+isPrimitiveFrom prims var =
330+ any (\p -> Var.isPrim p var) prims
365−data ExpandedRecord = ExpandedRecord
333+atomMatchesSuper :: Super -> Var.Canonical -> Bool
334+atomMatchesSuper super name =
337+ isPrimitiveFrom ["Int", "Float"] name
340+ isPrimitiveFrom ["Int", "Float", "Char", "String"] name
343+ Var.isPrim "String" name || Var.isText name
346+ Var.isPrim "String" name
349+unifySuperStructure :: Context -> Super -> Term1 Variable -> Unify ()
350+unifySuperStructure context super term =
351+ do appStructure <- liftIO (collectApps (Structure term))
352+ case appStructure of
354+ mismatch context (Just (badSuper super))
359+ mismatch context (Just (badSuper super))
362+ merge context (Structure term)
365+ do merge context (Structure term)
366+ unifyComparableRecursive (_orientation context) variable
369+ do merge context (Structure term)
370+ unifyComparableRecursive (_orientation context) variable
375+ mismatch context (Just (badSuper super))
378+ mismatch context (Just (badSuper super))
381+ if length entries > 6 then
382+ mismatch context (Just (Error.TooLongComparableTuple (length entries)))
385+ do merge context (Structure term)
386+ mapM_ (unifyComparableRecursive (_orientation context)) entries
389+ mismatch context (Just (badSuper super))
392+unifyComparableRecursive :: Orientation -> Variable -> Unify ()
393+unifyComparableRecursive orientation var =
396+ do desc <- UF.descriptor var
399+ { _content = Var Flex (Just Comparable) Nothing
400+ , _rank = _rank desc
405+ guardedUnify orientation compVar var
414+collectApps :: Content -> IO AppStructure
415+collectApps content =
416+ collectAppsHelp [] content
419+collectAppsHelp :: [Variable] -> Content -> IO AppStructure
420+collectAppsHelp args content =
421+ case (content, args) of
422+ (Structure (App1 func arg), _) ->
423+ collectAppsHelp (args ++ [arg]) =<< getContent func
425+ (Atom name, [arg]) | Var.isList name ->
428+ (Atom name, _) | Var.isTuple name ->
435+getContent :: Variable -> IO Content
436+getContent variable =
437+ _content <$> UF.descriptor variable
444+unifyAtom :: Context -> Var.Canonical -> Content -> Unify ()
445+unifyAtom context name otherContent =
446+ case otherContent of
450+ Var Flex Nothing _ ->
451+ merge context (Atom name)
453+ Var Flex (Just super) _ ->
454+ if atomMatchesSuper super name then
455+ merge context (Atom name)
458+ mismatch context (Just ((Error.flipReason (badSuper super))))
460+ Var Rigid _ maybeName ->
461+ mismatch context (Just (Error.flipReason (badRigid maybeName)))
464+ if name == otherName then
465+ merge context otherContent
469+ if isIntFloat name otherName || isIntFloat otherName name then
474+ Alias _ _ realVar ->
475+ subUnify context (_first context) realVar
478+ mismatch context Nothing
481+isIntFloat :: Var.Canonical -> Var.Canonical -> Bool
482+isIntFloat name otherName =
483+ Var.isPrim "Int" name && Var.isPrim "Float" otherName
489+unifyAlias :: Context -> Var.Canonical -> [(String, Variable)] -> Variable -> Content -> Unify ()
490+unifyAlias context name args realVar otherContent =
491+ case otherContent of
495+ Var Flex Nothing _ ->
496+ merge context (Alias name args realVar)
499+ subUnify context realVar (_second context)
502+ subUnify context realVar (_second context)
505+ Alias otherName otherArgs otherRealVar ->
506+ if name == otherName then
507+ do merge context otherContent
508+ zipWithM_ (subUnify context) (map snd args) (map snd otherArgs)
511+ subUnify context realVar otherRealVar
514+ subUnify context realVar (_second context)
521+unifyStructure :: Context -> Term1 Variable -> Content -> Unify ()
522+unifyStructure context term otherContent =
523+ case otherContent of
527+ Var Flex Nothing _ ->
528+ merge context (Structure term)
530+ Var Flex (Just super) _ ->
531+ unifySuper (reorient context) super (Structure term)
533+ Var Rigid _ maybeName ->
534+ mismatch context (Just (Error.flipReason (badRigid maybeName)))
537+ mismatch context Nothing
539+ Alias _ _ realVar ->
540+ subUnify context (_first context) realVar
542+ Structure otherTerm ->
543+ case (term, otherTerm) of
544+ (App1 func arg, App1 otherFunc otherArg) ->
545+ do subUnify context func otherFunc
546+ subUnify context arg otherArg
547+ merge context otherContent
549+ (Fun1 arg result, Fun1 otherArg otherResult) ->
550+ do subUnify context arg otherArg
551+ subUnify context result otherResult
552+ merge context otherContent
554+ (EmptyRecord1, EmptyRecord1) ->
555+ merge context otherContent
557+ (Record1 fields ext, EmptyRecord1) | Map.null fields ->
558+ subUnify context ext (_second context)
560+ (EmptyRecord1, Record1 fields ext) | Map.null fields ->
561+ subUnify context (_first context) ext
563+ (Record1 fields extension, Record1 otherFields otherExtension) ->
564+ do firstStructure <- gatherFields context fields extension
565+ secondStructure <- gatherFields context otherFields otherExtension
566+ unifyRecord context firstStructure secondStructure
569+ mismatch context Nothing
576+unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
577+unifyRecord context firstStructure secondStructure =
578+ do let (RecordStructure expFields expVar expStruct) = firstStructure
579+ let (RecordStructure actFields actVar actStruct) = secondStructure
581+ -- call after unifying extension, make sure record shape matches before
582+ -- looking into whether the particular field types match.
583+ let unifySharedFields otherFields ext =
584+ do let sharedFields = Map.intersectionWith (,) expFields actFields
585+ _ <- traverse (uncurry (subUnify context)) sharedFields
586+ let allFields = Map.union (Map.map fst sharedFields) otherFields
587+ merge context (Structure (Record1 allFields ext))
589+ let uniqueExpFields = Map.difference expFields actFields
590+ let uniqueActFields = Map.difference actFields expFields
592+ case (expStruct, Map.null uniqueExpFields, actStruct, Map.null uniqueActFields) of
593+ (_, True, _, True) ->
594+ do subUnify context expVar actVar
595+ unifySharedFields Map.empty expVar
597+ (Empty, _, _, False) ->
598+ mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
600+ (_, False, Empty, _) ->
601+ mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
603+ (_, False, _, True) ->
604+ do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
605+ subUnify context subRecord actVar
606+ unifySharedFields Map.empty subRecord
608+ (_, True, _, False) ->
609+ do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
610+ subUnify context expVar subRecord
611+ unifySharedFields Map.empty subRecord
613+ (Extension, False, Extension, False) ->
614+ do let subFields = Map.union uniqueExpFields uniqueActFields
615+ subExt <- fresh context (Var Flex Nothing Nothing)
616+ expRecord <- fresh context (Structure (Record1 uniqueActFields subExt))
617+ actRecord <- fresh context (Structure (Record1 uniqueExpFields subExt))
618+ subUnify context expVar expRecord
619+ subUnify context actRecord actVar
620+ unifySharedFields subFields subExt
624+-- GATHER RECORD STRUCTURE
627+data RecordStructure = RecordStructure
366− { _fields :: Map.Map String [Variable]
628+ { _fields :: Map.Map String Variable
367− , _extension :: Extension
629+ , _extVar :: Variable
630+ , _extStruct :: ExtensionStructure
370−data Extension = Empty Variable | Extension Variable
633+
634+data ExtensionStructure
373−gatherFields :: Variable -> IO ExpandedRecord
639+gatherFields :: Context -> Map.Map String Variable -> Variable -> Unify RecordStructure
374−gatherFields var =
640+gatherFields context fields variable =
375− do desc <- UF.descriptor var
641+ do desc <- liftIO (UF.descriptor variable)
376− case structure desc of
642+ case _content desc of
377− (Just (Record1 fields ext)) ->
643+ Structure (Record1 subFields subExt) ->
378− do (ExpandedRecord deeperFields rootExt) <- gatherFields ext
644+ gatherFields context (Map.union fields subFields) subExt
379− return (ExpandedRecord (Map.unionWith (++) fields deeperFields) rootExt)
381− (Just EmptyRecord1) ->
646+ Structure EmptyRecord1 ->
382− return (ExpandedRecord Map.empty (Empty var))
647+ return (RecordStructure fields variable Empty)
650+ -- TODO may be dropping useful alias info here
651+ gatherFields context fields var
385− return (ExpandedRecord Map.empty (Extension var))
654+ return (RecordStructure fields variable Extension)
388−-- assumes that one of the dicts has stuff in it
389−fieldMismatchError :: Map.Map String a -> String
390−fieldMismatchError missingFields =
391− case Map.keys missingFields of
394− "Looks like a record is missing the field `" ++ key ++ "`"
396− "Looks like a record is missing fields "
397− ++ List.intercalate ", " (init keys) ++ ", and " ++ last keys
403− -> (Maybe Var.Canonical, Flex, Int, Alias Variable)
404−combinedDescriptors desc1 desc2 =
405− (name', flex', rank', alias')
409− min (rank desc1) (rank desc2)
411− alias' :: Alias Variable
413− alias desc1 <|> alias desc2
415− name' :: Maybe Var.Canonical
417− case (name desc1, name desc2) of
418− (Just name1, Just name2) ->
419− case (flex desc1, flex desc2) of
420− (_, Flexible) -> Just name1
421− (Flexible, _) -> Just name2
422− (Is Number, Is _) -> Just name1
423− (Is _, Is Number) -> Just name2
424− (Is _, Is _) -> Just name1
426− (Just name1, _) -> Just name1
427− (_, Just name2) -> Just name2
432− case (flex desc1, flex desc2) of
435− (Is Number, Is _) -> Is Number
436− (Is _, Is Number) -> Is Number
437− (Is super, Is _) -> Is super