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.Maybe as Maybe
8import qualified Data.UnionFind.IO as UF
10import qualified AST.Variable as Var
11import qualified Reporting.Region as R
12import qualified Reporting.Error.Type as Error
13import qualified Type.State as TS
14import Type.Type as Type
18-- KICK OFF UNIFICATION
21unify :: Error.Hint -> R.Region -> Variable -> Variable -> TS.Solver ()
22unify hint region expected actual =
23 do result <- runExceptT (guardedUnify ExpectedActual expected actual)
28 Left (Mismatch maybeReason) ->
31 do expectedSrcType <- Type.toSrcType expected
32 actualSrcType <- Type.toSrcType actual
33 mergeHelp expected actual Error
34 let info = Error.MismatchInfo hint expectedSrcType actualSrcType maybeReason
35 return (Error.Mismatch info)
37 TS.addError region =<< liftIO mkError
45 ExceptT Mismatch TS.Solver
49 { _orientation :: Orientation
51 , _firstDesc :: Descriptor
53 , _secondDesc :: Descriptor
57data Orientation = ExpectedActual | ActualExpected
60reorient :: Context -> Context
61reorient (Context orientation var1 desc1 var2 desc2) =
65 ExpectedActual -> ActualExpected
66 ActualExpected -> ExpectedActual
68 Context otherOrientation var2 desc2 var1 desc1
76 Mismatch (Maybe Error.Reason)
79mismatch :: Context -> Maybe Error.Reason -> Unify a
80mismatch context@(Context orientation var1 _ var2 _) maybeReason =
81 do args1 <- liftIO $ collectArgs var1
82 args2 <- liftIO $ collectArgs var2
84 let numArgs1 = length args1
85 let numArgs2 = length args2
87 if numArgs1 == numArgs2
89 mismatchHelp orientation maybeReason
91 do zipWithM_ (\arg1 arg2 -> lift $ runExceptT $ subUnify context arg1 arg2) args1 args2
92 mismatchHelp orientation $ Just $ Error.MissingArgs $ abs (numArgs2 - numArgs1)
95mismatchHelp :: Orientation -> Maybe Error.Reason -> Unify a
96mismatchHelp orientation maybeReason =
97 throwError $ Mismatch $
103 Error.flipReason <$> maybeReason
106badRigid :: Maybe String -> Error.Reason
108 Error.BadVar (Just (Error.Rigid maybeName)) Nothing
111badSuper :: Super -> Error.Reason
113 Error.BadVar (Just (errorSuper super)) Nothing
116doubleBad :: Error.VarType -> Error.VarType -> Error.Reason
118 Error.BadVar (Just vt1) (Just vt2)
121errorSuper :: Super -> Error.VarType
141merge :: Context -> Content -> Unify ()
142merge (Context _ first _ second _) content =
143 liftIO $ mergeHelp first second content
146mergeHelp :: Variable -> Variable -> Content -> IO ()
147mergeHelp first second content =
148 UF.union' first second $ \desc1 desc2 ->
152 , _rank = min (_rank desc1) (_rank desc2)
158fresh :: Context -> Content -> Unify Variable
159fresh (Context _ _ desc1 _ desc2) content =
164 , _rank = min (_rank desc1) (_rank desc2)
168 lift (TS.register freshVariable)
172-- ACTUALLY UNIFY THINGS
175guardedUnify :: Orientation -> Variable -> Variable -> Unify ()
176guardedUnify orientation left right =
177 do equivalent <- liftIO $ UF.equivalent left right
181 do leftDesc <- liftIO $ UF.descriptor left
182 rightDesc <- liftIO $ UF.descriptor right
183 actuallyUnify (Context orientation left leftDesc right rightDesc)
186subUnify :: Context -> Variable -> Variable -> Unify ()
187subUnify context var1 var2 =
188 guardedUnify (_orientation context) var1 var2
191actuallyUnify :: Context -> Unify ()
192actuallyUnify context@(Context _ _ firstDesc _ secondDesc) =
194 secondContent = _content secondDesc
196 case _content firstDesc of
198 -- If there was an error, just pretend it is okay. This lets us avoid
199 -- "cascading" errors where one problem manifests as multiple message.
202 Var Flex Nothing _ ->
203 unifyFlex context secondContent
205 Var Flex (Just super) _ ->
206 unifySuper context super secondContent
208 Var Rigid maybeSuper maybeName ->
209 unifyRigid context maybeSuper maybeName secondContent
212 unifyAtom context name secondContent
214 Alias name args realVar ->
215 unifyAlias context name args realVar secondContent
218 unifyStructure context term secondContent
222-- UNIFY FLEXIBLE VARIABLES
225unifyFlex :: Context -> Content -> Unify ()
226unifyFlex context otherContent =
232 merge context otherContent
235 merge context otherContent
238 merge context otherContent
241 merge context otherContent
244 merge context otherContent
248-- UNIFY RIGID VARIABLES
251unifyRigid :: Context -> Maybe Super -> Maybe String -> Content -> Unify ()
252unifyRigid context maybeSuper maybeName otherContent =
257 Var Flex otherMaybeSuper _ ->
258 case (maybeSuper, otherMaybeSuper) of
260 merge context (Var Rigid maybeSuper maybeName)
263 mismatch context (Just (badRigid maybeName))
265 (Just super, Just otherSuper) ->
266 case combineSupers super otherSuper of
267 Right newSuper | newSuper == otherSuper ->
268 merge context otherContent
271 mismatch context (Just (badRigid maybeName))
273 Var Rigid _ otherMaybeName ->
274 mismatch context $ Just $
275 doubleBad (Error.Rigid maybeName) (Error.Rigid otherMaybeName)
278 mismatch context (Just (badRigid maybeName))
281 mismatch context (Just (badRigid maybeName))
284 mismatch context (Just (badRigid maybeName))
288-- UNIFY SUPER VARIABLES
291unifySuper :: Context -> Super -> Content -> Unify ()
292unifySuper context super otherContent =
295 unifySuperStructure context super term
298 if atomMatchesSuper super name then
299 merge context otherContent
301 mismatch context (Just (badSuper super))
303 Var Rigid Nothing maybeName ->
304 mismatch context (Just (doubleBad (errorSuper super) (Error.Rigid maybeName)))
306 Var Rigid (Just otherSuper) maybeName ->
307 case combineSupers super otherSuper of
308 Right newSuper | newSuper == super ->
309 merge context otherContent
312 mismatch context $ Just $
313 doubleBad (errorSuper super) (Error.Rigid maybeName)
315 Var Flex Nothing _ ->
316 merge context (Var Flex (Just super) Nothing)
318 Var Flex (Just otherSuper) _ ->
319 case combineSupers super otherSuper of
321 mismatch context (Just reason)
324 merge context (Var Flex (Just newSuper) Nothing)
327 subUnify context (_first context) realVar
333combineSupers :: Super -> Super -> Either Error.Reason Super
334combineSupers firstSuper secondSuper =
335 case (firstSuper, secondSuper) of
336 (Number , Number ) -> Right Number
337 (Comparable, Number ) -> Right Number
338 (Number , Comparable) -> Right Number
340 (Comparable, Comparable) -> Right Comparable
341 (Appendable, Appendable) -> Right Appendable
343 (Appendable, Comparable) -> Right CompAppend
344 (Comparable, Appendable) -> Right CompAppend
346 (CompAppend, CompAppend) -> Right CompAppend
347 (CompAppend, Comparable) -> Right CompAppend
348 (Comparable, CompAppend) -> Right CompAppend
349 (CompAppend, Appendable) -> Right CompAppend
350 (Appendable, CompAppend) -> Right CompAppend
353 Left $ doubleBad (errorSuper firstSuper) (errorSuper secondSuper)
356isPrimitiveFrom :: [String] -> Var.Canonical -> Bool
357isPrimitiveFrom prims var =
358 any (\p -> Var.isPrim p var) prims
361atomMatchesSuper :: Super -> Var.Canonical -> Bool
362atomMatchesSuper super name =
365 isPrimitiveFrom ["Int", "Float"] name
368 isPrimitiveFrom ["Int", "Float", "Char", "String"] name
371 Var.isPrim "String" name
374 Var.isPrim "String" name
377unifySuperStructure :: Context -> Super -> Term1 Variable -> Unify ()
378unifySuperStructure context super term =
379 do appStructure <- liftIO (collectApps (Structure term))
382 mismatch context (Just (badSuper super))
387 mismatch context (Just (badSuper super))
390 merge context (Structure term)
393 do merge context (Structure term)
394 unifyComparableRecursive (_orientation context) variable
397 do merge context (Structure term)
398 unifyComparableRecursive (_orientation context) variable
403 mismatch context (Just (badSuper super))
406 mismatch context (Just (badSuper super))
409 if length entries > 6 then
410 mismatch context (Just (Error.TooLongComparableTuple (length entries)))
413 do merge context (Structure term)
414 mapM_ (unifyComparableRecursive (_orientation context)) entries
417 mismatch context (Just (badSuper super))
420unifyComparableRecursive :: Orientation -> Variable -> Unify ()
421unifyComparableRecursive orientation var =
424 do desc <- UF.descriptor var
427 { _content = Var Flex (Just Comparable) Nothing
433 guardedUnify orientation compVar var
442collectApps :: Content -> IO AppStructure
444 collectAppsHelp [] content
447collectAppsHelp :: [Variable] -> Content -> IO AppStructure
448collectAppsHelp args content =
449 case (content, args) of
450 (Structure (App1 func arg), _) ->
451 collectAppsHelp (args ++ [arg]) =<< getContent func
453 (Atom name, [arg]) | Var.isList name ->
456 (Atom name, _) | Var.isTuple name ->
463collectArgs :: Variable -> IO [Variable]
464collectArgs variable =
465 collectArgsHelp [] variable
468collectArgsHelp :: [Variable] -> Variable -> IO [Variable]
469collectArgsHelp revArgs variable =
470 do content <- getContent variable
472 Structure (Fun1 arg returnType) ->
473 collectArgsHelp (arg : revArgs) returnType
476 return $ variable : revArgs
479getContent :: Variable -> IO Content
481 _content <$> UF.descriptor variable
488unifyAtom :: Context -> Var.Canonical -> Content -> Unify ()
489unifyAtom context name otherContent =
494 Var Flex Nothing _ ->
495 merge context (Atom name)
497 Var Flex (Just super) _ ->
498 if atomMatchesSuper super name then
499 merge context (Atom name)
502 mismatch context (Just ((Error.flipReason (badSuper super))))
504 Var Rigid _ maybeName ->
505 mismatch context (Just (Error.flipReason (badRigid maybeName)))
508 if name == otherName then
509 merge context otherContent
513 if isIntFloat name otherName || isIntFloat otherName name then
519 subUnify context (_first context) realVar
522 mismatch context Nothing
525isIntFloat :: Var.Canonical -> Var.Canonical -> Bool
526isIntFloat name otherName =
527 Var.isPrim "Int" name && Var.isPrim "Float" otherName
534unifyAlias :: Context -> Var.Canonical -> [(String, Variable)] -> Variable -> Content -> Unify ()
535unifyAlias context name args realVar otherContent =
540 Var Flex Nothing _ ->
541 merge context (Alias name args realVar)
544 subUnify context realVar (_second context)
547 subUnify context realVar (_second context)
549 Alias otherName otherArgs otherRealVar ->
550 if name == otherName then
551 do zipWithM_ (subUnify context) (map snd args) (map snd otherArgs)
552 merge context otherContent
555 subUnify context realVar otherRealVar
558 subUnify context realVar (_second context)
565unifyStructure :: Context -> Term1 Variable -> Content -> Unify ()
566unifyStructure context term otherContent =
571 Var Flex Nothing _ ->
572 merge context (Structure term)
574 Var Flex (Just super) _ ->
575 unifySuper (reorient context) super (Structure term)
577 Var Rigid _ maybeName ->
578 mismatch context (Just (Error.flipReason (badRigid maybeName)))
581 mismatch context Nothing
584 subUnify context (_first context) realVar
586 Structure otherTerm ->
587 case (term, otherTerm) of
588 (App1 func arg, App1 otherFunc otherArg) ->
589 do subUnify context func otherFunc
590 subUnify context arg otherArg
591 merge context otherContent
593 (Fun1 arg result, Fun1 otherArg otherResult) ->
594 do subUnify context arg otherArg
595 subUnify context result otherResult
596 merge context otherContent
598 (EmptyRecord1, EmptyRecord1) ->
599 merge context otherContent
601 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
602 subUnify context ext (_second context)
604 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
605 subUnify context (_first context) ext
607 (Record1 fields extension, Record1 otherFields otherExtension) ->
608 do firstStructure <- gatherFields context fields extension
609 secondStructure <- gatherFields context otherFields otherExtension
610 unifyRecord context firstStructure secondStructure
613 mismatch context Nothing
620unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
621unifyRecord context firstStructure secondStructure =
622 do let (RecordStructure expFields expVar expStruct) = firstStructure
623 let (RecordStructure actFields actVar actStruct) = secondStructure
625 let sharedFields = Map.intersectionWith (,) expFields actFields
627 -- call after unifying extension, make sure record shape matches before
628 -- looking into whether the particular field types match.
629 let unifySharedFields otherFields ext =
630 do unifySharedFieldsHelp context sharedFields
631 let allFields = Map.union (Map.map fst sharedFields) otherFields
632 merge context (Structure (Record1 allFields ext))
634 let uniqueExpFields = Map.difference expFields actFields
635 let uniqueActFields = Map.difference actFields expFields
637 case (expStruct, Map.null uniqueExpFields, actStruct, Map.null uniqueActFields) of
638 (_, True, _, True) ->
639 do subUnify context expVar actVar
640 unifySharedFields Map.empty expVar
642 (Empty, _, _, False) ->
643 mismatch context $ Just $
644 Error.MessyFields (Map.keys sharedFields) (Map.keys uniqueExpFields) (Map.keys uniqueActFields)
646 (_, False, Empty, _) ->
647 mismatch context $ Just $
648 Error.MessyFields (Map.keys sharedFields) (Map.keys uniqueExpFields) (Map.keys uniqueActFields)
650 (_, False, _, True) ->
651 do subRecord <- fresh context (Structure (Record1 uniqueExpFields expVar))
652 subUnify context subRecord actVar
653 unifySharedFields Map.empty subRecord
655 (_, True, _, False) ->
656 do subRecord <- fresh context (Structure (Record1 uniqueActFields actVar))
657 subUnify context expVar subRecord
658 unifySharedFields Map.empty subRecord
660 (Extension, False, Extension, False) ->
661 do let subFields = Map.union uniqueExpFields uniqueActFields
662 subExt <- fresh context (Var Flex Nothing Nothing)
663 expRecord <- fresh context (Structure (Record1 uniqueActFields subExt))
664 actRecord <- fresh context (Structure (Record1 uniqueExpFields subExt))
665 subUnify context expVar expRecord
666 subUnify context actRecord actVar
667 unifySharedFields subFields subExt
671unifySharedFieldsHelp :: Context -> Map.Map String (Variable, Variable) -> Unify ()
672unifySharedFieldsHelp context sharedFields =
673 do maybeBadFields <- traverse (unifyField context) (Map.toList sharedFields)
674 case Maybe.catMaybes maybeBadFields of
679 mismatch context (Just (Error.BadFields (reverse badFields)))
682unifyField :: Context -> (String, (Variable, Variable)) -> Unify (Maybe (String, Maybe Error.Reason))
683unifyField context (field, (expected, actual)) =
684 do result <- lift $ runExceptT $ subUnify context expected actual
689 Left (Mismatch maybeReason) ->
690 return $ Just (field, maybeReason)
694-- GATHER RECORD STRUCTURE
697data RecordStructure = RecordStructure
698 { _fields :: Map.Map String Variable
699 , _extVar :: Variable
700 , _extStruct :: ExtensionStructure
704data ExtensionStructure
709gatherFields :: Context -> Map.Map String Variable -> Variable -> Unify RecordStructure
710gatherFields context fields variable =
711 do desc <- liftIO (UF.descriptor variable)
712 case _content desc of
713 Structure (Record1 subFields subExt) ->
714 gatherFields context (Map.union fields subFields) subExt
716 Structure EmptyRecord1 ->
717 return (RecordStructure fields variable Empty)
720 -- TODO may be dropping useful alias info here
721 gatherFields context fields var
724 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