exprIsBottom inconsistent with strictness analyser
Because of Note [IO hack in the demand analyser] (which I hate), an expression like
f :: Int -> State# RealWorld -> (# State# RealWorld, Int #)
f x s = case blah of (# s::State# RealWorld, r::() #) ->
error (show x)
is not reported as a bottoming function by the strictness analyser.
But exprBotStrictness_maybe will say that the RHS is bottoming. That ultimately comes from CoreArity.arityType which has no analogous hack to the demand analyser.
These can't both be right! We could
- Cripple
exprBotStrictness_maybea bit by adding the hack there too. - Weaken the hack so that it propagates divergence.
The demand-analyser hack note says
{- Note [IO hack in the demand analyser]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There's a hack here for I/O operations. Consider
case foo x s of { (# s, r #) -> y }
Is this strict in 'y'? Normally yes, but what if 'foo' is an I/O
operation that simply terminates the program (not in an erroneous way)?
In that case we should not evaluate 'y' before the call to 'foo'.
Hackish solution: spot the IO-like situation and add a virtual branch,
as if we had
case foo x s of
(# s, r #) -> y
other -> return ()
So the 'y' isn't necessarily going to be evaluated
A more complete example (Trac #148, #1592) where this shows up is:
do { let len = <expensive> ;
; when (...) (exitWith ExitSuccess)
; print len }
I wonder if we could weaken the hack so that it propagated divergence/exception-thowing, while still making mentioned variables lazy. The big reason I'd like to do this is if we have
case f x s of (# s',r #) -> BIG
then I really want to discard the alternative (since f x s is guaranteed to throw an exception) to give
case f x s of {}
This is absolutely kosher; no change in evaluation order or anything.
But weakening the IO hack in this way can change strictness. For example
g A x y z s = x `seq` y `seq` (# s, () #)
g B x y z s = x `seq` case blah2 of (# s', _ #) ->
y `seq` (# s', () #)
g C x y z s = case blah of (# s', _ #) ->
error (show z)
Currently we treat this as lazy in x,y and z. With the above change, it'd become strict in x but not y or z, which is a little weird.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 8.0.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture |