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.NonEmptyList as NE
14import qualified Data.Vector as Vector
15import qualified Data.Vector.Mutable as MVector
17import qualified AST.Canonical as Can
18import qualified Reporting.Annotation as A
19import qualified Reporting.Error.Type as Error
20import qualified Reporting.Render.Type as RT
21import qualified Reporting.Render.Type.Localizer as L
22import qualified Type.Occurs as Occurs
23import Type.Type as Type
24import qualified Type.Error as ET
25import qualified Type.Unify as Unify
26import qualified Type.UnionFind as UF
33run :: Constraint -> IO (Either (NE.List Error.Error) (Map.Map Name.Name Can.Annotation))
35 do pools <- MVector.replicate 8 []
37 (State env _ errors) <-
38 solve Map.empty outermostRank pools emptyState constraint
42 Right <$> traverse Type.toAnnotation env
45 return $ Left (NE.List e es)
49{-# NOINLINE emptyState #-}
52 State Map.empty (nextMark noMark) []
60 Map.Map Name.Name Variable
64 MVector.IOVector [Variable]
71 , _errors :: [Error.Error]
75solve :: Env -> Int -> Pools -> State -> Constraint -> IO State
76solve env rank pools state constraint =
81 CSaveTheEnvironment ->
82 return (state { _env = env })
84 CEqual region category tipe expectation ->
85 do actual <- typeToVariable rank pools tipe
86 expected <- expectedToVariable rank pools expectation
87 answer <- Unify.unify actual expected
90 do introduce rank pools vars
93 Unify.Err vars actualType expectedType ->
94 do introduce rank pools vars
95 return $ addError state $
96 Error.BadExpr region category actualType $
97 Error.typeReplace expectation expectedType
99 CLocal region name expectation ->
100 do actual <- makeCopy rank pools (env ! name)
101 expected <- expectedToVariable rank pools expectation
102 answer <- Unify.unify actual expected
105 do introduce rank pools vars
108 Unify.Err vars actualType expectedType ->
109 do introduce rank pools vars
110 return $ addError state $
111 Error.BadExpr region (Error.Local name) actualType $
112 Error.typeReplace expectation expectedType
114 CForeign region name (Can.Forall freeVars srcType) expectation ->
115 do actual <- srcTypeToVariable rank pools freeVars srcType
116 expected <- expectedToVariable rank pools expectation
117 answer <- Unify.unify actual expected
120 do introduce rank pools vars
123 Unify.Err vars actualType expectedType ->
124 do introduce rank pools vars
125 return $ addError state $
126 Error.BadExpr region (Error.Foreign name) actualType $
127 Error.typeReplace expectation expectedType
129 CPattern region category tipe expectation ->
130 do actual <- typeToVariable rank pools tipe
131 expected <- patternExpectationToVariable rank pools expectation
132 answer <- Unify.unify actual expected
135 do introduce rank pools vars
138 Unify.Err vars actualType expectedType ->
139 do introduce rank pools vars
140 return $ addError state $
141 Error.BadPattern region category actualType
142 (Error.ptypeReplace expectation expectedType)
145 foldM (solve env rank pools) state constraints
147 CLet [] flexs _ headerCon CTrue ->
148 do introduce rank pools flexs
149 solve env rank pools state headerCon
151 CLet [] [] header headerCon subCon ->
152 do state1 <- solve env rank pools state headerCon
153 locals <- traverse (A.traverse (typeToVariable rank pools)) header
154 let newEnv = Map.union env (Map.map A.toValue locals)
155 state2 <- solve newEnv rank pools state1 subCon
156 foldM occurs state2 $ Map.toList locals
158 CLet rigids flexs header headerCon subCon ->
160 -- work in the next pool to localize header
161 let nextRank = rank + 1
162 let poolsLength = MVector.length pools
164 if nextRank < poolsLength
166 else MVector.grow pools poolsLength
168 -- introduce variables
169 let vars = rigids ++ flexs
171 UF.modify var $ \(Descriptor content _ mark copy) ->
172 Descriptor content nextRank mark copy
173 MVector.write nextPools nextRank vars
175 -- run solver in next pool
176 locals <- traverse (A.traverse (typeToVariable nextRank nextPools)) header
177 (State savedEnv mark errors) <-
178 solve env nextRank nextPools state headerCon
181 let visitMark = nextMark youngMark
182 let finalMark = nextMark visitMark
185 generalize youngMark visitMark nextRank nextPools
186 MVector.write nextPools nextRank []
188 -- check that things went well
189 mapM_ isGeneric rigids
191 let newEnv = Map.union env (Map.map A.toValue locals)
192 let tempState = State savedEnv finalMark errors
193 newState <- solve newEnv rank nextPools tempState subCon
195 foldM occurs newState (Map.toList locals)
198-- Check that a variable has rank == noRank, meaning that it can be generalized.
199isGeneric :: Variable -> IO ()
201 do (Descriptor _ rank _ _) <- UF.get var
205 do tipe <- Type.toErrorType var
207 "You ran into a compiler bug. Here are some details for the developers:\n\n"
208 ++ " " ++ show (ET.toDoc L.empty RT.None tipe) ++ " [rank = " ++ show rank ++ "]\n\n"
210 "Please create an <http://sscce.org/> and then report it\n\
211 \at <https://github.com/elm/compiler/issues>\n\n"
215-- EXPECTATIONS TO VARIABLE
218expectedToVariable :: Int -> Pools -> Error.Expected Type -> IO Variable
219expectedToVariable rank pools expectation =
220 typeToVariable rank pools $
222 Error.NoExpectation tipe ->
225 Error.FromContext _ _ tipe ->
228 Error.FromAnnotation _ _ _ tipe ->
232patternExpectationToVariable :: Int -> Pools -> Error.PExpected Type -> IO Variable
233patternExpectationToVariable rank pools expectation =
234 typeToVariable rank pools $
236 Error.PNoExpectation tipe ->
239 Error.PFromContext _ _ tipe ->
247addError :: State -> Error.Error -> State
248addError (State savedEnv rank errors) err =
249 State savedEnv rank (err:errors)
256occurs :: State -> (Name.Name, A.Located Variable) -> IO State
257occurs state (name, A.At region variable) =
258 do hasOccurred <- Occurs.occurs variable
261 do errorType <- Type.toErrorType variable
262 (Descriptor _ rank mark copy) <- UF.get variable
263 UF.set variable (Descriptor Error rank mark copy)
264 return $ addError state (Error.InfiniteType region name errorType)
273{-| Every variable has rank less than or equal to the maxRank of the pool.
274This sorts variables into the young and old pools accordingly.
276generalize :: Mark -> Mark -> Int -> Pools -> IO ()
277generalize youngMark visitMark youngRank pools =
278 do youngVars <- MVector.read pools youngRank
279 rankTable <- poolToRankTable youngMark youngRank youngVars
281 -- get the ranks right for each entry.
282 -- start at low ranks so that we only have to pass
283 -- over the information once.
285 (\rank table -> mapM_ (adjustRank youngMark visitMark rank) table)
288 -- For variables that have rank lowerer than youngRank, register them in
289 -- the appropriate old pool if they are not redundant.
290 Vector.forM_ (Vector.unsafeInit rankTable) $ \vars ->
292 do isRedundant <- UF.redundant var
296 do (Descriptor _ rank _ _) <- UF.get var
297 MVector.modify pools (var:) rank
299 -- For variables with rank youngRank
300 -- If rank < youngRank: register in oldPool
301 -- otherwise generalize
302 forM_ (Vector.unsafeLast rankTable) $ \var ->
303 do isRedundant <- UF.redundant var
307 do (Descriptor content rank mark copy) <- UF.get var
309 then MVector.modify pools (var:) rank
310 else UF.set var $ Descriptor content noRank mark copy
313poolToRankTable :: Mark -> Int -> [Variable] -> IO (Vector.Vector [Variable])
314poolToRankTable youngMark youngRank youngInhabitants =
315 do mutableTable <- MVector.replicate (youngRank + 1) []
317 -- Sort the youngPool variables into buckets by rank.
318 forM_ youngInhabitants $ \var ->
319 do (Descriptor content rank _ copy) <- UF.get var
320 UF.set var (Descriptor content rank youngMark copy)
321 MVector.modify mutableTable (var:) rank
323 Vector.unsafeFreeze mutableTable
330-- Adjust variable ranks such that ranks never increase as you move deeper.
331-- This way the outermost rank is representative of the entire structure.
333adjustRank :: Mark -> Mark -> Int -> Variable -> IO Int
334adjustRank youngMark visitMark groupRank var =
335 do (Descriptor content rank mark copy) <- UF.get var
336 if mark == youngMark then
337 do -- Set the variable as marked first because it may be cyclic.
338 UF.set var $ Descriptor content rank visitMark copy
339 maxRank <- adjustRankContent youngMark visitMark groupRank content
340 UF.set var $ Descriptor content maxRank visitMark copy
343 else if mark == visitMark then
347 do let minRank = min groupRank rank
348 -- TODO how can minRank ever be groupRank?
349 UF.set var $ Descriptor content minRank visitMark copy
353adjustRankContent :: Mark -> Mark -> Int -> Content -> IO Int
354adjustRankContent youngMark visitMark groupRank content =
356 go = adjustRank youngMark visitMark groupRank
371 Structure flatType ->
374 foldM (\rank arg -> max rank <$> go arg) outermostRank args
377 max <$> go arg <*> go result
380 -- THEORY: an empty record never needs to get generalized
383 Record1 fields extension ->
384 do extRank <- go extension
385 foldM (\rank field -> max rank <$> go field) extRank fields
388 -- THEORY: a unit never needs to get generalized
399 max (max ma mb) <$> go c
402 -- THEORY: anything in the realVar would be outermostRank
403 foldM (\rank (_, argVar) -> max rank <$> go argVar) outermostRank args
413introduce :: Int -> Pools -> [Variable] -> IO ()
414introduce rank pools variables =
415 do MVector.modify pools (variables++) rank
416 forM_ variables $ \var ->
417 UF.modify var $ \(Descriptor content _ mark copy) ->
418 Descriptor content rank mark copy
425typeToVariable :: Int -> Pools -> Type -> IO Variable
426typeToVariable rank pools tipe =
427 typeToVar rank pools Map.empty tipe
430-- PERF working with @mgriffith we noticed that a 784 line entry in a `let` was
431-- causing a ~1.5 second slowdown. Moving it to the top-level to be a function
432-- saved all that time. The slowdown seems to manifest in `typeToVar` and in
433-- `register` in particular. Have not explored further yet. Top-level definitions
434-- are recommended in cases like this anyway, so there is at least a safety
437typeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Type -> IO Variable
438typeToVar rank pools aliasDict tipe =
439 let go = typeToVar rank pools aliasDict in
444 AppN home name args ->
445 do argVars <- traverse go args
446 register rank pools (Structure (App1 home name argVars))
451 register rank pools (Structure (Fun1 aVar bVar))
453 AliasN home name args aliasType ->
454 do argVars <- traverse (traverse go) args
455 aliasVar <- typeToVar rank pools (Map.fromList argVars) aliasType
456 register rank pools (Alias home name argVars aliasVar)
459 return (aliasDict ! name)
461 RecordN fields ext ->
462 do fieldVars <- traverse go fields
464 register rank pools (Structure (Record1 fieldVars extVar))
467 register rank pools emptyRecord1
470 register rank pools unit1
475 cVar <- traverse go c
476 register rank pools (Structure (Tuple1 aVar bVar cVar))
479register :: Int -> Pools -> Content -> IO Variable
480register rank pools content =
481 do var <- UF.fresh (Descriptor content rank noMark Nothing)
482 MVector.modify pools (var:) rank
486{-# NOINLINE emptyRecord1 #-}
487emptyRecord1 :: Content
489 Structure EmptyRecord1
492{-# NOINLINE unit1 #-}
499-- SOURCE TYPE TO VARIABLE
502srcTypeToVariable :: Int -> Pools -> Map.Map Name.Name () -> Can.Type -> IO Variable
503srcTypeToVariable rank pools freeVars srcType =
506 | Name.isNumberType name = FlexSuper Number (Just name)
507 | Name.isComparableType name = FlexSuper Comparable (Just name)
508 | Name.isAppendableType name = FlexSuper Appendable (Just name)
509 | Name.isCompappendType name = FlexSuper CompAppend (Just name)
510 | otherwise = FlexVar (Just name)
513 UF.fresh (Descriptor (nameToContent name) rank noMark Nothing)
515 do flexVars <- Map.traverseWithKey makeVar freeVars
516 MVector.modify pools (Map.elems flexVars ++) rank
517 srcTypeToVar rank pools flexVars srcType
520srcTypeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Can.Type -> IO Variable
521srcTypeToVar rank pools flexVars srcType =
522 let go = srcTypeToVar rank pools flexVars in
524 Can.TLambda argument result ->
525 do argVar <- go argument
526 resultVar <- go result
527 register rank pools (Structure (Fun1 argVar resultVar))
530 return (flexVars ! name)
532 Can.TType home name args ->
533 do argVars <- traverse go args
534 register rank pools (Structure (App1 home name argVars))
536 Can.TRecord fields maybeExt ->
537 do fieldVars <- traverse (srcFieldTypeToVar rank pools flexVars) fields
540 Nothing -> register rank pools emptyRecord1
541 Just ext -> return (flexVars ! ext)
542 register rank pools (Structure (Record1 fieldVars extVar))
545 register rank pools unit1
550 cVar <- traverse go c
551 register rank pools (Structure (Tuple1 aVar bVar cVar))
553 Can.TAlias home name args aliasType ->
554 do argVars <- traverse (traverse go) args
558 srcTypeToVar rank pools (Map.fromList argVars) tipe
563 register rank pools (Alias home name argVars aliasVar)
566srcFieldTypeToVar :: Int -> Pools -> Map.Map Name.Name Variable -> Can.FieldType -> IO Variable
567srcFieldTypeToVar rank pools flexVars (Can.FieldType _ srcTipe) =
568 srcTypeToVar rank pools flexVars srcTipe
575makeCopy :: Int -> Pools -> Variable -> IO Variable
576makeCopy rank pools var =
577 do copy <- makeCopyHelp rank pools var
582makeCopyHelp :: Int -> Pools -> Variable -> IO Variable
583makeCopyHelp maxRank pools variable =
584 do (Descriptor content rank _ maybeCopy) <- UF.get variable
591 if rank /= noRank then
595 do let makeDescriptor c = Descriptor c maxRank noMark Nothing
596 copy <- UF.fresh $ makeDescriptor content
597 MVector.modify pools (copy:) maxRank
599 -- Link the original variable to the new variable. This lets us
600 -- avoid making multiple copies of the variable we are instantiating.
602 -- Need to do this before recursively copying to avoid looping.
604 Descriptor content rank noMark (Just copy)
606 -- Now we recursively copy the content of the variable.
607 -- We have already marked the variable as copied, so we
608 -- will not repeat this work or crawl this variable again.
611 do newTerm <- traverseFlatType (makeCopyHelp maxRank pools) term
612 UF.set copy $ makeDescriptor (Structure newTerm)
622 do UF.set copy $ makeDescriptor $ FlexVar (Just name)
625 RigidSuper super name ->
626 do UF.set copy $ makeDescriptor $ FlexSuper super (Just name)
629 Alias home name args realType ->
630 do newArgs <- mapM (traverse (makeCopyHelp maxRank pools)) args
631 newRealType <- makeCopyHelp maxRank pools realType
632 UF.set copy $ makeDescriptor (Alias home name newArgs newRealType)
643restore :: Variable -> IO ()
645 do (Descriptor content _ _ maybeCopy) <- UF.get variable
651 do UF.set variable $ Descriptor content noRank noMark Nothing
652 restoreContent content
655restoreContent :: Content -> IO ()
656restoreContent content =
682 Record1 fields ext ->
683 do mapM_ restore fields
696 Alias _ _ args var ->
697 do mapM_ (traverse restore) args
708traverseFlatType :: (Variable -> IO Variable) -> FlatType -> IO FlatType
709traverseFlatType f flatType =
711 App1 home name args ->
712 liftM (App1 home name) (traverse f args)
715 liftM2 Fun1 (f a) (f b)
720 Record1 fields ext ->
721 liftM2 Record1 (traverse f fields) (f ext)
727 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