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 ->
121-- UNIFICATION HELPERS
127 , _firstDesc :: Descriptor
128 , _second :: Variable
129 , _secondDesc :: Descriptor
133reorient :: Context -> Context
134reorient (Context var1 desc1 var2 desc2) =
135 Context var2 desc2 var1 desc1
142merge :: Context -> Content -> Unify ()
143merge (Context var1 (Descriptor _ rank1 _ _) var2 (Descriptor _ rank2 _ _)) content =
144 Unify $ \vars ok _ ->
146 UF.union var1 var2 (Descriptor content (min rank1 rank2) noMark Nothing)
149fresh :: Context -> Content -> Unify Variable
150fresh (Context _ (Descriptor _ rank1 _ _) _ (Descriptor _ rank2 _ _)) content =
151 register $ UF.fresh $
152 Descriptor content (min rank1 rank2) noMark Nothing
156-- ACTUALLY UNIFY THINGS
159guardedUnify :: Variable -> Variable -> Unify ()
160guardedUnify left right =
161 Unify $ \vars ok err ->
162 do equivalent <- UF.equivalent left right
166 do leftDesc <- UF.get left
167 rightDesc <- UF.get right
168 case actuallyUnify (Context left leftDesc right rightDesc) of
173subUnify :: Variable -> Variable -> Unify ()
175 guardedUnify var1 var2
178actuallyUnify :: Context -> Unify ()
179actuallyUnify context@(Context _ (Descriptor firstContent _ _ _) _ (Descriptor secondContent _ _ _)) =
182 unifyFlex context firstContent secondContent
185 unifyFlexSuper context super firstContent secondContent
188 unifyRigid context Nothing firstContent secondContent
190 RigidSuper super _ ->
191 unifyRigid context (Just super) firstContent secondContent
193 Alias home name args realVar ->
194 unifyAlias context home name args realVar secondContent
196 Structure flatType ->
197 unifyStructure context flatType firstContent secondContent
200 -- If there was an error, just pretend it is okay. This lets us avoid
201 -- "cascading" errors where one problem manifests as multiple message.
206-- UNIFY FLEXIBLE VARIABLES
209unifyFlex :: Context -> Content -> Content -> Unify ()
210unifyFlex context content otherContent =
215 -- TODO see if wildcarding makes a noticable perf difference
227 merge context otherContent
230 merge context otherContent
233 merge context otherContent
236 merge context otherContent
239 merge context otherContent
243-- UNIFY RIGID VARIABLES
246unifyRigid :: Context -> Maybe SuperType -> Content -> Content -> Unify ()
247unifyRigid context maybeSuper content otherContent =
250 merge context content
252 FlexSuper otherSuper _ ->
255 if combineRigidSupers super otherSuper then
256 merge context content
280-- UNIFY SUPER VARIABLES
283unifyFlexSuper :: Context -> SuperType -> Content -> Content -> Unify ()
284unifyFlexSuper context super content otherContent =
286 Structure flatType ->
287 unifyFlexSuperStructure context super flatType
292 RigidSuper otherSuper _ ->
293 if combineRigidSupers otherSuper super then
294 merge context otherContent
299 merge context content
301 FlexSuper otherSuper _ ->
305 Number -> merge context content
306 Comparable -> merge context content
307 Appendable -> mismatch
308 CompAppend -> mismatch
312 Comparable -> merge context otherContent
313 Number -> merge context otherContent
314 Appendable -> merge context (Type.unnamedFlexSuper CompAppend)
315 CompAppend -> merge context otherContent
319 Appendable -> merge context otherContent
320 Comparable -> merge context (Type.unnamedFlexSuper CompAppend)
321 CompAppend -> merge context otherContent
326 Comparable -> merge context content
327 Appendable -> merge context content
328 CompAppend -> merge context content
331 Alias _ _ _ realVar ->
332 subUnify (_first context) realVar
338combineRigidSupers :: SuperType -> SuperType -> Bool
339combineRigidSupers rigid flex =
341 || (rigid == Number && flex == Comparable)
342 || (rigid == CompAppend && (flex == Comparable || flex == Appendable))
345atomMatchesSuper :: SuperType -> ModuleName.Canonical -> N.Name -> Bool
346atomMatchesSuper super home name =
353 || Error.isString home name
354 || Error.isChar home name
357 Error.isString home name
360 Error.isString home name
363isNumber :: ModuleName.Canonical -> N.Name -> Bool
365 home == ModuleName.basics
367 (name == N.int || name == N.float)
370unifyFlexSuperStructure :: Context -> SuperType -> FlatType -> Unify ()
371unifyFlexSuperStructure context super flatType =
374 if atomMatchesSuper super home name then
375 merge context (Structure flatType)
379 App1 home name [variable] | home == ModuleName.list && name == N.list ->
385 merge context (Structure flatType)
388 do comparableOccursCheck context
389 merge context (Structure flatType)
390 unifyComparableRecursive variable
393 do comparableOccursCheck context
394 merge context (Structure flatType)
395 unifyComparableRecursive variable
406 do comparableOccursCheck context
407 merge context (Structure flatType)
408 unifyComparableRecursive a
409 unifyComparableRecursive b
415 unifyComparableRecursive c
424-- TODO: is there some way to avoid doing this?
425-- Do type classes require occurs checks?
426comparableOccursCheck :: Context -> Unify ()
427comparableOccursCheck (Context _ _ var _) =
428 Unify $ \vars ok err ->
429 do hasOccurred <- Occurs.occurs var
435unifyComparableRecursive :: Variable -> Unify ()
436unifyComparableRecursive var =
437 do compVar <- register $
438 do (Descriptor _ rank _ _) <- UF.get var
439 UF.fresh $ Descriptor (Type.unnamedFlexSuper Comparable) rank noMark Nothing
440 guardedUnify compVar var
447unifyAlias :: Context -> ModuleName.Canonical -> N.Name -> [(N.Name, Variable)] -> Variable -> Content -> Unify ()
448unifyAlias context home name args realVar otherContent =
451 merge context (Alias home name args realVar)
454 subUnify realVar (_second context)
457 subUnify realVar (_second context)
460 subUnify realVar (_second context)
462 Alias otherHome otherName otherArgs otherRealVar ->
463 if name == otherName && home == otherHome then
464 Unify $ \vars ok err ->
467 case merge context otherContent of
471 unifyAliasArgs vars context args otherArgs ok1 err
474 subUnify realVar otherRealVar
477 subUnify realVar (_second context)
483unifyAliasArgs :: [Variable] -> Context -> [(N.Name,Variable)] -> [(N.Name,Variable)] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
484unifyAliasArgs vars context args1 args2 ok err =
489 case subUnify arg1 arg2 of
492 (\vs () -> unifyAliasArgs vs context others1 others2 ok err)
493 (\vs () -> unifyAliasArgs vs context others1 others2 err err)
511unifyStructure :: Context -> FlatType -> Content -> Content -> Unify ()
512unifyStructure context flatType content otherContent =
515 merge context content
518 unifyFlexSuperStructure (reorient context) super flatType
526 Alias _ _ _ realVar ->
527 subUnify (_first context) realVar
529 Structure otherFlatType ->
530 case (flatType, otherFlatType) of
531 (App1 home name args, App1 otherHome otherName otherArgs) | home == otherHome && name == otherName ->
532 Unify $ \vars ok err ->
535 case merge context otherContent of
539 unifyArgs vars context args otherArgs ok1 err
541 (Fun1 arg1 res1, Fun1 arg2 res2) ->
542 do subUnify arg1 arg2
544 merge context otherContent
546 (EmptyRecord1, EmptyRecord1) ->
547 merge context otherContent
549 (Record1 fields ext, EmptyRecord1) | Map.null fields ->
550 subUnify ext (_second context)
552 (EmptyRecord1, Record1 fields ext) | Map.null fields ->
553 subUnify (_first context) ext
555 (Record1 fields1 ext1, Record1 fields2 ext2) ->
556 Unify $ \vars ok err ->
557 do structure1 <- gatherFields fields1 ext1
558 structure2 <- gatherFields fields2 ext2
559 case unifyRecord context structure1 structure2 of
563 (Tuple1 a b Nothing, Tuple1 x y Nothing) ->
566 merge context otherContent
568 (Tuple1 a b (Just c), Tuple1 x y (Just z)) ->
572 merge context otherContent
575 merge context otherContent
588unifyArgs :: [Variable] -> Context -> [Variable] -> [Variable] -> ([Variable] -> () -> IO r) -> ([Variable] -> () -> IO r) -> IO r
589unifyArgs vars context args1 args2 ok err =
594 case subUnify arg1 arg2 of
597 (\vs () -> unifyArgs vs context others1 others2 ok err)
598 (\vs () -> unifyArgs vs context others1 others2 err err)
616unifyRecord :: Context -> RecordStructure -> RecordStructure -> Unify ()
617unifyRecord context (RecordStructure fields1 ext1) (RecordStructure fields2 ext2) =
619 sharedFields = Map.intersectionWith (,) fields1 fields2
620 uniqueFields1 = Map.difference fields1 fields2
621 uniqueFields2 = Map.difference fields2 fields1
623 if Map.null uniqueFields1 then
625 if Map.null uniqueFields2 then
626 do subUnify ext1 ext2
627 unifySharedFields context sharedFields Map.empty ext1
630 do subRecord <- fresh context (Structure (Record1 uniqueFields2 ext2))
631 subUnify ext1 subRecord
632 unifySharedFields context sharedFields Map.empty subRecord
636 if Map.null uniqueFields2 then
637 do subRecord <- fresh context (Structure (Record1 uniqueFields1 ext1))
638 subUnify subRecord ext2
639 unifySharedFields context sharedFields Map.empty subRecord
642 do let otherFields = Map.union uniqueFields1 uniqueFields2
643 ext <- fresh context Type.unnamedFlexVar
644 sub1 <- fresh context (Structure (Record1 uniqueFields1 ext))
645 sub2 <- fresh context (Structure (Record1 uniqueFields2 ext))
648 unifySharedFields context sharedFields otherFields ext
651unifySharedFields :: Context -> Map.Map N.Name (Variable, Variable) -> Map.Map N.Name Variable -> Variable -> Unify ()
652unifySharedFields context sharedFields otherFields ext =
653 do matchingFields <- Map.traverseMaybeWithKey unifyField sharedFields
654 if Map.size sharedFields == Map.size matchingFields
655 then merge context (Structure (Record1 (Map.union matchingFields otherFields) ext))
659unifyField :: N.Name -> (Variable, Variable) -> Unify (Maybe Variable)
660unifyField _ (actual, expected) =
661 Unify $ \vars ok _ ->
662 case subUnify actual expected of
665 (\vs () -> ok vs (Just actual))
666 (\vs () -> ok vs Nothing)
670-- GATHER RECORD STRUCTURE
673data RecordStructure =
675 { _fields :: Map.Map N.Name Variable
676 , _extension :: Variable
680gatherFields :: Map.Map N.Name Variable -> Variable -> IO RecordStructure
681gatherFields fields variable =
682 do (Descriptor content _ _ _) <- UF.get variable
684 Structure (Record1 subFields subExt) ->
685 gatherFields (Map.union fields subFields) subExt
688 -- TODO may be dropping useful alias info here
689 gatherFields fields var
692 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