1module Type.Solve (solve) where
4import Control.Monad.State
5import qualified Data.List as List
6import qualified Data.Map as Map
7import qualified Data.Traversable as Traversable
8import qualified Data.UnionFind.IO as UF
11import qualified Type.ExtraChecks as Check
12import qualified Type.State as TS
13import qualified AST.Annotation as A
16-- | Every variable has rank less than or equal to the maxRank of the pool.
17-- This sorts variables into the young and old pools accordingly.
18generalize :: TS.Pool -> StateT TS.SolverState IO ()
20 do youngMark <- TS.uniqueMark
21 let youngRank = TS.maxRank youngPool
23 descriptor <- liftIO $ UF.descriptor var
24 liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
25 return $ Map.insertWith (++) (rank descriptor) [var] dict
27 -- Sort the youngPool variables by rank.
28 rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
30 -- get the ranks right for each entry.
31 -- start at low ranks so that we only have to pass
32 -- over the information once.
33 visitedMark <- TS.uniqueMark
34 forM (Map.toList rankDict) $ \(poolRank, vars) ->
35 mapM (adjustRank youngMark visitedMark poolRank) vars
37 -- For variables that have rank lowerer than youngRank, register them in
38 -- the old pool if they are not redundant.
39 let registerIfNotRedundant var = do
40 isRedundant <- liftIO $ UF.redundant var
41 if isRedundant then return var else TS.register var
43 let rankDict' = Map.delete youngRank rankDict
44 Traversable.traverse (mapM registerIfNotRedundant) rankDict'
46 -- For variables with rank youngRank
47 -- If rank < youngRank: register in oldPool
48 -- otherwise generalize
49 let registerIfLowerRank var = do
50 isRedundant <- liftIO $ UF.redundant var
54 desc <- liftIO $ UF.descriptor var
55 case rank desc < youngRank of
56 True -> TS.register var >> return ()
58 let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
59 liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
61 mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
64-- adjust the ranks of variables such that ranks never increase as you
65-- move deeper into a variable.
66adjustRank :: Int -> Int -> Int -> Variable -> StateT TS.SolverState IO Int
67adjustRank youngMark visitedMark groupRank var =
68 do descriptor <- liftIO $ UF.descriptor var
70 () | mark descriptor == youngMark ->
71 do -- Set the variable as marked first because it may be cyclic.
72 liftIO $ UF.modifyDescriptor var $ \desc ->
73 desc { mark = visitedMark }
74 rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
75 liftIO $ UF.modifyDescriptor var $ \desc ->
79 | mark descriptor /= visitedMark ->
80 do let rank' = min groupRank (rank descriptor)
81 liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
85 return (rank descriptor)
87 adjust = adjustRank youngMark visitedMark groupRank
91 App1 a b -> max `liftM` adjust a `ap` adjust b
92 Fun1 a b -> max `liftM` adjust a `ap` adjust b
94 EmptyRecord1 -> return outermostRank
95 Record1 fields extension ->
96 do ranks <- mapM adjust (concat (Map.elems fields))
97 rnk <- adjust extension
98 return . maximum $ rnk : ranks
101solve :: TypeConstraint -> StateT TS.SolverState IO ()
102solve (A.A region constraint) =
110 CEqual term1 term2 ->
111 do t1 <- TS.flatten term1
112 t2 <- TS.flatten term2
118 CLet [Scheme [] fqs constraint' _] (A.A _ CTrue) ->
119 do oldEnv <- TS.getEnv
120 mapM TS.introduce fqs
122 TS.modifyEnv (\_ -> oldEnv)
124 CLet schemes constraint' ->
125 do oldEnv <- TS.getEnv
126 headers <- Map.unions `fmap` mapM (solveScheme region) schemes
127 TS.modifyEnv $ \env -> Map.union headers env
129 mapM Check.occurs $ Map.toList headers
130 TS.modifyEnv (\_ -> oldEnv)
132 CInstance name term ->
135 case Map.lookup name env of
136 Just tipe -> TS.makeInstance tipe
138 | List.isPrefixOf "Native." name -> liftIO (variable Flexible)
140 error ("Could not find '" ++ name ++ "' when solving type constraints.")
143 unify region freshCopy t
146solveScheme :: A.Region -> TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
147solveScheme region scheme =
149 Scheme [] [] constraint header ->
151 Traversable.traverse TS.flatten header
153 Scheme rigidQuantifiers flexibleQuantifiers constraint header ->
154 do let quantifiers = rigidQuantifiers ++ flexibleQuantifiers
155 oldPool <- TS.getPool
157 -- fill in a new pool when working on this scheme's constraints
158 freshPool <- TS.nextRankPool
159 TS.switchToPool freshPool
160 mapM TS.introduce quantifiers
161 header' <- Traversable.traverse TS.flatten header
164 allDistinct region rigidQuantifiers
165 youngPool <- TS.getPool
166 TS.switchToPool oldPool
168 mapM (isGeneric region) rigidQuantifiers
172-- Checks that all of the given variables belong to distinct equivalence classes.
173-- Also checks that their structure is Nothing, so they represent a variable, not
174-- a more complex term.
175allDistinct :: A.Region -> [Variable] -> StateT TS.SolverState IO ()
176allDistinct region vars =
177 do seen <- TS.uniqueMark
179 desc <- liftIO $ UF.descriptor var
180 case structure desc of
181 Just _ -> TS.addError region (Just msg) var var
182 where msg = "Cannot generalize something that is not a type variable."
186 then let msg = "Duplicate variable during generalization."
187 in TS.addError region (Just msg) var var
189 liftIO $ UF.setDescriptor var (desc { mark = seen })
193-- Check that a variable has rank == noRank, meaning that it can be generalized.
194isGeneric :: A.Region -> Variable -> StateT TS.SolverState IO ()
195isGeneric region var =
196 do desc <- liftIO $ UF.descriptor var
197 if rank desc == noRank
200 let msg = "Unable to generalize a type variable. It is not unranked."
201 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