import qualified Language.Haskell.THSyntax as Meta
import HscTypes ( HscEnv(..), GhciMode(..), PersistentCompilerState(..), unQualInScope )
-import HsSyn ( HsBracket(..) )
+import HsSyn ( HsBracket(..), HsExpr(..) )
import Convert ( convertToHsExpr, convertToHsDecls )
import RnExpr ( rnExpr )
import RdrHsSyn ( RdrNameHsExpr, RdrNameHsDecl )
import RnHsSyn ( RenamedHsExpr )
-import TcExpr ( tcMonoExpr )
+import TcExpr ( tcCheckRho, tcMonoExpr )
import TcHsSyn ( TcExpr, TypecheckedHsExpr, mkHsLet, zonkTopExpr )
-import TcSimplify ( tcSimplifyTop )
+import TcSimplify ( tcSimplifyTop, tcSimplifyBracket )
+import TcUnify ( Expected, unifyTauTy, zapExpectedTo, zapExpectedType )
import TcType ( TcType, openTypeKind, mkAppTy )
-import TcEnv ( spliceOK, tcMetaTy )
+import TcEnv ( spliceOK, tcMetaTy, tcWithTempInstEnv, bracketOK )
import TcRnTypes ( TopEnv(..) )
-import TcMType ( newTyVarTy, zapToType )
+import TcMType ( newTyVarTy, UserTypeCtxt(ExprSigCtxt) )
+import TcMonoType ( tcHsSigType )
import Name ( Name )
import TcRnMonad
import TysWiredIn ( mkListTy )
-import DsMeta ( exprTyConName, declTyConName, decTyConName, qTyConName )
+import DsMeta ( expQTyConName, decQTyConName, typeQTyConName, decTyConName, qTyConName )
import ErrUtils (Message)
import Outputable
+import Panic ( showException )
import GHC.Base ( unsafeCoerce# ) -- Should have a better home in the module hierarchy
import Monad (liftM)
\end{code}
tcSpliceExpr :: Name
-> RenamedHsExpr
- -> TcType
+ -> Expected TcType
-> TcM TcExpr
#ifndef GHCI
%************************************************************************
%* *
-\subsection{Splicing an expression}
+\subsection{Quoting an expression}
%* *
%************************************************************************
\begin{code}
-tcBracket :: HsBracket Name -> TcM TcType
-tcBracket (ExpBr expr)
- = newTyVarTy openTypeKind `thenM` \ any_ty ->
- tcMonoExpr expr any_ty `thenM_`
- tcMetaTy exprTyConName
+tcBracket :: HsBracket Name -> Expected TcType -> TcM TcExpr
+tcBracket brack res_ty
+ = getStage `thenM` \ level ->
+ case bracketOK level of {
+ Nothing -> failWithTc (illegalBracket level) ;
+ Just next_level ->
+
+ -- Typecheck expr to make sure it is valid,
+ -- but throw away the results. We'll type check
+ -- it again when we actually use it.
+ newMutVar [] `thenM` \ pending_splices ->
+ getLIEVar `thenM` \ lie_var ->
+
+ setStage (Brack next_level pending_splices lie_var) (
+ getLIE (tc_bracket brack)
+ ) `thenM` \ (meta_ty, lie) ->
+ tcSimplifyBracket lie `thenM_`
+
+ -- Make the expected type have the right shape
+ zapExpectedTo res_ty meta_ty `thenM_`
+
+ -- Return the original expression, not the type-decorated one
+ readMutVar pending_splices `thenM` \ pendings ->
+ returnM (HsBracketOut brack pendings)
+ }
+
+tc_bracket :: HsBracket Name -> TcM TcType
+tc_bracket (ExpBr expr)
+ = newTyVarTy openTypeKind `thenM` \ any_ty ->
+ tcCheckRho expr any_ty `thenM_`
+ tcMetaTy expQTyConName
-- Result type is Expr (= Q Exp)
-tcBracket (DecBr decls)
- = tcTopSrcDecls decls `thenM_`
+tc_bracket (TypBr typ)
+ = tcHsSigType ExprSigCtxt typ `thenM_`
+ tcMetaTy typeQTyConName
+ -- Result type is Type (= Q Typ)
+
+tc_bracket (DecBr decls)
+ = tcWithTempInstEnv (tcTopSrcDecls decls) `thenM_`
+ -- Typecheck the declarations, dicarding any side effects
+ -- on the instance environment (which is in a mutable variable)
+ -- and the extended environment. We'll get all that stuff
+ -- later, when we splice it in
+
tcMetaTy decTyConName `thenM` \ decl_ty ->
tcMetaTy qTyConName `thenM` \ q_ty ->
returnM (mkAppTy q_ty (mkListTy decl_ty))
-- Here (h 4) :: Q Exp
-- but $(h 4) :: forall a.a i.e. anything!
- zapToType res_ty `thenM_`
- tcMetaTy exprTyConName `thenM` \ meta_exp_ty ->
+ zapExpectedType res_ty `thenM_`
+ tcMetaTy expQTyConName `thenM` \ meta_exp_ty ->
setStage (Splice next_level) (
setLIEVar lie_var $
- tcMonoExpr expr meta_exp_ty
+ tcCheckRho expr meta_exp_ty
) `thenM` \ expr' ->
-- Write the pending splice into the bucket
-- inner escape before dealing with the outer one
tcTopSplice expr res_ty
- = tcMetaTy exprTyConName `thenM` \ meta_exp_ty ->
- setStage topSpliceStage (
- getLIE (tcMonoExpr expr meta_exp_ty)
- ) `thenM` \ (expr', lie) ->
+ = tcMetaTy expQTyConName `thenM` \ meta_exp_ty ->
- -- Solve the constraints
- tcSimplifyTop lie `thenM` \ const_binds ->
- let
- q_expr = mkHsLet const_binds expr'
- in
- zonkTopExpr q_expr `thenM` \ zonked_q_expr ->
+ -- Typecheck the expression
+ tcTopSpliceExpr expr meta_exp_ty `thenM` \ zonked_q_expr ->
-- Run the expression
traceTc (text "About to run" <+> ppr zonked_q_expr) `thenM_`
importSupportingDecls fvs `thenM` \ env ->
setGblEnv env (tcMonoExpr exp3 res_ty)
+
+
+tcTopSpliceExpr :: RenamedHsExpr -> TcType -> TcM TypecheckedHsExpr
+-- Type check an expression that is the body of a top-level splice
+-- (the caller will compile and run it)
+tcTopSpliceExpr expr meta_ty
+ = checkNoErrs $ -- checkNoErrs: must not try to run the thing
+ -- if the type checker fails!
+
+ setStage topSpliceStage $
+
+ -- Typecheck the expression
+ getLIE (tcCheckRho expr meta_ty) `thenM` \ (expr', lie) ->
+
+ -- Solve the constraints
+ tcSimplifyTop lie `thenM` \ const_binds ->
+
+ -- And zonk it
+ zonkTopExpr (mkHsLet const_binds expr')
\end{code}
tcSpliceDecls expr
= tcMetaTy decTyConName `thenM` \ meta_dec_ty ->
tcMetaTy qTyConName `thenM` \ meta_q_ty ->
- setStage topSpliceStage (
- getLIE (tcMonoExpr expr (mkAppTy meta_q_ty (mkListTy meta_dec_ty)))
- ) `thenM` \ (expr', lie) ->
- -- Solve the constraints
- tcSimplifyTop lie `thenM` \ const_binds ->
- let
- q_expr = mkHsLet const_binds expr'
+ let
+ list_q = mkAppTy meta_q_ty (mkListTy meta_dec_ty)
in
- zonkTopExpr q_expr `thenM` \ zonked_q_expr ->
+ tcTopSpliceExpr expr list_q `thenM` \ zonked_q_expr ->
-- Run the expression
traceTc (text "About to run" <+> ppr zonked_q_expr) `thenM_`
-> TcM [Meta.Dec] -- Of type [Dec]
runMetaD e = runMeta e
-tcRunQ :: Meta.Q a -> TcM a
-tcRunQ thing = ioToTcRn (Meta.runQ thing)
-
runMeta :: TypecheckedHsExpr -- Of type X
-> TcM t -- Of type t
runMeta expr
type_env = tcg_type_env tcg_env
rdr_env = tcg_rdr_env tcg_env
in
- ioToTcRn (HscMain.compileExpr
- hsc_env pcs this_mod
- rdr_env type_env expr) `thenM` \ hval ->
-
- tryM (tcRunQ (unsafeCoerce# hval)) `thenM` \ either_tval ->
+ -- Wrap the compile-and-run in an exception-catcher
+ -- Compiling might fail if linking fails
+ -- Running might fail if it throws an exception
+ tryM (ioToTcRn (do
+ hval <- HscMain.compileExpr
+ hsc_env pcs this_mod
+ rdr_env type_env expr
+ Meta.runQ (unsafeCoerce# hval) -- Coerce it to Q t, and run it
+ )) `thenM` \ either_tval ->
case either_tval of
- Left exn -> failWithTc (vcat [text "Exception when running compile-time code:",
+ Left exn -> failWithTc (vcat [text "Exception when trying to run compile-time code:",
nest 4 (vcat [text "Code:" <+> ppr expr,
- text ("Exn: " ++ show exn)])])
+ text ("Exn: " ++ Panic.showException exn)])])
Right v -> returnM v
\end{code}
text "======>",
nest 2 after])])
+illegalBracket level
+ = ptext SLIT("Illegal bracket at level") <+> ppr level
+
illegalSplice level
= ptext SLIT("Illegal splice at level") <+> ppr level