Note [Inlining in CorePrep]

GHC/CoreToStg/Prep.hs:2421 compiler

There is a subtle but important invariant that must be upheld in the output
of CorePrep: there are no "trivial" updatable thunks.  Thus, this Core
is impermissible:

     let x :: ()
         x = y

(where y is a reference to a GLOBAL variable).  Thunks like this are silly:
they can always be profitably replaced by inlining x with y. Consequently,
the code generator/runtime does not bother implementing this properly
(specifically, there is no implementation of stg_ap_0_upd_info, which is the
stack frame that would be used to update this thunk.  The "0" means it has
zero free variables.)

In general, the inliner is good at eliminating these let-bindings.  However,
there is one case where these trivial updatable thunks can arise: when
we are optimizing away 'lazy' (see Note [lazyId magic], and also
'cpeRhsE'.)  Then, we could have started with:

     let x :: ()
         x = lazy @() y

which is a perfectly fine, non-trivial thunk, but then CorePrep will drop
'lazy', giving us 'x = y' which is trivial and impermissible.  The solution is
CorePrep to have a miniature inlining pass which deals with cases like this.
We can then drop the let-binding altogether.

Why does the removal of 'lazy' have to occur in CorePrep?  The gory details
are in Note [lazyId magic] in GHC.Types.Id.Make, but the main reason is that
lazy must appear in unfoldings (optimizer output) and it must prevent
call-by-value for catch# (which is implemented by CorePrep.)

An alternate strategy for solving this problem is to have the inliner treat
'lazy e' as a trivial expression if 'e' is trivial.  We decided not to adopt
this solution to keep the definition of 'exprIsTrivial' simple.

There is ONE caveat however: for top-level bindings we have
to preserve the binding so that we float the (hacky) non-recursive
binding for data constructors; see Note [Data constructor workers].

References 2

Referenced by 3