[project @ 1998-03-19 17:44:26 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplCore / Simplify.lhs
index 80d425f..03c9495 100644 (file)
@@ -4,55 +4,46 @@
 \section[Simplify]{The main module of the simplifier}
 
 \begin{code}
-#include "HsVersions.h"
-
 module Simplify ( simplTopBinds, simplExpr, simplBind ) where
 
-IMPORT_1_3(List(partition))
-
-IMP_Ubiq(){-uitous-}
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
-IMPORT_DELOOPER(SmplLoop)              -- paranoia checking
-#endif
+#include "HsVersions.h"
 
 import BinderInfo
 import CmdLineOpts     ( SimplifierSwitch(..) )
 import ConFold         ( completePrim )
-import CoreUnfold      ( Unfolding, SimpleUnfolding, mkFormSummary, exprIsTrivial, whnfOrBottom, FormSummary(..) )
+import CoreUnfold      ( Unfolding, mkFormSummary, 
+                         exprIsTrivial, whnfOrBottom, inlineUnconditionally,
+                         FormSummary(..)
+                       )
 import CostCentre      ( isSccCountCostCentre, cmpCostCentre, costsAreSubsumed, useCurrentCostCentre )
 import CoreSyn
 import CoreUtils       ( coreExprType, nonErrorRHSs, maybeErrorApp,
                          unTagBinders, squashableDictishCcExpr
                        )
-import Id              ( idType, idWantsToBeINLINEd, idMustNotBeINLINEd, addIdArity, getIdArity,
-                         getIdDemandInfo, addIdDemandInfo,
-                         GenId{-instance NamedThing-}
+import Id              ( idType, idMustBeINLINEd, idWantsToBeINLINEd, idMustNotBeINLINEd, 
+                         addIdArity, getIdArity,
+                         getIdDemandInfo, addIdDemandInfo
                        )
-import Name            ( isExported )
+import Name            ( isExported, isLocallyDefined )
 import IdInfo          ( willBeDemanded, noDemandInfo, DemandInfo, ArityInfo(..),
                          atLeastArity, unknownArity )
 import Literal         ( isNoRepLit )
 import Maybes          ( maybeToBool )
-import PprType         ( GenType{-instance Outputable-}, GenTyVar{- instance Outputable -} )
-#if __GLASGOW_HASKELL__ <= 30
-import PprCore         ( GenCoreArg, GenCoreExpr )
-#endif
-import TyVar           ( GenTyVar {- instance Eq -} )
-import Pretty          --( ($$) )
 import PrimOp          ( primOpOkForSpeculation, PrimOp(..) )
 import SimplCase       ( simplCase, bindLargeRhs )
 import SimplEnv
 import SimplMonad
-import SimplVar                ( completeVar )
-import Unique          ( Unique )
+import SimplVar                ( completeVar, simplBinder, simplBinders, simplTyBinder, simplTyBinders )
 import SimplUtils
-import Type            ( mkTyVarTy, mkTyVarTys, mkAppTy, applyTy, mkFunTys,
-                         splitFunTy, splitFunTyExpandingDicts, getFunTy_maybe, eqTy
+import Type            ( mkTyVarTy, mkTyVarTys, mkAppTy, applyTy, applyTys,
+                         mkFunTys, splitAlgTyConApp_maybe,
+                         splitFunTys, splitFunTy_maybe, isUnpointedType
+                       )
+import TysPrim         ( realWorldStatePrimTy )
+import Util            ( Eager, appEager, returnEager, runEager, mapEager,
+                         isSingleton, zipEqual, zipWithEqual, mapAndUnzip
                        )
-import TysWiredIn      ( realWorldStateTy )
-import Outputable      ( PprStyle(..), Outputable(..) )
-import Util            ( SYN_IE(Eager), appEager, returnEager, runEager, mapEager,
-                         isSingleton, zipEqual, zipWithEqual, mapAndUnzip, panic, pprPanic, assertPanic, pprTrace )
+import Outputable      
 \end{code}
 
 The controlling flags, and what they do
@@ -203,8 +194,9 @@ simplTopBinds env binds
 
     simpl_top_binds env (NonRec binder@(in_id,occ_info) rhs : binds)
       =                --- No cloning necessary at top level
-        simplRhsExpr env binder rhs in_id                              `thenSmpl` \ (rhs',arity) ->
-        completeNonRec env binder (in_id `withArity` arity) rhs'       `thenSmpl` \ (new_env, binds1') ->
+        simplBinder env binder                                         `thenSmpl` \ (env1, out_id) ->
+        simplRhsExpr env binder rhs out_id                             `thenSmpl` \ (rhs',arity) ->
+        completeNonRec env1 binder (out_id `withArity` arity) rhs'     `thenSmpl` \ (new_env, binds1') ->
         simpl_top_binds new_env binds                                  `thenSmpl` \ binds2' ->
         returnSmpl (binds1' ++ binds2')
 
@@ -224,15 +216,10 @@ simplTopBinds env binds
                --
                -- Sure we could have made the indirection-shorting a bit cleverer, but
                -- propagating pragma info is a Good Idea anyway.
-       let
-           env1 = extendIdEnvWithClones env binders ids
-       in
-        simplRecursiveGroup env1 ids pairs     `thenSmpl` \ (bind', new_env) ->
+       simplBinders env (map fst pairs)        `thenSmpl` \ (env1, out_ids) ->
+        simplRecursiveGroup env1 out_ids pairs         `thenSmpl` \ (bind', new_env) ->
         simpl_top_binds new_env binds          `thenSmpl` \ binds' ->
         returnSmpl (Rec bind' : binds')
-      where
-       binders = map fst pairs
-        ids     = map fst binders
 \end{code}
 
 %************************************************************************
@@ -259,17 +246,21 @@ Check if there's a macro-expansion, and if so rattle on.  Otherwise do
 the more sophisticated stuff.
 
 \begin{code}
-simplExpr env (Var v) args result_ty
-  = case (runEager $ lookupId env v) of
-      LitArg lit               -- A boring old literal
+simplExpr env (Var var) args result_ty
+  = case lookupIdSubst env var of
+  
+      Just (SubstExpr ty_subst id_subst expr)
+       -> simplExpr (setSubstEnvs env (ty_subst, id_subst)) expr args result_ty
+
+      Just (SubstLit lit)              -- A boring old literal
        -> ASSERT( null args )
           returnSmpl (Lit lit)
 
-      VarArg var       -- More interesting!  An id!
-       -> completeVar env var args result_ty
-                               -- Either Id is in the local envt, or it's a global.
-                               -- In either case we don't need to apply the type
-                               -- environment to it.
+      Just (SubstVar var')             -- More interesting!  An id!
+       -> completeVar env var' args result_ty
+
+      Nothing  -- Not in the substitution; hand off to completeVar
+       -> completeVar env var args result_ty 
 \end{code}
 
 Literals
@@ -335,18 +326,15 @@ First the case when it's applied to an argument.
 
 \begin{code}
 simplExpr env (Lam (TyBinder tyvar) body) (TyArg ty : args) result_ty
-  = -- ASSERT(not (isPrimType ty))
-    tick TyBetaReduction       `thenSmpl_`
-    simplExpr (extendTyEnv env tyvar ty) body args result_ty
+  = tick TyBetaReduction       `thenSmpl_`
+    simplExpr (bindTyVar env tyvar ty) body args result_ty
 \end{code}
 
 \begin{code}
 simplExpr env tylam@(Lam (TyBinder tyvar) body) [] result_ty
-  = cloneTyVarSmpl tyvar               `thenSmpl` \ tyvar' ->
+  = simplTyBinder env tyvar    `thenSmpl` \ (new_env, tyvar') ->
     let
-       new_ty  = mkTyVarTy tyvar'
-       new_env = extendTyEnv env tyvar new_ty
-       new_result_ty = applyTy result_ty new_ty
+       new_result_ty = applyTy result_ty (mkTyVarTy tyvar')
     in
     simplExpr new_env body [] new_result_ty            `thenSmpl` \ body' ->
     returnSmpl (Lam (TyBinder tyvar') body')
@@ -379,14 +367,14 @@ simplExpr env expr@(Lam (ValBinder binder) body) orig_args result_ty
     go n env (Lam (ValBinder binder) body) (val_arg : args)
       | isValArg val_arg               -- The lambda has an argument
       = tick BetaReduction     `thenSmpl_`
-        go (n+1) (extendIdEnvWithAtom env binder val_arg) body args
+        go (n+1) (bindIdToAtom env binder val_arg) body args
 
     go n env expr@(Lam (ValBinder binder) body) args
        -- The lambda is un-saturated, so we must zap the occurrence info
        -- on the arguments we've already beta-reduced into the body of the lambda
       = ASSERT( null args )    -- Value lambda must match value argument!
         let
-           new_env = markDangerousOccs env (take n orig_args)
+           new_env = markDangerousOccs env orig_args
         in
         simplValLam new_env expr 0 {- Guaranteed applied to at least 0 args! -} result_ty 
                                `thenSmpl` \ (expr', arity) ->
@@ -410,7 +398,10 @@ Case expressions
 
 \begin{code}
 simplExpr env expr@(Case scrut alts) args result_ty
-  = simplCase env scrut alts (\env rhs -> simplExpr env rhs args result_ty) result_ty
+  = simplCase env scrut
+             (getSubstEnvs env, alts)
+             (\env rhs -> simplExpr env rhs args result_ty)
+             result_ty
 \end{code}
 
 
@@ -430,7 +421,7 @@ We must be careful to maintain the scc counts ...
 
 \begin{code}
 simplExpr env (SCC cc1 (SCC cc2 expr)) args result_ty
-  | not (isSccCountCostCentre cc2) && case cmpCostCentre cc1 cc2 of { EQ_ -> True; _ -> False }
+  | not (isSccCountCostCentre cc2) && case cmpCostCentre cc1 cc2 of { EQ -> True; _ -> False }
        -- eliminate inner scc if no call counts and same cc as outer
   = simplExpr env (SCC cc1 expr) args result_ty
 
@@ -499,36 +490,22 @@ simplRhsExpr
        -> InExpr
        -> OutId                -- The new binder (used only for its type)
        -> SmplM (OutExpr, ArityInfo)
+\end{code}
 
--- First a special case for variable right-hand sides
---     v = w
--- It's OK to simplify the RHS, but it's often a waste of time.  Often
--- these v = w things persist because v is exported, and w is used 
--- elsewhere.  So if we're not careful we'll eta expand the rhs, only
--- to eta reduce it in competeNonRec.
---
--- If we leave the binding unchanged, we will certainly replace v by w at 
--- every occurrence of v, which is good enough.  
---
--- In fact, it's better to replace v by w than to inline w in v's rhs,
--- even if this is the only occurrence of w.  Why? Because w might have
--- IdInfo (like strictness) that v doesn't.
-
-simplRhsExpr env binder@(id,occ_info) (Var v) new_id
- = case (runEager $ lookupId env v) of
-      LitArg lit -> returnSmpl (Lit lit, ArityExactly 0)
-      VarArg v'         -> returnSmpl (Var v', getIdArity v')
 
+\begin{code}
 simplRhsExpr env binder@(id,occ_info) rhs new_id
-  =    -- Deal with the big lambda part
-    ASSERT( null uvars )       -- For now
+  | maybeToBool (splitAlgTyConApp_maybe rhs_ty)
+       -- Deal with the data type case, in which case the elaborate
+       -- eta-expansion nonsense is really quite a waste of time.
+  = simplExpr rhs_env rhs [] rhs_ty            `thenSmpl` \ rhs' ->
+    returnSmpl (rhs', ArityExactly 0)
 
-    mapSmpl cloneTyVarSmpl tyvars                      `thenSmpl` \ tyvars' ->
+  | otherwise  -- OK, use the big hammer
+  =    -- Deal with the big lambda part
+    simplTyBinders rhs_env tyvars                      `thenSmpl` \ (lam_env, tyvars') ->
     let
-       rhs_ty   = idType new_id
-       new_tys  = mkTyVarTys tyvars'
-       body_ty  = foldl applyTy rhs_ty new_tys
-       lam_env  = extendTyEnvList rhs_env (zipEqual "simplRhsExpr" tyvars new_tys)
+       body_ty  = applyTys rhs_ty (mkTyVarTys tyvars')
     in
        -- Deal with the little lambda part
        -- Note that we call simplLam even if there are no binders,
@@ -540,6 +517,7 @@ simplRhsExpr env binder@(id,occ_info) rhs new_id
 
     returnSmpl (rhs', arity)
   where
+    rhs_ty  = idType new_id
     rhs_env | idWantsToBeINLINEd id    -- Don't ever inline in a INLINE thing's rhs
            = switchOffInlining env1    -- See comments with switchOffInlining
            | otherwise 
@@ -556,10 +534,78 @@ simplRhsExpr env binder@(id,occ_info) rhs new_id
     env1 | costsAreSubsumed current_cc = setEnclosingCC env useCurrentCostCentre
         | otherwise                   = env
 
-    (uvars, tyvars, body) = collectUsageAndTyBinders rhs
+    (tyvars, body) = collectTyBinders rhs
 \end{code}
 
 
+----------------------------------------------------------------
+       An old special case that is now nuked.
+
+First a special case for variable right-hand sides
+       v = w
+It's OK to simplify the RHS, but it's often a waste of time.  Often
+these v = w things persist because v is exported, and w is used 
+elsewhere.  So if we're not careful we'll eta expand the rhs, only
+to eta reduce it in competeNonRec.
+
+If we leave the binding unchanged, we will certainly replace v by w at 
+every occurrence of v, which is good enough.  
+
+In fact, it's *better* to replace v by w than to inline w in v's rhs,
+even if this is the only occurrence of w.  Why? Because w might have
+IdInfo (such as strictness) that v doesn't.
+
+Furthermore, there might be other uses of w; if so, inlining w in 
+v's rhs will duplicate w's rhs, whereas replacing v by w doesn't.
+
+HOWEVER, we have to be careful if w is something that *must* be
+inlined.  In particular, its binding may have been dropped.  Here's
+an example that actually happened:
+       let x = let y = e in y
+     in f x
+The "let y" was floated out, and then (since y occurs once in a
+definitely inlinable position) the binding was dropped, leaving
+       {y=e} let x = y in f x
+But now using the reasoning of this little section, 
+y wasn't inlined, because it was a let x=y form.
+
+
+               HOWEVER
+
+This "optimisation" turned out to be a bad idea.  If there's are
+top-level exported bindings like
+
+       y = I# 3#
+       x = y
+
+then y wasn't getting inlined in x's rhs, and we were getting
+bad code.  So I've removed the special case from here, and
+instead we only try eta reduction and constructor reuse 
+in completeNonRec if the thing is *not* exported.
+
+
+\begin{pseudocode}
+simplRhsExpr env binder@(id,occ_info) (Var v) new_id
+ | maybeToBool maybe_stop_at_var
+ = returnSmpl (Var the_var, getIdArity the_var)
+ where
+   maybe_stop_at_var 
+     = case (runEager $ lookupId env v) of
+        VarArg v' | not (must_unfold v') -> Just v'
+        other                            -> Nothing
+
+   Just the_var = maybe_stop_at_var
+
+   must_unfold v' =  idMustBeINLINEd v'
+                 || case lookupOutIdEnv env v' of
+                       Just (_, _, InUnfolding _ _) -> True
+                       other                        -> False
+\end{pseudocode}
+       
+               End of old, nuked, special case.
+------------------------------------------------------------------
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{Simplify a lambda abstraction}
@@ -585,28 +631,22 @@ simplValLam env expr min_no_of_args expr_ty
 
     null potential_extra_binder_tys                ||  -- or ain't a function
     no_of_extra_binders <= 0                           -- or no extra binders needed
-  = cloneIds env binders               `thenSmpl` \ binders' ->
-    let
-       new_env = extendIdEnvWithClones env binders binders'
-    in
-    simplExpr new_env body [] body_ty          `thenSmpl` \ body' ->
+  = simplBinders env binders           `thenSmpl` \ (new_env, binders') ->
+    simplExpr new_env body [] body_ty  `thenSmpl` \ body' ->
     returnSmpl (mkValLam binders' body', final_arity)
 
   | otherwise                          -- Eta expansion possible
   = -- A SSERT( no_of_extra_binders <= length potential_extra_binder_tys )
     (if not ( no_of_extra_binders <= length potential_extra_binder_tys ) then
-       pprTrace "simplValLam" (vcat [ppr PprDebug expr, 
-                                         ppr PprDebug expr_ty,
-                                         ppr PprDebug binders,
+       pprTrace "simplValLam" (vcat [ppr expr, 
+                                         ppr expr_ty,
+                                         ppr binders,
                                          int no_of_extra_binders,
-                                         ppr PprDebug potential_extra_binder_tys])
+                                         ppr potential_extra_binder_tys])
     else \x -> x) $
 
     tick EtaExpansion                  `thenSmpl_`
-    cloneIds env binders               `thenSmpl` \ binders' ->
-    let
-       new_env = extendIdEnvWithClones env binders binders'
-    in
+    simplBinders env binders           `thenSmpl` \ (new_env, binders') ->
     newIds extra_binder_tys                                            `thenSmpl` \ extra_binders' ->
     simplExpr new_env body (map VarArg extra_binders') etad_body_ty    `thenSmpl` \ body' ->
     returnSmpl (
@@ -617,11 +657,11 @@ simplValLam env expr min_no_of_args expr_ty
   where
     (binders,body)            = collectValBinders expr
     no_of_binders             = length binders
-    (arg_tys, res_ty)         = splitFunTyExpandingDicts expr_ty
+    (arg_tys, res_ty)         = splitFunTys expr_ty
     potential_extra_binder_tys = (if not (no_of_binders <= length arg_tys) then
-                                       pprTrace "simplValLam" (vcat [ppr PprDebug expr, 
-                                                                         ppr PprDebug expr_ty,
-                                                                         ppr PprDebug binders])
+                                       pprTrace "simplValLam" (vcat [ppr expr, 
+                                                                         ppr expr_ty,
+                                                                         ppr binders])
                                  else \x->x) $
                                 drop no_of_binders arg_tys
     body_ty                   = mkFunTys potential_extra_binder_tys res_ty
@@ -657,7 +697,7 @@ simplValLam env expr min_no_of_args expr_ty
                                -- but usually doesn't
                           `max`
                           case potential_extra_binder_tys of
-                               [ty] | ty `eqTy` realWorldStateTy -> 1
+                               [ty] | ty == realWorldStatePrimTy -> 1
                                other                             -> 0
 \end{code}
 
@@ -672,7 +712,9 @@ simplValLam env expr min_no_of_args expr_ty
 \begin{code}
 -- (coerce (case s of p -> r)) args ==> case s of p -> (coerce r) args
 simplCoerce env coercion ty expr@(Case scrut alts) args result_ty
-  = simplCase env scrut alts (\env rhs -> simplCoerce env coercion ty rhs args result_ty) result_ty
+  = simplCase env scrut (getSubstEnvs env, alts)
+             (\env rhs -> simplCoerce env coercion ty rhs args result_ty)
+             result_ty
 
 -- (coerce (let defns in b)) args  ==> let defns' in (coerce b) args
 simplCoerce env coercion ty (Let bind body) args result_ty
@@ -696,7 +738,7 @@ simplCoerce env coercion ty expr args result_ty
 
 %************************************************************************
 %*                                                                     *
-\subsection[Simplify-let]{Let-expressions}
+\subsection[Simplify-bind]{Binding groups}
 %*                                                                     *
 %************************************************************************
 
@@ -706,8 +748,35 @@ simplBind :: SimplEnv
          -> (SimplEnv -> SmplM OutExpr)
          -> OutType
          -> SmplM OutExpr
+
+simplBind env (NonRec binder rhs) body_c body_ty = simplNonRec env binder rhs body_c body_ty
+simplBind env (Rec pairs)         body_c body_ty = simplRec    env pairs      body_c body_ty
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+\subsection[Simplify-let]{Let-expressions}
+%*                                                                     *
+%************************************************************************
+
+Float switches
+~~~~~~~~~~~~~~
+The booleans controlling floating have to be set with a little care.
+Here's one performance bug I found:
+
+       let x = let y = let z = case a# +# 1 of {b# -> E1}
+                       in E2
+               in E3
+       in E4
+
+Now, if E2, E3 aren't HNFs we won't float the y-binding or the z-binding.
+Before case_floating_ok included float_exposes_hnf, the case expression was floated
+*one level per simplifier iteration* outwards.  So it made th s
+
+
+Floating case from let
+~~~~~~~~~~~~~~~~~~~~~~
 When floating cases out of lets, remember this:
 
        let x* = case e of alts
@@ -747,120 +816,6 @@ achieving the same effect.
 ToDo: check this is OK with andy
 
 
-
-\begin{code}
--- Dead code is now discarded by the occurrence analyser,
-
-simplBind env (NonRec binder@(id,occ_info) rhs) body_c body_ty
-  | idWantsToBeINLINEd id
-  = complete_bind env rhs      -- Don't mess about with floating or let-to-case on
-                               -- INLINE things
-  | otherwise
-  = simpl_bind env rhs
-  where
-    -- Try let-to-case; see notes below about let-to-case
-    simpl_bind env rhs | try_let_to_case &&
-                        will_be_demanded &&
-                        (rhs_is_bot ||
-                         not rhs_is_whnf &&
-                         singleConstructorType rhs_ty
-                               -- Only do let-to-case for single constructor types. 
-                               -- For other types we defer doing it until the tidy-up phase at
-                               -- the end of simplification.
-                        )
-      = tick Let2Case                          `thenSmpl_`
-        simplCase env rhs (AlgAlts [] (BindDefault binder (Var id)))
-                         (\env rhs -> complete_bind env rhs) body_ty
-               -- OLD COMMENT:  [now the new RHS is only "x" so there's less worry]
-               -- NB: it's tidier to call complete_bind not simpl_bind, else
-               -- we nearly end up in a loop.  Consider:
-               --      let x = rhs in b
-               -- ==>  case rhs of (p,q) -> let x=(p,q) in b
-               -- This effectively what the above simplCase call does.
-               -- Now, the inner let is a let-to-case target again!  Actually, since
-               -- the RHS is in WHNF it won't happen, but it's a close thing!
-
-    -- Try let-from-let
-    simpl_bind env (Let bind rhs) | let_floating_ok
-      = tick LetFloatFromLet                    `thenSmpl_`
-       simplBind env (fix_up_demandedness will_be_demanded bind)
-                     (\env -> simpl_bind env rhs) body_ty
-
-    -- Try case-from-let; this deals with a strict let of error too
-    simpl_bind env (Case scrut alts) | case_floating_ok scrut
-      = tick CaseFloatFromLet                          `thenSmpl_`
-
-       -- First, bind large let-body if necessary
-       if ok_to_dup || isSingleton (nonErrorRHSs alts)
-       then
-           simplCase env scrut alts (\env rhs -> simpl_bind env rhs) body_ty
-       else
-           bindLargeRhs env [binder] body_ty body_c    `thenSmpl` \ (extra_binding, new_body) ->
-           let
-               body_c' = \env -> simplExpr env new_body [] body_ty
-               case_c  = \env rhs -> simplBind env (NonRec binder rhs) body_c' body_ty
-           in
-           simplCase env scrut alts case_c body_ty     `thenSmpl` \ case_expr ->
-           returnSmpl (Let extra_binding case_expr)
-
-    -- None of the above; simplify rhs and tidy up
-    simpl_bind env rhs = complete_bind env rhs
-    complete_bind env rhs
-      = cloneId env binder                     `thenSmpl` \ new_id ->
-       simplRhsExpr env binder rhs new_id      `thenSmpl` \ (rhs',arity) ->
-       completeNonRec env binder 
-               (new_id `withArity` arity) rhs' `thenSmpl` \ (new_env, binds) ->
-        body_c new_env                         `thenSmpl` \ body' ->
-        returnSmpl (mkCoLetsAny binds body')
-
-
-       -- All this stuff is computed at the start of the simpl_bind loop
-    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
-    float_primops            = switchIsSet env SimplOkToFloatPrimOps
-    ok_to_dup                = switchIsSet env SimplOkToDupCode
-    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
-    try_let_to_case           = switchIsSet env SimplLetToCase
-    no_float                 = switchIsSet env SimplNoLetFromStrictLet
-
-    demand_info             = getIdDemandInfo id
-    will_be_demanded = willBeDemanded demand_info
-    rhs_ty          = idType id
-
-    form       = mkFormSummary rhs
-    rhs_is_bot  = case form of
-                       BottomForm -> True
-                       other      -> False
-    rhs_is_whnf = case form of
-                       VarForm -> True
-                       ValueForm -> True
-                       other -> False
-
-    float_exposes_hnf = floatExposesHNF float_lets float_primops ok_to_dup rhs
-
-    let_floating_ok  = (will_be_demanded && not no_float) ||
-                      always_float_let_from_let ||
-                      float_exposes_hnf
-
-    case_floating_ok scrut = (will_be_demanded && not no_float) || 
-                            (float_exposes_hnf && is_cheap_prim_app scrut && float_primops)
-       -- See note below 
-\end{code}
-
-Float switches
-~~~~~~~~~~~~~~
-The booleans controlling floating have to be set with a little care.
-Here's one performance bug I found:
-
-       let x = let y = let z = case a# +# 1 of {b# -> E1}
-                       in E2
-               in E3
-       in E4
-
-Now, if E2, E3 aren't HNFs we won't float the y-binding or the z-binding.
-Before case_floating_ok included float_exposes_hnf, the case expression was floated
-*one level per simplifier iteration* outwards.  So it made th s
-
 Let to case: two points
 ~~~~~~~~~~~
 
@@ -935,142 +890,200 @@ Notice that let to case occurs only if x is used strictly in its body
 (obviously).
 
 
-Letrec expressions
-~~~~~~~~~~~~~~~~~~
-
-Simplify each RHS, float any let(recs) from the RHSs (if let-floating is
-on and it'll expose a HNF), and bang the whole resulting mess together
-into a huge letrec.
+\begin{code}
+-- Dead code is now discarded by the occurrence analyser,
 
-1. Any "macros" should be expanded.  The main application of this
-macro-expansion is:
+simplNonRec env binder@(id,_) rhs body_c body_ty
+  | inlineUnconditionally ok_to_dup binder
+  =    -- The binder is used in definitely-inline way in the body
+       -- So add it to the environment, drop the binding, and continue
+    body_c (bindIdToExpr env binder rhs)
 
-       letrec
-               f = ....g...
-               g = ....f...
-       in
-       ....f...
+  | idWantsToBeINLINEd id
+  = complete_bind env rhs      -- Don't mess about with floating or let-to-case on
+                               -- INLINE things
 
-Here we would like the single call to g to be inlined.
+       -- Do let-to-case right away for unpointed types
+       -- These shouldn't occur much, but do occur right after desugaring,
+       -- because we havn't done dependency analysis at that point, so
+       -- we can't trivially do let-to-case (because there may be some unboxed
+       -- things bound in letrecs that aren't really recursive).
+  | isUnpointedType rhs_ty && not rhs_is_whnf
+  = simplCase env rhs (getSubstEnvs env, PrimAlts [] (BindDefault binder (Var id)))
+                     (\env rhs -> complete_bind env rhs) body_ty
+
+       -- Try let-to-case; see notes below about let-to-case
+  | try_let_to_case &&
+    will_be_demanded &&
+    (  rhs_is_bot
+    || (not rhs_is_whnf && singleConstructorType rhs_ty)
+               -- Don't do let-to-case if the RHS is a constructor application.
+               -- Even then only do it for single constructor types. 
+               -- For other types we defer doing it until the tidy-up phase at
+               -- the end of simplification.
+    )
+  = tick Let2Case                              `thenSmpl_`
+    simplCase env rhs (getSubstEnvs env, AlgAlts [] (BindDefault binder (Var id)))
+                     (\env rhs -> complete_bind env rhs) body_ty
+               -- OLD COMMENT:  [now the new RHS is only "x" so there's less worry]
+               -- NB: it's tidier to call complete_bind not simpl_bind, else
+               -- we nearly end up in a loop.  Consider:
+               --      let x = rhs in b
+               -- ==>  case rhs of (p,q) -> let x=(p,q) in b
+               -- This effectively what the above simplCase call does.
+               -- Now, the inner let is a let-to-case target again!  Actually, since
+               -- the RHS is in WHNF it won't happen, but it's a close thing!
 
-We can spot this easily, because g will be tagged as having just one
-occurrence.  The "inlineUnconditionally" predicate is just what we want.
+  | otherwise
+  = simpl_bind env rhs
+  where
+    -- Try let-from-let
+    simpl_bind env (Let bind rhs) | let_floating_ok
+      = tick LetFloatFromLet                    `thenSmpl_`
+       simplBind env (if will_be_demanded then bind 
+                                          else un_demandify_bind bind)
+                     (\env -> simpl_bind env rhs) body_ty
 
-A worry: could this lead to non-termination?  For example:
+    -- Try case-from-let; this deals with a strict let of error too
+    simpl_bind env (Case scrut alts) | case_floating_ok scrut
+      = tick CaseFloatFromLet                          `thenSmpl_`
 
-       letrec
-               f = ...g...
-               g = ...f...
-               h = ...h...
-       in
-       ..h..
+       -- First, bind large let-body if necessary
+       if ok_to_dup || isSingleton (nonErrorRHSs alts)
+       then
+           simplCase env scrut (getSubstEnvs env, alts) 
+                     (\env rhs -> simpl_bind env rhs) body_ty
+       else
+           bindLargeRhs env [binder] body_ty body_c    `thenSmpl` \ (extra_binding, new_body) ->
+           let
+               body_c' = \env -> simplExpr env new_body [] body_ty
+               case_c  = \env rhs -> simplNonRec env binder rhs body_c' body_ty
+           in
+           simplCase env scrut (getSubstEnvs env, alts) case_c body_ty `thenSmpl` \ case_expr ->
+           returnSmpl (Let extra_binding case_expr)
 
-Here, f and g call each other (just once) and neither is used elsewhere.
-But it's OK:
+    -- None of the above; simplify rhs and tidy up
+    simpl_bind env rhs = complete_bind env rhs
+    complete_bind env rhs
+      = simplBinder env binder                 `thenSmpl` \ (env_w_clone, new_id) ->
+       simplRhsExpr env binder rhs new_id      `thenSmpl` \ (rhs',arity) ->
+       completeNonRec env_w_clone binder 
+               (new_id `withArity` arity) rhs' `thenSmpl` \ (new_env, binds) ->
+        body_c new_env                         `thenSmpl` \ body' ->
+        returnSmpl (mkCoLetsAny binds body')
 
-* the occurrence analyser will drop any (sub)-group that isn't used at
-  all.
 
-* If the group is used outside itself (ie in the "in" part), then there
-  can't be a cyle.
+       -- All this stuff is computed at the start of the simpl_bind loop
+    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
+    float_primops            = switchIsSet env SimplOkToFloatPrimOps
+    ok_to_dup                = switchIsSet env SimplOkToDupCode
+    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
+    try_let_to_case           = switchIsSet env SimplLetToCase
+    no_float                 = switchIsSet env SimplNoLetFromStrictLet
 
-** IMPORTANT: check that NewOccAnal has the property that a group of
-   bindings like the above has f&g dropped.! ***
+    demand_info             = getIdDemandInfo id
+    will_be_demanded = willBeDemanded demand_info
+    rhs_ty          = idType id
 
+    form       = mkFormSummary rhs
+    rhs_is_bot  = case form of
+                       BottomForm -> True
+                       other      -> False
+    rhs_is_whnf = case form of
+                       VarForm -> True
+                       ValueForm -> True
+                       other -> False
 
-2. We'd also like to pull out any top-level let(rec)s from the
-rhs of the defns:
+    float_exposes_hnf = floatExposesHNF float_lets float_primops ok_to_dup rhs
 
-       letrec
-               f = let h = ... in \x -> ....h...f...h...
-       in
-       ...f...
-====>
-       letrec
-               h = ...
-               f = \x -> ....h...f...h...
-       in
-       ...f...
+    let_floating_ok  = (will_be_demanded && not no_float) ||
+                      always_float_let_from_let ||
+                      float_exposes_hnf
 
-But floating cases is less easy?  (Don't for now; ToDo?)
+    case_floating_ok scrut = (will_be_demanded && not no_float) || 
+                            (float_exposes_hnf && is_cheap_prim_app scrut && float_primops)
+       -- See note below 
+\end{code}
 
 
-3.  We'd like to arrange that the RHSs "know" about members of the
-group that are bound to constructors.  For example:
+@completeNonRec@ looks at the simplified post-floating RHS of the
+let-expression, with a view to turning
+       x = e
+into
+       x = y
+where y is just a variable.  Now we can eliminate the binding
+altogether, and replace x by y throughout.
 
-    let rec
-       d.Eq      = (==,/=)
-       f a b c d = case d.Eq of (h,_) -> let x = (a,b); y = (c,d) in not (h x y)
-       /= a b    = unpack tuple a, unpack tuple b, call f
-    in d.Eq
+There are two cases when we can do this:
 
-here, by knowing about d.Eq in f's rhs, one could get rid of
-the case (and break out the recursion completely).
-[This occurred with more aggressive inlining threshold (4),
-nofib/spectral/knights]
+       * When e is a constructor application, and we have
+         another variable in scope bound to the same
+         constructor application.  [This is just a special
+         case of common-subexpression elimination.]
 
-How to do it?
-       1: we simplify constructor rhss first.
-       2: we record the "known constructors" in the environment
-       3: we simplify the other rhss, with the knowledge about the constructors
+       * When e can be eta-reduced to a variable.  E.g.
+               x = \a b -> y a b
 
 
+HOWEVER, if x is exported, we don't attempt this at all.  Why not?
+Because then we can't remove the x=y binding, in which case we 
+have just made things worse, perhaps a lot worse.
 
 \begin{code}
-simplBind env (Rec pairs) body_c body_ty
-  =    -- Do floating, if necessary
-    floatBind env False (Rec pairs)    `thenSmpl` \ [Rec pairs'] ->
-    let
-       binders = map fst pairs'
-    in
-    cloneIds env binders                       `thenSmpl` \ ids' ->
-    let
-       env_w_clones = extendIdEnvWithClones env binders ids'
-    in
-    simplRecursiveGroup env_w_clones ids' pairs'       `thenSmpl` \ (pairs', new_env) ->
+completeNonRec env binder new_id new_rhs
+  = returnSmpl (env', [NonRec b r | (b,r) <- binds])
+  where
+    (env', binds) = completeBind env binder new_id new_rhs
 
-    body_c new_env                             `thenSmpl` \ body' ->
 
-    returnSmpl (Let (Rec pairs') body')
-\end{code}
+completeBind :: SimplEnv 
+            -> InBinder -> OutId -> OutExpr            -- Id and RHS
+            -> (SimplEnv, [(OutId, OutExpr)])          -- Final envt and binding(s)
 
-\begin{code}
--- The env passed to simplRecursiveGroup already has 
--- bindings that clone the variables of the group.
-simplRecursiveGroup env new_ids []
-  = returnSmpl ([], env)
+completeBind env binder@(_,occ_info) new_id new_rhs
+  | idMustNotBeINLINEd new_id          -- Occurrence analyser says "don't inline"
+  = (env, new_binds)
 
-simplRecursiveGroup env (new_id : new_ids) ((binder@(_, occ_info), rhs) : pairs)
-  = simplRhsExpr env binder rhs new_id         `thenSmpl` \ (new_rhs, arity) ->
+  |  atomic_rhs                        -- If rhs (after eta reduction) is atomic
+  && not (isExported new_id)   -- and binder isn't exported
+  =    -- Drop the binding completely
     let
-       new_id' = new_id `withArity` arity
-    
-       -- ToDo: this next bit could usefully share code with completeNonRec
-
-        new_env 
-         | idMustNotBeINLINEd new_id           -- Occurrence analyser says "don't inline"
-         = env
+        env1 = notInScope env new_id
+       env2 = bindIdToAtom env1 binder the_arg
+    in
+    (env2, [])
 
-         | is_atomic eta'd_rhs                 -- If rhs (after eta reduction) is atomic
-         = extendIdEnvWithAtom env binder the_arg
+  |  atomic_rhs                -- Rhs is atomic, and new_id is exported
+  && case eta'd_rhs of { Var v -> isLocallyDefined v && not (isExported v); other -> False }
+  =    -- The local variable v will be eliminated next time round
+       -- in favour of new_id, so it's a waste to replace all new_id's with v's
+       -- this time round.
+       -- This case is an optional improvement; saves a simplifier iteration
+    (env, [(new_id, eta'd_rhs)])
 
-         | otherwise                           -- Non-atomic
-         = extendEnvGivenBinding env occ_info new_id new_rhs
-                                               -- Don't eta if it doesn't eliminate the binding
+  | otherwise                          -- Non-atomic
+  = let
+       env1 = extendEnvGivenBinding env occ_info new_id new_rhs
+    in 
+    (env1, new_binds)
+            
+  where
+    new_binds  = [(new_id, new_rhs)]
+    atomic_rhs = is_atomic eta'd_rhs
+    eta'd_rhs  = case lookForConstructor env new_rhs of 
+                  Just v -> Var v
+                  other  -> etaCoreExpr new_rhs
 
-        eta'd_rhs = etaCoreExpr new_rhs
-        the_arg   = case eta'd_rhs of
+    the_arg    = case eta'd_rhs of
                          Var v -> VarArg v
                          Lit l -> LitArg l
-    in
-    simplRecursiveGroup new_env new_ids pairs  `thenSmpl` \ (new_pairs, final_env) ->
-    returnSmpl ((new_id', new_rhs) : new_pairs, final_env)   
 \end{code}
 
+----------------------------------------------------------------------------
+       A digression on constructor CSE
 
-@completeLet@ looks at the simplified post-floating RHS of the
-let-expression, and decides what to do.  There's one interesting
-aspect to this, namely constructor reuse.  Consider
+Consider
 @
        f = \x -> case x of
                    (y:ys) -> y:ys
@@ -1105,12 +1118,14 @@ variable) when we find a let-expression:
        ... (let y = C a1 .. an in ...) ...
 @
 where it is always good to ditch the binding for y, and replace y by
-x.  That's just what completeLetBinding does.
+x.
+               End of digression
+----------------------------------------------------------------------------
 
+----------------------------------------------------------------------------
+               A digression on "optimising" coercions
 
-\begin{code}
-{- FAILED CODE
-   The trouble is that we keep transforming
+   The trouble is that we kept transforming
                let x = coerce e
                    y = coerce x
                in ...
@@ -1119,7 +1134,7 @@ x.  That's just what completeLetBinding does.
                    y' = coerce x'
                in ...
    and counting a couple of ticks for this non-transformation
-
+\begin{pseudocode}
        -- We want to ensure that all let-bound Coerces have 
        -- atomic bodies, so they can freely be inlined.
 completeNonRec env binder new_id (Coerce coercion ty rhs)
@@ -1138,51 +1153,82 @@ completeNonRec env binder new_id (Coerce coercion ty rhs)
                   (Coerce coercion ty atomic_rhs)      `thenSmpl` \ (env2, binds2) ->
 
     returnSmpl (env2, binds1 ++ binds2)
--}
-
-
-       -- Right hand sides that are constructors
-       --      let v = C args
-       --      in
-       --- ...(let w = C same-args in ...)...
-       -- Then use v instead of w.      This may save
-       -- re-constructing an existing constructor.
-completeNonRec env binder new_id rhs@(Con con con_args)
-  | switchIsSet env SimplReuseCon && 
-    maybeToBool maybe_existing_con &&
-    not (isExported new_id)            -- Don't bother for exported things
-                                       -- because we won't be able to drop
-                                       -- its binding.
-  = tick ConReused             `thenSmpl_`
-    returnSmpl (extendIdEnvWithAtom env binder (VarArg it), [NonRec new_id rhs])
-  where
-    maybe_existing_con = lookForConstructor env con con_args
-    Just it           = maybe_existing_con
+\end{pseudocode}
+----------------------------------------------------------------------------
 
 
-       -- Default case
-       -- Check for atomic right-hand sides.
-       -- We used to have a "tick AtomicRhs" in here, but it causes more trouble
-       -- than it's worth.  For a top-level binding a = b, where a is exported,
-       -- we can't drop the binding, so we get repeated AtomicRhs ticks
-completeNonRec env binder@(id,occ_info) new_id new_rhs
- | is_atomic eta'd_rhs                 -- If rhs (after eta reduction) is atomic
- = returnSmpl (atomic_env , [NonRec new_id eta'd_rhs])
 
- | otherwise                   -- Non atomic rhs (don't eta after all)
- = returnSmpl (non_atomic_env , [NonRec new_id new_rhs])
- where
-   atomic_env = extendIdEnvWithAtom env binder the_arg
+%************************************************************************
+%*                                                                     *
+\subsection[Simplify-letrec]{Letrec-expressions}
+%*                                                                     *
+%************************************************************************
 
-   non_atomic_env = extendEnvGivenBinding (extendIdEnvWithClone env binder new_id)
-                                         occ_info new_id new_rhs
+Letrec expressions
+~~~~~~~~~~~~~~~~~~
+Here's the game plan
+
+1. Float any let(rec)s out of the RHSs
+2. Clone all the Ids and extend the envt with these clones
+3. Simplify one binding at a time, adding each binding to the
+   environment once it's done.
+
+This relies on the occurrence analyser to
+       a) break all cycles with an Id marked MustNotBeInlined
+       b) sort the decls into topological order
+The former prevents infinite inlinings, and the latter means
+that we get maximum benefit from working top to bottom.
 
-   eta'd_rhs = etaCoreExpr new_rhs
-   the_arg   = case eta'd_rhs of
-                 Var v -> VarArg v
-                 Lit l -> LitArg l
+
+\begin{code}
+simplRec env pairs body_c body_ty
+  =    -- Do floating, if necessary
+    floatBind env False (Rec pairs)    `thenSmpl` \ [Rec pairs'] ->
+    let
+       binders = map fst pairs'
+    in
+    simplBinders env binders                           `thenSmpl` \ (env_w_clones, ids') ->
+    simplRecursiveGroup env_w_clones ids' pairs'       `thenSmpl` \ (pairs', new_env) ->
+
+    body_c new_env                                     `thenSmpl` \ body' ->
+
+    returnSmpl (Let (Rec pairs') body')
 \end{code}
 
+\begin{code}
+-- The env passed to simplRecursiveGroup already has 
+-- bindings that clone the variables of the group.
+simplRecursiveGroup env new_ids []
+  = returnSmpl ([], env)
+
+simplRecursiveGroup env (new_id : new_ids) ((binder, rhs) : pairs)
+  | inlineUnconditionally ok_to_dup binder
+  =    -- Single occurrence, so drop binding and extend env with the inlining
+       -- This is a little delicate, because what if the unique occurrence
+       -- is *before* this binding?  This'll never happen, because
+       -- either it'll be marked "never inline" or else its occurrence will
+       -- occur after its binding in the group.
+       --
+       -- If these claims aren't right Core Lint will spot an unbound
+       -- variable.  A quick fix is to delete this clause for simplRecursiveGroup
+    let
+       new_env = bindIdToExpr env binder rhs
+    in
+    simplRecursiveGroup new_env new_ids pairs
+
+  | otherwise
+  = simplRhsExpr env binder rhs new_id         `thenSmpl` \ (new_rhs, arity) ->
+    let
+       new_id'   = new_id `withArity` arity
+        (new_env, new_binds') = completeBind env binder new_id' new_rhs
+    in
+    simplRecursiveGroup new_env new_ids pairs  `thenSmpl` \ (new_pairs, final_env) ->
+    returnSmpl (new_binds' ++ new_pairs, final_env)   
+  where
+    ok_to_dup = switchIsSet env SimplOkToDupCode
+\end{code}
+
+
 
 \begin{code}
 floatBind :: SimplEnv
@@ -1214,7 +1260,8 @@ floatBind env top_level bind
     returnSmpl binds'
 
   where
-    (binds', _, n_extras) = fltBind bind       
+    binds'   = fltBind bind
+    n_extras = sum (map no_of_binds binds') - no_of_binds bind 
 
     float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
     always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
@@ -1222,27 +1269,22 @@ floatBind env top_level bind
        -- fltBind guarantees not to return leaky floats
        -- and all the binders of the floats have had their demand-info zapped
     fltBind (NonRec bndr rhs)
-      = (binds ++ [NonRec (un_demandify bndr) rhs'], 
-        leakFree bndr rhs', 
-        length binds)
+      = binds ++ [NonRec bndr rhs'] 
       where
         (binds, rhs') = fltRhs rhs
     
     fltBind (Rec pairs)
-      = ([Rec (extras
-              ++
-              binders `zip` rhss')],
-         and (zipWith leakFree binders rhss'),
-        length extras
-        )
-    
+      = [Rec pairs']
       where
-        (binders, rhss)  = unzip pairs
-        (binds_s, rhss') = mapAndUnzip fltRhs rhss
-       extras           = concat (map get_pairs (concat binds_s))
-
-        get_pairs (NonRec bndr rhs) = [(bndr,rhs)]
-        get_pairs (Rec pairs)       = pairs
+        pairs' = concat [ let
+                               (binds, rhs') = fltRhs rhs
+                         in
+                         foldr get_pairs [(bndr, rhs')] binds
+                       | (bndr, rhs) <- pairs
+                       ]
+
+        get_pairs (NonRec bndr rhs) rest = (bndr,rhs) :  rest
+        get_pairs (Rec pairs)       rest = pairs      ++ rest
     
        -- fltRhs has same invariant as fltBind
     fltRhs rhs
@@ -1260,16 +1302,23 @@ floatBind env top_level bind
             -- fltExpr guarantees not to return leaky floats
       = (binds' ++ body_binds, body')
       where
-        (body_binds, body')         = fltExpr body
-        (binds', binds_wont_leak, _) = fltBind bind
+        binds_wont_leak     = all leakFreeBind binds'
+        (body_binds, body') = fltExpr body
+        binds'             = fltBind (un_demandify_bind bind)
     
     fltExpr expr = ([], expr)
 
 -- Crude but effective
+no_of_binds (NonRec _ _) = 1
+no_of_binds (Rec pairs)  = length pairs
+
+leakFreeBind (NonRec bndr rhs) = leakFree bndr rhs
+leakFreeBind (Rec pairs)       = and [leakFree bndr rhs | (bndr, rhs) <- pairs]
+
 leakFree (id,_) rhs = case getIdArity id of
                        ArityAtLeast n | n > 0 -> True
                        ArityExactly n | n > 0 -> True
-                       other                  -> whnfOrBottom rhs
+                       other                  -> whnfOrBottom (mkFormSummary rhs)
 \end{code}
 
 
@@ -1285,7 +1334,14 @@ simplArg :: SimplEnv -> InArg -> Eager ans OutArg
 simplArg env (LitArg lit) = returnEager (LitArg lit)
 simplArg env (TyArg  ty)  = simplTy env ty     `appEager` \ ty' -> 
                            returnEager (TyArg ty')
-simplArg env (VarArg id)  = lookupId env id
+simplArg env arg@(VarArg id)
+  = case lookupIdSubst env id of
+       Just (SubstVar id')   -> returnEager (VarArg id')
+       Just (SubstLit lit)   -> returnEager (LitArg lit)
+       Just (SubstExpr _ __) -> panic "simplArg"
+       Nothing               -> case lookupOutIdEnv env id of
+                                 Just (id', _, _) -> returnEager (VarArg id')
+                                 Nothing          -> returnEager arg
 \end{code}
 
 %************************************************************************
@@ -1296,16 +1352,14 @@ simplArg env (VarArg id)  = lookupId env id
 
 
 \begin{code}
--- fix_up_demandedness switches off the willBeDemanded Info field
+-- un_demandify_bind switches off the willBeDemanded Info field
 -- for bindings floated out of a non-demanded let
-fix_up_demandedness True {- Will be demanded -} bind
-   = bind      -- Simple; no change to demand info needed
-fix_up_demandedness False {- May not be demanded -} (NonRec binder rhs)
-   = NonRec (un_demandify binder) rhs
-fix_up_demandedness False {- May not be demanded -} (Rec pairs)
-   = Rec [(un_demandify binder, rhs) | (binder,rhs) <- pairs]
+un_demandify_bind (NonRec binder rhs)
+   = NonRec (un_demandify_bndr binder) rhs
+un_demandify_bind (Rec pairs)
+   = Rec [(un_demandify_bndr binder, rhs) | (binder,rhs) <- pairs]
 
-un_demandify (id, occ_info) = (id `addIdDemandInfo` noDemandInfo, occ_info)
+un_demandify_bndr (id, occ_info) = (id `addIdDemandInfo` noDemandInfo, occ_info)
 
 is_cheap_prim_app (Prim op _) = primOpOkForSpeculation op
 is_cheap_prim_app other              = False
@@ -1316,14 +1370,14 @@ computeResultType env expr_ty orig_args
     let
        go ty [] = ty
        go ty (TyArg ty_arg : args) = go (mkAppTy ty ty_arg) args
-       go ty (a:args) | isValArg a = case (getFunTy_maybe ty) of
+       go ty (a:args) | isValArg a = case (splitFunTy_maybe ty) of
                                        Just (_, res_ty) -> go res_ty args
                                        Nothing          -> 
                                            pprPanic "computeResultType" (vcat [
-                                                                       ppr PprDebug (a:args),
-                                                                       ppr PprDebug orig_args,
-                                                                       ppr PprDebug expr_ty',
-                                                                       ppr PprDebug ty])
+                                                                       ppr (a:args),
+                                                                       ppr orig_args,
+                                                                       ppr expr_ty',
+                                                                       ppr ty])
     in
     go expr_ty' orig_args