Pattern synonym matcher is unnecessarily strict on unboxed continuations
As discovered while investigating #9732 (closed), if you have something like
{-# LANGUAGE PatternSynonyms, MagicHash #-}
import GHC.Base
pattern P = True
f :: Bool -> Int#
f P = 42#
f is compiled into
Main.f :: GHC.Types.Bool -> GHC.Prim.Int#
[LclIdX, Str=DmdType]
Main.f =
letrec {
f_apU :: GHC.Types.Bool -> GHC.Prim.Int#
[LclId, Str=DmdType]
f_apU =
\ (ds_dq1 :: GHC.Types.Bool) ->
break<2>()
let {
fail_dq2 :: GHC.Prim.Void# -> GHC.Prim.Int#
[LclId, Str=DmdType]
fail_dq2 =
\ (ds_dq3 [OS=OneShot] :: GHC.Prim.Void#) ->
Control.Exception.Base.patError
@ GHC.Prim.Int# "unboxed.hs:7:1-9|function f"# } in
case fail_dq2 GHC.Prim.void# of wild_00 { __DEFAULT ->
(case break<1>() 42 of wild_00 { __DEFAULT ->
Main.$mP @ GHC.Prim.Int# ds_dq1 wild_00
})
wild_00
}; } in
f_apU
Note how fail_dq2 is applied on void# before the pattern match, meaning the following expression:
I# (f True)
will fail with
*** Exception: unboxed.hs:7:1-9: Non-exhaustive patterns in function f
This is because the the type of P's matcher, instantiated for its use in f, is
$mP :: Bool -> Int# -> Int# -> Int#
so of course it is strict both on the success and the failure continuation.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture |