1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
10import qualified Data.Map.Strict as Map
11import Data.Map.Strict ((!))
12import qualified Data.Vector as Vector
13import qualified Data.Vector.Mutable as MVector
15import qualified AST.Canonical as Can
16import qualified Elm.Name as N
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Type as Error
19import qualified Reporting.Render.Type as RT
20import qualified Type.Occurs as Occurs
21import Type.Type as Type
22import qualified Type.Error as ET
23import qualified Type.Unify as Unify
24import qualified Type.UnionFind as UF
31run :: Constraint -> IO (Either [Error.Error] (Map.Map N.Name Can.Annotation))
33 do pools <- MVector.replicate 8 []
35 (State env _ errors) <-
36 solve Map.empty outermostRank pools emptyState constraint
40 Right <$> traverse Type.toAnnotation env
47{-# NOINLINE emptyState #-}
50 State Map.empty (nextMark noMark) []
58 Map.Map N.Name Variable
62 MVector.IOVector [Variable]
69 , _errors :: [Error.Error]
73solve :: Env -> Int -> Pools -> State -> Constraint -> IO State
74solve env rank pools state constraint =
79 CSaveTheEnvironment ->
80 return (state { _env = env })
82 CEqual region category tipe expectation ->
83 do actual <- typeToVariable rank pools tipe
84 expected <- expectedToVariable rank pools expectation
85 answer <- Unify.unify actual expected
88 do introduce rank pools vars
91 Unify.Err vars actualType expectedType ->
92 do introduce rank pools vars
93 return $ addError state $
94 Error.BadExpr region category actualType $
95 Error.typeReplace expectation expectedType
97 CLocal region name expectation ->
98 do actual <- makeCopy rank pools (env ! name)
99 expected <- expectedToVariable rank pools expectation
100 answer <- Unify.unify actual expected
103 do introduce rank pools vars
106 Unify.Err vars actualType expectedType ->
107 do introduce rank pools vars
108 return $ addError state $
109 Error.BadExpr region (Error.Local name) actualType $
110 Error.typeReplace expectation expectedType
112 CForeign region name (Can.Forall freeVars srcType) expectation ->
113 do actual <- srcTypeToVariable rank pools freeVars srcType
114 expected <- expectedToVariable rank pools expectation
115 answer <- Unify.unify actual expected
118 do introduce rank pools vars
121 Unify.Err vars actualType expectedType ->
122 do introduce rank pools vars
123 return $ addError state $
124 Error.BadExpr region (Error.Foreign name) actualType $
125 Error.typeReplace expectation expectedType
127 CPattern region category tipe expectation ->
128 do actual <- typeToVariable rank pools tipe
129 expected <- patternExpectationToVariable rank pools expectation
130 answer <- Unify.unify actual expected
133 do introduce rank pools vars
136 Unify.Err vars actualType expectedType ->
137 do introduce rank pools vars
138 return $ addError state $
139 Error.BadPattern region category actualType
140 (Error.ptypeReplace expectation expectedType)
143 foldM (solve env rank pools) state constraints
145 CLet [] flexs _ headerCon CTrue ->
146 do introduce rank pools flexs
147 solve env rank pools state headerCon
149 CLet [] [] header headerCon subCon ->
150 do state1 <- solve env rank pools state headerCon
151 locals <- traverse (A.traverse (typeToVariable rank pools)) header
152 let newEnv = Map.union env (Map.map A.toValue locals)
153 state2 <- solve newEnv rank pools state1 subCon
154 foldM occurs state2 $ Map.toList locals
156 CLet rigids flexs header headerCon subCon ->
158 -- work in the next pool to localize header
159 let nextRank = rank + 1
160 let poolsLength = MVector.length pools
162 if nextRank < poolsLength
164 else MVector.grow pools poolsLength
166 -- introduce variables
167 let vars = rigids ++ flexs
169 UF.modify var $ \(Descriptor content _ mark copy) ->
170 Descriptor content nextRank mark copy
171 MVector.write nextPools nextRank vars
173 -- run solver in next pool
174 locals <- traverse (A.traverse (typeToVariable nextRank nextPools)) header
175 (State savedEnv mark errors) <-
176 solve env nextRank nextPools state headerCon
179 let visitMark = nextMark youngMark
180 let finalMark = nextMark visitMark
183 generalize youngMark visitMark nextRank nextPools
184 MVector.write nextPools nextRank []
186 -- check that things went well
187 mapM_ isGeneric rigids
189 let newEnv = Map.union env (Map.map A.toValue locals)
190 let tempState = State savedEnv finalMark errors
191 newState <- solve newEnv rank nextPools tempState subCon
193 foldM occurs newState (Map.toList locals)
196-- Check that a variable has rank == noRank, meaning that it can be generalized.
197isGeneric :: Variable -> IO ()
199 do (Descriptor _ rank _ _) <- UF.get var
203 do tipe <- Type.toErrorType var
205 "You ran into a compiler bug. Here are some details for the developers:\n\n"
206 ++ " " ++ show (ET.toDoc Map.empty RT.None tipe) ++ " [rank = " ++ show rank ++ "]\n\n"
208 "Please create an <http://sscce.org/> and then report it\n\
209 \at <https://github.com/elm-lang/elm-compiler/issues>\n\n"
213-- EXPECTATIONS TO VARIABLE
216expectedToVariable :: Int -> Pools -> Error.Expected Type -> IO Variable
217expectedToVariable rank pools expectation =
218 typeToVariable rank pools $
220 Error.NoExpectation tipe ->
223 Error.FromContext _ _ tipe ->
226 Error.FromAnnotation _ _ _ tipe ->
230patternExpectationToVariable :: Int -> Pools -> Error.PExpected Type -> IO Variable
231patternExpectationToVariable rank pools expectation =
232 typeToVariable rank pools $
234 Error.PNoExpectation tipe ->
237 Error.PFromContext _ _ tipe ->
245addError :: State -> Error.Error -> State
246addError (State savedEnv rank errors) err =
247 State savedEnv rank (err:errors)
254occurs :: State -> (N.Name, A.Located Variable) -> IO State
255occurs state (name, A.At region variable) =
256 do hasOccurred <- Occurs.occurs variable
259 do errorType <- Type.toErrorType variable
260 (Descriptor _ rank mark copy) <- UF.get variable
261 UF.set variable (Descriptor Error rank mark copy)
262 return $ state { _errors = Error.InfiniteType region name errorType : _errors state }
271{-| Every variable has rank less than or equal to the maxRank of the pool.
272This sorts variables into the young and old pools accordingly.
274generalize :: Mark -> Mark -> Int -> Pools -> IO ()
275generalize youngMark visitMark youngRank pools =
276 do youngVars <- MVector.read pools youngRank
277 rankTable <- poolToRankTable youngMark youngRank youngVars
279 -- get the ranks right for each entry.
280 -- start at low ranks so that we only have to pass
281 -- over the information once.
283 (\rank table -> mapM_ (adjustRank youngMark visitMark rank) table)
286 -- For variables that have rank lowerer than youngRank, register them in
287 -- the appropriate old pool if they are not redundant.
288 Vector.forM_ (Vector.unsafeInit rankTable) $ \vars ->
290 do isRedundant <- UF.redundant var
294 do (Descriptor _ rank _ _) <- UF.get var
295 MVector.modify pools (var:) rank
297 -- For variables with rank youngRank
298 -- If rank < youngRank: register in oldPool
299 -- otherwise generalize
300 forM_ (Vector.unsafeLast rankTable) $ \var ->
301 do isRedundant <- UF.redundant var
305 do (Descriptor content rank mark copy) <- UF.get var
307 then MVector.modify pools (var:) rank
308 else UF.set var $ Descriptor content noRank mark copy
311poolToRankTable :: Mark -> Int -> [Variable] -> IO (Vector.Vector [Variable])
312poolToRankTable youngMark youngRank youngInhabitants =
313 do mutableTable <- MVector.replicate (youngRank + 1) []
315 -- Sort the youngPool variables into buckets by rank.
316 forM_ youngInhabitants $ \var ->
317 do (Descriptor content rank _ copy) <- UF.get var
318 UF.set var (Descriptor content rank youngMark copy)
319 MVector.modify mutableTable (var:) rank
321 Vector.unsafeFreeze mutableTable
328-- Adjust variable ranks such that ranks never increase as you move deeper.
329-- This way the outermost rank is representative of the entire structure.
331adjustRank :: Mark -> Mark -> Int -> Variable -> IO Int
332adjustRank youngMark visitMark groupRank var =
333 do (Descriptor content rank mark copy) <- UF.get var
334 if mark == youngMark then
335 do -- Set the variable as marked first because it may be cyclic.
336 UF.set var $ Descriptor content rank visitMark copy
337 maxRank <- adjustRankContent youngMark visitMark groupRank content
338 UF.set var $ Descriptor content maxRank visitMark copy
341 else if mark == visitMark then
345 do let minRank = min groupRank rank
346 -- TODO how can minRank ever be groupRank?
347 UF.set var $ Descriptor content minRank visitMark copy
351adjustRankContent :: Mark -> Mark -> Int -> Content -> IO Int
352adjustRankContent youngMark visitMark groupRank content =
354 go = adjustRank youngMark visitMark groupRank
369 Structure flatType ->
372 foldM (\rank arg -> max rank <$> go arg) outermostRank args
375 max <$> go arg <*> go result
378 -- THEORY: an empty record never needs to get generalized
381 Record1 fields extension ->
382 do extRank <- go extension
383 foldM (\rank field -> max rank <$> go field) extRank fields
386 -- THEORY: a unit never needs to get generalized
397 max (max ma mb) <$> go c
400 -- THEORY: anything in the realVar would be outermostRank
401 foldM (\rank (_, argVar) -> max rank <$> go argVar) outermostRank args
411introduce :: Int -> Pools -> [Variable] -> IO ()
412introduce rank pools variables =
413 do MVector.modify pools (variables++) rank
414 forM_ variables $ \var ->
415 UF.modify var $ \(Descriptor content _ mark copy) ->
416 Descriptor content rank mark copy
423typeToVariable :: Int -> Pools -> Type -> IO Variable
424typeToVariable rank pools tipe =
425 typeToVar rank pools Map.empty tipe
428typeToVar :: Int -> Pools -> Map.Map N.Name Variable -> Type -> IO Variable
429typeToVar rank pools aliasDict tipe =
430 let go = typeToVar rank pools aliasDict in
435 AppN home name args ->
436 do argVars <- traverse go args
437 register rank pools (Structure (App1 home name argVars))
442 register rank pools (Structure (Fun1 aVar bVar))
444 AliasN home name args aliasType ->
445 do argVars <- traverse (traverse go) args
446 aliasVar <- typeToVar rank pools (Map.fromList argVars) aliasType
447 register rank pools (Alias home name argVars aliasVar)
450 return (aliasDict ! name)
452 RecordN fields ext ->
453 do fieldVars <- traverse go fields
455 register rank pools (Structure (Record1 fieldVars extVar))
458 register rank pools emptyRecord1
461 register rank pools unit1
466 cVar <- traverse go c
467 register rank pools (Structure (Tuple1 aVar bVar cVar))
470register :: Int -> Pools -> Content -> IO Variable
471register rank pools content =
472 do var <- UF.fresh (Descriptor content rank noMark Nothing)
473 MVector.modify pools (var:) rank
477{-# NOINLINE emptyRecord1 #-}
478emptyRecord1 :: Content
480 Structure EmptyRecord1
483{-# NOINLINE unit1 #-}
490-- SOURCE TYPE TO VARIABLE
493srcTypeToVariable :: Int -> Pools -> Map.Map N.Name () -> Can.Type -> IO Variable
494srcTypeToVariable rank pools freeVars srcType =
497 | N.startsWith "number" name = FlexSuper Number (Just name)
498 | N.startsWith "comparable" name = FlexSuper Comparable (Just name)
499 | N.startsWith "appendable" name = FlexSuper Appendable (Just name)
500 | N.startsWith "compappend" name = FlexSuper CompAppend (Just name)
501 | otherwise = FlexVar (Just name)
504 UF.fresh (Descriptor (nameToContent name) rank noMark Nothing)
506 do flexVars <- Map.traverseWithKey makeVar freeVars
507 MVector.modify pools (Map.elems flexVars ++) rank
508 srcTypeToVar rank pools flexVars srcType
511srcTypeToVar :: Int -> Pools -> Map.Map N.Name Variable -> Can.Type -> IO Variable
512srcTypeToVar rank pools flexVars srcType =
513 let go = srcTypeToVar rank pools flexVars in
515 Can.TLambda argument result ->
516 do argVar <- go argument
517 resultVar <- go result
518 register rank pools (Structure (Fun1 argVar resultVar))
521 return (flexVars ! name)
523 Can.TType home name args ->
524 do argVars <- traverse go args
525 register rank pools (Structure (App1 home name argVars))
527 Can.TRecord fields maybeExt ->
528 do fieldVars <- traverse go fields
531 Nothing -> register rank pools emptyRecord1
532 Just ext -> return (flexVars ! ext)
533 register rank pools (Structure (Record1 fieldVars extVar))
536 register rank pools unit1
541 cVar <- traverse go c
542 register rank pools (Structure (Tuple1 aVar bVar cVar))
544 Can.TAlias home name args aliasType ->
545 do argVars <- traverse (traverse go) args
549 srcTypeToVar rank pools (Map.fromList argVars) tipe
554 register rank pools (Alias home name argVars aliasVar)
561makeCopy :: Int -> Pools -> Variable -> IO Variable
562makeCopy rank pools var =
563 do copy <- makeCopyHelp rank pools var
568makeCopyHelp :: Int -> Pools -> Variable -> IO Variable
569makeCopyHelp maxRank pools variable =
570 do (Descriptor content rank _ maybeCopy) <- UF.get variable
577 if rank /= noRank then
581 do let makeDescriptor c = Descriptor c maxRank noMark Nothing
582 copy <- UF.fresh $ makeDescriptor content
583 MVector.modify pools (copy:) maxRank
585 -- Link the original variable to the new variable. This lets us
586 -- avoid making multiple copies of the variable we are instantiating.
588 -- Need to do this before recursively copying to avoid looping.
590 Descriptor content rank noMark (Just copy)
592 -- Now we recursively copy the content of the variable.
593 -- We have already marked the variable as copied, so we
594 -- will not repeat this work or crawl this variable again.
597 do newTerm <- traverseFlatType (makeCopyHelp maxRank pools) term
598 UF.set copy $ makeDescriptor (Structure newTerm)
608 do UF.set copy $ makeDescriptor $ FlexVar (Just name)
611 RigidSuper super name ->
612 do UF.set copy $ makeDescriptor $ FlexSuper super (Just name)
615 Alias home name args realType ->
616 do newArgs <- mapM (traverse (makeCopyHelp maxRank pools)) args
617 newRealType <- makeCopyHelp maxRank pools realType
618 UF.set copy $ makeDescriptor (Alias home name newArgs newRealType)
629restore :: Variable -> IO ()
631 do (Descriptor content _ _ maybeCopy) <- UF.get variable
637 do UF.set variable $ Descriptor content noRank noMark Nothing
638 restoreContent content
641restoreContent :: Content -> IO ()
642restoreContent content =
668 Record1 fields ext ->
669 do mapM_ restore fields
682 Alias _ _ args var ->
683 do mapM_ (traverse restore) args
694traverseFlatType :: (Variable -> IO Variable) -> FlatType -> IO FlatType
695traverseFlatType f flatType =
697 App1 home name args ->
698 liftM (App1 home name) (traverse f args)
701 liftM2 Fun1 (f a) (f b)
706 Record1 fields ext ->
707 liftM2 Record1 (traverse f fields) (f ext)
713 liftM3 Tuple1 (f a) (f b) (traverse f cs)
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