1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings, Rank2Types #-}
10import qualified Data.Map.Strict as Map
12import qualified AST.Canonical as Can
13import qualified AST.Module.Name as ModuleName
14import qualified Elm.Name as N
15import qualified Type.Occurs as Occurs
16import Type.Type as Type
17import qualified Type.UnionFind as UF
26 | Err [Variable] Can.Type Can.Type
29unify :: Variable -> Variable -> IO Answer
31 case guardedUnify v1 v2 of
33 k [] onSuccess $ \vars () ->
34 do t1 <- Type.toSrcType v1
35 t2 <- Type.toSrcType v2
36 UF.union v1 v2 errorDescriptor
37 return (Err vars t1 t2)
40onSuccess :: [Variable] -> () -> IO Answer
45{-# NOINLINE errorDescriptor #-}
46errorDescriptor :: Descriptor
48 Descriptor (Error "?") noRank noMark Nothing
58 -> ([Variable] -> a -> IO r)
59 -> ([Variable] -> () -> IO r)
64-- TODO experiment with INLINE on the Unify instances
66instance Functor Unify where
67 fmap func (Unify kv) =
68 Unify $ \vars ok err ->
76instance Applicative Unify where
81 (<*>) (Unify kf) (Unify kv) =
82 Unify $ \vars ok err ->
94instance Monad Unify where
99 (>>=) (Unify ka) callback =
100 Unify $ \vars ok err ->
104 Unify kb -> kb vars1 ok err
109register :: IO Variable -> Unify Variable
111 Unify $ \vars ok _ ->
118 Unify $ \vars _ err ->
122try2 :: Unify () -> Unify () -> Unify ()
123try2 (Unify k1) (Unify k2) =
124 Unify $ \vars ok err ->
126 ok1 vars1 () = k2 vars1 ok err
127 err1 vars1 () = k2 vars1 err err
133try3 :: Unify () -> Unify () -> Unify () -> Unify ()
139-- UNIFICATION HELPERS
145 , _firstDesc :: Descriptor
146 , _second :: Variable
147 , _secondDesc :: Descriptor
151reorient :: Context -> Context
152reorient (Context var1 desc1 var2 desc2) =
153 Context var2 desc2 var1 desc1
160merge :: Context -> Content -> Unify ()
161merge (Context var1 (Descriptor _ rank1 _ _) var2 (Descriptor _ rank2 _ _)) content =
162 Unify $ \vars ok _ ->
164 UF.union var1 var2 (Descriptor content (min rank1 rank2) noMark Nothing)
167fresh :: Context -> Content -> Unify Variable
168fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
169 register $ UF.fresh $
170 Descriptor content (min rank1 rank2) noMark Nothing
174-- ACTUALLY UNIFY THINGS
177guardedUnify :: Variable -> Variable -> Unify ()
178guardedUnify left right =
179 Unify $ \vars ok err ->
180 do equivalent <- UF.equivalent left right
184 do leftDesc <- UF.get left
185 rightDesc <- UF.get right
186 case actuallyUnify (Context left leftDesc right rightDesc) of
191subUnify :: Variable -> Variable -> Unify ()
193 guardedUnify var1 var2
196actuallyUnify :: Context -> Unify ()
197actuallyUnify context@(Context _ (Descriptor firstContent _ _ _) _ (Descriptor secondContent _ _ _)) =
200 unifyFlex context firstContent secondContent
203 unifyFlexSuper context super firstContent secondContent
206 unifyRigid context Nothing firstContent secondContent
208 RigidSuper super _ ->
209 unifyRigid context (Just super) firstContent secondContent
211 Alias home name args realVar ->
212 unifyAlias context home name args realVar secondContent
214 Structure flatType ->
215 unifyStructure context flatType firstContent secondContent
218 -- If there was an error, just pretend it is okay. This lets us avoid
219 -- "cascading" errors where one problem manifests as multiple message.
224-- UNIFY FLEXIBLE VARIABLES
227unifyFlex :: Context -> Content -> Content -> Unify ()
228unifyFlex context content otherContent =
233 -- TODO see if wildcarding makes a noticable perf difference
245 merge context otherContent
248 merge context otherContent
251 merge context otherContent
254 merge context otherContent
257 merge context otherContent
261-- UNIFY RIGID VARIABLES
264unifyRigid :: Context -> Maybe SuperType -> Content -> Content -> Unify ()
265unifyRigid context maybeSuper content otherContent =
268 merge context content
270 FlexSuper otherSuper _ ->
273 if combineRigidSupers super otherSuper then
274 merge context content
298-- UNIFY SUPER VARIABLES
301unifyFlexSuper :: Context -> SuperType -> Content -> Content -> Unify ()
302unifyFlexSuper context super content otherContent =
304 Structure flatType ->
305 unifyFlexSuperStructure context super flatType
310 RigidSuper otherSuper _ ->
311 if combineRigidSupers otherSuper super then
312 merge context otherContent
317 merge context content
319 FlexSuper otherSuper _ ->
323 Number -> merge context content
324 Comparable -> merge context content
329 Comparable -> merge context otherContent
330 Number -> merge context otherContent
331 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
332 CompAppend -> merge context otherContent
336 Appendable -> merge context otherContent
337 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
338 CompAppend -> merge context otherContent
343 Comparable -> merge context content
344 Appendable -> merge context content
345 CompAppend -> merge context content
348 Alias _ _ _ realVar ->
349 subUnify (_first context) realVar
355combineRigidSupers :: SuperType -> SuperType -> Bool
356combineRigidSupers rigid flex =
358 || (rigid == Number && flex == Comparable)
359 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
362atomMatchesSuper :: SuperType -> ModuleName.Canonical -> N.Name -> Bool
363atomMatchesSuper super home name =
364 home == ModuleName.basics
384unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
385unifyFlexSuperStructure context super flatType =
388 if atomMatchesSuper super home name then
389 merge context (Structure flatType)
393 App1 home name [variable] | home == ModuleName.list && name == N.list ->
399 merge context (Structure flatType)
402 do comparableOccursCheck context
403 merge context (Structure flatType)
404 unifyComparableRecursive variable
407 do comparableOccursCheck context
408 merge context (Structure flatType)
409 unifyComparableRecursive variable
420 do comparableOccursCheck context
421 merge context (Structure flatType)
422 unifyComparableRecursive a
423 unifyComparableRecursive b
429 unifyComparableRecursive c
438-- TODO: is there some way to avoid doing this?
439-- Do type classes require occurs checks?
440comparableOccursCheck :: Context -> Unify ()
441comparableOccursCheck (Context _ _ var _) =
442 Unify $ \vars ok err ->
443 do hasOccurred <- Occurs.occurs var
449unifyComparableRecursive :: Variable -> Unify ()
450unifyComparableRecursive var =
451 do compVar <- register $
452 do (Descriptor _ rank _ _) <- UF.get var
453 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
454 guardedUnify compVar var
461unifyAlias :: Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Variable)] -> Variable -> Content -> Unify ()
462unifyAlias context home name args realVar otherContent =
465 merge context (Alias home name args realVar)
468 subUnify realVar (_second context)
471 subUnify realVar (_second context)
474 subUnify realVar (_second context)
476 Alias otherHome otherName otherArgs otherRealVar ->
477 if name == otherName && home == otherHome then
478 Unify $ \vars ok err ->
481 case merge context otherContent of
485 unifyAliasArgs vars context args otherArgs ok1 err
488 subUnify realVar otherRealVar
491 subUnify realVar (_second context)
497unifyAliasArgs :: [Variable] -> Context -> [(N.Name,Variable)] -> [(N.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
498unifyAliasArgs vars context args1 args2 ok err =
503 case subUnify arg1 arg2 of
506 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
507 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
525unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
526unifyStructure context flatType content otherContent =
529 merge context content
532 unifyFlexSuperStructure (reorient context) super flatType
540 Alias _ _ _ realVar ->
541 subUnify (_first context) realVar
543 Structure otherFlatType ->
544 case (flatType, otherFlatType) of
545 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
546 Unify $ \vars ok err ->
549 case merge context otherContent of
553 unifyArgs vars context args otherArgs ok1 err
555 (Fun1 arg1 res1, Fun1 arg2 res2) ->
559 merge context otherContent
561 (EmptyRecord1, EmptyRecord1) ->
562 merge context otherContent
564 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
565 subUnify ext (_second context)
567 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
568 subUnify (_first context) ext
570 (Record1 fields1 ext1, Record1 fields2 ext2) ->
571 Unify $ \vars ok err ->
572 do structure1 <- gatherFields fields1 ext1
573 structure2 <- gatherFields fields2 ext2
574 case unifyRecord context structure1 structure2 of
578 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
582 merge context otherContent
584 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
589 merge context otherContent
592 merge context otherContent
605unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
606unifyArgs vars context args1 args2 ok err =
611 case subUnify arg1 arg2 of
614 (\vs () -> unifyArgs vs context others1 others2 ok err)
615 (\vs () -> unifyArgs vs context others1 others2 err err)
633unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
634unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
636 sharedFields = Map.intersectionWith (,) fields1 fields2
637 uniqueFields1 = Map.difference fields1 fields2
638 uniqueFields2 = Map.difference fields2 fields1
640 if Map.null uniqueFields1 then
642 if Map.null uniqueFields2 then
645 (unifySharedFields context sharedFields Map.empty ext1)
648 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
650 (subUnify ext1 subRecord)
651 (unifySharedFields context sharedFields Map.empty subRecord)
655 if Map.null uniqueFields2 then
656 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
658 (subUnify subRecord ext2)
659 (unifySharedFields context sharedFields Map.empty subRecord)
662 do let otherFields = Map.union uniqueFields1 uniqueFields2
663 ext <- fresh context Type.unnamedFlexVar
664 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
665 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
669 (unifySharedFields context sharedFields otherFields ext)
672unifySharedFields :: Context -> Map.Map N.Name (Variable, Variable) -> Map.Map N.Name Variable -> Variable -> Unify ()
673unifySharedFields context sharedFields otherFields ext =
674 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
675 if Map.size sharedFields == Map.size matchingFields
676 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
680unifyField :: N.Name -> (Variable, Variable) -> Unify (Maybe Variable)
681unifyField _ (actual, expected) =
682 Unify $ \vars ok _ ->
683 case subUnify actual expected of
686 (\vs () -> ok vs (Just actual))
687 (\vs () -> ok vs Nothing)
691-- GATHER RECORD STRUCTURE
694data RecordStructure =
696 { _fields :: Map.Map N.Name Variable
697 , _extension :: Variable
701gatherFields :: Map.Map N.Name Variable -> Variable -> IO RecordStructure
702gatherFields fields variable =
703 do (Descriptor content _ _ _) <- UF.get variable
705 Structure (Record1 subFields subExt) ->
706 gatherFields (Map.union fields subFields) subExt
709 -- TODO may be dropping useful alias info here
710 gatherFields fields var
713 return (RecordStructure fields variable)
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