1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
10import qualified Data.Map.Strict as Map
11import Data.Map.Strict ((!))
12import qualified Data.Name as Name
13import qualified Data.Vector as Vector
14import qualified Data.Vector.Mutable as MVector
16import qualified AST.Canonical as Can
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Type as Error
19import qualified Reporting.Render.Type as RT
20import qualified Reporting.Render.Type.Localizer as L
21import qualified Type.Occurs as Occurs
22import Type.Type as Type
23import qualified Type.Error as ET
24import qualified Type.Unify as Unify
25import qualified Type.UnionFind as UF
32run :: Constraint -> IO (Either [Error.Error] (Map.Map Name.Name Can.Annotation))
34 do pools <- MVector.replicate 8 []
36 (State env _ errors) <-
37 solve Map.empty outermostRank pools emptyState constraint
41 Right <$> traverse Type.toAnnotation env
48{-# NOINLINE emptyState #-}
51 State Map.empty (nextMark noMark) []
59 Map.Map Name.Name Variable
63 MVector.IOVector [Variable]
70 , _errors :: [Error.Error]
74solve :: Env -> Int -> Pools -> State -> Constraint -> IO State
75solve env rank pools state constraint =
80 CSaveTheEnvironment ->
81 return (state { _env = env })
83 CEqual region category tipe expectation ->
84 do actual <- typeToVariable rank pools tipe
85 expected <- expectedToVariable rank pools expectation
86 answer <- Unify.unify actual expected
89 do introduce rank pools vars
92 Unify.Err vars actualType expectedType ->
93 do introduce rank pools vars
94 return $ addError state $
95 Error.BadExpr region category actualType $
96 Error.typeReplace expectation expectedType
98 CLocal 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 actualType expectedType ->
108 do introduce rank pools vars
109 return $ addError state $
110 Error.BadExpr region (Error.Local name) actualType $
111 Error.typeReplace expectation expectedType
113 CForeign region name (Can.Forall freeVars srcType) expectation ->
114 do actual <- srcTypeToVariable rank pools freeVars srcType
115 expected <- expectedToVariable rank pools expectation
116 answer <- Unify.unify actual expected
119 do introduce rank pools vars
122 Unify.Err vars actualType expectedType ->
123 do introduce rank pools vars
124 return $ addError state $
125 Error.BadExpr region (Error.Foreign name) actualType $
126 Error.typeReplace expectation expectedType
128 CPattern region category tipe expectation ->
129 do actual <- typeToVariable rank pools tipe
130 expected <- patternExpectationToVariable rank pools expectation
131 answer <- Unify.unify actual expected
134 do introduce rank pools vars
137 Unify.Err vars actualType expectedType ->
138 do introduce rank pools vars
139 return $ addError state $
140 Error.BadPattern region category actualType
141 (Error.ptypeReplace expectation expectedType)
144 foldM (solve env rank pools) state constraints
146 CLet [] flexs _ headerCon CTrue ->
147 do introduce rank pools flexs
148 solve env rank pools state headerCon
150 CLet [] [] header headerCon subCon ->
151 do state1 <- solve env rank pools state headerCon
152 locals <- traverse (A.traverse (typeToVariable rank pools)) header
153 let newEnv = Map.union env (Map.map A.toValue locals)
154 state2 <- solve newEnv rank pools state1 subCon
155 foldM occurs state2 $ Map.toList locals
157 CLet rigids flexs header headerCon subCon ->
159 -- work in the next pool to localize header
160 let nextRank = rank + 1
161 let poolsLength = MVector.length pools
163 if nextRank < poolsLength
165 else MVector.grow pools poolsLength
167 -- introduce variables
168 let vars = rigids ++ flexs
170 UF.modify var $ \(Descriptor content _ mark copy) ->
171 Descriptor content nextRank mark copy
172 MVector.write nextPools nextRank vars
174 -- run solver in next pool
175 locals <- traverse (A.traverse (typeToVariable nextRank nextPools)) header
176 (State savedEnv mark errors) <-
177 solve env nextRank nextPools state headerCon
180 let visitMark = nextMark youngMark
181 let finalMark = nextMark visitMark
184 generalize youngMark visitMark nextRank nextPools
185 MVector.write nextPools nextRank []
187 -- check that things went well
188 mapM_ isGeneric rigids
190 let newEnv = Map.union env (Map.map A.toValue locals)
191 let tempState = State savedEnv finalMark errors
192 newState <- solve newEnv rank nextPools tempState subCon
194 foldM occurs newState (Map.toList locals)
197-- Check that a variable has rank == noRank, meaning that it can be generalized.
198isGeneric :: Variable -> IO ()
200 do (Descriptor _ rank _ _) <- UF.get var
204 do tipe <- Type.toErrorType var
206 "You ran into a compiler bug. Here are some details for the developers:\n\n"
207 ++ " " ++ show (ET.toDoc L.empty RT.None tipe) ++ " [rank = " ++ show rank ++ "]\n\n"
209 "Please create an <http://sscce.org/> and then report it\n\
210 \at <https://github.com/elm/compiler/issues>\n\n"
214-- EXPECTATIONS TO VARIABLE
217expectedToVariable :: Int -> Pools -> Error.Expected Type -> IO Variable
218expectedToVariable rank pools expectation =
219 typeToVariable rank pools $
221 Error.NoExpectation tipe ->
224 Error.FromContext _ _ tipe ->
227 Error.FromAnnotation _ _ _ tipe ->
231patternExpectationToVariable :: Int -> Pools -> Error.PExpected Type -> IO Variable
232patternExpectationToVariable rank pools expectation =
233 typeToVariable rank pools $
235 Error.PNoExpectation tipe ->
238 Error.PFromContext _ _ tipe ->
246addError :: State -> Error.Error -> State
247addError (State savedEnv rank errors) err =
248 State savedEnv rank (err:errors)
255occurs :: State -> (Name.Name, A.Located Variable) -> IO State
256occurs state (name, A.At region variable) =
257 do hasOccurred <- Occurs.occurs variable
260 do errorType <- Type.toErrorType variable
261 (Descriptor _ rank mark copy) <- UF.get variable
262 UF.set variable (Descriptor Error rank mark copy)
263 return $ addError state (Error.InfiniteType region name errorType)
272{-| Every variable has rank less than or equal to the maxRank of the pool.
273This sorts variables into the young and old pools accordingly.
275generalize :: Mark -> Mark -> Int -> Pools -> IO ()
276generalize youngMark visitMark youngRank pools =
277 do youngVars <- MVector.read pools youngRank
278 rankTable <- poolToRankTable youngMark youngRank youngVars
280 -- get the ranks right for each entry.
281 -- start at low ranks so that we only have to pass
282 -- over the information once.
284 (\rank table -> mapM_ (adjustRank youngMark visitMark rank) table)
287 -- For variables that have rank lowerer than youngRank, register them in
288 -- the appropriate old pool if they are not redundant.
289 Vector.forM_ (Vector.unsafeInit rankTable) $ \vars ->
291 do isRedundant <- UF.redundant var
295 do (Descriptor _ rank _ _) <- UF.get var
296 MVector.modify pools (var:) rank
298 -- For variables with rank youngRank
299 -- If rank < youngRank: register in oldPool
300 -- otherwise generalize
301 forM_ (Vector.unsafeLast rankTable) $ \var ->
302 do isRedundant <- UF.redundant var
306 do (Descriptor content rank mark copy) <- UF.get var
308 then MVector.modify pools (var:) rank
309 else UF.set var $ Descriptor content noRank mark copy
312poolToRankTable :: Mark -> Int -> [Variable] -> IO (Vector.Vector [Variable])
313poolToRankTable youngMark youngRank youngInhabitants =
314 do mutableTable <- MVector.replicate (youngRank + 1) []
316 -- Sort the youngPool variables into buckets by rank.
317 forM_ youngInhabitants $ \var ->
318 do (Descriptor content rank _ copy) <- UF.get var
319 UF.set var (Descriptor content rank youngMark copy)
320 MVector.modify mutableTable (var:) rank
322 Vector.unsafeFreeze mutableTable
329-- Adjust variable ranks such that ranks never increase as you move deeper.
330-- This way the outermost rank is representative of the entire structure.
332adjustRank :: Mark -> Mark -> Int -> Variable -> IO Int
333adjustRank youngMark visitMark groupRank var =
334 do (Descriptor content rank mark copy) <- UF.get var
335 if mark == youngMark then
336 do -- Set the variable as marked first because it may be cyclic.
337 UF.set var $ Descriptor content rank visitMark copy
338 maxRank <- adjustRankContent youngMark visitMark groupRank content
339 UF.set var $ Descriptor content maxRank visitMark copy
342 else if mark == visitMark then
346 do let minRank = min groupRank rank
347 -- TODO how can minRank ever be groupRank?
348 UF.set var $ Descriptor content minRank visitMark copy
352adjustRankContent :: Mark -> Mark -> Int -> Content -> IO Int
353adjustRankContent youngMark visitMark groupRank content =
355 go = adjustRank youngMark visitMark groupRank
370 Structure flatType ->
373 foldM (\rank arg -> max rank <$> go arg) outermostRank args
376 max <$> go arg <*> go result
379 -- THEORY: an empty record never needs to get generalized
382 Record1 fields extension ->
383 do extRank <- go extension
384 foldM (\rank field -> max rank <$> go field) extRank fields
387 -- THEORY: a unit never needs to get generalized
398 max (max ma mb) <$> go c
401 -- THEORY: anything in the realVar would be outermostRank
402 foldM (\rank (_, argVar) -> max rank <$> go argVar) outermostRank args
412introduce :: Int -> Pools -> [Variable] -> IO ()
413introduce rank pools variables =
414 do MVector.modify pools (variables++) rank
415 forM_ variables $ \var ->
416 UF.modify var $ \(Descriptor content _ mark copy) ->
417 Descriptor content rank mark copy
424typeToVariable :: Int -> Pools -> Type -> IO Variable
425typeToVariable rank pools tipe =
426 typeToVar rank pools Map.empty tipe
429typeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Type -> IO Variable
430typeToVar rank pools aliasDict tipe =
431 let go = typeToVar rank pools aliasDict in
436 AppN home name args ->
437 do argVars <- traverse go args
438 register rank pools (Structure (App1 home name argVars))
443 register rank pools (Structure (Fun1 aVar bVar))
445 AliasN home name args aliasType ->
446 do argVars <- traverse (traverse go) args
447 aliasVar <- typeToVar rank pools (Map.fromList argVars) aliasType
448 register rank pools (Alias home name argVars aliasVar)
451 return (aliasDict ! name)
453 RecordN fields ext ->
454 do fieldVars <- traverse go fields
456 register rank pools (Structure (Record1 fieldVars extVar))
459 register rank pools emptyRecord1
462 register rank pools unit1
467 cVar <- traverse go c
468 register rank pools (Structure (Tuple1 aVar bVar cVar))
471register :: Int -> Pools -> Content -> IO Variable
472register rank pools content =
473 do var <- UF.fresh (Descriptor content rank noMark Nothing)
474 MVector.modify pools (var:) rank
478{-# NOINLINE emptyRecord1 #-}
479emptyRecord1 :: Content
481 Structure EmptyRecord1
484{-# NOINLINE unit1 #-}
491-- SOURCE TYPE TO VARIABLE
494srcTypeToVariable :: Int -> Pools -> Map.Map Name.Name () -> Can.Type -> IO Variable
495srcTypeToVariable rank pools freeVars srcType =
498 | Name.isNumberType name = FlexSuper Number (Just name)
499 | Name.isComparableType name = FlexSuper Comparable (Just name)
500 | Name.isAppendableType name = FlexSuper Appendable (Just name)
501 | Name.isCompappendType name = FlexSuper CompAppend (Just name)
502 | otherwise = FlexVar (Just name)
505 UF.fresh (Descriptor (nameToContent name) rank noMark Nothing)
507 do flexVars <- Map.traverseWithKey makeVar freeVars
508 MVector.modify pools (Map.elems flexVars ++) rank
509 srcTypeToVar rank pools flexVars srcType
512srcTypeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Can.Type -> IO Variable
513srcTypeToVar rank pools flexVars srcType =
514 let go = srcTypeToVar rank pools flexVars in
516 Can.TLambda argument result ->
517 do argVar <- go argument
518 resultVar <- go result
519 register rank pools (Structure (Fun1 argVar resultVar))
522 return (flexVars ! name)
524 Can.TType home name args ->
525 do argVars <- traverse go args
526 register rank pools (Structure (App1 home name argVars))
528 Can.TRecord fields maybeExt ->
529 do fieldVars <- traverse (srcFieldTypeToVar rank pools flexVars) fields
532 Nothing -> register rank pools emptyRecord1
533 Just ext -> return (flexVars ! ext)
534 register rank pools (Structure (Record1 fieldVars extVar))
537 register rank pools unit1
542 cVar <- traverse go c
543 register rank pools (Structure (Tuple1 aVar bVar cVar))
545 Can.TAlias home name args aliasType ->
546 do argVars <- traverse (traverse go) args
550 srcTypeToVar rank pools (Map.fromList argVars) tipe
555 register rank pools (Alias home name argVars aliasVar)
558srcFieldTypeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Can.FieldType -> IO Variable
559srcFieldTypeToVar rank pools flexVars (Can.FieldType _ srcTipe) =
560 srcTypeToVar rank pools flexVars srcTipe
567makeCopy :: Int -> Pools -> Variable -> IO Variable
568makeCopy rank pools var =
569 do copy <- makeCopyHelp rank pools var
574makeCopyHelp :: Int -> Pools -> Variable -> IO Variable
575makeCopyHelp maxRank pools variable =
576 do (Descriptor content rank _ maybeCopy) <- UF.get variable
583 if rank /= noRank then
587 do let makeDescriptor c = Descriptor c maxRank noMark Nothing
588 copy <- UF.fresh $ makeDescriptor content
589 MVector.modify pools (copy:) maxRank
591 -- Link the original variable to the new variable. This lets us
592 -- avoid making multiple copies of the variable we are instantiating.
594 -- Need to do this before recursively copying to avoid looping.
596 Descriptor content rank noMark (Just copy)
598 -- Now we recursively copy the content of the variable.
599 -- We have already marked the variable as copied, so we
600 -- will not repeat this work or crawl this variable again.
603 do newTerm <- traverseFlatType (makeCopyHelp maxRank pools) term
604 UF.set copy $ makeDescriptor (Structure newTerm)
614 do UF.set copy $ makeDescriptor $ FlexVar (Just name)
617 RigidSuper super name ->
618 do UF.set copy $ makeDescriptor $ FlexSuper super (Just name)
621 Alias home name args realType ->
622 do newArgs <- mapM (traverse (makeCopyHelp maxRank pools)) args
623 newRealType <- makeCopyHelp maxRank pools realType
624 UF.set copy $ makeDescriptor (Alias home name newArgs newRealType)
635restore :: Variable -> IO ()
637 do (Descriptor content _ _ maybeCopy) <- UF.get variable
643 do UF.set variable $ Descriptor content noRank noMark Nothing
644 restoreContent content
647restoreContent :: Content -> IO ()
648restoreContent content =
674 Record1 fields ext ->
675 do mapM_ restore fields
688 Alias _ _ args var ->
689 do mapM_ (traverse restore) args
700traverseFlatType :: (Variable -> IO Variable) -> FlatType -> IO FlatType
701traverseFlatType f flatType =
703 App1 home name args ->
704 liftM (App1 home name) (traverse f args)
707 liftM2 Fun1 (f a) (f b)
712 Record1 fields ext ->
713 liftM2 Record1 (traverse f fields) (f ext)
719 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