`[source] `_ compiler/simplStg/StgCse.hs =========================== Note [All alternatives are the binder] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ `[note link] `__ When all alternatives simply refer to the case binder, then we do not have to bother with the case expression at all (#13588). CoreSTG does this as well, but sometimes, types get into the way: :: newtype T = MkT Int f :: (Int, Int) -> (T, Int) f (x, y) = (MkT x, y) .. Core cannot just turn this into :: f p = p .. as this would not be well-typed. But to STG, where MkT is no longer in the way, we can. Note [Trivial case scrutinee] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ `[note link] `__ We want to be able to handle nested reconstruction of constructors as in :: nested :: Either Int (Either Int a) -> Either Bool (Either Bool a) nested (Right (Right v)) = Right (Right v) nested _ = Left True .. So if we come across case x of r1 Right a -> case a of r2 Right b -> let v = Right b in Right v we first replace v with r2. Next we want to replace Right r2 with r1. But the ce_conAppMap contains Right a! Therefore, we add r1 ↦ x to ce_bndrMap when analysing the outer case, and use this substitution before looking Right r2 up in ce_conAppMap, and everything works out. Note [Free variables of an StgClosure] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ `[note link] `__ StgClosures (function and thunks) have an explicit list of free variables: foo [x] = let not_a_free_var = Left [x] let a_free_var = Right [x] let closure = \[x a_free_var] -> \[y] -> bar y (Left [x]) a_free_var in closure If we were to CSE `Left [x]` in the body of `closure` with `not_a_free_var`, then the list of free variables would be wrong, so for now, we do not CSE across such a closure, simply because I (Joachim) was not sure about possible knock-on effects. If deemed safe and worth the slight code complication of re-calculating this list during or after this pass, this can surely be done.