Skip to content

Specialisation rules fail because dictionary projections do not match

Here is an apparent bug in ghc's specialisation rules. The rewrite rule generated by a SPECIALISE pragma seems to want to pattern-match on exact dictionaries (as well as types). But the compiler is not necessarily able to fully resolve dictionaries before the rules are supposed to fire.

First, the source code we want to specialise:

    {-# SPECIALISE
        hedgehog :: Float -> Vector3 Float
                          -> [Cell_8 (Coord3 Float)]
                          -> [Cell_8 (Vector3 Float)]
                          -> [(Coord3 Float, Coord3 Float)]
      #-}
    hedgehog  :: ( Fractional a, Cell cell vert, Eq vert
                 , Geom coord, Geom vector, Embed vector coord ) =>
                 a -> vector a
                   -> [cell (coord a)]
                   -> [cell (vector a)]
                   -> [(coord a, coord a)]

The core + interface generated for this module contains the rule:

 "SPEC Hedgehog.hedgehog" ALWAYS forall
  Hedgehog.hedgehog @ GHC.Float.Float
                    @ RectGrid.Cell_8
                    @ RectGrid.MyVertex
                    @ Geometries.Coord3
                    @ Geometries.Vector3
                    GHC.Float.$f16
                    RectGrid.$f2
                    RectGrid.$f10
                    Geometries.$f5
                    Geometries.$f3
                    Geometries.$f1

But in a different module (Viewer.hs), here is what the usage site looks like just before the specialisation rules are supposed to fire:

hedgehog_aWr =
  Hedgehog.hedgehog
    @ GHC.Float.Float
    @ RectGrid.Cell_8
    @ RectGrid.MyVertex
    @ Geometries.Coord3
    @ Geometries.Vector3
    GHC.Float.$f16
    RectGrid.$f2
    RectGrid.$f10
    (Dataset.$p2Embed @ Geometries.Vector3 @ Geometries.Coord3 Geometries.$f1)
    (Dataset.$p1Embed @ Geometries.Vector3 @ Geometries.Coord3 Geometries.$f1)
    Geometries.$f1

Notice how there are a couple of dictionary projection functions still sitting there, so although some of the dictionaries match, not all do, and the rule does not fire. However, later the worker-wrapper transformation is able to resolve those outstanding dictionaries, giving eventually:

hedgehog_r2at =
  Hedgehog.$whedgehog
    @ GHC.Float.Float
    @ RectGrid.Cell_8
    @ RectGrid.MyVertex
    @ Geometries.Coord3
    @ Geometries.Vector3
    GHC.Float.$f16
    RectGrid.$f2
    Geometries.$f5
    Geometries.$f3
    Geometries.$f1

So I'm left calling the worker for the polymorphic version of the function, rather than the specialised monomorphic code I wanted. Given how many dictionaries are involved, and that this is the inner loop of the program, I'm hoping there is a big performance win waiting for me, if only I can get that specialised code to run!

A code archive is attached, to help you reproduce the behaviour. I have cut down the code considerably already, but it is still spread over 5 modules: I was unable to cut it down much further without the bug disappearing (probably through inlining or something).

Classes are defined in Dataset.hs, instances in Geometries.hs. The code I want to specialise is in Hedgehog.hs, and the usage site is in Viewer.hs (the main program).

Trac metadata
Trac field Value
Version 6.8.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information