Skip to content

Literal Pattern match loses order

I found this long-standing bug while investigating #10245 (closed):

Consider this code:

f1 :: Int -> String
f1 n = case n of
  0 -> "bar"
  0x10000000000000000 -> "foo"
  _ -> "c"
{-# NOINLINE f1 #-}

g1 :: Int -> String
g1 n = if n == 0 then "bar" else
       if n == 0x10000000000000000 then  "foo" else
       "c"
{-# NOINLINE g1 #-}

f2 :: Int -> String
f2 n = case n of
  0x10000000000000000 -> "foo"
  0 -> "bar"
  _ -> "c"
{-# NOINLINE f2 #-}

g2 :: Int -> String
g2 n = if n == 0x10000000000000000 then  "foo" else
       if n == 0 then "bar" else
       "c"
{-# NOINLINE g2 #-}

main = do
    let i = read "0" :: Int
    print (f1 i)
    print (g1 i)
    print (f2 i)
    print (g2 i)

According to the report, f1 should behave like g1 and f2 should behave like g2. But that is not the case: I get

"foo"
"bar"
"foo"
"foo"

The reason is that the branches are sorted, to create fancy code for it, but this does not take into account that 0x10000000000000000 = 0, at least for Int.

This bug is present also in 7.8.4, and not (directly) related to my CmmSwitch code: It can also be observed with interpreted code, so the fix must happen earlier.

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