Skip to content

Commit e478378

Browse files
RyanGlScottmpickering
authored andcommitted
DerivingStrategies (#387)
Deriving Strategies
1 parent 70a9cd4 commit e478378

File tree

62 files changed

+8479
-7488
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+8479
-7488
lines changed

src/Language/Haskell/Exts/ExactPrint.hs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ instance ExactP Decl where
604604
exactPC dh
605605
-- the next line works for empty data types since the srcInfoPoints will be empty then
606606
printInterleaved (zip (srcInfoPoints l) ("=": repeat "|")) constrs
607-
maybeEP exactPC mder
607+
errorEP "TODO" -- mder
608608
GDataDecl l dn mctxt dh mk gds mder -> do
609609
let pts = srcInfoPoints l
610610
exactP dn
@@ -622,7 +622,7 @@ instance ExactP Decl where
622622
x:pts' -> do
623623
printStringAt (pos x) "where"
624624
layoutList pts' gds
625-
maybeEP exactPC mder
625+
errorEP "TODO" -- mder
626626
_ -> errorEP "ExactP: Decl: GDataDecl is given too few srcInfoPoints"
627627
DataFamDecl l mctxt dh mk -> do
628628
printString "data"
@@ -645,7 +645,7 @@ instance ExactP Decl where
645645
printStringAt (pos p) "instance"
646646
exactPC t
647647
printInterleaved (zip pts ("=": repeat "|")) constrs
648-
maybeEP exactPC mder
648+
errorEP "TODO" -- mder
649649
_ -> errorEP "ExactP: Decl: DataInsDecl is given too few srcInfoPoints"
650650
GDataInsDecl l dn t mk gds mder ->
651651
case srcInfoPoints l of
@@ -665,7 +665,7 @@ instance ExactP Decl where
665665
x:pts' -> do
666666
printStringAt (pos x) "where"
667667
layoutList pts' gds
668-
maybeEP exactPC mder
668+
errorEP "TODO" -- mder
669669
_ -> errorEP "ExactP: Decl: GDataInsDecl is given too few srcInfoPoints"
670670
_ -> errorEP "ExactP: Decl: GDataInsDecl is given too few srcInfoPoints"
671671
ClassDecl l mctxt dh fds mcds ->
@@ -700,10 +700,11 @@ instance ExactP Decl where
700700
layoutList pts' $ sepInstFunBinds ids
701701
) mids
702702
_ -> errorEP "ExactP: Decl: InstDecl is given too few srcInfoPoints"
703-
DerivDecl l movlp ih ->
703+
DerivDecl l mds movlp ih ->
704704
case srcInfoPoints l of
705705
[_,b] -> do
706706
printString "deriving"
707+
maybeEP exactPC mds
707708
printStringAt (pos b) "instance"
708709
maybeEP exactPC movlp
709710
exactPC ih
@@ -1228,15 +1229,24 @@ instance ExactP Asst where
12281229
WildCardA _ mn -> printString "_" >> maybeEP exactPC mn
12291230

12301231
instance ExactP Deriving where
1231-
exactP (Deriving l ihs) =
1232+
exactP (Deriving l mds ihs) =
12321233
case srcInfoPoints l of
12331234
_:pts -> do
12341235
printString "deriving"
1236+
maybeEP exactPC mds
12351237
case pts of
12361238
[] -> exactPC $ head ihs
12371239
_ -> parenList pts ihs
12381240
_ -> errorEP "ExactP: Deriving is given too few srcInfoPoints"
12391241

1242+
instance ExactP DerivStrategy where
1243+
exactP (DerivStock _) =
1244+
printString "stock"
1245+
exactP (DerivAnyclass _) =
1246+
printString "anyclass"
1247+
exactP (DerivNewtype _) =
1248+
printString "newtype"
1249+
12401250
instance ExactP ClassDecl where
12411251
exactP cdecl = case cdecl of
12421252
ClsDecl _ d -> exactP d
@@ -1291,7 +1301,7 @@ instance ExactP InstDecl where
12911301
exactP dn
12921302
exactPC t
12931303
printInterleaved (zip (srcInfoPoints l) ("=": repeat "|")) constrs
1294-
maybeEP exactPC mder
1304+
errorEP "TODO" -- mder
12951305
InsGData l dn t mk gds mder -> do
12961306
let pts = srcInfoPoints l
12971307
exactP dn
@@ -1308,7 +1318,7 @@ instance ExactP InstDecl where
13081318
x:_ -> do
13091319
printStringAt (pos x) "where"
13101320
mapM_ exactPC gds
1311-
maybeEP exactPC mder
1321+
errorEP "TODO" -- mder
13121322
_ -> errorEP "ExactP: InstDecl: InsGData is given too few srcInfoPoints"
13131323
-- InsInline l inl mact qn -> do
13141324
-- case srcInfoPoints l of

src/Language/Haskell/Exts/Extension.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,13 @@ data KnownExtension =
539539
| TypeFamilyDependencies
540540

541541
| OverloadedLabels
542+
543+
-- | Allow multiple @deriving@ clauses, each optionally qualified with a
544+
-- /strategy/.
545+
| DerivingStrategies
546+
542547
| UnboxedSums
548+
543549
deriving (Show, Read, Eq, Ord, Enum, Bounded, Data, Typeable)
544550

545551
-- | Certain extensions imply other extensions, and this function

src/Language/Haskell/Exts/InternalLexer.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ data Token
195195
| KW_Where
196196
| KW_Qualified
197197
| KW_Pattern
198+
| KW_Stock
199+
| KW_Anyclass
198200

199201
-- FFI
200202
| KW_Foreign
@@ -293,6 +295,8 @@ reserved_ids = [
293295
( "where", (KW_Where, Nothing) ),
294296
( "role", (KW_Role, Just (Any [RoleAnnotations]))),
295297
( "pattern", (KW_Pattern, Just (Any [PatternSynonyms]))),
298+
( "stock", (KW_Stock, Nothing)),
299+
( "anyclass", (KW_Anyclass, Nothing)),
296300

297301
-- FFI
298302
( "foreign", (KW_Foreign, Just (Any [ForeignFunctionInterface])) )
@@ -1440,5 +1444,7 @@ showToken t = case t of
14401444
KW_CApi -> "capi"
14411445
KW_Role -> "role"
14421446
KW_Pattern -> "pattern"
1447+
KW_Stock -> "stock"
1448+
KW_Anyclass -> "anyclass"
14431449

14441450
EOF -> "EOF"

src/Language/Haskell/Exts/InternalParser.ly

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ Reserved Ids
254254
> 'qualified' { Loc $$ KW_Qualified }
255255
> 'role' { Loc $$ KW_Role }
256256
> 'pattern' { Loc $$ KW_Pattern }
257+
> 'stock' { Loc $$ KW_Stock } -- for DerivingStrategies extension
258+
> 'anyclass' { Loc $$ KW_Anyclass } -- for DerivingStrategies extension
257259

258260
Pragmas
259261

@@ -586,22 +588,23 @@ Here there is no special keyword so we must do the check.
586588
> checkEnabled TypeFamilies ;
587589
> let {l = nIS $1 <++> ann $5 <** [$1,$2,$4]};
588590
> return (TypeInsDecl l $3 $5) } }
589-
> | data_or_newtype ctype constrs0 deriving
591+
> | data_or_newtype ctype constrs0 maybe_derivings
590592
> {% do { (cs,dh) <- checkDataHeader $2;
591593
> let { (qds,ss,minf) = $3;
592-
> l = $1 <> $2 <+?> minf <+?> fmap ann $4 <** ss};
594+
> l = $1 <> $2 <+?> minf <+?> fmap ann (listToMaybe $4) <** ss};
593595
> checkDataOrNew $1 qds;
594-
> return (DataDecl l $1 cs dh (reverse qds) $4) } }
596+
> return (DataDecl l $1 cs dh (reverse qds) (reverse $4)) } }
595597

596598
Requires the GADTs extension enabled, handled in gadtlist.
597-
> | data_or_newtype ctype optkind gadtlist deriving
599+
> | data_or_newtype ctype optkind gadtlist maybe_derivings
598600
> {% do { (cs,dh) <- checkDataHeader $2;
599601
> let { (gs,ss,minf) = $4;
600-
> l = ann $1 <+?> minf <+?> fmap ann $5 <** (snd $3 ++ ss)};
602+
> derivs' = reverse $5;
603+
> l = ann $1 <+?> minf <+?> fmap ann (listToMaybe $5) <** (snd $3 ++ ss)};
601604
> checkDataOrNewG $1 gs;
602605
> case (gs, fst $3) of
603-
> ([], Nothing) -> return (DataDecl l $1 cs dh [] $5)
604-
> _ -> checkEnabled GADTs >> return (GDataDecl l $1 cs dh (fst $3) (reverse gs) $5) } }
606+
> ([], Nothing) -> return (DataDecl l $1 cs dh [] derivs')
607+
> _ -> checkEnabled GADTs >> return (GDataDecl l $1 cs dh (fst $3) (reverse gs) derivs') } }
605608

606609
Same as above, lexer will handle it through the 'family' keyword.
607610
> | 'data' 'family' ctype opt_datafam_kind_sig
@@ -610,22 +613,23 @@ Same as above, lexer will handle it through the 'family' keyword.
610613
> return (DataFamDecl l cs dh $4) } }
611614

612615
Here we must check for TypeFamilies.
613-
> | data_or_newtype 'instance' truectype constrs0 deriving
616+
> | data_or_newtype 'instance' truectype constrs0 maybe_derivings
614617
> {% do { -- (cs,c,t) <- checkDataHeader $4;
615618
> checkEnabled TypeFamilies ;
616619
> let { (qds,ss,minf) = $4 ;
617-
> l = $1 <> $3 <+?> minf <+?> fmap ann $5 <** $2:ss };
620+
> l = $1 <> $3 <+?> minf <+?> fmap ann (listToMaybe $5) <** $2:ss };
618621
> checkDataOrNew $1 qds;
619-
> return (DataInsDecl l $1 $3 (reverse qds) $5) } }
622+
> return (DataInsDecl l $1 $3 (reverse qds) (reverse $5)) } }
620623

621624
This style requires both TypeFamilies and GADTs, the latter is handled in gadtlist.
622-
> | data_or_newtype 'instance' truectype optkind gadtlist deriving
625+
> | data_or_newtype 'instance' truectype optkind gadtlist maybe_derivings
623626
> {% do { -- (cs,c,t) <- checkDataHeader $4;
624627
> checkEnabled TypeFamilies ;
625628
> let {(gs,ss,minf) = $5;
626-
> l = ann $1 <+?> minf <+?> fmap ann $6 <** ($2:snd $4 ++ ss)};
629+
> derivs' = reverse $6;
630+
> l = ann $1 <+?> minf <+?> fmap ann (listToMaybe derivs') <** ($2:snd $4 ++ ss)};
627631
> checkDataOrNewG $1 gs;
628-
> return (GDataInsDecl l $1 $3 (fst $4) (reverse gs) $6) } }
632+
> return (GDataInsDecl l $1 $3 (fst $4) (reverse gs) derivs') } }
629633
> | 'class' ctype fds optcbody
630634
> {% do { (cs,dh) <- checkClassHeader $2;
631635
> let {(fds,ss1,minf1) = $3;(mcs,ss2,minf2) = $4} ;
@@ -637,11 +641,11 @@ This style requires both TypeFamilies and GADTs, the latter is handled in gadtli
637641
> return (InstDecl (nIS $1 <++> ann $3 <+?> minf <** ($1:ss)) $2 ih mis) } }
638642

639643
Requires the StandaloneDeriving extension enabled.
640-
> | 'deriving' 'instance' optoverlap ctype
644+
> | 'deriving' deriv_strategy 'instance' optoverlap ctype
641645
> {% do { checkEnabled StandaloneDeriving ;
642-
> ih <- checkInstHeader $4;
643-
> let {l = nIS $1 <++> ann $4 <** [$1,$2]};
644-
> return (DerivDecl l $3 ih) } }
646+
> ih <- checkInstHeader $5;
647+
> let {l = nIS $1 <++> ann $5 <** [$1,$3]};
648+
> return (DerivDecl l $2 $4 ih) } }
645649
> | 'default' '(' typelist ')'
646650
> { DefaultDecl ($1 <^^> $4 <** ($1:$2 : snd $3 ++ [$4])) (fst $3) }
647651

@@ -1165,14 +1169,24 @@ as qcon and then check separately that they are truly unqualified.
11651169
> fielddecl :: { FieldDecl L }
11661170
> : vars '::' truectype { let (ns,ss,l) = $1 in FieldDecl (l <++> ann $3 <** (reverse ss ++ [$2])) (reverse ns) $3 }
11671171

1168-
> deriving :: { Maybe (Deriving L) }
1169-
> : {- empty -} { Nothing }
1170-
> | 'deriving' qtycls1 { let l = nIS $1 <++> ann $2 <** [$1] in Just $ Deriving l [IRule (ann $2) Nothing Nothing $2] }
1171-
> | 'deriving' '(' ')' { Just $ Deriving ($1 <^^> $3 <** [$1,$2,$3]) [] }
1172-
> | 'deriving' '(' dclasses ')' { -- Distinguish deriving (Show) from deriving Show (#189)
1173-
> case fst $3 of
1174-
> [ts] -> Just $ Deriving ($1 <^^> $4 <** [$1]) [IParen ($2 <^^> $4 <** [$2,$4]) ts]
1175-
> tss -> Just $ Deriving ($1 <^^> $4 <** $1:$2: reverse (snd $3) ++ [$4]) (reverse tss)}
1172+
> maybe_derivings :: { [Deriving L] }
1173+
> : {- empty -} { [] }
1174+
> | derivings { $1 }
1175+
1176+
> derivings :: { [Deriving L] }
1177+
> : derivings deriving { $2 : $1 }
1178+
> | deriving { [$1] }
1179+
1180+
> deriving :: { Deriving L }
1181+
> : 'deriving' deriv_strategy qtycls1
1182+
> { let l = nIS $1 <++> ann $3 <** [$1] in Deriving l $2 [IRule (ann $3) Nothing Nothing $3] }
1183+
> | 'deriving' deriv_strategy '(' ')'
1184+
> { Deriving ($1 <^^> $4 <** [$1,$3,$4]) $2 [] }
1185+
> | 'deriving' deriv_strategy '(' dclasses ')'
1186+
> { -- Distinguish deriving (Show) from deriving Show (#189)
1187+
> case fst $4 of
1188+
> [ts] -> Deriving ($1 <^^> $5 <** [$1]) $2 [IParen ($3 <^^> $5 <** [$3,$5]) ts]
1189+
> tss -> Deriving ($1 <^^> $5 <** $1:$3: reverse (snd $4) ++ [$5]) $2 (reverse tss)}
11761190

11771191
> dclasses :: { ([InstRule L],[S]) }
11781192
> : types1 {% checkDeriving (fst $1) >>= \ds -> return (ds, snd $1) }
@@ -1299,16 +1313,16 @@ Associated types require the TypeFamilies extension enabled.
12991313
> : 'type' truedtype '=' truectype
13001314
> {% do { -- no checkSimpleType $4 since dtype may contain type patterns
13011315
> return (InsType (nIS $1 <++> ann $4 <** [$1,$3]) $2 $4) } }
1302-
> | data_or_newtype truectype constrs0 deriving
1316+
> | data_or_newtype truectype constrs0 maybe_derivings
13031317
> {% do { -- (cs,c,t) <- checkDataHeader $4;
13041318
> let {(ds,ss,minf) = $3};
13051319
> checkDataOrNew $1 ds;
1306-
> return (InsData ($1 <> $2 <+?> minf <+?> fmap ann $4 <** ss ) $1 $2 (reverse ds) $4) } }
1307-
> | data_or_newtype truectype optkind gadtlist deriving
1320+
> return (InsData ($1 <> $2 <+?> minf <+?> fmap ann (listToMaybe $4) <** ss ) $1 $2 (reverse ds) (reverse $4)) } }
1321+
> | data_or_newtype truectype optkind gadtlist maybe_derivings
13081322
> {% do { -- (cs,c,t) <- checkDataHeader $4;
13091323
> let { (gs,ss,minf) = $4 } ;
13101324
> checkDataOrNewG $1 gs;
1311-
> return $ InsGData (ann $1 <+?> minf <+?> fmap ann $5 <** (snd $3 ++ ss)) $1 $2 (fst $3) (reverse gs) $5 } }
1325+
> return $ InsGData (ann $1 <+?> minf <+?> fmap ann (listToMaybe $5) <** (snd $3 ++ ss)) $1 $2 (fst $3) (reverse gs) (reverse $5) } }
13121326

13131327
-----------------------------------------------------------------------------
13141328
Value definitions
@@ -1956,6 +1970,8 @@ Identifiers and Symbols
19561970
> | 'js' { js_name (nIS $1) }
19571971
> | 'javascript' { javascript_name (nIS $1) }
19581972
> | 'capi' { capi_name (nIS $1) }
1973+
> | 'stock' { stock_name (nIS $1) }
1974+
> | 'anyclass' { anyclass_name (nIS $1) }
19591975

19601976
> varid :: { Name L }
19611977
> : varid_no_safety { $1 }
@@ -2097,6 +2113,20 @@ Pattern Synonyms
20972113
> | type
20982114
> {% checkType $1 >>= \t -> return (Nothing, [], Nothing, Nothing, t) }
20992115

2116+
-----------------------------------------------------------------------------
2117+
Deriving strategies
2118+
2119+
> deriv_strategy :: { Maybe (DerivStrategy L) }
2120+
> : 'stock' {% do { checkEnabled DerivingStrategies
2121+
> ; return (Just (DerivStock (nIS $1))) } }
2122+
> | 'anyclass' {% do { checkEnabled DerivingStrategies
2123+
> ; checkEnabled DeriveAnyClass
2124+
> ; return (Just (DerivAnyclass (nIS $1))) } }
2125+
> | 'newtype' {% do { checkEnabled DerivingStrategies
2126+
> ; checkEnabled GeneralizedNewtypeDeriving
2127+
> ; return (Just (DerivNewtype (nIS $1))) } }
2128+
> | {- empty -} { Nothing }
2129+
21002130
-----------------------------------------------------------------------------
21012131
Miscellaneous (mostly renamings)
21022132

src/Language/Haskell/Exts/Pretty.hs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -409,13 +409,13 @@ instance Pretty (Decl l) where
409409

410410
<+> (myVcat (zipWith (<+>) (equals : repeat (char '|'))
411411
(map pretty constrList))
412-
$$$ maybePP pretty derives)
412+
$$$ ppIndent letIndent (map pretty derives))
413413

414414
pretty (GDataDecl _ don context dHead optkind gadtList derives) =
415415
mySep ( [pretty don, maybePP pretty context, pretty dHead]
416416
++ ppOptKind optkind ++ [text "where"])
417417
$$$ ppBody classIndent (map pretty gadtList)
418-
$$$ ppIndent letIndent [maybePP pretty derives]
418+
$$$ ppIndent letIndent (map pretty derives)
419419

420420
pretty (TypeFamDecl _ dHead optkind optinj) =
421421
mySep ([text "type", text "family", pretty dHead
@@ -437,13 +437,13 @@ instance Pretty (Decl l) where
437437
mySep [pretty don, text "instance ", pretty ntype]
438438
<+> (myVcat (zipWith (<+>) (equals : repeat (char '|'))
439439
(map pretty constrList))
440-
$$$ maybePP pretty derives)
440+
$$$ ppIndent letIndent (map pretty derives))
441441

442442
pretty (GDataInsDecl _ don ntype optkind gadtList derives) =
443443
mySep ( [pretty don, text "instance ", pretty ntype]
444444
++ ppOptKind optkind ++ [text "where"])
445445
$$$ ppBody classIndent (map pretty gadtList)
446-
$$$ maybePP pretty derives
446+
$$$ ppIndent letIndent (map pretty derives)
447447

448448
--m{spacing=False}
449449
-- special case for empty class declaration
@@ -464,8 +464,9 @@ instance Pretty (Decl l) where
464464
, pretty iHead, text "where"])
465465
$$$ ppBody classIndent (fromMaybe [] ((ppDecls False) <$> declList))
466466

467-
pretty (DerivDecl _ overlap irule) =
468-
mySep ( [text "deriving"
467+
pretty (DerivDecl _ mds overlap irule) =
468+
mySep ( [ text "deriving"
469+
, maybePP pretty mds
469470
, text "instance"
470471
, maybePP pretty overlap
471472
, pretty irule])
@@ -676,13 +677,13 @@ instance Pretty (InstDecl l) where
676677
mySep [pretty don, pretty ntype]
677678
<+> (myVcat (zipWith (<+>) (equals : repeat (char '|'))
678679
(map pretty constrList))
679-
$$$ maybePP pretty derives)
680+
$$$ ppIndent letIndent (map pretty derives))
680681

681682
pretty (InsGData _ don ntype optkind gadtList derives) =
682683
mySep ( [pretty don, pretty ntype]
683684
++ ppOptKind optkind ++ [text "where"])
684685
$$$ ppBody classIndent (map pretty gadtList)
685-
$$$ maybePP pretty derives
686+
$$$ ppIndent letIndent (map pretty derives)
686687

687688
-- pretty (InsInline loc inl activ name) =
688689
-- markLine loc $
@@ -802,9 +803,15 @@ instance Pretty (Unpackedness l) where
802803
pretty NoUnpackPragma {} = empty
803804

804805
instance Pretty (Deriving l) where
805-
pretty (Deriving _ []) = empty
806-
pretty (Deriving _ [d]) = text "deriving" <+> pretty d
807-
pretty (Deriving _ d) = text "deriving" <+> parenList (map pretty d)
806+
pretty (Deriving _ mds [d]) = text "deriving" <+> maybePP pretty mds <+> pretty d
807+
pretty (Deriving _ mds d) = text "deriving" <+> maybePP pretty mds <+> parenList (map pretty d)
808+
809+
instance Pretty (DerivStrategy l) where
810+
pretty ds = text $
811+
case ds of
812+
DerivStock _ -> "stock"
813+
DerivAnyclass _ -> "anyclass"
814+
DerivNewtype _ -> "newtype"
808815

809816
------------------------- Types -------------------------
810817
ppBType :: Type l -> Doc

0 commit comments

Comments
 (0)