Skip to content

Unexpected strictness (records, exception handling, and -O)

The program below (which is a minimal reproducer, AFAICT), should be equivalent to main = forever $ putStrLn "done". Instead, if compiled with -O (on GHC 8.10.4 or 9.0.1, MacOS), it prints once then crashes with the unused field error. Without -O, the correct behaviour is seen.

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TypeApplications #-}

import Control.Exception

data R = R {field :: ()}

main :: IO a
main = f r0

f :: R -> IO a
f x = do
  (\R{} -> handle @E . const $ pure x) x $ do
    putStrLn "done"
    pure r0
  f r0

r0 :: R
r0 = R{field = error "unused field"}

-- it doesn't matter which exception we handle - this could be e.g. type E = IOException
data E = E
  deriving (Show, Exception)
Edited by George Thomas
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information