1module Type.Solve (solve) where
3import Control.Applicative ((<$>), (<*>))
5import Control.Monad.State (StateT, execStateT, liftIO)
6import Control.Monad.Except (ExceptT, throwError)
7import qualified Data.List as List
8import qualified Data.Map as Map
9import qualified Data.Traversable as Traversable
10import qualified Data.UnionFind.IO as UF
12import qualified Reporting.Annotation as A
13import qualified Reporting.Error.Type as Error
14import qualified Type.State as TS
19{-| Every variable has rank less than or equal to the maxRank of the pool.
20This sorts variables into the young and old pools accordingly.
22generalize :: TS.Pool -> StateT TS.SolverState IO ()
24 do youngMark <- TS.uniqueMark
25 let youngRank = TS.maxRank youngPool
27 do descriptor <- liftIO $ UF.descriptor var
28 liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
29 return $ Map.insertWith (++) (rank descriptor) [var] dict
31 -- Sort the youngPool variables by rank.
32 rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
34 -- get the ranks right for each entry.
35 -- start at low ranks so that we only have to pass
36 -- over the information once.
37 visitedMark <- TS.uniqueMark
38 forM (Map.toList rankDict) $ \(poolRank, vars) ->
39 mapM (adjustRank youngMark visitedMark poolRank) vars
41 -- For variables that have rank lowerer than youngRank, register them in
42 -- the old pool if they are not redundant.
43 let registerIfNotRedundant var =
44 do isRedundant <- liftIO $ UF.redundant var
45 if isRedundant then return var else TS.register var
47 let rankDict' = Map.delete youngRank rankDict
48 Traversable.traverse (mapM registerIfNotRedundant) rankDict'
50 -- For variables with rank youngRank
51 -- If rank < youngRank: register in oldPool
52 -- otherwise generalize
53 let registerIfLowerRank var = do
54 isRedundant <- liftIO $ UF.redundant var
58 desc <- liftIO $ UF.descriptor var
59 case rank desc < youngRank of
60 True -> TS.register var >> return ()
62 let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
63 liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
65 mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
68-- adjust the ranks of variables such that ranks never increase as you
69-- move deeper into a variable.
70adjustRank :: Int -> Int -> Int -> Variable -> StateT TS.SolverState IO Int
71adjustRank youngMark visitedMark groupRank var =
72 do descriptor <- liftIO $ UF.descriptor var
74 () | mark descriptor == youngMark ->
75 do -- Set the variable as marked first because it may be cyclic.
76 liftIO $ UF.modifyDescriptor var $ \desc ->
77 desc { mark = visitedMark }
78 rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
79 liftIO $ UF.modifyDescriptor var $ \desc ->
83 | mark descriptor /= visitedMark ->
84 do let rank' = min groupRank (rank descriptor)
85 liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
89 return (rank descriptor)
92 adjustRank youngMark visitedMark groupRank
97 max `liftM` adjust a `ap` adjust b
100 max `liftM` adjust a `ap` adjust b
108 Record1 fields extension ->
109 do ranks <- mapM adjust (concat (Map.elems fields))
110 rnk <- adjust extension
111 return . maximum $ rnk : ranks
116solve :: TypeConstraint -> ExceptT [A.Located Error.Error] IO TS.SolverState
119 liftIO (execStateT (actuallySolve constraint) TS.initialState)
120 case TS.sError state of
127actuallySolve :: TypeConstraint -> StateT TS.SolverState IO ()
128actuallySolve constraint =
136 CEqual region term1 term2 ->
137 do t1 <- TS.flatten term1
138 t2 <- TS.flatten term2
142 mapM_ actuallySolve cs
144 CLet [Scheme [] fqs constraint' _] CTrue ->
145 do oldEnv <- TS.getEnv
146 mapM TS.introduce fqs
147 actuallySolve constraint'
148 TS.modifyEnv (\_ -> oldEnv)
150 CLet schemes constraint' ->
151 do oldEnv <- TS.getEnv
152 headers <- Map.unions `fmap` mapM solveScheme schemes
153 TS.modifyEnv $ \env -> Map.union headers env
154 actuallySolve constraint'
155 mapM occurs $ Map.toList headers
156 TS.modifyEnv (\_ -> oldEnv)
158 CInstance region name term ->
161 case Map.lookup name env of
165 if List.isPrefixOf "Native." name
166 then liftIO (variable Flexible)
167 else error ("Could not find '" ++ name ++ "' when solving type constraints.")
170 unify region freshCopy t
173solveScheme :: TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
176 Scheme [] [] constraint header ->
177 do actuallySolve constraint
178 Traversable.traverse TS.flatten header
180 Scheme rigidQuantifiers flexibleQuantifiers constraint header ->
181 do let quantifiers = rigidQuantifiers ++ flexibleQuantifiers
182 oldPool <- TS.getPool
184 -- fill in a new pool when working on this scheme's constraints
185 freshPool <- TS.nextRankPool
186 TS.switchToPool freshPool
187 mapM TS.introduce quantifiers
188 header' <- Traversable.traverse TS.flatten header
189 actuallySolve constraint
191 allDistinct rigidQuantifiers
192 youngPool <- TS.getPool
193 TS.switchToPool oldPool
195 mapM isGeneric rigidQuantifiers
201-- Checks that all of the given variables belong to distinct equivalence classes.
202-- Also checks that their structure is Nothing, so they represent a variable, not
203-- a more complex term.
204allDistinct :: [Variable] -> StateT TS.SolverState IO ()
206 do seen <- TS.uniqueMark
208 do desc <- liftIO $ UF.descriptor var
209 case structure desc of
211 TS.addError (error "Cannot generalize something that is not a type variable.") undefined
214 do when (mark desc == seen) $
215 TS.addError (error "Duplicate variable during generalization.") undefined
216 liftIO $ UF.setDescriptor var (desc { mark = seen })
219-- Check that a variable has rank == noRank, meaning that it can be generalized.
220isGeneric :: Variable -> StateT TS.SolverState IO ()
222 do desc <- liftIO $ UF.descriptor var
223 if rank desc == noRank
226 TS.addError (error "Unable to generalize a type variable. It is not unranked.") undefined
229occurs :: (String, Variable) -> StateT TS.SolverState IO ()
230occurs (_name, variable) =
231 do vars <- liftIO $ infiniteVars [] variable
237 do desc <- liftIO $ UF.descriptor var
238 case structure desc of
240 error "occurs check triggered"
243 error "occurs check triggered"
245 infiniteVars :: [Variable] -> Variable -> IO [Variable]
246 infiniteVars seen var =
247 let go = infiniteVars (var:seen)
252 desc <- UF.descriptor var
253 case structure desc of
258 (++) <$> go a <*> go b
261 (++) <$> go a <*> go b
269 Record1 fields ext ->
270 concat <$> mapM go (ext : concat (Map.elems fields))
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