@@ -1,438 +1,655 @@
1+{-# OPTIONS_GHC -Wall #-}
12module Type.Unify (unify) where
23
3−import Control.Applicative ((<|>))
4−import Control.Monad.Except (ExceptT, throwError, runExceptT)
5−import Control.Monad.State as State
6−import qualified Data.List as List
4+import Control.Monad (zipWithM_)
5+import Control.Monad.Except (ExceptT, lift, liftIO, throwError, runExceptT)
76import qualified Data.Map as Map
87import qualified Data.UnionFind.IO as UF
9−import Text.PrettyPrint (render)
108
11−import qualified AST.Type as AstType
129import qualified AST.Variable as Var
1310import qualified Reporting.Region as R
1411import qualified Reporting.Error.Type as Error
1512import qualified Type.State as TS
1613import Type.Type as Type
17−import Type.PrettyPrint
18−import Elm.Utils ((|>))
19−
20−
21−unify
22− :: Error.Hint
23− -> R.Region
24− -> Variable
25− -> Variable
26− -> StateT TS.SolverState IO ()
27−unify hint region variable1 variable2 =
28− do result <- runExceptT (unifyHelp variable1 variable2)
14+
15+
16+
17+-- KICK OFF UNIFICATION
18+
19+
20+unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
21+unify hint region expected actual =
22+ do result <- runExceptT (guardedUnify ExpectedActual expected actual)
2923 case result of
3024 Right state ->
3125 return state
3226
33− Left (RawMismatch (leftType, rightType, note)) ->
34− TS.addError region $ Error.Mismatch $
35− Error.MismatchInfo hint leftType rightType note
27+ Left (Mismatch subExpected subActual maybeReason) ->
28+ let
29+ mkError =
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)
35+ in
36+ TS.addError region =<< liftIO mkError
37+
3638
3739
38−-- ACTUALLY UNIFY STUFF
40+-- UNIFICATION HELPERS
41+
3942
4043type Unify =
41− ExceptT RawMismatch (StateT TS.SolverState IO)
44+ ExceptT Mismatch TS.Solver
45+
46+
47+data Context = Context
48+ { _orientation :: Orientation
49+ , _first :: Variable
50+ , _firstDesc :: Descriptor
51+ , _second :: Variable
52+ , _secondDesc :: Descriptor
53+ }
54+
55+
56+data Orientation = ExpectedActual | ActualExpected
57+
58+
59+reorient :: Context -> Context
60+reorient (Context orientation var1 desc1 var2 desc2) =
61+ let
62+ otherOrientation =
63+ case orientation of
64+ ExpectedActual -> ActualExpected
65+ ActualExpected -> ExpectedActual
66+ in
67+ Context otherOrientation var2 desc2 var1 desc1
68+
69+
70+
71+-- ERROR MESSAGES
72+
73+
74+data Mismatch
75+ = Mismatch Variable Variable (Maybe Error.Reason)
76+
77+
78+mismatch :: Context -> Maybe Error.Reason -> Unify a
79+mismatch (Context orientation first _ second _) maybeReason =
80+ let
81+ (expected, actual, orientedReason) =
82+ case orientation of
83+ ExpectedActual ->
84+ (first, second, maybeReason)
85+
86+ ActualExpected ->
87+ (second, first, Error.flipReason <$> maybeReason)
88+ in
89+ throwError (Mismatch expected actual orientedReason)
4290
4391
44−newtype RawMismatch =
45− RawMismatch (AstType.Canonical, AstType.Canonical, Maybe String)
92+badRigid :: Maybe String -> Error.Reason
93+badRigid maybeName =
94+ Error.BadVar (Just (Error.Rigid maybeName)) Nothing
4695
4796
48−typeError
49− :: UF.Point Descriptor
50− -> UF.Point Descriptor
51− -> Maybe String
52− -> Unify a
53−typeError leftType rightType note =
54− do leftSrcType <- liftIO (Type.toSrcType leftType)
55− rightSrcType <- liftIO (Type.toSrcType rightType)
56− liftIO $ do
57− UF.setDescriptor leftType (Type.descriptor Error)
58− UF.setDescriptor rightType (Type.descriptor Error)
59− throwError (RawMismatch (leftSrcType, rightSrcType, note))
97+badSuper :: Super -> Error.Reason
98+badSuper super =
99+ Error.BadVar (Just (errorSuper super)) Nothing
60100
61101
62−unifyHelp :: Variable -> Variable -> Unify ()
63−unifyHelp variable1 variable2 =
64− do equivalent <- liftIO $ UF.equivalent variable1 variable2
102+doubleBad :: Error.VarType -> Error.VarType -> Error.Reason
103+doubleBad vt1 vt2 =
104+ Error.BadVar (Just vt1) (Just vt2)
105+
106+
107+errorSuper :: Super -> Error.VarType
108+errorSuper super =
109+ case super of
110+ Number ->
111+ Error.Number
112+
113+ Comparable ->
114+ Error.Comparable
115+
116+ Appendable ->
117+ Error.Appendable
118+
119+ CompAppend ->
120+ Error.CompAppend
121+
122+
123+
124+-- MERGE
125+
126+
127+merge :: Context -> Content -> Unify ()
128+merge (Context _ first _ second _) content =
129+ liftIO $ mergeHelp first second content
130+
131+
132+mergeHelp :: Variable -> Variable -> Content -> IO ()
133+mergeHelp first second content =
134+ UF.union' first second $ \desc1 desc2 ->
135+ return $
136+ Descriptor
137+ { _content = content
138+ , _rank = min (_rank desc1) (_rank desc2)
139+ , _mark = noMark
140+ , _copy = Nothing
141+ }
142+
143+
144+fresh :: Context -> Content -> Unify Variable
145+fresh (Context _ _ desc1 _ desc2) content =
146+ do freshVariable <-
147+ liftIO $ UF.fresh $
148+ Descriptor
149+ { _content = content
150+ , _rank = min (_rank desc1) (_rank desc2)
151+ , _mark = noMark
152+ , _copy = Nothing
153+ }
154+ lift (TS.register freshVariable)
155+
156+
157+
158+-- ACTUALLY UNIFY THINGS
159+
160+
161+guardedUnify :: Orientation -> Variable -> Variable -> Unify ()
162+guardedUnify orientation left right =
163+ do equivalent <- liftIO $ UF.equivalent left right
65164 if equivalent
66− then return ()
67− else actuallyUnify variable1 variable2
68−
69−
70−actuallyUnify :: Variable -> Variable -> Unify ()
71−actuallyUnify variable1 variable2 = do
72− desc1 <- liftIO $ UF.descriptor variable1
73− desc2 <- liftIO $ UF.descriptor variable2
74− let (name', flex', rank', alias') = combinedDescriptors desc1 desc2
75−
76− merge1 :: Unify ()
77− merge1 =
78− liftIO $ do
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
84− , flex = flex'
85− , name = name'
86− , alias = alias'
87− }
88−
89− merge2 :: Unify ()
90− merge2 =
91− liftIO $ do
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
97− , flex = flex'
98− , name = name'
99− , alias = alias'
100− }
101−
102− merge =
103− if rank desc1 < rank desc2 then merge1 else merge2
104−
105− fresh :: Maybe (Term1 Variable) -> Unify Variable
106− fresh structure =
107− do v <- liftIO . UF.fresh $ Descriptor
108− { structure = structure
109− , rank = rank'
110− , flex = flex'
111− , name = name'
112− , copy = Nothing
113− , mark = noMark
114− , alias = alias'
115− }
116− lift (TS.register v)
117−
118− flexAndUnify v =
119− do liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
120− unifyHelp variable1 variable2
121−
122− unifyNumber svar (Var.Canonical home name) =
123− case home of
124− Var.BuiltIn | name `elem` ["Int","Float"] ->
125− flexAndUnify svar
126−
127− Var.Local | List.isPrefixOf "number" name ->
128− flexAndUnify svar
129−
130− Var.TopLevel _ | List.isPrefixOf "number" name ->
131− flexAndUnify svar
132−
133− _ ->
134− typeError variable1 variable2 Nothing
135−
136− comparableError maybeHint =
137− typeError variable1 variable2 $ Just $
138− "Note: comparable types include Int, Float, Char, String, lists, and tuples."
139− ++ maybe "" ("\n"++) maybeHint
140−
141− appendableError =
142− typeError variable1 variable2 $ Just $
143− "Note: appendable types include only Strings, Lists, and Text."
144−
145− unifyComparable v (Var.Canonical home name) =
146− case home of
147− Var.BuiltIn | name `elem` ["Int","Float","Char","String"] ->
148− flexAndUnify v
149− Var.Local | List.isPrefixOf "comparable" name ->
150− flexAndUnify v
151− _ ->
152− comparableError Nothing
153−
154− unifyComparableStructure varSuper varFlex =
155− do struct <- liftIO $ collectApps varFlex
156− case struct of
157− Other ->
158− comparableError Nothing
159−
160− List v ->
161− do flexAndUnify varSuper
162− unifyHelp v =<< liftIO (variable $ Is Comparable)
163−
164− Tuple vs ->
165− if length vs > 6 then
166− comparableError $ Just $
167− "Furthermore, it cannot be a tuple with more than 6 elements."
168− else
169− do flexAndUnify varSuper
170− cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
171− zipWithM_ unifyHelp vs cmpVars
172−
173− unifyAppendable v cvar@(Var.Canonical home name) =
174− let
175− canUnify =
176− Var.isPrim "String" cvar
177− || Var.isText cvar
178− || Var.isLocal (List.isPrefixOf "comparable") cvar
179− || Var.isLocal (List.isPrefixOf "appendable") cvar
180− in
181− if canUnify then
182− flexAndUnify v
183− else
184− appendableError
185−
186− unifyAppendableStructure varSuper varFlex =
187− do struct <- liftIO $ collectApps varFlex
188− case struct of
189− List _ -> flexAndUnify varSuper
190− _ -> appendableError
191−
192− rigidError var =
193− typeError variable1 variable2 $ Just $
194− rigidErrorMessage (render (pretty Never var))
195−
196− superUnify =
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
202−
203− (Is Number, _, _, Just name) -> unifyNumber variable1 name
204− (_, Is Number, Just name, _) -> unifyNumber variable2 name
205−
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
210−
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
215−
216− (Rigid, _, _, _) -> rigidError variable1
217− (_, Rigid, _, _) -> rigidError variable2
218− _ -> typeError variable1 variable2 Nothing
219−
220− case (structure desc1, structure desc2) of
221− (Nothing, Nothing)
222− | flex desc1 == Flexible && flex desc1 == Flexible ->
223− merge
224−
225− (Nothing, _)
226− | flex desc1 == Flexible -> merge2
227− | flex desc1 == Error -> return ()
228−
229− (_, Nothing)
230− | flex desc2 == Flexible -> merge1
231− | flex desc2 == Error -> return ()
232−
233− (Just (Var1 v), _) ->
234− unifyHelp v variable2
235−
236− (_, Just (Var1 v)) ->
237− unifyHelp variable1 v
238−
239− (Nothing, _) ->
240− superUnify
241−
242− (_, Nothing) ->
243− superUnify
244−
245− (Just type1, Just type2) ->
246− case (type1,type2) of
247− (App1 term1 term2, App1 term1' term2') ->
248− do merge
249− unifyHelp term1 term1'
250− unifyHelp term2 term2'
251− (Fun1 term1 term2, Fun1 term1' term2') ->
252− do merge
253− unifyHelp term1 term1'
254− unifyHelp term2 term2'
165+ then return ()
166+ else
167+ do leftDesc <- liftIO $ UF.descriptor left
168+ rightDesc <- liftIO $ UF.descriptor right
169+ actuallyUnify (Context orientation left leftDesc right rightDesc)
255170
256− (EmptyRecord1, EmptyRecord1) ->
257− return ()
258−
259− (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp ext variable2
260− (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp variable1 ext
261−
262− (Record1 _ _, Record1 _ _) ->
263− recordUnify fresh variable1 variable2
264−
265− _ -> typeError variable1 variable2 Nothing
266−
267−
268−-- RIGID ERROR
269−
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."
278−
279−
280−-- RECORD UNIFICATION
281−
282−recordUnify
283− :: (Maybe (Term1 Variable) -> Unify Variable)
284− -> Variable
285− -> Variable
286− -> Unify ()
287−recordUnify fresh variable1 variable2 =
288− do (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
289− (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
290−
291− unifyOverlappingFields fields1 fields2
292−
293− let freshRecord fields ext =
294− fresh (Just (Record1 fields ext))
295−
296− let uniqueFields1 = diffFields fields1 fields2
297− let uniqueFields2 = diffFields fields2 fields1
298−
299− let addFieldMismatchError missingFields =
300− typeError variable1 variable2 $ Just $
301− fieldMismatchError missingFields
302−
303− case (ext1, ext2) of
304− (Empty _, Empty _) ->
305− case Map.null uniqueFields1 && Map.null uniqueFields2 of
306− True -> return ()
307− False -> typeError variable1 variable2 Nothing
308−
309− (Empty var1, Extension var2) ->
310− case (Map.null uniqueFields1, Map.null uniqueFields2) of
311− (_, False) -> addFieldMismatchError uniqueFields2
312− (True, True) -> unifyHelp var1 var2
313− (False, True) ->
314− do subRecord <- freshRecord uniqueFields1 var1
315− unifyHelp subRecord var2
316−
317− (Extension var1, Empty var2) ->
318− case (Map.null uniqueFields1, Map.null uniqueFields2) of
319− (False, _) -> addFieldMismatchError uniqueFields1
320− (True, True) -> unifyHelp var1 var2
321− (True, False) ->
322− do subRecord <- freshRecord uniqueFields2 var2
323− unifyHelp var1 subRecord
324−
325− (Extension var1, Extension var2) ->
326− case (Map.null uniqueFields1, Map.null uniqueFields2) of
327− (True, True) ->
328− unifyHelp var1 var2
329−
330− (True, False) ->
331− do subRecord <- freshRecord uniqueFields2 var2
332− unifyHelp var1 subRecord
333−
334− (False, True) ->
335− do subRecord <- freshRecord uniqueFields1 var1
336− unifyHelp subRecord var2
337−
338− (False, False) ->
339− do record1' <- freshRecord uniqueFields1 =<< fresh Nothing
340− record2' <- freshRecord uniqueFields2 =<< fresh Nothing
341− unifyHelp record1' var2
342− unifyHelp var1 record2'
343−
344−
345−unifyOverlappingFields
346− :: Map.Map String [Variable]
347− -> Map.Map String [Variable]
348− -> Unify ()
349−unifyOverlappingFields fields1 fields2 =
350− Map.intersectionWith (zipWith unifyHelp) fields1 fields2
351− |> Map.elems
352− |> concat
353− |> sequence_
354−
355−
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
359− eat xs _ = xs
171+
172+subUnify :: Context -> Variable -> Variable -> Unify ()
173+subUnify context var1 var2 =
174+ guardedUnify (_orientation context) var1 var2
175+
176+
177+actuallyUnify :: Context -> Unify ()
178+actuallyUnify context@(Context _ _ firstDesc _ secondDesc) =
179+ let
180+ secondContent = _content secondDesc
360181 in
361− Map.union (Map.intersectionWith eat fields1 fields2) fields1
362− |> Map.filter (not . null)
182+ case _content firstDesc of
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.
186+ return ()
187+
188+ Var Flex Nothing _ ->
189+ unifyFlex context secondContent
190+
191+ Var Flex (Just super) _ ->
192+ unifySuper context super secondContent
193+
194+ Var Rigid maybeSuper maybeName ->
195+ unifyRigid context maybeSuper maybeName secondContent
196+
197+ Atom name ->
198+ unifyAtom context name secondContent
199+
200+ Alias name args realVar ->
201+ unifyAlias context name args realVar secondContent
202+
203+ Structure term ->
204+ unifyStructure context term secondContent
205+
206+
207+
208+-- UNIFY FLEXIBLE VARIABLES
209+
210+
211+unifyFlex :: Context -> Content -> Unify ()
212+unifyFlex context otherContent =
213+ case otherContent of
214+ Error ->
215+ return ()
216+
217+ Var Flex _ _ ->
218+ merge context otherContent
219+
220+ Var Rigid _ _ ->
221+ merge context otherContent
222+
223+ Atom _ ->
224+ merge context otherContent
225+
226+ Alias _ _ _ ->
227+ merge context otherContent
228+
229+ Structure _ ->
230+ merge context otherContent
231+
232+
233+
234+-- UNIFY RIGID VARIABLES
235+
236+
237+unifyRigid :: Context -> Maybe Super -> Maybe String -> Content -> Unify ()
238+unifyRigid context maybeSuper maybeName otherContent =
239+ case otherContent of
240+ Error ->
241+ return ()
242+
243+ Var Flex otherMaybeSuper _ ->
244+ if maybeSuper == otherMaybeSuper then
245+ merge context (Var Rigid maybeSuper maybeName)
246+ else
247+ mismatch context (Just (badRigid maybeName))
248+
249+ Var Rigid _ otherMaybeName ->
250+ mismatch context $ Just $
251+ doubleBad (Error.Rigid maybeName) (Error.Rigid otherMaybeName)
252+
253+ Atom _ ->
254+ mismatch context (Just (badRigid maybeName))
255+
256+ Alias _ _ _ ->
257+ mismatch context (Just (badRigid maybeName))
258+
259+ Structure _ ->
260+ mismatch context (Just (badRigid maybeName))
261+
262+
263+-- UNIFY SUPER VARIABLES
264+
265+
266+unifySuper :: Context -> Super -> Content -> Unify ()
267+unifySuper context super otherContent =
268+ case otherContent of
269+ Structure term ->
270+ unifySuperStructure context super term
271+
272+ Atom name ->
273+ if atomMatchesSuper super name then
274+ merge context otherContent
275+ else
276+ mismatch context (Just (badSuper super))
277+
278+ Var Rigid Nothing maybeName ->
279+ mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
280+
281+ Var Rigid (Just otherSuper) maybeName ->
282+ if super == otherSuper then
283+ merge context otherContent
284+ else
285+ mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
286+
287+ Var Flex Nothing _ ->
288+ merge context (Var Flex (Just super) Nothing)
289+
290+ Var Flex (Just otherSuper) _ ->
291+ case combineSupers super otherSuper of
292+ Left reason ->
293+ mismatch context (Just reason)
294+
295+ Right newSuper ->
296+ merge context (Var Flex (Just newSuper) Nothing)
297+
298+ Alias _ _ realVar ->
299+ subUnify context (_first context) realVar
300+
301+ Error ->
302+ return ()
303+
304+
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
311+
312+ (Comparable, Comparable) -> Right Comparable
313+ (Appendable, Appendable) -> Right Appendable
314+
315+ (Appendable, Comparable) -> Right CompAppend
316+ (Comparable, Appendable) -> Right CompAppend
317+
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
323+
324+ (_ , _ ) ->
325+ Left $ doubleBad (errorSuper firstSuper) (errorSuper secondSuper)
326+
327+
328+isPrimitiveFrom :: [String] -> Var.Canonical -> Bool
329+isPrimitiveFrom prims var =
330+ any (\p -> Var.isPrim p var) prims
363331
364332
365−data ExpandedRecord = ExpandedRecord
366− { _fields :: Map.Map String [Variable]
367− , _extension :: Extension
333+atomMatchesSuper :: Super -> Var.Canonical -> Bool
334+atomMatchesSuper super name =
335+ case super of
336+ Number ->
337+ isPrimitiveFrom ["Int", "Float"] name
338+
339+ Comparable ->
340+ isPrimitiveFrom ["Int", "Float", "Char", "String"] name
341+
342+ Appendable ->
343+ Var.isPrim "String" name || Var.isText name
344+
345+ CompAppend ->
346+ Var.isPrim "String" name
347+
348+
349+unifySuperStructure :: Context -> Super -> Term1 Variable -> Unify ()
350+unifySuperStructure context super term =
351+ do appStructure <- liftIO (collectApps (Structure term))
352+ case appStructure of
353+ Other ->
354+ mismatch context (Just (badSuper super))
355+
356+ List variable ->
357+ case super of
358+ Number ->
359+ mismatch context (Just (badSuper super))
360+
361+ Appendable ->
362+ merge context (Structure term)
363+
364+ Comparable ->
365+ do merge context (Structure term)
366+ unifyComparableRecursive (_orientation context) variable
367+
368+ CompAppend ->
369+ do merge context (Structure term)
370+ unifyComparableRecursive (_orientation context) variable
371+
372+ Tuple entries ->
373+ case super of
374+ Number ->
375+ mismatch context (Just (badSuper super))
376+
377+ Appendable ->
378+ mismatch context (Just (badSuper super))
379+
380+ Comparable ->
381+ if length entries > 6 then
382+ mismatch context (Just (Error.TooLongComparableTuple (length entries)))
383+
384+ else
385+ do merge context (Structure term)
386+ mapM_ (unifyComparableRecursive (_orientation context)) entries
387+
388+ CompAppend ->
389+ mismatch context (Just (badSuper super))
390+
391+
392+unifyComparableRecursive :: Orientation -> Variable -> Unify ()
393+unifyComparableRecursive orientation var =
394+ do compVar <-
395+ liftIO $
396+ do desc <- UF.descriptor var
397+ UF.fresh $
398+ Descriptor
399+ { _content = Var Flex (Just Comparable) Nothing
400+ , _rank = _rank desc
401+ , _mark = noMark
402+ , _copy = Nothing
403+ }
404+
405+ guardedUnify orientation compVar var
406+
407+
408+data AppStructure
409+ = List Variable
410+ | Tuple [Variable]
411+ | Other
412+
413+
414+collectApps :: Content -> IO AppStructure
415+collectApps content =
416+ collectAppsHelp [] content
417+
418+
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
424+
425+ (Atom name, [arg]) | Var.isList name ->
426+ return (List arg)
427+
428+ (Atom name, _) | Var.isTuple name ->
429+ return (Tuple args)
430+
431+ _ ->
432+ return Other
433+
434+
435+getContent :: Variable -> IO Content
436+getContent variable =
437+ _content <$> UF.descriptor variable
438+
439+
440+
441+-- UNIFY ATOMS
442+
443+
444+unifyAtom :: Context -> Var.Canonical -> Content -> Unify ()
445+unifyAtom context name otherContent =
446+ case otherContent of
447+ Error ->
448+ return ()
449+
450+ Var Flex Nothing _ ->
451+ merge context (Atom name)
452+
453+ Var Flex (Just super) _ ->
454+ if atomMatchesSuper super name then
455+ merge context (Atom name)
456+
457+ else
458+ mismatch context (Just ((Error.flipReason (badSuper super))))
459+
460+ Var Rigid _ maybeName ->
461+ mismatch context (Just (Error.flipReason (badRigid maybeName)))
462+
463+ Atom otherName ->
464+ if name == otherName then
465+ merge context otherContent
466+
467+ else
468+ mismatch context $
469+ if isIntFloat name otherName || isIntFloat otherName name then
470+ Just Error.IntFloat
471+ else
472+ Nothing
473+
474+ Alias _ _ realVar ->
475+ subUnify context (_first context) realVar
476+
477+ Structure _ ->
478+ mismatch context Nothing
479+
480+
481+isIntFloat :: Var.Canonical -> Var.Canonical -> Bool
482+isIntFloat name otherName =
483+ Var.isPrim "Int" name && Var.isPrim "Float" otherName
484+
485+
486+-- UNIFY ALIASES
487+
488+
489+unifyAlias :: Context -> Var.Canonical -> [(String, Variable)] -> Variable -> Content -> Unify ()
490+unifyAlias context name args realVar otherContent =
491+ case otherContent of
492+ Error ->
493+ return ()
494+
495+ Var Flex Nothing _ ->
496+ merge context (Alias name args realVar)
497+
498+ Var _ _ _ ->
499+ subUnify context realVar (_second context)
500+
501+ Atom _ ->
502+ subUnify context realVar (_second context)
503+
504+
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)
509+
510+ else
511+ subUnify context realVar otherRealVar
512+
513+ Structure _ ->
514+ subUnify context realVar (_second context)
515+
516+
517+
518+-- UNIFY STRUCTURES
519+
520+
521+unifyStructure :: Context -> Term1 Variable -> Content -> Unify ()
522+unifyStructure context term otherContent =
523+ case otherContent of
524+ Error ->
525+ return ()
526+
527+ Var Flex Nothing _ ->
528+ merge context (Structure term)
529+
530+ Var Flex (Just super) _ ->
531+ unifySuper (reorient context) super (Structure term)
532+
533+ Var Rigid _ maybeName ->
534+ mismatch context (Just (Error.flipReason (badRigid maybeName)))
535+
536+ Atom _ ->
537+ mismatch context Nothing
538+
539+ Alias _ _ realVar ->
540+ subUnify context (_first context) realVar
541+
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
548+
549+ (Fun1 arg result, Fun1 otherArg otherResult) ->
550+ do subUnify context arg otherArg
551+ subUnify context result otherResult
552+ merge context otherContent
553+
554+ (EmptyRecord1, EmptyRecord1) ->
555+ merge context otherContent
556+
557+ (Record1 fields ext, EmptyRecord1) | Map.null fields ->
558+ subUnify context ext (_second context)
559+
560+ (EmptyRecord1, Record1 fields ext) | Map.null fields ->
561+ subUnify context (_first context) ext
562+
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
567+
568+ _ ->
569+ mismatch context Nothing
570+
571+
572+
573+-- UNIFY RECORDS
574+
575+
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
580+
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))
588+
589+ let uniqueExpFields = Map.difference expFields actFields
590+ let uniqueActFields = Map.difference actFields expFields
591+
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
596+
597+ (Empty, _, _, False) ->
598+ mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
599+
600+ (_, False, Empty, _) ->
601+ mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
602+
603+ (_, False, _, True) ->
604+ do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
605+ subUnify context subRecord actVar
606+ unifySharedFields Map.empty subRecord
607+
608+ (_, True, _, False) ->
609+ do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
610+ subUnify context expVar subRecord
611+ unifySharedFields Map.empty subRecord
612+
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
621+
622+
623+
624+-- GATHER RECORD STRUCTURE
625+
626+
627+data RecordStructure = RecordStructure
628+ { _fields :: Map.Map String Variable
629+ , _extVar :: Variable
630+ , _extStruct :: ExtensionStructure
368631 }
369632
370−data Extension = Empty Variable | Extension Variable
633+
634+data ExtensionStructure
635+ = Empty
636+ | Extension
371637
372638
373−gatherFields :: Variable -> IO ExpandedRecord
374−gatherFields var =
375− do desc <- UF.descriptor var
376− case structure desc of
377− (Just (Record1 fields ext)) ->
378− do (ExpandedRecord deeperFields rootExt) <- gatherFields ext
379− return (ExpandedRecord (Map.unionWith (++) fields deeperFields) rootExt)
639+gatherFields :: Context -> Map.Map String Variable -> Variable -> Unify RecordStructure
640+gatherFields context fields variable =
641+ do desc <- liftIO (UF.descriptor variable)
642+ case _content desc of
643+ Structure (Record1 subFields subExt) ->
644+ gatherFields context (Map.union fields subFields) subExt
380645
381− (Just EmptyRecord1) ->
382− return (ExpandedRecord Map.empty (Empty var))
646+ Structure EmptyRecord1 ->
647+ return (RecordStructure fields variable Empty)
648+
649+ Alias _ _ var ->
650+ -- TODO may be dropping useful alias info here
651+ gatherFields context fields var
383652
384653 _ ->
385− return (ExpandedRecord Map.empty (Extension var))
386−
387−
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
392− [] -> ""
393− [key] ->
394− "Looks like a record is missing the field `" ++ key ++ "`"
395− keys ->
396− "Looks like a record is missing fields "
397− ++ List.intercalate ", " (init keys) ++ ", and " ++ last keys
398−
399−
400−combinedDescriptors
401− :: Descriptor
402− -> Descriptor
403− -> (Maybe Var.Canonical, Flex, Int, Alias Variable)
404−combinedDescriptors desc1 desc2 =
405− (name', flex', rank', alias')
406− where
407− rank' :: Int
408− rank' =
409− min (rank desc1) (rank desc2)
410−
411− alias' :: Alias Variable
412− alias' =
413− alias desc1 <|> alias desc2
414−
415− name' :: Maybe Var.Canonical
416− name' =
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
425− (_, _) -> Nothing
426− (Just name1, _) -> Just name1
427− (_, Just name2) -> Just name2
428− _ -> Nothing
429−
430− flex' :: Flex
431− flex' =
432− case (flex desc1, flex desc2) of
433− (f, Flexible) -> f
434− (Flexible, f) -> f
435− (Is Number, Is _) -> Is Number
436− (Is _, Is Number) -> Is Number
437− (Is super, Is _) -> Is super
438− (_, _) -> Flexible
654+ return (RecordStructure fields variable Extension)
655+