id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc	os	architecture	failure	difficulty	testcase	blockedby	blocking	related
7360	Case-of-identical-alts optimisation fails abjectly	simonpj		"Herbert Valerio Riedel writes: I've been trying to improve/fix a minor optimization sub-optimality w.r.t to the following code (code like that results from the generics-based NFData deriver[1]):
{{{
    data Foo = Foo1 | Foo2 | Foo3 !Int
    
    rnf1 :: Foo -> ()
    rnf1 x = case x of
               Foo1 -> ()
               Foo2 -> ()
               Foo3 {} -> ()
}}}
which the current GHC 7.6.1 translates to the following core
expression:
{{{
    NFDataTest2.rnf1 =
      \ x_aeG ->
        case x_aeG of _ {
          __DEFAULT -> GHC.Tuple.();
          NFDataTest2.Foo3 ds_deT -> GHC.Tuple.()
        }
}}}
...whereas I'd have expected it to to compile it to a collapsed `__DEFAULT`-only case, i.e.
{{{
    NFDataTest2.rnf1 =
      \ x_aeG -> case x_aeG of _ { __DEFAULT -> GHC.Tuple.() }
}}}
Now I've been hunting it down to the function `SimplUtils.mkCase1` [2], which according to the source-code comments, is supposed to merge identical alternatives, i.e.:
{{{
| 3.  Merge identical alternatives.
|     If several alternatives are identical, merge them into
|     a single DEFAULT alternative.  I've occasionally seen this
|     making a big difference:
| 
|         case e of               =====>     case e of
|           C _ -> f x                         D v -> ....v....
|           D v -> ....v....                   DEFAULT -> f x
|           DEFAULT -> f x
}}}
...and the `mkCase1` function itself reads as follows:
{{{
    mkCase1 dflags scrut case_bndr alts_ty ((_con1,bndrs1,rhs1) : con_alts)
      | all isDeadBinder bndrs1                     -- Remember the default
      , length filtered_alts < length con_alts      -- alternative comes first
            -- Also Note [Dead binders]
      = do  { tick (AltMerge case_bndr)
            ; mkCase2 dflags scrut case_bndr alts_ty alts' }
      where
        alts' = (DEFAULT, [], rhs1) : filtered_alts
        filtered_alts         = filter keep con_alts
        keep (_con,bndrs,rhs) = not (all isDeadBinder bndrs && rhs `cheapEqExpr` rhs1)
}}}
Now the problem seems to be, that `isDeadBinder` returns `False`; so I hacked up `mkCase1` and inserted a `occurAnalyseExpr` on artificially constructed single-alternative 'Case' values before applying `isDeadBinder`, and then it would return `True` and simplify the case expression as expected.

So now my question is, why isn't the occurrence information available for the case-alternative's binders (the occInfo is set to `NoOccInfo`) at `mkCase1`-time?  When is occurence analysis performed relative to the simplifier?


 * [1]: [http://hackage.haskell.org/package/deepseq-generics]
 * [2]: [http://www.haskell.org/ghc/docs/7.6.1/html/libraries/ghc-7.6.1/src/SimplUtils.html#mkCase1]
"	bug	closed	normal		Compiler	7.6.1	fixed		hvr@…	Unknown/Multiple	Unknown/Multiple	None/Unknown	Unknown	simplCore/should_compile/T7360			
