Skip to content

Rewrite rule can trigger Lint

Consider this program (produced by Michael Sperber)

{-# LANGUAGE MagicHash #-}
module ConCatRules where

import GHC.Prim
import GHC.Int

unboxI :: Int -> Int#
unboxI (I# i#) = i#

plus :: Int -> Int -> Int
plus x y = plus x y
{-# NOINLINE plus #-}

{-# RULES
"reboxa" forall u# v# . (+#) u# v# = unboxI (plus (I# u#) (I# v#))
#-}

foo = I# (10# +# 1#)

Compile with -O and you get

*** Core Lint errors : in result of Simplifier ***
Bar.hs:25:1: warning:
    This argument does not satisfy the let/app invariant:
      case plus (I# 10#) (I# 1#) of { I# i#_aBa -> i#_aBa }
    In the RHS of foo :: Int
    Substitution: [TCvSubst
                     In scope: InScope {}
                     Type env: []
                     Co env: []]

There is a good reason for this. The RULE rewrites

  • an expression that is okForSpeculation (namely 10# +# 1#)
  • into an expression that is not okForSpeculation (namely case plus (I# 10#) (I# 1#) of { I# i#_aBa -> i#_aBa })

The former is allowed as an argument of I# (as it appears in foo); but the latter is not, by the let/app invariant.

GHC never itself rewrites an expression that is okForSpeculation into one that isn't. But this RULE does. And that triggers Lint.

Is this a bug in GHC, or a bug in the RULE?

We could make the simplifier test for this situation, without much difficulty, but doing so would impose a small extra overhead on every compilation.

Edited by Simon Peyton Jones
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information