4import Control.Applicative ( (<$>), (<*>), Applicative, (<|>) )
5import Control.Monad.State
6import qualified Data.Map as Map
7import qualified Data.Traversable as Traversable
8import qualified Data.UnionFind.IO as UF
10import qualified AST.Annotation as A
12import Text.PrettyPrint as P
16-- Holds a bunch of variables
17-- The rank of each variable is less than or equal to the pool's "maxRank"
18-- The young pool exists to make it possible to identify these vars in constant time.
22 , inhabitants :: [Variable]
25emptyPool = Pool { maxRank = outermostRank, inhabitants = [] }
27type Env = Map.Map String Variable
29-- Keeps track of the environment, type variable pool, and a list of errors
30data SolverState = SS {
40 sSavedEnv = Map.empty,
42 sMark = noMark + 1, -- The mark must never be equal to noMark!
46modifyEnv f = modify $ \state -> state { sEnv = f (sEnv state) }
47modifyPool f = modify $ \state -> state { sPool = f (sPool state) }
49addError :: A.Region -> Maybe String -> UF.Point Descriptor -> UF.Point Descriptor
50 -> StateT SolverState IO ()
51addError region hint t1 t2 =
52 do err <- liftIO makeError
53 modify $ \state -> state { sErrors = err : sErrors state }
56 t1' <- pretty <$> toSrcType t1
57 t2' <- pretty <$> toSrcType t2
59 [ P.text "Type error" <+> pretty region <> P.colon
60 , maybe P.empty P.text hint
62 , P.nest 8 $ A.getRegionDocs region
64 , P.text " Expected Type:" <+> t1'
65 , P.text " Actual Type:" <+> t2'
68switchToPool pool = modifyPool (\_ -> pool)
70getPool :: StateT SolverState IO Pool
71getPool = sPool <$> get
73getEnv :: StateT SolverState IO Env
76saveLocalEnv :: StateT SolverState IO ()
79 modify $ \state -> state { sSavedEnv = env }
81uniqueMark :: StateT SolverState IO Int
84 let mark = sMark state
85 put $ state { sMark = mark + 1 }
88nextRankPool :: StateT SolverState IO Pool
91 return $ Pool { maxRank = maxRank pool + 1, inhabitants = [] }
93register :: Variable -> StateT SolverState IO Variable
95 modifyPool $ \pool -> pool { inhabitants = variable : inhabitants pool }
98introduce :: Variable -> StateT SolverState IO Variable
99introduce variable = do
101 liftIO $ UF.modifyDescriptor variable (\desc -> desc { rank = maxRank pool })
104flatten :: Type -> StateT SolverState IO Variable
107 VarN maybeAlias v -> do
108 liftIO $ UF.modifyDescriptor v $ \desc -> desc { alias = maybeAlias <|> alias desc }
110 TermN maybeAlias t -> do
111 flatStructure <- traverseTerm flatten t
113 var <- liftIO . UF.fresh $ Descriptor
114 { structure = Just flatStructure
115 , rank = maxRank pool
124makeInstance :: Variable -> StateT SolverState IO Variable
126 alreadyCopied <- uniqueMark
127 freshVar <- makeCopy alreadyCopied var
128 restore alreadyCopied var
131makeCopy :: Int -> Variable -> StateT SolverState IO Variable
132makeCopy alreadyCopied variable = do
133 desc <- liftIO $ UF.descriptor variable
135 () | mark desc == alreadyCopied ->
138 Nothing -> error $ "Error copying type variable. This should be impossible." ++
139 " Please report an error to the github repo!"
141 | rank desc /= noRank || flex desc == Constant ->
146 newVar <- liftIO $ UF.fresh $ Descriptor
147 { structure = Nothing
148 , rank = maxRank pool
150 , flex = case flex desc of
154 , name = case flex desc of
161 -- Link the original variable to the new variable. This lets us
162 -- avoid making multiple copies of the variable we are instantiating.
164 -- Need to do this before recursively copying the structure of
165 -- the variable to avoid looping on cyclic terms.
166 liftIO $ UF.modifyDescriptor variable $ \desc ->
167 desc { mark = alreadyCopied, copy = Just newVar }
169 -- Now we recursively copy the structure of the variable.
170 -- We have already marked the variable as copied, so we
171 -- will not repeat this work or crawl this variable again.
172 case structure desc of
173 Nothing -> return newVar
175 newTerm <- traverseTerm (makeCopy alreadyCopied) term
176 liftIO $ UF.modifyDescriptor newVar $ \desc ->
177 desc { structure = Just newTerm }
180restore :: Int -> Variable -> StateT SolverState IO Variable
181restore alreadyCopied variable = do
182 desc <- liftIO $ UF.descriptor variable
183 if mark desc /= alreadyCopied
187 Traversable.traverse (traverseTerm (restore alreadyCopied)) (structure desc)
188 liftIO $ UF.modifyDescriptor variable $ \desc ->
189 desc { mark = noMark, rank = noRank, structure = restoredStructure }
192traverseTerm :: (Monad f, Applicative f) => (a -> f b) -> Term1 a -> f (Term1 b)
195 App1 a b -> App1 <$> f a <*> f b
196 Fun1 a b -> Fun1 <$> f a <*> f b
197 Var1 x -> Var1 <$> f x
198 EmptyRecord1 -> return EmptyRecord1
199 Record1 fields ext ->
200 Record1 <$> Traversable.traverse (mapM f) fields <*> f ext
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