Note [Rubbish literals]

GHC/Types/Literal.hs:975 compiler 1 ticket

Sometimes, we need to cough up a rubbish value of a certain type that is used
in place of dead code we thus aim to eliminate. The value of a dead occurrence
has no effect on the dynamic semantics of the program, so we can pick any value
of the same representation.

Exploiting the results of absence analysis in worker/wrapper is a scenario where
we need such a rubbish value, see examples in Note [Absent fillers] in
GHC.Core.Opt.WorkWrap.Utils.

It's completely undefined what the *value* of a rubbish value is, e.g., we could
pick @0#@ for @Int#@ or @42#@; it mustn't matter where it's inserted into a Core
program. We embed these rubbish values in the 'LitRubbish' case of the 'Literal'
data type. Here are the moving parts:

1. Source Haskell: No way to produce rubbish lits in source syntax. Purely
   an IR feature.

2. Core: 'LitRubbish' carries a `Type` of kind RuntimeRep,
   describing the runtime representation of the literal (is it a
   pointer, an unboxed Double#, or whatever).

   We have it that `RUBBISH[rr]` has type `forall (a :: TYPE rr). a`.
   See the `LitRubbish` case of `literalType`.

   The function GHC.Core.Make.mkLitRubbish makes a Core rubbish literal of
   a given type.  It obeys the following invariants:

   INVARIANT 1: 'rr' has no free variables. Main reason: we don't need to run
   substitutions and free variable finders over Literal. The rules around
   levity/runtime-rep polymorphism naturally uphold this invariant.

   INVARIANT 2: we never make a rubbish literal of type (a ~# b). Reason:
   see Note [Core type and coercion invariant] in GHC.Core.  We can't substitute
   a LitRubbish inside a coercion, so it's best not to make one. They are zero
   width anyway, so passing absent ones around costs nothing.  If we wanted
   an absent filler of type (a ~# b) we should use (Coercion (UnivCo ...)),
   but it doesn't seem worth making a new UnivCoProvenance for this purpose.

   This is sad, though: see #18983.

3. STG: The type app in `RUBBISH[IntRep] @Int# :: Int#` is erased and we get
   the (untyped) 'StgLit' `RUBBISH[IntRep] :: Int#` in STG.

   It's treated mostly opaque, with the exception of the Unariser, where we
   take apart a case scrutinisation on, or arg occurrence of, e.g.,
   `RUBBISH[TupleRep[IntRep,DoubleRep]]` (which may stand in for `(# Int#, Double# #)`)
   into its sub-parts `RUBBISH[IntRep]` and `RUBBISH[DoubleRep]`, similar to
   unboxed tuples.

   See 'unariseLiteral_maybe' and also Note [Post-unarisation invariants].

4. Cmm: We translate 'LitRubbish' to their actual rubbish value in 'cgLit'.
   The particulars are boring, and only matter when debugging illicit use of
   a rubbish value; see Modes of failure below.

5. Bytecode: In GHC.ByteCode.Asm we just lower it as a 0 literal, because it's
   all boxed to the host GC anyway.

6. IfaceSyn: `Literal` is part of `IfaceSyn`, but `Type` really isn't.  So in
   the passage from Core to Iface we put LitRubbish into its own IfaceExpr data
   constructor, IfaceLitRubbish. The remaining constructors of Literal are
   fine as IfaceSyn.

Wrinkles

a) Why do we put the `Type` (of kind RuntimeRep) inside the literal?  Could
   we not instead /apply/ the literal to that RuntimeRep?  Alas no, because
   then LitRubbish :: forall (rr::RuntimeRep) (a::TYPE rr). a
   and that's an ill-formed type because its kind is `TYPE rr`, which escapes
   the binding site of `rr`. Annoying.

b) A rubbish literal is not bottom, and replies True to exprOkForSpeculation.
   For unboxed types there is no bottom anyway.  If we have
       let (x::Int#) = RUBBISH[IntRep] @Int#
   we want to convert that to a case!  We want to leave it as a let, and
   probably discard it as dead code soon after because x is unused.

c) We can see a rubbish literal at the head of an application chain.
   Most obviously, pretty much every rubbish literal is the head of a
   type application e.g. `RUBBISH[IntRep] @Int#`.  But see also
   Note [How a rubbish literal can be the head of an application]

c) Literal is in Ord, because (and only because) we use Ord on AltCon when
   building a TypeMap. Annoying.  We use `nonDetCmpType` here; the
   non-determinism won't matter because it's only used in TrieMap.
   Moreover, rubbish literals should not appear in patterns anyway.

d) Why not lower LitRubbish in CoreToStg? Because it enables us to use
   LitRubbish when unarising unboxed sums in the future, and it allows
   rubbish values of e.g.  VecRep, for which we can't cough up dummy
   values in STG.

Modes of failure

Suppose there is a bug in GHC, and a rubbish value is used after all. That is
undefined behavior, of course, but let us list a few examples for failure modes:

 a) For an value of unboxed numeric type like `Int#`, we just use a silly
    value like 42#. The error might propagate indefinitely, hence we better
    pick a rather unique literal. Same for Word, Floats, Char and VecRep.
 b) For AddrRep (like String lits), we emit a null pointer, resulting in a
    definitive segfault when accessed.
 c) For boxed values, unlifted or not, we use a pointer to a fixed closure,
    like `()`, so that the GC has a pointer to follow.
    If we use that pointer as an 'Array#', we will likely access fields of the
    array that don't exist, and a seg-fault is likely, but not guaranteed.
    If we use that pointer as `Either Int Bool`, we might try to access the
    'Int' field of the 'Left' constructor (which has the same ConTag as '()'),
    which doesn't exists. In the best case, we'll find an invalid pointer in its
    position and get a seg-fault, in the worst case the error manifests only one
    or two indirections later.

References 4

Referenced by 12