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 Type.Occurs as Occurs
20import Type.Constraint as Con
21import Type.Type as Type
22import qualified Type.Unify as Unify
23import qualified Type.UnionFind as UF
30run :: Constraint -> IO (Either [Error.Error] (Map.Map N.Name Can.Annotation))
32 do pools <- MVector.replicate 16 []
34 (State env _ errors) <-
35 solve Map.empty outermostRank pools emptyState constraint
39 Right <$> traverse Type.toAnnotation env
46{-# NOINLINE emptyState #-}
49 State Map.empty (nextMark noMark) []
57 Map.Map N.Name Variable
61 MVector.IOVector [Variable]
68 , _errors :: [Error.Error]
72solve :: Env -> Int -> Pools -> State -> Constraint -> IO State
73solve env rank pools state constraint =
78 CSaveTheEnvironment ->
79 return (state { _env = env })
81 CEqual region category tipe expectation ->
82 do actual <- typeToVariable rank pools tipe
83 expected <- expectedToVariable rank pools expectation
84 answer <- Unify.unify actual expected
87 do introduce rank pools vars
90 Unify.Err vars problem actualType expectedType ->
91 do introduce rank pools vars
92 return $ addError state $
94 (Error.BadExpr region category actualType)
95 (Con.typeReplace expectation expectedType)
98 CLookup region name expectation ->
99 do actual <- makeCopy rank pools (env ! name)
100 expected <- expectedToVariable rank pools expectation
101 answer <- Unify.unify actual expected
104 do introduce rank pools vars
107 Unify.Err vars problem actualType expectedType ->
108 do introduce rank pools vars
109 return $ addError state $
111 (Error.BadLocal region name actualType)
112 (Con.typeReplace expectation expectedType)
115 CInstance region funcName (Can.Forall freeVars srcType) expectation ->
116 do actual <- srcTypeToVariable rank pools freeVars srcType
117 expected <- expectedToVariable rank pools expectation
118 answer <- Unify.unify actual expected
121 do introduce rank pools vars
124 Unify.Err vars problem actualType expectedType ->
125 do introduce rank pools vars
126 return $ addError state $
128 (Error.BadForeign region funcName actualType)
129 (Con.typeReplace expectation expectedType)
132 CPattern region category tipe expectation ->
133 do actual <- typeToVariable rank pools tipe
134 expected <- patternExpectationToVariable rank pools expectation
135 answer <- Unify.unify actual expected
138 do introduce rank pools vars
141 Unify.Err vars problem actualType expectedType ->
142 do introduce rank pools vars
143 return $ addError state $
144 Error.BadPattern region category actualType
145 (Con.ptypeReplace expectation expectedType)
149 foldM (solve env rank pools) state constraints
151 CBranch a b eqCon makeNotEqCon ->
152 do aVar <- typeToVariable rank pools a
153 bVar <- typeToVariable rank pools b
154 answer <- Unify.unify aVar bVar
157 do introduce rank pools vars
158 solve env rank pools state eqCon
160 Unify.Err vars _ _ _ ->
161 do introduce rank pools vars
162 solve env rank pools state =<< makeNotEqCon
164 CLet [] flexs _ headerCon CTrue ->
165 do introduce rank pools flexs
166 solve env rank pools state headerCon
168 CLet [] [] header headerCon subCon ->
169 do state1 <- solve env rank pools state headerCon
170 locals <- traverse (A.traverse (typeToVariable rank pools)) header
171 let newEnv = Map.union env (Map.map A.toValue locals)
172 state2 <- solve newEnv rank pools state1 subCon
173 foldM occurs state2 $ Map.toList locals
175 CLet rigids flexs header headerCon subCon ->
177 -- work in the next pool to localize header
178 let nextRank = rank + 1
179 let poolsLength = MVector.length pools
181 if nextRank < poolsLength
183 else MVector.grow pools poolsLength
185 -- introduce variables
186 let vars = rigids ++ flexs
188 UF.modify var $ \(Descriptor content _ mark copy) ->
189 Descriptor content nextRank mark copy
190 MVector.write nextPools nextRank vars
192 -- run solver in next pool
193 locals <- traverse (A.traverse (typeToVariable rank nextPools)) header
194 (State savedEnv mark errors) <-
195 solve env nextRank nextPools state headerCon
198 let visitMark = nextMark youngMark
199 let finalMark = nextMark visitMark
202 generalize youngMark visitMark nextRank nextPools
203 MVector.write nextPools nextRank []
205 -- check that things went well
206 mapM_ isGeneric rigids
208 let newEnv = Map.union env (Map.map A.toValue locals)
209 let tempState = State savedEnv finalMark errors
210 newState <- solve newEnv nextRank nextPools tempState subCon
212 foldM occurs newState (Map.toList locals)
215-- Check that a variable has rank == noRank, meaning that it can be generalized.
216isGeneric :: Variable -> IO ()
218 do (Descriptor _ rank _ _) <- UF.get var
221 else crash "Unable to generalize a type variable. It is not unranked."
227 "It looks like something went wrong with the type inference algorithm.\n\n"
229 ++ "Please create a minimal example that triggers this problem and report it to\n"
230 ++ "<https://github.com/elm-lang/elm-compiler/issues>"
234-- EXPECTATIONS TO VARIABLE
237expectedToVariable :: Int -> Pools -> Expected Type -> IO Variable
238expectedToVariable rank pools expectation =
239 typeToVariable rank pools $
241 NoExpectation tipe ->
244 FromContext _ _ tipe ->
247 FromAnnotation _ _ _ tipe ->
251patternExpectationToVariable :: Int -> Pools -> PExpected Type -> IO Variable
252patternExpectationToVariable rank pools expectation =
253 typeToVariable rank pools $
255 PNoExpectation tipe ->
258 PFromContext _ _ tipe ->
266addError :: State -> Error.Error -> State
267addError (State savedEnv rank errors) err =
268 State savedEnv rank (err:errors)
275occurs :: State -> (N.Name, A.Located Variable) -> IO State
276occurs state (_name, A.At _region variable) =
277 do hasOccurred <- Occurs.occurs variable
280 do overallType <- Type.toSrcType variable
281 (Descriptor _ rank mark copy) <- UF.get variable
282 UF.set variable (Descriptor (Error "∞") rank mark copy)
283 return $ state { _errors = Error.InfiniteType overallType : _errors state }
292{-| Every variable has rank less than or equal to the maxRank of the pool.
293This sorts variables into the young and old pools accordingly.
295generalize :: Mark -> Mark -> Int -> Pools -> IO ()
296generalize youngMark visitMark youngRank pools =
297 do youngVars <- MVector.read pools youngRank
298 rankTable <- poolToRankTable youngMark youngRank youngVars
300 -- get the ranks right for each entry.
301 -- start at low ranks so that we only have to pass
302 -- over the information once.
303 Vector.imapM_ (mapM_ . adjustRank youngMark visitMark) rankTable
305 -- For variables that have rank lowerer than youngRank, register them in
306 -- the appropriate old pool if they are not redundant.
307 Vector.forM_ (Vector.unsafeInit rankTable) $ \vars ->
309 do isRedundant <- UF.redundant var
313 do (Descriptor _ rank _ _) <- UF.get var
314 MVector.modify pools (var:) rank
316 -- For variables with rank youngRank
317 -- If rank < youngRank: register in oldPool
318 -- otherwise generalize
319 forM_ (Vector.unsafeLast rankTable) $ \var ->
320 do isRedundant <- UF.redundant var
324 do (Descriptor content rank mark copy) <- UF.get var
326 then MVector.modify pools (var:) rank
327 else UF.set var $ Descriptor content noRank mark copy
330poolToRankTable :: Mark -> Int -> [Variable] -> IO (Vector.Vector [Variable])
331poolToRankTable youngMark youngRank youngInhabitants =
332 do mutableTable <- MVector.replicate (youngRank + 1) []
334 -- Sort the youngPool variables into buckets by rank.
335 forM_ youngInhabitants $ \var ->
336 do (Descriptor content rank _ copy) <- UF.get var
337 UF.set var (Descriptor content rank youngMark copy)
338 MVector.modify mutableTable (var:) rank
340 Vector.unsafeFreeze mutableTable
347-- Adjust variable ranks such that ranks never increase as you move deeper.
348-- This way the outermost rank is representative of the entire structure.
350adjustRank :: Mark -> Mark -> Int -> Variable -> IO Int
351adjustRank youngMark visitMark groupRank var =
352 {-# SCC elm_compiler_type_adjust #-}
353 do (Descriptor content rank mark copy) <- UF.get var
354 if mark == youngMark then
355 do -- Set the variable as marked first because it may be cyclic.
356 UF.set var $ Descriptor content rank visitMark copy
357 maxRank <- adjustRankContent youngMark visitMark groupRank content
358 UF.set var $ Descriptor content maxRank visitMark copy
361 else if mark == visitMark then
365 do let minRank = min groupRank rank
366 -- TODO how can minRank ever be groupRank?
367 UF.set var $ Descriptor content minRank visitMark copy
371adjustRankContent :: Mark -> Mark -> Int -> Content -> IO Int
372adjustRankContent youngMark visitMark groupRank content =
374 go = adjustRank youngMark visitMark groupRank
389 Structure flatType ->
392 foldM (\rank arg -> max rank <$> go arg) outermostRank args
395 max <$> go arg <*> go result
398 -- THEORY: an empty record never needs to get generalized
401 Record1 fields extension ->
402 do extRank <- go extension
403 foldM (\rank field -> max rank <$> go field) extRank fields
406 -- THEORY: a unit never needs to get generalized
417 max (max ma mb) <$> go c
420 -- THEORY: anything in the realVar would be outermostRank
421 foldM (\rank (_, argVar) -> max rank <$> go argVar) outermostRank args
431introduce :: Int -> Pools -> [Variable] -> IO ()
432introduce rank pools variables =
433 do MVector.modify pools (variables++) rank
434 forM_ variables $ \var ->
435 UF.modify var $ \(Descriptor content _ mark copy) ->
436 Descriptor content rank mark copy
443typeToVariable :: Int -> Pools -> Type -> IO Variable
444typeToVariable rank pools tipe =
445 typeToVar rank pools Map.empty tipe
448typeToVar :: Int -> Pools -> Map.Map N.Name Variable -> Type -> IO Variable
449typeToVar rank pools aliasDict tipe =
450 let go = typeToVar rank pools aliasDict in
455 AppN home name args ->
456 do argVars <- traverse go args
457 register rank pools (Structure (App1 home name argVars))
462 register rank pools (Structure (Fun1 aVar bVar))
464 AliasN home name args aliasType ->
465 do argVars <- traverse (traverse go) args
466 aliasVar <- typeToVar rank pools (Map.fromList argVars) aliasType
467 register rank pools (Alias home name argVars aliasVar)
470 return (aliasDict ! name)
472 RecordN fields ext ->
473 do fieldVars <- traverse go fields
475 register rank pools (Structure (Record1 fieldVars extVar))
478 register rank pools emptyRecord1
481 register rank pools unit1
486 cVar <- traverse go c
487 register rank pools (Structure (Tuple1 aVar bVar cVar))
490register :: Int -> Pools -> Content -> IO Variable
491register rank pools content =
492 do var <- UF.fresh (Descriptor content rank noMark Nothing)
493 MVector.modify pools (var:) rank
497{-# NOINLINE emptyRecord1 #-}
498emptyRecord1 :: Content
500 Structure EmptyRecord1
503{-# NOINLINE unit1 #-}
510-- SOURCE TYPE TO VARIABLE
513srcTypeToVariable :: Int -> Pools -> Map.Map N.Name () -> Can.Type -> IO Variable
514srcTypeToVariable rank pools freeVars srcType =
517 UF.fresh (Descriptor (FlexVar (Just name)) rank noMark Nothing)
519 do flexVars <- Map.traverseWithKey makeVar freeVars
520 MVector.modify pools (Map.elems flexVars ++) rank
521 srcTypeToVar rank pools flexVars srcType
524srcTypeToVar :: Int -> Pools -> Map.Map N.Name Variable -> Can.Type -> IO Variable
525srcTypeToVar rank pools flexVars srcType =
526 let go = srcTypeToVar rank pools flexVars in
528 Can.TLambda argument result ->
529 do argVar <- go argument
530 resultVar <- go result
531 register rank pools (Structure (Fun1 argVar resultVar))
534 return (flexVars ! name)
536 Can.TType home name args ->
537 do argVars <- traverse go args
538 register rank pools (Structure (App1 home name argVars))
540 Can.TRecord fields maybeExt ->
541 do fieldVars <- traverse go fields
542 extVar <- maybe (register rank pools emptyRecord1) go maybeExt
543 register rank pools (Structure (Record1 fieldVars extVar))
546 register rank pools unit1
551 cVar <- traverse go c
552 register rank pools (Structure (Tuple1 aVar bVar cVar))
554 Can.TAlias home name args aliasType ->
555 do argVars <- traverse (traverse go) args
559 srcTypeToVar rank pools (Map.fromList argVars) tipe
564 register rank pools (Alias home name argVars aliasVar)
571makeCopy :: Int -> Pools -> Variable -> IO Variable
572makeCopy rank pools var =
573 do copy <- makeCopyHelp rank pools var
578makeCopyHelp :: Int -> Pools -> Variable -> IO Variable
579makeCopyHelp maxRank pools variable =
580 do (Descriptor content rank _ maybeCopy) <-
588 if rank /= noRank then
592 do let makeDescriptor c = Descriptor c maxRank noMark Nothing
593 copy <- UF.fresh $ makeDescriptor content
594 MVector.modify pools (copy:) maxRank
596 -- Link the original variable to the new variable. This lets us
597 -- avoid making multiple copies of the variable we are instantiating.
599 -- Need to do this before recursively copying to avoid looping.
601 Descriptor content rank noMark (Just copy)
603 -- Now we recursively copy the content of the variable.
604 -- We have already marked the variable as copied, so we
605 -- will not repeat this work or crawl this variable again.
608 do newTerm <- traverseFlatType (makeCopyHelp maxRank pools) term
609 UF.set copy $ makeDescriptor (Structure newTerm)
619 do UF.set copy $ makeDescriptor $ FlexVar (Just name)
622 RigidSuper super name ->
623 do UF.set copy $ makeDescriptor $ FlexSuper super (Just name)
626 Alias home name args realType ->
627 do newArgs <- mapM (traverse (makeCopyHelp maxRank pools)) args
628 newRealType <- makeCopyHelp maxRank pools realType
629 UF.set copy $ makeDescriptor (Alias home name newArgs newRealType)
640restore :: Variable -> IO Variable
642 do (Descriptor content _rank _mark maybeCopy) <- UF.get variable
648 do restoredContent <- restoreContent content
650 Descriptor restoredContent noRank noMark Nothing
654restoreContent :: Content -> IO Content
655restoreContent content =
670 Structure <$> traverseFlatType restore term
672 Alias home name args var ->
674 <$> mapM (traverse restore) args
685traverseFlatType :: (Variable -> IO Variable) -> FlatType -> IO FlatType
686traverseFlatType f flatType =
688 App1 home name args ->
689 liftM (App1 home name) (traverse f args)
692 liftM2 Fun1 (f a) (f b)
697 Record1 fields ext ->
698 liftM2 Record1 (traverse f fields) (f ext)
704 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