summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorRyanGlScott <ryan.gl.scott@gmail.com>2015-09-21 21:50:55 -0500
committerAustin Seipp <austin@well-typed.com>2015-09-21 21:50:56 -0500
commit089b72f524a6a7564346baca9595fcd07081ec40 (patch)
tree2354366bd18fe44ddbcbe4953e172f345a374b66 /compiler
parentd4d34a73aacc225a8f28d7138137bf548c9e51cc (diff)
downloadhaskell-089b72f524a6a7564346baca9595fcd07081ec40.tar.gz
DeriveLift extension (#1830)
Summary: This implements -XDeriveLift, which allows for automatic derivation of the Lift class from template-haskell. The implementation is based off of Ian Lynagh's th-lift library (http://hackage.haskell.org/package/th-lift). Test Plan: ./validate Reviewers: hvr, simonpj, bgamari, goldfire, austin Reviewed By: goldfire, austin Subscribers: osa1, thomie Differential Revision: https://phabricator.haskell.org/D1168 GHC Trac Issues: #1830
Diffstat (limited to 'compiler')
-rw-r--r--compiler/main/DynFlags.hs2
-rw-r--r--compiler/prelude/PrelNames.hs9
-rw-r--r--compiler/prelude/THNames.hs49
-rw-r--r--compiler/typecheck/TcDeriv.hs13
-rw-r--r--compiler/typecheck/TcGenDeriv.hs127
5 files changed, 191 insertions, 9 deletions
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 802f264e36..0978c1132c 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -613,6 +613,7 @@ data ExtensionFlag
| Opt_DeriveGeneric -- Allow deriving Generic/1
| Opt_DefaultSignatures -- Allow extra signatures for defmeths
| Opt_DeriveAnyClass -- Allow deriving any class
+ | Opt_DeriveLift -- Allow deriving Lift
| Opt_TypeSynonymInstances
| Opt_FlexibleContexts
@@ -3133,6 +3134,7 @@ xFlags = [
flagSpec "DeriveFoldable" Opt_DeriveFoldable,
flagSpec "DeriveFunctor" Opt_DeriveFunctor,
flagSpec "DeriveGeneric" Opt_DeriveGeneric,
+ flagSpec "DeriveLift" Opt_DeriveLift,
flagSpec "DeriveTraversable" Opt_DeriveTraversable,
flagSpec "DisambiguateRecordFields" Opt_DisambiguateRecordFields,
flagSpec "DoAndIfThenElse" Opt_DoAndIfThenElse,
diff --git a/compiler/prelude/PrelNames.hs b/compiler/prelude/PrelNames.hs
index 1684a2f3e0..a6eb834641 100644
--- a/compiler/prelude/PrelNames.hs
+++ b/compiler/prelude/PrelNames.hs
@@ -599,6 +599,11 @@ minus_RDR = nameRdrName minusName
times_RDR = varQual_RDR gHC_NUM (fsLit "*")
plus_RDR = varQual_RDR gHC_NUM (fsLit "+")
+toInteger_RDR, toRational_RDR, fromIntegral_RDR :: RdrName
+toInteger_RDR = nameRdrName toIntegerName
+toRational_RDR = nameRdrName toRationalName
+fromIntegral_RDR = nameRdrName fromIntegralName
+
fromString_RDR :: RdrName
fromString_RDR = nameRdrName fromStringName
@@ -1305,6 +1310,10 @@ knownSymbolClassNameKey = mkPreludeClassUnique 43
ghciIoClassKey :: Unique
ghciIoClassKey = mkPreludeClassUnique 44
+---------------- Template Haskell -------------------
+-- USES ClassUniques 200-299
+-----------------------------------------------------
+
{-
************************************************************************
* *
diff --git a/compiler/prelude/THNames.hs b/compiler/prelude/THNames.hs
index 9367d4b85a..d3deb49ba2 100644
--- a/compiler/prelude/THNames.hs
+++ b/compiler/prelude/THNames.hs
@@ -9,7 +9,8 @@ module THNames where
import PrelNames( mk_known_key_name )
import Module( Module, mkModuleNameFS, mkModule, thPackageKey )
import Name( Name )
-import OccName( tcName, dataName, varName )
+import OccName( tcName, clsName, dataName, varName )
+import RdrName( RdrName, nameRdrName )
import Unique
import FastString
@@ -122,6 +123,9 @@ templateHaskellNames = [
-- AnnTarget
valueAnnotationName, typeAnnotationName, moduleAnnotationName,
+ -- The type classes
+ liftClassName,
+
-- And the tycons
qTyConName, nameTyConName, patTyConName, fieldPatTyConName, matchQTyConName,
clauseQTyConName, expQTyConName, fieldExpTyConName, predTyConName,
@@ -143,15 +147,19 @@ qqLib = mkTHModule (fsLit "Language.Haskell.TH.Quote")
mkTHModule :: FastString -> Module
mkTHModule m = mkModule thPackageKey (mkModuleNameFS m)
-libFun, libTc, thFun, thTc, thCon, qqFun :: FastString -> Unique -> Name
+libFun, libTc, thFun, thTc, thCls, thCon, qqFun :: FastString -> Unique -> Name
libFun = mk_known_key_name OccName.varName thLib
libTc = mk_known_key_name OccName.tcName thLib
thFun = mk_known_key_name OccName.varName thSyn
thTc = mk_known_key_name OccName.tcName thSyn
+thCls = mk_known_key_name OccName.clsName thSyn
thCon = mk_known_key_name OccName.dataName thSyn
qqFun = mk_known_key_name OccName.varName qqLib
-------------------- TH.Syntax -----------------------
+liftClassName :: Name
+liftClassName = thCls (fsLit "Lift") liftClassKey
+
qTyConName, nameTyConName, fieldExpTyConName, patTyConName,
fieldPatTyConName, expTyConName, decTyConName, typeTyConName,
tyVarBndrTyConName, matchTyConName, clauseTyConName, funDepTyConName,
@@ -512,6 +520,12 @@ quotePatName = qqFun (fsLit "quotePat") quotePatKey
quoteDecName = qqFun (fsLit "quoteDec") quoteDecKey
quoteTypeName = qqFun (fsLit "quoteType") quoteTypeKey
+-- ClassUniques available: 200-299
+-- Check in PrelNames if you want to change this
+
+liftClassKey :: Unique
+liftClassKey = mkPreludeClassUnique 200
+
-- TyConUniques available: 200-299
-- Check in PrelNames if you want to change this
@@ -873,3 +887,34 @@ valueAnnotationIdKey, typeAnnotationIdKey, moduleAnnotationIdKey :: Unique
valueAnnotationIdKey = mkPreludeMiscIdUnique 490
typeAnnotationIdKey = mkPreludeMiscIdUnique 491
moduleAnnotationIdKey = mkPreludeMiscIdUnique 492
+
+{-
+************************************************************************
+* *
+ RdrNames
+* *
+************************************************************************
+-}
+
+lift_RDR, mkNameG_dRDR, mkNameG_vRDR :: RdrName
+lift_RDR = nameRdrName liftName
+mkNameG_dRDR = nameRdrName mkNameG_dName
+mkNameG_vRDR = nameRdrName mkNameG_vName
+
+-- data Exp = ...
+conE_RDR, litE_RDR, appE_RDR, infixApp_RDR :: RdrName
+conE_RDR = nameRdrName conEName
+litE_RDR = nameRdrName litEName
+appE_RDR = nameRdrName appEName
+infixApp_RDR = nameRdrName infixAppName
+
+-- data Lit = ...
+stringL_RDR, intPrimL_RDR, wordPrimL_RDR, floatPrimL_RDR,
+ doublePrimL_RDR, stringPrimL_RDR, charPrimL_RDR :: RdrName
+stringL_RDR = nameRdrName stringLName
+intPrimL_RDR = nameRdrName intPrimLName
+wordPrimL_RDR = nameRdrName wordPrimLName
+floatPrimL_RDR = nameRdrName floatPrimLName
+doublePrimL_RDR = nameRdrName doublePrimLName
+stringPrimL_RDR = nameRdrName stringPrimLName
+charPrimL_RDR = nameRdrName charPrimLName
diff --git a/compiler/typecheck/TcDeriv.hs b/compiler/typecheck/TcDeriv.hs
index d76302fc37..58aeb2edc9 100644
--- a/compiler/typecheck/TcDeriv.hs
+++ b/compiler/typecheck/TcDeriv.hs
@@ -54,6 +54,7 @@ import TcType
import Var
import VarSet
import PrelNames
+import THNames ( liftClassKey )
import SrcLoc
import Util
import Outputable
@@ -1170,6 +1171,9 @@ sideConditions mtheta cls
| cls_key == gen1ClassKey = Just (checkFlag Opt_DeriveGeneric `andCond`
cond_vanilla `andCond`
cond_Representable1Ok)
+ | cls_key == liftClassKey = Just (checkFlag Opt_DeriveLift `andCond`
+ cond_vanilla `andCond`
+ cond_args cls)
| otherwise = Nothing
where
cls_key = getUnique cls
@@ -1257,6 +1261,7 @@ cond_args cls (_, tc, _)
| cls_key == eqClassKey = check_in arg_ty ordOpTbl
| cls_key == ordClassKey = check_in arg_ty ordOpTbl
| cls_key == showClassKey = check_in arg_ty boxConTbl
+ | cls_key == liftClassKey = check_in arg_ty litConTbl
| otherwise = False -- Read, Ix etc
check_in :: Type -> [(Type,a)] -> Bool
@@ -1355,20 +1360,20 @@ std_class_via_coercible :: Class -> Bool
-- because giving so gives the same results as generating the boilerplate
std_class_via_coercible clas
= classKey clas `elem` [eqClassKey, ordClassKey, ixClassKey, boundedClassKey]
- -- Not Read/Show because they respect the type
+ -- Not Read/Show/Lift because they respect the type
-- Not Enum, because newtypes are never in Enum
non_coercible_class :: Class -> Bool
--- *Never* derive Read, Show, Typeable, Data, Generic, Generic1 by Coercible,
--- even with -XGeneralizedNewtypeDeriving
+-- *Never* derive Read, Show, Typeable, Data, Generic, Generic1, Lift
+-- by Coercible, even with -XGeneralizedNewtypeDeriving
-- Also, avoid Traversable, as the Coercible-derived instance and the "normal"-derived
-- instance behave differently if there's a non-lawful Applicative out there.
-- Besides, with roles, Coercible-deriving Traversable is ill-roled.
non_coercible_class cls
= classKey cls `elem` ([ readClassKey, showClassKey, dataClassKey
, genClassKey, gen1ClassKey, typeableClassKey
- , traversableClassKey ])
+ , traversableClassKey, liftClassKey ])
new_dfun_name :: Class -> TyCon -> TcM Name
new_dfun_name clas tycon -- Just a simple wrapper
diff --git a/compiler/typecheck/TcGenDeriv.hs b/compiler/typecheck/TcGenDeriv.hs
index 5f6a021a4c..b60fc8c032 100644
--- a/compiler/typecheck/TcGenDeriv.hs
+++ b/compiler/typecheck/TcGenDeriv.hs
@@ -25,7 +25,7 @@ module TcGenDeriv (
mkCoerceClassMethEqn,
gen_Newtype_binds,
genAuxBinds,
- ordOpTbl, boxConTbl,
+ ordOpTbl, boxConTbl, litConTbl,
mkRdrFunBind
) where
@@ -44,6 +44,9 @@ import PrelInfo
import FamInstEnv( FamInst )
import MkCore ( eRROR_ID )
import PrelNames hiding (error_RDR)
+import THNames
+import Module ( moduleName, moduleNameString
+ , modulePackageKey, packageKeyString )
import MkId ( coerceId )
import PrimOp
import SrcLoc
@@ -130,8 +133,8 @@ genDerivedBinds dflags fix_env clas loc tycon
, (dataClassKey, gen_Data_binds dflags)
, (functorClassKey, gen_Functor_binds)
, (foldableClassKey, gen_Foldable_binds)
- , (traversableClassKey, gen_Traversable_binds) ]
-
+ , (traversableClassKey, gen_Traversable_binds)
+ , (liftClassKey, gen_Lift_binds) ]
-- Nothing: we can (try to) derive it via Generics
-- Just s: we can't, reason s
@@ -1887,6 +1890,90 @@ gen_Traversable_binds loc tycon
{-
************************************************************************
* *
+ Lift instances
+* *
+************************************************************************
+
+Example:
+
+ data Foo a = Foo a | a :^: a deriving Lift
+
+ ==>
+
+ instance (Lift a) => Lift (Foo a) where
+ lift (Foo a)
+ = appE
+ (conE
+ (mkNameG_d "package-name" "ModuleName" "Foo"))
+ (lift a)
+ lift (u :^: v)
+ = infixApp
+ (lift u)
+ (conE
+ (mkNameG_d "package-name" "ModuleName" ":^:"))
+ (lift v)
+
+Note that (mkNameG_d "package-name" "ModuleName" "Foo") is equivalent to what
+'Foo would be when using the -XTemplateHaskell extension. To make sure that
+-XDeriveLift can be used on stage-1 compilers, however, we expliticly invoke
+makeG_d.
+-}
+
+gen_Lift_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)
+gen_Lift_binds loc tycon
+ | null data_cons = (unitBag (L loc $ mkFunBind (L loc lift_RDR)
+ [mkMatch [nlWildPat] errorMsg_Expr emptyLocalBinds])
+ , emptyBag)
+ | otherwise = (unitBag lift_bind, emptyBag)
+ where
+ errorMsg_Expr = nlHsVar error_RDR `nlHsApp` nlHsLit
+ (mkHsString $ "Can't lift value of empty datatype " ++ tycon_str)
+
+ lift_bind = mk_FunBind loc lift_RDR (map pats_etc data_cons)
+ data_cons = tyConDataCons tycon
+ tycon_str = occNameString . nameOccName . tyConName $ tycon
+
+ pats_etc data_con
+ = ([con_pat], lift_Expr)
+ where
+ con_pat = nlConVarPat data_con_RDR as_needed
+ data_con_RDR = getRdrName data_con
+ con_arity = dataConSourceArity data_con
+ as_needed = take con_arity as_RDRs
+ lifted_as = zipWithEqual "mk_lift_app" mk_lift_app
+ tys_needed as_needed
+ tycon_name = tyConName tycon
+ is_infix = dataConIsInfix data_con
+ tys_needed = dataConOrigArgTys data_con
+
+ mk_lift_app ty a
+ | not (isUnLiftedType ty) = nlHsApp (nlHsVar lift_RDR)
+ (nlHsVar a)
+ | otherwise = nlHsApp (nlHsVar litE_RDR)
+ (primLitOp (mkBoxExp (nlHsVar a)))
+ where (primLitOp, mkBoxExp) = primLitOps "Lift" tycon ty
+
+ pkg_name = packageKeyString . modulePackageKey
+ . nameModule $ tycon_name
+ mod_name = moduleNameString . moduleName . nameModule $ tycon_name
+ con_name = occNameString . nameOccName . dataConName $ data_con
+
+ conE_Expr = nlHsApp (nlHsVar conE_RDR)
+ (nlHsApps mkNameG_dRDR
+ (map (nlHsLit . mkHsString)
+ [pkg_name, mod_name, con_name]))
+
+ lift_Expr
+ | is_infix = nlHsApps infixApp_RDR [a1, conE_Expr, a2]
+ | otherwise = foldl mk_appE_app conE_Expr lifted_as
+ (a1:a2:_) = lifted_as
+
+mk_appE_app :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName
+mk_appE_app a b = nlHsApps appE_RDR [a, b]
+
+{-
+************************************************************************
+* *
Newtype-deriving instances
* *
************************************************************************
@@ -2106,6 +2193,20 @@ primOrdOps :: String -- The class involved
-- See Note [Deriving and unboxed types] in TcDeriv
primOrdOps str tycon ty = assoc_ty_id str tycon ordOpTbl ty
+primLitOps :: String -- The class involved
+ -> TyCon -- The tycon involved
+ -> Type -- The type
+ -> ( LHsExpr RdrName -> LHsExpr RdrName -- Constructs a Q Exp value
+ , LHsExpr RdrName -> LHsExpr RdrName -- Constructs a boxed value
+ )
+primLitOps str tycon ty = ( assoc_ty_id str tycon litConTbl ty
+ , \v -> nlHsVar boxRDR `nlHsApp` v
+ )
+ where
+ boxRDR
+ | ty == addrPrimTy = unpackCString_RDR
+ | otherwise = assoc_ty_id str tycon boxConTbl ty
+
ordOpTbl :: [(Type, (RdrName, RdrName, RdrName, RdrName, RdrName))]
ordOpTbl
= [(charPrimTy , (ltChar_RDR , leChar_RDR , eqChar_RDR , geChar_RDR , gtChar_RDR ))
@@ -2134,6 +2235,26 @@ postfixModTbl
,(doublePrimTy, "##")
]
+litConTbl :: [(Type, LHsExpr RdrName -> LHsExpr RdrName)]
+litConTbl
+ = [(charPrimTy , nlHsApp (nlHsVar charPrimL_RDR))
+ ,(intPrimTy , nlHsApp (nlHsVar intPrimL_RDR)
+ . nlHsApp (nlHsVar toInteger_RDR))
+ ,(wordPrimTy , nlHsApp (nlHsVar wordPrimL_RDR)
+ . nlHsApp (nlHsVar toInteger_RDR))
+ ,(addrPrimTy , nlHsApp (nlHsVar stringPrimL_RDR)
+ . nlHsApp (nlHsApp
+ (nlHsVar map_RDR)
+ (compose_RDR `nlHsApps`
+ [ nlHsVar fromIntegral_RDR
+ , nlHsVar fromEnum_RDR
+ ])))
+ ,(floatPrimTy , nlHsApp (nlHsVar floatPrimL_RDR)
+ . nlHsApp (nlHsVar toRational_RDR))
+ ,(doublePrimTy, nlHsApp (nlHsVar doublePrimL_RDR)
+ . nlHsApp (nlHsVar toRational_RDR))
+ ]
+
-- | Lookup `Type` in an association list.
assoc_ty_id :: String -- The class involved
-> TyCon -- The tycon involved