Cross-module specialization fails due to irrelevant parametric polymorphism
Here are two modules:
module M1 where
import Data.Functor.Identity
class C f where
c :: f a -> a
instance C Identity where
c (Identity a) = a
newtype Tagged tag a = Tagged a
instance C (Tagged tag) where
c (Tagged a) = a
f :: C f => f a -> a
f a = c a
{-# INLINABLE[0] f #-}
module M2 where
import Data.Functor.Identity
import M1
g :: Identity a -> a
g a = f a
h :: Tagged tag a -> a
h a = f a
Since f
is marked INLINABLE
, I would expect both g
and h
to trigger cross-module specialization of f
. However, if I compile with -ddump-spec
, I find that only f @Identity
is specialized, not f @(Tagged tag)
:
==================== Specialise ====================
Result size of Specialise
= {terms: 32, types: 45, coercions: 42, joins: 0/0}
Rec {
-- RHS size: {terms: 4, types: 5, coercions: 15, joins: 0/0}
$sf :: forall a. Identity a -> a
$sf
= \ (@ a) (a1 :: Identity a) -> (M1.$fCIdentity1 `cast` <Co:15>) a1
end Rec }
-- RHS size: {terms: 5, types: 6, coercions: 12, joins: 0/0}
g :: forall a. Identity a -> a
g = \ (@ a) (a :: Identity a) ->
f (M1.$fCIdentity1 `cast` <Co:12>) a
-- RHS size: {terms: 6, types: 11, coercions: 15, joins: 0/0}
h :: forall tag a. Tagged tag a -> a
h = \ (@ tag) (@ a) (a :: Tagged tag a) ->
f (M1.$fCTagged1 `cast` <Co:15>) a
What gives? The tag
type variable contributes nothing at all to the choice of overloading of f
, so I would expect the specializer to produce a specialized version of f
of type forall tag a. Tagged tag a -> a
.
The difference in this contrived example is irrelevant, as f
will get inlined into h
, anyway. But in a real program of mine, I have a definition with a rather large unfolding that does not get inlined, and I’d like it to be specialized.
Environment
GHC versions tested with:
- 8.6.5
- 8.9.0.20191001