Note [Refine DEFAULT case alternatives]
refineDefaultAlt replaces the DEFAULT alt with a constructor if there
is one possible value it could be.
The simplest example being
foo :: () -> ()
foo x = case x of !_ -> ()
which rewrites to
foo :: () -> ()
foo x = case x of () -> ()
There are two reasons in general why replacing a DEFAULT alternative
with a specific constructor is desirable.
1. We can simplify inner expressions. For example
data Foo = Foo1 ()
test :: Foo -> ()
test x = case x of
DEFAULT -> mid (case x of
Foo1 x1 -> x1)
refineDefaultAlt fills in the DEFAULT here with `Foo ip1` and then
x becomes bound to `Foo ip1` so is inlined into the other case
which causes the KnownBranch optimisation to kick in. If we don't
refine DEFAULT to `Foo ip1`, we are left with both case expressions.
2. combineIdenticalAlts does a better job. For example (Simon Jacobi)
data D = C0 | C1 | C2
case e of
DEFAULT -> e0
C0 -> e1
C1 -> e1
When we apply combineIdenticalAlts to this expression, it can't
combine the alts for C0 and C1, as we already have a default case.
But if we apply refineDefaultAlt first, we get
case e of
C0 -> e1
C1 -> e1
C2 -> e0
and combineIdenticalAlts can turn that into
case e of
DEFAULT -> e1
C2 -> e0
It isn't obvious that refineDefaultAlt does this but if you look
at its one call site in GHC.Core.Opt.Simplify.Utils then the
`imposs_deflt_cons` argument is populated with constructors which
are matched elsewhere.
There are two exceptions where we avoid refining a DEFAULT case:
* Exception 1: Newtypes
We can have a newtype, if we are just doing an eval:
case x of { DEFAULT -> e }
And we don't want to fill in a default for them!
* Exception 2: `type data` declarations
The data constructors for a `type data` declaration (see
Note [Type data declarations] in GHC.Rename.Module) do not exist at the
value level. Nevertheless, it is possible to strictly evaluate a value
whose type is a `type data` declaration. Test case
type-data/should_compile/T2294b.hs contains an example:
type data T a where
A :: T Int
f :: T a -> ()
f !x = ()
We want to generate the following Core for f:
f = \(@a) (x :: T a) ->
case x of
__DEFAULT -> ()
Namely, we do _not_ want to match on `A`, as it doesn't exist at the value
level! See wrinkle (W2b) in Note [Type data declarations] in GHC.Rename.Module References 1
- Type data declarations GHC.Rename.Module
Referenced by 5
- GHC.Core.Utils call site ×3
- Abstract over coercions GHC.Core.Opt.Simplify.Utils
- Type data declarations GHC.Rename.Module