Opened 7 years ago

Closed 4 years ago

#5821 closed bug (fixed)

SPECIALISE fails with a cryptic warning

Reported by: rl Owned by: ezyang
Priority: normal Milestone: 7.10.1
Component: Compiler Version: 7.5
Keywords: Cc: illissius@…, mikhail.vorozhtsov@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect warning at compile-time Test Case: simplCore/should_compile/T5821
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D610
Wiki Page:

Description (last modified by ezyang)

Example:

{-# LANGUAGE TypeFamilies #-}                                                      
module A where

type family T a
type instance T Int = Bool

foo :: Num a => a -> T a
foo = undefined

{-# SPECIALISE foo :: Int -> Bool #-}

GHC produces this warning:

    RULE left-hand side too complicated to desugar
      case cobox of _ { GHC.Types.Eq# cobox ->
      (foo @ Int $dNum)
      `cast` (<Int> -> cobox :: (Int -> T Int) ~# (Int -> Bool))
      }

Given that rewrite rules don't reliably work in the presence of type families, I somewhat suspect that GHC won't be able to generate a sensible specialisation here but it should produce a better diagnostic.

Change History (15)

comment:1 Changed 7 years ago by igloo

difficulty: Unknown
Milestone: 7.6.1

comment:2 Changed 6 years ago by illissius

Cc: illissius@… added

With GHC 7.0 the message was at least a bit less noisy:

             RULE left-hand side too complicated to desugar
               (foo @ Int $dNum)
               `cast` (Int -> co :: (Int -> T Int) ~ (Int -> Bool))

Also, I can work around it by writing

{-# SPECIALIZE foo :: Int -> T Int #-}

that is, leave the type family unexpanded, and then it works.

But if I change the type signature of foo a bit, to introduce a name for T a:

foo :: (Num a, b ~ T a) => a -> b
{-# SPECIALIZE foo :: Int -> T Int #-}

that breaks again, with the 7.0 error message staying much the same (only an @ Bool and an @ co added to the second line), and the 7.4 message getting considerably uglier:

             RULE left-hand side too complicated to desugar
               case cobox of _ { GHC.Types.Eq# cobox ->
               (foo
                  @ Int
                  @ Bool
                  $dNum
                  (case cobox of _ { GHC.Types.Eq# cobox ->
                   GHC.Types.Eq# @ * @ Bool @ (T Int) @~ cobox
                   }))
               `cast` (<Int> -> cobox :: (Int -> Bool) ~# (Int -> T Int))
               }

If I once again change the pragma to match the new "shape" of the signature:

{-# SPECIALISE foo :: b ~ T Int => Int -> b #-}

then with 7.0 it compiles fine!, while 7.4 outputs this perfect monstrosity:

             RULE left-hand side too complicated to desugar
               let {
                 cobox :: T Int ~ b
                 [LclId]
                 cobox =
                   case cobox of _ { GHC.Types.Eq# cobox ->
                   GHC.Types.Eq# @ * @ (T Int) @ b @~ (Sym cobox)
                   } } in
               let {
                 cobox :: b ~ Bool
                 [LclId]
                 cobox =
                   case cobox of _ { GHC.Types.Eq# cobox ->
                   GHC.Types.Eq#
                     @ * @ b @ Asdf.R:TInt @~ (Sym cobox ; Asdf.TFCo:R:TInt)
                   } } in
               foo
                 @ Int
                 @ b
                 GHC.Num.$fNumInt
                 (case case case case cobox of _ { GHC.Types.Eq# cobox ->
                                 case cobox of _ { GHC.Types.Eq# cobox ->
                                 GHC.Types.Eq# @ * @ (T Int) @ Bool @~ (cobox ; cobox)
                                 }
                                 }
                            of _ { GHC.Types.Eq# cobox ->
                            case case cobox of _ { GHC.Types.Eq# cobox ->
                                 GHC.Types.Eq# @ * @ Bool @ b @~ (Sym cobox)
                                 }
                            of _ { GHC.Types.Eq# cobox ->
                            GHC.Types.Eq# @ * @ (T Int) @ b @~ (cobox ; cobox)
                            }
                            }
                       of _ { GHC.Types.Eq# cobox ->
                       GHC.Types.Eq# @ * @ b @ (T Int) @~ (Sym cobox)
                       }
                  of _ { GHC.Types.Eq# cobox ->
                  GHC.Types.Eq# @ * @ b @ (T Int) @~ cobox
                  })

I know this bug is only about the error message, but it seems like that last example might be an actual regression. Should I open a new ticket for it, or is it that "thou shalt not use RULES with type families and expect it to work"?

comment:3 Changed 6 years ago by illissius

Just to amuse matters further, these both work, with both 7.0 and 7.4:

foo :: (Num a, b ~ T a) => a -> b
{-# SPECIALISE foo :: b ~ Bool => Int -> b #-}
foo :: (Num a, b ~ T a) => a -> b
{-# SPECIALISE foo :: Int -> Bool #-}

that is, completely the opposite of the original example, now it works if and only if I *do* expand the type family, and it doesn't matter what I do with the equality constraint.

(FTR I'm testing with 7.0 and 7.4 because I don't have a 7.2 on hand.)

comment:4 Changed 6 years ago by igloo

Milestone: 7.6.17.6.2

comment:5 Changed 5 years ago by mikhail.vorozhtsov

Cc: mikhail.vorozhtsov@… added

comment:6 Changed 4 years ago by thoughtpolice

Milestone: 7.6.27.10.1

Moving to 7.10.1.

comment:7 Changed 4 years ago by thomie

In HEAD, the error message for the program from the description has changed to:

$ ghc-7.9.20141125 T5821.hs 
[1 of 1] Compiling T5821            ( T5821.hs, T5821.o )

T5821.hs:10:1: Warning:
    RULE left-hand side too complicated to desugar
      Optimised lhs: case cobox_ang
                     of _ [Occ=Dead] { GHC.Types.Eq# cobox ->
                     (foo @ Int $dNum_anf)
                     `cast` (<Int>_R -> Sub cobox :: (Int -> T Int) ~R# (Int -> Bool))
                     }
      Orig lhs: case cobox_ang of cobox_ang { GHC.Types.Eq# cobox ->
                (foo @ Int $dNum_anf)
                `cast` (<Int>_R -> Sub cobox :: (Int -> T Int) ~R# (Int -> Bool))
                }

Due to commit b34068144ec3d7bfe4279b16ad16d54dd46f1c5a:

Author: Simon Peyton Jones <>
Date:   Thu Mar 13 08:36:28 2014 +0000

    A bit more tracing to do with SPECIALISE pragmas

comment:8 Changed 4 years ago by thoughtpolice

Milestone: 7.10.17.12.1

Moving to 7.12.1 milestone; if you feel this is an error and should be addressed sooner, please move it back to the 7.10.1 milestone.

comment:9 Changed 4 years ago by ezyang

Milestone: 7.12.17.10.1
Owner: set to ezyang

I think we can nail this for 7.10. I'll attempt a patch.

comment:10 Changed 4 years ago by ezyang

Description: modified (diff)

comment:11 Changed 4 years ago by ezyang

Differential Rev(s): Phab:D610

The ideal resolution is to teach the RULE engine how to deal with type families, but until then I've just augmented the error message with a little note.

It might even be possible to look at type and realize that type families are involved (and maybe even suggest a better type) but that seems way more involved than just fixing it.

comment:12 Changed 4 years ago by ezyang

Status: newpatch

comment:13 Changed 4 years ago by Simon Peyton Jones <simonpj@…>

In 788413297eaddfa259d2ab76459a916a62d2604c/ghc:

Refactor handling of SPECIALISE pragmas (Trac #5821)

The provoking cause was Trac #5821, which concerned
type families, but in fixing it I did the usual round
of tidying up and docmenting.

The main comment is now
    Note [Handling SPECIALISE pragmas]
in TcBinds.

It is "wrinkle 2" that fixes #5821.

comment:14 Changed 4 years ago by Simon Peyton Jones <simonpj@…>

In c823b73cb2ca8e2392e2a4c48286879cc7baa51c/ghc:

Test Trac #5821

And rename the wrongly named rebindable/T5821 to T5908 (Trac #5908)

comment:15 Changed 4 years ago by simonpj

Resolution: fixed
Status: patchclosed
Test Case: simplCore/should_compile/T5821

Right, I've fixed this properly now.

Simon

Note: See TracTickets for help on using tickets.