1{-# OPTIONS_GHC -Wall #-}
2module Type.Unify (unify) where
4import Control.Monad (zipWithM_)
5import Control.Monad.Except (ExceptT, lift, liftIO, throwError, runExceptT)
6import qualified Data.Map as Map
7import qualified Data.UnionFind.IO as UF
9import qualified AST.Variable as Var
10import qualified Reporting.Region as R
11import qualified Reporting.Error.Type as Error
12import qualified Type.State as TS
13import Type.Type as Type
17-- KICK OFF UNIFICATION
20unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
21unify hint region expected actual =
22 do result <- runExceptT (guardedUnify ExpectedActual expected actual)
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)
36 TS.addError region =<< liftIO mkError
44 ExceptT Mismatch TS.Solver
48 { _orientation :: Orientation
50 , _firstDesc :: Descriptor
52 , _secondDesc :: Descriptor
56data Orientation = ExpectedActual | ActualExpected
59reorient :: Context -> Context
60reorient (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)
78mismatch :: Context -> Maybe Error.Reason -> Unify a
79mismatch (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)
92badRigid :: Maybe String -> Error.Reason
94 Error.BadVar (Just (Error.Rigid maybeName)) Nothing
97badSuper :: Super -> Error.Reason
99 Error.BadVar (Just (errorSuper super)) Nothing
102doubleBad :: Error.VarType -> Error.VarType -> Error.Reason
104 Error.BadVar (Just vt1) (Just vt2)
107errorSuper :: Super -> Error.VarType
127merge :: Context -> Content -> Unify ()
128merge (Context _ first _ second _) content =
129 liftIO $ mergeHelp first second content
132mergeHelp :: Variable -> Variable -> Content -> IO ()
133mergeHelp first second content =
134 UF.union' first second $ \desc1 desc2 ->
138 , _rank = min (_rank desc1) (_rank desc2)
144fresh :: Context -> Content -> Unify Variable
145fresh (Context _ _ desc1 _ desc2) content =
150 , _rank = min (_rank desc1) (_rank desc2)
154 lift (TS.register freshVariable)
158-- ACTUALLY UNIFY THINGS
161guardedUnify :: Orientation -> Variable -> Variable -> Unify ()
162guardedUnify orientation left right =
163 do equivalent <- liftIO $ UF.equivalent left right
167 do leftDesc <- liftIO $ UF.descriptor left
168 rightDesc <- liftIO $ UF.descriptor right
169 actuallyUnify (Context orientation left leftDesc right rightDesc)
172subUnify :: Context -> Variable -> Variable -> Unify ()
173subUnify context var1 var2 =
174 guardedUnify (_orientation context) var1 var2
177actuallyUnify :: Context -> Unify ()
178actuallyUnify context@(Context _ _ firstDesc _ secondDesc) =
180 secondContent = _content secondDesc
182 case _content firstDesc of
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
211unifyFlex :: Context -> Content -> Unify ()
212unifyFlex context otherContent =
218 merge context otherContent
221 merge context otherContent
224 merge context otherContent
227 merge context otherContent
230 merge context otherContent
234-- UNIFY RIGID VARIABLES
237unifyRigid :: Context -> Maybe Super -> Maybe String -> Content -> Unify ()
238unifyRigid context maybeSuper maybeName otherContent =
243 Var Flex otherMaybeSuper _ ->
244 case (maybeSuper, otherMaybeSuper) of
246 merge context (Var Rigid maybeSuper maybeName)
249 mismatch context (Just (badRigid maybeName))
251 (Just super, Just otherSuper) ->
252 case combineSupers super otherSuper of
253 Right newSuper | newSuper == otherSuper ->
254 merge context otherContent
257 mismatch context (Just (badRigid maybeName))
259 Var Rigid _ otherMaybeName ->
260 mismatch context $ Just $
261 doubleBad (Error.Rigid maybeName) (Error.Rigid otherMaybeName)
264 mismatch context (Just (badRigid maybeName))
267 mismatch context (Just (badRigid maybeName))
270 mismatch context (Just (badRigid maybeName))
274-- UNIFY SUPER VARIABLES
277unifySuper :: Context -> Super -> Content -> Unify ()
278unifySuper context super otherContent =
281 unifySuperStructure context super term
284 if atomMatchesSuper super name then
285 merge context otherContent
287 mismatch context (Just (badSuper super))
289 Var Rigid Nothing maybeName ->
290 mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
292 Var Rigid (Just otherSuper) maybeName ->
293 case combineSupers super otherSuper of
294 Right newSuper | newSuper == super ->
295 merge context otherContent
298 mismatch context $ Just $
299 doubleBad (errorSuper super) (Error.Rigid maybeName)
301 Var Flex Nothing _ ->
302 merge context (Var Flex (Just super) Nothing)
304 Var Flex (Just otherSuper) _ ->
305 case combineSupers super otherSuper of
307 mismatch context (Just reason)
310 merge context (Var Flex (Just newSuper) Nothing)
313 subUnify context (_first context) realVar
319combineSupers :: Super -> Super -> Either Error.Reason Super
320combineSupers firstSuper secondSuper =
321 case (firstSuper, secondSuper) of
322 (Number , Number ) -> Right Number
323 (Comparable, Number ) -> Right Number
324 (Number , Comparable) -> Right Number
326 (Comparable, Comparable) -> Right Comparable
327 (Appendable, Appendable) -> Right Appendable
329 (Appendable, Comparable) -> Right CompAppend
330 (Comparable, Appendable) -> Right CompAppend
332 (CompAppend, CompAppend) -> Right CompAppend
333 (CompAppend, Comparable) -> Right CompAppend
334 (Comparable, CompAppend) -> Right CompAppend
335 (CompAppend, Appendable) -> Right CompAppend
336 (Appendable, CompAppend) -> Right CompAppend
339 Left $ doubleBad (errorSuper firstSuper) (errorSuper secondSuper)
342isPrimitiveFrom :: [String] -> Var.Canonical -> Bool
343isPrimitiveFrom prims var =
344 any (\p -> Var.isPrim p var) prims
347atomMatchesSuper :: Super -> Var.Canonical -> Bool
348atomMatchesSuper super name =
351 isPrimitiveFrom ["Int", "Float"] name
354 isPrimitiveFrom ["Int", "Float", "Char", "String"] name
357 Var.isPrim "String" name
360 Var.isPrim "String" name
363unifySuperStructure :: Context -> Super -> Term1 Variable -> Unify ()
364unifySuperStructure context super term =
365 do appStructure <- liftIO (collectApps (Structure term))
368 mismatch context (Just (badSuper super))
373 mismatch context (Just (badSuper super))
376 merge context (Structure term)
379 do merge context (Structure term)
380 unifyComparableRecursive (_orientation context) variable
383 do merge context (Structure term)
384 unifyComparableRecursive (_orientation context) variable
389 mismatch context (Just (badSuper super))
392 mismatch context (Just (badSuper super))
395 if length entries > 6 then
396 mismatch context (Just (Error.TooLongComparableTuple (length entries)))
399 do merge context (Structure term)
400 mapM_ (unifyComparableRecursive (_orientation context)) entries
403 mismatch context (Just (badSuper super))
406unifyComparableRecursive :: Orientation -> Variable -> Unify ()
407unifyComparableRecursive orientation var =
410 do desc <- UF.descriptor var
413 { _content = Var Flex (Just Comparable) Nothing
419 guardedUnify orientation compVar var
428collectApps :: Content -> IO AppStructure
430 collectAppsHelp [] content
433collectAppsHelp :: [Variable] -> Content -> IO AppStructure
434collectAppsHelp args content =
435 case (content, args) of
436 (Structure (App1 func arg), _) ->
437 collectAppsHelp (args ++ [arg]) =<< getContent func
439 (Atom name, [arg]) | Var.isList name ->
442 (Atom name, _) | Var.isTuple name ->
449getContent :: Variable -> IO Content
451 _content <$> UF.descriptor variable
458unifyAtom :: Context -> Var.Canonical -> Content -> Unify ()
459unifyAtom context name otherContent =
464 Var Flex Nothing _ ->
465 merge context (Atom name)
467 Var Flex (Just super) _ ->
468 if atomMatchesSuper super name then
469 merge context (Atom name)
472 mismatch context (Just ((Error.flipReason (badSuper super))))
474 Var Rigid _ maybeName ->
475 mismatch context (Just (Error.flipReason (badRigid maybeName)))
478 if name == otherName then
479 merge context otherContent
483 if isIntFloat name otherName || isIntFloat otherName name then
489 subUnify context (_first context) realVar
492 mismatch context Nothing
495isIntFloat :: Var.Canonical -> Var.Canonical -> Bool
496isIntFloat name otherName =
497 Var.isPrim "Int" name && Var.isPrim "Float" otherName
504unifyAlias :: Context -> Var.Canonical -> [(String, Variable)] -> Variable -> Content -> Unify ()
505unifyAlias context name args realVar otherContent =
510 Var Flex Nothing _ ->
511 merge context (Alias name args realVar)
514 subUnify context realVar (_second context)
517 subUnify context realVar (_second context)
520 Alias otherName otherArgs otherRealVar ->
521 if name == otherName then
522 do zipWithM_ (subUnify context) (map snd args) (map snd otherArgs)
523 merge context otherContent
526 subUnify context realVar otherRealVar
529 subUnify context realVar (_second context)
536unifyStructure :: Context -> Term1 Variable -> Content -> Unify ()
537unifyStructure context term otherContent =
542 Var Flex Nothing _ ->
543 merge context (Structure term)
545 Var Flex (Just super) _ ->
546 unifySuper (reorient context) super (Structure term)
548 Var Rigid _ maybeName ->
549 mismatch context (Just (Error.flipReason (badRigid maybeName)))
552 mismatch context Nothing
555 subUnify context (_first context) realVar
557 Structure otherTerm ->
558 case (term, otherTerm) of
559 (App1 func arg, App1 otherFunc otherArg) ->
560 do subUnify context func otherFunc
561 subUnify context arg otherArg
562 merge context otherContent
564 (Fun1 arg result, Fun1 otherArg otherResult) ->
565 do subUnify context arg otherArg
566 subUnify context result otherResult
567 merge context otherContent
569 (EmptyRecord1, EmptyRecord1) ->
570 merge context otherContent
572 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
573 subUnify context ext (_second context)
575 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
576 subUnify context (_first context) ext
578 (Record1 fields extension, Record1 otherFields otherExtension) ->
579 do firstStructure <- gatherFields context fields extension
580 secondStructure <- gatherFields context otherFields otherExtension
581 unifyRecord context firstStructure secondStructure
584 mismatch context Nothing
591unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
592unifyRecord context firstStructure secondStructure =
593 do let (RecordStructure expFields expVar expStruct) = firstStructure
594 let (RecordStructure actFields actVar actStruct) = secondStructure
596 -- call after unifying extension, make sure record shape matches before
597 -- looking into whether the particular field types match.
598 let unifySharedFields otherFields ext =
599 do let sharedFields = Map.intersectionWith (,) expFields actFields
600 _ <- traverse (uncurry (subUnify context)) sharedFields
601 let allFields = Map.union (Map.map fst sharedFields) otherFields
602 merge context (Structure (Record1 allFields ext))
604 let uniqueExpFields = Map.difference expFields actFields
605 let uniqueActFields = Map.difference actFields expFields
607 case (expStruct, Map.null uniqueExpFields, actStruct, Map.null uniqueActFields) of
608 (_, True, _, True) ->
609 do subUnify context expVar actVar
610 unifySharedFields Map.empty expVar
612 (Empty, _, _, False) ->
613 mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
615 (_, False, Empty, _) ->
616 mismatch context (Just (Error.MessyFields (Map.keys uniqueExpFields) (Map.keys uniqueActFields)))
618 (_, False, _, True) ->
619 do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
620 subUnify context subRecord actVar
621 unifySharedFields Map.empty subRecord
623 (_, True, _, False) ->
624 do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
625 subUnify context expVar subRecord
626 unifySharedFields Map.empty subRecord
628 (Extension, False, Extension, False) ->
629 do let subFields = Map.union uniqueExpFields uniqueActFields
630 subExt <- fresh context (Var Flex Nothing Nothing)
631 expRecord <- fresh context (Structure (Record1 uniqueActFields subExt))
632 actRecord <- fresh context (Structure (Record1 uniqueExpFields subExt))
633 subUnify context expVar expRecord
634 subUnify context actRecord actVar
635 unifySharedFields subFields subExt
639-- GATHER RECORD STRUCTURE
642data RecordStructure = RecordStructure
643 { _fields :: Map.Map String Variable
644 , _extVar :: Variable
645 , _extStruct :: ExtensionStructure
649data ExtensionStructure
654gatherFields :: Context -> Map.Map String Variable -> Variable -> Unify RecordStructure
655gatherFields context fields variable =
656 do desc <- liftIO (UF.descriptor variable)
657 case _content desc of
658 Structure (Record1 subFields subExt) ->
659 gatherFields context (Map.union fields subFields) subExt
661 Structure EmptyRecord1 ->
662 return (RecordStructure fields variable Empty)
665 -- TODO may be dropping useful alias info here
666 gatherFields context fields var
669 return (RecordStructure fields variable Extension)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list