1{-# OPTIONS_GHC -Wall #-}
24import qualified Control.Monad.State as State
25import qualified Data.Map as Map
27import Data.Text (Text)
28import qualified Data.UnionFind.IO as UF
30import qualified Reporting.Annotation as A
31import qualified Reporting.Error.Type as Error
32import qualified Reporting.Region as R
39type Solver = State.StateT SolverState IO
42run :: Solver () -> IO SolverState
44 State.execStateT solver $
47 , sSavedEnv = Map.empty
48 , sPool = Pool outermostRank []
49 , sMark = noMark + 1 -- The mark must never be equal to noMark!
64 , sError :: [A.Located Error.Error]
68{-| A pool holds a bunch of variables
69The rank of each variable is less than or equal to the pool's "maxRank"
70The young pool exists to make it possible to identify these vars in constant time.
75 , inhabitants :: [Variable]
79type Env = Map.Map Text (A.Located Variable)
86modifyEnv :: (Env -> Env) -> Solver ()
88 State.modify $ \state -> state { sEnv = f (sEnv state) }
91modifyPool :: (Pool -> Pool) -> Solver ()
93 State.modify $ \state -> state { sPool = f (sPool state) }
96addError :: R.Region -> Error.Error -> Solver ()
98 State.modify $ \state -> state { sError = A.A region err : sError state }
101switchToPool :: Pool -> Solver ()
103 modifyPool (\_ -> pool)
106getPool :: Solver Pool
116saveLocalEnv :: Solver ()
118 do currentEnv <- getEnv
119 State.modify $ \state -> state { sSavedEnv = currentEnv }
122uniqueMark :: Solver Int
124 do state <- State.get
125 let mark = sMark state
126 State.put $ state { sMark = mark + 1 }
130nextRankPool :: Solver Pool
133 return $ Pool { maxRank = maxRank pool + 1, inhabitants = [] }
136register :: Variable -> Solver Variable
138 do modifyPool $ \pool -> pool { inhabitants = variable : inhabitants pool }
142introduce :: Variable -> Solver Variable
145 State.liftIO $ UF.modifyDescriptor variable (\desc -> desc { _rank = maxRank pool })
149flatten :: Type -> Solver Variable
151 flattenHelp Map.empty term
154flattenHelp :: Map.Map Text Variable -> Type -> Solver Variable
155flattenHelp aliasDict termN =
158 return (aliasDict ! name)
160 AliasN name args realType ->
161 do flatArgs <- mapM (traverse (flattenHelp aliasDict)) args
162 flatVar <- flattenHelp (Map.fromList flatArgs) realType
165 State.liftIO . UF.fresh $ Descriptor
166 { _content = Alias name flatArgs flatVar
167 , _rank = maxRank pool
177 do variableTerm <- traverseTerm (flattenHelp aliasDict) term1
180 State.liftIO . UF.fresh $ Descriptor
181 { _content = Structure variableTerm
182 , _rank = maxRank pool
189makeInstance :: Variable -> Solver Variable
191 do alreadyCopiedMark <- uniqueMark
192 freshVar <- makeCopy alreadyCopiedMark var
193 _ <- restore alreadyCopiedMark var
197makeCopy :: Int -> Variable -> Solver Variable
198makeCopy alreadyCopiedMark variable =
199 do desc <- State.liftIO $ UF.descriptor variable
200 makeCopyHelp desc alreadyCopiedMark variable
203makeCopyHelp :: Descriptor -> Int -> Variable -> Solver Variable
204makeCopyHelp descriptor alreadyCopiedMark variable =
205 if _mark descriptor == alreadyCopiedMark then
206 case _copy descriptor of
207 Just copiedVariable ->
208 return copiedVariable
212 "Error copying type variable. This should be impossible.\
213 \ Please report this at <https://github.com/elm-lang/elm-compiler/issues>\
214 \ with a <http://sscce.org> and information on your OS, how you installed,\
215 \ and any other configuration information that might be helpful."
217 else if _rank descriptor /= noRank || not (needsCopy (_content descriptor)) then
223 State.liftIO $ UF.fresh $ Descriptor
224 { _content = error "will be filled in soon!"
225 , _rank = maxRank pool
231 -- Link the original variable to the new variable. This lets us
232 -- avoid making multiple copies of the variable we are instantiating.
234 -- Need to do this before recursively copying the content of
235 -- the variable to avoid looping on cyclic terms.
236 State.liftIO $ UF.modifyDescriptor variable $ \desc ->
237 desc { _mark = alreadyCopiedMark, _copy = Just newVar }
239 -- Now we recursively copy the content of the variable.
240 -- We have already marked the variable as copied, so we
241 -- will not repeat this work or crawl this variable again.
242 let oldContent = _content descriptor
246 Structure <$> traverseTerm (makeCopy alreadyCopiedMark) term
251 Var Rigid maybeSuper maybeName ->
252 return (Var Flex maybeSuper maybeName)
257 Alias name args realType ->
259 <$> mapM (traverse (makeCopy alreadyCopiedMark)) args
260 <*> makeCopy alreadyCopiedMark realType
265 State.liftIO $ UF.modifyDescriptor newVar $ \desc ->
266 desc { _content = newContent }
271needsCopy :: Content -> Bool
291restore :: Int -> Variable -> Solver Variable
292restore alreadyCopiedMark variable =
293 do desc <- State.liftIO $ UF.descriptor variable
294 if _mark desc /= alreadyCopiedMark
299 do restoredContent <-
300 restoreContent alreadyCopiedMark (_content desc)
301 State.liftIO $ UF.setDescriptor variable $ Descriptor
302 { _content = restoredContent
311restoreContent :: Int -> Content -> Solver Content
312restoreContent alreadyCopiedMark content =
314 go = restore alreadyCopiedMark
318 Structure <$> traverseTerm go term
326 Alias name args var ->
328 <$> mapM (traverse go) args
339traverseTerm :: (Monad f, Applicative f) => (a -> f b) -> Term1 a -> f (Term1 b)
351 Record1 fields ext ->
352 Record1 <$> traverse 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