module Statics.Rename (
-- * The renaming monad and runners
Renaming, runRenaming, runRenamingM,
renameMapM,
-- * State between renaming steps
RenameState, renameState0,
-- ** Adding the basis
addVal, addType, addMod,
-- * Renamers
renameProg, renameDecls, renameDecl, renameType, renameSigItem,
-- * REPL query
getRenamingInfo, RenamingInfo(..),
renamingEnterScope,
) where
import Error
import Meta.Quasi
import AST hiding ((&))
import Data.Loc
import AST.TypeAnnotation
import qualified AST.Notable
import Util
import Syntax.Ppr (Ppr(..))
import Prelude ()
import qualified Data.Map as M
import qualified Data.Set as S
-- | The type to save the state of the renamer between calls
data RenameState = RenameState {
savedEnv :: Env,
savedCounter :: Renamed
} deriving Show
-- | The initial state
renameState0 :: RenameState
renameState0 = RenameState {
savedEnv = mempty {
datacons = M.singleton (ident "()") (ident "()", mkBogus "built-in", ())
},
savedCounter = renamed0
}
-- | Generate a renamer error.
renameErrorStop :: Message V -> R a
renameErrorStop msg0 = do
throwAlms (AlmsError RenamerPhase bogus msg0)
-- | Generate a renamer error, but keep going.
renameError :: Bogus a => Message V -> R a
renameError msg0 = do
reportAlms (AlmsError RenamerPhase bogus msg0)
return bogus
renameBug :: String -> String -> R a
renameBug culprit msg0 = do
throwAlms (almsBug RenamerPhase culprit msg0)
-- | The renaming monad: Reads a context, writes a module, and
-- keeps track of a renaming counter state.
newtype Renaming a = R {
unR :: RWST Context Module RState (AlmsErrorT Identity) a
} deriving (Functor, MonadAlmsError)
-- | The threaded state of the renamer.
newtype RState = RState {
-- | The gensym counter:
rsCounter :: Renamed
}
instance Monad Renaming where
return = R . return
m >>= k = R (unR m >>= unR . k)
fail = renameErrorStop . [msg| $words:1 |]
instance Applicative Renaming where
pure = return
(<*>) = ap
instance MonadWriter Module Renaming where
listen = R . listen . unR
tell = R . tell
pass = R . pass . unR
instance MonadReader Env Renaming where
ask = R (asks env)
local f = R . local (\cxt -> cxt { env = f (env cxt) }) . unR
instance MonadError [AlmsError] Renaming where
throwError = throwAlmsList
catchError = catchAlms
-- | The renaming environment
data Env = Env {
tycons :: !(EnvMap TypId [ConId Raw]),
vars :: !(EnvMap VarId ()),
datacons :: !(EnvMap ConId ()),
modules :: !(EnvMap ModId (Module, Env)),
sigs :: !(EnvMap SigId (Module, Env)),
tyvars :: !(EnvMap Lid (QLit, Bool))
} deriving Show
type EnvMap f i = M.Map (f Raw) (f Renamed, Loc, i)
-- | A module item is one of 5 renaming entries, an empty module, r
-- a pair of modules. Note that while type variables are not actual
-- module items, they are exported from patterns, so it's useful to
-- have them here.
type Module = [ModItem]
data ModItem
= MdTycon !Loc !(TypId Raw) !(TypId Renamed) ![ConId Raw]
| MdVar !Loc !(VarId Raw) !(VarId Renamed)
| MdDatacon !Loc !(ConId Raw) !(ConId Renamed)
| MdModule !Loc !(ModId Raw) !(ModId Renamed) !Module
| MdSig !Loc !(SigId Raw) !(SigId Renamed) !Module
| MdTyvar !Loc !(TyVar Raw) !(TyVar Renamed)
deriving Show
-- | The renaming context, which includes the environment (which is
-- persistant), and other information with is not
data Context = Context {
env :: !Env,
allocate :: !Bool,
inExpr :: !Bool
}
-- | Run a renaming computation
runRenaming :: Bool -> Loc -> RenameState -> Renaming a ->
Either [AlmsError] (a, RenameState)
runRenaming nonTrivial loc saved action = do
runIdentity $
runAlmsErrorT $ withLocation loc $ do
(result, rstate, md) <-
runRWST (unR action)
Context {
env = savedEnv saved,
allocate = nonTrivial,
inExpr = False
}
RState {
rsCounter = savedCounter saved
}
let env' = savedEnv saved `mappend` envify md
return (result, RenameState env' (rsCounter rstate))
-- | Run a renaming computation
runRenamingM :: MonadAlmsError m =>
Bool -> Loc -> RenameState -> Renaming a ->
m (a, RenameState)
runRenamingM = either throwAlmsList return <$$$$> runRenaming
-- | Alias
type R a = Renaming a
instance Monoid Env where
mempty = Env M.empty M.empty M.empty M.empty M.empty M.empty
mappend (Env a1 a2 a3 a4 a5 a6) (Env b1 b2 b3 b4 b5 b6) =
Env (a1 & b1) (a2 & b2) (a3 & b3) (a4 & b4) (a5 & b5) (a6 & b6)
where a & b = M.union b a
instance Bogus Env where bogus = mempty
-- | Open a module into an environment
envify :: Module -> Env
envify = foldMap envifyItem
envifyItem :: ModItem -> Env
envifyItem (MdTycon loc l l' dcs)
= mempty { tycons = M.singleton l (l', loc, dcs) }
envifyItem (MdVar loc l l')
= mempty { vars = M.singleton l (l', loc, ()) }
envifyItem (MdDatacon loc u u')
= mempty { datacons = M.singleton u (u', loc, ()) }
envifyItem (MdModule loc u u' md)
= mempty { modules = M.singleton u (u',loc,(md,envify md)) }
envifyItem (MdSig loc u u' md)
= mempty { sigs = M.singleton u (u',loc,(md,envify md)) }
envifyItem (MdTyvar loc tv tv')
= mempty { tyvars = M.singleton (tvname tv)
(tvname tv',loc,(tvqual tv', True)) }
-- | Like 'asks', but in the 'R' monad
withContext :: (Context -> R a) -> R a
withContext = R . (ask >>=) . fmap unR
-- | Append a module to the current environment
inModule :: Module -> R a -> R a
inModule m = local (\e -> e `mappend` envify m)
-- | Run in the environment consisting of only the given module
onlyInModule :: Module -> R a -> R a
onlyInModule = local (const mempty) <$$> inModule
-- | Add the free annotation type variables in the given syntax
-- for the context of the action.
withAnnotationTVs :: HasAnnotations s Raw => s -> R a -> R a
withAnnotationTVs stx action = do
skip <- R (asks inExpr)
((), md) <- steal $
if skip
then return ()
else traverse_ bindTyvar (annotFtvSet stx)
inModule md (R (local (\e -> e { inExpr = True }) (unR action)))
-- | Hide any annotation type variables that were in scope.
hideAnnotationTVs :: R a -> R a
hideAnnotationTVs =
R . local (\e -> e { inExpr = False }) . unR .
local (\e -> e { tyvars = each <$> tyvars e })
where each (a, b, (c, _)) = (a, b, (c, False))
-- | Temporarily stop allocating unique ids
don'tAllocate :: R a -> R a
don'tAllocate = R . local (\cxt -> cxt { allocate = False }) . unR
-- | Generate an unbound name error
unbound :: (Ppr a, Bogus b) => String -> a -> R b
unbound ns a =
renameError [msg| $words:ns not in scope: $q:a |]
-- | Generate an error about a name declared twice
repeatedMsg :: Ppr a => String -> a -> String -> [Loc] -> Message V
repeatedMsg what a inwhat locs =
[msg|
$words:what $a
repeated $words:times in $words:inwhat $words:at
$ul:slocs
|]
where
times = case length locs of
0 -> ""
1 -> ""
2 -> "twice"
3 -> "thrice"
_ -> show (length locs) ++ " times"
at = if length locs > 1 then "at:" else ""
slocs = map [msg| $show:1 |] locs
-- | Generate an error about a name declared twice
repeated :: (Ppr a, Bogus b) => String -> a -> String -> [Loc] -> R b
repeated what a inwhat locs =
renameError $ repeatedMsg what [msg| $q:a |] inwhat locs
-- | Generate an error about a name declared twice
repeatedTVs :: Bogus b => [TyVar i] -> String -> R b
repeatedTVs [] _ = renameBug "repatedTVs" "got empty list"
repeatedTVs tvs@(tv:_) inwhat =
let quals = ordNub (tvqual <$> tvs)
name = tvname tv
bothQs = length quals > 1
callIt = if bothQs then [msg| `$name / '$name |] else [msg| $tv |]
msg0 = repeatedMsg "Type variable" callIt inwhat (getLoc <$> tvs)
in renameError $
if bothQs
then [msg|
$msg0
(Type variables with the same name but different
qualifiers may not appear in the same scope.)
|]
else msg0
-- | Are all keys of the list unique? If not, return the key and
-- list of two or more values with the same keys
unique :: Ord a => (b -> a) -> [b] -> Maybe (a, [b])
unique getKey = loop M.empty where
loop _ [] = Nothing
loop seen (x:xs) =
let k = getKey x
in case M.lookup k seen of
Nothing -> loop (M.insert k x seen) xs
Just x' -> Just (k, x' : x : filter ((== k) . getKey) xs)
-- | Grab the module produced by a computation, and
-- produce no module
steal :: R a -> R (a, Module)
steal = R . censor (const mempty) . listen . unR
-- | Get all the variable names, included qualified, bound in a module
getAllVariables :: Module -> [QVarId Renamed]
getAllVariables = S.toList . foldMap loop where
loop (MdVar _ _ l') = S.singleton (J [] l')
loop (MdModule _ _ u' md) = S.mapMonotonic (\(J us l) -> J (u':us) l)
(foldMap loop md)
loop _ = S.empty
-- | Look up something in an environment
envLookup :: (Ord k, Show k) =>
(Env -> M.Map k k') ->
Path (ModId Raw) k ->
Env ->
Either (Maybe (Path (ModId Renamed) (ModId Raw)))
(Path (ModId Renamed) k')
envLookup prj = loop [] where
loop ms' (J [] x) e = case M.lookup x (prj e) of
Just x' -> Right (J (reverse ms') x')
Nothing -> Left Nothing
loop ms' (J (m:ms) x) e = case M.lookup m (modules e) of
Just (m', _, (_, e')) -> loop (m':ms') (J ms x) e'
Nothing -> Left (Just (J (reverse ms') m))
-- | Look up something in the environment
getGenericFull :: (Ord k, Show k, Bogus k') =>
String -> (Env -> M.Map k k') ->
Path (ModId Raw) k -> R (Path (ModId Renamed) k')
getGenericFull what prj qx = do
e <- ask
case envLookup prj qx e of
Right qx' -> return qx'
Left Nothing -> unbound what qx
Left (Just m) -> unbound "Module" m
-- | Look up something in the environment
getGeneric :: (Ord (f Raw), Show (f Raw), Bogus i, Bogus (f Renamed)) =>
String -> (Env -> EnvMap f i) ->
Path (ModId Raw) (f Raw) -> R (Path (ModId Renamed) (f Renamed))
getGeneric = liftM (fmap (\(qx', _, _) -> qx')) <$$$> getGenericFull
-- | Look up a variable in the environment
getVar :: QVarId Raw -> R (QVarId Renamed)
getVar = getGeneric "Variable" vars
-- | Look up a data constructor in the environment
getDatacon :: QConId Raw -> R (QConId Renamed)
getDatacon = getGeneric "Data constructor" datacons
-- | Look up a type in the environment
getTycon :: QTypId Raw -> R (QTypId Renamed)
getTycon = getGeneric "Type constructor" tycons
-- | Look up a type with constructors in the environment
getTyconFull :: QTypId Raw -> R (QTypId Renamed, [ConId Raw])
getTyconFull qtid = do
J ps (tid, _, cids) <- getGenericFull "Type name" tycons qtid
return (J ps tid, cids)
-- | Look up a module in the environment
getModule :: QModId Raw -> R (QModId Renamed, Module, Env)
getModule = liftM pull . getGenericFull "Structure" modules
where
pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)
-- | Look up a module in the environment
getSig :: QSigId Raw -> R (QSigId Renamed, Module, Env)
getSig = liftM pull . getGenericFull "Signature" sigs
where
pull (J ps (qu, _, (m, e))) = (J ps qu, m, e)
-- | Look up a type variable in the environment. This is complicated,
-- because there are several possibilities.
getTyvar :: TyVar Raw -> R (TyVar Renamed)
getTyvar tv@(TV name ql _) = do
e <- asks tyvars
case M.lookup name e of
-- If the type variable isn't found in the block-structured type
-- variable environment, that is an error.
Nothing -> do
renameError [msg| Type variable $tv is not in scope. |]
--
-- If the type variable *is* found in the bound type variable
-- environment, we need to check if it's in the current scope or
-- hidden, and if it's in the current scope, whether the qualifier
-- matches. If the qualifier doesn't match or if it's hidden, that
-- is an error.
Just (name', loc', (ql', True))
| ql == ql' -> return (TV name' ql' loc')
| otherwise ->
renameError $
[msg|
Type variable $tv is not in scope.
(Type variable $1 was bound at $loc', but the same
type variable name may not occur with different qualifiers
in the same scope.)
|] (TV name' ql' loc')
--
Just (_, loc', (_, False)) -> do
renameError
[msg|
Type variable $tv is not in scope.
(It was bound at $loc', but a nested declaration
can neither see nor shadow type variables from its
parent expression.)
|]
getTyvar (TVAnti a) = $antifail
-- | Get a new name for a variable binding
bindGeneric :: (Ord ident, Show ident, Antible ident) =>
(Renamed -> ident -> ident') ->
(Loc -> ident -> ident' -> ModItem) ->
ident -> R ident'
bindGeneric ren build x = do
case prjAnti x of
Just a -> $antifail
Nothing -> return ()
new <- newRenamed
loc <- getLocation
let x' = ren new x
tell [build loc x x']
return x'
-- | Allocate a new 'Renamed' token if we're in the right mode.
newRenamed :: R Renamed
newRenamed = R $ do
doAlloc <- asks allocate
if doAlloc
then do
rstate <- get
put rstate { rsCounter = succ (rsCounter rstate) }
return (rsCounter rstate)
else do
return trivialId
-- | Get a new name for a variable binding
bindVar :: VarId Raw -> R (VarId Renamed)
bindVar = bindGeneric renId MdVar
-- | Get a new name for a variable binding
bindTycon :: TypId Raw -> [ConId Raw] -> R (TypId Renamed)
bindTycon l0 dcs = bindGeneric renId build l0
where build loc old new = MdTycon loc old new dcs
-- | Get a new name for a data constructor binding
bindDatacon :: ConId Raw -> R (ConId Renamed)
bindDatacon = bindGeneric renId MdDatacon
-- | Get a new name for a module, and bind it in the environment
bindModule :: ModId Raw -> Module -> R (ModId Renamed)
bindModule u0 md = bindGeneric renId build u0
where build loc old new = MdModule loc old new md
-- | Get a new name for a signature, and bind it in the environment
bindSig :: SigId Raw -> Module -> R (SigId Renamed)
bindSig u0 md = bindGeneric renId build u0
where build loc old new = MdSig loc old new md
-- | Add a type variable to the scope
bindTyvar :: TyVar Raw -> R (TyVar Renamed)
bindTyvar tv = do
e <- asks tyvars
case M.lookup (tvname tv) e of
Nothing -> bindGeneric renId MdTyvar tv
Just (name', loc', (ql', _)) ->
if tvqual tv == ql'
then
renameError $
[msg|
Cannot shadow type variable $tv; it is already
bound at $loc'.
|]
else
renameError $
[msg|
Cannot introduce type variable $tv, because $1 is
already bound at $loc'. The same type variable name cannot
appear in the same scope with different qualifiers.
|] (TV name' ql' loc')
-- | Map a function over a list, allowing the exports of each item
-- to be in scope for the rest
renameMapM :: (a -> R b) -> [a] -> R [b]
renameMapM _ [] = return []
renameMapM f (x:xs) = do
(x', md) <- listen (f x)
xs' <- inModule md $ renameMapM f xs
return (x':xs')
-- | Rename a program
renameProg :: Prog Raw -> R (Prog Renamed)
renameProg [prQ| $list:ds in $opt:me1 |] = do
(ds', md) <- listen $ renameDecls ds
me1' <- inModule md $ traverse renameExpr me1
return [prQ|+ $list:ds' in $opt:me1' |]
-- | Rename a list of declarations and return the environment
-- that they bind
renameDecls :: [Decl Raw] -> R [Decl Renamed]
renameDecls = renameMapM renameDecl
-- | Rename a declaration and return the environment that it binds
renameDecl :: Decl Raw -> R (Decl Renamed)
renameDecl d0 = withLocation d0 $ case d0 of
[dc| let $x = $e |] -> do
x' <- renamePatt x
e' <- renameExpr e
return [dc|+ let $x' = $e' |]
[dc| let rec $list:bns |] -> do
(bns', md) <- renameBindings bns
tell md
return [dc|+ let rec $list:bns' |]
[dc| type $tid:lhs = type $qtid:rhs |] -> do
(rhs', dcs) <- getTyconFull rhs
lhs' <- bindTycon lhs dcs
mapM_ bindDatacon dcs
return [dc|+ type $tid:lhs' = type $qtid:rhs' |]
[dc| type $list:tds |] -> do
tds' <- renameTyDecs tds
return [dc|+ type $list:tds' |]
[dc| abstype $list:ats with $list:ds end |] -> do
let bindEach [atQ| $anti:a |] = $antifail
bindEach (N _ (AbsTy _ _ [tdQ| $anti:a |])) = $antifail
bindEach (N note at) = withLocation note $ do
let l = tdName (dataOf (atdecl at))
bindTycon l []
return (l, getLoc note)
(llocs, mdT) <- listen $ mapM bindEach ats
case unique fst llocs of
Nothing -> return ()
Just (l, locs) ->
repeated "Type declaration for" l "abstype group" (snd <$> locs)
(ats', mdD) <-
steal $
inModule mdT $
forM ats $ \at -> withLocation at $ case dataOf at of
AbsTy variances qe td -> do
(Just qe', td') <- renameTyDec (Just qe) td
return (absTy variances qe' td' <<@ at)
AbsTyAnti a -> $antifail
-- Don't tell mdD upward, since we're censoring the datacons
ds' <- inModule (mdT `mappend` mdD) $ renameDecls ds
return [dc|+ abstype $list:ats' with $list:ds' end |]
[dc| module INTERNALS = $me1 |] ->
R $ local (\context -> context { allocate = False }) $ unR $ do
let u = ident "INTERNALS"
(me1', md) <- steal $ renameModExp me1
u' <- bindModule u md
return [dc|+ module $mid:u' = $me1' |]
[dc| module $mid:u = $me1 |] -> do
(me1', md) <- steal $ renameModExp me1
u' <- bindModule u md
return [dc|+ module $mid:u' = $me1' |]
[dc| module type $sid:u = $se1 |] -> do
(se1', md) <- steal $ renameSigExp se1
u' <- bindSig u md
return [dc|+ module type $sid:u' = $se1' |]
[dc| open $me1 |] -> do
me1' <- renameModExp me1
return [dc|+ open $me1' |]
[dc| local $list:ds1 with $list:ds2 end |] -> do
(ds1', md) <- steal $ renameDecls ds1
ds2' <- inModule md $ renameDecls ds2
return [dc| local $list:ds1' with $list:ds2' end |]
[dc| exception $cid:u of $opt:mt |] -> do
u' <- bindDatacon u
mt' <- traverse renameType mt
return [dc|+ exception $cid:u' of $opt:mt' |]
[dc| $anti:a |] -> $antifail
renameTyDecs :: [TyDec Raw] -> R [TyDec Renamed]
renameTyDecs tds = withLocation tds $ do
let bindEach [tdQ| $anti:a |] = $antifail
bindEach (N note td) = withLocation note $ do
bindTycon (tdName td) (tdMaybeCons td)
return (tdName td, getLoc note)
(llocs, md) <- listen $ mapM bindEach tds
case unique fst llocs of
Nothing -> return ()
Just (l, locs) ->
repeated "Type declaration for" l "type group" (snd <$> locs)
inModule md $ mapM (liftM snd . renameTyDec Nothing) tds
tdMaybeCons :: TyDec' Raw -> [ConId Raw]
tdMaybeCons TdDat { tdAlts = alts } = fst <$> alts
tdMaybeCons _ = []
renameTyDec :: Maybe (QExp Raw) -> TyDec Raw ->
R (Maybe (QExp Renamed), TyDec Renamed)
renameTyDec _ (N _ (TdAnti a)) = $antierror
renameTyDec mqe (N note (TdSyn l clauses)) = withLocation note $ do
case mqe of
Nothing -> return ()
Just _ ->
renameBug "renameTyDec" "can’t rename QExp in context of type synonym"
J [] l' <- getTycon (J [] l)
clauses' <- forM clauses $ \(ps, rhs) -> withLocation ps $ do
(ps', md) <- steal $ renameTyPats ps
rhs' <- inModule md $ renameType rhs
return (ps', rhs')
return (Nothing, tdSyn l' clauses' <<@ note)
renameTyDec mqe (N note td) = withLocation note $ do
J [] l' <- getTycon (J [] (tdName td))
let tvs = tdParams td
case unique tvname tvs of
Nothing -> return ()
Just (_, tvs') -> repeatedTVs tvs' "type parameters"
(tvs', mdTvs) <- steal $ mapM bindTyvar tvs
inModule mdTvs $ do
mqe' <- traverse renameQExp mqe
td' <- case td of
TdAbs _ _ variances gs qe -> do
qe' <- renameQExp qe
gs' <- ordNub <$> mapM getTyvar gs
return (tdAbs l' tvs' variances gs' qe')
TdSyn _ _ -> renameBug "renameTyDec" "unexpected TdSyn"
TdDat _ _ cons -> do
case unique fst cons of
Nothing -> return ()
Just (u, _) ->
repeated "Data constructor" u "type declaration" []
cons' <- forM cons $ \(u, mt) -> do
-- XXX Why trivial?
let u' = renTrivial u
tell [MdDatacon (getLoc note) u u']
mt' <- traverse renameType mt
return (u', mt')
return (tdDat l' tvs' cons')
TdAnti a -> $antifail
return (mqe', td' <<@ note)
renameModExp :: ModExp Raw -> R (ModExp Renamed)
renameModExp me0 = withLocation me0 $ case me0 of
[meQ| struct $list:ds end |] -> do
ds' <- renameDecls ds
return [meQ|+ struct $list:ds' end |]
[meQ| $qmid:qu $list:_ |] -> do
(qu', md, _) <- getModule qu
let qls = getAllVariables md
tell md
return [meQ|+ $qmid:qu' $list:qls |]
[meQ| $me1 : $se2 |] -> do
(me1', md1) <- steal $ renameModExp me1
(se2', md2) <- steal $ renameSigExp se2
onlyInModule md1 $ sealWith md2
return [meQ| $me1' : $se2' |]
[meQ| $anti:a |] -> $antifail
renameSigExp :: SigExp Raw -> R (SigExp Renamed)
renameSigExp se0 = withLocation se0 $ case se0 of
[seQ| sig $list:sgs end |] -> do
(sgs', md) <- listen $ don'tAllocate $ renameMapM renameSigItem sgs
onlyInModule mempty $ checkSigDuplicates md
return [seQ|+ sig $list:sgs' end |]
[seQ| $qsid:qu $list:_ |] -> do
(qu', md, _) <- getSig qu
let qls = getAllVariables md
tell md
return [seQ|+ $qsid:qu' $list:qls |]
[seQ| $se1 with type $list:tvs $qtid:ql = $t |] -> do
(se1', md) <- listen $ renameSigExp se1
ql' <- onlyInModule md $ getTycon ql
case unique id tvs of
Nothing -> return ()
Just (_, tvs') -> repeatedTVs tvs' "with-type"
(tvs', mdtvs) <- steal $ mapM bindTyvar tvs
t' <- inModule mdtvs $ renameType t
return [seQ|+ $se1' with type $list:tvs' $qtid:ql' = $t' |]
[seQ| $anti:a |] -> $antifail
checkSigDuplicates :: Module -> R ()
checkSigDuplicates md = case md of
[] -> return ()
md1:md2 -> do
checkItem md1
inModule [md1] $ checkSigDuplicates md2
where
checkItem item = case item of
MdTycon loc l _ _ -> mustFail loc "Type" l $ getTycon (J [] l)
MdVar loc l _ -> mustFail loc "Variable" l $ getVar (J [] l)
MdDatacon loc u _ -> mustFail loc "Constructor" u $ getDatacon (J [] u)
MdModule loc u _ _ -> mustFail loc "Structure" u $ getModule (J [] u)
MdSig loc u _ _ -> mustFail loc "Signature" u $ getSig (J [] u)
MdTyvar loc tv _ -> mustFail loc "Tyvar" tv $ getTyvar tv
mustFail loc kind which check = do
failed <- (False <$ check) `catchError` \_ -> return True
unless failed $ do
withLocation loc $
repeated kind which "signature" []
sealWith :: Module -> R ()
sealWith = mapM_ (each Nothing) where
each b moditem = case moditem of
MdTycon _ l _ _ -> do
(l', loc, cs') <- locate b "type constructor" tycons l
tell [MdTycon loc l l' cs']
MdVar _ l _ -> do
(l', loc, _) <- locate b "variable" vars l
tell [MdVar loc l l']
MdDatacon _ u _ -> do
(u', loc, _) <- locate b "data constructor" datacons u
tell [MdDatacon loc u u']
MdModule _ u _ md2 -> do
(u', loc, (md1, _)) <- locate b "module" modules u
((), md1') <- steal $ onlyInModule md1 $ mapM_ (each b) md2
tell [MdModule loc u u' md1']
MdSig _ u _ md2 -> do
(u', loc, (md1, _)) <- locate b "module type" sigs u
((), _ ) <- steal $ onlyInModule md2 $ mapM_ (each (Just (Left u))) md1
((), md1') <- steal $ onlyInModule md1 $ mapM_ (each (Just (Right u))) md2
tell [MdSig loc u u' md1']
MdTyvar _ _ _ ->
renameBug "sealWith" "signature can’t declare type variable"
locate b what prj name = do
m <- asks prj
case M.lookup name m of
Just name' -> return name'
Nothing -> renameError $
case b of
Nothing -> [msg|
In signature matching, structure is missing
$words:what $q:name,
which is present in ascribed signature.
|]
Just (Left u) -> [msg|
In exact signature matching (for nested signature $u)
found unexpected $words:what $q:name.
|]
Just (Right u) -> [msg|
In exact signature matching (for nested signature $u)
missing expected $words:what $q:name.
|]
-- | Rename a signature item and return the environment
-- that they bind
renameSigItem :: SigItem Raw -> R (SigItem Renamed)
renameSigItem sg0 = withLocation sg0 $ case sg0 of
[sgQ| val $vid:l : $t |] -> do
l' <- bindVar l
t' <- renameType (closeType t)
return [sgQ|+ val $vid:l' : $t' |]
[sgQ| type $list:tds |] -> do
tds' <- renameTyDecs tds
return [sgQ|+ type $list:tds' |]
[sgQ| type $tid:lhs = type $qtid:rhs |] -> do
(rhs', dcs) <- getTyconFull rhs
lhs' <- bindTycon lhs dcs
mapM_ bindDatacon dcs
return [sgQ|+ type $tid:lhs' = type $qtid:rhs' |]
[sgQ| module $mid:u : $se1 |] -> do
(se1', md) <- steal $ renameSigExp se1
u' <- bindModule u md
return [sgQ|+ module $mid:u' : $se1' |]
[sgQ| module type $sid:u = $se1 |] -> do
(se1', md) <- steal $ renameSigExp se1
u' <- bindSig u md
return [sgQ|+ module type $sid:u' = $se1' |]
[sgQ| include $se1 |] -> do
se1' <- renameSigExp se1
return [sgQ|+ include $se1' |]
[sgQ| exception $cid:u of $opt:mt |] -> do
u' <- bindDatacon u
mt' <- traverse renameType mt
return [sgQ|+ exception $cid:u' of $opt:mt' |]
[sgQ| $anti:a |] -> $antifail
-- | Rename an expression
renameExpr :: Expr Raw -> R (Expr Renamed)
renameExpr e00 = withAnnotationTVs e00 $ loop e00 where
loop e0 = withLocation e0 $ case e0 of
[ex| $qvid:ql |] -> do
ql' <- getVar ql
return [ex|+ $qvid:ql' |]
[ex| $lit:lit |] -> do
lit' <- renameLit lit
return [ex|+ $lit:lit' |]
[ex| $qcid:qu $opt:me |] -> do
qu' <- getDatacon qu
me' <- traverse loop me
return [ex|+ $qcid:qu' $opt:me' |]
[ex| `$uid:u $opt:me |] -> do
let u' = renTrivial u
me' <- traverse loop me
return [ex|+ `$uid:u' $opt:me' |]
[ex| #$uid:u $e |] -> do
let u' = renTrivial u
e' <- loop e
return [ex|+ #$uid:u' $e' |]
[ex| let $x = $e1 in $e2 |] -> do
(x', md) <- steal $ renamePatt x
e1' <- loop e1
e2' <- inModule md $ loop e2
return [ex| let $x' = $e1' in $e2' |]
[ex| match $e1 with $list:cas |] -> do
e1' <- loop e1
cas' <- mapM renameCaseAlt cas
return [ex|+ match $e1' with $list:cas' |]
[ex| let rec $list:bns in $e |] -> do
(bns', md) <- renameBindings bns
e' <- inModule md $ loop e
return [ex|+ let rec $list:bns' in $e' |]
[ex| let $decl:d in $e |] -> do
(d', md) <- steal . hideAnnotationTVs $ renameDecl d
e' <- inModule md (loop e)
return [ex|+ let $decl:d' in $e' |]
[ex| ($e1, $e2) |] -> do
e1' <- loop e1
e2' <- loop e2
return [ex|+ ($e1', $e2') |]
[ex| fun $x -> $e |] -> do
(x', md) <- steal $ renamePatt x
e' <- inModule md $ loop e
return [ex|+ fun $x' -> $e' |]
[ex| $e1 $e2 |] -> do
e1' <- loop e1
e2' <- loop e2
return [ex|+ $e1' $e2' |]
[ex| { $list:flds | $e2 } |] -> do
flds' <- mapM renameField flds
e2' <- loop e2
return [ex|+ { $list:flds' | $e2' } |]
[ex| {+ $list:flds | $e2 +} |] -> do
flds' <- mapM renameField flds
e2' <- loop e2
return [ex|+ {+ $list:flds' | $e2' +} |]
[ex| $e1.$uid:u |] -> do
let u' = renTrivial u
e1' <- loop e1
return [ex|+ $e1'.$uid:u' |]
[ex| ( $e : $t) |] -> do
e' <- loop e
t' <- renameType t
return [ex| ( $e' : $t' ) |]
[ex| ( $e :> $t) |] -> do
e' <- loop e
t' <- renameType t
return [ex| ( $e' :> $t' ) |]
[ex| $anti:a |] -> $antifail
-- | Rename a literal (no-op, except fails on antiquotes)
renameLit :: Lit -> R Lit
renameLit lit0 = case lit0 of
LtAnti a -> $antifail
_ -> return lit0
-- | Rename a case alternative
renameCaseAlt :: CaseAlt Raw -> R (CaseAlt Renamed)
renameCaseAlt ca0 = withLocation ca0 $ case ca0 of
[caQ| $x -> $e |] -> do
(x', md) <- steal $ renamePatt x
e' <- inModule md $ renameExpr e
return [caQ|+ $x' -> $e' |]
[caQ| #$uid:lab -> $e |] -> do
let lab' = renTrivial lab
e' <- renameExpr e
return [caQ|+ #$uid:lab' -> $e' |]
[caQ| #$uid:lab $x -> $e |] -> do
let lab' = renTrivial lab
(x', md) <- steal $ renamePatt x
e' <- inModule md $ renameExpr e
return [caQ|+ #$uid:lab' $x' -> $e' |]
[caQ| $antiC:a |] -> $antifail
-- | Rename a set of let rec bindings
renameBindings :: [Binding Raw] -> R ([Binding Renamed], Module)
renameBindings bns = withAnnotationTVs bns $ withLocation bns $ do
lxes <- forM bns $ \bn ->
case bn of
[bnQ| $vid:x = $e |] -> return (_loc, x, e)
[bnQ| $antiB:a |] -> $antifail
case unique (\(_,x,_) -> x) lxes of
Nothing -> return ()
Just (x, locs) ->
repeated "Variable binding for" x "let-rec" (sel1 <$> locs)
let bindEach rest (l,x,e) = withLocation l $ do
x' <- bindVar x
return ((l,x',e):rest)
(lxes', md) <- steal $ foldM bindEach [] lxes
bns' <- inModule md $
forM (reverse lxes') $ \(l,x',e) -> withLocation l $ do
let _loc = l
e' <- renameExpr e
return [bnQ|+ $vid:x' = $e' |]
return (bns', md)
-- | Rename a record field
renameField :: Field Raw → R (Field Renamed)
renameField [fdQ| $uid:u = $e |] = do
let u' = renTrivial u
e' ← renameExpr e
return [fdQ|+ $uid:u' = $e' |]
renameField [fdQ| $antiF:a |] = $antifail
-- | Rename a type
renameType :: Type Raw -> R (Type Renamed)
renameType t0 = withLocation t0 $ case t0 of
[ty| ($list:ts) $qtid:ql |] -> do
ql' <- getTycon ql
ts' <- mapM renameType ts
return [ty|+ ($list:ts') $qtid:ql' |]
[ty| '$tv |] -> do
tv' <- getTyvar tv
return [ty|+ '$tv' |]
[ty| $t1 -[$opt:mqe]> $t2 |] -> do
t1' <- renameType t1
mqe' <- traverse renameQExp mqe
t2' <- renameType t2
return [ty|+ $t1' -[$opt:mqe']> $t2' |]
[ty| $quant:u '$tv. $t |] -> do
(tv', md) <- steal $ bindTyvar tv
t' <- inModule md $ renameType t
return [ty|+ $quant:u '$tv'. $t' |]
[ty| mu '$tv. $t |] -> do
(tv', md) <- steal $ bindTyvar tv
t' <- inModule md $ renameType t
return [ty|+ mu '$tv'. $t' |]
[ty| `$uid:u of $t1 | $t2 |] -> do
let u' = renTrivial u
t1' <- renameType t1
t2' <- renameType t2
return [ty| `$uid:u' of $t1' | $t2' |]
[ty| $anti:a |] -> $antifail
-- | Rename a type pattern
renameTyPats :: [TyPat Raw] -> R [TyPat Renamed]
renameTyPats x00 = evalStateT (mapM loop x00) M.empty where
loop :: TyPat Raw ->
StateT (M.Map (Lid Raw) (TyVar Raw, Loc)) Renaming (TyPat Renamed)
loop x0 = withLocation x0 $ case x0 of
[tpQ| $antiP:a |] -> $antifail
N note (TpVar tv var) -> do
tv' <- tyvar (getLoc note) tv
return (tpVar tv' var <<@ note)
N note (TpRow tv var) -> do
tv' <- tyvar (getLoc note) tv
return (tpRow tv' var <<@ note)
[tpQ| ($list:tps) $qtid:ql |] -> do
ql' <- lift (withLocation _loc (getTycon ql))
tps' <- mapM loop tps
return [tpQ|+ ($list:tps') $qtid:ql' |]
--
tyvar :: Loc -> TyVar Raw ->
StateT (M.Map (Lid Raw) (TyVar Raw, Loc)) Renaming (TyVar Renamed)
tyvar loc1 tv = do
seen <- get
case M.lookup (tvname tv) seen of
Just (tv', _) ->
lift (repeatedTVs [tv,tv'] "type parameters")
Nothing -> do
put (M.insert (tvname tv) (tv, loc1) seen)
lift (bindTyvar tv)
-- | Rename a qualifier expression
renameQExp :: QExp Raw -> R (QExp Renamed)
renameQExp qe0 = withLocation qe0 $ case qe0 of
[qeQ| $qlit:qlit |] -> do
return [qeQ|+ $qlit:qlit |]
[qeQ| $qvar:tv |] -> do
tv' <- getTyvar tv
return [qeQ| $qvar:tv' |]
[qeQ| $qe1 \/ $qe2 |] -> do
qe1' <- renameQExp qe1
qe2' <- renameQExp qe2
return [qeQ| $qe1' \/ $qe2' |]
[qeQ| $anti:a |] -> do
$antifail
-- | Rename a pattern
renamePatt :: Patt Raw -> R (Patt Renamed)
renamePatt x00 = evalStateT (loop x00) M.empty where
loop :: Patt Raw ->
StateT (M.Map (VarId Raw) Loc)
Renaming (Patt Renamed)
loop x0 = withLocation x0 $ case x0 of
[pa| _ |] ->
return [pa|+ _ |]
[pa| $vid:l |] -> do
l' <- var _loc l
return [pa|+ $vid:l' |]
[pa| $qcid:qu $opt:mx |] -> do
qu' <- lift $ getDatacon qu
mx' <- traverse loop mx
return [pa|+ $qcid:qu' $opt:mx' |]
[pa| `$uid:qu $opt:mx |] -> do
let qu' = renTrivial qu
mx' <- traverse loop mx
return [pa|+ `$uid:qu' $opt:mx' |]
[pa| ($x1, $x2) |] -> do
x1' <- loop x1
x2' <- loop x2
return [pa|+ ($x1', $x2') |]
[pa| $lit:lit |] -> do
lit' <- lift $ renameLit lit
return [pa|+ $lit:lit' |]
[pa| $x as $vid:l |] -> do
x' <- loop x
l' <- var _loc l
return [pa|+ $x' as $vid:l' |]
[pa| { $uid:u = $x | $y } |] -> do
let u' = renTrivial u
x' <- loop x
y' <- loop y
return [pa|! { $uid:u' = $x' | $y' } |]
[pa| ! $x |] -> do
x' <- loop x
return [pa| ! $x' |]
[pa| $x : $t |] -> do
x' <- loop x
t' <- lift $ renameType t
return [pa| $x' : $t' |]
[pa| $anti:a |] -> do
$antifail
--
var loc1 vid = do
seen <- get
case M.lookup vid seen of
Just loc2 -> lift (repeated "Variable" vid "pattern" [loc1, loc2])
Nothing -> do
put (M.insert vid loc1 seen)
lift (withLocation loc1 (bindVar vid))
-- | Univerally-quantify all free type variables
closeType :: Type Raw -> Type Raw
closeType t = foldr tyAll t (annotFtvSet t)
addVal :: VarId Raw -> R (VarId Renamed)
addType :: TypId Raw -> Renamed -> [ConId Raw] -> R (TypId Renamed)
addMod :: ModId Raw -> R a -> R (ModId Renamed, a)
addVal = bindVar
addType l i dcs = do
let l' = renId i l
loc <- getLocation
tell [MdTycon loc l l' dcs]
return l'
addMod u body = do
let u' = renTrivial u
(a, md) <- steal body
loc <- getLocation
tell [MdModule loc u u' md]
return (u', a)
-- | Result for 'getRenamingInfo'
data RenamingInfo
= ModuleAt { renInfoLoc :: Loc, renInfoQModId :: QModId Renamed }
| SigAt { renInfoLoc :: Loc, renInfoQSigId :: QSigId Renamed }
| VariableAt { renInfoLoc :: Loc, renInfoQVarId :: QVarId Renamed }
| TyconAt { renInfoLoc :: Loc, renInfoQTypId :: QTypId Renamed }
| DataconAt { renInfoLoc :: Loc, renInfoQConId :: QConId Renamed }
deriving Show
-- | For the REPL to find out where identifiers are bound and their
-- renamed name for looking up type info
getRenamingInfo :: Ident Raw -> RenameState -> [RenamingInfo]
getRenamingInfo name RenameState { savedEnv = e } =
catMaybes $ case view name of
Left ql -> [ look tycons (TypId <$> ql) TyconAt,
look vars (VarId <$> ql) VariableAt ]
Right qu -> [ look sigs (SigId <$> qu) SigAt,
look modules (ModId <$> qu) ModuleAt,
look datacons (ConId <$> qu) DataconAt ]
where
look prj qx build = case envLookup prj qx e of
Left _ -> Nothing
Right (J ps (x', loc, _)) -> Just (build loc (J ps x'))
-- Open the given module, if it exists.
renamingEnterScope :: ModId i -> RenameState -> RenameState
renamingEnterScope u r =
let e = savedEnv r in
case M.lookup (renTrivial u) (modules e) of
Nothing -> r
Just (_, _, (_, e'))
-> r { savedEnv = e `mappend` e' }
-- | Test runner for renaming an expression
re :: Expr Raw -> Either [AlmsError] (Expr Renamed)
re e = fst <$> runRenaming True bogus renameState0 (renameExpr e)
-- | Test runner for renaming an declaration
rd :: Decl Raw -> Either [AlmsError] (Decl Renamed)
rd d = fst <$> runRenaming True bogus renameState0 (renameDecl d)
_loc :: Loc
_loc = initial ""