Skip to content

Commit

Permalink
Generate INLINE [1] pragmas for TH-derived instances
Browse files Browse the repository at this point in the history
This backports changes to GHC's treatment of derived `Generic(1)` instances in
https://gitlab.haskell.org/ghc/ghc/-/merge_requests/2965, which affect GHC 9.2
or later. The Template Haskell-based implementation is here is adapted from
`linear-generics` (see linear-generics/linear-generics#21).

Fixes #89.
  • Loading branch information
RyanGlScott committed Mar 25, 2023
1 parent 5bfe558 commit 84567fa
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# next [????.??.??]
* Place `INLINE [1]` pragmas on `from` and `to` implementations when types
don't have too many constructors or fields, following the heuristics that GHC
9.2+ uses for `Generic` deriving.

# 1.14.3 [2023.02.27]
* Support `th-abstraction-0.5.*`.

Expand Down
37 changes: 36 additions & 1 deletion src/Generics/Deriving/TH.hs
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,44 @@ deriveInstCommon genericName repName gClass fromName toName opts n = do
fcs = mkBody mkFrom
tcs = mkBody mkTo

inline_pragmas
| inlining_useful cons
#if MIN_VERSION_template_haskell(2,7,0)
= map (\fun_name ->
pragInlD fun_name
# if MIN_VERSION_template_haskell(2,8,0)
Inline FunLike (FromPhase 1)
# else
(inlineSpecPhase True False True 1)
# endif
) [fromName, toName]
#else
= [] -- Sadly, GHC 7.0 and 7.2 appear to suffer from a bug that
-- prevents them from attaching INLINE pragmas to class methods
-- via Template Haskell, so don't bother generating any pragmas at
-- all for these GHC versions.
#endif
| otherwise
= []

fmap (:[]) $
instanceD (cxt []) (conT genericName `appT` return origSigTy)
[return tyIns, funD fromName fcs, funD toName tcs]
(inline_pragmas ++ [return tyIns, funD fromName fcs, funD toName tcs])
where
-- Adapted from inlining_useful in GHC.Tc.Deriv.Generics.mkBindsRep in the
-- GHC source code:
--
-- https://gitlab.haskell.org/ghc/ghc/-/blob/80729d96e47c99dc38e83612dfcfe01cf565eac0/compiler/GHC/Tc/Deriv/Generics.hs#L368-386
inlining_useful cons
| ncons <= 1 = True
| ncons <= 4 = max_fields <= 5
| ncons <= 8 = max_fields <= 2
| ncons <= 16 = max_fields <= 1
| ncons <= 24 = max_fields == 0
| otherwise = False
where
ncons = length cons
max_fields = maximum $ map (length . constructorFields) cons

{- $make
Expand Down

0 comments on commit 84567fa

Please sign in to comment.