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 ""