module SimplUtils (
simplBinder, simplBinders, simplRecBndrs,
simplLetBndr, simplLamBndrs,
- newId, mkLam, mkCase,
+ newId, mkLam, prepareAlts, mkCase,
-- The continuation type
SimplCont(..), DupFlag(..), LetRhsFlag(..),
contIsDupable, contResultType,
countValArgs, countArgs, pushContArgs,
- mkBoringStop, mkStop, contIsRhs, contIsRhsOrArg,
+ mkBoringStop, mkRhsStop, contIsRhs, contIsRhsOrArg,
getContArgs, interestingCallContext, interestingArg, isStrictType
) where
#include "HsVersions.h"
-import CmdLineOpts ( SimplifierSwitch(..),
- opt_SimplDoLambdaEtaExpansion, opt_SimplDoEtaReduction,
- opt_SimplCaseMerge, opt_UF_UpdateInPlace
- )
+import CmdLineOpts ( SimplifierSwitch(..), opt_UF_UpdateInPlace,
+ DynFlag(..), dopt )
import CoreSyn
-import CoreUtils ( cheapEqExpr, exprType,
- etaExpand, exprEtaExpandArity, bindNonRec, mkCoerce,
+import CoreFVs ( exprFreeVars )
+import CoreUtils ( cheapEqExpr, exprType, exprIsTrivial,
+ etaExpand, exprEtaExpandArity, bindNonRec, mkCoerce2,
findDefault, exprOkForSpeculation, exprIsValue
)
import qualified Subst ( simplBndrs, simplBndr, simplLetId, simplLamBndr )
-import Id ( Id, idType, idInfo,
+import Id ( Id, idType, idInfo, isDataConWorkId,
mkSysLocal, isDeadBinder, idNewDemandInfo,
idUnfolding, idNewStrictness
)
import NewDemand ( isStrictDmd, isBotRes, splitStrictSig )
import SimplMonad
-import Type ( Type, seqType,
- splitTyConApp_maybe, tyConAppArgs, mkTyVarTys,
- splitRepFunTys, isStrictType
+import Type ( Type, seqType, splitFunTys, dropForAlls, isStrictType,
+ splitTyConApp_maybe, tyConAppArgs, mkTyVarTys
)
-import OccName ( UserFS )
-import TyCon ( tyConDataConsIfAvailable, isAlgTyCon, isNewTyCon )
-import DataCon ( dataConRepArity, dataConSig, dataConArgTys )
-import Var ( mkSysTyVar, tyVarKind )
+import TcType ( isDictTy )
+import Name ( mkSysTvName )
+import OccName ( EncodedFS )
+import TyCon ( tyConDataCons_maybe, isAlgTyCon, isNewTyCon )
+import DataCon ( dataConRepArity, dataConTyVars, dataConArgTys, isVanillaDataCon )
+import Var ( tyVarKind, mkTyVar )
+import VarSet
import Util ( lengthExceeds, mapAccumL )
import Outputable
\end{code}
InId [InAlt] SimplEnv -- The case binder, alts, and subst-env
SimplCont
- | ArgOf DupFlag -- An arbitrary strict context: the argument
+ | ArgOf LetRhsFlag -- An arbitrary strict context: the argument
-- of a strict function, or a primitive-arg fn
-- or a PrimOp
- LetRhsFlag
+ -- No DupFlag because we never duplicate it
+ OutType -- arg_ty: type of the argument itself
OutType -- cont_ty: the type of the expression being sought by the context
-- f (error "foo") ==> coerce t (error "foo")
-- when f is strict
-- We need to know the type t, to which to coerce.
+
(SimplEnv -> OutExpr -> SimplM FloatsWithExpr) -- What to do with the result
-- The result expression in the OutExprStuff has type cont_ty
instance Outputable SimplCont where
ppr (Stop _ is_rhs _) = ptext SLIT("Stop") <> brackets (ppr is_rhs)
ppr (ApplyTo dup arg se cont) = (ptext SLIT("ApplyTo") <+> ppr dup <+> ppr arg) $$ ppr cont
- ppr (ArgOf dup _ _ _) = ptext SLIT("ArgOf...") <+> ppr dup
+ ppr (ArgOf _ _ _ _) = ptext SLIT("ArgOf...")
ppr (Select dup bndr alts se cont) = (ptext SLIT("Select") <+> ppr dup <+> ppr bndr) $$
(nest 4 (ppr alts)) $$ ppr cont
ppr (CoerceIt ty cont) = (ptext SLIT("CoerceIt") <+> ppr ty) $$ ppr cont
-------------------
-mkBoringStop :: OutType -> SimplCont
+mkBoringStop, mkRhsStop :: OutType -> SimplCont
mkBoringStop ty = Stop ty AnArg (canUpdateInPlace ty)
-
-mkStop :: OutType -> LetRhsFlag -> SimplCont
-mkStop ty is_rhs = Stop ty is_rhs (canUpdateInPlace ty)
+mkRhsStop ty = Stop ty AnRhs (canUpdateInPlace ty)
contIsRhs :: SimplCont -> Bool
contIsRhs (Stop _ AnRhs _) = True
-contIsRhs (ArgOf _ AnRhs _ _) = True
+contIsRhs (ArgOf AnRhs _ _ _) = True
contIsRhs other = False
contIsRhsOrArg (Stop _ _ _) = True
contIsDupable :: SimplCont -> Bool
contIsDupable (Stop _ _ _) = True
contIsDupable (ApplyTo OkToDup _ _ _) = True
-contIsDupable (ArgOf OkToDup _ _ _) = True
contIsDupable (Select OkToDup _ _ _ _) = True
contIsDupable (CoerceIt _ cont) = contIsDupable cont
-contIsDupable (InlinePlease cont) = contIsDupable cont
-contIsDupable other = False
+contIsDupable (InlinePlease cont) = contIsDupable cont
+contIsDupable other = False
-------------------
discardableCont :: SimplCont -> Bool
-- * (error "Hello") arg
-- * f (error "Hello") where f is strict
-- etc
+ -- Then, especially in the first of these cases, we'd like to discard
+ -- the continuation, leaving just the bottoming expression. But the
+ -- type might not be right, so we may have to add a coerce.
go acc ss inl cont
| null ss && discardableCont cont = (reverse acc, discardCont cont, inl)
| otherwise = (reverse acc, cont, inl)
computed_stricts = zipWith (||) fun_stricts arg_stricts
----------------------------
- (val_arg_tys, _) = splitRepFunTys (idType fun)
+ (val_arg_tys, _) = splitFunTys (dropForAlls (idType fun))
arg_stricts = map isStrictType val_arg_tys ++ repeat False
-- These argument types are used as a cheap and cheerful way to find
-- unboxed arguments, which must be strict. But it's an InType
-- and so there might be a type variable where we expect a function
-- type (the substitution hasn't happened yet). And we don't bother
-- doing the type applications for a polymorphic function.
- -- Hence the split*Rep*FunTys
+ -- Hence the splitFunTys*IgnoringForAlls*
----------------------------
-- If fun_stricts is finite, it means the function returns bottom
interestingArg (Var v) = hasSomeUnfolding (idUnfolding v)
-- Was: isValueUnfolding (idUnfolding v')
-- But that seems over-pessimistic
+ || isDataConWorkId v
+ -- This accounts for an argument like
+ -- () or [], which is definitely interesting
interestingArg (Type _) = False
interestingArg (App fn (Type _)) = interestingArg fn
interestingArg (Note _ a) = interestingArg a
interestingCallContext some_args some_val_args cont
= interesting cont
where
- interesting (InlinePlease _) = True
- interesting (Select _ _ _ _ _) = some_args
- interesting (ApplyTo _ _ _ _) = True -- Can happen if we have (coerce t (f x)) y
+ interesting (InlinePlease _) = True
+ interesting (Select _ _ _ _ _) = some_args
+ interesting (ApplyTo _ _ _ _) = True -- Can happen if we have (coerce t (f x)) y
-- Perhaps True is a bit over-keen, but I've
-- seen (coerce f) x, where f has an INLINE prag,
-- So we have to give some motivaiton for inlining it
| otherwise
= case splitTyConApp_maybe ty of
Nothing -> False
- Just (tycon, _) -> case tyConDataConsIfAvailable tycon of
- [dc] -> arity == 1 || arity == 2
- where
- arity = dataConRepArity dc
+ Just (tycon, _) -> case tyConDataCons_maybe tycon of
+ Just [dc] -> arity == 1 || arity == 2
+ where
+ arity = dataConRepArity dc
other -> False
\end{code}
\begin{code}
-newId :: UserFS -> Type -> SimplM Id
+newId :: EncodedFS -> Type -> SimplM Id
newId fs ty = getUniqueSmpl `thenSmpl` \ uniq ->
returnSmpl (mkSysLocal fs uniq ty)
\end{code}
\begin{code}
mkLam env bndrs body cont
- | opt_SimplDoEtaReduction,
- Just etad_lam <- tryEtaReduce bndrs body
- = tick (EtaReduction (head bndrs)) `thenSmpl_`
- returnSmpl (emptyFloats env, etad_lam)
-
- | opt_SimplDoLambdaEtaExpansion,
- any isRuntimeVar bndrs
- = tryEtaExpansion body `thenSmpl` \ body' ->
- returnSmpl (emptyFloats env, mkLams bndrs body')
+ = getDOptsSmpl `thenSmpl` \dflags ->
+ mkLam' dflags env bndrs body cont
+ where
+ mkLam' dflags env bndrs body cont
+ | dopt Opt_DoEtaReduction dflags,
+ Just etad_lam <- tryEtaReduce bndrs body
+ = tick (EtaReduction (head bndrs)) `thenSmpl_`
+ returnSmpl (emptyFloats env, etad_lam)
+
+ | dopt Opt_DoLambdaEtaExpansion dflags,
+ any isRuntimeVar bndrs
+ = tryEtaExpansion body `thenSmpl` \ body' ->
+ returnSmpl (emptyFloats env, mkLams bndrs body')
{- Sept 01: I'm experimenting with getting the
full laziness pass to float out past big lambdsa
returnSmpl (floats, mkLams bndrs body')
-}
- | otherwise
- = returnSmpl (emptyFloats env, mkLams bndrs body)
+ | otherwise
+ = returnSmpl (emptyFloats env, mkLams bndrs body)
\end{code}
-- efficient here:
-- (a) we already have the binders
-- (b) we can do the triviality test before computing the free vars
- -- [in fact I take the simple path and look for just a variable]
= go (reverse bndrs) body
where
go (b : bs) (App fun arg) | ok_arg b arg = go bs fun -- Loop round
- go [] (Var fun) | ok_fun fun = Just (Var fun) -- Success!
+ go [] fun | ok_fun fun = Just fun -- Success!
go _ _ = Nothing -- Failure!
- ok_fun fun = not (fun `elem` bndrs) &&
- isEvaldUnfolding (idUnfolding fun)
+ ok_fun fun = exprIsTrivial fun
+ && not (any (`elemVarSet` (exprFreeVars fun)) bndrs)
+ && (exprIsValue fun || all ok_lam bndrs)
+ ok_lam v = isTyVar v || isDictTy (idType v)
-- The exprIsValue is because eta reduction is not
-- valid in general: \x. bot /= bot
-- So we need to be sure that the "fun" is a value.
+ --
+ -- However, we always want to reduce (/\a -> f a) to f
+ -- This came up in a RULE: foldr (build (/\a -> g a))
+ -- did not match foldr (build (/\b -> ...something complex...))
+ -- The type checker can insert these eta-expanded versions,
+ -- with both type and dictionary lambdas; hence the slightly
+ -- ad-hoc isDictTy
+
ok_arg b arg = varToCoreExpr b `cheapEqExpr` arg
\end{code}
-}
\end{code}
+%************************************************************************
+%* *
+\subsection{Case alternative filtering
+%* *
+%************************************************************************
+
+prepareAlts does two things:
+
+1. Eliminate alternatives that cannot match, including the
+ DEFAULT alternative.
+
+2. If the DEFAULT alternative can match only one possible constructor,
+ then make that constructor explicit.
+ e.g.
+ case e of x { DEFAULT -> rhs }
+ ===>
+ case e of x { (a,b) -> rhs }
+ where the type is a single constructor type. This gives better code
+ when rhs also scrutinises x or e.
+
+It's a good idea do do this stuff before simplifying the alternatives, to
+avoid simplifying alternatives we know can't happen, and to come up with
+the list of constructors that are handled, to put into the IdInfo of the
+case binder, for use when simplifying the alternatives.
+
+Eliminating the default alternative in (1) isn't so obvious, but it can
+happen:
+
+data Colour = Red | Green | Blue
+
+f x = case x of
+ Red -> ..
+ Green -> ..
+ DEFAULT -> h x
+
+h y = case y of
+ Blue -> ..
+ DEFAULT -> [ case y of ... ]
+
+If we inline h into f, the default case of the inlined h can't happen.
+If we don't notice this, we may end up filtering out *all* the cases
+of the inner case y, which give us nowhere to go!
+
+
+\begin{code}
+prepareAlts :: OutExpr -- Scrutinee
+ -> InId -- Case binder
+ -> [InAlt]
+ -> SimplM ([InAlt], -- Better alternatives
+ [AltCon]) -- These cases are handled
+
+prepareAlts scrut case_bndr alts
+ = let
+ (alts_wo_default, maybe_deflt) = findDefault alts
+
+ impossible_cons = case scrut of
+ Var v -> otherCons (idUnfolding v)
+ other -> []
+
+ -- Filter out alternatives that can't possibly match
+ better_alts | null impossible_cons = alts_wo_default
+ | otherwise = [alt | alt@(con,_,_) <- alts_wo_default,
+ not (con `elem` impossible_cons)]
+
+ -- "handled_cons" are handled either by the context,
+ -- or by a branch in this case expression
+ -- (Don't add DEFAULT to the handled_cons!!)
+ handled_cons = impossible_cons ++ [con | (con,_,_) <- better_alts]
+ in
+ -- Filter out the default, if it can't happen,
+ -- or replace it with "proper" alternative if there
+ -- is only one constructor left
+ prepareDefault case_bndr handled_cons maybe_deflt `thenSmpl` \ deflt_alt ->
+
+ returnSmpl (deflt_alt ++ better_alts, handled_cons)
+
+prepareDefault case_bndr handled_cons (Just rhs)
+ | Just (tycon, inst_tys) <- splitTyConApp_maybe (idType case_bndr),
+ isAlgTyCon tycon, -- It's a data type, tuple, or unboxed tuples.
+ not (isNewTyCon tycon), -- We can have a newtype, if we are just doing an eval:
+ -- case x of { DEFAULT -> e }
+ -- and we don't want to fill in a default for them!
+ Just all_cons <- tyConDataCons_maybe tycon,
+ not (null all_cons), -- This is a tricky corner case. If the data type has no constructors,
+ -- which GHC allows, then the case expression will have at most a default
+ -- alternative. We don't want to eliminate that alternative, because the
+ -- invariant is that there's always one alternative. It's more convenient
+ -- to leave
+ -- case x of { DEFAULT -> e }
+ -- as it is, rather than transform it to
+ -- error "case cant match"
+ -- which would be quite legitmate. But it's a really obscure corner, and
+ -- not worth wasting code on.
+ let handled_data_cons = [data_con | DataAlt data_con <- handled_cons],
+ let missing_cons = [con | con <- all_cons,
+ not (con `elem` handled_data_cons)]
+ = case missing_cons of
+ [] -> returnSmpl [] -- Eliminate the default alternative
+ -- if it can't match
+
+ [con] -> -- It matches exactly one constructor, so fill it in
+ tick (FillInCaseDefault case_bndr) `thenSmpl_`
+ mk_args con inst_tys `thenSmpl` \ args ->
+ returnSmpl [(DataAlt con, args, rhs)]
+
+ two_or_more -> returnSmpl [(DEFAULT, [], rhs)]
+
+ | otherwise
+ = returnSmpl [(DEFAULT, [], rhs)]
+
+prepareDefault case_bndr handled_cons Nothing
+ = returnSmpl []
+
+mk_args missing_con inst_tys
+ = mk_tv_bndrs missing_con inst_tys `thenSmpl` \ (tv_bndrs, inst_tys') ->
+ getUniquesSmpl `thenSmpl` \ id_uniqs ->
+ let arg_tys = dataConArgTys missing_con inst_tys'
+ arg_ids = zipWith (mkSysLocal FSLIT("a")) id_uniqs arg_tys
+ in
+ returnSmpl (tv_bndrs ++ arg_ids)
+
+mk_tv_bndrs missing_con inst_tys
+ | isVanillaDataCon missing_con
+ = returnSmpl ([], inst_tys)
+ | otherwise
+ = getUniquesSmpl `thenSmpl` \ tv_uniqs ->
+ let new_tvs = zipWith mk tv_uniqs (dataConTyVars missing_con)
+ mk uniq tv = mkTyVar (mkSysTvName uniq FSLIT("t")) (tyVarKind tv)
+ in
+ returnSmpl (new_tvs, mkTyVarTys new_tvs)
+\end{code}
+
%************************************************************************
%* *
mkCase puts a case expression back together, trying various transformations first.
\begin{code}
-mkCase :: OutExpr -> [AltCon] -> OutId -> [OutAlt] -> SimplM OutExpr
+mkCase :: OutExpr -> OutId -> OutType -> [OutAlt] -> SimplM OutExpr
-mkCase scrut handled_cons case_bndr alts
- = mkAlts scrut handled_cons case_bndr alts `thenSmpl` \ better_alts ->
- mkCase1 scrut case_bndr better_alts
+mkCase scrut case_bndr ty alts
+ = mkAlts scrut case_bndr alts `thenSmpl` \ better_alts ->
+ mkCase1 scrut case_bndr ty better_alts
\end{code}
a) all branches equal
b) some branches equal to the DEFAULT (which occurs first)
-2. If the DEFAULT alternative can match only one possible constructor,
- then make that constructor explicit.
- e.g.
- case e of x { DEFAULT -> rhs }
- ===>
- case e of x { (a,b) -> rhs }
- where the type is a single constructor type. This gives better code
- when rhs also scrutinises x or e.
-
-3. Case merging:
+2. Case merging:
case e of b { ==> case e of b {
p1 -> rhs1 p1 -> rhs1
... ...
--------------------------------------------------
-- 1. Merge identical branches
--------------------------------------------------
-mkAlts scrut handled_cons case_bndr alts@((con1,bndrs1,rhs1) : con_alts)
+mkAlts scrut case_bndr alts@((con1,bndrs1,rhs1) : con_alts)
| all isDeadBinder bndrs1, -- Remember the default
length filtered_alts < length con_alts -- alternative comes first
= tick (AltMerge case_bndr) `thenSmpl_`
--------------------------------------------------
--- 2. Fill in missing constructor
+-- 2. Merge nested cases
--------------------------------------------------
-mkAlts scrut handled_cons case_bndr alts
- | (alts_no_deflt, Just rhs) <- findDefault alts,
- -- There is a DEFAULT case
-
- Just (tycon, inst_tys) <- splitTyConApp_maybe (idType case_bndr),
- isAlgTyCon tycon, -- It's a data type, tuple, or unboxed tuples.
- not (isNewTyCon tycon), -- We can have a newtype, if we are just doing an eval:
- -- case x of { DEFAULT -> e }
- -- and we don't want to fill in a default for them!
-
- [missing_con] <- [con | con <- tyConDataConsIfAvailable tycon,
- not (con `elem` handled_data_cons)]
- -- There is just one missing constructor!
-
- = tick (FillInCaseDefault case_bndr) `thenSmpl_`
- getUniquesSmpl `thenSmpl` \ tv_uniqs ->
- getUniquesSmpl `thenSmpl` \ id_uniqs ->
- let
- (_,_,ex_tyvars,_,_,_) = dataConSig missing_con
- ex_tyvars' = zipWith mk tv_uniqs ex_tyvars
- mk uniq tv = mkSysTyVar uniq (tyVarKind tv)
- arg_ids = zipWith (mkSysLocal SLIT("a")) id_uniqs arg_tys
- arg_tys = dataConArgTys missing_con (inst_tys ++ mkTyVarTys ex_tyvars')
- better_alts = (DataAlt missing_con, ex_tyvars' ++ arg_ids, rhs) : alts_no_deflt
- in
- returnSmpl better_alts
+mkAlts scrut outer_bndr outer_alts
+ = getDOptsSmpl `thenSmpl` \dflags ->
+ mkAlts' dflags scrut outer_bndr outer_alts
where
- handled_data_cons = [data_con | DataAlt data_con <- handled_cons]
-
---------------------------------------------------
--- 3. Merge nested cases
---------------------------------------------------
-
-mkAlts scrut handled_cons outer_bndr outer_alts
- | opt_SimplCaseMerge,
- (outer_alts_without_deflt, maybe_outer_deflt) <- findDefault outer_alts,
- Just (Case (Var scrut_var) inner_bndr inner_alts) <- maybe_outer_deflt,
- scruting_same_var scrut_var
-
- = let -- Eliminate any inner alts which are shadowed by the outer ones
+ mkAlts' dflags scrut outer_bndr outer_alts
+ | dopt Opt_CaseMerge dflags,
+ (outer_alts_without_deflt, maybe_outer_deflt) <- findDefault outer_alts,
+-- gaw 2004
+ Just (Case (Var scrut_var) inner_bndr _ inner_alts) <- maybe_outer_deflt,
+ scruting_same_var scrut_var
+
+ = let -- Eliminate any inner alts which are shadowed by the outer ones
outer_cons = [con | (con,_,_) <- outer_alts_without_deflt]
munged_inner_alts = [ (con, args, munge_rhs rhs)
-- mkCase applied to them, so they won't have a case in their default
-- Secondly, if you do, you get an infinite loop, because the bindCaseBndr
-- in munge_rhs may put a case into the DEFAULT branch!
- where
+ where
-- We are scrutinising the same variable if it's
-- the outer case-binder, or if the outer case scrutinises a variable
-- (and it's the same). Testing both allows us not to replace the
-- outer scrut-var with the outer case-binder (Simplify.simplCaseBinder).
- scruting_same_var = case scrut of
+ scruting_same_var = case scrut of
Var outer_scrut -> \ v -> v == outer_bndr || v == outer_scrut
other -> \ v -> v == outer_bndr
- add_default (Just rhs) alts = (DEFAULT,[],rhs) : alts
- add_default Nothing alts = alts
+ add_default (Just rhs) alts = (DEFAULT,[],rhs) : alts
+ add_default Nothing alts = alts
--------------------------------------------------
-- Catch-all
--------------------------------------------------
-mkAlts scrut handled_cons case_bndr other_alts = returnSmpl other_alts
+ mkAlts' dflags scrut case_bndr other_alts = returnSmpl other_alts
\end{code}
If so, then we can replace the case with one of the rhss.
+Further notes about case elimination
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider: test :: Integer -> IO ()
+ test = print
+
+Turns out that this compiles to:
+ Print.test
+ = \ eta :: Integer
+ eta1 :: State# RealWorld ->
+ case PrelNum.< eta PrelNum.zeroInteger of wild { __DEFAULT ->
+ case hPutStr stdout
+ (PrelNum.jtos eta ($w[] @ Char))
+ eta1
+ of wild1 { (# new_s, a4 #) -> PrelIO.lvl23 new_s }}
+
+Notice the strange '<' which has no effect at all. This is a funny one.
+It started like this:
+
+f x y = if x < 0 then jtos x
+ else if y==0 then "" else jtos x
+
+At a particular call site we have (f v 1). So we inline to get
+
+ if v < 0 then jtos x
+ else if 1==0 then "" else jtos x
+
+Now simplify the 1==0 conditional:
+
+ if v<0 then jtos v else jtos v
+
+Now common-up the two branches of the case:
+
+ case (v<0) of DEFAULT -> jtos v
+
+Why don't we drop the case? Because it's strict in v. It's technically
+wrong to drop even unnecessary evaluations, and in practice they
+may be a result of 'seq' so we *definitely* don't want to drop those.
+I don't really know how to improve this situation.
+
\begin{code}
--------------------------------------------------
+-- 0. Check for empty alternatives
+--------------------------------------------------
+
+#ifdef DEBUG
+mkCase1 scrut case_bndr ty []
+ = pprTrace "mkCase1: null alts" (ppr case_bndr <+> ppr scrut) $
+ returnSmpl scrut
+#endif
+
+--------------------------------------------------
-- 1. Eliminate the case altogether if poss
--------------------------------------------------
-mkCase1 scrut case_bndr [(con,bndrs,rhs)]
+mkCase1 scrut case_bndr ty [(con,bndrs,rhs)]
-- See if we can get rid of the case altogether
-- See the extensive notes on case-elimination above
-- mkCase made sure that if all the alternatives are equal,
-- Here we must *not* discard the case, because dataToTag# just fetches the tag from
-- the info pointer. So we'll be pedantic all the time, and see if that gives any
-- other problems
+-- Also we don't want to discard 'seq's
= tick (CaseElim case_bndr) `thenSmpl_`
returnSmpl (bindCaseBndr case_bndr scrut rhs)
-- 2. Identity case
--------------------------------------------------
-mkCase1 scrut case_bndr alts -- Identity case
+mkCase1 scrut case_bndr ty alts -- Identity case
| all identity_alt alts
= tick (CaseIdentity case_bndr) `thenSmpl_`
returnSmpl (re_note scrut)
-- re_note wraps a coerce if it might be necessary
re_note scrut = case head alts of
- (_,_,rhs1@(Note _ _)) -> mkCoerce (exprType rhs1) (idType case_bndr) scrut
+ (_,_,rhs1@(Note _ _)) -> mkCoerce2 (exprType rhs1) (idType case_bndr) scrut
other -> scrut
--------------------------------------------------
-- Catch-all
--------------------------------------------------
-mkCase1 scrut bndr alts = returnSmpl (Case scrut bndr alts)
+-- gaw 2004
+mkCase1 scrut bndr ty alts = returnSmpl (Case scrut bndr ty alts)
\end{code}