summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Scott <ryan.gl.scott@gmail.com>2016-09-30 20:15:25 -0400
committerBen Gamari <ben@smart-cactus.org>2016-09-30 23:23:44 -0400
commit9e862765ffe161da8a4fd9cd67b0a600874feaa9 (patch)
tree235c1ba702b0101e1fa6a8fe7f8146e2c7ec9c69
parentb3d55e20d20344bfc09f4ca4a554a819c4ecbfa8 (diff)
downloadhaskell-9e862765ffe161da8a4fd9cd67b0a600874feaa9.tar.gz
Implement deriving strategies
Allows users to explicitly request which approach to `deriving` to use via keywords, e.g., ``` newtype Foo = Foo Bar deriving Eq deriving stock Ord deriving newtype Show ``` Fixes #10598. Updates haddock submodule. Test Plan: ./validate Reviewers: hvr, kosmikus, goldfire, alanz, bgamari, simonpj, austin, erikd, simonmar Reviewed By: alanz, bgamari, simonpj Subscribers: thomie, mpickering, oerjan Differential Revision: https://phabricator.haskell.org/D2280 GHC Trac Issues: #10598
-rw-r--r--compiler/basicTypes/BasicTypes.hs26
-rw-r--r--compiler/deSugar/DsMeta.hs57
-rw-r--r--compiler/hsSyn/Convert.hs27
-rw-r--r--compiler/hsSyn/HsDecls.hs89
-rw-r--r--compiler/main/DynFlags.hs1
-rw-r--r--compiler/main/HscStats.hs8
-rw-r--r--compiler/parser/ApiAnnotation.hs4
-rw-r--r--compiler/parser/Lexer.x4
-rw-r--r--compiler/parser/Parser.y126
-rw-r--r--compiler/prelude/THNames.hs151
-rw-r--r--compiler/rename/RnSource.hs45
-rw-r--r--compiler/rename/RnTypes.hs4
-rw-r--r--compiler/typecheck/TcDeriv.hs554
-rw-r--r--compiler/typecheck/TcGenDeriv.hs21
-rw-r--r--compiler/typecheck/TcInstDcls.hs10
-rw-r--r--docs/users_guide/8.2.1-notes.rst4
-rw-r--r--docs/users_guide/glasgow_exts.rst62
-rw-r--r--docs/users_guide/safe_haskell.rst7
-rw-r--r--libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs1
-rw-r--r--libraries/ghci/GHCi/TH/Binary.hs2
-rw-r--r--libraries/template-haskell/Language/Haskell/TH.hs13
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Lib.hs32
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Ppr.hs29
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Syntax.hs40
-rw-r--r--libraries/template-haskell/changelog.md3
-rw-r--r--testsuite/driver/extra_files.py1
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail1.hs11
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail1.stderr17
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail2.hs5
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail2.stderr12
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail3.hs8
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail3.stderr5
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail4.hs4
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail4.stderr4
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail5.hs5
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail5.stderr4
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail6.hs5
-rw-r--r--testsuite/tests/deriving/should_fail/T10598_fail6.stderr6
-rw-r--r--testsuite/tests/deriving/should_fail/T3833.stderr2
-rw-r--r--testsuite/tests/deriving/should_fail/T3834.stderr2
-rw-r--r--testsuite/tests/deriving/should_fail/T9600.stderr2
-rw-r--r--testsuite/tests/deriving/should_fail/T9968a.stderr2
-rw-r--r--testsuite/tests/deriving/should_fail/all.T6
-rw-r--r--testsuite/tests/deriving/should_fail/drvfail008.stderr2
-rw-r--r--testsuite/tests/deriving/should_run/T10598_bug.hs9
-rw-r--r--testsuite/tests/deriving/should_run/T10598_bug.stdout1
-rw-r--r--testsuite/tests/deriving/should_run/T10598_run.hs24
-rw-r--r--testsuite/tests/deriving/should_run/T10598_run.stdout2
-rw-r--r--testsuite/tests/deriving/should_run/all.T2
-rw-r--r--testsuite/tests/driver/T4437.hs3
-rw-r--r--testsuite/tests/generics/T5462No1.stderr6
-rw-r--r--testsuite/tests/ghc-api/annotations/Makefile4
-rw-r--r--testsuite/tests/ghc-api/annotations/T10598.stdout36
-rw-r--r--testsuite/tests/ghc-api/annotations/Test10598.hs18
-rw-r--r--testsuite/tests/ghc-api/annotations/all.T1
-rw-r--r--testsuite/tests/module/mod53.stderr2
-rw-r--r--testsuite/tests/parser/should_fail/readFail039.stderr2
-rw-r--r--testsuite/tests/rts/T7919A.hs2
-rw-r--r--testsuite/tests/safeHaskell/ghci/p16.stderr2
-rw-r--r--testsuite/tests/th/T10598_TH.hs42
-rw-r--r--testsuite/tests/th/T10598_TH.stderr41
-rw-r--r--testsuite/tests/th/T10697_sourceUtil.hs2
-rw-r--r--testsuite/tests/th/T10819.hs3
-rw-r--r--testsuite/tests/th/T8100.hs4
-rw-r--r--testsuite/tests/th/TH_dataD1.hs2
-rw-r--r--testsuite/tests/th/all.T1
m---------utils/haddock0
-rw-r--r--utils/mkUserGuidePart/Options/Language.hs7
68 files changed, 1235 insertions, 404 deletions
diff --git a/compiler/basicTypes/BasicTypes.hs b/compiler/basicTypes/BasicTypes.hs
index aab0528d1c..0429a43f5d 100644
--- a/compiler/basicTypes/BasicTypes.hs
+++ b/compiler/basicTypes/BasicTypes.hs
@@ -41,6 +41,8 @@ module BasicTypes(
TopLevelFlag(..), isTopLevel, isNotTopLevel,
+ DerivStrategy(..),
+
OverlapFlag(..), OverlapMode(..), setOverlapModeMaybe,
hasOverlappingFlag, hasOverlappableFlag, hasIncoherentFlag,
@@ -479,6 +481,30 @@ instance Outputable Origin where
{-
************************************************************************
* *
+ Deriving strategies
+* *
+************************************************************************
+-}
+
+-- | Which technique the user explicitly requested when deriving an instance.
+data DerivStrategy
+ -- See Note [Deriving strategies] in TcDeriv
+ = DerivStock -- ^ GHC's \"standard\" strategy, which is to implement a
+ -- custom instance for the data type. This only works for
+ -- certain types that GHC knows about (e.g., 'Eq', 'Show',
+ -- 'Functor' when @-XDeriveFunctor@ is enabled, etc.)
+ | DerivAnyclass -- ^ @-XDeriveAnyClass@
+ | DerivNewtype -- ^ @-XGeneralizedNewtypeDeriving@
+ deriving (Eq, Data)
+
+instance Outputable DerivStrategy where
+ ppr DerivStock = text "stock"
+ ppr DerivAnyclass = text "anyclass"
+ ppr DerivNewtype = text "newtype"
+
+{-
+************************************************************************
+* *
Instance overlap flag
* *
************************************************************************
diff --git a/compiler/deSugar/DsMeta.hs b/compiler/deSugar/DsMeta.hs
index 638d9b468b..d8fdb54183 100644
--- a/compiler/deSugar/DsMeta.hs
+++ b/compiler/deSugar/DsMeta.hs
@@ -455,11 +455,13 @@ repClsInstD (ClsInstDecl { cid_poly_ty = ty, cid_binds = binds
(tvs, cxt, inst_ty) = splitLHsInstDeclTy ty
repStandaloneDerivD :: LDerivDecl Name -> DsM (SrcSpan, Core TH.DecQ)
-repStandaloneDerivD (L loc (DerivDecl { deriv_type = ty }))
+repStandaloneDerivD (L loc (DerivDecl { deriv_strategy = strat
+ , deriv_type = ty }))
= do { dec <- addSimpleTyVarBinds tvs $
do { cxt' <- repLContext cxt
+ ; strat' <- repDerivStrategy strat
; inst_ty' <- repLTy inst_ty
- ; repDeriv cxt' inst_ty' }
+ ; repDeriv strat' cxt' inst_ty' }
; return (loc, dec) }
where
(tvs, cxt, inst_ty) = splitLHsInstDeclTy ty
@@ -668,22 +670,22 @@ repBangTy ty = do
_ -> (NoSrcUnpack, NoSrcStrict, ty)
-------------------------------------------------------
--- Deriving clause
+-- Deriving clauses
-------------------------------------------------------
-repDerivs :: HsDeriving Name -> DsM (Core TH.CxtQ)
-repDerivs deriv = do
- let clauses = case deriv of
- Nothing -> []
- Just (L _ ctxt) -> ctxt
- tys <- repList typeQTyConName
- (rep_deriv . hsSigType)
- clauses
- :: DsM (Core [TH.PredQ])
- repCtxt tys
+repDerivs :: HsDeriving Name -> DsM (Core [TH.DerivClauseQ])
+repDerivs (L _ clauses) = repList derivClauseQTyConName repDerivClause clauses
+
+repDerivClause :: LHsDerivingClause Name
+ -> DsM (Core TH.DerivClauseQ)
+repDerivClause (L _ (HsDerivingClause { deriv_clause_strategy = dcs
+ , deriv_clause_tys = L _ dct }))
+ = do MkC dcs' <- repDerivStrategy dcs
+ MkC dct' <- repList typeQTyConName (rep_deriv_ty . hsSigType) dct
+ rep2 derivClauseName [dcs',dct']
where
- rep_deriv :: LHsType Name -> DsM (Core TH.TypeQ)
- rep_deriv (L _ ty) = repTy ty
+ rep_deriv_ty :: LHsType Name -> DsM (Core TH.TypeQ)
+ rep_deriv_ty (L _ ty) = repTy ty
-------------------------------------------------------
-- Signatures in a class decl, or a group of bindings
@@ -1982,7 +1984,7 @@ repFun (MkC nm) (MkC b) = rep2 funDName [nm, b]
repData :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]
-> Maybe (Core [TH.TypeQ]) -> Core (Maybe TH.Kind)
- -> Core [TH.ConQ] -> Core TH.CxtQ -> DsM (Core TH.DecQ)
+ -> Core [TH.ConQ] -> Core [TH.DerivClauseQ] -> DsM (Core TH.DecQ)
repData (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC ksig) (MkC cons) (MkC derivs)
= rep2 dataDName [cxt, nm, tvs, ksig, cons, derivs]
repData (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC ksig) (MkC cons)
@@ -1991,7 +1993,7 @@ repData (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC ksig) (MkC cons)
repNewtype :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]
-> Maybe (Core [TH.TypeQ]) -> Core (Maybe TH.Kind)
- -> Core TH.ConQ -> Core TH.CxtQ -> DsM (Core TH.DecQ)
+ -> Core TH.ConQ -> Core [TH.DerivClauseQ] -> DsM (Core TH.DecQ)
repNewtype (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC ksig) (MkC con)
(MkC derivs)
= rep2 newtypeDName [cxt, nm, tvs, ksig, con, derivs]
@@ -2009,6 +2011,20 @@ repInst :: Core (Maybe TH.Overlap) ->
repInst (MkC o) (MkC cxt) (MkC ty) (MkC ds) = rep2 instanceWithOverlapDName
[o, cxt, ty, ds]
+repDerivStrategy :: Maybe (Located DerivStrategy)
+ -> DsM (Core (Maybe TH.DerivStrategy))
+repDerivStrategy mds =
+ case mds of
+ Nothing -> nothing
+ Just (L _ ds) ->
+ case ds of
+ DerivStock -> just =<< dataCon stockDataConName
+ DerivAnyclass -> just =<< dataCon anyclassDataConName
+ DerivNewtype -> just =<< dataCon newtypeDataConName
+ where
+ nothing = coreNothing derivStrategyTyConName
+ just = coreJust derivStrategyTyConName
+
repOverlap :: Maybe OverlapMode -> DsM (Core (Maybe TH.Overlap))
repOverlap mb =
case mb of
@@ -2031,8 +2047,11 @@ repClass :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]
repClass (MkC cxt) (MkC cls) (MkC tvs) (MkC fds) (MkC ds)
= rep2 classDName [cxt, cls, tvs, fds, ds]
-repDeriv :: Core TH.CxtQ -> Core TH.TypeQ -> DsM (Core TH.DecQ)
-repDeriv (MkC cxt) (MkC ty) = rep2 standaloneDerivDName [cxt, ty]
+repDeriv :: Core (Maybe TH.DerivStrategy)
+ -> Core TH.CxtQ -> Core TH.TypeQ
+ -> DsM (Core TH.DecQ)
+repDeriv (MkC ds) (MkC cxt) (MkC ty)
+ = rep2 standaloneDerivWithStrategyDName [ds, cxt, ty]
repPragInl :: Core TH.Name -> Core TH.Inline -> Core TH.RuleMatch
-> Core TH.Phases -> DsM (Core TH.DecQ)
diff --git a/compiler/hsSyn/Convert.hs b/compiler/hsSyn/Convert.hs
index 5b5119a404..6bb71991d4 100644
--- a/compiler/hsSyn/Convert.hs
+++ b/compiler/hsSyn/Convert.hs
@@ -339,12 +339,14 @@ cvtDec (TH.RoleAnnotD tc roles)
; let roles' = map (noLoc . cvtRole) roles
; returnJustL $ Hs.RoleAnnotD (RoleAnnotDecl tc' roles') }
-cvtDec (TH.StandaloneDerivD cxt ty)
+cvtDec (TH.StandaloneDerivD ds cxt ty)
= do { cxt' <- cvtContext cxt
; L loc ty' <- cvtType ty
; let inst_ty' = L loc $ HsQualTy { hst_ctxt = cxt', hst_body = L loc ty' }
; returnJustL $ DerivD $
- DerivDecl { deriv_type = mkLHsSigType inst_ty', deriv_overlap_mode = Nothing } }
+ DerivDecl { deriv_strategy = fmap (L loc . cvtDerivStrategy) ds
+ , deriv_type = mkLHsSigType inst_ty'
+ , deriv_overlap_mode = Nothing } }
cvtDec (TH.DefaultSigD nm typ)
= do { nm' <- vNameL nm
@@ -560,12 +562,9 @@ cvt_id_arg (i, str, ty)
, cd_fld_type = ty'
, cd_fld_doc = Nothing}) }
-cvtDerivs :: TH.Cxt -> CvtM (HsDeriving RdrName)
-cvtDerivs [] = return Nothing
-cvtDerivs cs = fmap (Just . mkSigTypes) (cvtContext cs)
- where
- mkSigTypes :: Located (HsContext RdrName) -> Located [LHsSigType RdrName]
- mkSigTypes = fmap (map mkLHsSigType)
+cvtDerivs :: [TH.DerivClause] -> CvtM (HsDeriving RdrName)
+cvtDerivs cs = do { cs' <- mapM cvtDerivClause cs
+ ; returnL cs' }
cvt_fundep :: FunDep -> CvtM (Located (Class.FunDep (Located RdrName)))
cvt_fundep (FunDep xs ys) = do { xs' <- mapM tNameL xs
@@ -1127,6 +1126,18 @@ cvtContext tys = do { preds' <- mapM cvtPred tys; returnL preds' }
cvtPred :: TH.Pred -> CvtM (LHsType RdrName)
cvtPred = cvtType
+cvtDerivClause :: TH.DerivClause
+ -> CvtM (LHsDerivingClause RdrName)
+cvtDerivClause (TH.DerivClause ds ctxt)
+ = do { ctxt'@(L loc _) <- fmap (map mkLHsSigType) <$> cvtContext ctxt
+ ; let ds' = fmap (L loc . cvtDerivStrategy) ds
+ ; returnL $ HsDerivingClause ds' ctxt' }
+
+cvtDerivStrategy :: TH.DerivStrategy -> Hs.DerivStrategy
+cvtDerivStrategy TH.Stock = Hs.DerivStock
+cvtDerivStrategy TH.Anyclass = Hs.DerivAnyclass
+cvtDerivStrategy TH.Newtype = Hs.DerivNewtype
+
cvtType :: TH.Type -> CvtM (LHsType RdrName)
cvtType = cvtTypeKind "type"
diff --git a/compiler/hsSyn/HsDecls.hs b/compiler/hsSyn/HsDecls.hs
index 24b13c4917..ed8da4d4e1 100644
--- a/compiler/hsSyn/HsDecls.hs
+++ b/compiler/hsSyn/HsDecls.hs
@@ -19,6 +19,7 @@
module HsDecls (
-- * Toplevel declarations
HsDecl(..), LHsDecl, HsDataDefn(..), HsDeriving,
+ HsDerivingClause(..), LHsDerivingClause,
-- ** Class or type declarations
TyClDecl(..), LTyClDecl,
@@ -1027,23 +1028,47 @@ data HsDataDefn name -- The payload of a data type defn
deriving instance (DataId id) => Data (HsDataDefn id)
-- | Haskell Deriving clause
-type HsDeriving name = Maybe (Located [LHsSigType name])
- -- ^ The optional 'deriving' clause of a data declaration
+type HsDeriving name = Located [LHsDerivingClause name]
+ -- ^ The optional @deriving@ clauses of a data declaration. "Clauses" is
+ -- plural because one can specify multiple deriving clauses using the
+ -- @-XDerivingStrategies@ language extension.
--
- -- @Nothing@ => not specified,
- -- @Just []@ => derive exactly what is asked
- --
- -- It's a 'LHsSigType' because, with Generalised Newtype
- -- Deriving, we can mention type variables that aren't
- -- bound by the date type. e.g.
- -- data T b = ... deriving( C [a] )
- -- should producd a derived instance for (C [a] (T b))
- --
- -- The payload of the Maybe is Located so that we have a
- -- place to hang the API annotations:
- -- - 'ApiAnnotation.AnnKeywordId' :
- -- 'ApiAnnotation.AnnDeriving',
- -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'
+ -- The list of 'LHsDerivingClause's corresponds to exactly what the user
+ -- requested to derive, in order. If no deriving clauses were specified,
+ -- the list is empty.
+
+type LHsDerivingClause name = Located (HsDerivingClause name)
+
+-- | A single @deriving@ clause of a data declaration.
+--
+-- - 'ApiAnnotation.AnnKeywordId' :
+-- 'ApiAnnotation.AnnDeriving', 'ApiAnnotation.AnnStock',
+-- 'ApiAnnotation.AnnAnyClass', 'Api.AnnNewtype',
+-- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'
+data HsDerivingClause name
+ -- See Note [Deriving strategies] in TcDeriv
+ = HsDerivingClause
+ { deriv_clause_strategy :: Maybe (Located DerivStrategy)
+ -- ^ The user-specified strategy (if any) to use when deriving
+ -- 'deriv_clause_tys'.
+ , deriv_clause_tys :: Located [LHsSigType name]
+ -- ^ The types to derive.
+ --
+ -- It uses 'LHsSigType's because, with @-XGeneralizedNewtypeDeriving@,
+ -- we can mention type variables that aren't bound by the datatype, e.g.
+ --
+ -- > data T b = ... deriving (C [a])
+ --
+ -- should produce a derived instance for @C [a] (T b)@.
+ }
+deriving instance (DataId id) => Data (HsDerivingClause id)
+
+instance (OutputableBndrId name) => Outputable (HsDerivingClause name) where
+ ppr (HsDerivingClause { deriv_clause_strategy = dcs
+ , deriv_clause_tys = L _ dct })
+ = hsep [ text "deriving"
+ , ppDerivStrategy dcs
+ , parens (interpp'SP dct) ]
data NewOrData
= NewType -- ^ @newtype Blah ...@
@@ -1159,15 +1184,12 @@ pp_data_defn pp_hdr (HsDataDefn { dd_ND = new_or_data, dd_ctxt = L _ context
| otherwise
= hang (ppr new_or_data <+> pp_hdr context <+> pp_sig)
- 2 (pp_condecls condecls $$ pp_derivings)
+ 2 (pp_condecls condecls $$ pp_derivings derivings)
where
pp_sig = case mb_sig of
Nothing -> empty
Just kind -> dcolon <+> ppr kind
- pp_derivings = case derivings of
- Nothing -> empty
- Just (L _ ds) -> hsep [ text "deriving"
- , parens (interpp'SP ds)]
+ pp_derivings (L _ ds) = vcat (map ppr ds)
instance (OutputableBndrId name) => Outputable (HsDataDefn name) where
ppr d = pp_data_defn (\_ -> text "Naked HsDataDefn") d
@@ -1455,6 +1477,12 @@ instance (OutputableBndrId name) => Outputable (ClsInstDecl name) where
top_matter = text "instance" <+> ppOverlapPragma mbOverlap
<+> ppr inst_ty
+ppDerivStrategy :: Maybe (Located DerivStrategy) -> SDoc
+ppDerivStrategy mb =
+ case mb of
+ Nothing -> empty
+ Just (L _ ds) -> ppr ds
+
ppOverlapPragma :: Maybe (Located OverlapMode) -> SDoc
ppOverlapPragma mb =
case mb of
@@ -1496,19 +1524,26 @@ type LDerivDecl name = Located (DerivDecl name)
-- | Deriving Declaration
data DerivDecl name = DerivDecl
{ deriv_type :: LHsSigType name
+ , deriv_strategy :: Maybe (Located DerivStrategy)
, deriv_overlap_mode :: Maybe (Located OverlapMode)
- -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',
- -- 'ApiAnnotation.AnnClose',
- -- 'ApiAnnotation.AnnDeriving',
- -- 'ApiAnnotation.AnnInstance'
+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDeriving',
+ -- 'ApiAnnotation.AnnInstance', 'ApiAnnotation.AnnStock',
+ -- 'ApiAnnotation.AnnAnyClass', 'Api.AnnNewtype',
+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'
-- For details on above see note [Api annotations] in ApiAnnotation
}
deriving instance (DataId name) => Data (DerivDecl name)
instance (OutputableBndrId name) => Outputable (DerivDecl name) where
- ppr (DerivDecl ty o)
- = hsep [text "deriving instance", ppOverlapPragma o, ppr ty]
+ ppr (DerivDecl { deriv_type = ty
+ , deriv_strategy = ds
+ , deriv_overlap_mode = o })
+ = hsep [ text "deriving"
+ , ppDerivStrategy ds
+ , text "instance"
+ , ppOverlapPragma o
+ , ppr ty ]
{-
************************************************************************
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index b642bead7b..a972716bc1 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -3561,6 +3561,7 @@ xFlagsDeps = [
flagSpec "DeriveGeneric" LangExt.DeriveGeneric,
flagSpec "DeriveLift" LangExt.DeriveLift,
flagSpec "DeriveTraversable" LangExt.DeriveTraversable,
+ flagSpec "DerivingStrategies" LangExt.DerivingStrategies,
flagSpec "DisambiguateRecordFields" LangExt.DisambiguateRecordFields,
flagSpec "DoAndIfThenElse" LangExt.DoAndIfThenElse,
depFlagSpec' "DoRec" LangExt.RecursiveDo
diff --git a/compiler/main/HscStats.hs b/compiler/main/HscStats.hs
index 78020f72bc..241dfd8095 100644
--- a/compiler/main/HscStats.hs
+++ b/compiler/main/HscStats.hs
@@ -16,6 +16,7 @@ import SrcLoc
import Util
import Data.Char
+import Data.Foldable (foldl')
-- | Source Statistics
ppSourceStats :: Bool -> Located (HsModule RdrName) -> SDoc
@@ -128,9 +129,10 @@ ppSourceStats short (L _ (HsModule _ exports imports ldecls _ _))
spec_info (Just (True, _)) = (0,0,0,0,0,0,1)
data_info (DataDecl { tcdDataDefn = HsDataDefn { dd_cons = cs
- , dd_derivs = derivs}})
- = (length cs, case derivs of Nothing -> 0
- Just (L _ ds) -> length ds)
+ , dd_derivs = L _ derivs}})
+ = ( length cs
+ , foldl' (\s dc -> length (deriv_clause_tys $ unLoc dc) + s)
+ 0 derivs )
data_info _ = (0,0)
class_info decl@(ClassDecl {})
diff --git a/compiler/parser/ApiAnnotation.hs b/compiler/parser/ApiAnnotation.hs
index eebec547cc..ac784bcea4 100644
--- a/compiler/parser/ApiAnnotation.hs
+++ b/compiler/parser/ApiAnnotation.hs
@@ -186,7 +186,8 @@ getAndRemoveAnnotationComments (anns,canns) span =
-- corresponding token, unless otherwise noted
-- See note [Api annotations] above for details of the usage
data AnnKeywordId
- = AnnAs
+ = AnnAnyclass
+ | AnnAs
| AnnAt
| AnnBang -- ^ '!'
| AnnBackquote -- ^ '`'
@@ -256,6 +257,7 @@ data AnnKeywordId
| AnnSemi -- ^ ';'
| AnnSimpleQuote -- ^ '''
| AnnStatic -- ^ 'static'
+ | AnnStock
| AnnThen
| AnnThIdSplice -- ^ '$'
| AnnThIdTySplice -- ^ '$$'
diff --git a/compiler/parser/Lexer.x b/compiler/parser/Lexer.x
index 410d150f45..361fa0be6a 100644
--- a/compiler/parser/Lexer.x
+++ b/compiler/parser/Lexer.x
@@ -612,6 +612,8 @@ data Token
| ITusing
| ITpattern
| ITstatic
+ | ITstock
+ | ITanyclass
-- Pragmas, see note [Pragma source text] in BasicTypes
| ITinline_prag SourceText InlineSpec RuleMatchInfo
@@ -803,6 +805,8 @@ reservedWordsFM = listToUFM $
( "role", ITrole, 0 ),
( "pattern", ITpattern, xbit PatternSynonymsBit),
( "static", ITstatic, 0 ),
+ ( "stock", ITstock, 0 ),
+ ( "anyclass", ITanyclass, 0 ),
( "group", ITgroup, xbit TransformComprehensionsBit),
( "by", ITby, xbit TransformComprehensionsBit),
( "using", ITusing, xbit TransformComprehensionsBit),
diff --git a/compiler/parser/Parser.y b/compiler/parser/Parser.y
index 5db535f20e..4cab083484 100644
--- a/compiler/parser/Parser.y
+++ b/compiler/parser/Parser.y
@@ -88,7 +88,7 @@ import qualified GHC.LanguageExtensions as LangExt
%expect 36 -- shift/reduce conflicts
-{- Last updated: 9 Jan 2016
+{- Last updated: 3 Aug 2016
If you modify this parser and add a conflict, please update this comment.
You can learn more about the conflicts by passing 'happy' the -i flag:
@@ -119,7 +119,7 @@ follows. Shift parses as if the 'module' keyword follows.
-------------------------------------------------------------------------------
-state 46 contains 2 shift/reduce conflicts.
+state 48 contains 2 shift/reduce conflicts.
*** strict_mark -> unpackedness .
strict_mark -> unpackedness . strictness
@@ -128,7 +128,7 @@ state 46 contains 2 shift/reduce conflicts.
-------------------------------------------------------------------------------
-state 50 contains 1 shift/reduce conflict.
+state 52 contains 1 shift/reduce conflict.
context -> btype .
*** type -> btype .
@@ -138,7 +138,7 @@ state 50 contains 1 shift/reduce conflict.
-------------------------------------------------------------------------------
-state 51 contains 9 shift/reduce conflicts.
+state 53 contains 9 shift/reduce conflicts.
*** btype -> tyapps .
tyapps -> tyapps . tyapp
@@ -147,7 +147,7 @@ state 51 contains 9 shift/reduce conflicts.
-------------------------------------------------------------------------------
-state 132 contains 14 shift/reduce conflicts.
+state 134 contains 14 shift/reduce conflicts.
exp -> infixexp . '::' sigtype
exp -> infixexp . '-<' exp
@@ -172,7 +172,7 @@ Shift parses as (per longest-parse rule):
-------------------------------------------------------------------------------
-state 295 contains 1 shift/reduce conflicts.
+state 299 contains 1 shift/reduce conflicts.
rule -> STRING . rule_activation rule_forall infixexp '=' exp
@@ -190,7 +190,7 @@ a rule instructing how to rewrite the expression '[0] f'.
-------------------------------------------------------------------------------
-state 304 contains 1 shift/reduce conflict.
+state 309 contains 1 shift/reduce conflict.
*** type -> btype .
type -> btype . '->' ctype
@@ -201,7 +201,7 @@ Same as state 50 but without contexts.
-------------------------------------------------------------------------------
-state 340 contains 1 shift/reduce conflicts.
+state 348 contains 1 shift/reduce conflicts.
tup_exprs -> commas . tup_tail
sysdcon_nolist -> '(' commas . ')'
@@ -216,7 +216,7 @@ if -XTupleSections is not specified.
-------------------------------------------------------------------------------
-state 391 contains 1 shift/reduce conflicts.
+state 402 contains 1 shift/reduce conflicts.
tup_exprs -> commas . tup_tail
sysdcon_nolist -> '(#' commas . '#)'
@@ -228,7 +228,7 @@ Same as State 324 for unboxed tuples.
-------------------------------------------------------------------------------
-state 465 contains 1 shift/reduce conflict.
+state 477 contains 1 shift/reduce conflict.
oqtycon -> '(' qtyconsym . ')'
*** qtyconop -> qtyconsym .
@@ -239,7 +239,7 @@ TODO: Why?
-------------------------------------------------------------------------------
-state 639 contains 1 shift/reduce conflicts.
+state 658 contains 1 shift/reduce conflicts.
*** aexp2 -> ipvar .
dbind -> ipvar . '=' exp
@@ -254,7 +254,7 @@ sensible meaning, namely the lhs of an implicit binding.
-------------------------------------------------------------------------------
-state 707 contains 1 shift/reduce conflicts.
+state 731 contains 1 shift/reduce conflicts.
rule -> STRING rule_activation . rule_forall infixexp '=' exp
@@ -271,7 +271,7 @@ doesn't include 'forall'.
-------------------------------------------------------------------------------
-state 933 contains 1 shift/reduce conflicts.
+state 963 contains 1 shift/reduce conflicts.
transformqual -> 'then' 'group' . 'using' exp
transformqual -> 'then' 'group' . 'by' exp 'using' exp
@@ -281,7 +281,7 @@ state 933 contains 1 shift/reduce conflicts.
-------------------------------------------------------------------------------
-state 1269 contains 1 shift/reduce conflict.
+state 1303 contains 1 shift/reduce conflict.
*** atype -> tyvar .
tv_bndr -> '(' tyvar . '::' kind ')'
@@ -368,6 +368,8 @@ output it generates.
'using' { L _ ITusing } -- for list transform extension
'pattern' { L _ ITpattern } -- for pattern synonyms
'static' { L _ ITstatic } -- for static pointers extension
+ 'stock' { L _ ITstock } -- for DerivingStrategies extension
+ 'anyclass' { L _ ITanyclass } -- for DerivingStrategies extension
'{-# INLINE' { L _ (ITinline_prag _ _ _) } -- INLINE or INLINABLE
'{-# SPECIALISE' { L _ (ITspec_prag _) }
@@ -870,10 +872,10 @@ ty_decl :: { LTyClDecl RdrName }
++ (fst $ unLoc $5) ++ (fst $ unLoc $6)) }
-- ordinary data type or newtype declaration
- | data_or_newtype capi_ctype tycl_hdr constrs deriving
+ | data_or_newtype capi_ctype tycl_hdr constrs maybe_derivings
{% amms (mkTyData (comb4 $1 $3 $4 $5) (snd $ unLoc $1) $2 $3
Nothing (reverse (snd $ unLoc $4))
- (unLoc $5))
+ (fmap reverse $5))
-- We need the location on tycl_hdr in case
-- constrs and deriving are both empty
((fst $ unLoc $1):(fst $ unLoc $4)) }
@@ -881,9 +883,10 @@ ty_decl :: { LTyClDecl RdrName }
-- ordinary GADT declaration
| data_or_newtype capi_ctype tycl_hdr opt_kind_sig
gadt_constrlist
- deriving
+ maybe_derivings
{% amms (mkTyData (comb4 $1 $3 $5 $6) (snd $ unLoc $1) $2 $3
- (snd $ unLoc $4) (snd $ unLoc $5) (unLoc $6) )
+ (snd $ unLoc $4) (snd $ unLoc $5)
+ (fmap reverse $6) )
-- We need the location on tycl_hdr in case
-- constrs and deriving are both empty
((fst $ unLoc $1):(fst $ unLoc $4)++(fst $ unLoc $5)) }
@@ -912,18 +915,20 @@ inst_decl :: { LInstDecl RdrName }
(mj AnnType $1:mj AnnInstance $2:(fst $ unLoc $3)) }
-- data/newtype instance declaration
- | data_or_newtype 'instance' capi_ctype tycl_hdr constrs deriving
+ | data_or_newtype 'instance' capi_ctype tycl_hdr constrs
+ maybe_derivings
{% amms (mkDataFamInst (comb4 $1 $4 $5 $6) (snd $ unLoc $1) $3 $4
Nothing (reverse (snd $ unLoc $5))
- (unLoc $6))
+ (fmap reverse $6))
((fst $ unLoc $1):mj AnnInstance $2:(fst $ unLoc $5)) }
-- GADT instance declaration
| data_or_newtype 'instance' capi_ctype tycl_hdr opt_kind_sig
gadt_constrlist
- deriving
+ maybe_derivings
{% amms (mkDataFamInst (comb4 $1 $4 $6 $7) (snd $ unLoc $1) $3 $4
- (snd $ unLoc $5) (snd $ unLoc $6) (unLoc $7))
+ (snd $ unLoc $5) (snd $ unLoc $6)
+ (fmap reverse $7))
((fst $ unLoc $1):mj AnnInstance $2
:(fst $ unLoc $5)++(fst $ unLoc $6)) }
@@ -938,6 +943,14 @@ overlap_pragma :: { Maybe (Located OverlapMode) }
[mo $1,mc $2] }
| {- empty -} { Nothing }
+deriv_strategy :: { Maybe (Located DerivStrategy) }
+ : 'stock' {% ajs (Just (sL1 $1 DerivStock))
+ [mj AnnStock $1] }
+ | 'anyclass' {% ajs (Just (sL1 $1 DerivAnyclass))
+ [mj AnnAnyclass $1] }
+ | 'newtype' {% ajs (Just (sL1 $1 DerivNewtype))
+ [mj AnnNewtype $1] }
+ | {- empty -} { Nothing }
-- Injective type families
@@ -1048,18 +1061,19 @@ at_decl_inst :: { LInstDecl RdrName }
(mj AnnType $1:(fst $ unLoc $2)) }
-- data/newtype instance declaration
- | data_or_newtype capi_ctype tycl_hdr constrs deriving
+ | data_or_newtype capi_ctype tycl_hdr constrs maybe_derivings
{% amms (mkDataFamInst (comb4 $1 $3 $4 $5) (snd $ unLoc $1) $2 $3
Nothing (reverse (snd $ unLoc $4))
- (unLoc $5))
+ (fmap reverse $5))
((fst $ unLoc $1):(fst $ unLoc $4)) }
-- GADT instance declaration
| data_or_newtype capi_ctype tycl_hdr opt_kind_sig
gadt_constrlist
- deriving
+ maybe_derivings
{% amms (mkDataFamInst (comb4 $1 $3 $5 $6) (snd $ unLoc $1) $2
- $3 (snd $ unLoc $4) (snd $ unLoc $5) (unLoc $6))
+ $3 (snd $ unLoc $4) (snd $ unLoc $5)
+ (fmap reverse $6))
((fst $ unLoc $1):(fst $ unLoc $4)++(fst $ unLoc $5)) }
data_or_newtype :: { Located (AddAnn, NewOrData) }
@@ -1120,11 +1134,11 @@ capi_ctype : '{-# CTYPE' STRING STRING '#-}'
-- Glasgow extension: stand-alone deriving declarations
stand_alone_deriving :: { LDerivDecl RdrName }
- : 'deriving' 'instance' overlap_pragma inst_type
- {% do { let { err = text "in the stand-alone deriving instance"
- <> colon <+> quotes (ppr $4) }
- ; ams (sLL $1 (hsSigType $>) (DerivDecl $4 $3))
- [mj AnnDeriving $1, mj AnnInstance $2] } }
+ : 'deriving' deriv_strategy 'instance' overlap_pragma inst_type
+ {% do { let { err = text "in the stand-alone deriving instance"
+ <> colon <+> quotes (ppr $5) }
+ ; ams (sLL $1 (hsSigType $>) (DerivDecl $5 $2 $4))
+ [mj AnnDeriving $1, mj AnnInstance $3] } }
-----------------------------------------------------------------------------
-- Role annotations
@@ -1929,22 +1943,34 @@ fielddecl :: { LConDeclField RdrName }
(ConDeclField (reverse (map (\ln@(L l n) -> L l $ FieldOcc ln PlaceHolder) (unLoc $2))) $4 ($1 `mplus` $5)))
[mu AnnDcolon $3] }
+-- Reversed!
+maybe_derivings :: { HsDeriving RdrName }
+ : {- empty -} { noLoc [] }
+ | derivings { $1 }
+
+-- A list of one or more deriving clauses at the end of a datatype
+derivings :: { HsDeriving RdrName }
+ : derivings deriving { sLL $1 $> $ $2 : unLoc $1 }
+ | deriving { sLL $1 $> [$1] }
+
-- The outer Located is just to allow the caller to
-- know the rightmost extremity of the 'deriving' clause
-deriving :: { Located (HsDeriving RdrName) }
- : {- empty -} { noLoc Nothing }
- | 'deriving' qtycondoc {% let { full_loc = comb2 $1 $> }
- in ams (L full_loc $ Just $ L full_loc $
- [mkLHsSigType $2])
- [mj AnnDeriving $1] }
-
- | 'deriving' '(' ')' {% let { full_loc = comb2 $1 $> }
- in ams (L full_loc $ Just $ L full_loc [])
- [mj AnnDeriving $1,mop $2,mcp $3] }
-
- | 'deriving' '(' deriv_types ')' {% let { full_loc = comb2 $1 $> }
- in ams (L full_loc $ Just $ L full_loc $3)
- [mj AnnDeriving $1,mop $2,mcp $4] }
+deriving :: { LHsDerivingClause RdrName }
+ : 'deriving' deriv_strategy qtycondoc
+ {% let { full_loc = comb2 $1 $> }
+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc
+ [mkLHsSigType $3])
+ [mj AnnDeriving $1] }
+
+ | 'deriving' deriv_strategy '(' ')'
+ {% let { full_loc = comb2 $1 $> }
+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc [])
+ [mj AnnDeriving $1,mop $3,mcp $4] }
+
+ | 'deriving' deriv_strategy '(' deriv_types ')'
+ {% let { full_loc = comb2 $1 $> }
+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc $4)
+ [mj AnnDeriving $1,mop $3,mcp $5] }
-- Glasgow extension: allow partial
-- applications in derivings
@@ -3014,8 +3040,8 @@ qvarid :: { Located RdrName }
| QVARID { sL1 $1 $! mkQual varName (getQVARID $1) }
-- Note that 'role' and 'family' get lexed separately regardless of
--- the use of extensions. However, because they are listed here, this
--- is OK and they can be used as normal varids.
+-- the use of extensions. However, because they are listed here,
+-- this is OK and they can be used as normal varids.
-- See Note [Lexing type pseudo-keywords] in Lexer.x
varid :: { Located RdrName }
: VARID { sL1 $1 $! mkUnqual varName (getVARID $1) }
@@ -3049,8 +3075,8 @@ varsym_no_minus :: { Located RdrName } -- varsym not including '-'
-- These special_ids are treated as keywords in various places,
-- but as ordinary ids elsewhere. 'special_id' collects all these
--- except 'unsafe', 'interruptible', 'forall', 'family', and 'role',
--- whose treatment differs depending on context
+-- except 'unsafe', 'interruptible', 'forall', 'family', 'role', 'stock', and
+-- 'anyclass', whose treatment differs depending on context
special_id :: { Located FastString }
special_id
: 'as' { sL1 $1 (fsLit "as") }
@@ -3065,6 +3091,8 @@ special_id
| 'prim' { sL1 $1 (fsLit "prim") }
| 'javascript' { sL1 $1 (fsLit "javascript") }
| 'group' { sL1 $1 (fsLit "group") }
+ | 'stock' { sL1 $1 (fsLit "stock") }
+ | 'anyclass' { sL1 $1 (fsLit "anyclass") }
special_sym :: { Located FastString }
special_sym : '!' {% ams (sL1 $1 (fsLit "!")) [mj AnnBang $1] }
diff --git a/compiler/prelude/THNames.hs b/compiler/prelude/THNames.hs
index 4f98114bb5..8c184f851e 100644
--- a/compiler/prelude/THNames.hs
+++ b/compiler/prelude/THNames.hs
@@ -65,7 +65,7 @@ templateHaskellNames = [
-- Dec
funDName, valDName, dataDName, newtypeDName, tySynDName,
classDName, instanceWithOverlapDName,
- standaloneDerivDName, sigDName, forImpDName,
+ standaloneDerivWithStrategyDName, sigDName, forImpDName,
pragInlDName, pragSpecDName, pragSpecInlDName, pragSpecInstDName,
pragRuleDName, pragAnnDName, defaultSigDName,
dataFamilyDName, openTypeFamilyDName, closedTypeFamilyDName,
@@ -125,6 +125,8 @@ templateHaskellNames = [
-- Overlap
overlappableDataConName, overlappingDataConName, overlapsDataConName,
incoherentDataConName,
+ -- DerivStrategy
+ stockDataConName, anyclassDataConName, newtypeDataConName,
-- TExp
tExpDataConName,
-- RuleBndr
@@ -137,6 +139,8 @@ templateHaskellNames = [
tySynEqnName,
-- AnnTarget
valueAnnotationName, typeAnnotationName, moduleAnnotationName,
+ -- DerivClause
+ derivClauseName,
-- The type classes
liftClassName,
@@ -150,7 +154,7 @@ templateHaskellNames = [
patQTyConName, fieldPatQTyConName, fieldExpQTyConName, funDepTyConName,
predQTyConName, decsQTyConName, ruleBndrQTyConName, tySynEqnQTyConName,
roleTyConName, tExpTyConName, injAnnTyConName, kindTyConName,
- overlapTyConName,
+ overlapTyConName, derivClauseQTyConName, derivStrategyTyConName,
-- Quasiquoting
quoteDecName, quoteTypeName, quoteExpName, quotePatName]
@@ -180,24 +184,25 @@ qTyConName, nameTyConName, fieldExpTyConName, patTyConName,
fieldPatTyConName, expTyConName, decTyConName, typeTyConName,
tyVarBndrTyConName, matchTyConName, clauseTyConName, funDepTyConName,
predTyConName, tExpTyConName, injAnnTyConName, kindTyConName,
- overlapTyConName :: Name
-qTyConName = thTc (fsLit "Q") qTyConKey
-nameTyConName = thTc (fsLit "Name") nameTyConKey
-fieldExpTyConName = thTc (fsLit "FieldExp") fieldExpTyConKey
-patTyConName = thTc (fsLit "Pat") patTyConKey
-fieldPatTyConName = thTc (fsLit "FieldPat") fieldPatTyConKey
-expTyConName = thTc (fsLit "Exp") expTyConKey
-decTyConName = thTc (fsLit "Dec") decTyConKey
-typeTyConName = thTc (fsLit "Type") typeTyConKey
-tyVarBndrTyConName= thTc (fsLit "TyVarBndr") tyVarBndrTyConKey
-matchTyConName = thTc (fsLit "Match") matchTyConKey
-clauseTyConName = thTc (fsLit "Clause") clauseTyConKey
-funDepTyConName = thTc (fsLit "FunDep") funDepTyConKey
-predTyConName = thTc (fsLit "Pred") predTyConKey
-tExpTyConName = thTc (fsLit "TExp") tExpTyConKey
-injAnnTyConName = thTc (fsLit "InjectivityAnn") injAnnTyConKey
-kindTyConName = thTc (fsLit "Kind") kindTyConKey
-overlapTyConName = thTc (fsLit "Overlap") overlapTyConKey
+ overlapTyConName, derivStrategyTyConName :: Name
+qTyConName = thTc (fsLit "Q") qTyConKey
+nameTyConName = thTc (fsLit "Name") nameTyConKey
+fieldExpTyConName = thTc (fsLit "FieldExp") fieldExpTyConKey
+patTyConName = thTc (fsLit "Pat") patTyConKey
+fieldPatTyConName = thTc (fsLit "FieldPat") fieldPatTyConKey
+expTyConName = thTc (fsLit "Exp") expTyConKey
+decTyConName = thTc (fsLit "Dec") decTyConKey
+typeTyConName = thTc (fsLit "Type") typeTyConKey
+tyVarBndrTyConName = thTc (fsLit "TyVarBndr") tyVarBndrTyConKey
+matchTyConName = thTc (fsLit "Match") matchTyConKey
+clauseTyConName = thTc (fsLit "Clause") clauseTyConKey
+funDepTyConName = thTc (fsLit "FunDep") funDepTyConKey
+predTyConName = thTc (fsLit "Pred") predTyConKey
+tExpTyConName = thTc (fsLit "TExp") tExpTyConKey
+injAnnTyConName = thTc (fsLit "InjectivityAnn") injAnnTyConKey
+kindTyConName = thTc (fsLit "Kind") kindTyConKey
+overlapTyConName = thTc (fsLit "Overlap") overlapTyConKey
+derivStrategyTyConName = thTc (fsLit "DerivStrategy") derivStrategyTyConKey
returnQName, bindQName, sequenceQName, newNameName, liftName,
mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName,
@@ -332,12 +337,11 @@ parSName = libFun (fsLit "parS") parSIdKey
-- data Dec = ...
funDName, valDName, dataDName, newtypeDName, tySynDName, classDName,
instanceWithOverlapDName, sigDName, forImpDName, pragInlDName,
- pragSpecDName,
- pragSpecInlDName, pragSpecInstDName, pragRuleDName, pragAnnDName,
- standaloneDerivDName, defaultSigDName, dataInstDName, newtypeInstDName,
- tySynInstDName, dataFamilyDName, openTypeFamilyDName, closedTypeFamilyDName,
- infixLDName, infixRDName, infixNDName, roleAnnotDName, patSynDName,
- patSynSigDName :: Name
+ pragSpecDName, pragSpecInlDName, pragSpecInstDName, pragRuleDName,
+ pragAnnDName, standaloneDerivWithStrategyDName, defaultSigDName,
+ dataInstDName, newtypeInstDName, tySynInstDName, dataFamilyDName,
+ openTypeFamilyDName, closedTypeFamilyDName, infixLDName, infixRDName,
+ infixNDName, roleAnnotDName, patSynDName, patSynSigDName :: Name
funDName = libFun (fsLit "funD") funDIdKey
valDName = libFun (fsLit "valD") valDIdKey
dataDName = libFun (fsLit "dataD") dataDIdKey
@@ -346,7 +350,8 @@ tySynDName = libFun (fsLit "tySynD") tySynDIdKey
classDName = libFun (fsLit "classD") classDIdKey
instanceWithOverlapDName
= libFun (fsLit "instanceWithOverlapD") instanceWithOverlapDIdKey
-standaloneDerivDName = libFun (fsLit "standaloneDerivD") standaloneDerivDIdKey
+standaloneDerivWithStrategyDName = libFun
+ (fsLit "standaloneDerivWithStrategyD") standaloneDerivWithStrategyDIdKey
sigDName = libFun (fsLit "sigD") sigDIdKey
defaultSigDName = libFun (fsLit "defaultSigD") defaultSigDIdKey
forImpDName = libFun (fsLit "forImpD") forImpDIdKey
@@ -522,11 +527,16 @@ valueAnnotationName = libFun (fsLit "valueAnnotation") valueAnnotationIdKey
typeAnnotationName = libFun (fsLit "typeAnnotation") typeAnnotationIdKey
moduleAnnotationName = libFun (fsLit "moduleAnnotation") moduleAnnotationIdKey
+-- type DerivClause = ...
+derivClauseName :: Name
+derivClauseName = libFun (fsLit "derivClause") derivClauseIdKey
+
matchQTyConName, clauseQTyConName, expQTyConName, stmtQTyConName,
decQTyConName, conQTyConName, bangTypeQTyConName,
varBangTypeQTyConName, typeQTyConName, fieldExpQTyConName,
patQTyConName, fieldPatQTyConName, predQTyConName, decsQTyConName,
- ruleBndrQTyConName, tySynEqnQTyConName, roleTyConName :: Name
+ ruleBndrQTyConName, tySynEqnQTyConName, roleTyConName,
+ derivClauseQTyConName :: Name
matchQTyConName = libTc (fsLit "MatchQ") matchQTyConKey
clauseQTyConName = libTc (fsLit "ClauseQ") clauseQTyConKey
expQTyConName = libTc (fsLit "ExpQ") expQTyConKey
@@ -544,6 +554,7 @@ predQTyConName = libTc (fsLit "PredQ") predQTyConKey
ruleBndrQTyConName = libTc (fsLit "RuleBndrQ") ruleBndrQTyConKey
tySynEqnQTyConName = libTc (fsLit "TySynEqnQ") tySynEqnQTyConKey
roleTyConName = libTc (fsLit "Role") roleTyConKey
+derivClauseQTyConName = libTc (fsLit "DerivClauseQ") derivClauseQTyConKey
-- quasiquoting
quoteExpName, quotePatName, quoteDecName, quoteTypeName :: Name
@@ -579,6 +590,12 @@ overlappingDataConName = thCon (fsLit "Overlapping") overlappingDataConKey
overlapsDataConName = thCon (fsLit "Overlaps") overlapsDataConKey
incoherentDataConName = thCon (fsLit "Incoherent") incoherentDataConKey
+-- data DerivStrategy = ...
+stockDataConName, anyclassDataConName, newtypeDataConName :: Name
+stockDataConName = thCon (fsLit "Stock") stockDataConKey
+anyclassDataConName = thCon (fsLit "Anyclass") anyclassDataConKey
+newtypeDataConName = thCon (fsLit "Newtype") newtypeDataConKey
+
{- *********************************************************************
* *
Class keys
@@ -608,7 +625,7 @@ expTyConKey, matchTyConKey, clauseTyConKey, qTyConKey, expQTyConKey,
fieldPatQTyConKey, fieldExpQTyConKey, funDepTyConKey, predTyConKey,
predQTyConKey, decsQTyConKey, ruleBndrQTyConKey, tySynEqnQTyConKey,
roleTyConKey, tExpTyConKey, injAnnTyConKey, kindTyConKey,
- overlapTyConKey :: Unique
+ overlapTyConKey, derivClauseQTyConKey, derivStrategyTyConKey :: Unique
expTyConKey = mkPreludeTyConUnique 200
matchTyConKey = mkPreludeTyConUnique 201
clauseTyConKey = mkPreludeTyConUnique 202
@@ -643,6 +660,8 @@ tExpTyConKey = mkPreludeTyConUnique 230
injAnnTyConKey = mkPreludeTyConUnique 231
kindTyConKey = mkPreludeTyConUnique 232
overlapTyConKey = mkPreludeTyConUnique 233
+derivClauseQTyConKey = mkPreludeTyConUnique 234
+derivStrategyTyConKey = mkPreludeTyConUnique 235
{- *********************************************************************
* *
@@ -684,6 +703,12 @@ overlappingDataConKey = mkPreludeDataConUnique 110
overlapsDataConKey = mkPreludeDataConUnique 111
incoherentDataConKey = mkPreludeDataConUnique 112
+-- data DerivStrategy = ...
+stockDataConKey, anyclassDataConKey, newtypeDataConKey :: Unique
+stockDataConKey = mkPreludeDataConUnique 113
+anyclassDataConKey = mkPreludeDataConUnique 114
+newtypeDataConKey = mkPreludeDataConUnique 115
+
{- *********************************************************************
* *
Id keys
@@ -830,39 +855,39 @@ funDIdKey, valDIdKey, dataDIdKey, newtypeDIdKey, tySynDIdKey, classDIdKey,
pragInlDIdKey, pragSpecDIdKey, pragSpecInlDIdKey, pragSpecInstDIdKey,
pragRuleDIdKey, pragAnnDIdKey, defaultSigDIdKey, dataFamilyDIdKey,
openTypeFamilyDIdKey, closedTypeFamilyDIdKey, dataInstDIdKey,
- newtypeInstDIdKey, tySynInstDIdKey, standaloneDerivDIdKey, infixLDIdKey,
- infixRDIdKey, infixNDIdKey, roleAnnotDIdKey, patSynDIdKey,
+ newtypeInstDIdKey, tySynInstDIdKey, standaloneDerivWithStrategyDIdKey,
+ infixLDIdKey, infixRDIdKey, infixNDIdKey, roleAnnotDIdKey, patSynDIdKey,
patSynSigDIdKey :: Unique
-funDIdKey = mkPreludeMiscIdUnique 320
-valDIdKey = mkPreludeMiscIdUnique 321
-dataDIdKey = mkPreludeMiscIdUnique 322
-newtypeDIdKey = mkPreludeMiscIdUnique 323
-tySynDIdKey = mkPreludeMiscIdUnique 324
-classDIdKey = mkPreludeMiscIdUnique 325
-instanceWithOverlapDIdKey = mkPreludeMiscIdUnique 326
-instanceDIdKey = mkPreludeMiscIdUnique 327
-sigDIdKey = mkPreludeMiscIdUnique 328
-forImpDIdKey = mkPreludeMiscIdUnique 329
-pragInlDIdKey = mkPreludeMiscIdUnique 330
-pragSpecDIdKey = mkPreludeMiscIdUnique 331
-pragSpecInlDIdKey = mkPreludeMiscIdUnique 332
-pragSpecInstDIdKey = mkPreludeMiscIdUnique 333
-pragRuleDIdKey = mkPreludeMiscIdUnique 334
-pragAnnDIdKey = mkPreludeMiscIdUnique 335
-dataFamilyDIdKey = mkPreludeMiscIdUnique 336
-openTypeFamilyDIdKey = mkPreludeMiscIdUnique 337
-dataInstDIdKey = mkPreludeMiscIdUnique 338
-newtypeInstDIdKey = mkPreludeMiscIdUnique 339
-tySynInstDIdKey = mkPreludeMiscIdUnique 340
-closedTypeFamilyDIdKey = mkPreludeMiscIdUnique 341
-infixLDIdKey = mkPreludeMiscIdUnique 342
-infixRDIdKey = mkPreludeMiscIdUnique 343
-infixNDIdKey = mkPreludeMiscIdUnique 344
-roleAnnotDIdKey = mkPreludeMiscIdUnique 345
-standaloneDerivDIdKey = mkPreludeMiscIdUnique 346
-defaultSigDIdKey = mkPreludeMiscIdUnique 347
-patSynDIdKey = mkPreludeMiscIdUnique 348
-patSynSigDIdKey = mkPreludeMiscIdUnique 349
+funDIdKey = mkPreludeMiscIdUnique 320
+valDIdKey = mkPreludeMiscIdUnique 321
+dataDIdKey = mkPreludeMiscIdUnique 322
+newtypeDIdKey = mkPreludeMiscIdUnique 323
+tySynDIdKey = mkPreludeMiscIdUnique 324
+classDIdKey = mkPreludeMiscIdUnique 325
+instanceWithOverlapDIdKey = mkPreludeMiscIdUnique 326
+instanceDIdKey = mkPreludeMiscIdUnique 327
+sigDIdKey = mkPreludeMiscIdUnique 328
+forImpDIdKey = mkPreludeMiscIdUnique 329
+pragInlDIdKey = mkPreludeMiscIdUnique 330
+pragSpecDIdKey = mkPreludeMiscIdUnique 331
+pragSpecInlDIdKey = mkPreludeMiscIdUnique 332
+pragSpecInstDIdKey = mkPreludeMiscIdUnique 333
+pragRuleDIdKey = mkPreludeMiscIdUnique 334
+pragAnnDIdKey = mkPreludeMiscIdUnique 335
+dataFamilyDIdKey = mkPreludeMiscIdUnique 336
+openTypeFamilyDIdKey = mkPreludeMiscIdUnique 337
+dataInstDIdKey = mkPreludeMiscIdUnique 338
+newtypeInstDIdKey = mkPreludeMiscIdUnique 339
+tySynInstDIdKey = mkPreludeMiscIdUnique 340
+closedTypeFamilyDIdKey = mkPreludeMiscIdUnique 341
+infixLDIdKey = mkPreludeMiscIdUnique 342
+infixRDIdKey = mkPreludeMiscIdUnique 343
+infixNDIdKey = mkPreludeMiscIdUnique 344
+roleAnnotDIdKey = mkPreludeMiscIdUnique 345
+standaloneDerivWithStrategyDIdKey = mkPreludeMiscIdUnique 346
+defaultSigDIdKey = mkPreludeMiscIdUnique 347
+patSynDIdKey = mkPreludeMiscIdUnique 348
+patSynSigDIdKey = mkPreludeMiscIdUnique 349
-- type Cxt = ...
cxtIdKey :: Unique
@@ -1022,6 +1047,10 @@ valueAnnotationIdKey = mkPreludeMiscIdUnique 490
typeAnnotationIdKey = mkPreludeMiscIdUnique 491
moduleAnnotationIdKey = mkPreludeMiscIdUnique 492
+-- type DerivPred = ...
+derivClauseIdKey :: Unique
+derivClauseIdKey = mkPreludeMiscIdUnique 493
+
{-
************************************************************************
* *
diff --git a/compiler/rename/RnSource.hs b/compiler/rename/RnSource.hs
index e3c90a8e2d..68038d98bb 100644
--- a/compiler/rename/RnSource.hs
+++ b/compiler/rename/RnSource.hs
@@ -42,11 +42,11 @@ import NameEnv
import Avail
import Outputable
import Bag
-import BasicTypes ( RuleName, pprRuleName )
+import BasicTypes ( DerivStrategy, RuleName, pprRuleName )
import FastString
import SrcLoc
import DynFlags
-import Util ( debugIsOn, partitionWith )
+import Util ( debugIsOn, lengthExceeds, partitionWith )
import HscTypes ( HscEnv, hsc_dflags )
import ListSetOps ( findDupsEq, removeDups, equivClasses )
import Digraph ( SCC, flattenSCC, flattenSCCs
@@ -57,6 +57,7 @@ import qualified GHC.LanguageExtensions as LangExt
import Control.Monad
import Control.Arrow ( first )
import Data.List ( sortBy, mapAccumL )
+import Data.Maybe ( isJust )
import qualified Data.Set as Set ( difference, fromList, toList, null )
{-
@@ -945,11 +946,14 @@ Here 'k' is in scope in the kind signature, just like 'x'.
-}
rnSrcDerivDecl :: DerivDecl RdrName -> RnM (DerivDecl Name, FreeVars)
-rnSrcDerivDecl (DerivDecl ty overlap)
+rnSrcDerivDecl (DerivDecl ty deriv_strat overlap)
= do { standalone_deriv_ok <- xoptM LangExt.StandaloneDeriving
+ ; deriv_strats_ok <- xoptM LangExt.DerivingStrategies
; unless standalone_deriv_ok (addErr standaloneDerivErr)
+ ; failIfTc (isJust deriv_strat && not deriv_strats_ok) $
+ illegalDerivStrategyErr $ fmap unLoc deriv_strat
; (ty', fvs) <- rnLHsInstType (text "In a deriving declaration") ty
- ; return (DerivDecl ty' overlap, fvs) }
+ ; return (DerivDecl ty' deriv_strat overlap, fvs) }
standaloneDerivErr :: SDoc
standaloneDerivErr
@@ -1767,17 +1771,40 @@ rnDataDefn doc (HsDataDefn { dd_ND = new_or_data, dd_cType = cType
L _ (ConDeclGADT {}) : _ -> False
_ -> True
- rn_derivs Nothing
- = return (Nothing, emptyFVs)
- rn_derivs (Just (L loc ds))
- = do { (ds', fvs) <- mapFvRn (rnHsSigType doc) ds
- ; return (Just (L loc ds'), fvs) }
+ rn_derivs (L loc ds)
+ = do { deriv_strats_ok <- xoptM LangExt.DerivingStrategies
+ ; failIfTc (lengthExceeds ds 1 && not deriv_strats_ok)
+ multipleDerivClausesErr
+ ; (ds', fvs) <- mapFvRn (rnLHsDerivingClause deriv_strats_ok doc) ds
+ ; return (L loc ds', fvs) }
+
+rnLHsDerivingClause :: Bool -> HsDocContext -> LHsDerivingClause RdrName
+ -> RnM (LHsDerivingClause Name, FreeVars)
+rnLHsDerivingClause deriv_strats_ok doc
+ (L loc (HsDerivingClause { deriv_clause_strategy = dcs
+ , deriv_clause_tys = L loc' dct }))
+ = do { failIfTc (isJust dcs && not deriv_strats_ok) $
+ illegalDerivStrategyErr $ fmap unLoc dcs
+ ; (dct', fvs) <- mapFvRn (rnHsSigType doc) dct
+ ; return ( L loc (HsDerivingClause { deriv_clause_strategy = dcs
+ , deriv_clause_tys = L loc' dct' })
+ , fvs ) }
badGadtStupidTheta :: HsDocContext -> SDoc
badGadtStupidTheta _
= vcat [text "No context is allowed on a GADT-style data declaration",
text "(You can put a context on each constructor, though.)"]
+illegalDerivStrategyErr :: Maybe DerivStrategy -> SDoc
+illegalDerivStrategyErr ds
+ = vcat [ text "Illegal deriving strategy" <> colon <+> maybe empty ppr ds
+ , text "Use DerivingStrategies to enable this extension" ]
+
+multipleDerivClausesErr :: SDoc
+multipleDerivClausesErr
+ = vcat [ text "Illegal use of multiple, consecutive deriving clauses"
+ , text "Use DerivingStrategies to allow this" ]
+
rnFamDecl :: Maybe Name -- Just cls => this FamilyDecl is nested
-- inside an *class decl* for cls
-- used for associated types
diff --git a/compiler/rename/RnTypes.hs b/compiler/rename/RnTypes.hs
index f201b221a6..d672aa081c 100644
--- a/compiler/rename/RnTypes.hs
+++ b/compiler/rename/RnTypes.hs
@@ -1553,11 +1553,11 @@ extractDataDefnKindVars :: HsDataDefn RdrName -> RnM [Located RdrName]
-- Eg data T a = T1 (S (a :: k) | forall (b::k). T2 (S b)
-- Here k should scope over the whole definition
extractDataDefnKindVars (HsDataDefn { dd_ctxt = ctxt, dd_kindSig = ksig
- , dd_cons = cons, dd_derivs = derivs })
+ , dd_cons = cons, dd_derivs = L _ derivs })
= (nubL . freeKiTyVarsKindVars) <$>
(extract_lctxt TypeLevel ctxt =<<
extract_mb extract_lkind ksig =<<
- extract_mb (extract_sig_tys . unLoc) derivs =<<
+ extract_sig_tys (concatMap (unLoc . deriv_clause_tys . unLoc) derivs) =<<
foldrM (extract_con . unLoc) emptyFKTV cons)
where
extract_con (ConDeclGADT { }) acc = return acc
diff --git a/compiler/typecheck/TcDeriv.hs b/compiler/typecheck/TcDeriv.hs
index 858d9209df..c47b00b827 100644
--- a/compiler/typecheck/TcDeriv.hs
+++ b/compiler/typecheck/TcDeriv.hs
@@ -39,6 +39,7 @@ import RnSource ( addTcgDUs )
import Avail
import Unify( tcUnifyTy )
+import BasicTypes ( DerivStrategy(..) )
import Class
import Type
import ErrUtils
@@ -83,16 +84,16 @@ Overall plan
3. Add the derived bindings, generating InstInfos
-}
--- DerivSpec is purely local to this module
-data DerivSpec theta = DS { ds_loc :: SrcSpan
- , ds_name :: Name -- DFun name
- , ds_tvs :: [TyVar]
- , ds_theta :: theta
- , ds_cls :: Class
- , ds_tys :: [Type]
- , ds_tc :: TyCon
- , ds_overlap :: Maybe OverlapMode
- , ds_newtype :: Maybe Type } -- The newtype rep type
+-- DerivSpec is purely local to this module
+data DerivSpec theta = DS { ds_loc :: SrcSpan
+ , ds_name :: Name -- DFun name
+ , ds_tvs :: [TyVar]
+ , ds_theta :: theta
+ , ds_cls :: Class
+ , ds_tys :: [Type]
+ , ds_tc :: TyCon
+ , ds_overlap :: Maybe OverlapMode
+ , ds_mechanism :: DerivSpecMechanism }
-- This spec implies a dfun declaration of the form
-- df :: forall tvs. theta => C tys
-- The Name is the name for the DFun we'll build
@@ -105,8 +106,8 @@ data DerivSpec theta = DS { ds_loc :: SrcSpan
-- the theta is either the given and final theta, in standalone deriving,
-- or the not-yet-simplified list of constraints together with their origin
- -- ds_newtype = Just rep_ty <=> Generalised Newtype Deriving (GND)
- -- Nothing <=> Vanilla deriving
+ -- ds_mechanism specifies the means by which GHC derives the instance.
+ -- See Note [Deriving strategies]
{-
Example:
@@ -117,9 +118,25 @@ Example:
axiom :RTList a = Tree a
DS { ds_tvs = [a,s], ds_cls = C, ds_tys = [s, T [a]]
- , ds_tc = :RTList, ds_newtype = Just (Tree a) }
+ , ds_tc = :RTList, ds_mechanism = DerivSpecNewtype (Tree a) }
-}
+-- What action to take in order to derive a class instance.
+-- See Note [Deriving strategies]
+-- NB: DerivSpecMechanism is purely local to this module
+data DerivSpecMechanism
+ = DerivSpecStock -- "Standard" classes (except for Generic(1), which is
+ -- covered by the special case of DerivSpecGeneric)
+ (SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff))
+
+ | DerivSpecGeneric -- -XDeriveGeneric
+ (TyCon -> [Type] -> TcM (LHsBinds RdrName, FamInst))
+
+ | DerivSpecNewtype -- -XGeneralizedNewtypeDeriving
+ Type -- ^ The newtype rep type
+
+ | DerivSpecAnyClass -- -XDeriveAnyClass
+
type DerivContext = Maybe ThetaType
-- Nothing <=> Vanilla deriving; infer the context of the instance decl
-- Just theta <=> Standalone deriving: context supplied by programmer
@@ -318,12 +335,12 @@ both of them. So we gather defs/uses from deriving just like anything else.
-}
--- | Stuff needed to process a `deriving` clause
-data DerivInfo = DerivInfo { di_rep_tc :: TyCon
+-- | Stuff needed to process a datatype's `deriving` clauses
+data DerivInfo = DerivInfo { di_rep_tc :: TyCon
-- ^ The data tycon for normal datatypes,
-- or the *representation* tycon for data families
- , di_preds :: [LHsSigType Name]
- , di_ctxt :: SDoc -- ^ error context
+ , di_clauses :: [LHsDerivingClause Name]
+ , di_ctxt :: SDoc -- ^ error context
}
-- | Extract `deriving` clauses of proper data type (skips data families)
@@ -333,9 +350,9 @@ mkDerivInfos decls = concatMapM (mk_deriv . unLoc) decls
mk_deriv decl@(DataDecl { tcdLName = L _ data_name
, tcdDataDefn =
- HsDataDefn { dd_derivs = Just (L _ preds) } })
+ HsDataDefn { dd_derivs = L _ clauses } })
= do { tycon <- tcLookupTyCon data_name
- ; return [DerivInfo { di_rep_tc = tycon, di_preds = preds
+ ; return [DerivInfo { di_rep_tc = tycon, di_clauses = clauses
, di_ctxt = tcMkDeclCtxt decl }] }
mk_deriv _ = return []
@@ -527,10 +544,10 @@ makeDerivSpecs is_boot deriv_infos deriv_decls
------------------------------------------------------------------
-- | Process a `deriving` clause
deriveDerivInfo :: DerivInfo -> TcM [EarlyDerivSpec]
-deriveDerivInfo (DerivInfo { di_rep_tc = rep_tc, di_preds = preds
+deriveDerivInfo (DerivInfo { di_rep_tc = rep_tc, di_clauses = clauses
, di_ctxt = err_ctxt })
= addErrCtxt err_ctxt $
- concatMapM (deriveTyData tvs tc tys) preds
+ concatMapM (deriveForClause . unLoc) clauses
where
tvs = tyConTyVars rep_tc
(tc, tys) = case tyConFamInstSig_maybe rep_tc of
@@ -541,15 +558,23 @@ deriveDerivInfo (DerivInfo { di_rep_tc = rep_tc, di_preds = preds
_ -> (rep_tc, mkTyVarTys tvs) -- datatype
+ deriveForClause :: HsDerivingClause Name -> TcM [EarlyDerivSpec]
+ deriveForClause (HsDerivingClause { deriv_clause_strategy = dcs
+ , deriv_clause_tys = L _ preds })
+ = concatMapM (deriveTyData tvs tc tys (fmap unLoc dcs)) preds
+
------------------------------------------------------------------
deriveStandalone :: LDerivDecl Name -> TcM [EarlyDerivSpec]
-- Standalone deriving declarations
-- e.g. deriving instance Show a => Show (T a)
-- Rather like tcLocalInstDecl
-deriveStandalone (L loc (DerivDecl deriv_ty overlap_mode))
+deriveStandalone (L loc (DerivDecl deriv_ty deriv_strat' overlap_mode))
= setSrcSpan loc $
addErrCtxt (standaloneCtxt deriv_ty) $
do { traceTc "Standalone deriving decl for" (ppr deriv_ty)
+ ; let deriv_strat = fmap unLoc deriv_strat'
+ ; traceTc "Deriving strategy (standalone deriving)" $
+ vcat [ppr deriv_strat, ppr deriv_ty]
; (tvs, theta, cls, inst_tys) <- tcHsClsInstType TcType.InstDeclCtxt deriv_ty
; traceTc "Standalone deriving;" $ vcat
[ text "tvs:" <+> ppr tvs
@@ -575,11 +600,12 @@ deriveStandalone (L loc (DerivDecl deriv_ty overlap_mode))
| isAlgTyCon tc || isDataFamilyTyCon tc -- All other classes
-> do { spec <- mkEqnHelp (fmap unLoc overlap_mode)
tvs cls cls_tys tc tc_args
- (Just theta)
+ (Just theta) deriv_strat
; return [spec] }
_ -> -- Complain about functions, primitive types, etc,
- failWithTc $ derivingThingErr False cls cls_tys inst_ty $
+ failWithTc $ derivingThingErr False cls cls_tys
+ inst_ty deriv_strat $
text "The last argument of the instance must be a data or newtype application"
}
@@ -593,11 +619,12 @@ warnUselessTypeable
------------------------------------------------------------------
deriveTyData :: [TyVar] -> TyCon -> [Type] -- LHS of data or data instance
-- Can be a data instance, hence [Type] args
+ -> Maybe DerivStrategy -- The optional deriving strategy
-> LHsSigType Name -- The deriving predicate
-> TcM [EarlyDerivSpec]
-- The deriving clause of a data or newtype declaration
-- I.e. not standalone deriving
-deriveTyData tvs tc tc_args deriv_pred
+deriveTyData tvs tc tc_args deriv_strat deriv_pred
= setSrcSpan (getLoc (hsSigType deriv_pred)) $ -- Use loc of the 'deriving' item
do { (deriv_tvs, cls, cls_tys, cls_arg_kinds)
<- tcExtendTyVarEnv tvs $
@@ -654,6 +681,9 @@ deriveTyData tvs tc tc_args deriv_pred
tkvs = tyCoVarsOfTypesWellScoped $
final_cls_tys ++ final_tc_args
+ ; traceTc "Deriving strategy (deriving clause)" $
+ vcat [ppr deriv_strat, ppr deriv_pred]
+
; traceTc "derivTyData1" (vcat [ pprTvBndrs tvs, ppr tc, ppr tc_args, ppr deriv_pred
, pprTvBndrs (tyCoVarsOfTypesList tc_args)
, ppr n_args_to_keep, ppr n_args_to_drop
@@ -676,7 +706,8 @@ deriveTyData tvs tc tc_args deriv_pred
-- newtype instance K a a = ... deriving( Monad )
; spec <- mkEqnHelp Nothing tkvs
- cls final_cls_tys tc final_tc_args Nothing
+ cls final_cls_tys tc final_tc_args
+ Nothing deriv_strat
; traceTc "derivTyData" (ppr spec)
; return [spec] } }
@@ -865,13 +896,14 @@ mkEqnHelp :: Maybe OverlapMode
-> TyCon -> [Type]
-> DerivContext -- Just => context supplied (standalone deriving)
-- Nothing => context inferred (deriving on data decl)
+ -> Maybe DerivStrategy
-> TcRn EarlyDerivSpec
-- Make the EarlyDerivSpec for an instance
-- forall tvs. theta => cls (tys ++ [ty])
-- where the 'theta' is optional (that's the Maybe part)
-- Assumes that this declaration is well-kinded
-mkEqnHelp overlap_mode tvs cls cls_tys tycon tc_args mtheta
+mkEqnHelp overlap_mode tvs cls cls_tys tycon tc_args mtheta deriv_strat
= do { -- Find the instance of a data family
-- Note [Looking up family instances for deriving]
fam_envs <- tcGetFamInstEnvs
@@ -896,12 +928,13 @@ mkEqnHelp overlap_mode tvs cls cls_tys tycon tc_args mtheta
; dflags <- getDynFlags
; if isDataTyCon rep_tc then
mkDataTypeEqn dflags overlap_mode tvs cls cls_tys
- tycon tc_args rep_tc rep_tc_args mtheta
+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat
else
mkNewTypeEqn dflags overlap_mode tvs cls cls_tys
- tycon tc_args rep_tc rep_tc_args mtheta }
+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat }
where
- bale_out msg = failWithTc (derivingThingErr False cls cls_tys (mkTyConApp tycon tc_args) msg)
+ bale_out msg = failWithTc (derivingThingErr False cls cls_tys
+ (mkTyConApp tycon tc_args) deriv_strat msg)
{-
Note [Looking up family instances for deriving]
@@ -980,24 +1013,37 @@ mkDataTypeEqn :: DynFlags
-> TyCon -- rep of the above (for type families)
-> [Type] -- rep of the above
-> DerivContext -- Context of the instance, for standalone deriving
+ -> Maybe DerivStrategy -- 'Just' if user requests a particular
+ -- deriving strategy.
+ -- Otherwise, 'Nothing'.
-> TcRn EarlyDerivSpec -- Return 'Nothing' if error
mkDataTypeEqn dflags overlap_mode tvs cls cls_tys
- tycon tc_args rep_tc rep_tc_args mtheta
- = case checkSideConditions dflags mtheta cls cls_tys rep_tc of
- -- NB: pass the *representation* tycon to checkSideConditions
- NonDerivableClass msg -> bale_out (nonStdErr cls $$ msg)
- DerivableClassError msg -> bale_out msg
- CanDerive -> go_for_it
- DerivableViaInstance -> go_for_it
+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat
+ = case deriv_strat of
+ Just DerivStock -> mk_eqn_stock dflags mtheta cls cls_tys rep_tc
+ go_for_it bale_out
+ Just DerivAnyclass -> mk_eqn_anyclass dflags rep_tc cls
+ go_for_it bale_out
+ -- GeneralizedNewtypeDeriving makes no sense for non-newtypes
+ Just DerivNewtype -> bale_out gndNonNewtypeErr
+ -- Lacking a user-requested deriving strategy, we will try to pick
+ -- between the stock or anyclass strategies
+ Nothing -> mk_eqn_no_mechanism dflags mtheta cls cls_tys rep_tc
+ go_for_it bale_out
where
go_for_it = mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args mtheta
- bale_out msg = failWithTc (derivingThingErr False cls cls_tys (mkTyConApp tycon tc_args) msg)
+ bale_out msg = failWithTc (derivingThingErr False cls cls_tys
+ (mkTyConApp tycon tc_args) deriv_strat msg)
mk_data_eqn :: Maybe OverlapMode -> [TyVar] -> Class -> [Type]
-> TyCon -> [TcType] -> TyCon -> [TcType] -> DerivContext
+ -> DerivSpecMechanism -- How GHC should proceed attempting to
+ -- derive this instance, determined in
+ -- mkDataTypeEqn/mkNewTypeEqn
-> TcM EarlyDerivSpec
-mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args mtheta
+mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args
+ mtheta mechanism
= do loc <- getSrcSpanM
dfun_name <- newDFunName' cls tycon
case mtheta of
@@ -1012,7 +1058,7 @@ mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args mtheta
, ds_tc = rep_tc
, ds_theta = inferred_constraints
, ds_overlap = overlap_mode
- , ds_newtype = Nothing }
+ , ds_mechanism = mechanism }
Just theta -> do -- Specified context
return $ GivenTheta $ DS
{ ds_loc = loc
@@ -1021,11 +1067,56 @@ mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args mtheta
, ds_tc = rep_tc
, ds_theta = theta
, ds_overlap = overlap_mode
- , ds_newtype = Nothing }
+ , ds_mechanism = mechanism }
where
inst_ty = mkTyConApp tycon tc_args
inst_tys = cls_tys ++ [inst_ty]
+mk_eqn_stock :: DynFlags -> DerivContext -> Class -> [Type] -> TyCon
+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)
+ -> (SDoc -> TcRn EarlyDerivSpec)
+ -> TcRn EarlyDerivSpec
+mk_eqn_stock dflags mtheta cls cls_tys rep_tc go_for_it bale_out
+ = case checkSideConditions dflags mtheta cls cls_tys rep_tc of
+ CanDerive -> mk_eqn_stock' cls go_for_it
+ DerivableClassError msg -> bale_out msg
+ _ -> bale_out (nonStdErr cls)
+
+mk_eqn_stock' :: Class -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)
+ -> TcRn EarlyDerivSpec
+mk_eqn_stock' cls go_for_it
+ | let ck = classKey cls
+ , ck `elem` [genClassKey, gen1ClassKey]
+ = let gk = if ck == genClassKey then Gen0 else Gen1
+ in go_for_it . DerivSpecGeneric . gen_Generic_binds $ gk
+
+ | otherwise = go_for_it $ case hasStockDeriving cls of
+ Just gen_fn -> DerivSpecStock gen_fn
+ Nothing ->
+ pprPanic "mk_eqn_stock': Not a stock class!" (ppr cls)
+
+mk_eqn_anyclass :: DynFlags -> TyCon -> Class
+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)
+ -> (SDoc -> TcRn EarlyDerivSpec)
+ -> TcRn EarlyDerivSpec
+mk_eqn_anyclass dflags rep_tc cls go_for_it bale_out
+ = case canDeriveAnyClass dflags rep_tc cls of
+ Nothing -> go_for_it DerivSpecAnyClass
+ Just msg -> bale_out msg
+
+mk_eqn_no_mechanism :: DynFlags -> DerivContext -> Class -> [Type] -> TyCon
+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)
+ -> (SDoc -> TcRn EarlyDerivSpec)
+ -> TcRn EarlyDerivSpec
+mk_eqn_no_mechanism dflags mtheta cls cls_tys rep_tc go_for_it bale_out
+ = case checkSideConditions dflags mtheta cls cls_tys rep_tc of
+ -- NB: pass the *representation* tycon to checkSideConditions
+ NonDerivableClass msg -> bale_out (nonStdErr cls $$ msg)
+ DerivableClassError msg -> bale_out msg
+ CanDerive -> mk_eqn_stock' cls go_for_it
+ DerivableViaInstance -> go_for_it DerivSpecAnyClass
+
+
----------------------
inferConstraints :: [TyVar] -> Class -> [TcType] -> TcType
@@ -1219,7 +1310,7 @@ Note [Deriving any class]
~~~~~~~~~~~~~~~~~~~~~~~~~
Classic uses of a deriving clause, or a standalone-deriving declaration, are
for:
- * a built-in class like Eq or Show, for which GHC knows how to generate
+ * a stock class like Eq or Show, for which GHC knows how to generate
the instance code
* a newtype, via the mechanism enabled by GeneralizedNewtypeDeriving
@@ -1244,8 +1335,8 @@ if DeriveAnyClass is enabled.
This is not restricted to Generics; any class can be derived, simply giving
rise to an empty instance.
-Unfortunately, it is not clear how to determine the context (in case of
-standard deriving; in standalone deriving, the user provides the context).
+Unfortunately, it is not clear how to determine the context (when using a
+deriving clause; in standalone deriving, the user provides the context).
GHC uses the same heuristic for figuring out the class context that it uses for
Eq in the case of *-kinded classes, and for Functor in the case of
* -> *-kinded classes. That may not be optimal or even wrong. But in such
@@ -1260,13 +1351,14 @@ cases, standalone deriving can still be used.
-- the data constructors - but we need to be careful to fall back to the
-- family tycon (with indexes) in error messages.
-data DerivStatus = CanDerive -- Standard class, can derive
- | DerivableClassError SDoc -- Standard class, but can't do it
+data DerivStatus = CanDerive -- Stock class, can derive
+ | DerivableClassError SDoc -- Stock class, but can't do it
| DerivableViaInstance -- See Note [Deriving any class]
- | NonDerivableClass SDoc -- Non-standard class
+ | NonDerivableClass SDoc -- Non-stock class
--- A "standard" class is one defined in the Haskell report which GHC knows how
--- to generate code for, such as Eq, Ord, Ix, etc.
+-- A stock class is one either defined in the Haskell report or for which GHC
+-- otherwise knows how to generate code for (possibly requiring the use of a
+-- language extension), such as Eq, Ord, Ix, Data, Generic, etc.
checkSideConditions :: DynFlags -> DerivContext -> Class -> [TcType]
-> TyCon -- tycon
@@ -1277,11 +1369,11 @@ checkSideConditions dflags mtheta cls cls_tys rep_tc
NotValid err -> DerivableClassError err -- Class-specific error
IsValid | null (filterOutInvisibleTypes (classTyCon cls) cls_tys)
-> CanDerive
- -- All derivable classes are unary in the sense that there
- -- should be not types in cls_tys (i.e., no type args other
- -- than last). Note that cls_types can contain invisible
- -- types as well (e.g., for Generic1, which is poly-kinded),
- -- so make sure those are not counted.
+ -- All stock derivable classes are unary in the sense that
+ -- there should be not types in cls_tys (i.e., no type args
+ -- other than last). Note that cls_types can contain
+ -- invisible types as well (e.g., for Generic1, which is
+ -- poly-kinded), so make sure those are not counted.
| otherwise -> DerivableClassError (classArgsErr cls cls_tys)
-- e.g. deriving( Eq s )
@@ -1302,12 +1394,23 @@ nonUnaryErr ct = quotes (ppr ct)
nonStdErr :: Class -> SDoc
nonStdErr cls =
quotes (ppr cls)
- <+> text "is not a standard derivable class (Eq, Show, etc.)"
+ <+> text "is not a stock derivable class (Eq, Show, etc.)"
+
+gndNonNewtypeErr :: SDoc
+gndNonNewtypeErr =
+ text "GeneralizedNewtypeDeriving cannot be used on non-newtypes"
+-- Side conditions (whether the datatype must have at least one constructor,
+-- required language extensions, etc.) for using GHC's stock deriving
+-- mechanism on certain classes (as opposed to classes that require
+-- GeneralizedNewtypeDeriving or DeriveAnyClass). Returns Nothing for a
+-- class for which stock deriving isn't possible.
+--
+-- NB: The classes listed below should be in sync with the ones listed in the
+-- definition of hasStockDeriving in TcGenDeriv (except for Generic(1),
+-- which are handled specially). If you add new class to sideConditions,
+-- make sure to update hasStockDeriving as well!
sideConditions :: DerivContext -> Class -> Maybe Condition
--- Side conditions for classes that GHC knows about,
--- that is, "deriviable classes"
--- Returns Nothing for a non-derivable class
sideConditions mtheta cls
| cls_key == eqClassKey = Just (cond_std `andCond` cond_args cls)
| cls_key == ordClassKey = Just (cond_std `andCond` cond_args cls)
@@ -1548,7 +1651,7 @@ 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/Lift because they respect the type
+ -- Not Read/Show because they respect the type
-- Not Enum, because newtypes are never in Enum
@@ -1636,63 +1739,108 @@ a context for the Data instances:
mkNewTypeEqn :: DynFlags -> Maybe OverlapMode -> [TyVar] -> Class
-> [Type] -> TyCon -> [Type] -> TyCon -> [Type]
- -> DerivContext
+ -> DerivContext -> Maybe DerivStrategy
-> TcRn EarlyDerivSpec
mkNewTypeEqn dflags overlap_mode tvs
- cls cls_tys tycon tc_args rep_tycon rep_tc_args mtheta
+ cls cls_tys tycon tc_args rep_tycon rep_tc_args
+ mtheta deriv_strat
-- Want: instance (...) => cls (cls_tys ++ [tycon tc_args]) where ...
- | ASSERT( length cls_tys + 1 == classArity cls )
- might_derive_via_coercible && ((newtype_deriving && not deriveAnyClass)
- || std_class_via_coercible cls)
- = do traceTc "newtype deriving:" (ppr tycon <+> ppr rep_tys <+> ppr all_preds)
- dfun_name <- newDFunName' cls tycon
- loc <- getSrcSpanM
- case mtheta of
- Just theta -> return $ GivenTheta $ DS
- { ds_loc = loc
- , ds_name = dfun_name, ds_tvs = dfun_tvs
- , ds_cls = cls, ds_tys = inst_tys
- , ds_tc = rep_tycon
- , ds_theta = theta
- , ds_overlap = overlap_mode
- , ds_newtype = Just rep_inst_ty }
- Nothing -> return $ InferTheta $ DS
- { ds_loc = loc
- , ds_name = dfun_name, ds_tvs = dfun_tvs
- , ds_cls = cls, ds_tys = inst_tys
- , ds_tc = rep_tycon
- , ds_theta = all_preds
- , ds_overlap = overlap_mode
- , ds_newtype = Just rep_inst_ty }
- | otherwise
- = case checkSideConditions dflags mtheta cls cls_tys rep_tycon of
- -- Error with standard class
- DerivableClassError msg
- | might_derive_via_coercible -> bale_out (msg $$ suggest_gnd)
- | otherwise -> bale_out msg
-
- -- Must use newtype deriving or DeriveAnyClass
- NonDerivableClass _msg
- -- Too hard, even with newtype deriving
- | newtype_deriving -> bale_out cant_derive_err
- -- Try newtype deriving!
- -- Here we suggest GeneralizedNewtypeDeriving even in cases where it may
- -- not be applicable. See Trac #9600.
- | otherwise -> bale_out (non_std $$ suggest_gnd)
-
- -- CanDerive/DerivableViaInstance
- _ -> do when (newtype_deriving && deriveAnyClass) $
- addWarnTc NoReason
- (sep [ text "Both DeriveAnyClass and GeneralizedNewtypeDeriving are enabled"
- , text "Defaulting to the DeriveAnyClass strategy for instantiating" <+> ppr cls ])
- go_for_it
+ = ASSERT( length cls_tys + 1 == classArity cls )
+ case deriv_strat of
+ Just DerivStock -> mk_eqn_stock dflags mtheta cls cls_tys rep_tycon
+ go_for_it_other bale_out
+ Just DerivAnyclass -> mk_eqn_anyclass dflags rep_tycon cls
+ go_for_it_other bale_out
+ Just DerivNewtype ->
+ -- Since the user explicitly asked for GeneralizedNewtypeDeriving, we
+ -- don't need to perform all of the checks we normally would, such as
+ -- if the class being derived is known to produce ill-roled coercions
+ -- (e.g., Traversable), since we can just derive the instance and let
+ -- it error if need be.
+ -- See Note [Determining whether newtype-deriving is appropriate]
+ if coercion_looks_sensible && newtype_deriving
+ then go_for_it_gnd
+ else bale_out (cant_derive_err $$
+ if newtype_deriving then empty else suggest_gnd)
+ Nothing
+ | might_derive_via_coercible
+ && ((newtype_deriving && not deriveAnyClass)
+ || std_class_via_coercible cls)
+ -> go_for_it_gnd
+ | otherwise
+ -> case checkSideConditions dflags mtheta cls cls_tys rep_tycon of
+ DerivableClassError msg
+ -- There's a particular corner case where
+ --
+ -- 1. -XGeneralizedNewtypeDeriving and -XDeriveAnyClass are both
+ -- enabled at the same time
+ -- 2. We're deriving a particular stock derivable class
+ -- (such as Functor)
+ --
+ -- and the previous cases won't catch it. This fixes the bug
+ -- reported in Trac #10598.
+ | might_derive_via_coercible && newtype_deriving
+ -> go_for_it_gnd
+ -- Otherwise, throw an error for a stock class
+ | might_derive_via_coercible && not newtype_deriving
+ -> bale_out (msg $$ suggest_gnd)
+ | otherwise
+ -> bale_out msg
+
+ -- Must use newtype deriving or DeriveAnyClass
+ NonDerivableClass _msg
+ -- Too hard, even with newtype deriving
+ | newtype_deriving -> bale_out cant_derive_err
+ -- Try newtype deriving!
+ -- Here we suggest GeneralizedNewtypeDeriving even in cases where
+ -- it may not be applicable. See Trac #9600.
+ | otherwise -> bale_out (non_std $$ suggest_gnd)
+
+ -- DerivableViaInstance
+ DerivableViaInstance -> do
+ -- If both DeriveAnyClass and GeneralizedNewtypeDeriving are
+ -- enabled, we take the diplomatic approach of defaulting to
+ -- DeriveAnyClass, but emitting a warning about the choice.
+ -- See Note [Deriving strategies]
+ when (newtype_deriving && deriveAnyClass) $
+ addWarnTc NoReason $ sep
+ [ text "Both DeriveAnyClass and"
+ <+> text "GeneralizedNewtypeDeriving are enabled"
+ , text "Defaulting to the DeriveAnyClass strategy"
+ <+> text "for instantiating" <+> ppr cls ]
+ go_for_it_other DerivSpecAnyClass
+ -- CanDerive
+ CanDerive -> mk_eqn_stock' cls go_for_it_other
where
newtype_deriving = xopt LangExt.GeneralizedNewtypeDeriving dflags
deriveAnyClass = xopt LangExt.DeriveAnyClass dflags
- go_for_it = mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args
- rep_tycon rep_tc_args mtheta
+ go_for_it_gnd = do
+ traceTc "newtype deriving:" $
+ ppr tycon <+> ppr rep_tys <+> ppr all_preds
+ dfun_name <- newDFunName' cls tycon
+ loc <- getSrcSpanM
+ case mtheta of
+ Just theta -> return $ GivenTheta $ DS
+ { ds_loc = loc
+ , ds_name = dfun_name, ds_tvs = dfun_tvs
+ , ds_cls = cls, ds_tys = inst_tys
+ , ds_tc = rep_tycon
+ , ds_theta = theta
+ , ds_overlap = overlap_mode
+ , ds_mechanism = DerivSpecNewtype rep_inst_ty }
+ Nothing -> return $ InferTheta $ DS
+ { ds_loc = loc
+ , ds_name = dfun_name, ds_tvs = dfun_tvs
+ , ds_cls = cls, ds_tys = inst_tys
+ , ds_tc = rep_tycon
+ , ds_theta = all_preds
+ , ds_overlap = overlap_mode
+ , ds_mechanism = DerivSpecNewtype rep_inst_ty }
+ go_for_it_other = mk_data_eqn overlap_mode tvs cls cls_tys tycon
+ tc_args rep_tycon rep_tc_args mtheta
bale_out = bale_out' newtype_deriving
bale_out' b = failWithTc . derivingThingErr b cls cls_tys inst_ty
+ deriv_strat
non_std = nonStdErr cls
suggest_gnd = text "Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension"
@@ -1785,9 +1933,9 @@ mkNewTypeEqn dflags overlap_mode tvs
-- See Note [Determining whether newtype-deriving is appropriate]
might_derive_via_coercible
= not (non_coercible_class cls)
- && eta_ok
- && ats_ok
+ && coercion_looks_sensible
-- && not (isRecursiveTyCon tycon) -- Note [Recursive newtypes]
+ coercion_looks_sensible = eta_ok && ats_ok
-- Check that eta reduction is OK
eta_ok = nt_eta_arity <= length rep_tc_args
@@ -1835,6 +1983,18 @@ or do we do normal deriving? In general, we prefer to do newtype deriving
wherever possible. So, we try newtype deriving unless there's a glaring
reason not to.
+"Glaring reasons not to" include trying to derive a class for which a
+coercion-based instance doesn't make sense. These classes are listed in
+the definition of non_coercible_class. They include Show (since it must
+show the name of the datatype) and Traversable (since a coercion-based
+Traversable instance is ill-roled).
+
+However, non_coercible_class is ignored if the user explicitly requests
+to derive an instance with GeneralizedNewtypeDeriving using the newtype
+deriving strategy. In such a scenario, GHC will unquestioningly try to
+derive the instance via coercions (even if the final generated code is
+ill-roled!). See Note [Deriving strategies].
+
Note that newtype deriving might fail, even after we commit to it. This
is because the derived instance uses `coerce`, which must satisfy its
`Coercible` constraint. This is different than other deriving scenarios,
@@ -2262,15 +2422,19 @@ the renamer. What a great hack!
genInst :: DerivSpec ThetaType
-> TcM (InstInfo RdrName, BagDerivStuff, Maybe Name)
genInst spec@(DS { ds_tvs = tvs, ds_tc = rep_tycon
- , ds_theta = theta, ds_newtype = is_newtype, ds_tys = tys
+ , ds_theta = theta, ds_mechanism = mechanism, ds_tys = tys
, ds_cls = clas, ds_loc = loc })
- | Just rhs_ty <- is_newtype -- See Note [Bindings for Generalised Newtype Deriving]
+ -- See Note [Bindings for Generalised Newtype Deriving]
+ | DerivSpecNewtype rhs_ty <- mechanism
= do { inst_spec <- newDerivClsInst theta spec
+ ; doDerivInstErrorChecks clas inst_spec mechanism
; return ( InstInfo
{ iSpec = inst_spec
, iBinds = InstBindings
- { ib_binds = gen_Newtype_binds loc clas tvs tys rhs_ty
- , ib_tyvars = map Var.varName tvs -- Scope over bindings
+ { ib_binds = gen_Newtype_binds loc clas
+ tvs tys rhs_ty
+ -- Scope over bindings
+ , ib_tyvars = map Var.varName tvs
, ib_pragmas = []
, ib_extensions = [ LangExt.ImpredicativeTypes
, LangExt.RankNTypes ]
@@ -2280,58 +2444,78 @@ genInst spec@(DS { ds_tvs = tvs, ds_tc = rep_tycon
, emptyBag
, Just $ getName $ head $ tyConDataCons rep_tycon ) }
-- See Note [Newtype deriving and unused constructors]
-
| otherwise
- = do { (meth_binds, deriv_stuff) <- genDerivStuff loc clas rep_tycon tys tvs
+ = do { (meth_binds, deriv_stuff) <- genDerivStuff mechanism loc clas
+ rep_tycon tys tvs
; inst_spec <- newDerivClsInst theta spec
+ ; doDerivInstErrorChecks clas inst_spec mechanism
; traceTc "newder" (ppr inst_spec)
- ; let inst_info = InstInfo { iSpec = inst_spec
- , iBinds = InstBindings
- { ib_binds = meth_binds
- , ib_tyvars = map Var.varName tvs
- , ib_pragmas = []
- , ib_extensions = []
- , ib_derived = True } }
+ ; let inst_info
+ = InstInfo { iSpec = inst_spec
+ , iBinds = InstBindings
+ { ib_binds = meth_binds
+ , ib_tyvars = map Var.varName tvs
+ , ib_pragmas = []
+ , ib_extensions = []
+ , ib_derived = True } }
; return ( inst_info, deriv_stuff, Nothing ) }
+doDerivInstErrorChecks :: Class -> ClsInst -> DerivSpecMechanism -> TcM ()
+doDerivInstErrorChecks clas clas_inst mechanism
+ = do { traceTc "doDerivInstErrorChecks" (ppr clas_inst)
+ ; dflags <- getDynFlags
+ -- Check for Generic instances that are derived with an exotic
+ -- deriving strategy like DAC
+ -- See Note [Deriving strategies]
+ ; when (exotic_mechanism && className clas `elem` genericClassNames) $
+ do { failIfTc (safeLanguageOn dflags) gen_inst_err
+ ; when (safeInferOn dflags) (recordUnsafeInfer emptyBag) } }
+ where
+ exotic_mechanism = case mechanism of
+ DerivSpecGeneric _ -> False
+ _ -> True
+
+ gen_inst_err = hang (text ("Generic instances can only be derived in "
+ ++ "Safe Haskell using the stock strategy.") $+$
+ text "In the following instance:")
+ 2 (pprInstanceHdr clas_inst)
+
-- Generate the bindings needed for a derived class that isn't handled by
-- -XGeneralizedNewtypeDeriving.
-genDerivStuff :: SrcSpan -> Class -> TyCon -> [Type] -> [TyVar]
+genDerivStuff :: DerivSpecMechanism -> SrcSpan -> Class
+ -> TyCon -> [Type] -> [TyVar]
-> TcM (LHsBinds RdrName, BagDerivStuff)
-genDerivStuff loc clas tycon inst_tys tyvars
- -- Special case for DeriveGeneric
- | let ck = classKey clas
- , ck `elem` [genClassKey, gen1ClassKey]
- = let gk = if ck == genClassKey then Gen0 else Gen1
+genDerivStuff mechanism loc clas tycon inst_tys tyvars
+ = case mechanism of
+ -- Special case for DeriveGeneric, since it's monadic
+ DerivSpecGeneric gen_fn -> do
-- TODO NSF: correctly identify when we're building Both instead of One
- in do
- (binds, faminst) <- gen_Generic_binds gk tycon inst_tys
- return (binds, unitBag (DerivFamInst faminst))
+ (binds, faminst) <- gen_fn tycon inst_tys
+ return (binds, unitBag (DerivFamInst faminst))
- -- Not deriving Generic(1), so we first check if the compiler has built-in
- -- support for deriving the class in question.
- | Just gen_fn <- hasBuiltinDeriving clas
- = gen_fn loc tycon
+ -- The rest of the stock derivers
+ DerivSpecStock gen_fn -> gen_fn loc tycon
- | otherwise
- = do { -- If there isn't compiler support for deriving the class, our last
- -- resort is -XDeriveAnyClass (since -XGeneralizedNewtypeDeriving
- -- fell through).
+ -- If there isn't compiler support for deriving the class, our last
+ -- resort is -XDeriveAnyClass (since -XGeneralizedNewtypeDeriving
+ -- fell through).
+ DerivSpecAnyClass -> do
let mini_env = mkVarEnv (classTyVars clas `zip` inst_tys)
mini_subst = mkTvSubst (mkInScopeSet (mkVarSet tyvars)) mini_env
-
- ; dflags <- getDynFlags
- ; tyfam_insts <-
- ASSERT2( isNothing (canDeriveAnyClass dflags tycon clas)
- , ppr "genDerivStuff: bad derived class" <+> ppr clas )
- mapM (tcATDefault False loc mini_subst emptyNameSet)
- (classATItems clas)
- ; return ( emptyBag -- No method bindings are needed...
- , listToBag (map DerivFamInst (concat tyfam_insts))
- -- ...but we may need to generate binding for associated type
- -- family default instances.
- -- See Note [DeriveAnyClass and default family instances]
- ) }
+ dflags <- getDynFlags
+ tyfam_insts <-
+ ASSERT2( isNothing (canDeriveAnyClass dflags tycon clas)
+ , ppr "genDerivStuff: bad derived class" <+> ppr clas )
+ mapM (tcATDefault False loc mini_subst emptyNameSet)
+ (classATItems clas)
+ return ( emptyBag -- No method bindings are needed...
+ , listToBag (map DerivFamInst (concat tyfam_insts))
+ -- ...but we may need to generate binding for associated type
+ -- family default instances.
+ -- See Note [DeriveAnyClass and default family instances]
+ )
+
+ _ -> panic "genDerivStuff"
{-
Note [Bindings for Generalised Newtype Deriving]
@@ -2380,6 +2564,54 @@ an implementation for them. We "fill in" the default instances using the
tcATDefault function from TcClsDcl (which is also used in TcInstDcls to handle
the empty instance declaration case).
+Note [Deriving strategies]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+GHC has a notion of deriving strategies, which allow the user to explicitly
+request which approach to use when deriving an instance (enabled with the
+-XDerivingStrategies language extension). For more information, refer to the
+original Trac ticket (#10598) or the associated wiki page:
+https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies
+
+A deriving strategy can be specified in a deriving clause:
+
+ newtype Foo = MkFoo Bar
+ deriving newtype C
+
+Or in a standalone deriving declaration:
+
+ deriving anyclass instance C Foo
+
+-XDerivingStrategies also allows the use of multiple deriving clauses per data
+declaration so that a user can derive some instance with one deriving strategy
+and other instances with another deriving strategy. For example:
+
+ newtype Baz = Baz Quux
+ deriving (Eq, Ord)
+ deriving stock (Read, Show)
+ deriving newtype (Num, Floating)
+ deriving anyclass C
+
+Currently, the deriving strategies are:
+
+* stock: Have GHC implement a "standard" instance for a data type, if possible
+ (e.g., Eq, Ord, Generic, Data, Functor, etc.)
+
+* anyclass: Use -XDeriveAnyClass
+
+* newtype: Use -XGeneralizedNewtypeDeriving
+
+If an explicit deriving strategy is not given, GHC has an algorithm it uses to
+determine which strategy it will actually use. The algorithm is quite long,
+so it lives in the Haskell wiki at
+https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies
+("The deriving strategy resolution algorithm" section).
+
+Internally, GHC uses the DerivStrategy datatype to denote a user-requested
+deriving strategy, and it uses the DerivSpecMechanism datatype to denote what
+GHC will use to derive the instance after taking the above steps. In other
+words, GHC will always settle on a DerivSpecMechnism, even if the user did not
+ask for a particular DerivStrategy (using the algorithm linked to above).
+
************************************************************************
* *
\subsection[TcDeriv-taggery-Names]{What con2tag/tag2con functions are available?}
@@ -2411,16 +2643,22 @@ derivingEtaErr cls cls_tys inst_ty
nest 2 (text "instance (...) =>"
<+> pprClassPred cls (cls_tys ++ [inst_ty]))]
-derivingThingErr :: Bool -> Class -> [Type] -> Type -> MsgDoc -> MsgDoc
-derivingThingErr newtype_deriving clas tys ty why
+derivingThingErr :: Bool -> Class -> [Type] -> Type -> Maybe DerivStrategy
+ -> MsgDoc -> MsgDoc
+derivingThingErr newtype_deriving clas tys ty deriv_strat why
= sep [(hang (text "Can't make a derived instance of")
- 2 (quotes (ppr pred))
+ 2 (quotes (ppr pred) <+> via_mechanism)
$$ nest 2 extra) <> colon,
nest 2 why]
where
- extra | newtype_deriving = text "(even with cunning GeneralizedNewtypeDeriving)"
- | otherwise = Outputable.empty
+ extra | Nothing <- deriv_strat, newtype_deriving
+ = text "(even with cunning GeneralizedNewtypeDeriving)"
+ | otherwise = Outputable.empty
pred = mkClassPred clas (tys ++ [ty])
+ via_mechanism = case deriv_strat of
+ Just strat -> text "with the" <+> ppr strat
+ <+> text "strategy"
+ Nothing -> empty
derivingHiddenErr :: TyCon -> SDoc
derivingHiddenErr tc
diff --git a/compiler/typecheck/TcGenDeriv.hs b/compiler/typecheck/TcGenDeriv.hs
index e7d7bd3143..0a5fbb0cf9 100644
--- a/compiler/typecheck/TcGenDeriv.hs
+++ b/compiler/typecheck/TcGenDeriv.hs
@@ -18,7 +18,7 @@ This is where we do all the grimy bindings' generation.
module TcGenDeriv (
BagDerivStuff, DerivStuff(..),
- hasBuiltinDeriving,
+ hasStockDeriving,
FFoldType(..), functorLikeTraverse,
deepSubtypesContaining, foldDataConArgs,
mkCoerceClassMethEqn,
@@ -102,20 +102,25 @@ data DerivStuff -- Please add this auxiliary stuff
* *
************************************************************************
-Only certain blessed classes can be used in a deriving clause. These classes
-are listed below in the definition of hasBuiltinDeriving (with the exception
+Only certain blessed classes can be used in a deriving clause (without the
+assistance of GeneralizedNewtypeDeriving or DeriveAnyClass). These classes
+are listed below in the definition of hasStockDeriving (with the exception
of Generic and Generic1, which are handled separately in TcGenGenerics).
-A class might be able to be used in a deriving clause if it -XDeriveAnyClass
-is willing to support it. The canDeriveAnyClass function checks if this is
-the case.
+A class might be able to be used in a deriving clause if -XDeriveAnyClass
+is willing to support it. The canDeriveAnyClass function in TcDeriv checks
+if this is the case.
-}
-hasBuiltinDeriving :: Class
+-- NB: The classes listed below should be in sync with the ones listed in
+-- the definition of sideConditions in TcDeriv (except for Generic(1), as
+-- noted above). If you add a new class to hasStockDeriving, make sure to
+-- update sideConditions as well!
+hasStockDeriving :: Class
-> Maybe (SrcSpan
-> TyCon
-> TcM (LHsBinds RdrName, BagDerivStuff))
-hasBuiltinDeriving clas
+hasStockDeriving clas
= assocMaybe gen_list (getUnique clas)
where
gen_list :: [(Unique, SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff))]
diff --git a/compiler/typecheck/TcInstDcls.hs b/compiler/typecheck/TcInstDcls.hs
index 96d7493f79..2e7104cef8 100644
--- a/compiler/typecheck/TcInstDcls.hs
+++ b/compiler/typecheck/TcInstDcls.hs
@@ -683,11 +683,11 @@ tcDataFamInstDecl mb_clsinfo
; checkValidTyCon rep_tc
; let m_deriv_info = case derivs of
- Nothing -> Nothing
- Just (L _ preds) ->
- Just $ DerivInfo { di_rep_tc = rep_tc
- , di_preds = preds
- , di_ctxt = tcMkDataFamInstCtxt decl }
+ L _ [] -> Nothing
+ L _ preds ->
+ Just $ DerivInfo { di_rep_tc = rep_tc
+ , di_clauses = preds
+ , di_ctxt = tcMkDataFamInstCtxt decl }
; fam_inst <- newFamInst (DataFamilyInst rep_tc) axiom
; return (fam_inst, m_deriv_info) } }
diff --git a/docs/users_guide/8.2.1-notes.rst b/docs/users_guide/8.2.1-notes.rst
index 87bc97f768..3e13f57c57 100644
--- a/docs/users_guide/8.2.1-notes.rst
+++ b/docs/users_guide/8.2.1-notes.rst
@@ -38,6 +38,10 @@ Compiler
syntax can be used, in addition to a new form for specifying the cost centre
name. See :ref:`scc-pragma` for examples.
+- It is now possible to explicitly pick a strategy to use when deriving a
+ class instance using the :ghc-flag:`-XDerivingStrategies` language extension
+ (see :ref:`deriving-strategies`).
+
GHCi
~~~~
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index b41a09a097..bcfef017e1 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -3955,10 +3955,10 @@ usually have one "main" parameter for which deriving new instances is
most interesting.
Lastly, all of this applies only for classes other than ``Read``,
-``Show``, ``Typeable``, and ``Data``, for which the built-in derivation
+``Show``, ``Typeable``, and ``Data``, for which the stock derivation
applies (section 4.3.3. of the Haskell Report). (For the standard
classes ``Eq``, ``Ord``, ``Ix``, and ``Bounded`` it is immaterial
-whether the standard method is used or the one described here.)
+whether the stock method is used or the one described here.)
.. _derive-any-class:
@@ -4064,6 +4064,64 @@ Note the following details
and then the normal rules for filling in associated types from the
default will apply, making ``Size Bar`` equal to ``Int``.
+.. _deriving-strategies:
+
+Deriving strategies
+-------------------
+
+In most scenarios, every ``deriving`` statement generates a typeclass instance
+in an unambiguous fashion. There is a corner case, however, where
+simultaneously enabling both the :ghc-flag:`-XGeneralizedNewtypeDeriving` and
+:ghc-flag:`-XDeriveAnyClass` extensions can make deriving become ambiguous.
+Consider the following example ::
+
+ {-# LANGUAGE DeriveAnyClass, GeneralizedNewtypeDeriving #-}
+ newtype Foo = MkFoo Bar deriving C
+
+One could either pick the ``DeriveAnyClass`` approach to deriving ``C`` or the
+``GeneralizedNewtypeDeriving`` approach to deriving ``C``, both of which would
+be equally as valid. GHC defaults to favoring ``DeriveAnyClass`` in such a
+dispute, but this is not a satisfying solution, since that leaves users unable
+to use both language extensions in a single module.
+
+To make this more robust, GHC has a notion of deriving strategies, which allow
+the user to explicitly request which approach to use when deriving an instance.
+To enable this feature, one must enable the :ghc-flag:`-XDerivingStrategies`
+language extension. A deriving strategy can be specified in a deriving
+clause ::
+
+ newtype Foo = MkFoo Bar
+ deriving newtype C
+
+Or in a standalone deriving declaration ::
+
+ deriving anyclass instance C Foo
+
+:ghc-flag:`-XDerivingStrategies` also allows the use of multiple deriving
+clauses per data declaration so that a user can derive some instance with
+one deriving strategy and other instances with another deriving strategy.
+For example ::
+
+ newtype Baz = Baz Quux
+ deriving (Eq, Ord)
+ deriving stock (Read, Show)
+ deriving newtype (Num, Floating)
+ deriving anyclass C
+
+Currently, the deriving strategies are:
+
+- ``stock``: Have GHC implement a "standard" instance for a data type,
+ if possible (e.g., ``Eq``, ``Ord``, ``Generic``, ``Data``, ``Functor``, etc.)
+
+- ``anyclass``: Use :ghc-flag:`-XDeriveAnyClass`
+
+- ``newtype``: Use :ghc-flag:`-XGeneralizedNewtypeDeriving`
+
+If an explicit deriving strategy is not given, GHC has an algorithm for
+determining how it will actually derive an instance. For brevity, the algorithm
+is omitted here. You can read the full algorithm at
+:ghc-wiki:`Wiki page <DerivingStrategies>`.
+
.. _pattern-synonyms:
Pattern synonyms
diff --git a/docs/users_guide/safe_haskell.rst b/docs/users_guide/safe_haskell.rst
index 6ce8b8fc26..653b741339 100644
--- a/docs/users_guide/safe_haskell.rst
+++ b/docs/users_guide/safe_haskell.rst
@@ -284,7 +284,12 @@ Furthermore, we restrict the following features:
the structure of the data type for which the instance is defined, and
allowing manually implemented ``Generic`` instances would break that
invariant. Derived instances (through the :ghc-flag:`-XDeriveGeneric`
- extension) are still allowed. Refer to the
+ extension) are still allowed. Note that the only allowed
+ :ref:`deriving strategy <deriving-strategies>` for deriving ``Generic`` under
+ Safe Haskell is ``stock``, as another strategy (e.g., ``anyclass``) would
+ produce an instance that violates the invariant.
+
+ Refer to the
:ref:`generic programming <generic-programming>` section for more details.
.. _safe-overlapping-instances:
diff --git a/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs b/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
index 85664c2144..ff26ec6ce7 100644
--- a/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
+++ b/libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs
@@ -80,6 +80,7 @@ data Extension
| DefaultSignatures -- Allow extra signatures for defmeths
| DeriveAnyClass -- Allow deriving any class
| DeriveLift -- Allow deriving Lift
+ | DerivingStrategies
| TypeSynonymInstances
| FlexibleContexts
diff --git a/libraries/ghci/GHCi/TH/Binary.hs b/libraries/ghci/GHCi/TH/Binary.hs
index 0bdc756870..e93095662e 100644
--- a/libraries/ghci/GHCi/TH/Binary.hs
+++ b/libraries/ghci/GHCi/TH/Binary.hs
@@ -30,6 +30,8 @@ instance Binary TH.Pat
instance Binary TH.Exp
instance Binary TH.Dec
instance Binary TH.Overlap
+instance Binary TH.DerivClause
+instance Binary TH.DerivStrategy
instance Binary TH.Guard
instance Binary TH.Body
instance Binary TH.Match
diff --git a/libraries/template-haskell/Language/Haskell/TH.hs b/libraries/template-haskell/Language/Haskell/TH.hs
index 7cf342a460..bde698eaa3 100644
--- a/libraries/template-haskell/Language/Haskell/TH.hs
+++ b/libraries/template-haskell/Language/Haskell/TH.hs
@@ -85,11 +85,11 @@ module Language.Haskell.TH(
-- * Library functions
-- ** Abbreviations
- InfoQ, ExpQ, DecQ, DecsQ, ConQ, TypeQ, TyLitQ, CxtQ, PredQ, MatchQ,
- ClauseQ, BodyQ, GuardQ, StmtQ, RangeQ, SourceStrictnessQ,
- SourceUnpackednessQ, BangTypeQ, VarBangTypeQ, StrictTypeQ,
- VarStrictTypeQ, PatQ, FieldPatQ, RuleBndrQ, TySynEqnQ, PatSynDirQ,
- PatSynArgsQ,
+ InfoQ, ExpQ, DecQ, DecsQ, ConQ, TypeQ, TyLitQ, CxtQ, PredQ,
+ DerivClauseQ, MatchQ, ClauseQ, BodyQ, GuardQ, StmtQ, RangeQ,
+ SourceStrictnessQ, SourceUnpackednessQ, BangTypeQ, VarBangTypeQ,
+ StrictTypeQ, VarStrictTypeQ, PatQ, FieldPatQ, RuleBndrQ, TySynEqnQ,
+ PatSynDirQ, PatSynArgsQ,
-- ** Constructors lifted to 'Q'
-- *** Literals
@@ -144,9 +144,10 @@ module Language.Haskell.TH(
-- *** Top Level Declarations
-- **** Data
valD, funD, tySynD, dataD, newtypeD,
+ derivClause, DerivClause(..), DerivStrategy(..),
-- **** Class
classD, instanceD, instanceWithOverlapD, Overlap(..),
- sigD, standaloneDerivD, defaultSigD,
+ sigD, standaloneDerivD, standaloneDerivWithStrategyD, defaultSigD,
-- **** Role annotations
roleAnnotD,
diff --git a/libraries/template-haskell/Language/Haskell/TH/Lib.hs b/libraries/template-haskell/Language/Haskell/TH/Lib.hs
index 2631c0e32d..c42543863d 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Lib.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Lib.hs
@@ -30,6 +30,7 @@ type TypeQ = Q Type
type TyLitQ = Q TyLit
type CxtQ = Q Cxt
type PredQ = Q Pred
+type DerivClauseQ = Q DerivClause
type MatchQ = Q Match
type ClauseQ = Q Clause
type BodyQ = Q Body
@@ -360,20 +361,22 @@ funD nm cs =
tySynD :: Name -> [TyVarBndr] -> TypeQ -> DecQ
tySynD tc tvs rhs = do { rhs1 <- rhs; return (TySynD tc tvs rhs1) }
-dataD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> [ConQ] -> CxtQ -> DecQ
+dataD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> [ConQ] -> [DerivClauseQ]
+ -> DecQ
dataD ctxt tc tvs ksig cons derivs =
do
ctxt1 <- ctxt
cons1 <- sequence cons
- derivs1 <- derivs
+ derivs1 <- sequence derivs
return (DataD ctxt1 tc tvs ksig cons1 derivs1)
-newtypeD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> ConQ -> CxtQ -> DecQ
+newtypeD :: CxtQ -> Name -> [TyVarBndr] -> Maybe Kind -> ConQ -> [DerivClauseQ]
+ -> DecQ
newtypeD ctxt tc tvs ksig con derivs =
do
ctxt1 <- ctxt
con1 <- con
- derivs1 <- derivs
+ derivs1 <- sequence derivs
return (NewtypeD ctxt1 tc tvs ksig con1 derivs1)
classD :: CxtQ -> Name -> [TyVarBndr] -> [FunDep] -> [DecQ] -> DecQ
@@ -452,22 +455,24 @@ pragAnnD target expr
pragLineD :: Int -> String -> DecQ
pragLineD line file = return $ PragmaD $ LineP line file
-dataInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> [ConQ] -> CxtQ -> DecQ
+dataInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> [ConQ] -> [DerivClauseQ]
+ -> DecQ
dataInstD ctxt tc tys ksig cons derivs =
do
ctxt1 <- ctxt
tys1 <- sequence tys
cons1 <- sequence cons
- derivs1 <- derivs
+ derivs1 <- sequence derivs
return (DataInstD ctxt1 tc tys1 ksig cons1 derivs1)
-newtypeInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> ConQ -> CxtQ -> DecQ
+newtypeInstD :: CxtQ -> Name -> [TypeQ] -> Maybe Kind -> ConQ -> [DerivClauseQ]
+ -> DecQ
newtypeInstD ctxt tc tys ksig con derivs =
do
ctxt1 <- ctxt
tys1 <- sequence tys
con1 <- con
- derivs1 <- derivs
+ derivs1 <- sequence derivs
return (NewtypeInstD ctxt1 tc tys1 ksig con1 derivs1)
tySynInstD :: Name -> TySynEqnQ -> DecQ
@@ -534,11 +539,14 @@ roleAnnotD :: Name -> [Role] -> DecQ
roleAnnotD name roles = return $ RoleAnnotD name roles
standaloneDerivD :: CxtQ -> TypeQ -> DecQ
-standaloneDerivD ctxtq tyq =
+standaloneDerivD = standaloneDerivWithStrategyD Nothing
+
+standaloneDerivWithStrategyD :: Maybe DerivStrategy -> CxtQ -> TypeQ -> DecQ
+standaloneDerivWithStrategyD ds ctxtq tyq =
do
ctxt <- ctxtq
ty <- tyq
- return $ StandaloneDerivD ctxt ty
+ return $ StandaloneDerivD ds ctxt ty
defaultSigD :: Name -> TypeQ -> DecQ
defaultSigD n tyq =
@@ -570,6 +578,10 @@ tySynEqn lhs rhs =
cxt :: [PredQ] -> CxtQ
cxt = sequence
+derivClause :: Maybe DerivStrategy -> [PredQ] -> DerivClauseQ
+derivClause ds p = do p' <- cxt p
+ return $ DerivClause ds p'
+
normalC :: Name -> [BangTypeQ] -> ConQ
normalC con strtys = liftM (NormalC con) $ sequence strtys
diff --git a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
index 7376135ed0..8941a8ba81 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
@@ -358,8 +358,12 @@ ppr_dec _ (ClosedTypeFamilyD tfhead@(TypeFamilyHead tc _ _ _) eqns)
= ppr tc <+> sep (map pprParendType lhs) <+> text "=" <+> ppr rhs
ppr_dec _ (RoleAnnotD name roles)
= hsep [ text "type role", ppr name ] <+> hsep (map ppr roles)
-ppr_dec _ (StandaloneDerivD cxt ty)
- = hsep [ text "deriving instance", pprCxt cxt, ppr ty ]
+ppr_dec _ (StandaloneDerivD ds cxt ty)
+ = hsep [ text "deriving"
+ , maybe empty ppr_deriv_strategy ds
+ , text "instance"
+ , pprCxt cxt
+ , ppr ty ]
ppr_dec _ (DefaultSigD n ty)
= hsep [ text "default", pprPrefixOcc n, dcolon, ppr ty ]
ppr_dec _ (PatSynD name args dir pat)
@@ -373,6 +377,12 @@ ppr_dec _ (PatSynD name args dir pat)
ppr_dec _ (PatSynSigD name ty)
= pprPatSynSig name ty
+ppr_deriv_strategy :: DerivStrategy -> Doc
+ppr_deriv_strategy ds = text $
+ case ds of
+ Stock -> "stock"
+ Anyclass -> "anyclass"
+ Newtype -> "newtype"
ppr_overlap :: Overlap -> Doc
ppr_overlap o = text $
@@ -382,7 +392,8 @@ ppr_overlap o = text $
Overlapping -> "{-# OVERLAPPING #-}"
Incoherent -> "{-# INCOHERENT #-}"
-ppr_data :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> [Con] -> Cxt -> Doc
+ppr_data :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> [Con] -> [DerivClause]
+ -> Doc
ppr_data maybeInst ctxt t argsDoc ksig cs decs
= sep [text "data" <+> maybeInst
<+> pprCxt ctxt
@@ -391,7 +402,7 @@ ppr_data maybeInst ctxt t argsDoc ksig cs decs
if null decs
then empty
else nest nestDepth
- $ text "deriving" <+> ppr_cxt_preds decs]
+ $ vcat $ map ppr_deriv_clause decs]
where
pref :: [Doc] -> [Doc]
pref xs | isGadtDecl = xs
@@ -413,7 +424,8 @@ ppr_data maybeInst ctxt t argsDoc ksig cs decs
Nothing -> empty
Just k -> dcolon <+> ppr k
-ppr_newtype :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> Con -> Cxt -> Doc
+ppr_newtype :: Doc -> Cxt -> Name -> Doc -> Maybe Kind -> Con -> [DerivClause]
+ -> Doc
ppr_newtype maybeInst ctxt t argsDoc ksig c decs
= sep [text "newtype" <+> maybeInst
<+> pprCxt ctxt
@@ -422,12 +434,17 @@ ppr_newtype maybeInst ctxt t argsDoc ksig c decs
if null decs
then empty
else nest nestDepth
- $ text "deriving" <+> ppr_cxt_preds decs]
+ $ vcat $ map ppr_deriv_clause decs]
where
ksigDoc = case ksig of
Nothing -> empty
Just k -> dcolon <+> ppr k
+ppr_deriv_clause :: DerivClause -> Doc
+ppr_deriv_clause (DerivClause ds ctxt)
+ = text "deriving" <+> maybe empty ppr_deriv_strategy ds
+ <+> ppr_cxt_preds ctxt
+
ppr_tySyn :: Doc -> Name -> Doc -> Type -> Doc
ppr_tySyn maybeInst t argsDoc rhs
= text "type" <+> maybeInst <+> ppr t <+> argsDoc <+> text "=" <+> ppr rhs
diff --git a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
index 00ac0b308b..afe961b50e 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
@@ -1549,13 +1549,15 @@ data Dec
| ValD Pat Body [Dec] -- ^ @{ p = b where decs }@
| DataD Cxt Name [TyVarBndr]
(Maybe Kind) -- Kind signature (allowed only for GADTs)
- [Con] Cxt
+ [Con] [DerivClause]
-- ^ @{ data Cxt x => T x = A x | B (T x)
- -- deriving (Z,W)}@
+ -- deriving (Z,W)
+ -- deriving stock Eq }@
| NewtypeD Cxt Name [TyVarBndr]
(Maybe Kind) -- Kind signature
- Con Cxt -- ^ @{ newtype Cxt x => T x = A (B x)
- -- deriving (Z,W Q)}@
+ Con [DerivClause] -- ^ @{ newtype Cxt x => T x = A (B x)
+ -- deriving (Z,W Q)
+ -- deriving stock Eq }@
| TySynD Name [TyVarBndr] Type -- ^ @{ type T x = (x,x) }@
| ClassD Cxt Name [TyVarBndr]
[FunDep] [Dec] -- ^ @{ class Eq a => Ord a where ds }@
@@ -1578,14 +1580,18 @@ data Dec
| DataInstD Cxt Name [Type]
(Maybe Kind) -- Kind signature
- [Con] Cxt -- ^ @{ data instance Cxt x => T [x]
- -- = A x | B (T x) deriving (Z,W)}@
+ [Con] [DerivClause] -- ^ @{ data instance Cxt x => T [x]
+ -- = A x | B (T x)
+ -- deriving (Z,W)
+ -- deriving stock Eq }@
| NewtypeInstD Cxt Name [Type]
- (Maybe Kind) -- Kind signature
- Con Cxt -- ^ @{ newtype instance Cxt x => T [x]
- -- = A (B x) deriving (Z,W)}@
- | TySynInstD Name TySynEqn -- ^ @{ type instance ... }@
+ (Maybe Kind) -- Kind signature
+ Con [DerivClause] -- ^ @{ newtype instance Cxt x => T [x]
+ -- = A (B x)
+ -- deriving (Z,W)
+ -- deriving stock Eq }@
+ | TySynInstD Name TySynEqn -- ^ @{ type instance ... }@
-- | open type families (may also appear in [Dec] of 'ClassD' and 'InstanceD')
| OpenTypeFamilyD TypeFamilyHead
@@ -1595,7 +1601,8 @@ data Dec
-- ^ @{ type family F a b = (r :: *) | r -> a where ... }@
| RoleAnnotD Name [Role] -- ^ @{ type role T nominal representational }@
- | StandaloneDerivD Cxt Type -- ^ @{ deriving instance Ord a => Ord (Foo a) }@
+ | StandaloneDerivD (Maybe DerivStrategy) Cxt Type
+ -- ^ @{ deriving stock instance Ord a => Ord (Foo a) }@
| DefaultSigD Name Type -- ^ @{ default size :: Data a => a -> Int }@
-- | Pattern Synonyms
@@ -1620,6 +1627,17 @@ data Overlap = Overlappable -- ^ May be overlapped by more specific instances
-- available.
deriving( Show, Eq, Ord, Data, Generic )
+-- | A single @deriving@ clause at the end of a datatype.
+data DerivClause = DerivClause (Maybe DerivStrategy) Cxt
+ -- ^ @{ deriving stock (Eq, Ord) }@
+ deriving( Show, Eq, Ord, Data, Generic )
+
+-- | What the user explicitly requests when deriving an instance.
+data DerivStrategy = Stock -- ^ A \"standard\" derived instance
+ | Anyclass -- ^ @-XDeriveAnyClass@
+ | Newtype -- ^ @-XGeneralizedNewtypeDeriving@
+ deriving( Show, Eq, Ord, Data, Generic )
+
-- | A Pattern synonym's type. Note that a pattern synonym's *fully*
-- specified type has a peculiar shape coming with two forall
-- quantifiers and two constraint contexts. For example, consider the
diff --git a/libraries/template-haskell/changelog.md b/libraries/template-haskell/changelog.md
index e23fbf7db1..19038c755e 100644
--- a/libraries/template-haskell/changelog.md
+++ b/libraries/template-haskell/changelog.md
@@ -12,6 +12,9 @@
* Add support for visible type applications. (#12530)
+ * Add support for attaching deriving strategies to `deriving` statements
+ (#10598)
+
## 2.11.0.0 *May 2016*
* Bundled with GHC 8.0.1
diff --git a/testsuite/driver/extra_files.py b/testsuite/driver/extra_files.py
index 5af9695885..3f1e75b644 100644
--- a/testsuite/driver/extra_files.py
+++ b/testsuite/driver/extra_files.py
@@ -50,6 +50,7 @@ extra_src_files = {
'T10529c': ['.hpc/', 'hpc_sample_no_parse.tix'],
'T10576a': ['T10576.hs'],
'T10576b': ['T10576.hs'],
+ 'T10598': ['Test10598.hs'],
'T10637': ['A.hs', 'A.hs-boot'],
'T10672_x64': ['Main.hs', 'Printf.hs', 'cxxy.cpp'],
'T10672_x86': ['Main.hs', 'Printf.hs', 'cxxy.cpp'],
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail1.hs b/testsuite/tests/deriving/should_fail/T10598_fail1.hs
new file mode 100644
index 0000000000..ee488869a4
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail1.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module T10598_fail1 where
+
+class Z f where
+ z :: f a b
+
+data A = A Int deriving newtype Show
+newtype B = B Int deriving stock Num
+data C a b = C Int deriving anyclass Z
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail1.stderr b/testsuite/tests/deriving/should_fail/T10598_fail1.stderr
new file mode 100644
index 0000000000..0183ec515d
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail1.stderr
@@ -0,0 +1,17 @@
+
+T10598_fail1.hs:9:40: error:
+ • Can't make a derived instance of
+ ‘Show A’ with the newtype strategy:
+ GeneralizedNewtypeDeriving cannot be used on non-newtypes
+ • In the data declaration for ‘A’
+
+T10598_fail1.hs:10:40: error:
+ • Can't make a derived instance of ‘Num B’ with the stock strategy:
+ ‘Num’ is not a stock derivable class (Eq, Show, etc.)
+ • In the newtype declaration for ‘B’
+
+T10598_fail1.hs:11:41: error:
+ • Can't make a derived instance of
+ ‘Z C’ with the anyclass strategy:
+ The last argument of class ‘Z’ does not have kind * or (* -> *)
+ • In the data declaration for ‘C’
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail2.hs b/testsuite/tests/deriving/should_fail/T10598_fail2.hs
new file mode 100644
index 0000000000..ba77fe0fbf
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail2.hs
@@ -0,0 +1,5 @@
+{-# LANGUAGE DerivingStrategies #-}
+module T10598_fail2 where
+
+data A = A Int deriving anyclass Eq
+newtype B = B Int deriving newtype Eq
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail2.stderr b/testsuite/tests/deriving/should_fail/T10598_fail2.stderr
new file mode 100644
index 0000000000..5ddd81dd1e
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail2.stderr
@@ -0,0 +1,12 @@
+
+T10598_fail2.hs:4:37: error:
+ • Can't make a derived instance of
+ ‘Eq A’ with the anyclass strategy:
+ Try enabling DeriveAnyClass
+ • In the data declaration for ‘A’
+
+T10598_fail2.hs:5:37: error:
+ • Can't make a derived instance of
+ ‘Eq B’ with the newtype strategy:
+ Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
+ • In the newtype declaration for ‘B’
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail3.hs b/testsuite/tests/deriving/should_fail/T10598_fail3.hs
new file mode 100644
index 0000000000..23f9ad987f
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail3.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE Safe #-}
+module T10598_fail3 where
+
+import GHC.Generics
+
+data T = MkT Int deriving anyclass Generic
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail3.stderr b/testsuite/tests/deriving/should_fail/T10598_fail3.stderr
new file mode 100644
index 0000000000..a987a4993d
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail3.stderr
@@ -0,0 +1,5 @@
+
+T10598_fail3.hs:1:1: error:
+ Generic instances can only be derived in Safe Haskell using the stock strategy.
+ In the following instance:
+ instance [safe] Generic T
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail4.hs b/testsuite/tests/deriving/should_fail/T10598_fail4.hs
new file mode 100644
index 0000000000..911111c8ea
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail4.hs
@@ -0,0 +1,4 @@
+module T10598_fail4 where
+
+data Bar = Bar
+ deriving stock Eq
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail4.stderr b/testsuite/tests/deriving/should_fail/T10598_fail4.stderr
new file mode 100644
index 0000000000..7d724d07bd
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail4.stderr
@@ -0,0 +1,4 @@
+
+T10598_fail4.hs:3:1: error:
+ Illegal deriving strategy: stock
+ Use DerivingStrategies to enable this extension
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail5.hs b/testsuite/tests/deriving/should_fail/T10598_fail5.hs
new file mode 100644
index 0000000000..74f57fd307
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail5.hs
@@ -0,0 +1,5 @@
+module T10598_fail5 where
+
+data Foo = Foo
+ deriving Eq
+ deriving Ord
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail5.stderr b/testsuite/tests/deriving/should_fail/T10598_fail5.stderr
new file mode 100644
index 0000000000..af38cdcc51
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail5.stderr
@@ -0,0 +1,4 @@
+
+T10598_fail5.hs:3:1: error:
+ Illegal use of multiple, consecutive deriving clauses
+ Use DerivingStrategies to allow this
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail6.hs b/testsuite/tests/deriving/should_fail/T10598_fail6.hs
new file mode 100644
index 0000000000..673bfcc971
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail6.hs
@@ -0,0 +1,5 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module T10598_fail6 where
+
+newtype F x = F ([x], Maybe x) deriving Functor
diff --git a/testsuite/tests/deriving/should_fail/T10598_fail6.stderr b/testsuite/tests/deriving/should_fail/T10598_fail6.stderr
new file mode 100644
index 0000000000..a80e5bab56
--- /dev/null
+++ b/testsuite/tests/deriving/should_fail/T10598_fail6.stderr
@@ -0,0 +1,6 @@
+
+T10598_fail6.hs:5:41: error:
+ • Can't make a derived instance of ‘Functor F’
+ (even with cunning GeneralizedNewtypeDeriving):
+ You need DeriveFunctor to derive an instance for this class
+ • In the newtype declaration for ‘F’
diff --git a/testsuite/tests/deriving/should_fail/T3833.stderr b/testsuite/tests/deriving/should_fail/T3833.stderr
index da7da919bc..bf9a59cb8a 100644
--- a/testsuite/tests/deriving/should_fail/T3833.stderr
+++ b/testsuite/tests/deriving/should_fail/T3833.stderr
@@ -1,6 +1,6 @@
T3833.hs:9:1: error:
Can't make a derived instance of ‘Monoid (DecodeMap e)’:
- ‘Monoid’ is not a standard derivable class (Eq, Show, etc.)
+ ‘Monoid’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the stand-alone deriving instance for ‘Monoid (DecodeMap e)’
diff --git a/testsuite/tests/deriving/should_fail/T3834.stderr b/testsuite/tests/deriving/should_fail/T3834.stderr
index 3eec64a6c5..9d2223e1f8 100644
--- a/testsuite/tests/deriving/should_fail/T3834.stderr
+++ b/testsuite/tests/deriving/should_fail/T3834.stderr
@@ -1,6 +1,6 @@
T3834.hs:8:1: error:
Can't make a derived instance of ‘C T’:
- ‘C’ is not a standard derivable class (Eq, Show, etc.)
+ ‘C’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the stand-alone deriving instance for ‘C T’
diff --git a/testsuite/tests/deriving/should_fail/T9600.stderr b/testsuite/tests/deriving/should_fail/T9600.stderr
index 2e88277f54..5c03f2efc2 100644
--- a/testsuite/tests/deriving/should_fail/T9600.stderr
+++ b/testsuite/tests/deriving/should_fail/T9600.stderr
@@ -1,6 +1,6 @@
T9600.hs:3:39: error:
Can't make a derived instance of ‘Applicative Foo’:
- ‘Applicative’ is not a standard derivable class (Eq, Show, etc.)
+ ‘Applicative’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the newtype declaration for ‘Foo’
diff --git a/testsuite/tests/deriving/should_fail/T9968a.stderr b/testsuite/tests/deriving/should_fail/T9968a.stderr
index 9f52b2efa9..a72563162e 100644
--- a/testsuite/tests/deriving/should_fail/T9968a.stderr
+++ b/testsuite/tests/deriving/should_fail/T9968a.stderr
@@ -1,6 +1,6 @@
T9968a.hs:8:13: error:
• Can't make a derived instance of ‘Bifunctor Blah’:
- ‘Bifunctor’ is not a standard derivable class (Eq, Show, etc.)
+ ‘Bifunctor’ is not a stock derivable class (Eq, Show, etc.)
The last argument of class ‘Bifunctor’ does not have kind * or (* -> *)
• In the data declaration for ‘Blah’
diff --git a/testsuite/tests/deriving/should_fail/all.T b/testsuite/tests/deriving/should_fail/all.T
index bcb410b6ef..aebfa9e470 100644
--- a/testsuite/tests/deriving/should_fail/all.T
+++ b/testsuite/tests/deriving/should_fail/all.T
@@ -58,4 +58,10 @@ test('T9687', normal, compile_fail, [''])
test('T8984', normal, compile_fail, [''])
test('T9968a', normal, compile_fail, [''])
+test('T10598_fail1', normal, compile_fail, [''])
+test('T10598_fail2', normal, compile_fail, [''])
+test('T10598_fail3', normal, compile_fail, [''])
+test('T10598_fail4', normal, compile_fail, [''])
+test('T10598_fail5', normal, compile_fail, [''])
+test('T10598_fail6', normal, compile_fail, [''])
test('T12163', normal, compile_fail, [''])
diff --git a/testsuite/tests/deriving/should_fail/drvfail008.stderr b/testsuite/tests/deriving/should_fail/drvfail008.stderr
index bfa73927c9..dcd43eca62 100644
--- a/testsuite/tests/deriving/should_fail/drvfail008.stderr
+++ b/testsuite/tests/deriving/should_fail/drvfail008.stderr
@@ -1,6 +1,6 @@
drvfail008.hs:10:43: error:
• Can't make a derived instance of ‘Monad M’:
- ‘Monad’ is not a standard derivable class (Eq, Show, etc.)
+ ‘Monad’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
• In the newtype declaration for ‘M’
diff --git a/testsuite/tests/deriving/should_run/T10598_bug.hs b/testsuite/tests/deriving/should_run/T10598_bug.hs
new file mode 100644
index 0000000000..e34d2c24ee
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T10598_bug.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+module Main where
+
+newtype MyMaybe a = MyMaybe (Maybe a)
+ deriving (Functor, Show)
+
+main :: IO ()
+main = print $ fmap (+1) $ MyMaybe $ Just (10 :: Int)
diff --git a/testsuite/tests/deriving/should_run/T10598_bug.stdout b/testsuite/tests/deriving/should_run/T10598_bug.stdout
new file mode 100644
index 0000000000..31d7367d82
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T10598_bug.stdout
@@ -0,0 +1 @@
+MyMaybe (Just 11)
diff --git a/testsuite/tests/deriving/should_run/T10598_run.hs b/testsuite/tests/deriving/should_run/T10598_run.hs
new file mode 100644
index 0000000000..96238d70f8
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T10598_run.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+module Main where
+
+import Data.Proxy
+
+class C a where
+ c :: proxy a -> Int
+ c _ = 42
+
+instance C Int where
+ c _ = 27
+
+newtype Foo = MkFoo Int
+ deriving Eq
+ deriving anyclass C
+deriving newtype instance Show Foo
+
+main :: IO ()
+main = do
+ print $ MkFoo 100
+ print $ c (Proxy :: Proxy Foo)
diff --git a/testsuite/tests/deriving/should_run/T10598_run.stdout b/testsuite/tests/deriving/should_run/T10598_run.stdout
new file mode 100644
index 0000000000..74a3087e37
--- /dev/null
+++ b/testsuite/tests/deriving/should_run/T10598_run.stdout
@@ -0,0 +1,2 @@
+100
+42
diff --git a/testsuite/tests/deriving/should_run/all.T b/testsuite/tests/deriving/should_run/all.T
index 29e8bbd250..ede2f90140 100644
--- a/testsuite/tests/deriving/should_run/all.T
+++ b/testsuite/tests/deriving/should_run/all.T
@@ -40,5 +40,7 @@ test('T9576', exit_code(1), compile_and_run, [''])
test('T9830', extra_clean(['T9830a.hi', 'T9830a.o']), multimod_compile_and_run, ['T9830','-v0'])
test('T10104', normal, compile_and_run, [''])
test('T10447', normal, compile_and_run, [''])
+test('T10598_bug', normal, compile_and_run, [''])
+test('T10598_run', normal, compile_and_run, [''])
test('T11535', when(opsys('mingw32'), expect_broken_for(12210, ['ghci'])),
compile_and_run, [''])
diff --git a/testsuite/tests/driver/T4437.hs b/testsuite/tests/driver/T4437.hs
index 45e257e4ec..0bef4c5632 100644
--- a/testsuite/tests/driver/T4437.hs
+++ b/testsuite/tests/driver/T4437.hs
@@ -40,7 +40,8 @@ expectedGhcOnlyExtensions = ["RelaxedLayout",
"AlternativeLayoutRule",
"AlternativeLayoutRuleTransitional",
"TypeFamilyDependencies",
- "UnboxedSums"]
+ "UnboxedSums",
+ "DerivingStrategies"]
expectedCabalOnlyExtensions :: [String]
expectedCabalOnlyExtensions = ["Generics",
diff --git a/testsuite/tests/generics/T5462No1.stderr b/testsuite/tests/generics/T5462No1.stderr
index 7c1aec8d79..c82f1b86ee 100644
--- a/testsuite/tests/generics/T5462No1.stderr
+++ b/testsuite/tests/generics/T5462No1.stderr
@@ -3,18 +3,18 @@
T5462No1.hs:24:42: error:
Can't make a derived instance of ‘GFunctor F’:
- ‘GFunctor’ is not a standard derivable class (Eq, Show, etc.)
+ ‘GFunctor’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the newtype declaration for ‘F’
T5462No1.hs:26:23: error:
Can't make a derived instance of ‘C1 G’:
- ‘C1’ is not a standard derivable class (Eq, Show, etc.)
+ ‘C1’ is not a stock derivable class (Eq, Show, etc.)
Try enabling DeriveAnyClass
In the data declaration for ‘G’
T5462No1.hs:27:23: error:
Can't make a derived instance of ‘C2 H’:
- ‘C2’ is not a standard derivable class (Eq, Show, etc.)
+ ‘C2’ is not a stock derivable class (Eq, Show, etc.)
Try enabling DeriveAnyClass
In the data declaration for ‘H’
diff --git a/testsuite/tests/ghc-api/annotations/Makefile b/testsuite/tests/ghc-api/annotations/Makefile
index c557c66624..158dadb72c 100644
--- a/testsuite/tests/ghc-api/annotations/Makefile
+++ b/testsuite/tests/ghc-api/annotations/Makefile
@@ -112,6 +112,10 @@ T11018:
T10276:
$(CHECK_API_ANNOTATIONS) "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`" Test10276.hs
+.PHONY: T10598
+T10598:
+ $(CHECK_API_ANNOTATIONS) "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`" Test10598.hs
+
.PHONY: T11321
T11321:
$(CHECK_API_ANNOTATIONS) "`'$(TEST_HC)' $(TEST_HC_OPTS) --print-libdir | tr -d '\r'`" Test11321.hs
diff --git a/testsuite/tests/ghc-api/annotations/T10598.stdout b/testsuite/tests/ghc-api/annotations/T10598.stdout
new file mode 100644
index 0000000000..21029da26d
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/T10598.stdout
@@ -0,0 +1,36 @@
+---Problems (should be empty list)---
+[]
+---Annotations-----------------------
+-- SrcSpan the annotation is attached to, AnnKeywordId,
+-- list of locations the keyword item appears in
+[
+((Test10598.hs:1:1,AnnModule), [Test10598.hs:5:1-6]),
+((Test10598.hs:1:1,AnnWhere), [Test10598.hs:5:18-22]),
+((Test10598.hs:(7,1)-(9,10),AnnClass), [Test10598.hs:7:1-5]),
+((Test10598.hs:(7,1)-(9,10),AnnSemi), [Test10598.hs:11:1]),
+((Test10598.hs:(7,1)-(9,10),AnnWhere), [Test10598.hs:7:11-15]),
+((Test10598.hs:8:3-21,AnnDcolon), [Test10598.hs:8:5-6]),
+((Test10598.hs:8:3-21,AnnSemi), [Test10598.hs:9:3]),
+((Test10598.hs:8:8-21,AnnRarrow), [Test10598.hs:8:16-17]),
+((Test10598.hs:9:3-10,AnnEqual), [Test10598.hs:9:7]),
+((Test10598.hs:9:3-10,AnnFunId), [Test10598.hs:9:3]),
+((Test10598.hs:(11,1)-(12,10),AnnInstance), [Test10598.hs:11:1-8]),
+((Test10598.hs:(11,1)-(12,10),AnnSemi), [Test10598.hs:14:1]),
+((Test10598.hs:(11,1)-(12,10),AnnWhere), [Test10598.hs:11:16-20]),
+((Test10598.hs:12:3-10,AnnEqual), [Test10598.hs:12:7]),
+((Test10598.hs:12:3-10,AnnFunId), [Test10598.hs:12:3]),
+((Test10598.hs:(14,1)-(17,21),AnnEqual), [Test10598.hs:14:13]),
+((Test10598.hs:(14,1)-(17,21),AnnNewtype), [Test10598.hs:14:1-7]),
+((Test10598.hs:(14,1)-(17,21),AnnSemi), [Test10598.hs:18:1]),
+((Test10598.hs:15:3-22,AnnDeriving), [Test10598.hs:15:3-10]),
+((Test10598.hs:16:3-23,AnnDeriving), [Test10598.hs:16:3-10]),
+((Test10598.hs:16:12-16,AnnStock), [Test10598.hs:16:12-16]),
+((Test10598.hs:17:3-21,AnnDeriving), [Test10598.hs:17:3-10]),
+((Test10598.hs:17:12-19,AnnAnyclass), [Test10598.hs:17:12-19]),
+((Test10598.hs:18:1-34,AnnDeriving), [Test10598.hs:18:1-8]),
+((Test10598.hs:18:1-34,AnnInstance), [Test10598.hs:18:18-25]),
+((Test10598.hs:18:1-34,AnnSemi), [Test10598.hs:19:1]),
+((Test10598.hs:18:10-16,AnnNewtype), [Test10598.hs:18:10-16]),
+((<no location info>,AnnEofPos), [Test10598.hs:19:1])
+]
+
diff --git a/testsuite/tests/ghc-api/annotations/Test10598.hs b/testsuite/tests/ghc-api/annotations/Test10598.hs
new file mode 100644
index 0000000000..8a7651c154
--- /dev/null
+++ b/testsuite/tests/ghc-api/annotations/Test10598.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+module Test10598 where
+
+class C a where
+ c :: proxy a -> Int
+ c _ = 42
+
+instance C Int where
+ c _ = 27
+
+newtype Foo = MkFoo Int
+ deriving Eq
+ deriving stock Ord
+ deriving anyclass C
+deriving newtype instance Show Foo
diff --git a/testsuite/tests/ghc-api/annotations/all.T b/testsuite/tests/ghc-api/annotations/all.T
index c14153dfbb..fac5d56658 100644
--- a/testsuite/tests/ghc-api/annotations/all.T
+++ b/testsuite/tests/ghc-api/annotations/all.T
@@ -21,6 +21,7 @@ test('T10313', normal, run_command, ['$MAKE -s --no-print-directory T10313'
test('T11018', normal, run_command, ['$MAKE -s --no-print-directory T11018'])
test('bundle-export', normal, run_command, ['$MAKE -s --no-print-directory bundle-export'])
test('T10276', normal, run_command, ['$MAKE -s --no-print-directory T10276'])
+test('T10598', normal, run_command, ['$MAKE -s --no-print-directory T10598'])
test('T11321', normal, run_command, ['$MAKE -s --no-print-directory T11321'])
test('T11332', normal, run_command, ['$MAKE -s --no-print-directory T11332'])
test('T11430', normal, run_command, ['$MAKE -s --no-print-directory T11430'])
diff --git a/testsuite/tests/module/mod53.stderr b/testsuite/tests/module/mod53.stderr
index a4c176d11a..754c4524a5 100644
--- a/testsuite/tests/module/mod53.stderr
+++ b/testsuite/tests/module/mod53.stderr
@@ -1,6 +1,6 @@
mod53.hs:4:22: error:
Can't make a derived instance of ‘C T’:
- ‘C’ is not a standard derivable class (Eq, Show, etc.)
+ ‘C’ is not a stock derivable class (Eq, Show, etc.)
Try enabling DeriveAnyClass
In the data declaration for ‘T’
diff --git a/testsuite/tests/parser/should_fail/readFail039.stderr b/testsuite/tests/parser/should_fail/readFail039.stderr
index 91b9a16553..be948f0a07 100644
--- a/testsuite/tests/parser/should_fail/readFail039.stderr
+++ b/testsuite/tests/parser/should_fail/readFail039.stderr
@@ -1,6 +1,6 @@
readFail039.hs:8:14: error:
Can't make a derived instance of ‘C Foo’:
- ‘C’ is not a standard derivable class (Eq, Show, etc.)
+ ‘C’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
In the newtype declaration for ‘Foo’
diff --git a/testsuite/tests/rts/T7919A.hs b/testsuite/tests/rts/T7919A.hs
index ddbdb04750..cfcb329517 100644
--- a/testsuite/tests/rts/T7919A.hs
+++ b/testsuite/tests/rts/T7919A.hs
@@ -23,7 +23,7 @@ largeData =
[normalC dataName
(replicate size (((,) <$> bang noSourceUnpackedness
noSourceStrictness) `ap` [t| Int |]))]
- (cxt [])
+ []
conE' :: Name -> [ExpQ] -> ExpQ
conE' n es = foldl appE (conE n) es
diff --git a/testsuite/tests/safeHaskell/ghci/p16.stderr b/testsuite/tests/safeHaskell/ghci/p16.stderr
index 4b445166d2..52315cce17 100644
--- a/testsuite/tests/safeHaskell/ghci/p16.stderr
+++ b/testsuite/tests/safeHaskell/ghci/p16.stderr
@@ -4,7 +4,7 @@
<interactive>:15:29: error:
• Can't make a derived instance of ‘Op T2’:
- ‘Op’ is not a standard derivable class (Eq, Show, etc.)
+ ‘Op’ is not a stock derivable class (Eq, Show, etc.)
Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension
• In the newtype declaration for ‘T2’
diff --git a/testsuite/tests/th/T10598_TH.hs b/testsuite/tests/th/T10598_TH.hs
new file mode 100644
index 0000000000..aab8bb3aa6
--- /dev/null
+++ b/testsuite/tests/th/T10598_TH.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+module T10598_TH where
+
+import Language.Haskell.TH
+
+class C a
+instance C Int
+
+class C a => D a
+instance D Int
+
+{-
+newtype Foo = MkFoo Int
+ deriving stock Eq
+ deriving anyclass C
+ deriving newtype Read
+
+deriving stock instance Ord Foo
+deriving anyclass instance D Foo
+deriving newtype instance Show Foo
+-}
+
+$(do fooDataName <- newName "Foo"
+ mkFooConName <- newName "MkFoo"
+ let fooType = conT fooDataName
+ sequence [ newtypeD (cxt []) fooDataName [] Nothing
+ (normalC mkFooConName
+ [ bangType (bang noSourceUnpackedness noSourceStrictness)
+ [t| Int |] ])
+ [ derivClause (Just Stock) [ [t| Eq |] ]
+ , derivClause (Just Anyclass) [ [t| C |] ]
+ , derivClause (Just Newtype) [ [t| Read |] ] ]
+ , standaloneDerivWithStrategyD (Just Stock)
+ (cxt []) [t| Ord $(fooType) |]
+ , standaloneDerivWithStrategyD (Just Anyclass)
+ (cxt []) [t| D $(fooType) |]
+ , standaloneDerivWithStrategyD (Just Newtype)
+ (cxt []) [t| Show $(fooType) |] ])
diff --git a/testsuite/tests/th/T10598_TH.stderr b/testsuite/tests/th/T10598_TH.stderr
new file mode 100644
index 0000000000..bcfbb089c5
--- /dev/null
+++ b/testsuite/tests/th/T10598_TH.stderr
@@ -0,0 +1,41 @@
+T10598_TH.hs:(27,3)-(42,50): Splicing declarations
+ do { fooDataName <- newName "Foo";
+ mkFooConName <- newName "MkFoo";
+ let fooType = conT fooDataName;
+ sequence
+ [newtypeD
+ (cxt [])
+ fooDataName
+ []
+ Nothing
+ (normalC
+ mkFooConName
+ [bangType
+ (bang noSourceUnpackedness noSourceStrictness) [t| Int |]])
+ [derivClause (Just Stock) [[t| Eq |]],
+ derivClause (Just Anyclass) [[t| C |]],
+ derivClause (Just Newtype) [[t| Read |]]],
+ standaloneDerivWithStrategyD
+ (Just Stock)
+ (cxt [])
+ [t| Ord $fooType |]
+ pending(rn) [<splice, fooType>],
+ standaloneDerivWithStrategyD
+ (Just Anyclass)
+ (cxt [])
+ [t| D $fooType |]
+ pending(rn) [<splice, fooType>],
+ standaloneDerivWithStrategyD
+ (Just Newtype)
+ (cxt [])
+ [t| Show $fooType |]
+ pending(rn) [<splice, fooType>]] }
+ ======>
+ newtype Foo
+ = MkFoo Int
+ deriving stock (Eq)
+ deriving anyclass (C)
+ deriving newtype (Read)
+ deriving stock instance Ord Foo
+ deriving anyclass instance D Foo
+ deriving newtype instance Show Foo
diff --git a/testsuite/tests/th/T10697_sourceUtil.hs b/testsuite/tests/th/T10697_sourceUtil.hs
index 048a422b99..7ef60b79ae 100644
--- a/testsuite/tests/th/T10697_sourceUtil.hs
+++ b/testsuite/tests/th/T10697_sourceUtil.hs
@@ -10,7 +10,7 @@ makeSimpleDatatype :: Name
-> Q Dec
makeSimpleDatatype tyName conName srcUpk srcStr =
dataD (cxt []) tyName [] Nothing [normalC conName
- [bangType (bang srcUpk srcStr) (conT ''Int)]] (cxt [])
+ [bangType (bang srcUpk srcStr) (conT ''Int)]] []
checkBang :: Name
-> SourceUnpackednessQ
diff --git a/testsuite/tests/th/T10819.hs b/testsuite/tests/th/T10819.hs
index 0a217df479..265934be1a 100644
--- a/testsuite/tests/th/T10819.hs
+++ b/testsuite/tests/th/T10819.hs
@@ -16,7 +16,8 @@ data D = X
instance C Int D where
f X = 2
-$(doSomeTH "N" (mkName "D") [ConT (mkName "C") `AppT` ConT (mkName "Int")])
+$(doSomeTH "N" (mkName "D")
+ [DerivClause Nothing [ConT (mkName "C") `AppT` ConT (mkName "Int")]])
thing :: N
thing = N X
diff --git a/testsuite/tests/th/T8100.hs b/testsuite/tests/th/T8100.hs
index debc2f7166..3551251299 100644
--- a/testsuite/tests/th/T8100.hs
+++ b/testsuite/tests/th/T8100.hs
@@ -9,8 +9,8 @@ data Bar = Bar Int
$( do decs <- [d| deriving instance Eq a => Eq (Foo a)
deriving instance Ord a => Ord (Foo a) |]
- return ( StandaloneDerivD [] (ConT ''Eq `AppT` ConT ''Bar)
- : StandaloneDerivD [] (ConT ''Ord `AppT` ConT ''Bar)
+ return ( StandaloneDerivD Nothing [] (ConT ''Eq `AppT` ConT ''Bar)
+ : StandaloneDerivD Nothing [] (ConT ''Ord `AppT` ConT ''Bar)
: decs ) )
blah :: Ord a => Foo a -> Foo a -> Ordering
diff --git a/testsuite/tests/th/TH_dataD1.hs b/testsuite/tests/th/TH_dataD1.hs
index 1a51ac4aef..9d0c95b1a9 100644
--- a/testsuite/tests/th/TH_dataD1.hs
+++ b/testsuite/tests/th/TH_dataD1.hs
@@ -6,7 +6,7 @@ import Language.Haskell.TH
ds :: Q [Dec]
ds = [d|
$(do { d <- dataD (cxt []) (mkName "D") [] Nothing
- [normalC (mkName "K") []] (cxt [])
+ [normalC (mkName "K") []] []
; return [d]})
|]
diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T
index 5d2fe3b051..d6a124c48e 100644
--- a/testsuite/tests/th/all.T
+++ b/testsuite/tests/th/all.T
@@ -368,6 +368,7 @@ test('T10267', extra_clean(['T10267a.hi', 'T10267a.o']),
test('T10279', normal, compile_fail, ['-v0'])
test('T10306', normal, compile, ['-v0'])
test('T10596', normal, compile, ['-v0'])
+test('T10598_TH', normal, compile, ['-v0 -dsuppress-uniques -ddump-splices'])
test('T10620', normal, compile_and_run, ['-v0'])
test('T10638', normal, compile_fail, ['-v0'])
test('T10697_decided_1', normal, compile_and_run, ['-v0'])
diff --git a/utils/haddock b/utils/haddock
-Subproject 073d899a8f94ddec698f617a38d3420160a7fd0
+Subproject d73b286cb39ad9d02bee4b1a104e817783ceb19
diff --git a/utils/mkUserGuidePart/Options/Language.hs b/utils/mkUserGuidePart/Options/Language.hs
index c2012af915..f86b27d6c7 100644
--- a/utils/mkUserGuidePart/Options/Language.hs
+++ b/utils/mkUserGuidePart/Options/Language.hs
@@ -191,6 +191,13 @@ languageOptions =
, flagReverse = "-XNoDeriveTraversable"
, flagSince = "7.10.1"
}
+ , flag { flagName = "-XDerivingStrategies"
+ , flagDescription =
+ "Enables :ref:`deriving strategies <deriving-strategies>`."
+ , flagType = DynamicFlag
+ , flagReverse = "-XNoDerivingStrategies"
+ , flagSince = "8.2.1"
+ }
, flag { flagName = "-XDisambiguateRecordFields"
, flagDescription =
"Enable :ref:`record field disambiguation <disambiguate-fields>`. "++