{-
For @Lets@, the possible ``drop points'' for the \tr{to_drop}
bindings are: (a)~in the body, (b1)~in the RHS of a NonRec binding,
or~(b2), in each of the RHSs of the pairs of a @Rec@.

Note that we do {\em weird things} with this let's binding.  Consider:
\begin{verbatim}
let
    w = ...
in {
    let v = ... w ...
    in ... v .. w ...
}
\end{verbatim}
Look at the inner \tr{let}.  As \tr{w} is used in both the bind and
body of the inner let, we could panic and leave \tr{w}'s binding where
it is.  But \tr{v} is floatable further into the body of the inner let, and
{\em then} \tr{w} will also be only in the body of that inner let.

So: rather than drop \tr{w}'s binding here, we add it onto the list of
things to drop in the outer let's body, and let nature take its
course.

Note [extra_fvs (1): avoid floating into RHS]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider let x=\y....t... in body.  We do not necessarily want to float
a binding for t into the RHS, because it'll immediately be floated out
again.  (It won't go inside the lambda else we risk losing work.)
In letrec, we need to be more careful still. We don't want to transform
        let x# = y# +# 1#
        in
        letrec f = \z. ...x#...f...
        in ...
into
        letrec f = let x# = y# +# 1# in \z. ...x#...f... in ...
because now we can't float the let out again, because a letrec
can't have unboxed bindings.

So we make "extra_fvs" which is the rhs_fvs of such bindings, and
arrange to dump bindings that bind extra_fvs before the entire let.

Note [extra_fvs (2): free variables of rules]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Consider
  let x{rule mentioning y} = rhs in body
Here y is not free in rhs or body; but we still want to dump bindings
that bind y outside the let.  So we augment extra_fvs with the
idRuleAndUnfoldingVars of x.  No need for type variables, hence not using
idFreeVars.
-}

fiExpr dflags to_drop (_,AnnLet (AnnNonRec id rhs@(rhs_fvs, ann_rhs)) body)
  = fiExpr dflags new_to_drop body
  where
    body_fvs = freeVarsOf body `delVarSet` id
    rhs_ty = idType id

    rule_fvs = idRuleAndUnfoldingVars id        -- See Note [extra_fvs (2): free variables of rules]
    extra_fvs | noFloatIntoRhs ann_rhs rhs_ty = rule_fvs `unionVarSet` rhs_fvs
              | otherwise                     = rule_fvs
        -- See Note [extra_fvs (1): avoid floating into RHS]
        -- No point in floating in only to float straight out again
        -- Ditto ok-for-speculation unlifted RHSs

    [shared_binds, extra_binds, rhs_binds, body_binds]
        = sepBindsByDropPoint dflags False [extra_fvs, rhs_fvs, body_fvs] to_drop

    new_to_drop = body_binds ++                         -- the bindings used only in the body
                  [FB (unitVarSet id) rhs_fvs'
                      (FloatLet (NonRec id rhs'))] ++   -- the new binding itself
                  extra_binds ++                        -- bindings from extra_fvs
                  shared_binds                          -- the bindings used both in rhs and body

        -- Push rhs_binds into the right hand side of the binding
    rhs'     = fiExpr dflags rhs_binds rhs
    rhs_fvs' = rhs_fvs `unionVarSet` floatedBindsFVs rhs_binds `unionVarSet` rule_fvs
                        -- Don't forget the rule_fvs; the binding mentions them!
fiExpr dflags to_drop (_,AnnLet (AnnNonRec id rhs@(rhs_fvs, ann_rhs)) body)
  = fiExpr dflags new_to_drop body
  where
    body_fvs = freeVarsOf body `delVarSet` id
    rhs_ty = idType id

    rule_fvs = idRuleAndUnfoldingVars id        -- See Note [extra_fvs (2): free variables of rules]
    extra_fvs | noFloatIntoRhs ann_rhs rhs_ty = rule_fvs `unionVarSet` rhs_fvs
              | otherwise                     = rule_fvs
        -- See Note [extra_fvs (1): avoid floating into RHS]
        -- No point in floating in only to float straight out again
        -- Ditto ok-for-speculation unlifted RHSs

    [shared_binds, extra_binds, rhs_binds, body_binds]
        = sepBindsByDropPoint dflags False [extra_fvs, rhs_fvs, body_fvs] to_drop

    new_to_drop = body_binds ++                         -- the bindings used only in the body
                  [FB (unitVarSet id) rhs_fvs'
                      (FloatLet (NonRec id rhs'))] ++   -- the new binding itself
                  extra_binds ++                        -- bindings from extra_fvs
                  shared_binds                          -- the bindings used both in rhs and body

        -- Push rhs_binds into the right hand side of the binding
    rhs'     = fiExpr dflags rhs_binds rhs
    rhs_fvs' = rhs_fvs `unionVarSet` floatedBindsFVs rhs_binds `unionVarSet` rule_fvs
                        -- Don't forget the rule_fvs; the binding mentions them!
fiExpr dflags to_drop (_,AnnLet (AnnNonRec id rhs@(rhs_fvs, ann_rhs)) body)
  = fiExpr dflags new_to_drop body
  where
    body_fvs = freeVarsOf body `delVarSet` id
    rhs_ty = idType id

    rule_fvs = idRuleAndUnfoldingVars id        -- See Note [extra_fvs (2): free variables of rules]
    extra_fvs | noFloatIntoRhs ann_rhs rhs_ty = rule_fvs `unionVarSet` rhs_fvs
              | otherwise                     = rule_fvs
        -- See Note [extra_fvs (1): avoid floating into RHS]
        -- No point in floating in only to float straight out again
        -- Ditto ok-for-speculation unlifted RHSs

    [shared_binds, extra_binds, rhs_binds, body_binds]
        = sepBindsByDropPoint dflags False [extra_fvs, rhs_fvs, body_fvs] to_drop

    new_to_drop = body_binds ++                         -- the bindings used only in the body
                  [FB (unitVarSet id) rhs_fvs'
                      (FloatLet (NonRec id rhs'))] ++   -- the new binding itself
                  extra_binds ++                        -- bindings from extra_fvs
                  shared_binds                          -- the bindings used both in rhs and body

        -- Push rhs_binds into the right hand side of the binding
    rhs'     = fiExpr dflags rhs_binds rhs
    rhs_fvs' = rhs_fvs `unionVarSet` floatedBindsFVs rhs_binds `unionVarSet` rule_fvs
                        -- Don't forget the rule_fvs; the binding mentions them!