1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings, Rank2Types #-}
10import qualified Data.Map.Strict as Map
11import qualified Data.Name as Name
13import qualified Elm.ModuleName as ModuleName
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
93 -- TODO PERF add INLINE here?
98 (>>=) (Unify ka) callback =
99 Unify $ \vars ok err ->
103 Unify kb -> kb vars1 ok err
107 (>>) (Unify ka) (Unify kb) =
108 Unify $ \vars ok err ->
110 ok1 vars1 _ = kb vars1 ok err
115register :: IO Variable -> Unify Variable
117 Unify $ \vars ok _ ->
124 Unify $ \vars _ err ->
129-- UNIFICATION HELPERS
135 , _firstDesc :: Descriptor
136 , _second :: Variable
137 , _secondDesc :: Descriptor
141reorient :: Context -> Context
142reorient (Context var1 desc1 var2 desc2) =
143 Context var2 desc2 var1 desc1
150merge :: Context -> Content -> Unify ()
151merge (Context var1 (Descriptor _ rank1 _ _) var2 (Descriptor _ rank2 _ _)) content =
152 Unify $ \vars ok _ ->
154 UF.union var1 var2 (Descriptor content (min rank1 rank2) noMark Nothing)
157fresh :: Context -> Content -> Unify Variable
158fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
159 register $ UF.fresh $
160 Descriptor content (min rank1 rank2) noMark Nothing
164-- ACTUALLY UNIFY THINGS
167guardedUnify :: Variable -> Variable -> Unify ()
168guardedUnify left right =
169 Unify $ \vars ok err ->
170 do equivalent <- UF.equivalent left right
174 do leftDesc <- UF.get left
175 rightDesc <- UF.get right
176 case actuallyUnify (Context left leftDesc right rightDesc) of
181subUnify :: Variable -> Variable -> Unify ()
183 guardedUnify var1 var2
186actuallyUnify :: Context -> Unify ()
187actuallyUnify context@(Context _ (Descriptor firstContent _ _ _) _ (Descriptor secondContent _ _ _)) =
190 unifyFlex context firstContent secondContent
193 unifyFlexSuper context super firstContent secondContent
196 unifyRigid context Nothing firstContent secondContent
198 RigidSuper super _ ->
199 unifyRigid context (Just super) firstContent secondContent
201 Alias home name args realVar ->
202 unifyAlias context home name args realVar secondContent
204 Structure flatType ->
205 unifyStructure context flatType firstContent secondContent
208 -- If there was an error, just pretend it is okay. This lets us avoid
209 -- "cascading" errors where one problem manifests as multiple message.
214-- UNIFY FLEXIBLE VARIABLES
217unifyFlex :: Context -> Content -> Content -> Unify ()
218unifyFlex context content otherContent =
223 -- TODO see if wildcarding makes a noticable perf difference
235 merge context otherContent
238 merge context otherContent
241 merge context otherContent
244 merge context otherContent
247 merge context otherContent
251-- UNIFY RIGID VARIABLES
254unifyRigid :: Context -> Maybe SuperType -> Content -> Content -> Unify ()
255unifyRigid context maybeSuper content otherContent =
258 merge context content
260 FlexSuper otherSuper _ ->
263 if combineRigidSupers super otherSuper then
264 merge context content
288-- UNIFY SUPER VARIABLES
291unifyFlexSuper :: Context -> SuperType -> Content -> Content -> Unify ()
292unifyFlexSuper context super content otherContent =
294 Structure flatType ->
295 unifyFlexSuperStructure context super flatType
300 RigidSuper otherSuper _ ->
301 if combineRigidSupers otherSuper super then
302 merge context otherContent
307 merge context content
309 FlexSuper otherSuper _ ->
313 Number -> merge context content
314 Comparable -> merge context content
315 Appendable -> mismatch
316 CompAppend -> mismatch
320 Comparable -> merge context otherContent
321 Number -> merge context otherContent
322 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
323 CompAppend -> merge context otherContent
327 Appendable -> merge context otherContent
328 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
329 CompAppend -> merge context otherContent
334 Comparable -> merge context content
335 Appendable -> merge context content
336 CompAppend -> merge context content
339 Alias _ _ _ realVar ->
340 subUnify (_first context) realVar
346combineRigidSupers :: SuperType -> SuperType -> Bool
347combineRigidSupers rigid flex =
349 || (rigid == Number && flex == Comparable)
350 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
353atomMatchesSuper :: SuperType -> ModuleName.Canonical -> Name.Name -> Bool
354atomMatchesSuper super home name =
361 || Error.isString home name
362 || Error.isChar home name
365 Error.isString home name
368 Error.isString home name
371isNumber :: ModuleName.Canonical -> Name.Name -> Bool
373 home == ModuleName.basics
375 (name == Name.int || name == Name.float)
378unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
379unifyFlexSuperStructure context super flatType =
382 if atomMatchesSuper super home name then
383 merge context (Structure flatType)
387 App1 home name [variable] | home == ModuleName.list && name == Name.list ->
393 merge context (Structure flatType)
396 do comparableOccursCheck context
397 merge context (Structure flatType)
398 unifyComparableRecursive variable
401 do comparableOccursCheck context
402 merge context (Structure flatType)
403 unifyComparableRecursive variable
414 do comparableOccursCheck context
415 merge context (Structure flatType)
416 unifyComparableRecursive a
417 unifyComparableRecursive b
423 unifyComparableRecursive c
432-- TODO: is there some way to avoid doing this?
433-- Do type classes require occurs checks?
434comparableOccursCheck :: Context -> Unify ()
435comparableOccursCheck (Context _ _ var _) =
436 Unify $ \vars ok err ->
437 do hasOccurred <- Occurs.occurs var
443unifyComparableRecursive :: Variable -> Unify ()
444unifyComparableRecursive var =
445 do compVar <- register $
446 do (Descriptor _ rank _ _) <- UF.get var
447 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
448 guardedUnify compVar var
455unifyAlias :: Context -> ModuleName.Canonical -> Name.Name -> [(Name.Name, Variable)] -> Variable -> Content -> Unify ()
456unifyAlias context home name args realVar otherContent =
459 merge context (Alias home name args realVar)
462 subUnify realVar (_second context)
465 subUnify realVar (_second context)
468 subUnify realVar (_second context)
470 Alias otherHome otherName otherArgs otherRealVar ->
471 if name == otherName && home == otherHome then
472 Unify $ \vars ok err ->
475 case merge context otherContent of
479 unifyAliasArgs vars context args otherArgs ok1 err
482 subUnify realVar otherRealVar
485 subUnify realVar (_second context)
491unifyAliasArgs :: [Variable] -> Context -> [(Name.Name,Variable)] -> [(Name.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
492unifyAliasArgs vars context args1 args2 ok err =
497 case subUnify arg1 arg2 of
500 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
501 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
519unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
520unifyStructure context flatType content otherContent =
523 merge context content
526 unifyFlexSuperStructure (reorient context) super flatType
534 Alias _ _ _ realVar ->
535 subUnify (_first context) realVar
537 Structure otherFlatType ->
538 case (flatType, otherFlatType) of
539 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
540 Unify $ \vars ok err ->
543 case merge context otherContent of
547 unifyArgs vars context args otherArgs ok1 err
549 (Fun1 arg1 res1, Fun1 arg2 res2) ->
550 do subUnify arg1 arg2
552 merge context otherContent
554 (EmptyRecord1, EmptyRecord1) ->
555 merge context otherContent
557 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
558 subUnify ext (_second context)
560 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
561 subUnify (_first context) ext
563 (Record1 fields1 ext1, Record1 fields2 ext2) ->
564 Unify $ \vars ok err ->
565 do structure1 <- gatherFields fields1 ext1
566 structure2 <- gatherFields fields2 ext2
567 case unifyRecord context structure1 structure2 of
571 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
574 merge context otherContent
576 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
580 merge context otherContent
583 merge context otherContent
596unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
597unifyArgs vars context args1 args2 ok err =
602 case subUnify arg1 arg2 of
605 (\vs () -> unifyArgs vs context others1 others2 ok err)
606 (\vs () -> unifyArgs vs context others1 others2 err err)
624unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
625unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
627 sharedFields = Map.intersectionWith (,) fields1 fields2
628 uniqueFields1 = Map.difference fields1 fields2
629 uniqueFields2 = Map.difference fields2 fields1
631 if Map.null uniqueFields1 then
633 if Map.null uniqueFields2 then
634 do subUnify ext1 ext2
635 unifySharedFields context sharedFields Map.empty ext1
638 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
639 subUnify ext1 subRecord
640 unifySharedFields context sharedFields Map.empty subRecord
644 if Map.null uniqueFields2 then
645 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
646 subUnify subRecord ext2
647 unifySharedFields context sharedFields Map.empty subRecord
650 do let otherFields = Map.union uniqueFields1 uniqueFields2
651 ext <- fresh context Type.unnamedFlexVar
652 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
653 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
656 unifySharedFields context sharedFields otherFields ext
659unifySharedFields :: Context -> Map.Map Name.Name (Variable, Variable) -> Map.Map Name.Name Variable -> Variable -> Unify ()
660unifySharedFields context sharedFields otherFields ext =
661 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
662 if Map.size sharedFields == Map.size matchingFields
663 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
667unifyField :: Name.Name -> (Variable, Variable) -> Unify (Maybe Variable)
668unifyField _ (actual, expected) =
669 Unify $ \vars ok _ ->
670 case subUnify actual expected of
673 (\vs () -> ok vs (Just actual))
674 (\vs () -> ok vs Nothing)
678-- GATHER RECORD STRUCTURE
681data RecordStructure =
683 { _fields :: Map.Map Name.Name Variable
684 , _extension :: Variable
688gatherFields :: Map.Map Name.Name Variable -> Variable -> IO RecordStructure
689gatherFields fields variable =
690 do (Descriptor content _ _ _) <- UF.get variable
692 Structure (Record1 subFields subExt) ->
693 gatherFields (Map.union fields subFields) subExt
696 -- TODO may be dropping useful alias info here
697 gatherFields fields var
700 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