logo       

succ optimization bug with derived Eq and Enum: msg#00058

lang.haskell.glasgow.bugs

Subject: succ optimization bug with derived Eq and Enum

GHC 6.2.2 (and a few older 6.2.x versions I tried) seems to improperly
optimize the expression "succ x == y" when using the derived Eq and Enum
instances. Using the data declaration below "isFive Five" will be False.

data Digit = Zero | One | Two | Three | Four | Five
| Six | Seven | Eight deriving (Eq,Enum)
isFive x = succ x == Six

This only happens when using the derived Eq and Enum. If either of
them are replaced with a hand written instance everything works fine. It
also has something to do with the number constructors the datatype has. If
there are less than 9 constructors everything works fine. Finally, the bug
only shows up when the -O flag is used.

Plenty more details (including a self contained test case) are below.

-Brian

transam:~/tmp$ cat GHCBug.lhs
\begin{code}
import System (getArgs)

-- NOTE: When if you remove Eight (or any other constructor) everything works
-- Having at least 9 constructors has something to do with the bug
data Digit = Zero | One | Two | Three | Four | Five | Six | Seven | Eight
deriving (Eq,Enum)

instance Show Digit where
show Five = "Five"
show Six = "Six"
show _ = undefined

-- Use either of these instances (instead of derived) and everything works
{-instance Enum Digit where
fromEnum Five = 5
fromEnum _ = undefined
toEnum 6 = Six
toEnum _ = undefined-}

{-instance Eq Digit where
Five == Five = True
Six == Six = True
_ == _ = undefined-}

isFive :: Digit -> Bool
isFive a = succ a == Six

main :: IO()
main = do
putStrLn ("======")
-- These next two lines are just here to keep ghc from optimizing away stuff
args <- getArgs
let x = if length args == -1 then undefined else Five
putStrLn ("x: " ++ show x)
let y = succ x
putStrLn ("let y = succ x")
putStrLn ("y: " ++ show y)
putStrLn ("y == Six: " ++ show (y == Six))
putStrLn ("succ x == Six: " ++ show (succ x == Six))
putStrLn ("isFive x: " ++ show (isFive x))
\end{code}
transam:~/tmp$ ghc -no-recomp -o GHCBug GHCBug.lhs && ./GHCBug
======
x: Five
let y = succ x
y: Six
y == Six: True
succ x == Six: True
isFive x: True
transam:~/tmp$ ghc -O -no-recomp -o GHCBug GHCBug.lhs && ./GHCBug
======
x: Five
let y = succ x
y: Six
y == Six: True
succ x == Six: False
isFive x: False
transam:~/tmp$ ghci GHCBug.lhs
___ ___ _
/ _ \ /\ /\/ __(_)
/ /_\// /_/ / / | | GHC Interactive, version 6.2.2, for Haskell 98.
/ /_\\/ __ / /___| | http://www.haskell.org/ghc/
\____/\/ /_/\____/|_| Type :? for help.

Loading package base ... linking ... done.
Skipping Main ( GHCBug.lhs, GHCBug.o )
Ok, modules loaded: Main.
Prelude Main> isFive Five
Loading package haskell98 ... linking ... done.
False
Prelude Main> :q
Leaving GHCi.


<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise