module GHC.Tc.Gen.Splice(
tcSpliceExpr, tcTypedBracket, tcUntypedBracket,
runAnnotation,
runMetaE, runMetaP, runMetaT, runMetaD, runQuasi,
tcTopSpliceExpr, lookupThName_maybe,
defaultRunMeta, runMeta', runRemoteModFinalizers,
finishTH, runTopSplice
) where
#include "HsVersions.h"
import GHC.Prelude
import GHC.Driver.Plugins
import GHC.Driver.Main
import GHC.Driver.Session
import GHC.Driver.Env
import GHC.Driver.Hooks
import GHC.Hs
import GHC.Tc.Utils.Monad
import GHC.Tc.Utils.TcType
import GHC.Tc.Gen.Expr
import GHC.Tc.Utils.Unify
import GHC.Tc.Utils.Env
import GHC.Tc.Types.Origin
import GHC.Tc.Types.Evidence
import GHC.Tc.Utils.Zonk
import GHC.Tc.Solver
import GHC.Tc.Utils.TcMType
import GHC.Tc.Gen.HsType
import GHC.Tc.Instance.Family
import GHC.Tc.Utils.Instantiate
import GHC.Core.Multiplicity
import GHC.Core.Coercion( etaExpandCoAxBranch )
import GHC.Core.Type as Type
import GHC.Core.TyCo.Rep as TyCoRep
import GHC.Core.FamInstEnv
import GHC.Core.InstEnv as InstEnv
import GHC.Builtin.Names.TH
import GHC.Builtin.Names
import GHC.Builtin.Types
import GHC.ThToHs
import GHC.HsToCore.Docs
import GHC.HsToCore.Expr
import GHC.HsToCore.Monad
import GHC.IfaceToCore
import GHC.Iface.Load
import GHCi.Message
import GHCi.RemoteTypes
import GHC.Runtime.Interpreter
import GHC.Rename.Splice( traceSplice, SpliceInfo(..))
import GHC.Rename.Expr
import GHC.Rename.Env
import GHC.Rename.Utils ( HsDocContext(..) )
import GHC.Rename.Fixity ( lookupFixityRn_help )
import GHC.Rename.HsType
import GHC.Core.Class
import GHC.Core.TyCon
import GHC.Core.Coercion.Axiom
import GHC.Core.PatSyn
import GHC.Core.ConLike
import GHC.Core.DataCon as DataCon
import GHC.Types.FieldLabel
import GHC.Types.SrcLoc
import GHC.Types.Name.Env
import GHC.Types.Name.Set
import GHC.Types.Name.Reader
import GHC.Types.Name.Occurrence as OccName
import GHC.Types.Var
import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Types.Unique
import GHC.Types.Var.Set
import GHC.Types.Meta
import GHC.Types.Basic hiding( SuccessFlag(..) )
import GHC.Types.Error
import GHC.Types.Fixity as Hs
import GHC.Types.Annotations
import GHC.Types.Name
import GHC.Serialized
import GHC.Unit.Finder
import GHC.Unit.Module
import GHC.Unit.Module.ModIface
import GHC.Unit.Module.Deps
import GHC.Utils.Misc
import GHC.Utils.Panic as Panic
import GHC.Utils.Lexeme
import GHC.Utils.Outputable
import GHC.Utils.Logger
import GHC.Utils.TmpFs ( newTempName, TempFileLifetime(..) )
import GHC.Data.FastString
import GHC.Data.Maybe( MaybeErr(..) )
import qualified GHC.Data.EnumSet as EnumSet
import qualified Language.Haskell.TH as TH
import qualified Language.Haskell.TH.Syntax as TH
#if defined(HAVE_INTERNAL_INTERPRETER)
import GHC.Desugar ( AnnotationWrapper(..) )
import Unsafe.Coerce ( unsafeCoerce )
#endif
import Control.Monad
import Control.Exception
import Data.Binary
import Data.Binary.Get
import Data.List ( find )
import Data.Maybe
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB
import Data.Dynamic ( fromDynamic, toDyn )
import qualified Data.IntMap as IntMap
import qualified Data.Map as Map
import Data.Typeable ( typeOf, Typeable, TypeRep, typeRep )
import Data.Data (Data)
import Data.Proxy ( Proxy (..) )
tcTypedBracket :: HsExpr GhcRn -> HsBracket GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
tcUntypedBracket :: HsExpr GhcRn -> HsBracket GhcRn -> [PendingRnSplice] -> ExpRhoType
-> TcM (HsExpr GhcTc)
tcSpliceExpr :: HsSplice GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
runAnnotation :: CoreAnnTarget -> LHsExpr GhcRn -> TcM Annotation
tcTypedBracket rn_expr brack@(TExpBr _ expr) res_ty
= addErrCtxt (quotationCtxtDoc brack) $
do { cur_stage <- getStage
; ps_ref <- newMutVar []
; lie_var <- getConstraintVar
; m_var <- mkTyVarTy <$> mkMetaTyVar
; ev_var <- emitQuoteWanted m_var
; let wrapper = QuoteWrapper ev_var m_var
; (_tc_expr, expr_ty) <- setStage (Brack cur_stage (TcPending ps_ref lie_var wrapper)) $
tcScalingUsage Many $
tcInferRhoNC expr
; let rep = getRuntimeRep expr_ty
; meta_ty <- tcTExpTy m_var expr_ty
; ps' <- readMutVar ps_ref
; texpco <- tcLookupId unsafeCodeCoerceName
; tcWrapResultO (Shouldn'tHappenOrigin "TExpBr")
rn_expr
(unLoc (mkHsApp (mkLHsWrap (applyQuoteWrapper wrapper)
(nlHsTyApp texpco [rep, expr_ty]))
(noLocA (HsTcBracketOut noExtField (Just wrapper) brack ps'))))
meta_ty res_ty }
tcTypedBracket _ other_brack _
= pprPanic "tcTypedBracket" (ppr other_brack)
tcUntypedBracket rn_expr brack ps res_ty
= do { traceTc "tc_bracket untyped" (ppr brack $$ ppr ps)
; (brack_info, expected_type) <- brackTy brack
; ps' <- case quoteWrapperTyVarTy <$> brack_info of
Just m_var -> mapM (tcPendingSplice m_var) ps
Nothing -> ASSERT(null ps) return []
; traceTc "tc_bracket done untyped" (ppr expected_type)
; tcWrapResultO BracketOrigin rn_expr
(HsTcBracketOut noExtField brack_info brack ps')
expected_type res_ty
}
mkMetaTyVar :: TcM TyVar
mkMetaTyVar =
newNamedFlexiTyVar (fsLit "m") (mkVisFunTyMany liftedTypeKind liftedTypeKind)
emitQuoteWanted :: Type -> TcM EvVar
emitQuoteWanted m_var = do
quote_con <- tcLookupTyCon quoteClassName
emitWantedEvVar BracketOrigin $
mkTyConApp quote_con [m_var]
brackTy :: HsBracket GhcRn -> TcM (Maybe QuoteWrapper, Type)
brackTy b =
let mkTy n = do
m_var <- mkTyVarTy <$> mkMetaTyVar
ev_var <- emitQuoteWanted m_var
final_ty <- mkAppTy m_var <$> tcMetaTy n
let wrapper = QuoteWrapper ev_var m_var
return (Just wrapper, final_ty)
in
case b of
(VarBr {}) -> (Nothing,) <$> tcMetaTy nameTyConName
(ExpBr {}) -> mkTy expTyConName
(TypBr {}) -> mkTy typeTyConName
(DecBrG {}) -> mkTy decsTyConName
(PatBr {}) -> mkTy patTyConName
(DecBrL {}) -> panic "tcBrackTy: Unexpected DecBrL"
(TExpBr {}) -> panic "tcUntypedBracket: Unexpected TExpBr"
tcPendingSplice :: TcType
-> PendingRnSplice
-> TcM PendingTcSplice
tcPendingSplice m_var (PendingRnSplice flavour splice_name expr)
= do { meta_ty <- tcMetaTy meta_ty_name
; let expected_type = mkAppTy m_var meta_ty
; expr' <- tcScalingUsage Many $ tcCheckPolyExpr expr expected_type
; return (PendingTcSplice splice_name expr') }
where
meta_ty_name = case flavour of
UntypedExpSplice -> expTyConName
UntypedPatSplice -> patTyConName
UntypedTypeSplice -> typeTyConName
UntypedDeclSplice -> decsTyConName
tcTExpTy :: TcType -> TcType -> TcM TcType
tcTExpTy m_ty exp_ty
= do { unless (isTauTy exp_ty) $ addErr (err_msg exp_ty)
; codeCon <- tcLookupTyCon codeTyConName
; let rep = getRuntimeRep exp_ty
; return (mkTyConApp codeCon [rep, m_ty, exp_ty]) }
where
err_msg ty
= vcat [ text "Illegal polytype:" <+> ppr ty
, text "The type of a Typed Template Haskell expression must" <+>
text "not have any quantification." ]
quotationCtxtDoc :: HsBracket GhcRn -> SDoc
quotationCtxtDoc br_body
= hang (text "In the Template Haskell quotation")
2 (ppr br_body)
getThSpliceOrigin :: TcM Origin
getThSpliceOrigin = do
warn <- goptM Opt_EnableThSpliceWarnings
if warn then return FromSource else return Generated
tcSpliceExpr splice@(HsTypedSplice _ _ name expr) res_ty
= addErrCtxt (spliceCtxtDoc splice) $
setSrcSpan (getLocA expr) $ do
{ stage <- getStage
; case stage of
Splice {} -> tcTopSplice expr res_ty
Brack pop_stage pend -> tcNestedSplice pop_stage pend name expr res_ty
RunSplice _ ->
pprPanic ("tcSpliceExpr: attempted to typecheck a splice when " ++
"running another splice") (ppr splice)
Comp -> tcTopSplice expr res_ty
}
tcSpliceExpr splice _
= pprPanic "tcSpliceExpr" (ppr splice)
tcNestedSplice :: ThStage -> PendingStuff -> Name
-> LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
tcNestedSplice pop_stage (TcPending ps_var lie_var q@(QuoteWrapper _ m_var)) splice_name expr res_ty
= do { res_ty <- expTypeToType res_ty
; let rep = getRuntimeRep res_ty
; meta_exp_ty <- tcTExpTy m_var res_ty
; expr' <- setStage pop_stage $
setConstraintVar lie_var $
tcCheckMonoExpr expr meta_exp_ty
; untype_code <- tcLookupId unTypeCodeName
; let expr'' = mkHsApp
(mkLHsWrap (applyQuoteWrapper q)
(nlHsTyApp untype_code [rep, res_ty])) expr'
; ps <- readMutVar ps_var
; writeMutVar ps_var (PendingTcSplice splice_name expr'' : ps)
; return (HsSpliceE noAnn $
HsSpliced noExtField (ThModFinalizers []) $
HsSplicedExpr (unLoc expr'')) }
tcNestedSplice _ _ splice_name _ _
= pprPanic "tcNestedSplice: rename stage found" (ppr splice_name)
tcTopSplice :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
tcTopSplice expr res_ty
= do {
res_ty <- expTypeToType res_ty
; q_type <- tcMetaTy qTyConName
; meta_exp_ty <- tcTExpTy q_type res_ty
; q_expr <- tcTopSpliceExpr Typed $
tcCheckMonoExpr expr meta_exp_ty
; lcl_env <- getLclEnv
; let delayed_splice
= DelayedSplice lcl_env expr res_ty q_expr
; return (HsSpliceE noAnn (XSplice (HsSplicedT delayed_splice)))
}
runTopSplice :: DelayedSplice -> TcM (HsExpr GhcTc)
runTopSplice (DelayedSplice lcl_env orig_expr res_ty q_expr)
= setLclEnv lcl_env $ do {
zonked_ty <- zonkTcType res_ty
; zonked_q_expr <- zonkTopLExpr q_expr
; modfinalizers_ref <- newTcRef []
; expr2 <- setStage (RunSplice modfinalizers_ref) $
runMetaE zonked_q_expr
; mod_finalizers <- readTcRef modfinalizers_ref
; addModFinalizersWithLclEnv $ ThModFinalizers mod_finalizers
; traceSplice (SpliceInfo { spliceDescription = "expression"
, spliceIsDecl = False
, spliceSource = Just orig_expr
, spliceGenerated = ppr expr2 })
; (res, wcs) <-
captureConstraints $
addErrCtxt (spliceResultDoc zonked_q_expr) $ do
{ (exp3, _fvs) <- rnLExpr expr2
; tcCheckMonoExpr exp3 zonked_ty }
; ev <- simplifyTop wcs
; return $ unLoc (mkHsDictLet (EvBinds ev) res)
}
spliceCtxtDoc :: HsSplice GhcRn -> SDoc
spliceCtxtDoc splice
= hang (text "In the Template Haskell splice")
2 (pprSplice splice)
spliceResultDoc :: LHsExpr GhcTc -> SDoc
spliceResultDoc expr
= sep [ text "In the result of the splice:"
, nest 2 (char '$' <> ppr expr)
, text "To see what the splice expanded to, use -ddump-splices"]
tcTopSpliceExpr :: SpliceType -> TcM (LHsExpr GhcTc) -> TcM (LHsExpr GhcTc)
tcTopSpliceExpr isTypedSplice tc_action
= checkNoErrs $
unsetGOptM Opt_DeferTypeErrors $
setStage (Splice isTypedSplice) $
do {
(expr', wanted) <- captureConstraints tc_action
; const_binds <- simplifyTop wanted
; return $ mkHsDictLet (EvBinds const_binds) expr' }
runAnnotation target expr = do
loc <- getSrcSpanM
data_class <- tcLookupClass dataClassName
to_annotation_wrapper_id <- tcLookupId toAnnotationWrapperName
zonked_wrapped_expr' <- zonkTopLExpr =<< tcTopSpliceExpr Untyped (
do { (expr', expr_ty) <- tcInferRhoNC expr
; wrapper <- instCall AnnOrigin [expr_ty] [mkClassPred data_class [expr_ty]]
; let loc' = noAnnSrcSpan loc
; let specialised_to_annotation_wrapper_expr
= L loc' (mkHsWrap wrapper
(HsVar noExtField (L (noAnnSrcSpan loc) to_annotation_wrapper_id)))
; return (L loc' (HsApp noComments
specialised_to_annotation_wrapper_expr expr'))
})
serialized <- runMetaAW zonked_wrapped_expr'
return Annotation {
ann_target = target,
ann_value = serialized
}
convertAnnotationWrapper :: ForeignHValue -> TcM (Either SDoc Serialized)
convertAnnotationWrapper fhv = do
interp <- tcGetInterp
case interpInstance interp of
ExternalInterp {} -> Right <$> runTH THAnnWrapper fhv
#if defined(HAVE_INTERNAL_INTERPRETER)
InternalInterp -> do
annotation_wrapper <- liftIO $ wormhole interp fhv
return $ Right $
case unsafeCoerce annotation_wrapper of
AnnotationWrapper value | let serialized = toSerialized serializeWithData value ->
seqSerialized serialized `seq` serialized
seqSerialized :: Serialized -> ()
seqSerialized (Serialized the_type bytes) = the_type `seq` bytes `seqList` ()
#endif
runQuasi :: TH.Q a -> TcM a
runQuasi act = TH.runQ act
runRemoteModFinalizers :: ThModFinalizers -> TcM ()
runRemoteModFinalizers (ThModFinalizers finRefs) = do
let withForeignRefs [] f = f []
withForeignRefs (x : xs) f = withForeignRef x $ \r ->
withForeignRefs xs $ \rs -> f (r : rs)
interp <- tcGetInterp
case interpInstance interp of
#if defined(HAVE_INTERNAL_INTERPRETER)
InternalInterp -> do
qs <- liftIO (withForeignRefs finRefs $ mapM localRef)
runQuasi $ sequence_ qs
#endif
ExternalInterp conf iserv -> withIServ_ conf iserv $ \i -> do
tcg <- getGblEnv
th_state <- readTcRef (tcg_th_remote_state tcg)
case th_state of
Nothing -> return ()
Just fhv -> do
liftIO $ withForeignRef fhv $ \st ->
withForeignRefs finRefs $ \qrefs ->
writeIServ i (putMessage (RunModFinalizers st qrefs))
() <- runRemoteTH i []
readQResult i
runQResult
:: (a -> String)
-> (Origin -> SrcSpan -> a -> b)
-> (ForeignHValue -> TcM a)
-> SrcSpan
-> ForeignHValue
-> TcM b
runQResult show_th f runQ expr_span hval
= do { th_result <- runQ hval
; th_origin <- getThSpliceOrigin
; traceTc "Got TH result:" (text (show_th th_result))
; return (f th_origin expr_span th_result) }
runMeta :: (MetaHook TcM -> LHsExpr GhcTc -> TcM hs_syn)
-> LHsExpr GhcTc
-> TcM hs_syn
runMeta unwrap e = do
hooks <- getHooks
case runMetaHook hooks of
Nothing -> unwrap defaultRunMeta e
Just h -> unwrap h e
defaultRunMeta :: MetaHook TcM
defaultRunMeta (MetaE r)
= fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsExpr runTHExp)
defaultRunMeta (MetaP r)
= fmap r . runMeta' True ppr (runQResult TH.pprint convertToPat runTHPat)
defaultRunMeta (MetaT r)
= fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsType runTHType)
defaultRunMeta (MetaD r)
= fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsDecls runTHDec)
defaultRunMeta (MetaAW r)
= fmap r . runMeta' False (const empty) (const convertAnnotationWrapper)
runMetaAW :: LHsExpr GhcTc
-> TcM Serialized
runMetaAW = runMeta metaRequestAW
runMetaE :: LHsExpr GhcTc
-> TcM (LHsExpr GhcPs)
runMetaE = runMeta metaRequestE
runMetaP :: LHsExpr GhcTc
-> TcM (LPat GhcPs)
runMetaP = runMeta metaRequestP
runMetaT :: LHsExpr GhcTc
-> TcM (LHsType GhcPs)
runMetaT = runMeta metaRequestT
runMetaD :: LHsExpr GhcTc
-> TcM [LHsDecl GhcPs]
runMetaD = runMeta metaRequestD
runMeta' :: Bool
-> (hs_syn -> SDoc)
-> (SrcSpan -> ForeignHValue -> TcM (Either SDoc hs_syn))
-> LHsExpr GhcTc
-> TcM hs_syn
runMeta' show_code ppr_hs run_and_convert expr
= do { traceTc "About to run" (ppr expr)
; recordThSpliceUse
; failIfErrsM
; hsc_env <- getTopEnv
; expr' <- withPlugins hsc_env spliceRunAction expr
; ds_expr <- initDsTc (dsLExpr expr')
; src_span <- getSrcSpanM
; traceTc "About to run (desugared)" (ppr ds_expr)
; either_hval <- tryM $ liftIO $
GHC.Driver.Main.hscCompileCoreExpr hsc_env src_span ds_expr
; case either_hval of {
Left exn -> fail_with_exn "compile and link" exn ;
Right hval -> do
{
let expr_span = getLocA expr
; either_tval <- tryAllM $
setSrcSpan expr_span $
do { mb_result <- run_and_convert expr_span hval
; case mb_result of
Left err -> failWithTc err
Right result -> do { traceTc "Got HsSyn result:" (ppr_hs result)
; return $! result } }
; case either_tval of
Right v -> return v
Left se -> case fromException se of
Just IOEnvFailure -> failM
_ -> fail_with_exn "run" se
}}}
where
fail_with_exn :: Exception e => String -> e -> TcM a
fail_with_exn phase exn = do
exn_msg <- liftIO $ Panic.safeShowException exn
let msg = vcat [text "Exception when trying to" <+> text phase <+> text "compile-time code:",
nest 2 (text exn_msg),
if show_code then text "Code:" <+> ppr expr else empty]
failWithTc msg
instance TH.Quasi TcM where
qNewName s = do { u <- newUnique
; let i = toInteger (getKey u)
; return (TH.mkNameU s i) }
qReport True msg = seqList msg $ addErr (text msg)
qReport False msg = seqList msg $ addWarn NoReason (text msg)
qLocation = do { m <- getModule
; l <- getSrcSpanM
; r <- case l of
UnhelpfulSpan _ -> pprPanic "qLocation: Unhelpful location"
(ppr l)
RealSrcSpan s _ -> return s
; return (TH.Loc { TH.loc_filename = unpackFS (srcSpanFile r)
, TH.loc_module = moduleNameString (moduleName m)
, TH.loc_package = unitString (moduleUnit m)
, TH.loc_start = (srcSpanStartLine r, srcSpanStartCol r)
, TH.loc_end = (srcSpanEndLine r, srcSpanEndCol r) }) }
qLookupName = lookupName
qReify = reify
qReifyFixity nm = lookupThName nm >>= reifyFixity
qReifyType = reifyTypeOfThing
qReifyInstances = reifyInstances
qReifyRoles = reifyRoles
qReifyAnnotations = reifyAnnotations
qReifyModule = reifyModule
qReifyConStrictness nm = do { nm' <- lookupThName nm
; dc <- tcLookupDataCon nm'
; let bangs = dataConImplBangs dc
; return (map reifyDecidedStrictness bangs) }
qRecover recover main = tryTcDiscardingErrs recover main
qAddDependentFile fp = do
ref <- fmap tcg_dependent_files getGblEnv
dep_files <- readTcRef ref
writeTcRef ref (fp:dep_files)
qAddTempFile suffix = do
dflags <- getDynFlags
logger <- getLogger
tmpfs <- hsc_tmpfs <$> getTopEnv
liftIO $ newTempName logger tmpfs dflags TFL_GhcSession suffix
qAddTopDecls thds = do
l <- getSrcSpanM
th_origin <- getThSpliceOrigin
let either_hval = convertToHsDecls th_origin l thds
ds <- case either_hval of
Left exn -> failWithTc $
hang (text "Error in a declaration passed to addTopDecls:")
2 exn
Right ds -> return ds
mapM_ (checkTopDecl . unLoc) ds
th_topdecls_var <- fmap tcg_th_topdecls getGblEnv
updTcRef th_topdecls_var (\topds -> ds ++ topds)
where
checkTopDecl :: HsDecl GhcPs -> TcM ()
checkTopDecl (ValD _ binds)
= mapM_ bindName (collectHsBindBinders CollNoDictBinders binds)
checkTopDecl (SigD _ _)
= return ()
checkTopDecl (AnnD _ _)
= return ()
checkTopDecl (ForD _ (ForeignImport { fd_name = L _ name }))
= bindName name
checkTopDecl _
= addErr $ text "Only function, value, annotation, and foreign import declarations may be added with addTopDecl"
bindName :: RdrName -> TcM ()
bindName (Exact n)
= do { th_topnames_var <- fmap tcg_th_topnames getGblEnv
; updTcRef th_topnames_var (\ns -> extendNameSet ns n)
}
bindName name =
addErr $
hang (text "The binder" <+> quotes (ppr name) <+> ptext (sLit "is not a NameU."))
2 (text "Probable cause: you used mkName instead of newName to generate a binding.")
qAddForeignFilePath lang fp = do
var <- fmap tcg_th_foreign_files getGblEnv
updTcRef var ((lang, fp) :)
qAddModFinalizer fin = do
r <- liftIO $ mkRemoteRef fin
fref <- liftIO $ mkForeignRef r (freeRemoteRef r)
addModFinalizerRef fref
qAddCorePlugin plugin = do
hsc_env <- getTopEnv
r <- liftIO $ findHomeModule hsc_env (mkModuleName plugin)
let err = hang
(text "addCorePlugin: invalid plugin module "
<+> text (show plugin)
)
2
(text "Plugins in the current package can't be specified.")
case r of
Found {} -> addErr err
FoundMultiple {} -> addErr err
_ -> return ()
th_coreplugins_var <- tcg_th_coreplugins <$> getGblEnv
updTcRef th_coreplugins_var (plugin:)
qGetQ :: forall a. Typeable a => TcM (Maybe a)
qGetQ = do
th_state_var <- fmap tcg_th_state getGblEnv
th_state <- readTcRef th_state_var
return (Map.lookup (typeRep (Proxy :: Proxy a)) th_state >>= fromDynamic)
qPutQ x = do
th_state_var <- fmap tcg_th_state getGblEnv
updTcRef th_state_var (\m -> Map.insert (typeOf x) (toDyn x) m)
qIsExtEnabled = xoptM
qExtsEnabled =
EnumSet.toList . extensionFlags . hsc_dflags <$> getTopEnv
qPutDoc doc_loc s = do
th_doc_var <- tcg_th_docs <$> getGblEnv
resolved_doc_loc <- resolve_loc doc_loc
is_local <- checkLocalName resolved_doc_loc
unless is_local $ failWithTc $ text
"Can't add documentation to" <+> ppr_loc doc_loc <+>
text "as it isn't inside the current module"
updTcRef th_doc_var (Map.insert resolved_doc_loc s)
where
resolve_loc (TH.DeclDoc n) = DeclDoc <$> lookupThName n
resolve_loc (TH.ArgDoc n i) = ArgDoc <$> lookupThName n <*> pure i
resolve_loc (TH.InstDoc t) = InstDoc <$> fmap getName (lookupThInstName t)
resolve_loc TH.ModuleDoc = pure ModuleDoc
ppr_loc (TH.DeclDoc n) = ppr_th n
ppr_loc (TH.ArgDoc n _) = ppr_th n
ppr_loc (TH.InstDoc t) = ppr_th t
ppr_loc TH.ModuleDoc = text "the module header"
checkLocalName (DeclDoc n) = nameIsLocalOrFrom <$> getModule <*> pure n
checkLocalName (ArgDoc n _) = nameIsLocalOrFrom <$> getModule <*> pure n
checkLocalName (InstDoc n) = nameIsLocalOrFrom <$> getModule <*> pure n
checkLocalName ModuleDoc = pure True
qGetDoc (TH.DeclDoc n) = lookupThName n >>= lookupDeclDoc
qGetDoc (TH.InstDoc t) = lookupThInstName t >>= lookupDeclDoc
qGetDoc (TH.ArgDoc n i) = lookupThName n >>= lookupArgDoc i
qGetDoc TH.ModuleDoc = do
(moduleDoc, _, _) <- getGblEnv >>= extractDocs
return (fmap unpackHDS moduleDoc)
lookupDeclDoc :: Name -> TcM (Maybe String)
lookupDeclDoc nm = do
(_, DeclDocMap declDocs, _) <- getGblEnv >>= extractDocs
fam_insts <- tcg_fam_insts <$> getGblEnv
traceTc "lookupDeclDoc" (ppr nm <+> ppr declDocs <+> ppr fam_insts)
case Map.lookup nm declDocs of
Just doc -> pure $ Just (unpackHDS doc)
Nothing -> do
mIface <- getExternalModIface nm
case mIface of
Nothing -> pure Nothing
Just ModIface { mi_decl_docs = DeclDocMap dmap } ->
pure $ unpackHDS <$> Map.lookup nm dmap
lookupArgDoc :: Int -> Name -> TcM (Maybe String)
lookupArgDoc i nm = do
(_, _, ArgDocMap argDocs) <- getGblEnv >>= extractDocs
case Map.lookup nm argDocs of
Just m -> pure $ unpackHDS <$> IntMap.lookup i m
Nothing -> do
mIface <- getExternalModIface nm
case mIface of
Nothing -> pure Nothing
Just ModIface { mi_arg_docs = ArgDocMap amap } ->
pure $ unpackHDS <$> (Map.lookup nm amap >>= IntMap.lookup i)
getExternalModIface :: Name -> TcM (Maybe ModIface)
getExternalModIface nm = do
isLocal <- nameIsLocalOrFrom <$> getModule <*> pure nm
if isLocal
then pure Nothing
else case nameModule_maybe nm of
Nothing -> pure Nothing
Just modNm -> do
hsc_env <- getTopEnv
iface <- liftIO $ hscGetModuleInterface hsc_env modNm
pure (Just iface)
lookupThInstName :: TH.Type -> TcM Name
lookupThInstName th_type = do
cls_name <- inst_cls_name th_type
insts <- reifyInstances' cls_name (inst_arg_types th_type)
case insts of
Left (_, (inst:_)) -> return $ getName inst
Left (_, []) -> noMatches
Right (_, (inst:_)) -> return $ getName inst
Right (_, []) -> noMatches
where
noMatches = failWithTc $
text "Couldn't find any instances of"
<+> ppr_th th_type
<+> text "to add documentation to"
inst_cls_name :: TH.Type -> TcM TH.Name
inst_cls_name (TH.AppT t _) = inst_cls_name t
inst_cls_name (TH.SigT n _) = inst_cls_name n
inst_cls_name (TH.VarT n) = pure n
inst_cls_name (TH.ConT n) = pure n
inst_cls_name (TH.PromotedT n) = pure n
inst_cls_name (TH.InfixT _ n _) = pure n
inst_cls_name (TH.UInfixT _ n _) = pure n
inst_cls_name (TH.ParensT t) = inst_cls_name t
inst_cls_name (TH.ForallT _ _ _) = inst_cls_name_err
inst_cls_name (TH.ForallVisT _ _) = inst_cls_name_err
inst_cls_name (TH.AppKindT _ _) = inst_cls_name_err
inst_cls_name (TH.TupleT _) = inst_cls_name_err
inst_cls_name (TH.UnboxedTupleT _) = inst_cls_name_err
inst_cls_name (TH.UnboxedSumT _) = inst_cls_name_err
inst_cls_name TH.ArrowT = inst_cls_name_err
inst_cls_name TH.MulArrowT = inst_cls_name_err
inst_cls_name TH.EqualityT = inst_cls_name_err
inst_cls_name TH.ListT = inst_cls_name_err
inst_cls_name (TH.PromotedTupleT _) = inst_cls_name_err
inst_cls_name TH.PromotedNilT = inst_cls_name_err
inst_cls_name TH.PromotedConsT = inst_cls_name_err
inst_cls_name TH.StarT = inst_cls_name_err
inst_cls_name TH.ConstraintT = inst_cls_name_err
inst_cls_name (TH.LitT _) = inst_cls_name_err
inst_cls_name TH.WildCardT = inst_cls_name_err
inst_cls_name (TH.ImplicitParamT _ _) = inst_cls_name_err
inst_cls_name_err = failWithTc $
text "Couldn't work out what instance"
<+> ppr_th th_type
<+> text "is supposed to be"
inst_arg_types :: TH.Type -> [TH.Type]
inst_arg_types (TH.AppT _ args) =
let go (TH.AppT t ts) = t:go ts
go t = [t]
in go args
inst_arg_types _ = []
addModFinalizerRef :: ForeignRef (TH.Q ()) -> TcM ()
addModFinalizerRef finRef = do
th_stage <- getStage
case th_stage of
RunSplice th_modfinalizers_var -> updTcRef th_modfinalizers_var (finRef :)
_ ->
pprPanic "addModFinalizer was called when no finalizers were collected"
(ppr th_stage)
finishTH :: TcM ()
finishTH = do
hsc_env <- getTopEnv
case interpInstance <$> hsc_interp hsc_env of
Nothing -> pure ()
#if defined(HAVE_INTERNAL_INTERPRETER)
Just InternalInterp -> pure ()
#endif
Just (ExternalInterp {}) -> do
tcg <- getGblEnv
writeTcRef (tcg_th_remote_state tcg) Nothing
runTHExp :: ForeignHValue -> TcM TH.Exp
runTHExp = runTH THExp
runTHPat :: ForeignHValue -> TcM TH.Pat
runTHPat = runTH THPat
runTHType :: ForeignHValue -> TcM TH.Type
runTHType = runTH THType
runTHDec :: ForeignHValue -> TcM [TH.Dec]
runTHDec = runTH THDec
runTH :: Binary a => THResultType -> ForeignHValue -> TcM a
runTH ty fhv = do
interp <- tcGetInterp
case interpInstance interp of
#if defined(HAVE_INTERNAL_INTERPRETER)
InternalInterp -> do
hv <- liftIO $ wormhole interp fhv
r <- runQuasi (unsafeCoerce hv :: TH.Q a)
return r
#endif
ExternalInterp conf iserv ->
withIServ_ conf iserv $ \i -> do
rstate <- getTHState i
loc <- TH.qLocation
liftIO $
withForeignRef rstate $ \state_hv ->
withForeignRef fhv $ \q_hv ->
writeIServ i (putMessage (RunTH state_hv q_hv ty (Just loc)))
runRemoteTH i []
bs <- readQResult i
return $! runGet get (LB.fromStrict bs)
runRemoteTH
:: IServInstance
-> [Messages DecoratedSDoc]
-> TcM ()
runRemoteTH iserv recovers = do
THMsg msg <- liftIO $ readIServ iserv getTHMessage
case msg of
RunTHDone -> return ()
StartRecover -> do
v <- getErrsVar
msgs <- readTcRef v
writeTcRef v emptyMessages
runRemoteTH iserv (msgs : recovers)
EndRecover caught_error -> do
let (prev_msgs, rest) = case recovers of
[] -> panic "EndRecover"
a : b -> (a,b)
v <- getErrsVar
warn_msgs <- getWarningMessages <$> readTcRef v
writeTcRef v $ if caught_error
then prev_msgs
else mkMessages warn_msgs `unionMessages` prev_msgs
runRemoteTH iserv rest
_other -> do
r <- handleTHMessage msg
liftIO $ writeIServ iserv (put r)
runRemoteTH iserv recovers
readQResult :: Binary a => IServInstance -> TcM a
readQResult i = do
qr <- liftIO $ readIServ i get
case qr of
QDone a -> return a
QException str -> liftIO $ throwIO (ErrorCall str)
QFail str -> fail str
getTHState :: IServInstance -> TcM (ForeignRef (IORef QState))
getTHState i = do
tcg <- getGblEnv
th_state <- readTcRef (tcg_th_remote_state tcg)
case th_state of
Just rhv -> return rhv
Nothing -> do
interp <- tcGetInterp
fhv <- liftIO $ mkFinalizedHValue interp =<< iservCall i StartTH
writeTcRef (tcg_th_remote_state tcg) (Just fhv)
return fhv
wrapTHResult :: TcM a -> TcM (THResult a)
wrapTHResult tcm = do
e <- tryM tcm
case e of
Left e -> return (THException (show e))
Right a -> return (THComplete a)
handleTHMessage :: THMessage a -> TcM a
handleTHMessage msg = case msg of
NewName a -> wrapTHResult $ TH.qNewName a
Report b str -> wrapTHResult $ TH.qReport b str
LookupName b str -> wrapTHResult $ TH.qLookupName b str
Reify n -> wrapTHResult $ TH.qReify n
ReifyFixity n -> wrapTHResult $ TH.qReifyFixity n
ReifyType n -> wrapTHResult $ TH.qReifyType n
ReifyInstances n ts -> wrapTHResult $ TH.qReifyInstances n ts
ReifyRoles n -> wrapTHResult $ TH.qReifyRoles n
ReifyAnnotations lookup tyrep ->
wrapTHResult $ (map B.pack <$> getAnnotationsByTypeRep lookup tyrep)
ReifyModule m -> wrapTHResult $ TH.qReifyModule m
ReifyConStrictness nm -> wrapTHResult $ TH.qReifyConStrictness nm
AddDependentFile f -> wrapTHResult $ TH.qAddDependentFile f
AddTempFile s -> wrapTHResult $ TH.qAddTempFile s
AddModFinalizer r -> do
interp <- hscInterp <$> getTopEnv
wrapTHResult $ liftIO (mkFinalizedHValue interp r) >>= addModFinalizerRef
AddCorePlugin str -> wrapTHResult $ TH.qAddCorePlugin str
AddTopDecls decs -> wrapTHResult $ TH.qAddTopDecls decs
AddForeignFilePath lang str -> wrapTHResult $ TH.qAddForeignFilePath lang str
IsExtEnabled ext -> wrapTHResult $ TH.qIsExtEnabled ext
ExtsEnabled -> wrapTHResult $ TH.qExtsEnabled
PutDoc l s -> wrapTHResult $ TH.qPutDoc l s
GetDoc l -> wrapTHResult $ TH.qGetDoc l
FailIfErrs -> wrapTHResult failIfErrsM
_ -> panic ("handleTHMessage: unexpected message " ++ show msg)
getAnnotationsByTypeRep :: TH.AnnLookup -> TypeRep -> TcM [[Word8]]
getAnnotationsByTypeRep th_name tyrep
= do { name <- lookupThAnnLookup th_name
; topEnv <- getTopEnv
; epsHptAnns <- liftIO $ prepareAnnotations topEnv Nothing
; tcg <- getGblEnv
; let selectedEpsHptAnns = findAnnsByTypeRep epsHptAnns name tyrep
; let selectedTcgAnns = findAnnsByTypeRep (tcg_ann_env tcg) name tyrep
; return (selectedEpsHptAnns ++ selectedTcgAnns) }
reifyInstances :: TH.Name -> [TH.Type] -> TcM [TH.Dec]
reifyInstances th_nm th_tys
= do { insts <- reifyInstances' th_nm th_tys
; case insts of
Left (cls, cls_insts) ->
reifyClassInstances cls cls_insts
Right (tc, fam_insts) ->
reifyFamilyInstances tc fam_insts }
reifyInstances' :: TH.Name
-> [TH.Type]
-> TcM (Either (Class, [ClsInst]) (TyCon, [FamInst]))
reifyInstances' th_nm th_tys
= addErrCtxt (text "In the argument of reifyInstances:"
<+> ppr_th th_nm <+> sep (map ppr_th th_tys)) $
do { loc <- getSrcSpanM
; th_origin <- getThSpliceOrigin
; rdr_ty <- cvt th_origin loc (mkThAppTs (TH.ConT th_nm) th_tys)
; let tv_rdrs = extractHsTyRdrTyVars rdr_ty
; ((tv_names, rn_ty), _fvs)
<- checkNoErrs $
rnImplicitTvOccs Nothing tv_rdrs $ \ tv_names ->
do { (rn_ty, fvs) <- rnLHsType doc rdr_ty
; return ((tv_names, rn_ty), fvs) }
; (tclvl, wanted, (tvs, ty))
<- pushLevelAndSolveEqualitiesX "reifyInstances" $
bindImplicitTKBndrs_Skol tv_names $
tcInferLHsType rn_ty
; tvs <- zonkAndScopedSort tvs
; reportUnsolvedEqualities ReifySkol tvs tclvl wanted
; ty <- zonkTcTypeToType ty
; traceTc "reifyInstances'" (ppr ty $$ ppr (tcTypeKind ty))
; case splitTyConApp_maybe ty of
Just (tc, tys)
| Just cls <- tyConClass_maybe tc
-> do { inst_envs <- tcGetInstEnvs
; let (matches, unifies, _) = lookupInstEnv False inst_envs cls tys
; traceTc "reifyInstances'1" (ppr matches)
; return $ Left (cls, map fst matches ++ unifies) }
| isOpenFamilyTyCon tc
-> do { inst_envs <- tcGetFamInstEnvs
; let matches = lookupFamInstEnv inst_envs tc tys
; traceTc "reifyInstances'2" (ppr matches)
; return $ Right (tc, map fim_instance matches) }
_ -> bale_out (hang (text "reifyInstances:" <+> quotes (ppr ty))
2 (text "is not a class constraint or type family application")) }
where
doc = ClassInstanceCtx
bale_out msg = failWithTc msg
cvt :: Origin -> SrcSpan -> TH.Type -> TcM (LHsType GhcPs)
cvt origin loc th_ty = case convertToHsType origin loc th_ty of
Left msg -> failWithTc msg
Right ty -> return ty
lookupName :: Bool
-> String -> TcM (Maybe TH.Name)
lookupName is_type_name s
= do { mb_nm <- lookupOccRn_maybe rdr_name
; return (fmap reifyName mb_nm) }
where
th_name = TH.mkName s
occ_fs :: FastString
occ_fs = mkFastString (TH.nameBase th_name)
occ :: OccName
occ | is_type_name
= if isLexVarSym occ_fs || isLexCon occ_fs
then mkTcOccFS occ_fs
else mkTyVarOccFS occ_fs
| otherwise
= if isLexCon occ_fs then mkDataOccFS occ_fs
else mkVarOccFS occ_fs
rdr_name = case TH.nameModule th_name of
Nothing -> mkRdrUnqual occ
Just mod -> mkRdrQual (mkModuleName mod) occ
getThing :: TH.Name -> TcM TcTyThing
getThing th_name
= do { name <- lookupThName th_name
; traceIf (text "reify" <+> text (show th_name) <+> brackets (ppr_ns th_name) <+> ppr name)
; tcLookupTh name }
where
ppr_ns (TH.Name _ (TH.NameG TH.DataName _pkg _mod)) = text "data"
ppr_ns (TH.Name _ (TH.NameG TH.TcClsName _pkg _mod)) = text "tc"
ppr_ns (TH.Name _ (TH.NameG TH.VarName _pkg _mod)) = text "var"
ppr_ns _ = panic "reify/ppr_ns"
reify :: TH.Name -> TcM TH.Info
reify th_name
= do { traceTc "reify 1" (text (TH.showName th_name))
; thing <- getThing th_name
; traceTc "reify 2" (ppr thing)
; reifyThing thing }
lookupThName :: TH.Name -> TcM Name
lookupThName th_name = do
mb_name <- lookupThName_maybe th_name
case mb_name of
Nothing -> failWithTc (notInScope th_name)
Just name -> return name
lookupThName_maybe :: TH.Name -> TcM (Maybe Name)
lookupThName_maybe th_name
= do { names <- mapMaybeM lookupOccRn_maybe (thRdrNameGuesses th_name)
; return (listToMaybe names) }
tcLookupTh :: Name -> TcM TcTyThing
tcLookupTh name
= do { (gbl_env, lcl_env) <- getEnvs
; case lookupNameEnv (tcl_env lcl_env) name of {
Just thing -> return thing;
Nothing ->
case lookupNameEnv (tcg_type_env gbl_env) name of {
Just thing -> return (AGlobal thing);
Nothing ->
if nameIsLocalOrFrom (tcg_semantic_mod gbl_env) name
then
failWithTc (notInEnv name)
else
do { mb_thing <- tcLookupImported_maybe name
; case mb_thing of
Succeeded thing -> return (AGlobal thing)
Failed msg -> failWithTc msg
}}}}
notInScope :: TH.Name -> SDoc
notInScope th_name = quotes (text (TH.pprint th_name)) <+>
text "is not in scope at a reify"
notInEnv :: Name -> SDoc
notInEnv name = quotes (ppr name) <+>
text "is not in the type environment at a reify"
reifyRoles :: TH.Name -> TcM [TH.Role]
reifyRoles th_name
= do { thing <- getThing th_name
; case thing of
AGlobal (ATyCon tc) -> return (map reify_role (tyConRoles tc))
_ -> failWithTc (text "No roles associated with" <+> (ppr thing))
}
where
reify_role Nominal = TH.NominalR
reify_role Representational = TH.RepresentationalR
reify_role Phantom = TH.PhantomR
reifyThing :: TcTyThing -> TcM TH.Info
reifyThing (AGlobal (AnId id))
= do { ty <- reifyType (idType id)
; let v = reifyName id
; case idDetails id of
ClassOpId cls -> return (TH.ClassOpI v ty (reifyName cls))
RecSelId{sel_tycon=RecSelData tc}
-> return (TH.VarI (reifySelector id tc) ty Nothing)
_ -> return (TH.VarI v ty Nothing)
}
reifyThing (AGlobal (ATyCon tc)) = reifyTyCon tc
reifyThing (AGlobal (AConLike (RealDataCon dc)))
= do { let name = dataConName dc
; ty <- reifyType (idType (dataConWrapId dc))
; return (TH.DataConI (reifyName name) ty
(reifyName (dataConOrigTyCon dc)))
}
reifyThing (AGlobal (AConLike (PatSynCon ps)))
= do { let name = reifyName ps
; ty <- reifyPatSynType (patSynSigBndr ps)
; return (TH.PatSynI name ty) }
reifyThing (ATcId {tct_id = id})
= do { ty1 <- zonkTcType (idType id)
; ty2 <- reifyType ty1
; return (TH.VarI (reifyName id) ty2 Nothing) }
reifyThing (ATyVar tv tv1)
= do { ty1 <- zonkTcTyVar tv1
; ty2 <- reifyType ty1
; return (TH.TyVarI (reifyName tv) ty2) }
reifyThing thing = pprPanic "reifyThing" (pprTcTyThingCategory thing)
reifyAxBranch :: TyCon -> CoAxBranch -> TcM TH.TySynEqn
reifyAxBranch fam_tc (CoAxBranch { cab_tvs = tvs
, cab_lhs = lhs
, cab_rhs = rhs })
= do { tvs' <- reifyTyVarsToMaybe tvs
; let lhs_types_only = filterOutInvisibleTypes fam_tc lhs
; lhs' <- reifyTypes lhs_types_only
; annot_th_lhs <- zipWith3M annotThType (tyConArgsPolyKinded fam_tc)
lhs_types_only lhs'
; let lhs_type = mkThAppTs (TH.ConT $ reifyName fam_tc) annot_th_lhs
; rhs' <- reifyType rhs
; return (TH.TySynEqn tvs' lhs_type rhs') }
reifyTyCon :: TyCon -> TcM TH.Info
reifyTyCon tc
| Just cls <- tyConClass_maybe tc
= reifyClass cls
| isFunTyCon tc
= return (TH.PrimTyConI (reifyName tc) 2 False)
| isPrimTyCon tc
= return (TH.PrimTyConI (reifyName tc) (length (tyConVisibleTyVars tc))
(isUnliftedTyCon tc))
| isTypeFamilyTyCon tc
= do { let tvs = tyConTyVars tc
res_kind = tyConResKind tc
resVar = famTcResVar tc
; kind' <- reifyKind res_kind
; let (resultSig, injectivity) =
case resVar of
Nothing -> (TH.KindSig kind', Nothing)
Just name ->
let thName = reifyName name
injAnnot = tyConInjectivityInfo tc
sig = TH.TyVarSig (TH.KindedTV thName () kind')
inj = case injAnnot of
NotInjective -> Nothing
Injective ms ->
Just (TH.InjectivityAnn thName injRHS)
where
injRHS = map (reifyName . tyVarName)
(filterByList ms tvs)
in (sig, inj)
; tvs' <- reifyTyVars (tyConVisibleTyVars tc)
; let tfHead =
TH.TypeFamilyHead (reifyName tc) tvs' resultSig injectivity
; if isOpenTypeFamilyTyCon tc
then do { fam_envs <- tcGetFamInstEnvs
; instances <- reifyFamilyInstances tc
(familyInstances fam_envs tc)
; return (TH.FamilyI (TH.OpenTypeFamilyD tfHead) instances) }
else do { eqns <-
case isClosedSynFamilyTyConWithAxiom_maybe tc of
Just ax -> mapM (reifyAxBranch tc) $
fromBranches $ coAxiomBranches ax
Nothing -> return []
; return (TH.FamilyI (TH.ClosedTypeFamilyD tfHead eqns)
[]) } }
| isDataFamilyTyCon tc
= do { let res_kind = tyConResKind tc
; kind' <- fmap Just (reifyKind res_kind)
; tvs' <- reifyTyVars (tyConVisibleTyVars tc)
; fam_envs <- tcGetFamInstEnvs
; instances <- reifyFamilyInstances tc (familyInstances fam_envs tc)
; return (TH.FamilyI
(TH.DataFamilyD (reifyName tc) tvs' kind') instances) }
| Just (_, rhs) <- synTyConDefn_maybe tc
= do { rhs' <- reifyType rhs
; tvs' <- reifyTyVars (tyConVisibleTyVars tc)
; return (TH.TyConI
(TH.TySynD (reifyName tc) tvs' rhs'))
}
| otherwise
= do { cxt <- reifyCxt (tyConStupidTheta tc)
; let tvs = tyConTyVars tc
dataCons = tyConDataCons tc
isGadt = isGadtSyntaxTyCon tc
; cons <- mapM (reifyDataCon isGadt (mkTyVarTys tvs)) dataCons
; r_tvs <- reifyTyVars (tyConVisibleTyVars tc)
; let name = reifyName tc
deriv = []
decl | isNewTyCon tc =
TH.NewtypeD cxt name r_tvs Nothing (head cons) deriv
| otherwise =
TH.DataD cxt name r_tvs Nothing cons deriv
; return (TH.TyConI decl) }
reifyDataCon :: Bool -> [Type] -> DataCon -> TcM TH.Con
reifyDataCon isGadtDataCon tys dc
= do { let
(ex_tvs, theta, arg_tys)
= dataConInstSig dc tys
g_user_tvs' = dataConUserTyVarBinders dc
(g_univ_tvs, _, g_eq_spec, g_theta', g_arg_tys', g_res_ty')
= dataConFullSig dc
(srcUnpks, srcStricts)
= mapAndUnzip reifySourceBang (dataConSrcBangs dc)
dcdBangs = zipWith TH.Bang srcUnpks srcStricts
fields = dataConFieldLabels dc
name = reifyName dc
eq_spec_tvs = mkVarSet (map eqSpecTyVar g_eq_spec)
; (univ_subst, _)
<- freshenTyVarBndrs $
filterOut (`elemVarSet` eq_spec_tvs) g_univ_tvs
; let (tvb_subst, g_user_tvs) = subst_tv_binders univ_subst g_user_tvs'
g_theta = substTys tvb_subst g_theta'
g_arg_tys = substTys tvb_subst (map scaledThing g_arg_tys')
g_res_ty = substTy tvb_subst g_res_ty'
; r_arg_tys <- reifyTypes (if isGadtDataCon then g_arg_tys else arg_tys)
; main_con <-
if | not (null fields) && not isGadtDataCon ->
return $ TH.RecC name (zip3 (map reifyFieldLabel fields)
dcdBangs r_arg_tys)
| not (null fields) -> do
{ res_ty <- reifyType g_res_ty
; return $ TH.RecGadtC [name]
(zip3 (map (reifyName . flSelector) fields)
dcdBangs r_arg_tys) res_ty }
| dataConIsInfix dc && not isGadtDataCon ->
ASSERT( r_arg_tys `lengthIs` 2 ) do
{ let [r_a1, r_a2] = r_arg_tys
[s1, s2] = dcdBangs
; return $ TH.InfixC (s1,r_a1) name (s2,r_a2) }
| isGadtDataCon -> do
{ res_ty <- reifyType g_res_ty
; return $ TH.GadtC [name] (dcdBangs `zip` r_arg_tys) res_ty }
| otherwise ->
return $ TH.NormalC name (dcdBangs `zip` r_arg_tys)
; let (ex_tvs', theta') | isGadtDataCon = (g_user_tvs, g_theta)
| otherwise = ASSERT( all isTyVar ex_tvs )
(map mk_specified ex_tvs, theta)
ret_con | null ex_tvs' && null theta' = return main_con
| otherwise = do
{ cxt <- reifyCxt theta'
; ex_tvs'' <- reifyTyVarBndrs ex_tvs'
; return (TH.ForallC ex_tvs'' cxt main_con) }
; ASSERT( r_arg_tys `equalLength` dcdBangs )
ret_con }
where
mk_specified tv = Bndr tv SpecifiedSpec
subst_tv_binders subst tv_bndrs =
let tvs = binderVars tv_bndrs
flags = map binderArgFlag tv_bndrs
(subst', tvs') = substTyVarBndrs subst tvs
tv_bndrs' = map (\(tv,fl) -> Bndr tv fl) (zip tvs' flags)
in (subst', tv_bndrs')
reifyClass :: Class -> TcM TH.Info
reifyClass cls
= do { cxt <- reifyCxt theta
; inst_envs <- tcGetInstEnvs
; insts <- reifyClassInstances cls (InstEnv.classInstances inst_envs cls)
; assocTys <- concatMapM reifyAT ats
; ops <- concatMapM reify_op op_stuff
; tvs' <- reifyTyVars (tyConVisibleTyVars (classTyCon cls))
; let dec = TH.ClassD cxt (reifyName cls) tvs' fds' (assocTys ++ ops)
; return (TH.ClassI dec insts) }
where
(_, fds, theta, _, ats, op_stuff) = classExtraBigSig cls
fds' = map reifyFunDep fds
reify_op (op, def_meth)
= do { let (_, _, ty) = tcSplitMethodTy (idType op)
; ty' <- reifyType ty
; let nm' = reifyName op
; case def_meth of
Just (_, GenericDM gdm_ty) ->
do { gdm_ty' <- reifyType gdm_ty
; return [TH.SigD nm' ty', TH.DefaultSigD nm' gdm_ty'] }
_ -> return [TH.SigD nm' ty'] }
reifyAT :: ClassATItem -> TcM [TH.Dec]
reifyAT (ATI tycon def) = do
tycon' <- reifyTyCon tycon
case tycon' of
TH.FamilyI dec _ -> do
let (tyName, tyArgs) = tfNames dec
(dec :) <$> maybe (return [])
(fmap (:[]) . reifyDefImpl tyName tyArgs . fst)
def
_ -> pprPanic "reifyAT" (text (show tycon'))
reifyDefImpl :: TH.Name -> [TH.Name] -> Type -> TcM TH.Dec
reifyDefImpl n args ty =
TH.TySynInstD . TH.TySynEqn Nothing (mkThAppTs (TH.ConT n) (map TH.VarT args))
<$> reifyType ty
tfNames :: TH.Dec -> (TH.Name, [TH.Name])
tfNames (TH.OpenTypeFamilyD (TH.TypeFamilyHead n args _ _))
= (n, map bndrName args)
tfNames d = pprPanic "tfNames" (text (show d))
bndrName :: TH.TyVarBndr flag -> TH.Name
bndrName (TH.PlainTV n _) = n
bndrName (TH.KindedTV n _ _) = n
annotThType :: Bool
-> TyCoRep.Type -> TH.Type -> TcM TH.Type
annotThType _ _ th_ty@(TH.SigT {}) = return th_ty
annotThType True ty th_ty
| not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty
= do { let ki = tcTypeKind ty
; th_ki <- reifyKind ki
; return (TH.SigT th_ty th_ki) }
annotThType _ _ th_ty = return th_ty
tyConArgsPolyKinded :: TyCon -> [Bool]
tyConArgsPolyKinded tc =
map (is_poly_ty . tyVarKind) tc_vis_tvs
++ map (is_poly_ty . tyCoBinderType) tc_res_kind_vis_bndrs
++ repeat True
where
is_poly_ty :: Type -> Bool
is_poly_ty ty = not $
isEmptyVarSet $
filterVarSet isTyVar $
tyCoVarsOfType ty
tc_vis_tvs :: [TyVar]
tc_vis_tvs = tyConVisibleTyVars tc
tc_res_kind_vis_bndrs :: [TyCoBinder]
tc_res_kind_vis_bndrs = filter isVisibleBinder $ fst $ splitPiTys $ tyConResKind tc
reifyClassInstances :: Class -> [ClsInst] -> TcM [TH.Dec]
reifyClassInstances cls insts
= mapM (reifyClassInstance (tyConArgsPolyKinded (classTyCon cls))) insts
reifyClassInstance :: [Bool]
-> ClsInst -> TcM TH.Dec
reifyClassInstance is_poly_tvs i
= do { cxt <- reifyCxt theta
; let vis_types = filterOutInvisibleTypes cls_tc types
; thtypes <- reifyTypes vis_types
; annot_thtypes <- zipWith3M annotThType is_poly_tvs vis_types thtypes
; let head_ty = mkThAppTs (TH.ConT (reifyName cls)) annot_thtypes
; return $ (TH.InstanceD over cxt head_ty []) }
where
(_tvs, theta, cls, types) = tcSplitDFunTy (idType dfun)
cls_tc = classTyCon cls
dfun = instanceDFunId i
over = case overlapMode (is_flag i) of
NoOverlap _ -> Nothing
Overlappable _ -> Just TH.Overlappable
Overlapping _ -> Just TH.Overlapping
Overlaps _ -> Just TH.Overlaps
Incoherent _ -> Just TH.Incoherent
reifyFamilyInstances :: TyCon -> [FamInst] -> TcM [TH.Dec]
reifyFamilyInstances fam_tc fam_insts
= mapM (reifyFamilyInstance (tyConArgsPolyKinded fam_tc)) fam_insts
reifyFamilyInstance :: [Bool]
-> FamInst -> TcM TH.Dec
reifyFamilyInstance is_poly_tvs (FamInst { fi_flavor = flavor
, fi_axiom = ax
, fi_fam = fam })
| let fam_tc = coAxiomTyCon ax
branch = coAxiomSingleBranch ax
, CoAxBranch { cab_tvs = tvs, cab_lhs = lhs, cab_rhs = rhs } <- branch
= case flavor of
SynFamilyInst ->
do { th_tvs <- reifyTyVarsToMaybe tvs
; let lhs_types_only = filterOutInvisibleTypes fam_tc lhs
; th_lhs <- reifyTypes lhs_types_only
; annot_th_lhs <- zipWith3M annotThType is_poly_tvs lhs_types_only
th_lhs
; let lhs_type = mkThAppTs (TH.ConT $ reifyName fam) annot_th_lhs
; th_rhs <- reifyType rhs
; return (TH.TySynInstD (TH.TySynEqn th_tvs lhs_type th_rhs)) }
DataFamilyInst rep_tc ->
do { let
(ee_tvs, ee_lhs, _) = etaExpandCoAxBranch branch
fam' = reifyName fam
dataCons = tyConDataCons rep_tc
isGadt = isGadtSyntaxTyCon rep_tc
; th_tvs <- reifyTyVarsToMaybe ee_tvs
; cons <- mapM (reifyDataCon isGadt (mkTyVarTys ee_tvs)) dataCons
; let types_only = filterOutInvisibleTypes fam_tc ee_lhs
; th_tys <- reifyTypes types_only
; annot_th_tys <- zipWith3M annotThType is_poly_tvs types_only th_tys
; let lhs_type = mkThAppTs (TH.ConT fam') annot_th_tys
; mb_sig <-
if (null cons || isGadtSyntaxTyCon rep_tc)
&& tyConAppNeedsKindSig False fam_tc (length ee_lhs)
then do { let full_kind = tcTypeKind (mkTyConApp fam_tc ee_lhs)
; th_full_kind <- reifyKind full_kind
; pure $ Just th_full_kind }
else pure Nothing
; return $
if isNewTyCon rep_tc
then TH.NewtypeInstD [] th_tvs lhs_type mb_sig (head cons) []
else TH.DataInstD [] th_tvs lhs_type mb_sig cons []
}
reifyType :: TyCoRep.Type -> TcM TH.Type
reifyType ty | tcIsLiftedTypeKind ty = return TH.StarT
reifyType ty@(ForAllTy (Bndr _ argf) _)
= reify_for_all argf ty
reifyType (LitTy t) = do { r <- reifyTyLit t; return (TH.LitT r) }
reifyType (TyVarTy tv) = return (TH.VarT (reifyName tv))
reifyType (TyConApp tc tys) = reify_tc_app tc tys
reifyType ty@(AppTy {}) = do
let (ty_head, ty_args) = splitAppTys ty
ty_head' <- reifyType ty_head
ty_args' <- reifyTypes (filter_out_invisible_args ty_head ty_args)
pure $ mkThAppTs ty_head' ty_args'
where
filter_out_invisible_args :: Type -> [Type] -> [Type]
filter_out_invisible_args ty_head ty_args =
filterByList (map isVisibleArgFlag $ appTyArgFlags ty_head ty_args)
ty_args
reifyType ty@(FunTy { ft_af = af, ft_mult = Many, ft_arg = t1, ft_res = t2 })
| InvisArg <- af = reify_for_all Inferred ty
| otherwise = do { [r1,r2] <- reifyTypes [t1,t2]
; return (TH.ArrowT `TH.AppT` r1 `TH.AppT` r2) }
reifyType ty@(FunTy { ft_af = af, ft_mult = tm, ft_arg = t1, ft_res = t2 })
| InvisArg <- af = noTH (sLit "linear invisible argument") (ppr ty)
| otherwise = do { [rm,r1,r2] <- reifyTypes [tm,t1,t2]
; return (TH.MulArrowT `TH.AppT` rm `TH.AppT` r1 `TH.AppT` r2) }
reifyType (CastTy t _) = reifyType t
reifyType ty@(CoercionTy {})= noTH (sLit "coercions in types") (ppr ty)
reify_for_all :: TyCoRep.ArgFlag -> TyCoRep.Type -> TcM TH.Type
reify_for_all argf ty
| isVisibleArgFlag argf
= do let (req_bndrs, phi) = tcSplitForAllReqTVBinders ty
tvbndrs' <- reifyTyVarBndrs req_bndrs
phi' <- reifyType phi
pure $ TH.ForallVisT tvbndrs' phi'
| otherwise
= do let (inv_bndrs, phi) = tcSplitForAllInvisTVBinders ty
tvbndrs' <- reifyTyVarBndrs inv_bndrs
let (cxt, tau) = tcSplitPhiTy phi
cxt' <- reifyCxt cxt
tau' <- reifyType tau
pure $ TH.ForallT tvbndrs' cxt' tau'
reifyTyLit :: TyCoRep.TyLit -> TcM TH.TyLit
reifyTyLit (NumTyLit n) = return (TH.NumTyLit n)
reifyTyLit (StrTyLit s) = return (TH.StrTyLit (unpackFS s))
reifyTyLit (CharTyLit c) = return (TH.CharTyLit c)
reifyTypes :: [Type] -> TcM [TH.Type]
reifyTypes = mapM reifyType
reifyPatSynType
:: ([InvisTVBinder], ThetaType, [InvisTVBinder], ThetaType, [Scaled Type], Type) -> TcM TH.Type
reifyPatSynType (univTyVars, req, exTyVars, prov, argTys, resTy)
= do { univTyVars' <- reifyTyVarBndrs univTyVars
; req' <- reifyCxt req
; exTyVars' <- reifyTyVarBndrs exTyVars
; prov' <- reifyCxt prov
; tau' <- reifyType (mkVisFunTys argTys resTy)
; return $ TH.ForallT univTyVars' req'
$ TH.ForallT exTyVars' prov' tau' }
reifyKind :: Kind -> TcM TH.Kind
reifyKind = reifyType
reifyCxt :: [PredType] -> TcM [TH.Pred]
reifyCxt = mapM reifyType
reifyFunDep :: ([TyVar], [TyVar]) -> TH.FunDep
reifyFunDep (xs, ys) = TH.FunDep (map reifyName xs) (map reifyName ys)
class ReifyFlag flag flag' | flag -> flag' where
reifyFlag :: flag -> flag'
instance ReifyFlag () () where
reifyFlag () = ()
instance ReifyFlag Specificity TH.Specificity where
reifyFlag SpecifiedSpec = TH.SpecifiedSpec
reifyFlag InferredSpec = TH.InferredSpec
reifyTyVars :: [TyVar] -> TcM [TH.TyVarBndr ()]
reifyTyVars = reifyTyVarBndrs . map mk_bndr
where
mk_bndr tv = Bndr tv ()
reifyTyVarBndrs :: ReifyFlag flag flag'
=> [VarBndr TyVar flag] -> TcM [TH.TyVarBndr flag']
reifyTyVarBndrs = mapM reify_tvbndr
where
reify_tvbndr (Bndr tv fl) = TH.KindedTV (reifyName tv)
(reifyFlag fl)
<$> reifyKind (tyVarKind tv)
reifyTyVarsToMaybe :: [TyVar] -> TcM (Maybe [TH.TyVarBndr ()])
reifyTyVarsToMaybe [] = pure Nothing
reifyTyVarsToMaybe tys = Just <$> reifyTyVars tys
reify_tc_app :: TyCon -> [Type.Type] -> TcM TH.Type
reify_tc_app tc tys
= do { tys' <- reifyTypes (filterOutInvisibleTypes tc tys)
; maybe_sig_t (mkThAppTs r_tc tys') }
where
arity = tyConArity tc
r_tc | isUnboxedSumTyCon tc = TH.UnboxedSumT (arity `div` 2)
| isUnboxedTupleTyCon tc = TH.UnboxedTupleT (arity `div` 2)
| isPromotedTupleTyCon tc = TH.PromotedTupleT (arity `div` 2)
| isTupleTyCon tc = if isPromotedDataCon tc
then TH.PromotedTupleT arity
else TH.TupleT arity
| tc `hasKey` constraintKindTyConKey
= TH.ConstraintT
| tc `hasKey` unrestrictedFunTyConKey = TH.ArrowT
| tc `hasKey` listTyConKey = TH.ListT
| tc `hasKey` nilDataConKey = TH.PromotedNilT
| tc `hasKey` consDataConKey = TH.PromotedConsT
| tc `hasKey` heqTyConKey = TH.EqualityT
| tc `hasKey` eqPrimTyConKey = TH.EqualityT
| tc `hasKey` eqReprPrimTyConKey = TH.ConT (reifyName coercibleTyCon)
| isPromotedDataCon tc = TH.PromotedT (reifyName tc)
| otherwise = TH.ConT (reifyName tc)
maybe_sig_t th_type
| tyConAppNeedsKindSig
False
tc (length tys)
= do { let full_kind = tcTypeKind (mkTyConApp tc tys)
; th_full_kind <- reifyKind full_kind
; return (TH.SigT th_type th_full_kind) }
| otherwise
= return th_type
reifyName :: NamedThing n => n -> TH.Name
reifyName thing
| isExternalName name
= mk_varg pkg_str mod_str occ_str
| otherwise = TH.mkNameU occ_str (toInteger $ getKey (getUnique name))
where
name = getName thing
mod = ASSERT( isExternalName name ) nameModule name
pkg_str = unitString (moduleUnit mod)
mod_str = moduleNameString (moduleName mod)
occ_str = occNameString occ
occ = nameOccName name
mk_varg | OccName.isDataOcc occ = TH.mkNameG_d
| OccName.isVarOcc occ = TH.mkNameG_v
| OccName.isTcOcc occ = TH.mkNameG_tc
| otherwise = pprPanic "reifyName" (ppr name)
reifyFieldLabel :: FieldLabel -> TH.Name
reifyFieldLabel fl
| flIsOverloaded fl
= TH.Name (TH.mkOccName occ_str) (TH.NameQ (TH.mkModName mod_str))
| otherwise = TH.mkNameG_v pkg_str mod_str occ_str
where
name = flSelector fl
mod = ASSERT( isExternalName name ) nameModule name
pkg_str = unitString (moduleUnit mod)
mod_str = moduleNameString (moduleName mod)
occ_str = unpackFS (flLabel fl)
reifySelector :: Id -> TyCon -> TH.Name
reifySelector id tc
= case find ((idName id ==) . flSelector) (tyConFieldLabels tc) of
Just fl -> reifyFieldLabel fl
Nothing -> pprPanic "reifySelector: missing field" (ppr id $$ ppr tc)
reifyFixity :: Name -> TcM (Maybe TH.Fixity)
reifyFixity name
= do { (found, fix) <- lookupFixityRn_help name
; return (if found then Just (conv_fix fix) else Nothing) }
where
conv_fix (Hs.Fixity _ i d) = TH.Fixity i (conv_dir d)
conv_dir Hs.InfixR = TH.InfixR
conv_dir Hs.InfixL = TH.InfixL
conv_dir Hs.InfixN = TH.InfixN
reifyUnpackedness :: DataCon.SrcUnpackedness -> TH.SourceUnpackedness
reifyUnpackedness NoSrcUnpack = TH.NoSourceUnpackedness
reifyUnpackedness SrcNoUnpack = TH.SourceNoUnpack
reifyUnpackedness SrcUnpack = TH.SourceUnpack
reifyStrictness :: DataCon.SrcStrictness -> TH.SourceStrictness
reifyStrictness NoSrcStrict = TH.NoSourceStrictness
reifyStrictness SrcStrict = TH.SourceStrict
reifyStrictness SrcLazy = TH.SourceLazy
reifySourceBang :: DataCon.HsSrcBang
-> (TH.SourceUnpackedness, TH.SourceStrictness)
reifySourceBang (HsSrcBang _ u s) = (reifyUnpackedness u, reifyStrictness s)
reifyDecidedStrictness :: DataCon.HsImplBang -> TH.DecidedStrictness
reifyDecidedStrictness HsLazy = TH.DecidedLazy
reifyDecidedStrictness HsStrict = TH.DecidedStrict
reifyDecidedStrictness HsUnpack{} = TH.DecidedUnpack
reifyTypeOfThing :: TH.Name -> TcM TH.Type
reifyTypeOfThing th_name = do
thing <- getThing th_name
case thing of
AGlobal (AnId id) -> reifyType (idType id)
AGlobal (ATyCon tc) -> reifyKind (tyConKind tc)
AGlobal (AConLike (RealDataCon dc)) ->
reifyType (idType (dataConWrapId dc))
AGlobal (AConLike (PatSynCon ps)) ->
reifyPatSynType (patSynSigBndr ps)
ATcId{tct_id = id} -> zonkTcType (idType id) >>= reifyType
ATyVar _ tctv -> zonkTcTyVar tctv >>= reifyType
AGlobal (ACoAxiom _) -> panic "reifyTypeOfThing: ACoAxiom"
ATcTyCon _ -> panic "reifyTypeOfThing: ATcTyCon"
APromotionErr _ -> panic "reifyTypeOfThing: APromotionErr"
lookupThAnnLookup :: TH.AnnLookup -> TcM CoreAnnTarget
lookupThAnnLookup (TH.AnnLookupName th_nm) = fmap NamedTarget (lookupThName th_nm)
lookupThAnnLookup (TH.AnnLookupModule (TH.Module pn mn))
= return $ ModuleTarget $
mkModule (stringToUnit $ TH.pkgString pn) (mkModuleName $ TH.modString mn)
reifyAnnotations :: Data a => TH.AnnLookup -> TcM [a]
reifyAnnotations th_name
= do { name <- lookupThAnnLookup th_name
; topEnv <- getTopEnv
; epsHptAnns <- liftIO $ prepareAnnotations topEnv Nothing
; tcg <- getGblEnv
; let selectedEpsHptAnns = findAnns deserializeWithData epsHptAnns name
; let selectedTcgAnns = findAnns deserializeWithData (tcg_ann_env tcg) name
; return (selectedEpsHptAnns ++ selectedTcgAnns) }
modToTHMod :: Module -> TH.Module
modToTHMod m = TH.Module (TH.PkgName $ unitString $ moduleUnit m)
(TH.ModName $ moduleNameString $ moduleName m)
reifyModule :: TH.Module -> TcM TH.ModuleInfo
reifyModule (TH.Module (TH.PkgName pkgString) (TH.ModName mString)) = do
this_mod <- getModule
let reifMod = mkModule (stringToUnit pkgString) (mkModuleName mString)
if (reifMod == this_mod) then reifyThisModule else reifyFromIface reifMod
where
reifyThisModule = do
usages <- fmap (map modToTHMod . moduleEnvKeys . imp_mods) getImports
return $ TH.ModuleInfo usages
reifyFromIface reifMod = do
iface <- loadInterfaceForModule (text "reifying module from TH for" <+> ppr reifMod) reifMod
let usages = [modToTHMod m | usage <- mi_usages iface,
Just m <- [usageToModule (moduleUnit reifMod) usage] ]
return $ TH.ModuleInfo usages
usageToModule :: Unit -> Usage -> Maybe Module
usageToModule _ (UsageFile {}) = Nothing
usageToModule this_pkg (UsageHomeModule { usg_mod_name = mn }) = Just $ mkModule this_pkg mn
usageToModule _ (UsagePackageModule { usg_mod = m }) = Just m
usageToModule _ (UsageMergedRequirement { usg_mod = m }) = Just m
mkThAppTs :: TH.Type -> [TH.Type] -> TH.Type
mkThAppTs fun_ty arg_tys = foldl' TH.AppT fun_ty arg_tys
noTH :: PtrString -> SDoc -> TcM a
noTH s d = failWithTc (hsep [text "Can't represent" <+> ptext s <+>
text "in Template Haskell:",
nest 2 d])
ppr_th :: TH.Ppr a => a -> SDoc
ppr_th x = text (TH.pprint x)
tcGetInterp :: TcM Interp
tcGetInterp = do
hsc_env <- getTopEnv
case hsc_interp hsc_env of
Nothing -> liftIO $ throwIO (InstallationError "Template haskell requires a target code interpreter")
Just i -> pure i