1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings, Rank2Types #-}
10import qualified Data.Map.Strict as Map
12import qualified AST.Module.Name as ModuleName
13import qualified Elm.Name as N
14import qualified Type.Error as Error
15import qualified Type.Occurs as Occurs
16import Type.Type as Type
17import qualified Type.UnionFind as UF
26 | Err [Variable] Error.Type Error.Type
29unify :: Variable -> Variable -> IO Answer
31 case guardedUnify v1 v2 of
33 k [] onSuccess $ \vars () ->
34 do t1 <- Type.toErrorType v1
35 t2 <- Type.toErrorType 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)
64instance Functor Unify where
65 fmap func (Unify kv) =
66 Unify $ \vars ok err ->
74instance Applicative Unify where
79 (<*>) (Unify kf) (Unify kv) =
80 Unify $ \vars ok err ->
92instance Monad Unify where
97 (>>=) (Unify ka) callback =
98 Unify $ \vars ok err ->
102 Unify kb -> kb vars1 ok err
107register :: IO Variable -> Unify Variable
109 Unify $ \vars ok _ ->
116 Unify $ \vars _ err ->
120try2 :: Unify () -> Unify () -> Unify ()
121try2 (Unify k1) (Unify k2) =
122 Unify $ \vars ok err ->
124 ok1 vars1 () = k2 vars1 ok err
125 err1 vars1 () = k2 vars1 err err
131try3 :: Unify () -> Unify () -> Unify () -> Unify ()
137-- UNIFICATION HELPERS
143 , _firstDesc :: Descriptor
144 , _second :: Variable
145 , _secondDesc :: Descriptor
149reorient :: Context -> Context
150reorient (Context var1 desc1 var2 desc2) =
151 Context var2 desc2 var1 desc1
158merge :: Context -> Content -> Unify ()
159merge (Context var1 (Descriptor _ rank1 _ _) var2 (Descriptor _ rank2 _ _)) content =
160 Unify $ \vars ok _ ->
162 UF.union var1 var2 (Descriptor content (min rank1 rank2) noMark Nothing)
165fresh :: Context -> Content -> Unify Variable
166fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
167 register $ UF.fresh $
168 Descriptor content (min rank1 rank2) noMark Nothing
172-- ACTUALLY UNIFY THINGS
175guardedUnify :: Variable -> Variable -> Unify ()
176guardedUnify left right =
177 Unify $ \vars ok err ->
178 do equivalent <- UF.equivalent left right
182 do leftDesc <- UF.get left
183 rightDesc <- UF.get right
184 case actuallyUnify (Context left leftDesc right rightDesc) of
189subUnify :: Variable -> Variable -> Unify ()
191 guardedUnify var1 var2
194actuallyUnify :: Context -> Unify ()
195actuallyUnify context@(Context _ (Descriptor firstContent _ _ _) _ (Descriptor secondContent _ _ _)) =
198 unifyFlex context firstContent secondContent
201 unifyFlexSuper context super firstContent secondContent
204 unifyRigid context Nothing firstContent secondContent
206 RigidSuper super _ ->
207 unifyRigid context (Just super) firstContent secondContent
209 Alias home name args realVar ->
210 unifyAlias context home name args realVar secondContent
212 Structure flatType ->
213 unifyStructure context flatType firstContent secondContent
216 -- If there was an error, just pretend it is okay. This lets us avoid
217 -- "cascading" errors where one problem manifests as multiple message.
222-- UNIFY FLEXIBLE VARIABLES
225unifyFlex :: Context -> Content -> Content -> Unify ()
226unifyFlex context content otherContent =
231 -- TODO see if wildcarding makes a noticable perf difference
243 merge context otherContent
246 merge context otherContent
249 merge context otherContent
252 merge context otherContent
255 merge context otherContent
259-- UNIFY RIGID VARIABLES
262unifyRigid :: Context -> Maybe SuperType -> Content -> Content -> Unify ()
263unifyRigid context maybeSuper content otherContent =
266 merge context content
268 FlexSuper otherSuper _ ->
271 if combineRigidSupers super otherSuper then
272 merge context content
296-- UNIFY SUPER VARIABLES
299unifyFlexSuper :: Context -> SuperType -> Content -> Content -> Unify ()
300unifyFlexSuper context super content otherContent =
302 Structure flatType ->
303 unifyFlexSuperStructure context super flatType
308 RigidSuper otherSuper _ ->
309 if combineRigidSupers otherSuper super then
310 merge context otherContent
315 merge context content
317 FlexSuper otherSuper _ ->
321 Number -> merge context content
322 Comparable -> merge context content
323 Appendable -> mismatch
324 CompAppend -> mismatch
328 Comparable -> merge context otherContent
329 Number -> merge context otherContent
330 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
331 CompAppend -> merge context otherContent
335 Appendable -> merge context otherContent
336 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
337 CompAppend -> merge context otherContent
342 Comparable -> merge context content
343 Appendable -> merge context content
344 CompAppend -> merge context content
347 Alias _ _ _ realVar ->
348 subUnify (_first context) realVar
354combineRigidSupers :: SuperType -> SuperType -> Bool
355combineRigidSupers rigid flex =
357 || (rigid == Number && flex == Comparable)
358 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
361atomMatchesSuper :: SuperType -> ModuleName.Canonical -> N.Name -> Bool
362atomMatchesSuper super home name =
363 home == ModuleName.basics
383unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
384unifyFlexSuperStructure context super flatType =
387 if atomMatchesSuper super home name then
388 merge context (Structure flatType)
392 App1 home name [variable] | home == ModuleName.list && name == N.list ->
398 merge context (Structure flatType)
401 do comparableOccursCheck context
402 merge context (Structure flatType)
403 unifyComparableRecursive variable
406 do comparableOccursCheck context
407 merge context (Structure flatType)
408 unifyComparableRecursive variable
419 do comparableOccursCheck context
420 merge context (Structure flatType)
421 unifyComparableRecursive a
422 unifyComparableRecursive b
428 unifyComparableRecursive c
437-- TODO: is there some way to avoid doing this?
438-- Do type classes require occurs checks?
439comparableOccursCheck :: Context -> Unify ()
440comparableOccursCheck (Context _ _ var _) =
441 Unify $ \vars ok err ->
442 do hasOccurred <- Occurs.occurs var
448unifyComparableRecursive :: Variable -> Unify ()
449unifyComparableRecursive var =
450 do compVar <- register $
451 do (Descriptor _ rank _ _) <- UF.get var
452 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
453 guardedUnify compVar var
460unifyAlias :: Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Variable)] -> Variable -> Content -> Unify ()
461unifyAlias context home name args realVar otherContent =
464 merge context (Alias home name args realVar)
467 subUnify realVar (_second context)
470 subUnify realVar (_second context)
473 subUnify realVar (_second context)
475 Alias otherHome otherName otherArgs otherRealVar ->
476 if name == otherName && home == otherHome then
477 Unify $ \vars ok err ->
480 case merge context otherContent of
484 unifyAliasArgs vars context args otherArgs ok1 err
487 subUnify realVar otherRealVar
490 subUnify realVar (_second context)
496unifyAliasArgs :: [Variable] -> Context -> [(N.Name,Variable)] -> [(N.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
497unifyAliasArgs vars context args1 args2 ok err =
502 case subUnify arg1 arg2 of
505 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
506 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
524unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
525unifyStructure context flatType content otherContent =
528 merge context content
531 unifyFlexSuperStructure (reorient context) super flatType
539 Alias _ _ _ realVar ->
540 subUnify (_first context) realVar
542 Structure otherFlatType ->
543 case (flatType, otherFlatType) of
544 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
545 Unify $ \vars ok err ->
548 case merge context otherContent of
552 unifyArgs vars context args otherArgs ok1 err
554 (Fun1 arg1 res1, Fun1 arg2 res2) ->
558 merge context otherContent
560 (EmptyRecord1, EmptyRecord1) ->
561 merge context otherContent
563 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
564 subUnify ext (_second context)
566 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
567 subUnify (_first context) ext
569 (Record1 fields1 ext1, Record1 fields2 ext2) ->
570 Unify $ \vars ok err ->
571 do structure1 <- gatherFields fields1 ext1
572 structure2 <- gatherFields fields2 ext2
573 case unifyRecord context structure1 structure2 of
577 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
581 merge context otherContent
583 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
588 merge context otherContent
591 merge context otherContent
604unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
605unifyArgs vars context args1 args2 ok err =
610 case subUnify arg1 arg2 of
613 (\vs () -> unifyArgs vs context others1 others2 ok err)
614 (\vs () -> unifyArgs vs context others1 others2 err err)
632unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
633unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
635 sharedFields = Map.intersectionWith (,) fields1 fields2
636 uniqueFields1 = Map.difference fields1 fields2
637 uniqueFields2 = Map.difference fields2 fields1
639 if Map.null uniqueFields1 then
641 if Map.null uniqueFields2 then
644 (unifySharedFields context sharedFields Map.empty ext1)
647 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
649 (subUnify ext1 subRecord)
650 (unifySharedFields context sharedFields Map.empty subRecord)
654 if Map.null uniqueFields2 then
655 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
657 (subUnify subRecord ext2)
658 (unifySharedFields context sharedFields Map.empty subRecord)
661 do let otherFields = Map.union uniqueFields1 uniqueFields2
662 ext <- fresh context Type.unnamedFlexVar
663 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
664 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
668 (unifySharedFields context sharedFields otherFields ext)
671unifySharedFields :: Context -> Map.Map N.Name (Variable, Variable) -> Map.Map N.Name Variable -> Variable -> Unify ()
672unifySharedFields context sharedFields otherFields ext =
673 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
674 if Map.size sharedFields == Map.size matchingFields
675 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
679unifyField :: N.Name -> (Variable, Variable) -> Unify (Maybe Variable)
680unifyField _ (actual, expected) =
681 Unify $ \vars ok _ ->
682 case subUnify actual expected of
685 (\vs () -> ok vs (Just actual))
686 (\vs () -> ok vs Nothing)
690-- GATHER RECORD STRUCTURE
693data RecordStructure =
695 { _fields :: Map.Map N.Name Variable
696 , _extension :: Variable
700gatherFields :: Map.Map N.Name Variable -> Variable -> IO RecordStructure
701gatherFields fields variable =
702 do (Descriptor content _ _ _) <- UF.get variable
704 Structure (Record1 subFields subExt) ->
705 gatherFields (Map.union fields subFields) subExt
708 -- TODO may be dropping useful alias info here
709 gatherFields fields var
712 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