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,862
    • Issues 4,862
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 455
    • Merge requests 455
  • 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
  • #17914
Closed
Open
Created Mar 12, 2020 by Simon Peyton Jones@simonpjDeveloper

Improving default method optimisation

Consider this:

class C a where
  op1, op2 :: [a] -> [a]

  op2 xs =  op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))
        ++ op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))
        ++ op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))

instance C Int where
  op1 xs = [sum xs]

instance C b => C [b] where
  op1 xs = map op1 xs

The default method behaves as if it was macro-expanded (compulsorily inlined) at every call site, so we get nice non-recursive bindings. When we write

class C a where
  op1 :: a -> a
  op2 :: a -> a
  op2 x = <op2-dm-expr>

instance C T where
  op1 = <op1-T-expr>

it's as if we wrote

instance C T where
  op1 = <op1-T-expr>
  op2 = <op2-dm-expr>    -- Macro-expanded here

But this is deeply strange and requires special compulsory-inlining of default methods. See Note [INLINE and default methods] in TcInstDcls, and the strange IsDefaultMethod constructor of TcSpecPrags.

Moreover it doesn't work if you to it by hand:

class C a where
  op1, op2 :: [a] -> [a]

dmop2 xs = op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))
        ++ op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))
        ++ op1 (op1 (op1 xs)) ++ reverse (reverse (op1 (op1 xs)))


instance C Int where
  op1 xs = [sum xs]
  op2 = dmop2

instance C b => C [b] where
  op1 xs = map op1 xs
  op2 = dmop2

We get much less good code. I've made dmop2 artifically big so that it doesn't inline. If it inlines, it's just like macro-expansion again, and things are good. But if dmop2 is recursive, that doesn't work either.

What should happen is that the speicaliser should speicalise dmop2 for the instance. But that doesn't happen.

TL;DR: This ticket is about improving the specialiser so that it does a good job of this example. Then we can get rid of the strange code around default methods.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking