Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,868
    • Issues 4,868
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 456
    • Merge requests 456
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #17366
Closed
Open
Created Oct 15, 2019 by Alexis King@lexi.lambda

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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking