GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2021-02-16T21:31:07Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/18435full-laziness optimization makes program run out of memory2021-02-16T21:31:07Zplsnpfull-laziness optimization makes program run out of memoryThe full laziness optimization pass seems to produce an executable that runs Out Of Memory. Without this optimization the executable runs without the OOM problem.
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html#ghc-flag--ffull-laziness
Please see the attachment for a full test case [tc1.zip](/uploads/124c4d599050eb458090400a176d14f9/tc1.zip). Go into package.yaml and comment / uncomment the -fno-full-laziness flag.
Command used to build and run the program: `reset && stack clean && stack build && rm -rf data_bench && echo "Running .." && /usr/bin/time stack exec -- tc1`
Setting -O0 and -ffull-laziness does NOT trigger the problem. -O1 must be set for the problem to become visible. As much as possible other optimization flags have been disabled to minimize the code transformation in the core-to-core pipeline (handy for when comparing with VS without full laziness).
Changing `GenerateCommand 2 1 11046 1 187960` to `GenerateCommand 1 1 11046 1 187960` in the source code also gets rid of the problem. This information might help to pinpoint the problem.
LTS 16.4 for ghc-8.8.3 was used as package set and compiler. 64 bits ubuntu 20.04
One of the following conclusions may be derived:
* My code was poorly written thus triggering the problem with full laziness optimization.
* This is normal that it happens sometimes, as stated in the documentation `Full laziness increases sharing, which can lead to increased memory residency.`
* Even if the code is poor and the optimization doesn't always work that well ("increased memory residency"), the OOM problem is still severe and normally should not happen, thus might be an indication of a bug in the full laziness optimization pass.The full laziness optimization pass seems to produce an executable that runs Out Of Memory. Without this optimization the executable runs without the OOM problem.
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-optimisation.html#ghc-flag--ffull-laziness
Please see the attachment for a full test case [tc1.zip](/uploads/124c4d599050eb458090400a176d14f9/tc1.zip). Go into package.yaml and comment / uncomment the -fno-full-laziness flag.
Command used to build and run the program: `reset && stack clean && stack build && rm -rf data_bench && echo "Running .." && /usr/bin/time stack exec -- tc1`
Setting -O0 and -ffull-laziness does NOT trigger the problem. -O1 must be set for the problem to become visible. As much as possible other optimization flags have been disabled to minimize the code transformation in the core-to-core pipeline (handy for when comparing with VS without full laziness).
Changing `GenerateCommand 2 1 11046 1 187960` to `GenerateCommand 1 1 11046 1 187960` in the source code also gets rid of the problem. This information might help to pinpoint the problem.
LTS 16.4 for ghc-8.8.3 was used as package set and compiler. 64 bits ubuntu 20.04
One of the following conclusions may be derived:
* My code was poorly written thus triggering the problem with full laziness optimization.
* This is normal that it happens sometimes, as stated in the documentation `Full laziness increases sharing, which can lead to increased memory residency.`
* Even if the code is poor and the optimization doesn't always work that well ("increased memory residency"), the OOM problem is still severe and normally should not happen, thus might be an indication of a bug in the full laziness optimization pass.https://gitlab.haskell.org/ghc/ghc/-/issues/18238Explore alternatives to the state hack2021-02-16T21:31:07ZSebastian GrafExplore alternatives to the state hackThe state hack (`-fstate-hack`, on by default, see `Note [The state-transformer hack]` in G.C.O.Arity) is a smart hack without which efficient compilation of `IO` wouldn't be possible. But fixes such as https://gitlab.haskell.org/ghc/ghc/-/commit/69c0e16e9ce9fe045851c09425956fa3407824ae?merge_request_iid=3318 made me thinking: Now that we have `GHC.Magic.oneShot`, can we get by without?
Suppose we define (in `ghc-prim:GHC.Types`):
```hs
newtype IO a = IONoEta (State# RealWorld -> (# State# RealWorld, a #))
pattern IO m <- IONoEta m
where
IO m = IONoEta (oneShot m)
```
Similarly for `ST`. I hope that we can get rid of the state hack this way. That would also fix #14596.
Another advantage to this is that we can use `IONoEta` on a use by use basis, rather than having the rather unobtrusive `{-# OPTIONS_GHC -fno-state-hack #-}` at the top of the module, disconnected from its usage.The state hack (`-fstate-hack`, on by default, see `Note [The state-transformer hack]` in G.C.O.Arity) is a smart hack without which efficient compilation of `IO` wouldn't be possible. But fixes such as https://gitlab.haskell.org/ghc/ghc/-/commit/69c0e16e9ce9fe045851c09425956fa3407824ae?merge_request_iid=3318 made me thinking: Now that we have `GHC.Magic.oneShot`, can we get by without?
Suppose we define (in `ghc-prim:GHC.Types`):
```hs
newtype IO a = IONoEta (State# RealWorld -> (# State# RealWorld, a #))
pattern IO m <- IONoEta m
where
IO m = IONoEta (oneShot m)
```
Similarly for `ST`. I hope that we can get rid of the state hack this way. That would also fix #14596.
Another advantage to this is that we can use `IONoEta` on a use by use basis, rather than having the rather unobtrusive `{-# OPTIONS_GHC -fno-state-hack #-}` at the top of the module, disconnected from its usage.https://gitlab.haskell.org/ghc/ghc/-/issues/18202Check eta-expansion in the compiler2021-02-27T15:05:12ZSylvain HenryCheck eta-expansion in the compiler@nomeata reported on his blog [1] that the ReaderT pattern (i.e. a newtype containing a function) can lead to missed eta-expansions. In his case he reports "Improvement: Allocations: -23.20% Time: -23.00%"
We use this pattern in GHC too so we should check if we could gain anything by forcing eta-expansions in a few places.
MR !3309
Things done:
* !3503: make the unifier use a one-shot monad.
* !3751: make the Simplifier use a one-shot monad
[1] https://www.joachim-breitner.de/blog/763-Faster_Winter_5__Eta-Expanding_ReaderT
---------
Edit by me (@AndreasK): We should just check all Monads. So far it seems this was beneficial to any monad it was applied to.
Based on grep here is a list of Monads in GHC:
Monads and checked:
- [ ] compiler/GHC/ByteCode/Asm.hs:instance Monad Assembler where
- [ ] compiler/GHC/Cmm/Lint.hs:instance Monad CmmLint where
- [ ] compiler/GHC/Cmm/Parser/Monad.hs:instance Monad PD where
- [ ] compiler/GHC/CmmToAsm/CFG/Dominators.hs:instance Monad (S z s) where
- [ ] compiler/GHC/CmmToAsm/Monad.hs:instance Monad NatM where
- [x] compiler/GHC/CmmToAsm/Reg/Linear/State.hs:instance Monad (RegM freeRegs) where
!4759
- [ ] compiler/GHC/CmmToAsm.hs:instance Monad CmmOptM where
- [ ] compiler/GHC/CmmToC.hs:instance Monad TE where
- [ ] compiler/GHC/CmmToLlvm/Base.hs:instance Monad LlvmM where
- [ ] compiler/GHC/Core/FamInstEnv.hs:instance Monad NormM where
- [ ] compiler/GHC/Core/Lint.hs:instance Monad LintM where
- [ ] compiler/GHC/Core/Opt/ConstantFold.hs:instance Monad RuleM where
- [ ] compiler/GHC/Core/Opt/Monad.hs:instance Monad CoreM where
- [ ] compiler/GHC/Core/Opt/Monad.hs-boot:instance Monad CoreM
- [x] compiler/GHC/Core/Opt/Simplify/Monad.hs:instance Monad SimplM where
- [ ] compiler/GHC/Core/Unify.hs:instance Monad UnifyResultM where
- [ ] compiler/GHC/Core/Unify.hs:instance Monad UM where
- [ ] compiler/GHC/CoreToByteCode.hs:instance Monad BcM where
- [ ] compiler/GHC/CoreToStg.hs:instance Monad CtsM where
- [x] compiler/GHC/Data/IOEnv.hs:instance Monad (IOEnv m) where
- [ ] compiler/GHC/Data/Maybe.hs:instance Monad (MaybeErr err) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad f => Functor (Stream f a) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad m => Applicative (Stream m a) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad m => Monad (Stream m a) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Functor (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Applicative (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Monad (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad (CmdLineP s) where
- [ ] compiler/GHC/Driver/Env/Types.hs:instance Monad Hsc where
- [ ] compiler/GHC/Driver/Monad.hs:instance Monad Ghc where
- [ ] compiler/GHC/Driver/Monad.hs:instance Monad m => Monad (GhcT m) where
- [ ] compiler/GHC/Driver/Pipeline/Monad.hs:instance Monad CompPipeline where
- [ ] compiler/GHC/HsToCore/Coverage.hs:instance Monad TM where
- [ ] compiler/GHC/Iface/Tidy.hs:instance Monad DFFV where
- [ ] compiler/GHC/Parser/Lexer.x:instance Monad P where
- [ ] compiler/GHC/Parser/PostProcess.hs:instance Monad PV where
- [ ] compiler/GHC/Rename/Pat.hs:instance Monad CpsRn where
- [ ] compiler/GHC/Stg/Lint.hs:instance Monad LintM where
- [ ] compiler/GHC/StgToCmm/ExtCode.hs:instance Monad CmmParse where
- [ ] compiler/GHC/StgToCmm/Monad.hs:instance Monad FCode where
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad S -- by coercion sym (Monad :CoS) : Monad [] ~ Monad S
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad (T Int) -- only if we can eta reduce???
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad (T Int) -- only if we can eta reduce???
- [ ] compiler/GHC/Tc/Deriv.hs: -- instance Monad (ST s) => Monad (T s) where
- [x] compiler/GHC/Tc/Solver/Monad.hs:instance Monad TcS where
- [x] compiler/GHC/Tc/Solver/Rewrite.hs:instance Monad RewriteM where
- [ ] compiler/GHC/Tc/TyCl/Utils.hs:instance Monad SynCycleM where
- [ ] compiler/GHC/Tc/TyCl/Utils.hs:instance Monad RoleM where
- [ ] compiler/GHC/Tc/Types.hs:instance Monad TcPluginM where
- [ ] compiler/GHC/ThToHs.hs:instance Monad CvtM where
- [ ] compiler/GHC/Types/Unique/Supply.hs:instance Monad UniqSM where
- [ ] compiler/GHC/Utils/Monad/State.hs:instance Monad (State s) where
- [ ] compiler/GHC/Utils/Monad.hs: instance Monad M where@nomeata reported on his blog [1] that the ReaderT pattern (i.e. a newtype containing a function) can lead to missed eta-expansions. In his case he reports "Improvement: Allocations: -23.20% Time: -23.00%"
We use this pattern in GHC too so we should check if we could gain anything by forcing eta-expansions in a few places.
MR !3309
Things done:
* !3503: make the unifier use a one-shot monad.
* !3751: make the Simplifier use a one-shot monad
[1] https://www.joachim-breitner.de/blog/763-Faster_Winter_5__Eta-Expanding_ReaderT
---------
Edit by me (@AndreasK): We should just check all Monads. So far it seems this was beneficial to any monad it was applied to.
Based on grep here is a list of Monads in GHC:
Monads and checked:
- [ ] compiler/GHC/ByteCode/Asm.hs:instance Monad Assembler where
- [ ] compiler/GHC/Cmm/Lint.hs:instance Monad CmmLint where
- [ ] compiler/GHC/Cmm/Parser/Monad.hs:instance Monad PD where
- [ ] compiler/GHC/CmmToAsm/CFG/Dominators.hs:instance Monad (S z s) where
- [ ] compiler/GHC/CmmToAsm/Monad.hs:instance Monad NatM where
- [x] compiler/GHC/CmmToAsm/Reg/Linear/State.hs:instance Monad (RegM freeRegs) where
!4759
- [ ] compiler/GHC/CmmToAsm.hs:instance Monad CmmOptM where
- [ ] compiler/GHC/CmmToC.hs:instance Monad TE where
- [ ] compiler/GHC/CmmToLlvm/Base.hs:instance Monad LlvmM where
- [ ] compiler/GHC/Core/FamInstEnv.hs:instance Monad NormM where
- [ ] compiler/GHC/Core/Lint.hs:instance Monad LintM where
- [ ] compiler/GHC/Core/Opt/ConstantFold.hs:instance Monad RuleM where
- [ ] compiler/GHC/Core/Opt/Monad.hs:instance Monad CoreM where
- [ ] compiler/GHC/Core/Opt/Monad.hs-boot:instance Monad CoreM
- [x] compiler/GHC/Core/Opt/Simplify/Monad.hs:instance Monad SimplM where
- [ ] compiler/GHC/Core/Unify.hs:instance Monad UnifyResultM where
- [ ] compiler/GHC/Core/Unify.hs:instance Monad UM where
- [ ] compiler/GHC/CoreToByteCode.hs:instance Monad BcM where
- [ ] compiler/GHC/CoreToStg.hs:instance Monad CtsM where
- [x] compiler/GHC/Data/IOEnv.hs:instance Monad (IOEnv m) where
- [ ] compiler/GHC/Data/Maybe.hs:instance Monad (MaybeErr err) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad f => Functor (Stream f a) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad m => Applicative (Stream m a) where
- [ ] compiler/GHC/Data/Stream.hs:instance Monad m => Monad (Stream m a) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Functor (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Applicative (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad m => Monad (EwM m) where
- [ ] compiler/GHC/Driver/CmdLine.hs:instance Monad (CmdLineP s) where
- [ ] compiler/GHC/Driver/Env/Types.hs:instance Monad Hsc where
- [ ] compiler/GHC/Driver/Monad.hs:instance Monad Ghc where
- [ ] compiler/GHC/Driver/Monad.hs:instance Monad m => Monad (GhcT m) where
- [ ] compiler/GHC/Driver/Pipeline/Monad.hs:instance Monad CompPipeline where
- [ ] compiler/GHC/HsToCore/Coverage.hs:instance Monad TM where
- [ ] compiler/GHC/Iface/Tidy.hs:instance Monad DFFV where
- [ ] compiler/GHC/Parser/Lexer.x:instance Monad P where
- [ ] compiler/GHC/Parser/PostProcess.hs:instance Monad PV where
- [ ] compiler/GHC/Rename/Pat.hs:instance Monad CpsRn where
- [ ] compiler/GHC/Stg/Lint.hs:instance Monad LintM where
- [ ] compiler/GHC/StgToCmm/ExtCode.hs:instance Monad CmmParse where
- [ ] compiler/GHC/StgToCmm/Monad.hs:instance Monad FCode where
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad S -- by coercion sym (Monad :CoS) : Monad [] ~ Monad S
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad (T Int) -- only if we can eta reduce???
- [ ] compiler/GHC/Tc/Deriv.hs: instance Monad [] => Monad (T Int) -- only if we can eta reduce???
- [ ] compiler/GHC/Tc/Deriv.hs: -- instance Monad (ST s) => Monad (T s) where
- [x] compiler/GHC/Tc/Solver/Monad.hs:instance Monad TcS where
- [x] compiler/GHC/Tc/Solver/Rewrite.hs:instance Monad RewriteM where
- [ ] compiler/GHC/Tc/TyCl/Utils.hs:instance Monad SynCycleM where
- [ ] compiler/GHC/Tc/TyCl/Utils.hs:instance Monad RoleM where
- [ ] compiler/GHC/Tc/Types.hs:instance Monad TcPluginM where
- [ ] compiler/GHC/ThToHs.hs:instance Monad CvtM where
- [ ] compiler/GHC/Types/Unique/Supply.hs:instance Monad UniqSM where
- [ ] compiler/GHC/Utils/Monad/State.hs:instance Monad (State s) where
- [ ] compiler/GHC/Utils/Monad.hs: instance Monad M wherehttps://gitlab.haskell.org/ghc/ghc/-/issues/14596Remove uses of unsafeGlobalDynFlags for state hack2020-06-02T19:51:39ZBen GamariRemove uses of unsafeGlobalDynFlags for state hackCurrently there are a variety of uses of the terrible `unsafeGlobalDynFlags` scattered about the compiler to implement `-fno-state-hack`. This global state makes parallel compilation unreliable and complicates API usage. Remove these uses.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.2.1 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Remove uses of unsafeGlobalDynFlags for state hack","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"Currently there are a variety of uses of the terrible `unsafeGlobalDynFlags` scattered about the compiler to implement `-fno-state-hack`. This global state makes parallel compilation unreliable and complicates API usage. Remove these uses.","type_of_failure":"OtherFailure","blocking":[]} -->Currently there are a variety of uses of the terrible `unsafeGlobalDynFlags` scattered about the compiler to implement `-fno-state-hack`. This global state makes parallel compilation unreliable and complicates API usage. Remove these uses.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.2.1 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Remove uses of unsafeGlobalDynFlags for state hack","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"Currently there are a variety of uses of the terrible `unsafeGlobalDynFlags` scattered about the compiler to implement `-fno-state-hack`. This global state makes parallel compilation unreliable and complicates API usage. Remove these uses.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/9349excessive inlining due to state hack2020-06-02T23:44:20Zrwbartonexcessive inlining due to state hackThe program at https://gist.github.com/jorendorff/a3005968adc8f054baf7 runs very slowly when compiled with `-O` or higher. It seems that `arr` and/or `rangeMap` is being inlined into the do block on lines 89-91 and recomputed for each iteration of the loop. The program runs nearly instantly when compiled with `-O0` or with `-O -fno-pre-inlining`. (Of course, this does not mean `-fpre-inlining` is necessary the culprit; it could be enabling some subsequent misoptimization.)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.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":"excessive inlining with -fpre-inlining","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The program at https://gist.github.com/jorendorff/a3005968adc8f054baf7 runs very slowly when compiled with `-O` or higher. It seems that `arr` and/or `rangeMap` is being inlined into the do block on lines 89-91 and recomputed for each iteration of the loop. The program runs nearly instantly when compiled with `-O0` or with `-O -fno-pre-inlining`. (Of course, this does not mean `-fpre-inlining` is necessary the culprit; it could be enabling some subsequent misoptimization.)","type_of_failure":"OtherFailure","blocking":[]} -->The program at https://gist.github.com/jorendorff/a3005968adc8f054baf7 runs very slowly when compiled with `-O` or higher. It seems that `arr` and/or `rangeMap` is being inlined into the do block on lines 89-91 and recomputed for each iteration of the loop. The program runs nearly instantly when compiled with `-O0` or with `-O -fno-pre-inlining`. (Of course, this does not mean `-fpre-inlining` is necessary the culprit; it could be enabling some subsequent misoptimization.)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.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":"excessive inlining with -fpre-inlining","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The program at https://gist.github.com/jorendorff/a3005968adc8f054baf7 runs very slowly when compiled with `-O` or higher. It seems that `arr` and/or `rangeMap` is being inlined into the do block on lines 89-91 and recomputed for each iteration of the loop. The program runs nearly instantly when compiled with `-O0` or with `-O -fno-pre-inlining`. (Of course, this does not mean `-fpre-inlining` is necessary the culprit; it could be enabling some subsequent misoptimization.)","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7411Exceptions are optimized away in certain situations2020-05-27T16:04:30ZSimon Hengelsol@typeful.netExceptions are optimized away in certain situationsThe issue came up in [this thread on glasgow-haskell-users](http://www.haskell.org/pipermail/glasgow-haskell-users/2012-November/023027.html).
## Steps to reproduce:
```hs
-- file Foo.hs
import Control.Exception
import Control.DeepSeq
main = evaluate (('a' : undefined) `deepseq` return () :: IO ())
```
```
$ ghc -fforce-recomp -fpedantic-bottoms -O Foo.hs
```
### Expected result:
The program should fail with:
```
Foo: Prelude.undefined
```
### Actual result:
The program succeeds.
Compiling the program with `-fno-state-hack` helps.The issue came up in [this thread on glasgow-haskell-users](http://www.haskell.org/pipermail/glasgow-haskell-users/2012-November/023027.html).
## Steps to reproduce:
```hs
-- file Foo.hs
import Control.Exception
import Control.DeepSeq
main = evaluate (('a' : undefined) `deepseq` return () :: IO ())
```
```
$ ghc -fforce-recomp -fpedantic-bottoms -O Foo.hs
```
### Expected result:
The program should fail with:
```
Foo: Prelude.undefined
```
### Actual result:
The program succeeds.
Compiling the program with `-fno-state-hack` helps.8.10.2Tobias Dammerstdammers@gmail.comTobias Dammerstdammers@gmail.com