CPR is overly conservative on recursive types as witnessed with ghc-9.4 on a TH derived JSON instance.
I'm looking at the module Auto.T.BigRecord
from aeson compiled with -O2 -fexpose-all-unfoldings -fspecialise-aggressively
in ghc-9.4.4
And for the toJSON method derived for the BigRecord type (stripped by a few fields) I see this core:
-- RHS size: {terms: 51, types: 25, coercions: 13, joins: 0/0}
Auto.T.BigRecord.$w$ctoJSON [InlPrag=[2]]
:: ghc-prim:GHC.Prim.Int#
-> ghc-prim:GHC.Prim.Int#
-> ghc-prim:GHC.Prim.Int#
-> ghc-prim:GHC.Prim.Int#
-> ghc-prim:GHC.Prim.Int#
-> Value
[GblId,
Arity=5,
Str=<L><L><L><L><L>,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=IF_ARGS [0 0 0 0 0] 290 10}]
Auto.T.BigRecord.$w$ctoJSON
= \ (ww_s9He :: ghc-prim:GHC.Prim.Int#)
(ww1_s9Hf :: ghc-prim:GHC.Prim.Int#)
(ww2_s9Hg :: ghc-prim:GHC.Prim.Int#)
(ww3_s9Hh :: ghc-prim:GHC.Prim.Int#)
(ww4_s9Hi :: ghc-prim:GHC.Prim.Int#) ->
case Data.Aeson.KeyMap.$fArbitrary1KeyMap_$sfromList
@Value
(ghc-prim:GHC.Types.:
@Data.Aeson.Types.Internal.Pair
(Auto.T.BigRecord.$fFromJSONBigRecord10
`cast` (Sym (Data.Aeson.Key.N:Key[0])
:: Data.Text.Internal.Text ~R# Key),
Data.Aeson.Types.Internal.Number
(Data.Scientific.Scientific (GHC.Num.Integer.IS ww_s9He) 0#))
(ghc-prim:GHC.Types.:
@Data.Aeson.Types.Internal.Pair
(Auto.T.BigRecord.$fFromJSONBigRecord8
`cast` (Sym (Data.Aeson.Key.N:Key[0])
:: Data.Text.Internal.Text ~R# Key),
Data.Aeson.Types.Internal.Number
(Data.Scientific.Scientific (GHC.Num.Integer.IS ww1_s9Hf) 0#))
(ghc-prim:GHC.Types.:
@Data.Aeson.Types.Internal.Pair
(Auto.T.BigRecord.$fFromJSONBigRecord6
`cast` (Sym (Data.Aeson.Key.N:Key[0])
:: Data.Text.Internal.Text ~R# Key),
Data.Aeson.Types.Internal.Number
(Data.Scientific.Scientific (GHC.Num.Integer.IS ww2_s9Hg) 0#))
(ghc-prim:GHC.Types.:
@Data.Aeson.Types.Internal.Pair
(Auto.T.BigRecord.$fFromJSONBigRecord4
`cast` (Sym (Data.Aeson.Key.N:Key[0])
:: Data.Text.Internal.Text ~R# Key),
Data.Aeson.Types.Internal.Number
(Data.Scientific.Scientific (GHC.Num.Integer.IS ww3_s9Hh) 0#))
(ghc-prim:GHC.Types.:
@Data.Aeson.Types.Internal.Pair
(Auto.T.BigRecord.$fFromJSONBigRecord2
`cast` (Sym (Data.Aeson.Key.N:Key[0])
:: Data.Text.Internal.Text ~R# Key),
Data.Aeson.Types.Internal.Number
(Data.Scientific.Scientific (GHC.Num.Integer.IS ww4_s9Hi) 0#))
(ghc-prim:GHC.Types.[] @Data.Aeson.Types.Internal.Pair))))))
of nt_i8wJ
{ __DEFAULT ->
Data.Aeson.Types.Internal.Object
(nt_i8wJ
`cast` (Sym (Data.Aeson.KeyMap.N:KeyMap[0]) <Value>_N
:: Data.Map.Internal.Map Key Value
~R# Data.Aeson.KeyMap.KeyMap Value))
}
I'm confused why we don't get CPR for the result here. Clearly the application of Object nt_i8wJ
should qualify for CPR as I understand it.
I assume the cast isn't properly handled somewhere in the analysis. I'm currently looking into the code but it might be obvious to you @sgraf812 if you have the time to take a look.
This used to work with ghc-8.10 I haven't checked versions in between.