summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2020-05-26 13:31:13 +0100
committerBen Gamari <ben@smart-cactus.org>2020-07-21 14:47:19 -0400
commita625719284db7c69fa3d122e829291a16960e85f (patch)
treeb15fb36d401ea100a93ec9baec4c6b8c36adffba /compiler/GHC/Tc
parent05910be1ac5c1f485132d2c8bd1ceb4f86e06db5 (diff)
downloadhaskell-a625719284db7c69fa3d122e829291a16960e85f.tar.gz
Use a newtype `Code` for the return type of typed quotations (Proposal #195)
There are three problems with the current API: 1. It is hard to properly write instances for ``Quote m => m (TExp a)`` as the type is the composition of two type constructors. Doing so in your program involves making your own newtype and doing a lot of wrapping/unwrapping. For example, if I want to create a language which I can either run immediately or generate code from I could write the following with the new API. :: class Lang r where _int :: Int -> r Int _if :: r Bool -> r a -> r a -> r a instance Lang Identity where _int = Identity _if (Identity b) (Identity t) (Identity f) = Identity (if b then t else f) instance Quote m => Lang (Code m) where _int = liftTyped _if cb ct cf = [|| if $$cb then $$ct else $$cf ||] 2. When doing code generation it is common to want to store code fragments in a map. When doing typed code generation, these code fragments contain a type index so it is desirable to store them in one of the parameterised map data types such as ``DMap`` from ``dependent-map`` or ``MapF`` from ``parameterized-utils``. :: compiler :: Env -> AST a -> Code Q a data AST a where ... data Ident a = ... type Env = MapF Ident (Code Q) newtype Code m a = Code (m (TExp a)) In this example, the ``MapF`` maps an ``Ident String`` directly to a ``Code Q String``. Using one of these map types currently requires creating your own newtype and constantly wrapping every quotation and unwrapping it when using a splice. Achievable, but it creates even more syntactic noise than normal metaprogramming. 3. ``m (TExp a)`` is ugly to read and write, understanding ``Code m a`` is easier. This is a weak reason but one everyone can surely agree with. Updates text submodule.
Diffstat (limited to 'compiler/GHC/Tc')
-rw-r--r--compiler/GHC/Tc/Deriv/Generate.hs25
-rw-r--r--compiler/GHC/Tc/Gen/Splice.hs10
2 files changed, 18 insertions, 17 deletions
diff --git a/compiler/GHC/Tc/Deriv/Generate.hs b/compiler/GHC/Tc/Deriv/Generate.hs
index f0655f5b4e..650bc16714 100644
--- a/compiler/GHC/Tc/Deriv/Generate.hs
+++ b/compiler/GHC/Tc/Deriv/Generate.hs
@@ -1621,7 +1621,7 @@ gen_Lift_binds loc tycon = (listToBag [lift_bind, liftTyped_bind], emptyBag)
where
lift_bind = mkFunBindEC 1 loc lift_RDR (nlHsApp pure_Expr)
(map (pats_etc mk_exp) data_cons)
- liftTyped_bind = mkFunBindEC 1 loc liftTyped_RDR (nlHsApp pure_Expr)
+ liftTyped_bind = mkFunBindEC 1 loc liftTyped_RDR (nlHsApp unsafeCodeCoerce_Expr . nlHsApp pure_Expr)
(map (pats_etc mk_texp) data_cons)
mk_exp = ExpBr noExtField
@@ -2461,17 +2461,18 @@ bs_RDRs = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) ..
cs_RDRs = [ mkVarUnqual (mkFastString ("c"++show i)) | i <- [(1::Int) .. ] ]
a_Expr, b_Expr, c_Expr, z_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr, false_Expr,
- true_Expr, pure_Expr :: LHsExpr GhcPs
-a_Expr = nlHsVar a_RDR
-b_Expr = nlHsVar b_RDR
-c_Expr = nlHsVar c_RDR
-z_Expr = nlHsVar z_RDR
-ltTag_Expr = nlHsVar ltTag_RDR
-eqTag_Expr = nlHsVar eqTag_RDR
-gtTag_Expr = nlHsVar gtTag_RDR
-false_Expr = nlHsVar false_RDR
-true_Expr = nlHsVar true_RDR
-pure_Expr = nlHsVar pure_RDR
+ true_Expr, pure_Expr, unsafeCodeCoerce_Expr :: LHsExpr GhcPs
+a_Expr = nlHsVar a_RDR
+b_Expr = nlHsVar b_RDR
+c_Expr = nlHsVar c_RDR
+z_Expr = nlHsVar z_RDR
+ltTag_Expr = nlHsVar ltTag_RDR
+eqTag_Expr = nlHsVar eqTag_RDR
+gtTag_Expr = nlHsVar gtTag_RDR
+false_Expr = nlHsVar false_RDR
+true_Expr = nlHsVar true_RDR
+pure_Expr = nlHsVar pure_RDR
+unsafeCodeCoerce_Expr = nlHsVar unsafeCodeCoerce_RDR
a_Pat, b_Pat, c_Pat, d_Pat, k_Pat, z_Pat :: LPat GhcPs
a_Pat = nlVarPat a_RDR
diff --git a/compiler/GHC/Tc/Gen/Splice.hs b/compiler/GHC/Tc/Gen/Splice.hs
index 55a74e87b1..c18ce5f3cf 100644
--- a/compiler/GHC/Tc/Gen/Splice.hs
+++ b/compiler/GHC/Tc/Gen/Splice.hs
@@ -197,7 +197,7 @@ tcTypedBracket rn_expr brack@(TExpBr _ expr) res_ty
; let rep = getRuntimeRep expr_ty
; meta_ty <- tcTExpTy m_var expr_ty
; ps' <- readMutVar ps_ref
- ; texpco <- tcLookupId unsafeTExpCoerceName
+ ; texpco <- tcLookupId unsafeCodeCoerceName
; tcWrapResultO (Shouldn'tHappenOrigin "TExpBr")
rn_expr
(unLoc (mkHsApp (mkLHsWrap (applyQuoteWrapper wrapper)
@@ -303,9 +303,9 @@ tcPendingSplice m_var (PendingRnSplice flavour splice_name expr)
tcTExpTy :: TcType -> TcType -> TcM TcType
tcTExpTy m_ty exp_ty
= do { unless (isTauTy exp_ty) $ addErr (err_msg exp_ty)
- ; texp <- tcLookupTyCon tExpTyConName
+ ; codeCon <- tcLookupTyCon codeTyConName
; let rep = getRuntimeRep exp_ty
- ; return (mkAppTy m_ty (mkTyConApp texp [rep, exp_ty])) }
+ ; return (mkTyConApp codeCon [rep, m_ty, exp_ty]) }
where
err_msg ty
= vcat [ text "Illegal polytype:" <+> ppr ty
@@ -620,10 +620,10 @@ tcNestedSplice pop_stage (TcPending ps_var lie_var q@(QuoteWrapper _ m_var)) spl
; expr' <- setStage pop_stage $
setConstraintVar lie_var $
tcCheckMonoExpr expr meta_exp_ty
- ; untypeq <- tcLookupId unTypeQName
+ ; untype_code <- tcLookupId unTypeCodeName
; let expr'' = mkHsApp
(mkLHsWrap (applyQuoteWrapper q)
- (nlHsTyApp untypeq [rep, res_ty])) expr'
+ (nlHsTyApp untype_code [rep, res_ty])) expr'
; ps <- readMutVar ps_var
; writeMutVar ps_var (PendingTcSplice splice_name expr'' : ps)