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
327 Comparable -> merge context otherContent
328 Number -> merge context otherContent
329 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
330 CompAppend -> merge context otherContent
334 Appendable -> merge context otherContent
335 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
336 CompAppend -> merge context otherContent
341 Comparable -> merge context content
342 Appendable -> merge context content
343 CompAppend -> merge context content
346 Alias _ _ _ realVar ->
347 subUnify (_first context) realVar
353combineRigidSupers :: SuperType -> SuperType -> Bool
354combineRigidSupers rigid flex =
356 || (rigid == Number && flex == Comparable)
357 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
360atomMatchesSuper :: SuperType -> ModuleName.Canonical -> N.Name -> Bool
361atomMatchesSuper super home name =
362 home == ModuleName.basics
382unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
383unifyFlexSuperStructure context super flatType =
386 if atomMatchesSuper super home name then
387 merge context (Structure flatType)
391 App1 home name [variable] | home == ModuleName.list && name == N.list ->
397 merge context (Structure flatType)
400 do comparableOccursCheck context
401 merge context (Structure flatType)
402 unifyComparableRecursive variable
405 do comparableOccursCheck context
406 merge context (Structure flatType)
407 unifyComparableRecursive variable
418 do comparableOccursCheck context
419 merge context (Structure flatType)
420 unifyComparableRecursive a
421 unifyComparableRecursive b
427 unifyComparableRecursive c
436-- TODO: is there some way to avoid doing this?
437-- Do type classes require occurs checks?
438comparableOccursCheck :: Context -> Unify ()
439comparableOccursCheck (Context _ _ var _) =
440 Unify $ \vars ok err ->
441 do hasOccurred <- Occurs.occurs var
447unifyComparableRecursive :: Variable -> Unify ()
448unifyComparableRecursive var =
449 do compVar <- register $
450 do (Descriptor _ rank _ _) <- UF.get var
451 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
452 guardedUnify compVar var
459unifyAlias :: Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Variable)] -> Variable -> Content -> Unify ()
460unifyAlias context home name args realVar otherContent =
463 merge context (Alias home name args realVar)
466 subUnify realVar (_second context)
469 subUnify realVar (_second context)
472 subUnify realVar (_second context)
474 Alias otherHome otherName otherArgs otherRealVar ->
475 if name == otherName && home == otherHome then
476 Unify $ \vars ok err ->
479 case merge context otherContent of
483 unifyAliasArgs vars context args otherArgs ok1 err
486 subUnify realVar otherRealVar
489 subUnify realVar (_second context)
495unifyAliasArgs :: [Variable] -> Context -> [(N.Name,Variable)] -> [(N.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
496unifyAliasArgs vars context args1 args2 ok err =
501 case subUnify arg1 arg2 of
504 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
505 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
523unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
524unifyStructure context flatType content otherContent =
527 merge context content
530 unifyFlexSuperStructure (reorient context) super flatType
538 Alias _ _ _ realVar ->
539 subUnify (_first context) realVar
541 Structure otherFlatType ->
542 case (flatType, otherFlatType) of
543 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
544 Unify $ \vars ok err ->
547 case merge context otherContent of
551 unifyArgs vars context args otherArgs ok1 err
553 (Fun1 arg1 res1, Fun1 arg2 res2) ->
557 merge context otherContent
559 (EmptyRecord1, EmptyRecord1) ->
560 merge context otherContent
562 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
563 subUnify ext (_second context)
565 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
566 subUnify (_first context) ext
568 (Record1 fields1 ext1, Record1 fields2 ext2) ->
569 Unify $ \vars ok err ->
570 do structure1 <- gatherFields fields1 ext1
571 structure2 <- gatherFields fields2 ext2
572 case unifyRecord context structure1 structure2 of
576 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
580 merge context otherContent
582 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
587 merge context otherContent
590 merge context otherContent
603unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
604unifyArgs vars context args1 args2 ok err =
609 case subUnify arg1 arg2 of
612 (\vs () -> unifyArgs vs context others1 others2 ok err)
613 (\vs () -> unifyArgs vs context others1 others2 err err)
631unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
632unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
634 sharedFields = Map.intersectionWith (,) fields1 fields2
635 uniqueFields1 = Map.difference fields1 fields2
636 uniqueFields2 = Map.difference fields2 fields1
638 if Map.null uniqueFields1 then
640 if Map.null uniqueFields2 then
643 (unifySharedFields context sharedFields Map.empty ext1)
646 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
648 (subUnify ext1 subRecord)
649 (unifySharedFields context sharedFields Map.empty subRecord)
653 if Map.null uniqueFields2 then
654 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
656 (subUnify subRecord ext2)
657 (unifySharedFields context sharedFields Map.empty subRecord)
660 do let otherFields = Map.union uniqueFields1 uniqueFields2
661 ext <- fresh context Type.unnamedFlexVar
662 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
663 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
667 (unifySharedFields context sharedFields otherFields ext)
670unifySharedFields :: Context -> Map.Map N.Name (Variable, Variable) -> Map.Map N.Name Variable -> Variable -> Unify ()
671unifySharedFields context sharedFields otherFields ext =
672 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
673 if Map.size sharedFields == Map.size matchingFields
674 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
678unifyField :: N.Name -> (Variable, Variable) -> Unify (Maybe Variable)
679unifyField _ (actual, expected) =
680 Unify $ \vars ok _ ->
681 case subUnify actual expected of
684 (\vs () -> ok vs (Just actual))
685 (\vs () -> ok vs Nothing)
689-- GATHER RECORD STRUCTURE
692data RecordStructure =
694 { _fields :: Map.Map N.Name Variable
695 , _extension :: Variable
699gatherFields :: Map.Map N.Name Variable -> Variable -> IO RecordStructure
700gatherFields fields variable =
701 do (Descriptor content _ _ _) <- UF.get variable
703 Structure (Record1 subFields subExt) ->
704 gatherFields (Map.union fields subFields) subExt
707 -- TODO may be dropping useful alias info here
708 gatherFields fields var
711 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