3import Control.Applicative ( (<$>), (<*>), Applicative, (<|>) )
4import Control.Monad.State
5import qualified Data.Map as Map
6import qualified Data.Traversable as Traversable
7import qualified Data.UnionFind.IO as UF
9import qualified AST.Annotation as A
11import Text.PrettyPrint as P
15-- Holds a bunch of variables
16-- The rank of each variable is less than or equal to the pool's "maxRank"
17-- The young pool exists to make it possible to identify these vars in constant time.
21 , inhabitants :: [Variable]
24emptyPool = Pool { maxRank = outermostRank, inhabitants = [] }
26type Env = Map.Map String Variable
28-- Keeps track of the environment, type variable pool, and a list of errors
29data SolverState = SS {
39 sSavedEnv = Map.empty,
41 sMark = noMark + 1, -- The mark must never be equal to noMark!
45modifyEnv f = modify $ \state -> state { sEnv = f (sEnv state) }
46modifyPool f = modify $ \state -> state { sPool = f (sPool state) }
48addError :: A.Region -> Maybe String -> UF.Point Descriptor -> UF.Point Descriptor
49 -> StateT SolverState IO ()
50addError region hint t1 t2 =
51 do err <- liftIO makeError
52 modify $ \state -> state { sErrors = err : sErrors state }
55 t1' <- pretty <$> toSrcType t1
56 t2' <- pretty <$> toSrcType t2
57 return . foldr ($+$) P.empty $
58 [ P.text "Type mismatch" <+> pretty region <> P.text "."
59 , maybe P.empty P.text hint
61 , P.nest 8 $ A.getRegionDocs region
63 , P.text " Something is causing a mismatch between the following types:"
70switchToPool pool = modifyPool (\_ -> pool)
72getPool :: StateT SolverState IO Pool
73getPool = sPool <$> get
75getEnv :: StateT SolverState IO Env
78saveLocalEnv :: StateT SolverState IO ()
81 modify $ \state -> state { sSavedEnv = env }
83uniqueMark :: StateT SolverState IO Int
86 let mark = sMark state
87 put $ state { sMark = mark + 1 }
90nextRankPool :: StateT SolverState IO Pool
93 return $ Pool { maxRank = maxRank pool + 1, inhabitants = [] }
95register :: Variable -> StateT SolverState IO Variable
97 modifyPool $ \pool -> pool { inhabitants = variable : inhabitants pool }
100introduce :: Variable -> StateT SolverState IO Variable
101introduce variable = do
103 liftIO $ UF.modifyDescriptor variable (\desc -> desc { rank = maxRank pool })
106flatten :: Type -> StateT SolverState IO Variable
109 VarN maybeAlias v -> do
110 liftIO $ UF.modifyDescriptor v $ \desc -> desc { alias = maybeAlias <|> alias desc }
112 TermN maybeAlias t -> do
113 flatStructure <- traverseTerm flatten t
115 var <- liftIO . UF.fresh $ Descriptor
116 { structure = Just flatStructure
117 , rank = maxRank pool
126makeInstance :: Variable -> StateT SolverState IO Variable
128 alreadyCopied <- uniqueMark
129 freshVar <- makeCopy alreadyCopied var
130 restore alreadyCopied var
133makeCopy :: Int -> Variable -> StateT SolverState IO Variable
134makeCopy alreadyCopied variable = do
135 desc <- liftIO $ UF.descriptor variable
137 () | mark desc == alreadyCopied ->
140 Nothing -> error $ "Error copying type variable. This should be impossible." ++
141 " Please report an error to the github repo!"
143 | rank desc /= noRank || flex desc == Constant ->
148 newVar <- liftIO $ UF.fresh $ Descriptor
149 { structure = Nothing
150 , rank = maxRank pool
152 , flex = case flex desc of
156 , name = case flex desc of
163 -- Link the original variable to the new variable. This lets us
164 -- avoid making multiple copies of the variable we are instantiating.
166 -- Need to do this before recursively copying the structure of
167 -- the variable to avoid looping on cyclic terms.
168 liftIO $ UF.modifyDescriptor variable $ \desc ->
169 desc { mark = alreadyCopied, copy = Just newVar }
171 -- Now we recursively copy the structure of the variable.
172 -- We have already marked the variable as copied, so we
173 -- will not repeat this work or crawl this variable again.
174 case structure desc of
175 Nothing -> return newVar
177 newTerm <- traverseTerm (makeCopy alreadyCopied) term
178 liftIO $ UF.modifyDescriptor newVar $ \desc ->
179 desc { structure = Just newTerm }
182restore :: Int -> Variable -> StateT SolverState IO Variable
183restore alreadyCopied variable = do
184 desc <- liftIO $ UF.descriptor variable
185 if mark desc /= alreadyCopied
189 Traversable.traverse (traverseTerm (restore alreadyCopied)) (structure desc)
190 liftIO $ UF.modifyDescriptor variable $ \desc ->
191 desc { mark = noMark, rank = noRank, structure = restoredStructure }
194traverseTerm :: (Monad f, Applicative f) => (a -> f b) -> Term1 a -> f (Term1 b)
197 App1 a b -> App1 <$> f a <*> f b
198 Fun1 a b -> Fun1 <$> f a <*> f b
199 Var1 x -> Var1 <$> f x
200 EmptyRecord1 -> return EmptyRecord1
201 Record1 fields ext ->
202 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