"evaluate" optimized away
Reported on Stackoverflow: http://stackoverflow.com/questions/5697159/testing-for-error-calls-in-hunit
With optimizations on, the following program, which normally succeeds (correctly generating an exception), instead fails, and the exception is optimized away.
```
import Control.Exception
import Test.HUnit
throwIfNegative :: Int -> String
throwIfNegative n | n < 0 = error "negative"
| otherwise = "no worries"
{-# NOINLINE throwIfNegative #-}
case_negative =
handleJust errorCalls (const $ return ()) $ do
evaluate $ throwIfNegative (-1)
assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
main = runTestTT $ TestCase case_negative
```
Looking at the core, after a few iterations, the call to `throwIfNegative` is dropped as dead code.
Using seq instead of evaluate is happy enough:
```
case_negative =
handleJust errorCalls (const $ return ()) $ do
throwIfNegative (-1) `seq` assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
```
or a bang pattern:
```
case_negative =
handleJust errorCalls (const $ return ()) $ do
let !x = throwIfNegative (-1)
assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
```
Possibly related to #2273
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.0.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"\"evaluate\" optimized away","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.0.3","keywords":["evaluate","seq,"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Reported on Stackoverflow: http://stackoverflow.com/questions/5697159/testing-for-error-calls-in-hunit\r\n\r\nWith optimizations on, the following program, which normally succeeds (correctly generating an exception), instead fails, and the exception is optimized away.\r\n\r\n{{{\r\nimport Control.Exception\r\nimport Test.HUnit\r\n\r\nthrowIfNegative :: Int -> String\r\nthrowIfNegative n | n < 0 = error \"negative\"\r\n | otherwise = \"no worries\"\r\n{-# NOINLINE throwIfNegative #-}\r\n\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n evaluate $ throwIfNegative (-1)\r\n assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n\r\nmain = runTestTT $ TestCase case_negative\r\n}}}\r\n\r\nLooking at the core, after a few iterations, the call to `throwIfNegative` is dropped as dead code.\r\n\r\nUsing seq instead of evaluate is happy enough:\r\n\r\n{{{\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n throwIfNegative (-1) `seq` assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n}}}\r\n\r\nor a bang pattern:\r\n\r\n{{{\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n let !x = throwIfNegative (-1)\r\n assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n}}}\r\n\r\nPossibly related to #2273","type_of_failure":"OtherFailure","blocking":[]} -->
issue