{-# LANGUAGE FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, QuasiQuotes, RankNTypes, RelaxedPolyRec, TemplateHaskell, TypeSynonymInstances #-} module 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, -- * REPL query getRenamingInfo, RenamingInfo(..), ) where import ErrorMessage import Meta.Quasi import Syntax hiding ((&)) import qualified Loc import qualified Syntax.Decl import qualified Syntax.Expr import qualified Syntax.Notable import qualified Syntax.Patt import Util import qualified Data.List as List import Data.Monoid import qualified Data.Map as M import qualified Data.Set as S import Control.Monad.RWS as RWST import qualified Control.Monad.State as M.S import Control.Monad.Error as M.E -- | 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 (uid "()") (uid "()", mkBogus "built-in", ()) }, savedCounter = renamed0 } -- | Generate a renamer error. renameError :: MessageV -> R a renameError msg0 = do loc <- R (asks location) throwAlms (AlmsException RenamerPhase loc msg0) renameBug :: String -> String -> R a renameBug culprit msg0 = do loc <- R (asks location) throwAlms (almsBug RenamerPhase loc 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 Renamed (Either AlmsException) a } deriving Functor instance Monad Renaming where return = R . return m >>= k = R (unR m >>= unR . k) fail = renameError . [$msg| $words:1 |] 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 AlmsException Renaming where throwError = R . throwError catchError body handler = R (catchError (unR body) (unR . handler)) instance AlmsMonad Renaming where throwAlms = throwError catchAlms = catchError -- | The renaming environment data Env = Env { tycons, vars :: !(EnvMap Lid ()), datacons :: !(EnvMap Uid ()), modules, sigs :: !(EnvMap Uid (Module, Env)), tyvars :: !(EnvMap TyVar 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. data Module = MdNil | MdApp !Module !Module | MdTycon !Loc !(Lid Raw) !(Lid Renamed) | MdVar !Loc !(Lid Raw) !(Lid Renamed) | MdDatacon !Loc !(Uid Raw) !(Uid Renamed) | MdModule !Loc !(Uid Raw) !(Uid Renamed) !Module | MdSig !Loc !(Uid Raw) !(Uid 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, location :: !Loc } -- | Run a renaming computation runRenaming :: Bool -> Loc -> RenameState -> Renaming a -> Either AlmsException (a, RenameState) runRenaming nonTrivial loc saved action = do (result, counter, md) <- runRWST (unR action) Context { env = savedEnv saved, allocate = nonTrivial, location = loc } (savedCounter saved) let env' = savedEnv saved `mappend` envify md return (result, RenameState env' counter) -- | Run a renaming computation runRenamingM :: AlmsMonad m => Bool -> Loc -> RenameState -> Renaming a -> m (a, RenameState) runRenamingM = unTryAlms . 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 Monoid Module where mempty = MdNil mappend = MdApp -- | Open a module into an environment envify :: Module -> Env envify MdNil = mempty envify (MdApp md1 md2) = envify md1 `mappend` envify md2 envify (MdTycon loc l l') = mempty { tycons = M.singleton l (l', loc, ()) } envify (MdVar loc l l') = mempty { vars = M.singleton l (l', loc, ()) } envify (MdDatacon loc u u') = mempty { datacons = M.singleton u (u', loc, ()) } envify (MdModule loc u u' md) = mempty { modules = M.singleton u (u',loc,(md,envify md)) } envify (MdSig loc u u' md) = mempty { sigs = M.singleton u (u',loc,(md,envify md)) } envify (MdTyvar loc tv tv') = mempty { tyvars = M.singleton tv (tv',loc,True) } -- | Like 'asks', but in the 'R' monad withContext :: (Context -> R a) -> R a withContext = R . (ask >>=) . fmap unR -- | Run in the context of a given source location withLoc :: Locatable loc => loc -> R a -> R a withLoc loc = R . local (\cxt -> cxt { location = location cxt <<@ loc }) . 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 -- | 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 :: Show a => String -> a -> R b unbound ns a = renameError [$msg| $words:ns not in scope: $show:a. |] -- | Generate an error about a name declared twice repeated :: Show a => String -> a -> String -> [Loc] -> R b repeated what a inwhat locs = renameError [$msg| $words:what $show: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 -- | Are all keys of the list unique? If not, return a pair of -- values unique :: Ord a => (b -> a) -> [b] -> Maybe (b, 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 (x', x) -- | 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 -> [QLid Renamed] getAllVariables = S.toList . loop where loop (MdApp md1 md2) = loop md1 `S.union` loop md2 loop (MdVar _ _ l') = S.singleton (J [] l') loop (MdModule _ _ u' md) = S.mapMonotonic (\(J us l) -> J (u':us) l) (loop md) loop _ = S.empty -- | Temporarily hide the type variables in scope, and pass the -- continuation a function to bring them back hideTyvars :: R a -> R a hideTyvars = local (\e -> e { tyvars = M.map each (tyvars e) }) where each (tv, loc, _) = (tv, loc, False) -- | Look up something in an environment envLookup :: (Ord k, Show k) => (Env -> M.Map k k') -> Path (Uid Raw) k -> Env -> Either (Maybe (Path (Uid Renamed) (Uid Raw))) (Path (Uid 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) => String -> (Env -> M.Map k k') -> Path (Uid Raw) k -> R (Path (Uid 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)) => String -> (Env -> EnvMap f i) -> Path (Uid Raw) (f Raw) -> R (Path (Uid Renamed) (f Renamed)) getGeneric = liftM (fmap (\(qx', _, _) -> qx')) <$$$> getGenericFull -- | Look up a variable in the environment getVar :: QLid Raw -> R (QLid Renamed) getVar = getGeneric "Variable" vars -- | Look up a data constructor in the environment getDatacon :: QUid Raw -> R (QUid Renamed) getDatacon = getGeneric "Data constructor" datacons -- | Look up a variable in the environment getTycon :: QLid Raw -> R (QLid Renamed) getTycon = getGeneric "Type constructor" tycons -- | Look up a module in the environment getModule :: QUid Raw -> R (QUid 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 :: QUid Raw -> R (QUid Renamed, Module, Env) getSig = liftM pull . getGenericFull "Signature" sigs where pull (J ps (qu, _, (m, e))) = (J ps qu, m, e) -- | Look up a variable in the environment getTyvar :: TyVar Raw -> R (TyVar Renamed) getTyvar tv = do e <- asks tyvars case M.lookup tv e of Nothing -> unbound "Type variable" tv Just (tv', _, True) -> return tv' Just (_, loc, False) -> renameError [$msg| Type variable $show:tv not in scope. (It was bound at $show:loc, but a nested declaration cannot see type variables from its parent expression.) |] -- | Get a new name for a variable binding bindGeneric :: (Ord ident, Show ident, Antible ident) => (Renamed -> ident -> ident') -> (Loc -> ident -> ident' -> Module) -> ident -> R ident' bindGeneric ren build x = R $ do case prjAnti x of Just a -> $antifail Nothing -> return () doAlloc <- asks allocate x' <- if doAlloc then do counter <- get put (succ counter) return (ren counter x) else do return (ren trivialId x) loc <- asks location tell (build loc x x') return x' -- | Get a new name for a variable binding bindVar :: Lid Raw -> R (Lid Renamed) bindVar = bindGeneric (\r -> Lid r . unLid) MdVar -- | Get a new name for a variable binding bindTycon :: Lid Raw -> R (Lid Renamed) bindTycon = bindGeneric (\r -> Lid r . unLid) MdTycon -- | Get a new name for a data constructor binding bindDatacon :: Uid Raw -> R (Uid Renamed) bindDatacon = bindGeneric (\r -> Uid r . unUid) MdDatacon -- | Get a new name for a module, and bind it in the environment bindModule :: Uid Raw -> Module -> R (Uid Renamed) bindModule u0 md = bindGeneric (\r -> Uid r . unUid) 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 :: Uid Raw -> Module -> R (Uid Renamed) bindSig u0 md = bindGeneric (\r -> Uid r . unUid) 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 = bindGeneric (\r (TV l q) -> TV (Lid r (unLid l)) q) MdTyvar -- | 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 $ gmapM 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 = withLoc d0 $ case d0 of [$dc| let $x : $opt:mt = $e |] -> do x' <- renamePatt x mt' <- gmapM renameType (fmap closeType mt) e' <- renameExpr (closeExpr e) return [$dc|+ let $x' : $opt:mt' = $e' |] [$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) = withLoc 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, loc1), (_, loc2)) -> repeated "Type" l "abstype group" [loc1, loc2] (ats', mdD) <- steal $ inModule mdT $ forM ats $ \at -> withLoc 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 = uid "INTERNALS" (me1', md) <- steal $ renameModExp me1 u' <- bindModule u md return [$dc|+ module $uid:u' = $me1' |] [$dc| module $uid:u = $me1 |] -> do (me1', md) <- steal $ renameModExp me1 u' <- bindModule u md return [$dc|+ module $uid:u' = $me1' |] [$dc| module type $uid:u = $se1 |] -> do (se1', md) <- steal $ renameSigExp se1 u' <- bindSig u md return [$dc|+ module type $uid: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 $uid:u of $opt:mt |] -> do u' <- bindDatacon u mt' <- gmapM renameType mt return [$dc|+ exception $uid:u' of $opt:mt' |] [$dc| $anti:a |] -> $antifail renameTyDecs :: [TyDec Raw] -> R [TyDec Renamed] renameTyDecs tds = do let bindEach [$tdQ| $anti:a |] = $antifail bindEach (N note td) = withLoc note $ do bindTycon (tdName td) return (tdName td, getLoc note) (llocs, md) <- listen $ mapM bindEach tds case unique fst llocs of Nothing -> return () Just ((l, loc1), (_, loc2)) -> repeated "Type" l "type group" [loc1, loc2] inModule md $ mapM (liftM snd . renameTyDec Nothing) tds renameTyDec :: Maybe (QExp Raw) -> TyDec Raw -> R (Maybe (QExp Renamed), TyDec Renamed) renameTyDec _ (N _ (TdAnti a)) = $antierror renameTyDec mqe (N note (TdSyn l clauses)) = withLoc 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) -> withLoc 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) = withLoc note $ do J [] l' <- getTycon (J [] (tdName td)) let tvs = tdParams td case unique id tvs of Nothing -> return () Just (tv, _) -> repeated "Type variable" tv "type parameters" [] (tvs', mdTvs) <- steal $ mapM bindTyvar tvs inModule mdTvs $ do mqe' <- gmapM renameQExp mqe td' <- case td of TdAbs _ _ variances qe -> do qe' <- renameQExp qe return (tdAbs l' tvs' variances 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) -> withLoc mt $ do let u' = uid (unUid u) tell (MdDatacon (getLoc mt) u u') mt' <- gmapM 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 = withLoc me0 $ case me0 of [$me| struct $list:ds end |] -> do ds' <- renameDecls ds return [$me|+ struct $list:ds' end |] [$me| $quid:qu $list:_ |] -> do (qu', md, _) <- getModule qu let qls = getAllVariables md tell md return [$me|+ $quid:qu' $list:qls |] [$me| $me1 : $se2 |] -> do (me1', md1) <- steal $ renameModExp me1 (se2', md2) <- steal $ renameSigExp se2 onlyInModule md1 $ sealWith md2 return [$me| $me1' : $se2' |] [$me| $anti:a |] -> $antifail renameSigExp :: SigExp Raw -> R (SigExp Renamed) renameSigExp se0 = withLoc 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| $quid:qu $list:_ |] -> do (qu', md, _) <- getSig qu let qls = getAllVariables md tell md return [$seQ|+ $quid:qu' $list:qls |] [$seQ| $se1 with type $list:tvs $qlid:ql = $t |] -> do (se1', md) <- listen $ renameSigExp se1 ql' <- onlyInModule md $ getTycon ql case unique id tvs of Nothing -> return () Just (tv, _) -> repeated "Type variable" tv "with-type" [] (tvs', mdtvs) <- steal $ mapM bindTyvar tvs t' <- inModule mdtvs $ renameType t return [$seQ|+ $se1' with type $list:tvs' $qlid:ql' = $t' |] [$seQ| $anti:a |] -> $antifail checkSigDuplicates :: Module -> R () checkSigDuplicates md = case md of MdNil -> return () MdApp md1 md2 -> do checkSigDuplicates md1 inModule md1 $ checkSigDuplicates md2 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 where mustFail loc kind which check = do failed <- (False <$ check) `M.E.catchError` \_ -> return True unless failed $ do withLoc loc $ repeated kind which "signature" [] sealWith :: Module -> R () sealWith md = case md of MdNil -> return () MdApp md1 md2 -> do sealWith md1; sealWith md2 MdTycon _ l _ -> do (l', loc, _) <- find "type constructor" tycons l tell (MdTycon loc l l') MdVar _ l _ -> do (l', loc, _) <- find "variable" vars l tell (MdVar loc l l') MdDatacon _ u _ -> do (u', loc, _) <- find "data constructor" datacons u tell (MdDatacon loc u u') MdModule _ u _ md2 -> do (u', loc, (md1, _)) <- find "module" modules u ((), md1') <- steal $ onlyInModule md1 $ sealWith md2 tell (MdModule loc u u' md1') MdSig _ u _ md2 -> do (u', loc, (md1, _)) <- find "module type" sigs u let ctch body = body `catchError` \_ -> renameError [$msg| In signature matching, signature $qshow:u does not match exactly. |] ((), _ ) <- ctch $ steal $ onlyInModule md2 $ sealWith md1 ((), md1') <- ctch $ steal $ onlyInModule md1 $ sealWith md2 tell (MdSig loc u u' md1') MdTyvar _ _ _ -> renameBug "sealWith" "signature can’t declare type variable" where find what prj ident = do m <- asks prj case M.lookup ident m of Just ident' -> return ident' Nothing -> renameError $ [$msg| In signature matching, structure is missing $words:what $qshow:ident, which is present in ascribed signature. |] -- | Rename a signature item and return the environment -- that they bind renameSigItem :: SigItem Raw -> R (SigItem Renamed) renameSigItem sg0 = case sg0 of [$sgQ| val $lid:l : $t |] -> do l' <- bindVar l t' <- renameType (closeType t) return [$sgQ|+ val $lid:l' : $t' |] [$sgQ| type $list:tds |] -> do tds' <- renameTyDecs tds return [$sgQ|+ type $list:tds' |] [$sgQ| module $uid:u : $se1 |] -> do (se1', md) <- steal $ renameSigExp se1 u' <- bindModule u md return [$sgQ|+ module $uid:u' : $se1' |] [$sgQ| module type $uid:u = $se1 |] -> do (se1', md) <- steal $ renameSigExp se1 u' <- bindSig u md return [$sgQ|+ module type $uid:u' = $se1' |] [$sgQ| include $se1 |] -> do se1' <- renameSigExp se1 return [$sgQ|+ include $se1' |] [$sgQ| exception $uid:u of $opt:mt |] -> do u' <- bindDatacon u mt' <- gmapM renameType mt return [$sgQ|+ exception $uid:u' of $opt:mt' |] [$sgQ| $anti:a |] -> $antifail -- | Rename an expression renameExpr :: Expr Raw -> R (Expr Renamed) renameExpr e0 = withLoc e0 $ case e0 of [$ex| $id:x |] -> case view x of Left ql -> do ql' <- getVar ql let x' = fmap Var ql' return [$ex|+ $id:x' |] Right qu -> do qu' <- getDatacon qu let x' = fmap Con qu' return [$ex|+ $id:x' |] [$ex| $lit:lit |] -> do lit' <- renameLit lit return [$ex|+ $lit:lit' |] [$ex| match $e1 with $list:cas |] -> do e1' <- renameExpr 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 $ renameExpr e return [$ex|+ let rec $list:bns' in $e' |] [$ex| let $decl:d in $e |] -> do (d', md) <- steal $ hideTyvars $ renameDecl d e' <- inModule md (renameExpr e) return [$ex|+ let $decl:d' in $e' |] [$ex| ($e1, $e2) |] -> do e1' <- renameExpr e1 e2' <- renameExpr e2 return [$ex|+ ($e1', $e2') |] [$ex| fun $x : $t -> $e |] -> do t' <- renameType t (x', md) <- steal $ renamePatt x e' <- inModule md $ renameExpr e return [$ex|+ fun $x' : $t' -> $e' |] [$ex| $e1 $e2 |] -> do e1' <- renameExpr e1 e2' <- renameExpr e2 return [$ex|+ $e1' $e2' |] [$ex| fun '$tv -> $e |] -> do (tv', md) <- steal $ bindTyvar tv e' <- inModule md $ renameExpr e return [$ex|+ fun '$tv' -> $e' |] [$ex| $e [$t] |] -> do e' <- renameExpr e t' <- renameType t return [$ex|+ $e' [$t'] |] [$ex| Pack[$opt:mt]($t, $e) |] -> do mt' <- gmapM renameType mt t' <- renameType t e' <- renameExpr e return [$ex|+ Pack[$opt:mt']($t', $e') |] [$ex| ( $e : $t) |] -> do e' <- renameExpr e t' <- renameType t return [$ex| ( $e' : $t' ) |] [$ex| ( $e :> $t) |] -> do e' <- renameExpr 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 = withLoc ca0 $ case ca0 of [$caQ| $x -> $e |] -> do (x', md) <- steal $ renamePatt x e' <- inModule md $ renameExpr e return [$caQ|+ $x' -> $e' |] [$caQ| $antiC:a |] -> $antifail -- | Rename a set of let rec bindings renameBindings :: [Binding Raw] -> R ([Binding Renamed], Module) renameBindings bns = do lxtes <- forM bns $ \bn -> case bn of [$bnQ| $lid:x : $t = $e |] -> return (_loc, x, t, e) [$bnQ| $antiB:a |] -> $antifail case unique (\(_,x,_,_) -> x) lxtes of Nothing -> return () Just ((l1,x,_,_),(l2,_,_,_)) -> repeated "Variable" x "let-rec" [l1, l2] let bindEach rest (l,x,t,e) = withLoc l $ do x' <- bindVar x return ((l,x',t,e):rest) (lxtes', md) <- steal $ foldM bindEach [] lxtes bns' <- inModule md $ forM (reverse lxtes') $ \(l,x',t,e) -> withLoc l $ do let _loc = l t' <- renameType t e' <- renameExpr e return [$bnQ|+ $lid:x' : $t' = $e' |] return (bns', md) -- | Rename a type renameType :: Type Raw -> R (Type Renamed) renameType t0 = case t0 of [$ty| ($list:ts) $qlid:ql |] -> do ql' <- getTycon ql ts' <- mapM renameType ts return [$ty|+ ($list:ts') $qlid:ql' |] [$ty| '$tv |] -> do tv' <- getTyvar tv return [$ty|+ '$tv' |] [$ty| $t1 -[$qe]> $t2 |] -> do t1' <- renameType t1 qe' <- renameQExp qe t2' <- renameType t2 return [$ty|+ $t1' -[$qe']> $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| $anti:a |] -> $antifail -- | Rename a type pattern renameTyPats :: [TyPat Raw] -> R [TyPat Renamed] renameTyPats x00 = withLoc x00 $ M.S.evalStateT (mapM loop x00) M.empty where loop :: TyPat Raw -> M.S.StateT (M.Map (TyVar Raw) Loc) Renaming (TyPat Renamed) loop x0 = case x0 of [$tpQ| $antiP:a |] -> $antifail N note (TpVar tv var) -> do tv' <- tyvar (getLoc note) tv return (tpVar tv' var <<@ note) [$tpQ| ($list:tps) $qlid:ql |] -> do ql' <- lift (withLoc _loc (getTycon ql)) tps' <- mapM loop tps return [$tpQ|+ ($list:tps') $qlid:ql' |] -- tyvar :: Loc -> TyVar Raw -> M.S.StateT (M.Map (TyVar Raw) Loc) Renaming (TyVar Renamed) tyvar loc1 tv = do seen <- get case M.lookup tv seen of Just loc2 -> lift (repeated "Type variable" tv "type pattern" [loc1, loc2]) Nothing -> do put (M.insert tv loc1 seen) lift (bindTyvar tv) -- | Rename a qualifier expression renameQExp :: QExp Raw -> R (QExp Renamed) renameQExp qe0 = case qe0 of [$qeQ| $qlit:qlit |] -> do return [$qeQ|+ $qlit:qlit |] [$qeQ| $qvar:tv |] -> do tv' <- getTyvar tv return [$qeQ| $qvar:tv' |] [$qeQ| $qdisj:qes |] -> do qes' <- mapM renameQExp qes return [$qeQ| $qdisj:qes' |] [$qeQ| $qconj:qes |] -> do qes' <- mapM renameQExp qes return [$qeQ| $qconj:qes' |] [$qeQ| $anti:a |] -> do $antifail -- | Rename a pattern renamePatt :: Patt Raw -> R (Patt Renamed) renamePatt x00 = withLoc x00 $ M.S.evalStateT (loop x00) M.empty where loop :: Patt Raw -> M.S.StateT (M.Map (Either (Lid Raw) (TyVar Raw)) Loc) Renaming (Patt Renamed) loop x0 = case x0 of [$pa| _ |] -> return [$pa|+ _ |] [$pa| $lid:l |] -> do l' <- var _loc l return [$pa|+ $lid:l' |] [$pa| $quid:qu |] -> do qu' <- lift $ getDatacon qu return [$pa|+ $quid:qu' |] [$pa| $quid:qu $x |] -> do qu' <- lift $ getDatacon qu x' <- loop x return [$pa|+ $quid:qu' $x' |] [$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 $lid:l |] -> do x' <- loop x l' <- var _loc l return [$pa|+ $x' as $lid:l' |] [$pa| Pack('$tv, $x) |] -> do tv' <- tyvar _loc tv x' <- loop x return [$pa|+ Pack('$tv', $x') |] [$pa| $anti:a |] -> do $antifail -- var loc1 l = do seen <- get case M.lookup (Left l) seen of Just loc2 -> lift (repeated "Variable" l "pattern" [loc1, loc2]) Nothing -> do put (M.insert (Left l) loc1 seen) lift (withLoc loc1 (bindVar l)) -- tyvar loc1 tv = do seen <- get case M.lookup (Right tv) seen of Just loc2 -> lift (repeated "Type variable" tv "pattern" [loc1, loc2]) Nothing -> do put (M.insert (Right tv) loc1 seen) lift (bindTyvar tv) -- | Univerally-quantify all free type variables closeType :: Type Raw -> Type Raw closeType t = foldr tyAll t (ftvList t) -- | Add type abstractions for free type variables in -- function arguments closeExpr :: Expr Raw -> Expr Raw closeExpr e = foldr exTAbs e (ftvList e) class FtvList a where ftvList :: a -> [TyVar Raw] instance FtvList a => FtvList [a] where ftvList = foldr List.union [] . map ftvList instance FtvList a => FtvList (Maybe a) where ftvList = maybe [] ftvList -- | Get the free type variables in a QExp, in order of appearance instance FtvList (QExp Raw) where ftvList qe0 = case qe0 of [$qeQ| $qlit:_ |] -> [] [$qeQ| '$tv |] -> [tv] [$qeQ| $qdisj:qes |] -> ftvList qes [$qeQ| $qconj:qes |] -> ftvList qes [$qeQ| $anti:a |] -> $antierror -- | Get the free type variables in a type, in order of appearance instance FtvList (Type Raw) where ftvList t0 = case t0 of [$ty| ($list:ts) $qlid:_ |] -> ftvList ts [$ty| '$tv |] -> [tv] [$ty| $t1 -[$qe]> $t2 |] -> ftvList t1 `List.union` ftvList qe `List.union` ftvList t2 [$ty| $quant:_ '$tv. $t |] -> List.delete tv (ftvList t) [$ty| mu '$tv. $t |] -> List.delete tv (ftvList t) [$ty| $anti:a |] -> $antierror instance FtvList (Expr Raw) where ftvList e0 = case e0 of [$ex| fun ($_ : $t) -> $e |] -> ftvList t `List.union` ftvList e [$ex| fun '$tv -> $e |] -> List.delete tv (ftvList e) _ -> [] addVal :: Lid Raw -> R (Lid Renamed) addType :: Lid Raw -> Renamed -> R (Lid Renamed) addMod :: Uid Raw -> R a -> R (Uid Renamed, a) addVal = bindVar addType l i = do let l' = Lid i (unLid l) loc <- R $ asks location tell (MdTycon loc l l') return l' addMod u body = do let u' = uid (unUid u) (a, md) <- steal body loc <- R $ asks location tell (MdModule loc u u' md) return (u', a) -- | Result for 'getRenamingInfo' data RenamingInfo = ModuleAt { renInfoLoc :: Loc, renInfoQUid :: QUid Renamed } | SigAt { renInfoLoc :: Loc, renInfoQUid :: QUid Renamed } | VariableAt { renInfoLoc :: Loc, renInfoQLid :: QLid Renamed } | TyconAt { renInfoLoc :: Loc, renInfoQLid :: QLid Renamed } | DataconAt { renInfoLoc :: Loc, renInfoQUid :: QUid 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 ident RenameState { savedEnv = e } = catMaybes $ case view ident of Left ql -> [ look tycons ql TyconAt, look vars ql VariableAt ] Right qu -> [ look sigs qu SigAt, look modules qu ModuleAt, look datacons 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'))