Note [Desugaring seq]

GHC/HsToCore/Expr.hs:580 compiler 3 tickets

There are a few subtleties in the desugaring of `seq`, all
implemented in the `seqId` case of `ds_app_var`:

 1. (as described in #1031)

    Consider,
       f x y = x `seq` (y `seq` (# x,y #))

    Because the argument to the outer 'seq' has an unlifted type, we'll use
    call-by-value, and compile it as if we had

       f x y = case (y `seq` (# x,y #)) of v -> x `seq` v

    But that is bad, because we now evaluate y before x!

    Seq is very, very special!  So we recognise it right here, and desugar to
            case x of _ -> case y of _ -> (# x,y #)

 2. (as described in #2273)

    Consider
       let chp = case b of { True -> fst x; False -> 0 }
       in chp `seq` ...chp...
    Here the seq is designed to plug the space leak of retaining (snd x)
    for too long.

    If we rely on the ordinary inlining of seq, we'll get
       let chp = case b of { True -> fst x; False -> 0 }
       case chp of _ { I# -> ...chp... }

    But since chp is cheap, and the case is an alluring context, we'll
    inline chp into the case scrutinee.  Now there is only one use of chp,
    so we'll inline a second copy.  Alas, we've now ruined the purpose of
    the seq, by re-introducing the space leak:
        case (case b of {True -> fst x; False -> 0}) of
          I# _ -> ...case b of {True -> fst x; False -> 0}...

    We can try to avoid doing this by ensuring that the binder-swap in the
    case happens, so we get this at an early stage:
       case chp of chp2 { I# -> ...chp2... }
    But this is fragile.  The real culprit is the source program.  Perhaps we
    should have said explicitly
       let !chp2 = chp in ...chp2...

    But that's painful.  So the code here does a little hack to make seq
    more robust: a saturated application of 'seq' is turned *directly* into
    the case expression, thus:
       x  `seq` e2 ==> case x of x -> e2    -- Note shadowing!
       e1 `seq` e2 ==> case x of _ -> e2

    So we desugar our example to:
       let chp = case b of { True -> fst x; False -> 0 }
       case chp of chp { I# -> ...chp... }
    And now all is well.

    The reason it's a hack is because if you define mySeq=seq, the hack
    won't work on mySeq.

 3. (as described in #2409)

    The isInternalName ensures that we don't turn
            True `seq` e
    into
            case True of True { ... }
    which stupidly tries to bind the datacon 'True'.

References 0

This Note does not link to any other.

Referenced by 3