1{-# OPTIONS_GHC -Wall #-}
4import Control.Monad.State (StateT, liftIO)
5import qualified Control.Monad.State as State
6import qualified Data.List as List
7import qualified Data.Map as Map
8import qualified Data.Set as Set
9import qualified Data.Traversable as Traverse (traverse)
10import qualified Data.UnionFind.IO as UF
12import qualified AST.Module.Name as ModuleName
13import qualified AST.Type as T
14import qualified AST.Variable as Var
15import qualified Reporting.Annotation as A
16import qualified Reporting.Error.Type as Error
17import qualified Reporting.Region as R
33 Constraint Type Variable
48 | Record1 (Map.Map String a) a
49 | Effects1 (Set.Set ModuleName.Canonical)
54 | AliasN Var.Canonical [(String, TermN a)] (TermN a)
56 | TermN (Term1 (TermN a))
59record :: Map.Map String (TermN a) -> TermN a -> TermN a
61 TermN (Record1 fs rec)
68data Descriptor = Descriptor
72 , _copy :: Maybe Variable
77 = Structure (Term1 Variable)
79 | Var Flex (Maybe Super) (Maybe String)
80 | Alias Var.Canonical [(String,Variable)] Variable
118getVarNamesMark :: Int
130 | CEqual Error.Hint R.Region a a
131 | CAnd [Constraint a b]
132 | CLet [Scheme a b] (Constraint a b)
133 | CInstance R.Region SchemeName a
136type SchemeName = String
139data Scheme a b = Scheme
140 { _rigidQuantifiers :: [b]
141 , _flexibleQuantifiers :: [b]
142 , _constraint :: Constraint a b
143 , _header :: Map.Map String (A.Located a)
154(==>) :: Type -> Type -> Type
159(<|) :: TermN a -> TermN a -> TermN a
168mkDescriptor :: Content -> Descriptor
169mkDescriptor content =
178mkAtom :: Var.Canonical -> IO Variable
180 UF.fresh $ mkDescriptor (Atom name)
183mkVar :: Maybe Super -> IO Variable
185 UF.fresh $ mkDescriptor (Var Flex maybeSuper Nothing)
188mkNamedVar :: String -> IO Variable
190 UF.fresh $ mkDescriptor (Var Flex (toSuper name) Nothing)
193mkRigid :: String -> IO Variable
195 UF.fresh $ mkDescriptor (Var Rigid (toSuper name) (Just name))
198toSuper :: String -> Maybe Super
200 if List.isPrefixOf "number" name then
203 else if List.isPrefixOf "comparable" name then
206 else if List.isPrefixOf "appendable" name then
217monoscheme :: Map.Map String (A.Located a) -> Scheme a b
219 Scheme [] [] CTrue headers
224(/\) :: Constraint a b -> Constraint a b -> Constraint a b
232-- ex qs constraint == exists qs. constraint
233ex :: [Variable] -> TypeConstraint -> TypeConstraint
235 CLet [Scheme [] fqs constraint Map.empty] CTrue
238-- fl qs constraint == forall qs. constraint
239fl :: [Variable] -> TypeConstraint -> TypeConstraint
241 CLet [Scheme rqs [] constraint Map.empty] CTrue
244exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
246 do v <- mkVar Nothing
247 ex [v] <$> f (VarN v)
250existsNumber :: (Type -> IO TypeConstraint) -> IO TypeConstraint
252 do v <- mkVar (Just Number)
253 ex [v] <$> f (VarN v)
257-- CONVERT TO SOURCE TYPES
260-- TODO: Attach resulting type to the descriptor so that you
261-- never have to do extra work, particularly nice for aliased types
262toSrcType :: Variable -> IO T.Canonical
264 do usedNames <- getVarNames variable
265 State.evalStateT (variableToSrcType variable) (makeNameState usedNames)
268variableToSrcType :: Variable -> StateT NameState IO T.Canonical
269variableToSrcType variable =
270 do descriptor <- liftIO $ UF.descriptor variable
271 let mark = _mark descriptor
272 if mark == occursMark
277 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
278 srcType <- contentToSrcType variable (_content descriptor)
279 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
283contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
284contentToSrcType variable content =
292 Var _ _ (Just name) ->
295 Var flex maybeSuper Nothing ->
296 do freshName <- getFreshName maybeSuper
297 liftIO $ UF.modifyDescriptor variable $ \desc ->
298 desc { _content = Var flex maybeSuper (Just freshName) }
299 return (T.Var freshName)
301 Alias name args realVariable ->
302 do srcArgs <- mapM (\(arg,tvar) -> (,) arg <$> variableToSrcType tvar) args
303 srcType <- variableToSrcType realVariable
304 return (T.Aliased name srcArgs (T.Filled srcType))
310termToSrcType :: Term1 Variable -> StateT NameState IO T.Canonical
314 do srcFunc <- variableToSrcType func
315 srcArg <- variableToSrcType arg
318 return (T.App f (args ++ [srcArg]))
321 return (T.App srcFunc [srcArg])
325 <$> variableToSrcType a
326 <*> variableToSrcType b
329 return $ T.Record [] Nothing
331 Record1 fields extension ->
332 do srcFields <- Map.toList <$> Traverse.traverse variableToSrcType fields
333 srcExt <- T.iteratedDealias <$> variableToSrcType extension
336 T.Record subFields subExt ->
337 T.Record (subFields ++ srcFields) subExt
340 T.Record srcFields (Just srcExt)
343 error "Used toSrcType on a type that is not well-formed"
346 return $ T.Effects names
350-- MANAGE FRESH VARIABLE NAMES
353data NameState = NameState
354 { _freeNames :: [String]
355 , _numberPrimes :: Int
356 , _comparablePrimes :: Int
357 , _appendablePrimes :: Int
358 , _compAppendPrimes :: Int
362makeNameState :: Set.Set String -> NameState
363makeNameState usedNames =
366 map (:suffix) ['a'..'z']
369 concatMap makeName ("" : map show [ (1 :: Int) .. ])
372 filter (\name -> Set.notMember name usedNames) allNames
374 NameState freeNames 0 0 0 0
377getFreshName :: (Monad m) => Maybe Super -> StateT NameState m String
378getFreshName maybeSuper =
381 do names <- State.gets _freeNames
382 State.modify (\state -> state { _freeNames = tail names })
386 do primes <- State.gets _numberPrimes
387 State.modify (\state -> state { _numberPrimes = primes + 1 })
388 return ("number" ++ replicate primes '\'')
391 do primes <- State.gets _comparablePrimes
392 State.modify (\state -> state { _comparablePrimes = primes + 1 })
393 return ("comparable" ++ replicate primes '\'')
396 do primes <- State.gets _appendablePrimes
397 State.modify (\state -> state { _appendablePrimes = primes + 1 })
398 return ("appendable" ++ replicate primes '\'')
401 do primes <- State.gets _compAppendPrimes
402 State.modify (\state -> state { _compAppendPrimes = primes + 1 })
403 return ("compappend" ++ replicate primes '\'')
407-- GET ALL VARIABLE NAMES
410getVarNames :: Variable -> IO (Set.Set String)
412 do desc <- UF.descriptor var
413 if _mark desc == getVarNamesMark
418 do UF.setDescriptor var (desc { _mark = getVarNamesMark })
419 getVarNamesHelp (_content desc)
422getVarNamesHelp :: Content -> IO (Set.Set String)
423getVarNamesHelp content =
425 Var _ _ (Just name) ->
426 return (Set.singleton name)
434 Alias _name args realVar ->
435 do let argSet = Set.fromList (map fst args)
436 realSet <- getVarNames realVar
437 sets <- mapM (getVarNames . snd) args
438 return (Set.unions (realSet : argSet : sets))
447getVarNamesTerm :: Term1 Variable -> IO (Set.Set String)
448getVarNamesTerm term =
449 let go = getVarNames in
452 Set.union <$> go a <*> go b
455 Set.union <$> go a <*> go b
460 Record1 fields extension ->
461 do fieldVars <- Set.unions <$> mapM go (Map.elems fields)
462 Set.union fieldVars <$> go extension
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