fiExpr dflags to_drop (_,AnnLet (AnnRec bindings) body)
  = fiExpr dflags new_to_drop body
  where
    (ids, rhss) = unzip bindings
    rhss_fvs = map freeVarsOf rhss
    body_fvs = freeVarsOf body

        -- See Note [extra_fvs (1,2)]
    rule_fvs = mapUnionVarSet idRuleAndUnfoldingVars ids
    extra_fvs = rule_fvs `unionVarSet`
                unionVarSets [ fvs | (fvs, rhs) <- rhss
                             , noFloatIntoExpr rhs ]

    (shared_binds:extra_binds:body_binds:rhss_binds)
        = sepBindsByDropPoint dflags False (extra_fvs:body_fvs:rhss_fvs) to_drop

    new_to_drop = body_binds ++         -- the bindings used only in the body
                  [FB (mkVarSet ids) rhs_fvs'
                      (FloatLet (Rec (fi_bind rhss_binds bindings)))] ++
                                        -- The new binding itself
                  extra_binds ++        -- Note [extra_fvs (1,2)]
                  shared_binds          -- Used in more than one place

    rhs_fvs' = unionVarSets rhss_fvs `unionVarSet`
               unionVarSets (map floatedBindsFVs rhss_binds) `unionVarSet`
               rule_fvs         -- Don't forget the rule variables!

    -- Push rhs_binds into the right hand side of the binding
    fi_bind :: [FloatInBinds]       -- one per "drop pt" conjured w/ fvs_of_rhss
            -> [(Id, CoreExprWithFVs)]
            -> [(Id, CoreExpr)]

    fi_bind to_drops pairs
      = [ (binder, fiExpr dflags to_drop rhs)
        | ((binder, rhs), to_drop) <- zipEqual "fi_bind" pairs to_drops ]

{-
For @Case@, the possible ``drop points'' for the \tr{to_drop}
bindings are: (a)~inside the scrutinee, (b)~inside one of the
alternatives/default [default FVs always {\em first}!].

Floating case expressions inward was added to fix Trac #5658: strict bindings
not floated in. In particular, this change allows array indexing operations,
which have a single DEFAULT alternative without any binders, to be floated
inward. SIMD primops for unpacking SIMD vectors into an unboxed tuple of unboxed
scalars also need to be floated inward, but unpacks have a single non-DEFAULT
alternative that binds the elements of the tuple. We now therefore also support
floating in cases with a single alternative that may bind values.
-}
fiExpr dflags to_drop (_,AnnLet (AnnRec bindings) body)
  = fiExpr dflags new_to_drop body
  where
    (ids, rhss) = unzip bindings
    rhss_fvs = map freeVarsOf rhss
    body_fvs = freeVarsOf body

        -- See Note [extra_fvs (1,2)]
    rule_fvs = mapUnionVarSet idRuleAndUnfoldingVars ids
    extra_fvs = rule_fvs `unionVarSet`
                unionVarSets [ fvs | (fvs, rhs) <- rhss
                             , noFloatIntoExpr rhs ]

    (shared_binds:extra_binds:body_binds:rhss_binds)
        = sepBindsByDropPoint dflags False (extra_fvs:body_fvs:rhss_fvs) to_drop

    new_to_drop = body_binds ++         -- the bindings used only in the body
                  [FB (mkVarSet ids) rhs_fvs'
                      (FloatLet (Rec (fi_bind rhss_binds bindings)))] ++
                                        -- The new binding itself
                  extra_binds ++        -- Note [extra_fvs (1,2)]
                  shared_binds          -- Used in more than one place

    rhs_fvs' = unionVarSets rhss_fvs `unionVarSet`
               unionVarSets (map floatedBindsFVs rhss_binds) `unionVarSet`
               rule_fvs         -- Don't forget the rule variables!

    -- Push rhs_binds into the right hand side of the binding
    fi_bind :: [FloatInBinds]       -- one per "drop pt" conjured w/ fvs_of_rhss
            -> [(Id, CoreExprWithFVs)]
            -> [(Id, CoreExpr)]

    fi_bind to_drops pairs
      = [ (binder, fiExpr dflags to_drop rhs)
        | ((binder, rhs), to_drop) <- zipEqual "fi_bind" pairs to_drops ]

{-
For @Case@, the possible ``drop points'' for the \tr{to_drop}
bindings are: (a)~inside the scrutinee, (b)~inside one of the
alternatives/default [default FVs always {\em first}!].

Floating case expressions inward was added to fix Trac #5658: strict bindings
not floated in. In particular, this change allows array indexing operations,
which have a single DEFAULT alternative without any binders, to be floated
inward. SIMD primops for unpacking SIMD vectors into an unboxed tuple of unboxed
scalars also need to be floated inward, but unpacks have a single non-DEFAULT
alternative that binds the elements of the tuple. We now therefore also support
floating in cases with a single alternative that may bind values.
-}
fiExpr dflags to_drop (_,AnnLet (AnnRec bindings) body)
  = fiExpr dflags new_to_drop body
  where
    (ids, rhss) = unzip bindings
    rhss_fvs = map freeVarsOf rhss
    body_fvs = freeVarsOf body

        -- See Note [extra_fvs (1,2)]
    rule_fvs = mapUnionVarSet idRuleAndUnfoldingVars ids
    extra_fvs = rule_fvs `unionVarSet`
                unionVarSets [ fvs | (fvs, rhs) <- rhss
                             , noFloatIntoExpr rhs ]

    (shared_binds:extra_binds:body_binds:rhss_binds)
        = sepBindsByDropPoint dflags False (extra_fvs:body_fvs:rhss_fvs) to_drop

    new_to_drop = body_binds ++         -- the bindings used only in the body
                  [FB (mkVarSet ids) rhs_fvs'
                      (FloatLet (Rec (fi_bind rhss_binds bindings)))] ++
                                        -- The new binding itself
                  extra_binds ++        -- Note [extra_fvs (1,2)]
                  shared_binds          -- Used in more than one place

    rhs_fvs' = unionVarSets rhss_fvs `unionVarSet`
               unionVarSets (map floatedBindsFVs rhss_binds) `unionVarSet`
               rule_fvs         -- Don't forget the rule variables!

    -- Push rhs_binds into the right hand side of the binding
    fi_bind :: [FloatInBinds]       -- one per "drop pt" conjured w/ fvs_of_rhss
            -> [(Id, CoreExprWithFVs)]
            -> [(Id, CoreExpr)]

    fi_bind to_drops pairs
      = [ (binder, fiExpr dflags to_drop rhs)
        | ((binder, rhs), to_drop) <- zipEqual "fi_bind" pairs to_drops ]

{-
For @Case@, the possible ``drop points'' for the \tr{to_drop}
bindings are: (a)~inside the scrutinee, (b)~inside one of the
alternatives/default [default FVs always {\em first}!].

Floating case expressions inward was added to fix Trac #5658: strict bindings
not floated in. In particular, this change allows array indexing operations,
which have a single DEFAULT alternative without any binders, to be floated
inward. SIMD primops for unpacking SIMD vectors into an unboxed tuple of unboxed
scalars also need to be floated inward, but unpacks have a single non-DEFAULT
alternative that binds the elements of the tuple. We now therefore also support
floating in cases with a single alternative that may bind values.
-}