--------------------------------------------------
--      2. Eliminate Identity Case
--------------------------------------------------

mkCase1 _dflags scrut case_bndr _ alts@((_,_,rhs1) : _)      -- Identity case
  | all identity_alt alts
  = do { tick (CaseIdentity case_bndr)
       ; return (mkTicks ticks $ re_cast scrut rhs1) }
  where
    ticks = concatMap (stripTicksT tickishFloatable . thirdOf3) (tail alts)
    identity_alt (con, args, rhs) = check_eq rhs con args

    check_eq (Cast rhs co) con        args
      = not (any (`elemVarSet` tyCoVarsOfCo co) args) && check_eq rhs con args
        -- See Note [RHS casts]
    check_eq (Lit lit)  (LitAlt lit') _    = lit == lit'
    check_eq (Var v) _ _  | v == case_bndr = True
    check_eq (Var v)    (DataAlt con) []   = v == dataConWorkId con
                                             -- Optimisation only
    check_eq (Tick t e) alt           args = tickishFloatable t &&
                                             check_eq e alt args
    check_eq rhs        (DataAlt con) args = cheapEqExpr' tickishFloatable rhs $
                                             mkConApp con (arg_tys ++
                                                           varsToCoreExprs args)
    check_eq _          _             _    = False

    arg_tys = map Type (tyConAppArgs (idType case_bndr))

        -- Note [RHS casts]
        -- ~~~~~~~~~~~~~~~~
        -- We've seen this:
        --      case e of x { _ -> x `cast` c }
        -- And we definitely want to eliminate this case, to give
        --      e `cast` c
        -- So we throw away the cast from the RHS, and reconstruct
        -- it at the other end.  All the RHS casts must be the same
        -- if (all identity_alt alts) holds.
        --
        -- Don't worry about nested casts, because the simplifier combines them

    re_cast scrut (Cast rhs co) = Cast (re_cast scrut rhs) co
    re_cast scrut _             = scrut
mkCase1 _dflags scrut case_bndr _ alts@((_,_,rhs1) : _)      -- Identity case
  | all identity_alt alts
  = do { tick (CaseIdentity case_bndr)
       ; return (mkTicks ticks $ re_cast scrut rhs1) }
  where
    ticks = concatMap (stripTicksT tickishFloatable . thirdOf3) (tail alts)
    identity_alt (con, args, rhs) = check_eq rhs con args

    check_eq (Cast rhs co) con        args
      = not (any (`elemVarSet` tyCoVarsOfCo co) args) && check_eq rhs con args
        -- See Note [RHS casts]
    check_eq (Lit lit)  (LitAlt lit') _    = lit == lit'
    check_eq (Var v) _ _  | v == case_bndr = True
    check_eq (Var v)    (DataAlt con) []   = v == dataConWorkId con
                                             -- Optimisation only
    check_eq (Tick t e) alt           args = tickishFloatable t &&
                                             check_eq e alt args
    check_eq rhs        (DataAlt con) args = cheapEqExpr' tickishFloatable rhs $
                                             mkConApp con (arg_tys ++
                                                           varsToCoreExprs args)
    check_eq _          _             _    = False

    arg_tys = map Type (tyConAppArgs (idType case_bndr))

        -- Note [RHS casts]
        -- ~~~~~~~~~~~~~~~~
        -- We've seen this:
        --      case e of x { _ -> x `cast` c }
        -- And we definitely want to eliminate this case, to give
        --      e `cast` c
        -- So we throw away the cast from the RHS, and reconstruct
        -- it at the other end.  All the RHS casts must be the same
        -- if (all identity_alt alts) holds.
        --
        -- Don't worry about nested casts, because the simplifier combines them

    re_cast scrut (Cast rhs co) = Cast (re_cast scrut rhs) co
    re_cast scrut _             = scrut
mkCase1 _dflags scrut case_bndr _ alts@((_,_,rhs1) : _)      -- Identity case
  | all identity_alt alts
  = do { tick (CaseIdentity case_bndr)
       ; return (mkTicks ticks $ re_cast scrut rhs1) }
  where
    ticks = concatMap (stripTicksT tickishFloatable . thirdOf3) (tail alts)
    identity_alt (con, args, rhs) = check_eq rhs con args

    check_eq (Cast rhs co) con        args
      = not (any (`elemVarSet` tyCoVarsOfCo co) args) && check_eq rhs con args
        -- See Note [RHS casts]
    check_eq (Lit lit)  (LitAlt lit') _    = lit == lit'
    check_eq (Var v) _ _  | v == case_bndr = True
    check_eq (Var v)    (DataAlt con) []   = v == dataConWorkId con
                                             -- Optimisation only
    check_eq (Tick t e) alt           args = tickishFloatable t &&
                                             check_eq e alt args
    check_eq rhs        (DataAlt con) args = cheapEqExpr' tickishFloatable rhs $
                                             mkConApp con (arg_tys ++
                                                           varsToCoreExprs args)
    check_eq _          _             _    = False

    arg_tys = map Type (tyConAppArgs (idType case_bndr))

        -- Note [RHS casts]
        -- ~~~~~~~~~~~~~~~~
        -- We've seen this:
        --      case e of x { _ -> x `cast` c }
        -- And we definitely want to eliminate this case, to give
        --      e `cast` c
        -- So we throw away the cast from the RHS, and reconstruct
        -- it at the other end.  All the RHS casts must be the same
        -- if (all identity_alt alts) holds.
        --
        -- Don't worry about nested casts, because the simplifier combines them

    re_cast scrut (Cast rhs co) = Cast (re_cast scrut rhs) co
    re_cast scrut _             = scrut