2module Type.Solve (solve) where
5import Control.Monad.State
6import qualified Data.List as List
7import qualified Data.Map as Map
8import qualified Data.Traversable as Traversable
9import qualified Data.UnionFind.IO as UF
12import qualified Type.ExtraChecks as Check
13import qualified Type.State as TS
14import qualified AST.Annotation as A
17-- | Every variable has rank less than or equal to the maxRank of the pool.
18-- This sorts variables into the young and old pools accordingly.
19generalize :: TS.Pool -> StateT TS.SolverState IO ()
20generalize youngPool = do
21 youngMark <- TS.uniqueMark
22 let youngRank = TS.maxRank youngPool
24 descriptor <- liftIO $ UF.descriptor var
25 liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
26 return $ Map.insertWith (++) (rank descriptor) [var] dict
28 -- Sort the youngPool variables by rank.
29 rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
31 -- get the ranks right for each entry.
32 -- start at low ranks so that we only have to pass
33 -- over the information once.
34 visitedMark <- TS.uniqueMark
35 forM (Map.toList rankDict) $ \(poolRank, vars) ->
36 mapM (adjustRank youngMark visitedMark poolRank) vars
38 -- For variables that have rank lowerer than youngRank, register them in
39 -- the old pool if they are not redundant.
40 let registerIfNotRedundant var = do
41 isRedundant <- liftIO $ UF.redundant var
42 if isRedundant then return var else TS.register var
44 let rankDict' = Map.delete youngRank rankDict
45 Traversable.traverse (mapM registerIfNotRedundant) rankDict'
47 -- For variables with rank youngRank
48 -- If rank < youngRank: register in oldPool
49 -- otherwise generalize
50 let registerIfLowerRank var = do
51 isRedundant <- liftIO $ UF.redundant var
55 desc <- liftIO $ UF.descriptor var
56 case rank desc < youngRank of
57 True -> TS.register var >> return ()
59 let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
60 liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
62 mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
65-- adjust the ranks of variables such that ranks never increase as you
66-- move deeper into a variable.
67adjustRank :: Int -> Int -> Int -> Variable -> StateT TS.SolverState IO Int
68adjustRank youngMark visitedMark groupRank var =
69 do descriptor <- liftIO $ UF.descriptor var
71 () | mark descriptor == youngMark ->
72 do -- Set the variable as marked first because it may be cyclic.
73 liftIO $ UF.modifyDescriptor var $ \desc ->
74 desc { mark = visitedMark }
75 rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
76 liftIO $ UF.modifyDescriptor var $ \desc ->
80 | mark descriptor /= visitedMark ->
81 do let rank' = min groupRank (rank descriptor)
82 liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
85 | otherwise -> return (rank descriptor)
88 adjust = adjustRank youngMark visitedMark groupRank
92 App1 a b -> max `liftM` adjust a `ap` adjust b
93 Fun1 a b -> max `liftM` adjust a `ap` adjust b
95 EmptyRecord1 -> return outermostRank
96 Record1 fields extension ->
97 do ranks <- mapM adjust (concat (Map.elems fields))
98 rnk <- adjust extension
99 return . maximum $ rnk : ranks
102solve :: TypeConstraint -> StateT TS.SolverState IO ()
103solve (A.A region constraint) =
107 CSaveEnv -> TS.saveLocalEnv
109 CEqual term1 term2 -> do
110 t1 <- TS.flatten term1
111 t2 <- TS.flatten term2
114 CAnd cs -> mapM_ solve cs
116 CLet [Scheme [] fqs constraint' _] (A.A _ CTrue) -> do
118 mapM TS.introduce fqs
120 TS.modifyEnv (\_ -> oldEnv)
122 CLet schemes constraint' -> do
124 headers <- Map.unions `fmap` mapM (solveScheme region) schemes
125 TS.modifyEnv $ \env -> Map.union headers env
127 mapM Check.occurs $ Map.toList headers
128 TS.modifyEnv (\_ -> oldEnv)
130 CInstance name term -> do
133 case Map.lookup name env of
134 Just tipe -> TS.makeInstance tipe
136 | List.isPrefixOf "Native." name -> liftIO (variable Flexible)
138 error ("Could not find '" ++ name ++ "' when solving type constraints.")
141 unify region freshCopy t
143solveScheme :: A.Region -> TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
144solveScheme region scheme =
146 Scheme [] [] constraint header -> do
148 Traversable.traverse TS.flatten header
150 Scheme rigidQuantifiers flexibleQuantifiers constraint header -> do
151 let quantifiers = rigidQuantifiers ++ flexibleQuantifiers
152 oldPool <- TS.getPool
154 -- fill in a new pool when working on this scheme's constraints
155 freshPool <- TS.nextRankPool
156 TS.switchToPool freshPool
157 mapM TS.introduce quantifiers
158 header' <- Traversable.traverse TS.flatten header
161 allDistinct region rigidQuantifiers
162 youngPool <- TS.getPool
163 TS.switchToPool oldPool
165 mapM (isGeneric region) rigidQuantifiers
169-- Checks that all of the given variables belong to distinct equivalence classes.
170-- Also checks that their structure is Nothing, so they represent a variable, not
171-- a more complex term.
172allDistinct :: A.Region -> [Variable] -> StateT TS.SolverState IO ()
173allDistinct region vars = do
174 seen <- TS.uniqueMark
176 desc <- liftIO $ UF.descriptor var
177 case structure desc of
178 Just _ -> TS.addError region (Just msg) var var
179 where msg = "Cannot generalize something that is not a type variable."
183 then let msg = "Duplicate variable during generalization."
184 in TS.addError region (Just msg) var var
186 liftIO $ UF.setDescriptor var (desc { mark = seen })
189-- Check that a variable has rank == noRank, meaning that it can be generalized.
190isGeneric :: A.Region -> Variable -> StateT TS.SolverState IO ()
191isGeneric region var = do
192 desc <- liftIO $ UF.descriptor var
193 if rank desc == noRank
195 else let msg = "Unable to generalize a type variable. It is not unranked."
196 in TS.addError region (Just msg) var var
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