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
97 (>>=) (Unify ka) callback =
98 Unify $ \vars ok err ->
102 Unify kb -> kb vars1 ok err
106 (>>) (Unify ka) (Unify kb) =
107 Unify $ \vars ok err ->
109 ok1 vars1 _ = kb vars1 ok err
114register :: IO Variable -> Unify Variable
116 Unify $ \vars ok _ ->
123 Unify $ \vars _ err ->
128-- UNIFICATION HELPERS
134 , _firstDesc :: Descriptor
135 , _second :: Variable
136 , _secondDesc :: Descriptor
140reorient :: Context -> Context
141reorient (Context var1 desc1 var2 desc2) =
142 Context var2 desc2 var1 desc1
149merge :: Context -> Content -> Unify ()
150merge (Context var1 (Descriptor _ rank1 _ _) var2 (Descriptor _ rank2 _ _)) content =
151 Unify $ \vars ok _ ->
153 UF.union var1 var2 (Descriptor content (min rank1 rank2) noMark Nothing)
156fresh :: Context -> Content -> Unify Variable
157fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
158 register $ UF.fresh $
159 Descriptor content (min rank1 rank2) noMark Nothing
163-- ACTUALLY UNIFY THINGS
166guardedUnify :: Variable -> Variable -> Unify ()
167guardedUnify left right =
168 Unify $ \vars ok err ->
169 do equivalent <- UF.equivalent left right
173 do leftDesc <- UF.get left
174 rightDesc <- UF.get right
175 case actuallyUnify (Context left leftDesc right rightDesc) of
180subUnify :: Variable -> Variable -> Unify ()
182 guardedUnify var1 var2
185actuallyUnify :: Context -> Unify ()
186actuallyUnify context@(Context _ (Descriptor firstContent _ _ _) _ (Descriptor secondContent _ _ _)) =
189 unifyFlex context firstContent secondContent
192 unifyFlexSuper context super firstContent secondContent
195 unifyRigid context Nothing firstContent secondContent
197 RigidSuper super _ ->
198 unifyRigid context (Just super) firstContent secondContent
200 Alias home name args realVar ->
201 unifyAlias context home name args realVar secondContent
203 Structure flatType ->
204 unifyStructure context flatType firstContent secondContent
207 -- If there was an error, just pretend it is okay. This lets us avoid
208 -- "cascading" errors where one problem manifests as multiple message.
213-- UNIFY FLEXIBLE VARIABLES
216unifyFlex :: Context -> Content -> Content -> Unify ()
217unifyFlex context content otherContent =
232 merge context otherContent
235 merge context otherContent
238 merge context otherContent
241 merge context otherContent
244 merge context otherContent
248-- UNIFY RIGID VARIABLES
251unifyRigid :: Context -> Maybe SuperType -> Content -> Content -> Unify ()
252unifyRigid context maybeSuper content otherContent =
255 merge context content
257 FlexSuper otherSuper _ ->
260 if combineRigidSupers super otherSuper then
261 merge context content
285-- UNIFY SUPER VARIABLES
288unifyFlexSuper :: Context -> SuperType -> Content -> Content -> Unify ()
289unifyFlexSuper context super content otherContent =
291 Structure flatType ->
292 unifyFlexSuperStructure context super flatType
297 RigidSuper otherSuper _ ->
298 if combineRigidSupers otherSuper super then
299 merge context otherContent
304 merge context content
306 FlexSuper otherSuper _ ->
310 Number -> merge context content
311 Comparable -> merge context content
312 Appendable -> mismatch
313 CompAppend -> mismatch
317 Comparable -> merge context otherContent
318 Number -> merge context otherContent
319 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
320 CompAppend -> merge context otherContent
324 Appendable -> merge context otherContent
325 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
326 CompAppend -> merge context otherContent
331 Comparable -> merge context content
332 Appendable -> merge context content
333 CompAppend -> merge context content
336 Alias _ _ _ realVar ->
337 subUnify (_first context) realVar
343combineRigidSupers :: SuperType -> SuperType -> Bool
344combineRigidSupers rigid flex =
346 || (rigid == Number && flex == Comparable)
347 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
350atomMatchesSuper :: SuperType -> ModuleName.Canonical -> Name.Name -> Bool
351atomMatchesSuper super home name =
358 || Error.isString home name
359 || Error.isChar home name
362 Error.isString home name
365 Error.isString home name
368isNumber :: ModuleName.Canonical -> Name.Name -> Bool
370 home == ModuleName.basics
372 (name == Name.int || name == Name.float)
375unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
376unifyFlexSuperStructure context super flatType =
379 if atomMatchesSuper super home name then
380 merge context (Structure flatType)
384 App1 home name [variable] | home == ModuleName.list && name == Name.list ->
390 merge context (Structure flatType)
393 do comparableOccursCheck context
394 merge context (Structure flatType)
395 unifyComparableRecursive variable
398 do comparableOccursCheck context
399 merge context (Structure flatType)
400 unifyComparableRecursive variable
411 do comparableOccursCheck context
412 merge context (Structure flatType)
413 unifyComparableRecursive a
414 unifyComparableRecursive b
420 unifyComparableRecursive c
429-- TODO: is there some way to avoid doing this?
430-- Do type classes require occurs checks?
431comparableOccursCheck :: Context -> Unify ()
432comparableOccursCheck (Context _ _ var _) =
433 Unify $ \vars ok err ->
434 do hasOccurred <- Occurs.occurs var
440unifyComparableRecursive :: Variable -> Unify ()
441unifyComparableRecursive var =
442 do compVar <- register $
443 do (Descriptor _ rank _ _) <- UF.get var
444 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
445 guardedUnify compVar var
452unifyAlias :: Context -> ModuleName.Canonical -> Name.Name -> [(Name.Name, Variable)] -> Variable -> Content -> Unify ()
453unifyAlias context home name args realVar otherContent =
456 merge context (Alias home name args realVar)
459 subUnify realVar (_second context)
462 subUnify realVar (_second context)
465 subUnify realVar (_second context)
467 Alias otherHome otherName otherArgs otherRealVar ->
468 if name == otherName && home == otherHome then
469 Unify $ \vars ok err ->
472 case merge context otherContent of
476 unifyAliasArgs vars context args otherArgs ok1 err
479 subUnify realVar otherRealVar
482 subUnify realVar (_second context)
488unifyAliasArgs :: [Variable] -> Context -> [(Name.Name,Variable)] -> [(Name.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
489unifyAliasArgs vars context args1 args2 ok err =
494 case subUnify arg1 arg2 of
497 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
498 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
516unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
517unifyStructure context flatType content otherContent =
520 merge context content
523 unifyFlexSuperStructure (reorient context) super flatType
531 Alias _ _ _ realVar ->
532 subUnify (_first context) realVar
534 Structure otherFlatType ->
535 case (flatType, otherFlatType) of
536 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
537 Unify $ \vars ok err ->
540 case merge context otherContent of
544 unifyArgs vars context args otherArgs ok1 err
546 (Fun1 arg1 res1, Fun1 arg2 res2) ->
547 do subUnify arg1 arg2
549 merge context otherContent
551 (EmptyRecord1, EmptyRecord1) ->
552 merge context otherContent
554 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
555 subUnify ext (_second context)
557 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
558 subUnify (_first context) ext
560 (Record1 fields1 ext1, Record1 fields2 ext2) ->
561 Unify $ \vars ok err ->
562 do structure1 <- gatherFields fields1 ext1
563 structure2 <- gatherFields fields2 ext2
564 case unifyRecord context structure1 structure2 of
568 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
571 merge context otherContent
573 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
577 merge context otherContent
580 merge context otherContent
593unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
594unifyArgs vars context args1 args2 ok err =
599 case subUnify arg1 arg2 of
602 (\vs () -> unifyArgs vs context others1 others2 ok err)
603 (\vs () -> unifyArgs vs context others1 others2 err err)
621unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
622unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
624 sharedFields = Map.intersectionWith (,) fields1 fields2
625 uniqueFields1 = Map.difference fields1 fields2
626 uniqueFields2 = Map.difference fields2 fields1
628 if Map.null uniqueFields1 then
630 if Map.null uniqueFields2 then
631 do subUnify ext1 ext2
632 unifySharedFields context sharedFields Map.empty ext1
635 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
636 subUnify ext1 subRecord
637 unifySharedFields context sharedFields Map.empty subRecord
641 if Map.null uniqueFields2 then
642 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
643 subUnify subRecord ext2
644 unifySharedFields context sharedFields Map.empty subRecord
647 do let otherFields = Map.union uniqueFields1 uniqueFields2
648 ext <- fresh context Type.unnamedFlexVar
649 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
650 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
653 unifySharedFields context sharedFields otherFields ext
656unifySharedFields :: Context -> Map.Map Name.Name (Variable, Variable) -> Map.Map Name.Name Variable -> Variable -> Unify ()
657unifySharedFields context sharedFields otherFields ext =
658 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
659 if Map.size sharedFields == Map.size matchingFields
660 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
664unifyField :: Name.Name -> (Variable, Variable) -> Unify (Maybe Variable)
665unifyField _ (actual, expected) =
666 Unify $ \vars ok _ ->
667 case subUnify actual expected of
670 (\vs () -> ok vs (Just actual))
671 (\vs () -> ok vs Nothing)
675-- GATHER RECORD STRUCTURE
678data RecordStructure =
680 { _fields :: Map.Map Name.Name Variable
681 , _extension :: Variable
685gatherFields :: Map.Map Name.Name Variable -> Variable -> IO RecordStructure
686gatherFields fields variable =
687 do (Descriptor content _ _ _) <- UF.get variable
689 Structure (Record1 subFields subExt) ->
690 gatherFields (Map.union fields subFields) subExt
693 -- TODO may be dropping useful alias info here
694 gatherFields fields var
697 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