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 =
369 || Error.isString home name
370 || Error.isChar home name
373 Error.isString home name
376 Error.isString home name
379isNumber :: ModuleName.Canonical -> N.Name -> Bool
381 home == ModuleName.basics
383 (name == N.int || name == N.float)
386unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
387unifyFlexSuperStructure context super flatType =
390 if atomMatchesSuper super home name then
391 merge context (Structure flatType)
395 App1 home name [variable] | home == ModuleName.list && name == N.list ->
401 merge context (Structure flatType)
404 do comparableOccursCheck context
405 merge context (Structure flatType)
406 unifyComparableRecursive variable
409 do comparableOccursCheck context
410 merge context (Structure flatType)
411 unifyComparableRecursive variable
422 do comparableOccursCheck context
423 merge context (Structure flatType)
424 unifyComparableRecursive a
425 unifyComparableRecursive b
431 unifyComparableRecursive c
440-- TODO: is there some way to avoid doing this?
441-- Do type classes require occurs checks?
442comparableOccursCheck :: Context -> Unify ()
443comparableOccursCheck (Context _ _ var _) =
444 Unify $ \vars ok err ->
445 do hasOccurred <- Occurs.occurs var
451unifyComparableRecursive :: Variable -> Unify ()
452unifyComparableRecursive var =
453 do compVar <- register $
454 do (Descriptor _ rank _ _) <- UF.get var
455 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
456 guardedUnify compVar var
463unifyAlias :: Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Variable)] -> Variable -> Content -> Unify ()
464unifyAlias context home name args realVar otherContent =
467 merge context (Alias home name args realVar)
470 subUnify realVar (_second context)
473 subUnify realVar (_second context)
476 subUnify realVar (_second context)
478 Alias otherHome otherName otherArgs otherRealVar ->
479 if name == otherName && home == otherHome then
480 Unify $ \vars ok err ->
483 case merge context otherContent of
487 unifyAliasArgs vars context args otherArgs ok1 err
490 subUnify realVar otherRealVar
493 subUnify realVar (_second context)
499unifyAliasArgs :: [Variable] -> Context -> [(N.Name,Variable)] -> [(N.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
500unifyAliasArgs vars context args1 args2 ok err =
505 case subUnify arg1 arg2 of
508 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
509 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
527unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
528unifyStructure context flatType content otherContent =
531 merge context content
534 unifyFlexSuperStructure (reorient context) super flatType
542 Alias _ _ _ realVar ->
543 subUnify (_first context) realVar
545 Structure otherFlatType ->
546 case (flatType, otherFlatType) of
547 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
548 Unify $ \vars ok err ->
551 case merge context otherContent of
555 unifyArgs vars context args otherArgs ok1 err
557 (Fun1 arg1 res1, Fun1 arg2 res2) ->
561 merge context otherContent
563 (EmptyRecord1, EmptyRecord1) ->
564 merge context otherContent
566 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
567 subUnify ext (_second context)
569 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
570 subUnify (_first context) ext
572 (Record1 fields1 ext1, Record1 fields2 ext2) ->
573 Unify $ \vars ok err ->
574 do structure1 <- gatherFields fields1 ext1
575 structure2 <- gatherFields fields2 ext2
576 case unifyRecord context structure1 structure2 of
580 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
584 merge context otherContent
586 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
591 merge context otherContent
594 merge context otherContent
607unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
608unifyArgs vars context args1 args2 ok err =
613 case subUnify arg1 arg2 of
616 (\vs () -> unifyArgs vs context others1 others2 ok err)
617 (\vs () -> unifyArgs vs context others1 others2 err err)
635unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
636unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
638 sharedFields = Map.intersectionWith (,) fields1 fields2
639 uniqueFields1 = Map.difference fields1 fields2
640 uniqueFields2 = Map.difference fields2 fields1
642 if Map.null uniqueFields1 then
644 if Map.null uniqueFields2 then
647 (unifySharedFields context sharedFields Map.empty ext1)
650 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
652 (subUnify ext1 subRecord)
653 (unifySharedFields context sharedFields Map.empty subRecord)
657 if Map.null uniqueFields2 then
658 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
660 (subUnify subRecord ext2)
661 (unifySharedFields context sharedFields Map.empty subRecord)
664 do let otherFields = Map.union uniqueFields1 uniqueFields2
665 ext <- fresh context Type.unnamedFlexVar
666 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
667 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
671 (unifySharedFields context sharedFields otherFields ext)
674unifySharedFields :: Context -> Map.Map N.Name (Variable, Variable) -> Map.Map N.Name Variable -> Variable -> Unify ()
675unifySharedFields context sharedFields otherFields ext =
676 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
677 if Map.size sharedFields == Map.size matchingFields
678 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
682unifyField :: N.Name -> (Variable, Variable) -> Unify (Maybe Variable)
683unifyField _ (actual, expected) =
684 Unify $ \vars ok _ ->
685 case subUnify actual expected of
688 (\vs () -> ok vs (Just actual))
689 (\vs () -> ok vs Nothing)
693-- GATHER RECORD STRUCTURE
696data RecordStructure =
698 { _fields :: Map.Map N.Name Variable
699 , _extension :: Variable
703gatherFields :: Map.Map N.Name Variable -> Variable -> IO RecordStructure
704gatherFields fields variable =
705 do (Descriptor content _ _ _) <- UF.get variable
707 Structure (Record1 subFields subExt) ->
708 gatherFields (Map.union fields subFields) subExt
711 -- TODO may be dropping useful alias info here
712 gatherFields fields var
715 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