[project @ 2003-01-10 14:20:41 by simonpj]
[ghc-hetmet.git] / ghc / compiler / typecheck / TcSplice.lhs
index e269f9f..a5ebd6e 100644 (file)
@@ -1,4 +1,4 @@
-%
+2%
 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 \section[TcSplice]{Template Haskell splices}
@@ -24,17 +24,20 @@ import RnHsSyn              ( RenamedHsExpr )
 import TcExpr          ( tcMonoExpr )
 import TcHsSyn         ( TcExpr, TypecheckedHsExpr, mkHsLet, zonkTopExpr )
 import TcSimplify      ( tcSimplifyTop )
-import TcType          ( TcType, openTypeKind )
+import TcType          ( TcType, openTypeKind, mkAppTy )
 import TcEnv           ( spliceOK, tcMetaTy )
 import TcRnTypes       ( TopEnv(..) )
-import TcMType         ( newTyVarTy )
+import TcMType         ( newTyVarTy, zapToType )
 import Name            ( Name )
 import TcRnMonad
 
 import TysWiredIn      ( mkListTy )
-import DsMeta          ( exprTyConName, declTyConName )
+import DsMeta          ( exprTyConName, declTyConName, 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}
 
 
@@ -70,13 +73,17 @@ tcBracket (ExpBr expr)
   = newTyVarTy openTypeKind            `thenM` \ any_ty ->
     tcMonoExpr expr any_ty             `thenM_`
     tcMetaTy exprTyConName
+       -- Result type is Expr (= Q Exp)
 
 tcBracket (DecBr decls)
   = tcTopSrcDecls decls                        `thenM_`
-    tcMetaTy declTyConName             `thenM` \ decl_ty ->
-    returnM (mkListTy decl_ty)
+    tcMetaTy decTyConName              `thenM` \ decl_ty ->
+    tcMetaTy qTyConName                        `thenM` \ q_ty ->
+    returnM (mkAppTy q_ty (mkListTy decl_ty))
+       -- Result type is Q [Dec]
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection{Splicing an expression}
@@ -95,11 +102,12 @@ tcSpliceExpr name expr res_ty
        Brack _ ps_var lie_var ->  
 
        -- A splice inside brackets
-       -- NB: ignore res_ty
+       -- NB: ignore res_ty, apart from zapping it to a mono-type
        -- e.g.   [| reverse $(h 4) |]
        -- Here (h 4) :: Q Exp
        -- but $(h 4) :: forall a.a     i.e. anything!
 
+    zapToType res_ty                           `thenM_`
     tcMetaTy exprTyConName                     `thenM` \ meta_exp_ty ->
     setStage (Splice next_level) (
        setLIEVar lie_var          $
@@ -121,17 +129,21 @@ tcSpliceExpr name expr res_ty
 -- 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) ->
+  = checkNoErrs (
+       -- checkNoErrs: must not try to run the thing
+       --              if the type checker fails!
+
+       tcMetaTy exprTyConName          `thenM` \ meta_exp_ty ->
+       setStage topSpliceStage (
+         getLIE (tcMonoExpr expr meta_exp_ty)
+        )                              `thenM` \ (expr', lie) ->
 
        -- Solve the constraints
-    tcSimplifyTop lie                  `thenM` \ const_binds ->
-    let 
-       q_expr = mkHsLet const_binds expr'
-    in
-    zonkTopExpr q_expr                 `thenM` \ zonked_q_expr ->
+       tcSimplifyTop lie               `thenM` \ const_binds ->
+
+       -- Wrap the bindings around it and zonk
+       zonkTopExpr (mkHsLet const_binds expr')
+    )                                  `thenM` \ zonked_q_expr ->
 
        -- Run the expression
     traceTc (text "About to run" <+> ppr zonked_q_expr)        `thenM_`
@@ -144,6 +156,9 @@ tcTopSplice expr res_ty
        expr2 = convertToHsExpr simple_expr 
     in
     traceTc (text "Got result" <+> ppr expr2)  `thenM_`
+
+    showSplice "expression" 
+              zonked_q_expr (ppr expr2)        `thenM_`
     initRn SourceMode (rnExpr expr2)           `thenM` \ (exp3, fvs) ->
     importSupportingDecls fvs                  `thenM` \ env ->
 
@@ -160,9 +175,10 @@ tcTopSplice expr res_ty
 \begin{code}
 -- Always at top level
 tcSpliceDecls expr
-  = tcMetaTy declTyConName             `thenM` \ meta_dec_ty ->
+  = tcMetaTy decTyConName              `thenM` \ meta_dec_ty ->
+    tcMetaTy qTyConName                `thenM` \ meta_q_ty ->
     setStage topSpliceStage (
-       getLIE (tcMonoExpr expr (mkListTy meta_dec_ty))
+       getLIE (tcMonoExpr expr (mkAppTy meta_q_ty (mkListTy meta_dec_ty)))
     )                                  `thenM` \ (expr', lie) ->
        -- Solve the constraints
     tcSimplifyTop lie                  `thenM` \ const_binds ->
@@ -174,13 +190,19 @@ tcSpliceDecls expr
        -- Run the expression
     traceTc (text "About to run" <+> ppr zonked_q_expr)        `thenM_`
     runMetaD zonked_q_expr             `thenM` \ simple_expr ->
-    let 
-       -- simple_expr :: [Meta.Dec]
-       decls :: [RdrNameHsDecl]
-       decls = convertToHsDecls simple_expr 
-    in
+    -- simple_expr :: [Meta.Dec]
+    -- decls :: [RdrNameHsDecl]
+    handleErrors (convertToHsDecls simple_expr) `thenM` \ decls ->
     traceTc (text "Got result" <+> vcat (map ppr decls))       `thenM_`
+    showSplice "declarations"
+              zonked_q_expr (vcat (map ppr decls))             `thenM_`
     returnM decls
+
+  where handleErrors :: [Either a Message] -> TcM [a]
+        handleErrors [] = return []
+        handleErrors (Left x:xs) = liftM (x:) (handleErrors xs)
+        handleErrors (Right m:xs) = do addErrTc m
+                                       handleErrors xs
 \end{code}
 
 
@@ -193,29 +215,20 @@ tcSpliceDecls expr
 \begin{code}
 runMetaE :: TypecheckedHsExpr  -- Of type (Q Exp)
         -> TcM Meta.Exp        -- Of type Exp
-runMetaE e = runMeta tcRunQ e
+runMetaE e = runMeta e
 
-runMetaD :: TypecheckedHsExpr  -- Of type [Q Dec]
+runMetaD :: TypecheckedHsExpr  -- Of type Q [Dec]
         -> TcM [Meta.Dec]      -- Of type [Dec]
-runMetaD e = runMeta run_decl e
-          where
-            run_decl :: [Meta.Decl] -> TcM [Meta.Dec]
-            run_decl ds = mappM tcRunQ ds
+runMetaD e = runMeta e
 
--- Warning: if Q is anything other than IO, we need to change this
-tcRunQ :: Meta.Q a -> TcM a
-tcRunQ thing = ioToTcRn thing
-
-
-runMeta :: (x -> TcM t)                -- :: X -> IO t
-       -> TypecheckedHsExpr    -- Of type X
+runMeta :: TypecheckedHsExpr   -- Of type X
        -> TcM t                -- Of type t
-runMeta run_it expr :: TcM t
+runMeta expr
   = getTopEnv          `thenM` \ top_env ->
+    getGblEnv          `thenM` \ tcg_env ->
     getEps             `thenM` \ eps ->
     getNameCache       `thenM` \ name_cache -> 
     getModule          `thenM` \ this_mod ->
-    getGlobalRdrEnv    `thenM` \ rdr_env -> 
     let
        ghci_mode = top_mode top_env
 
@@ -224,24 +237,23 @@ runMeta run_it expr :: TcM t
 
        pcs = PCS { pcs_nc = name_cache, pcs_EPS = eps }
 
-       print_unqual = unQualInScope rdr_env
+       type_env = tcg_type_env tcg_env
+       rdr_env  = tcg_rdr_env tcg_env
     in
-    if (ghci_mode == OneShot) then
-       failWithTc (ptext SLIT("You must use --make or --interactive to run splice expressions"))
-       -- The reason for this is that the demand-linker doesn't have
-       -- enough information available to link all the things that
-       -- are needed when you try to run a splice
-    else
-
-    ioToTcRn (HscMain.compileExpr hsc_env pcs this_mod 
-                                 print_unqual expr) `thenM` \ hval ->
-
-    tryM (run_it (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}
 
@@ -341,6 +353,14 @@ Two successive brackets aren't allowed
 %************************************************************************
 
 \begin{code}
+showSplice :: String -> TypecheckedHsExpr -> SDoc -> TcM ()
+showSplice what before after
+  = getSrcLocM         `thenM` \ loc ->
+    traceSplice (vcat [ppr loc <> colon <+> text "Splicing" <+> text what, 
+                      nest 2 (sep [nest 2 (ppr before),
+                                   text "======>",
+                                   nest 2 after])])
+
 illegalSplice level
   = ptext SLIT("Illegal splice at level") <+> ppr level