remove empty dir
[ghc-hetmet.git] / ghc / compiler / stgSyn / CoreToStg.lhs
index 9772179..824caba 100644 (file)
@@ -12,32 +12,30 @@ module CoreToStg ( coreToStg, coreExprToStg ) where
 #include "HsVersions.h"
 
 import CoreSyn
 #include "HsVersions.h"
 
 import CoreSyn
-import CoreUtils
+import CoreUtils       ( rhsIsStatic, manifestArity, exprType, findDefault )
 import StgSyn
 
 import Type
 import TyCon           ( isAlgTyCon )
 import StgSyn
 
 import Type
 import TyCon           ( isAlgTyCon )
-import Literal
 import Id
 import Id
-import Var             ( Var, globalIdDetails )
+import Var             ( Var, globalIdDetails, idType )
+import TyCon           ( isUnboxedTupleTyCon, isPrimTyCon, isFunTyCon, isHiBootTyCon )
+#ifdef ILX
+import MkId            ( unsafeCoerceId )
+#endif
 import IdInfo
 import DataCon
 import CostCentre      ( noCCS )
 import VarSet
 import VarEnv
 import IdInfo
 import DataCon
 import CostCentre      ( noCCS )
 import VarSet
 import VarEnv
-import DataCon         ( dataConWrapId )
-import IdInfo          ( OccInfo(..) )
-import TysPrim         ( foreignObjPrimTyCon )
 import Maybes          ( maybeToBool )
 import Maybes          ( maybeToBool )
-import Name            ( getOccName, isExternallyVisibleName, isDllName )
-import OccName         ( occNameUserString )
-import BasicTypes       ( TopLevelFlag(..), isNotTopLevel, Arity )
-import CmdLineOpts     ( DynFlags, opt_KeepStgTypes )
-import FastTypes       hiding ( fastOr )
+import Name            ( getOccName, isExternalName, nameOccName )
+import OccName         ( occNameString, occNameFS )
+import BasicTypes       ( Arity )
+import Packages                ( HomeModules )
+import StaticFlags     ( opt_RuntimeTypes )
 import Outputable
 
 import Outputable
 
-import List            ( partition )
-
 infixr 9 `thenLne`
 \end{code}
 
 infixr 9 `thenLne`
 \end{code}
 
@@ -105,8 +103,7 @@ A top-level Id has CafInfo, which is
          one or more CAFs, or
        - NoCafRefs if it definitely doesn't
 
          one or more CAFs, or
        - NoCafRefs if it definitely doesn't
 
-we collect the CafInfo first by analysing the original Core expression, and
-also place this information in the environment.
+The CafInfo has already been calculated during the CoreTidy pass.
 
 During CoreToStg, we then pin onto each binding and case expression, a
 list of Ids which represents the "live" CAFs at that point.  The meaning
 
 During CoreToStg, we then pin onto each binding and case expression, a
 list of Ids which represents the "live" CAFs at that point.  The meaning
@@ -117,6 +114,25 @@ The later SRT pass takes these lists of Ids and uses them to construct
 the actual nested SRTs, and replaces the lists of Ids with (offset,length)
 pairs.
 
 the actual nested SRTs, and replaces the lists of Ids with (offset,length)
 pairs.
 
+
+Interaction of let-no-escape with SRTs   [Sept 01]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+
+       let-no-escape x = ...caf1...caf2...
+       in
+       ...x...x...x...
+
+where caf1,caf2 are CAFs.  Since x doesn't have a closure, we 
+build SRTs just as if x's defn was inlined at each call site, and
+that means that x's CAF refs get duplicated in the overall SRT.
+
+This is unlike ordinary lets, in which the CAF refs are not duplicated.
+
+We could fix this loss of (static) sharing by making a sort of pseudo-closure
+for x, solely to put in the SRTs lower down.
+
+
 %************************************************************************
 %*                                                                     *
 \subsection[binds-StgVarInfo]{Setting variable info: top-level, binds, RHSs}
 %************************************************************************
 %*                                                                     *
 \subsection[binds-StgVarInfo]{Setting variable info: top-level, binds, RHSs}
@@ -124,10 +140,10 @@ pairs.
 %************************************************************************
 
 \begin{code}
 %************************************************************************
 
 \begin{code}
-coreToStg :: DynFlags -> [CoreBind] -> IO [StgBinding]
-coreToStg dflags pgm
+coreToStg :: HomeModules -> [CoreBind] -> IO [StgBinding]
+coreToStg hmods pgm
   = return pgm'
   = return pgm'
-  where (_, _, pgm') = coreTopBindsToStg emptyVarEnv pgm
+  where (_, _, pgm') = coreTopBindsToStg hmods emptyVarEnv pgm
 
 coreExprToStg :: CoreExpr -> StgExpr
 coreExprToStg expr 
 
 coreExprToStg :: CoreExpr -> StgExpr
 coreExprToStg expr 
@@ -135,165 +151,122 @@ coreExprToStg expr
 
 
 coreTopBindsToStg
 
 
 coreTopBindsToStg
-    :: IdEnv HowBound          -- environment for the bindings
+    :: HomeModules
+    -> IdEnv HowBound          -- environment for the bindings
     -> [CoreBind]
     -> (IdEnv HowBound, FreeVarsInfo, [StgBinding])
 
     -> [CoreBind]
     -> (IdEnv HowBound, FreeVarsInfo, [StgBinding])
 
-coreTopBindsToStg env [] = (env, emptyFVInfo, [])
-coreTopBindsToStg env (b:bs)
+coreTopBindsToStg hmods env [] = (env, emptyFVInfo, [])
+coreTopBindsToStg hmods env (b:bs)
   = (env2, fvs2, b':bs')
   where
        -- env accumulates down the list of binds, fvs accumulates upwards
   = (env2, fvs2, b':bs')
   where
        -- env accumulates down the list of binds, fvs accumulates upwards
-       (env1, fvs2, b' ) = coreTopBindToStg env fvs1 b
-       (env2, fvs1, bs') = coreTopBindsToStg env1 bs
+       (env1, fvs2, b' ) = coreTopBindToStg hmods env fvs1 b
+       (env2, fvs1, bs') = coreTopBindsToStg hmods env1 bs
 
 
 coreTopBindToStg
 
 
 coreTopBindToStg
-       :: IdEnv HowBound
+       :: HomeModules
+       -> IdEnv HowBound
        -> FreeVarsInfo         -- Info about the body
        -> CoreBind
        -> (IdEnv HowBound, FreeVarsInfo, StgBinding)
 
        -> FreeVarsInfo         -- Info about the body
        -> CoreBind
        -> (IdEnv HowBound, FreeVarsInfo, StgBinding)
 
-coreTopBindToStg env body_fvs (NonRec id rhs)
+coreTopBindToStg hmods env body_fvs (NonRec id rhs)
   = let 
   = let 
-       caf_info = hasCafRefs env rhs
-
-       env' = extendVarEnv env id (LetBound how_bound emptyLVS (predictArity rhs))
-
-       how_bound | mayHaveCafRefs caf_info = TopLevelHasCafs
-                 | otherwise               = TopLevelNoCafs
+       env'      = extendVarEnv env id how_bound
+       how_bound = LetBound TopLet $! manifestArity rhs
 
 
-        (stg_rhs, fvs', cafs) = 
+        (stg_rhs, fvs') = 
            initLne env (
            initLne env (
-              coreToStgRhs body_fvs TopLevel (id,rhs) 
-                       `thenLne` \ (stg_rhs, fvs', _) ->
-             freeVarsToLiveVars fvs' `thenLne` \ (_, cafs) ->
-             returnLne (stg_rhs, fvs', cafs)
+              coreToTopStgRhs hmods body_fvs (id,rhs)  `thenLne` \ (stg_rhs, fvs') ->
+             returnLne (stg_rhs, fvs')
            )
        
            )
        
-       bind = StgNonRec (SRTEntries cafs) id stg_rhs
+       bind = StgNonRec id stg_rhs
     in
     in
-    ASSERT2(predictArity rhs == stgRhsArity stg_rhs, ppr id)
-    ASSERT2(consistent caf_info bind, ppr id)
+    ASSERT2(manifestArity rhs == stgRhsArity stg_rhs, ppr id)
+    ASSERT2(consistentCafInfo id bind, ppr id)
 --    WARN(not (consistent caf_info bind), ppr id <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
 
 --    WARN(not (consistent caf_info bind), ppr id <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
 
-coreTopBindToStg env body_fvs (Rec pairs)
+coreTopBindToStg hmods env body_fvs (Rec pairs)
   = let 
        (binders, rhss) = unzip pairs
 
   = let 
        (binders, rhss) = unzip pairs
 
-       -- to calculate caf_info, we initially map all the binders to
-       -- TopLevelNoCafs.
-       env1 = extendVarEnvList env 
-               [ (b, LetBound TopLevelNoCafs emptyLVS (error "no arity"))
-               | b <- binders ]
+       extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)
+                    | (b, rhs) <- pairs ]
+       env' = extendVarEnvList env extra_env'
 
 
-       caf_info = hasCafRefss env1{-NB: not env'-} rhss
-
-       env' = extendVarEnvList env 
-               [ (b, LetBound how_bound emptyLVS (predictArity rhs)) 
-               | (b,rhs) <- pairs ]
-
-       how_bound | mayHaveCafRefs caf_info = TopLevelHasCafs
-                 | otherwise               = TopLevelNoCafs
-
-        (stg_rhss, fvs', cafs)
+        (stg_rhss, fvs')
          = initLne env' (
          = initLne env' (
-              mapAndUnzip3Lne (coreToStgRhs body_fvs TopLevel) pairs
-                       `thenLne` \ (stg_rhss, fvss', _) ->
+              mapAndUnzipLne (coreToTopStgRhs hmods body_fvs) pairs
+                                               `thenLne` \ (stg_rhss, fvss') ->
               let fvs' = unionFVInfos fvss' in
               let fvs' = unionFVInfos fvss' in
-              freeVarsToLiveVars fvs'  `thenLne` \ (_, cafs) ->
-              returnLne (stg_rhss, fvs', cafs)
+              returnLne (stg_rhss, fvs')
            )
 
            )
 
-       bind = StgRec (SRTEntries cafs) (zip binders stg_rhss)
+       bind = StgRec (zip binders stg_rhss)
     in
     in
-    ASSERT2(and [predictArity rhs == stgRhsArity stg_rhs | (rhs,stg_rhs) <- rhss `zip` stg_rhss], ppr binders)
-    ASSERT2(consistent caf_info bind, ppr binders)
---    WARN(not (consistent caf_info bind), ppr binders <+> ppr cafs <+> ppCafInfo caf_info)
+    ASSERT2(and [manifestArity rhs == stgRhsArity stg_rhs | (rhs,stg_rhs) <- rhss `zip` stg_rhss], ppr binders)
+    ASSERT2(consistentCafInfo (head binders) bind, ppr binders)
     (env', fvs' `unionFVInfo` body_fvs, bind)
 
     (env', fvs' `unionFVInfo` body_fvs, bind)
 
--- assertion helper
-consistent caf_info bind = mayHaveCafRefs caf_info == stgBindHasCafRefs bind
+#ifdef DEBUG
+-- Assertion helper: this checks that the CafInfo on the Id matches
+-- what CoreToStg has figured out about the binding's SRT.  The
+-- CafInfo will be exact in all cases except when CorePrep has
+-- floated out a binding, in which case it will be approximate.
+consistentCafInfo id bind
+  | occNameFS (nameOccName (idName id)) == FSLIT("sat")
+  = safe
+  | otherwise
+  = WARN (not exact, ppr id) safe
+  where
+       safe  = id_marked_caffy || not binding_is_caffy
+       exact = id_marked_caffy == binding_is_caffy
+       id_marked_caffy  = mayHaveCafRefs (idCafInfo id)
+       binding_is_caffy = stgBindHasCafRefs bind
+#endif
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
-coreToStgRhs
-       :: FreeVarsInfo         -- Free var info for the scope of the binding
-       -> TopLevelFlag
+coreToTopStgRhs
+       :: HomeModules
+       -> FreeVarsInfo         -- Free var info for the scope of the binding
        -> (Id,CoreExpr)
        -> (Id,CoreExpr)
-       -> LneM (StgRhs, FreeVarsInfo, EscVarsSet)
+       -> LneM (StgRhs, FreeVarsInfo)
 
 
-coreToStgRhs scope_fv_info top (binder, rhs)
-  = coreToStgExpr rhs  `thenLne` \ (new_rhs, rhs_fvs, rhs_escs) ->
-    returnLne (mkStgRhs top rhs_fvs binder_info new_rhs, 
-              rhs_fvs, rhs_escs)
+coreToTopStgRhs hmods scope_fv_info (bndr, rhs)
+  = coreToStgExpr rhs          `thenLne` \ (new_rhs, rhs_fvs, _) ->
+    freeVarsToLiveVars rhs_fvs `thenLne` \ lv_info ->
+    returnLne (mkTopStgRhs is_static rhs_fvs (mkSRT lv_info) bndr_info new_rhs, rhs_fvs)
   where
   where
-    binder_info = lookupFVInfo scope_fv_info binder
+    bndr_info = lookupFVInfo scope_fv_info bndr
+    is_static = rhsIsStatic hmods rhs
 
 
-mkStgRhs :: TopLevelFlag -> FreeVarsInfo -> StgBinderInfo
-        -> StgExpr -> StgRhs
+mkTopStgRhs :: Bool -> FreeVarsInfo -> SRT -> StgBinderInfo -> StgExpr
+       -> StgRhs
 
 
-mkStgRhs top rhs_fvs binder_info (StgLam _ bndrs body)
-  = StgRhsClosure noCCS binder_info
+mkTopStgRhs is_static rhs_fvs srt binder_info (StgLam _ bndrs body)
+  = ASSERT( is_static )
+    StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
                  ReEntrant
                  (getFVs rhs_fvs)               
                  ReEntrant
+                 srt
                  bndrs body
        
                  bndrs body
        
-mkStgRhs top rhs_fvs binder_info (StgConApp con args)
-  | isNotTopLevel top || not (isDllConApp con args)
+mkTopStgRhs is_static rhs_fvs srt binder_info (StgConApp con args)
+  | is_static   -- StgConApps can be updatable (see isCrossDllConApp)
   = StgRhsCon noCCS con args
 
   = StgRhsCon noCCS con args
 
-mkStgRhs top rhs_fvs binder_info rhs
-  = StgRhsClosure noCCS binder_info
+mkTopStgRhs is_static rhs_fvs srt binder_info rhs
+  = ASSERT2( not is_static, ppr rhs )
+    StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
                  (getFVs rhs_fvs)               
-                 (updatable [] rhs)
+                 Updatable
+                 srt
                  [] rhs
                  [] rhs
-  where
-    updatable args body | null args && isPAP body  = ReEntrant
-                       | otherwise                = Updatable
-{- ToDo:
-          upd = if isOnceDem dem
-                   then (if isNotTop toplev 
-                           then SingleEntry    -- HA!  Paydirt for "dem"
-                           else 
-#ifdef DEBUG
-                     trace "WARNING: SE CAFs unsupported, forcing UPD instead" $
-#endif
-                     Updatable)
-               else Updatable
-        -- For now we forbid SingleEntry CAFs; they tickle the
-        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,
-        -- and I don't understand why.  There's only one SE_CAF (well,
-        -- only one that tickled a great gaping bug in an earlier attempt
-        -- at ClosureInfo.getEntryConvention) in the whole of nofib, 
-        -- specifically Main.lvl6 in spectral/cryptarithm2.
-        -- So no great loss.  KSW 2000-07.
--}
-\end{code}
-
-Detect thunks which will reduce immediately to PAPs, and make them
-non-updatable.  This has several advantages:
-
-        - the non-updatable thunk behaves exactly like the PAP,
-
-       - the thunk is more efficient to enter, because it is
-         specialised to the task.
-
-        - we save one update frame, one stg_update_PAP, one update
-         and lots of PAP_enters.
-
-       - in the case where the thunk is top-level, we save building
-         a black hole and futhermore the thunk isn't considered to
-         be a CAF any more, so it doesn't appear in any SRTs.
-
-We do it here, because the arity information is accurate, and we need
-to do it before the SRT pass to save the SRT entries associated with
-any top-level PAPs.
-
-\begin{code}
-isPAP (StgApp f args) = idArity f > length args
-isPAP _              = False
 \end{code}
 
 
 \end{code}
 
 
@@ -329,15 +302,15 @@ coreToStgExpr expr@(App _ _)
     (f, args) = myCollectArgs expr
 
 coreToStgExpr expr@(Lam _ _)
     (f, args) = myCollectArgs expr
 
 coreToStgExpr expr@(Lam _ _)
-  = let (args, body) = myCollectBinders expr 
+  = let
+       (args, body) = myCollectBinders expr 
        args'        = filterStgBinders args
     in
     extendVarEnvLne [ (a, LambdaBound) | a <- args' ] $
     coreToStgExpr body  `thenLne` \ (body, body_fvs, body_escs) ->
     let
        args'        = filterStgBinders args
     in
     extendVarEnvLne [ (a, LambdaBound) | a <- args' ] $
     coreToStgExpr body  `thenLne` \ (body, body_fvs, body_escs) ->
     let
-       set_of_args     = mkVarSet args'
        fvs             = args' `minusFVBinders` body_fvs
        fvs             = args' `minusFVBinders` body_fvs
-       escs            = body_escs `minusVarSet`    set_of_args
+       escs            = body_escs `delVarSetList` args'
        result_expr | null args' = body
                    | otherwise  = StgLam (exprType expr) args' body
     in
        result_expr | null args' = body
                    | otherwise  = StgLam (exprType expr) args' body
     in
@@ -347,112 +320,81 @@ coreToStgExpr (Note (SCC cc) expr)
   = coreToStgExpr expr         `thenLne` ( \ (expr2, fvs, escs) ->
     returnLne (StgSCC cc expr2, fvs, escs) )
 
   = coreToStgExpr expr         `thenLne` ( \ (expr2, fvs, escs) ->
     returnLne (StgSCC cc expr2, fvs, escs) )
 
+#ifdef ILX
+-- For ILX, convert (__coerce__ to_ty from_ty e) 
+--         into    (coerce to_ty from_ty e)
+-- where coerce is real function
+coreToStgExpr (Note (Coerce to_ty from_ty) expr)
+  = coreToStgExpr (mkApps (Var unsafeCoerceId) 
+                         [Type from_ty, Type to_ty, expr])
+#endif
+
 coreToStgExpr (Note other_note expr)
   = coreToStgExpr expr
 
 coreToStgExpr (Note other_note expr)
   = coreToStgExpr expr
 
-
 -- Cases require a little more real work.
 
 -- Cases require a little more real work.
 
-coreToStgExpr (Case scrut bndr alts)
-  = extendVarEnvLne [(bndr, CaseBound)]        $
-    vars_alts (findDefault alts)   `thenLne` \ (alts2, alts_fvs, alts_escs) ->
-    freeVarsToLiveVars  alts_fvs   `thenLne` \ (alts_lvs, alts_caf_refs) ->
+coreToStgExpr (Case scrut bndr _ alts)
+  = extendVarEnvLne [(bndr, LambdaBound)]      (
+        mapAndUnzip3Lne vars_alt alts  `thenLne` \ (alts2, fvs_s, escs_s) ->
+        returnLne ( alts2,
+                    unionFVInfos fvs_s,
+                    unionVarSets escs_s )
+    )                                  `thenLne` \ (alts2, alts_fvs, alts_escs) ->
     let
     let
-       -- determine whether the default binder is dead or not
+       -- Determine whether the default binder is dead or not
        -- This helps the code generator to avoid generating an assignment
        -- for the case binder (is extremely rare cases) ToDo: remove.
        -- This helps the code generator to avoid generating an assignment
        -- for the case binder (is extremely rare cases) ToDo: remove.
-       bndr'= if (bndr `elementOfFVInfo` alts_fvs) 
-                 then bndr
-                 else bndr `setIdOccInfo` IAmDead
+       bndr' | bndr `elementOfFVInfo` alts_fvs = bndr
+             | otherwise                       = bndr `setIdOccInfo` IAmDead
 
        -- Don't consider the default binder as being 'live in alts',
        -- since this is from the point of view of the case expr, where
        -- the default binder is not free.
 
        -- Don't consider the default binder as being 'live in alts',
        -- since this is from the point of view of the case expr, where
        -- the default binder is not free.
-       live_in_alts = (alts_lvs `minusVarSet` unitVarSet bndr)
+       alts_fvs_wo_bndr  = bndr `minusFVBinder` alts_fvs
+       alts_escs_wo_bndr = alts_escs `delVarSet` bndr
     in
     in
-       -- we tell the scrutinee that everything live in the alts
-       -- is live in it, too.
-    setVarsLiveInCont (live_in_alts,alts_caf_refs) (
+
+    freeVarsToLiveVars alts_fvs_wo_bndr                `thenLne` \ alts_lv_info ->
+
+       -- We tell the scrutinee that everything 
+       -- live in the alts is live in it, too.
+    setVarsLiveInCont alts_lv_info (
        coreToStgExpr scrut       `thenLne` \ (scrut2, scrut_fvs, scrut_escs) ->
        coreToStgExpr scrut       `thenLne` \ (scrut2, scrut_fvs, scrut_escs) ->
-        freeVarsToLiveVars scrut_fvs `thenLne` \ (scrut_lvs, _) ->
-       returnLne (scrut2, scrut_fvs, scrut_escs, scrut_lvs)
+        freeVarsToLiveVars scrut_fvs `thenLne` \ scrut_lv_info ->
+       returnLne (scrut2, scrut_fvs, scrut_escs, scrut_lv_info)
       )    
       )    
-               `thenLne` \ (scrut2, scrut_fvs, scrut_escs, scrut_lvs) ->
+               `thenLne` \ (scrut2, scrut_fvs, scrut_escs, scrut_lv_info) ->
 
 
-    let srt = SRTEntries alts_caf_refs
-    in
     returnLne (
     returnLne (
-      StgCase scrut2 scrut_lvs live_in_alts bndr' srt alts2,
-      bndr `minusFVBinder` (scrut_fvs `unionFVInfo` alts_fvs),
-      (alts_escs `minusVarSet` unitVarSet bndr) `unionVarSet` getFVSet scrut_fvs
+      StgCase scrut2 (getLiveVars scrut_lv_info)
+                    (getLiveVars alts_lv_info)
+                    bndr'
+                    (mkSRT alts_lv_info)
+                    (mkStgAltType (idType bndr) alts)
+                    alts2,
+      scrut_fvs `unionFVInfo` alts_fvs_wo_bndr,
+      alts_escs_wo_bndr `unionVarSet` getFVSet scrut_fvs
                -- You might think we should have scrut_escs, not 
                -- (getFVSet scrut_fvs), but actually we can't call, and 
                -- then return from, a let-no-escape thing.
       )
   where
                -- You might think we should have scrut_escs, not 
                -- (getFVSet scrut_fvs), but actually we can't call, and 
                -- then return from, a let-no-escape thing.
       )
   where
-    scrut_ty   = idType bndr
-    prim_case  = isUnLiftedType scrut_ty && not (isUnboxedTupleType scrut_ty)
-
-    vars_alts (alts,deflt)
-       | prim_case
-        = mapAndUnzip3Lne vars_prim_alt alts
-                       `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
-         let
-             alts_fvs  = unionFVInfos alts_fvs_list
-             alts_escs = unionVarSets alts_escs_list
-         in
-         vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
-         returnLne (
-             mkStgPrimAlts scrut_ty alts2 deflt2,
-             alts_fvs  `unionFVInfo`   deflt_fvs,
-             alts_escs `unionVarSet` deflt_escs
-         )
-
-       | otherwise
-        = mapAndUnzip3Lne vars_alg_alt alts
-                       `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
-         let
-             alts_fvs  = unionFVInfos alts_fvs_list
-             alts_escs = unionVarSets alts_escs_list
-         in
-         vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
-         returnLne (
-             mkStgAlgAlts scrut_ty alts2 deflt2,
-             alts_fvs  `unionFVInfo`   deflt_fvs,
-             alts_escs `unionVarSet` deflt_escs
-         )
-
-      where
-       vars_prim_alt (LitAlt lit, _, rhs)
-         = coreToStgExpr rhs   `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-           returnLne ((lit, rhs2), rhs_fvs, rhs_escs)
-
-       vars_alg_alt (DataAlt con, binders, rhs)
-         = let
-               -- remove type variables
-               binders' = filterStgBinders binders
-           in  
-           extendVarEnvLne [(b, CaseBound) | b <- binders']    $
-           coreToStgExpr rhs   `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-           let
-               good_use_mask = [ b `elementOfFVInfo` rhs_fvs | b <- binders' ]
-               -- records whether each param is used in the RHS
-           in
-           returnLne (
-               (con, binders', good_use_mask, rhs2),
-               binders' `minusFVBinders` rhs_fvs,
-               rhs_escs `minusVarSet`   mkVarSet binders'
-                       -- ToDo: remove the minusVarSet;
-                       -- since escs won't include any of these binders
-           )
-       vars_alg_alt other = pprPanic "vars_alg_alt" (ppr other)
-
-       vars_deflt Nothing
-          = returnLne (StgNoDefault, emptyFVInfo, emptyVarSet)
-     
-       vars_deflt (Just rhs)
-          = coreToStgExpr rhs  `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-            returnLne (StgBindDefault rhs2, rhs_fvs, rhs_escs)
+    vars_alt (con, binders, rhs)
+      = let            -- Remove type variables
+           binders' = filterStgBinders binders
+        in     
+        extendVarEnvLne [(b, LambdaBound) | b <- binders']     $
+        coreToStgExpr rhs      `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
+        let
+               -- Records whether each param is used in the RHS
+           good_use_mask = [ b `elementOfFVInfo` rhs_fvs | b <- binders' ]
+        in
+        returnLne ( (con, binders', good_use_mask, rhs2),
+                   binders' `minusFVBinders` rhs_fvs,
+                   rhs_escs `delVarSetList` binders' )
+               -- ToDo: remove the delVarSet;
+               -- since escs won't include any of these binders
 \end{code}
 
 Lets not only take quite a bit of work, but this is where we convert
 \end{code}
 
 Lets not only take quite a bit of work, but this is where we convert
@@ -468,36 +410,30 @@ coreToStgExpr (Let bind body)
     returnLne (new_let, fvs, escs)
 \end{code}
 
     returnLne (new_let, fvs, escs)
 \end{code}
 
-If we've got a case containing a _ccall_GC_ primop, we need to
-ensure that the arguments are kept live for the duration of the
-call. This only an issue
-
 \begin{code}
 \begin{code}
-isForeignObjArg :: Id -> Bool
-isForeignObjArg x = isId x && isForeignObjPrimTy (idType x)
+mkStgAltType scrut_ty alts
+  = case splitTyConApp_maybe (repType scrut_ty) of
+       Just (tc,_) | isUnboxedTupleTyCon tc -> UbxTupAlt tc
+                   | isPrimTyCon tc         -> PrimAlt tc
+                   | isHiBootTyCon tc       -> look_for_better_tycon
+                   | isAlgTyCon tc          -> AlgAlt tc
+                   | isFunTyCon tc          -> PolyAlt
+                   | otherwise              -> pprPanic "mkStgAlts" (ppr tc)
+       Nothing                              -> PolyAlt
 
 
-isForeignObjPrimTy ty
-   = case splitTyConApp_maybe ty of
-       Just (tycon, _) -> tycon == foreignObjPrimTyCon
-       Nothing         -> False
-\end{code}
-
-\begin{code}
-mkStgAlgAlts ty alts deflt
- =  case alts of
-               -- Get the tycon from the data con
-       (dc, _, _, _) : _rest
-           -> StgAlgAlts (Just (dataConTyCon dc)) alts deflt
-
-               -- Otherwise just do your best
-       [] -> case splitTyConApp_maybe (repType ty) of
-               Just (tc,_) | isAlgTyCon tc 
-                       -> StgAlgAlts (Just tc) alts deflt
-               other
-                       -> StgAlgAlts Nothing alts deflt
-
-mkStgPrimAlts ty alts deflt 
-  = StgPrimAlts (tyConAppTyCon ty) alts deflt
+  where
+   -- Sometimes, the TyCon in the type of the scrutinee is an HiBootTyCon,
+   -- which may not have any constructors inside it.  If so, then we
+   -- can get a better TyCon by grabbing the one from a constructor alternative
+   -- if one exists.
+   look_for_better_tycon
+       | ((DataAlt con, _, _) : _) <- data_alts = 
+               AlgAlt (dataConTyCon con)
+       | otherwise =
+               ASSERT(null data_alts)
+               PolyAlt
+       where
+               (data_alts, _deflt) = findDefault alts
 \end{code}
 
 
 \end{code}
 
 
@@ -522,16 +458,29 @@ coreToStgApp maybe_thunk_body f args
     let
        n_val_args       = valArgCount args
        not_letrec_bound = not (isLetBound how_bound)
     let
        n_val_args       = valArgCount args
        not_letrec_bound = not (isLetBound how_bound)
-       fun_fvs          = singletonFVInfo f how_bound fun_occ
-
-       f_arity = case how_bound of 
-                       LetBound _ _ arity -> arity
-                       _                  -> 0
+       fun_fvs          
+          = let fvs = singletonFVInfo f how_bound fun_occ in
+            -- e.g. (f :: a -> int) (x :: a) 
+            -- Here the free variables are "f", "x" AND the type variable "a"
+            -- coreToStgArgs will deal with the arguments recursively
+            if opt_RuntimeTypes then
+             fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType (idType f))
+           else fvs
+
+       -- Mostly, the arity info of a function is in the fn's IdInfo
+       -- But new bindings introduced by CoreSat may not have no
+       -- arity info; it would do us no good anyway.  For example:
+       --      let f = \ab -> e in f
+       -- No point in having correct arity info for f!
+       -- Hence the hasArity stuff below.
+       -- NB: f_arity is only consulted for LetBound things
+       f_arity   = stgArity f how_bound
+       saturated = f_arity <= n_val_args
 
        fun_occ 
 
        fun_occ 
-        | not_letrec_bound                     = noBinderInfo  -- Uninteresting variable
-        | f_arity > 0 && f_arity <= n_val_args = stgSatOcc     -- Saturated or over-saturated function call
-        | otherwise                            = stgUnsatOcc   -- Unsaturated function or thunk
+        | not_letrec_bound         = noBinderInfo      -- Uninteresting variable
+        | f_arity > 0 && saturated = stgSatOcc -- Saturated or over-saturated function call
+        | otherwise                = stgUnsatOcc       -- Unsaturated function or thunk
 
        fun_escs
         | not_letrec_bound      = emptyVarSet  -- Only letrec-bound escapees are interesting
 
        fun_escs
         | not_letrec_bound      = emptyVarSet  -- Only letrec-bound escapees are interesting
@@ -552,10 +501,14 @@ coreToStgApp maybe_thunk_body f args
        --         continuation, but it does no harm to just union the
        --         two regardless.
 
        --         continuation, but it does no harm to just union the
        --         two regardless.
 
+       res_ty = exprType (mkApps (Var f) args)
        app = case globalIdDetails f of
        app = case globalIdDetails f of
-               DataConId dc -> StgConApp dc args'
-               PrimOpId op  -> StgPrimApp op args' (exprType (mkApps (Var f) args))
-               _other       -> StgApp f args'
+               DataConWorkId dc | saturated -> StgConApp dc args'
+               PrimOpId op                  -> ASSERT( saturated )
+                                               StgOpApp (StgPrimOp op) args' res_ty
+               FCallId call     -> ASSERT( saturated )
+                                   StgOpApp (StgFCallOp call (idUnique f)) args' res_ty
+               _other           -> StgApp f args'
 
     in
     returnLne (
 
     in
     returnLne (
@@ -579,7 +532,7 @@ coreToStgArgs []
 
 coreToStgArgs (Type ty : args) -- Type argument
   = coreToStgArgs args `thenLne` \ (args', fvs) ->
 
 coreToStgArgs (Type ty : args) -- Type argument
   = coreToStgArgs args `thenLne` \ (args', fvs) ->
-    if opt_KeepStgTypes then
+    if opt_RuntimeTypes then
        returnLne (StgTypeArg ty : args', fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType ty))
     else
     returnLne (args', fvs)
        returnLne (StgTypeArg ty : args', fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType ty))
     else
     returnLne (args', fvs)
@@ -591,7 +544,7 @@ coreToStgArgs (arg : args)  -- Non-type argument
        fvs = args_fvs `unionFVInfo` arg_fvs
        stg_arg = case arg' of
                       StgApp v []      -> StgVarArg v
        fvs = args_fvs `unionFVInfo` arg_fvs
        stg_arg = case arg' of
                       StgApp v []      -> StgVarArg v
-                      StgConApp con [] -> StgVarArg (dataConWrapId con)
+                      StgConApp con [] -> StgVarArg (dataConWorkId con)
                       StgLit lit       -> StgLitArg lit
                       _                -> pprPanic "coreToStgArgs" (ppr arg)
     in
                       StgLit lit       -> StgLitArg lit
                       _                -> pprPanic "coreToStgArgs" (ppr arg)
     in
@@ -613,28 +566,27 @@ coreToStgLet
                                -- is among the escaping vars
 
 coreToStgLet let_no_escape bind body
                                -- is among the escaping vars
 
 coreToStgLet let_no_escape bind body
-  = fixLne (\ ~(_, _, _, _, _, _, rec_body_fvs, _, _) ->
+  = fixLne (\ ~(_, _, _, _, _, rec_body_fvs, _, _) ->
 
        -- Do the bindings, setting live_in_cont to empty if
        -- we ain't in a let-no-escape world
        getVarsLiveInCont               `thenLne` \ live_in_cont ->
        setVarsLiveInCont (if let_no_escape 
                                then live_in_cont 
 
        -- Do the bindings, setting live_in_cont to empty if
        -- we ain't in a let-no-escape world
        getVarsLiveInCont               `thenLne` \ live_in_cont ->
        setVarsLiveInCont (if let_no_escape 
                                then live_in_cont 
-                               else emptyLVS)
+                               else emptyLiveInfo)
                          (vars_bind rec_body_fvs bind)
                          (vars_bind rec_body_fvs bind)
-           `thenLne` \ ( bind2, bind_fvs, bind_escs
-                       , bind_lvs, bind_cafs, env_ext) ->
+           `thenLne` \ ( bind2, bind_fvs, bind_escs, bind_lv_info, env_ext) ->
 
        -- Do the body
        extendVarEnvLne env_ext (
          coreToStgExpr body          `thenLne` \(body2, body_fvs, body_escs) ->
 
        -- Do the body
        extendVarEnvLne env_ext (
          coreToStgExpr body          `thenLne` \(body2, body_fvs, body_escs) ->
-         freeVarsToLiveVars body_fvs `thenLne` \(body_lvs, _) ->
+         freeVarsToLiveVars body_fvs `thenLne` \ body_lv_info ->
 
 
-         returnLne (bind2, bind_fvs, bind_escs, bind_lvs, bind_cafs,
-                    body2, body_fvs, body_escs, body_lvs)
+         returnLne (bind2, bind_fvs, bind_escs, getLiveVars bind_lv_info,
+                    body2, body_fvs, body_escs, getLiveVars body_lv_info)
        )
 
        )
 
-    ) `thenLne` (\ (bind2, bind_fvs, bind_escs, bind_lvs, bind_cafs, 
+    ) `thenLne` (\ (bind2, bind_fvs, bind_escs, bind_lvs, 
                    body2, body_fvs, body_escs, body_lvs) ->
 
 
                    body2, body_fvs, body_escs, body_lvs) ->
 
 
@@ -647,7 +599,7 @@ coreToStgLet let_no_escape bind body
          = binders `minusFVBinders` (bind_fvs `unionFVInfo` body_fvs)
 
        live_in_whole_let
          = binders `minusFVBinders` (bind_fvs `unionFVInfo` body_fvs)
 
        live_in_whole_let
-         = bind_lvs `unionVarSet` (body_lvs `minusVarSet` set_of_binders)
+         = bind_lvs `unionVarSet` (body_lvs `delVarSetList` binders)
 
        real_bind_escs = if let_no_escape then
                            bind_escs
 
        real_bind_escs = if let_no_escape then
                            bind_escs
@@ -655,7 +607,7 @@ coreToStgLet let_no_escape bind body
                            getFVSet bind_fvs
                            -- Everything escapes which is free in the bindings
 
                            getFVSet bind_fvs
                            -- Everything escapes which is free in the bindings
 
-       let_escs = (real_bind_escs `unionVarSet` body_escs) `minusVarSet` set_of_binders
+       let_escs = (real_bind_escs `unionVarSet` body_escs) `delVarSetList` binders
 
        all_escs = bind_escs `unionVarSet` body_escs    -- Still includes binders of
                                                        -- this let(rec)
 
        all_escs = bind_escs `unionVarSet` body_escs    -- Still includes binders of
                                                        -- this let(rec)
@@ -684,93 +636,146 @@ coreToStgLet let_no_escape bind body
     ))
   where
     set_of_binders = mkVarSet binders
     ))
   where
     set_of_binders = mkVarSet binders
-    binders       = case bind of
-                       NonRec binder rhs -> [binder]
-                       Rec pairs         -> map fst pairs
+    binders       = bindersOf bind
 
 
-    mk_binding bind_lvs bind_cafs binder rhs
-       = (binder,  LetBound  NotTopLevelBound  -- Not top level
-                       live_vars (predictArity rhs)
-          )
+    mk_binding bind_lv_info binder rhs
+       = (binder, LetBound (NestedLet live_vars) (manifestArity rhs))
        where
        where
-          live_vars = if let_no_escape then
-                           (extendVarSet bind_lvs binder, bind_cafs)
-                      else
-                           (unitVarSet binder, emptyVarSet)
+          live_vars | let_no_escape = addLiveVar bind_lv_info binder
+                    | otherwise     = unitLiveVar binder
+               -- c.f. the invariant on NestedLet
 
     vars_bind :: FreeVarsInfo          -- Free var info for body of binding
              -> CoreBind
              -> LneM (StgBinding,
                       FreeVarsInfo, 
                       EscVarsSet,        -- free vars; escapee vars
 
     vars_bind :: FreeVarsInfo          -- Free var info for body of binding
              -> CoreBind
              -> LneM (StgBinding,
                       FreeVarsInfo, 
                       EscVarsSet,        -- free vars; escapee vars
-                      StgLiveVars,       -- vars live in binding
-                      IdSet,             -- CAFs live in binding
+                      LiveInfo,          -- Vars and CAFs live in binding
                       [(Id, HowBound)])  -- extension to environment
                                         
 
     vars_bind body_fvs (NonRec binder rhs)
                       [(Id, HowBound)])  -- extension to environment
                                         
 
     vars_bind body_fvs (NonRec binder rhs)
-      = coreToStgRhs body_fvs NotTopLevel (binder,rhs)
-                               `thenLne` \ (rhs2, bind_fvs, escs) ->
-
-       freeVarsToLiveVars bind_fvs `thenLne` \ (bind_lvs, bind_cafs) ->
+      = coreToStgRhs body_fvs [] (binder,rhs)
+                               `thenLne` \ (rhs2, bind_fvs, bind_lv_info, escs) ->
        let
        let
-           env_ext_item = mk_binding bind_lvs bind_cafs binder rhs
+           env_ext_item = mk_binding bind_lv_info binder rhs
        in
        in
-       returnLne (StgNonRec (SRTEntries bind_cafs) binder rhs2, 
-                       bind_fvs, escs, bind_lvs, bind_cafs, [env_ext_item])
+       returnLne (StgNonRec binder rhs2, 
+                  bind_fvs, escs, bind_lv_info, [env_ext_item])
 
 
     vars_bind body_fvs (Rec pairs)
 
 
     vars_bind body_fvs (Rec pairs)
-      = fixLne (\ ~(_, rec_rhs_fvs, _, bind_lvs, bind_cafs, _) ->
+      = fixLne (\ ~(_, rec_rhs_fvs, _, bind_lv_info, _) ->
           let
                rec_scope_fvs = unionFVInfo body_fvs rec_rhs_fvs
                binders = map fst pairs
           let
                rec_scope_fvs = unionFVInfo body_fvs rec_rhs_fvs
                binders = map fst pairs
-               env_ext = [ mk_binding bind_lvs bind_cafs b rhs 
+               env_ext = [ mk_binding bind_lv_info b rhs 
                          | (b,rhs) <- pairs ]
           in
           extendVarEnvLne env_ext (
                          | (b,rhs) <- pairs ]
           in
           extendVarEnvLne env_ext (
-             mapAndUnzip3Lne (coreToStgRhs rec_scope_fvs NotTopLevel) pairs 
-                                       `thenLne` \ (rhss2, fvss, escss) ->
+             mapAndUnzip4Lne (coreToStgRhs rec_scope_fvs binders) pairs 
+                                       `thenLne` \ (rhss2, fvss, lv_infos, escss) ->
              let
                        bind_fvs = unionFVInfos fvss
              let
                        bind_fvs = unionFVInfos fvss
+                       bind_lv_info = foldr unionLiveInfo emptyLiveInfo lv_infos
                        escs     = unionVarSets escss
              in
                        escs     = unionVarSets escss
              in
-             freeVarsToLiveVars (binders `minusFVBinders` bind_fvs)
-                                       `thenLne` \ (bind_lvs, bind_cafs) ->
-
-             returnLne (StgRec (SRTEntries bind_cafs) (binders `zip` rhss2), 
-                               bind_fvs, escs, bind_lvs, bind_cafs, env_ext)
+             returnLne (StgRec (binders `zip` rhss2),
+                        bind_fvs, escs, bind_lv_info, env_ext)
           )
        )
 
 is_join_var :: Id -> Bool
 -- A hack (used only for compiler debuggging) to tell if
 -- a variable started life as a join point ($j)
           )
        )
 
 is_join_var :: Id -> Bool
 -- A hack (used only for compiler debuggging) to tell if
 -- a variable started life as a join point ($j)
-is_join_var j = occNameUserString (getOccName j) == "$j"
+is_join_var j = occNameString (getOccName j) == "$j"
 \end{code}
 
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Arity prediction}
-%*                                                                     *
-%************************************************************************
+\begin{code}
+coreToStgRhs :: FreeVarsInfo           -- Free var info for the scope of the binding
+            -> [Id]
+            -> (Id,CoreExpr)
+            -> LneM (StgRhs, FreeVarsInfo, LiveInfo, EscVarsSet)
+
+coreToStgRhs scope_fv_info binders (bndr, rhs)
+  = coreToStgExpr rhs          `thenLne` \ (new_rhs, rhs_fvs, rhs_escs) ->
+    getEnvLne                  `thenLne` \ env ->    
+    freeVarsToLiveVars (binders `minusFVBinders` rhs_fvs) `thenLne` \ lv_info ->
+    returnLne (mkStgRhs rhs_fvs (mkSRT lv_info) bndr_info new_rhs,
+              rhs_fvs, lv_info, rhs_escs)
+  where
+    bndr_info = lookupFVInfo scope_fv_info bndr
 
 
-To avoid yet another knot, we predict the arity of each function from
-its Core form, based on the number of visible top-level lambdas.  
-It should be the same as the arity of the STG RHS!
+mkStgRhs :: FreeVarsInfo -> SRT -> StgBinderInfo -> StgExpr -> StgRhs
 
 
-\begin{code}
-predictArity :: CoreExpr -> Int
-predictArity (Lam x e)
-  | isTyVar x = predictArity e
-  | otherwise = 1 + predictArity e
-predictArity (Note _ e)
-  -- Ignore coercions.   Top level sccs are removed by the final 
-  -- profiling pass, so we ignore those too.
-  = predictArity e
-predictArity _ = 0
+mkStgRhs rhs_fvs srt binder_info (StgConApp con args)
+  = StgRhsCon noCCS con args
+
+mkStgRhs rhs_fvs srt binder_info (StgLam _ bndrs body)
+  = StgRhsClosure noCCS binder_info
+                 (getFVs rhs_fvs)               
+                 ReEntrant
+                 srt bndrs body
+       
+mkStgRhs rhs_fvs srt binder_info rhs
+  = StgRhsClosure noCCS binder_info
+                 (getFVs rhs_fvs)               
+                 upd_flag srt [] rhs
+  where
+   upd_flag = Updatable
+  {-
+    SDM: disabled.  Eval/Apply can't handle functions with arity zero very
+    well; and making these into simple non-updatable thunks breaks other
+    assumptions (namely that they will be entered only once).
+
+    upd_flag | isPAP env rhs  = ReEntrant
+            | otherwise      = Updatable
+  -}
+
+{- ToDo:
+          upd = if isOnceDem dem
+                   then (if isNotTop toplev 
+                           then SingleEntry    -- HA!  Paydirt for "dem"
+                           else 
+#ifdef DEBUG
+                     trace "WARNING: SE CAFs unsupported, forcing UPD instead" $
+#endif
+                     Updatable)
+               else Updatable
+        -- For now we forbid SingleEntry CAFs; they tickle the
+        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,
+        -- and I don't understand why.  There's only one SE_CAF (well,
+        -- only one that tickled a great gaping bug in an earlier attempt
+        -- at ClosureInfo.getEntryConvention) in the whole of nofib, 
+        -- specifically Main.lvl6 in spectral/cryptarithm2.
+        -- So no great loss.  KSW 2000-07.
+-}
 \end{code}
 
 \end{code}
 
+Detect thunks which will reduce immediately to PAPs, and make them
+non-updatable.  This has several advantages:
+
+        - the non-updatable thunk behaves exactly like the PAP,
+
+       - the thunk is more efficient to enter, because it is
+         specialised to the task.
+
+        - we save one update frame, one stg_update_PAP, one update
+         and lots of PAP_enters.
+
+       - in the case where the thunk is top-level, we save building
+         a black hole and futhermore the thunk isn't considered to
+         be a CAF any more, so it doesn't appear in any SRTs.
+
+We do it here, because the arity information is accurate, and we need
+to do it before the SRT pass to save the SRT entries associated with
+any top-level PAPs.
+
+isPAP env (StgApp f args) = listLengthCmp args arity == LT -- idArity f > length args
+                         where
+                           arity = stgArity f (lookupBinding env f)
+isPAP env _              = False
+
 
 %************************************************************************
 %*                                                                     *
 
 %************************************************************************
 %*                                                                     *
@@ -783,40 +788,86 @@ help.  All the stuff here is only passed *down*.
 
 \begin{code}
 type LneM a =  IdEnv HowBound
 
 \begin{code}
 type LneM a =  IdEnv HowBound
-           -> (StgLiveVars,    -- vars live in continuation
-               IdSet)          -- cafs live in continuation
+           -> LiveInfo         -- Vars and CAFs live in continuation
            -> a
 
            -> a
 
+type LiveInfo = (StgLiveVars,  -- Dynamic live variables; 
+                               -- i.e. ones with a nested (non-top-level) binding
+                CafSet)        -- Static live variables;
+                               -- i.e. top-level variables that are CAFs or refer to them
+
+type EscVarsSet = IdSet
+type CafSet     = IdSet
+
 data HowBound
 data HowBound
-  = ImportBound
-  | CaseBound
-  | LambdaBound
-  | LetBound
-       TopLevelCafInfo
-       (StgLiveVars, IdSet) -- (Live vars, Live CAFs)... see notes below
-       Arity      -- its arity (local Ids don't have arity info at this point)
-
-isLetBound (LetBound _ _ _) = True
-isLetBound other           = False
+  = ImportBound                -- Used only as a response to lookupBinding; never
+                       -- exists in the range of the (IdEnv HowBound)
+
+  | LetBound           -- A let(rec) in this module
+       LetInfo         -- Whether top level or nested
+       Arity           -- Its arity (local Ids don't have arity info at this point)
+
+  | LambdaBound                -- Used for both lambda and case
+
+data LetInfo
+  = TopLet             -- top level things
+  | NestedLet LiveInfo -- For nested things, what is live if this
+                       -- thing is live?  Invariant: the binder
+                       -- itself is always a member of
+                       -- the dynamic set of its own LiveInfo
+
+isLetBound (LetBound _ _) = True
+isLetBound other         = False
+
+topLevelBound ImportBound        = True
+topLevelBound (LetBound TopLet _) = True
+topLevelBound other              = False
 \end{code}
 
 \end{code}
 
-For a let(rec)-bound variable, x, we record StgLiveVars, the set of
-variables that are live if x is live.  For "normal" variables that is
-just x alone.  If x is a let-no-escaped variable then x is represented
-by a code pointer and a stack pointer (well, one for each stack).  So
-all of the variables needed in the execution of x are live if x is,
-and are therefore recorded in the LetBound constructor; x itself
-*is* included.
+For a let(rec)-bound variable, x, we record LiveInfo, the set of
+variables that are live if x is live.  This LiveInfo comprises
+       (a) dynamic live variables (ones with a non-top-level binding)
+       (b) static live variabes (CAFs or things that refer to CAFs)
+
+For "normal" variables (a) is just x alone.  If x is a let-no-escaped
+variable then x is represented by a code pointer and a stack pointer
+(well, one for each stack).  So all of the variables needed in the
+execution of x are live if x is, and are therefore recorded in the
+LetBound constructor; x itself *is* included.
 
 
-The set of live variables is guaranteed ot have no further let-no-escaped
+The set of dynamic live variables is guaranteed ot have no further let-no-escaped
 variables in it.
 
 variables in it.
 
+\begin{code}
+emptyLiveInfo :: LiveInfo
+emptyLiveInfo = (emptyVarSet,emptyVarSet)
+
+unitLiveVar :: Id -> LiveInfo
+unitLiveVar lv = (unitVarSet lv, emptyVarSet)
+
+unitLiveCaf :: Id -> LiveInfo
+unitLiveCaf caf = (emptyVarSet, unitVarSet caf)
+
+addLiveVar :: LiveInfo -> Id -> LiveInfo
+addLiveVar (lvs, cafs) id = (lvs `extendVarSet` id, cafs)
+
+unionLiveInfo :: LiveInfo -> LiveInfo -> LiveInfo
+unionLiveInfo (lv1,caf1) (lv2,caf2) = (lv1 `unionVarSet` lv2, caf1 `unionVarSet` caf2)
+
+mkSRT :: LiveInfo -> SRT
+mkSRT (_, cafs) = SRTEntries cafs
+
+getLiveVars :: LiveInfo -> StgLiveVars
+getLiveVars (lvs, _) = lvs
+\end{code}
+
+
 The std monad functions:
 \begin{code}
 initLne :: IdEnv HowBound -> LneM a -> a
 The std monad functions:
 \begin{code}
 initLne :: IdEnv HowBound -> LneM a -> a
-initLne env m = m env emptyLVS
+initLne env m = m env emptyLiveInfo
+
 
 
-emptyLVS = (emptyVarSet,emptyVarSet)
 
 {-# INLINE thenLne #-}
 {-# INLINE returnLne #-}
 
 {-# INLINE thenLne #-}
 {-# INLINE returnLne #-}
@@ -828,15 +879,7 @@ thenLne :: LneM a -> (a -> LneM b) -> LneM b
 thenLne m k env lvs_cont 
   = k (m env lvs_cont) env lvs_cont
 
 thenLne m k env lvs_cont 
   = k (m env lvs_cont) env lvs_cont
 
-mapLne  :: (a -> LneM b)   -> [a] -> LneM [b]
-mapLne f [] = returnLne []
-mapLne f (x:xs)
-  = f x                `thenLne` \ r  ->
-    mapLne f xs        `thenLne` \ rs ->
-    returnLne (r:rs)
-
 mapAndUnzipLne  :: (a -> LneM (b,c))   -> [a] -> LneM ([b],[c])
 mapAndUnzipLne  :: (a -> LneM (b,c))   -> [a] -> LneM ([b],[c])
-
 mapAndUnzipLne f [] = returnLne ([],[])
 mapAndUnzipLne f (x:xs)
   = f x                        `thenLne` \ (r1,  r2)  ->
 mapAndUnzipLne f [] = returnLne ([],[])
 mapAndUnzipLne f (x:xs)
   = f x                        `thenLne` \ (r1,  r2)  ->
@@ -844,13 +887,19 @@ mapAndUnzipLne f (x:xs)
     returnLne (r1:rs1, r2:rs2)
 
 mapAndUnzip3Lne :: (a -> LneM (b,c,d)) -> [a] -> LneM ([b],[c],[d])
     returnLne (r1:rs1, r2:rs2)
 
 mapAndUnzip3Lne :: (a -> LneM (b,c,d)) -> [a] -> LneM ([b],[c],[d])
-
 mapAndUnzip3Lne f []   = returnLne ([],[],[])
 mapAndUnzip3Lne f (x:xs)
   = f x                         `thenLne` \ (r1,  r2,  r3)  ->
     mapAndUnzip3Lne f xs `thenLne` \ (rs1, rs2, rs3) ->
     returnLne (r1:rs1, r2:rs2, r3:rs3)
 
 mapAndUnzip3Lne f []   = returnLne ([],[],[])
 mapAndUnzip3Lne f (x:xs)
   = f x                         `thenLne` \ (r1,  r2,  r3)  ->
     mapAndUnzip3Lne f xs `thenLne` \ (rs1, rs2, rs3) ->
     returnLne (r1:rs1, r2:rs2, r3:rs3)
 
+mapAndUnzip4Lne :: (a -> LneM (b,c,d,e)) -> [a] -> LneM ([b],[c],[d],[e])
+mapAndUnzip4Lne f []   = returnLne ([],[],[],[])
+mapAndUnzip4Lne f (x:xs)
+  = f x                         `thenLne` \ (r1,  r2,  r3, r4)  ->
+    mapAndUnzip4Lne f xs `thenLne` \ (rs1, rs2, rs3, rs4) ->
+    returnLne (r1:rs1, r2:rs2, r3:rs3, r4:rs4)
+
 fixLne :: (a -> LneM a) -> LneM a
 fixLne expr env lvs_cont
   = result
 fixLne :: (a -> LneM a) -> LneM a
 fixLne expr env lvs_cont
   = result
@@ -861,10 +910,10 @@ fixLne expr env lvs_cont
 Functions specific to this monad:
 
 \begin{code}
 Functions specific to this monad:
 
 \begin{code}
-getVarsLiveInCont :: LneM (StgLiveVars, IdSet)
+getVarsLiveInCont :: LneM LiveInfo
 getVarsLiveInCont env lvs_cont = lvs_cont
 
 getVarsLiveInCont env lvs_cont = lvs_cont
 
-setVarsLiveInCont :: (StgLiveVars,IdSet) -> LneM a -> LneM a
+setVarsLiveInCont :: LiveInfo -> LneM a -> LneM a
 setVarsLiveInCont new_lvs_cont expr env lvs_cont
   = expr env new_lvs_cont
 
 setVarsLiveInCont new_lvs_cont expr env lvs_cont
   = expr env new_lvs_cont
 
@@ -873,45 +922,40 @@ extendVarEnvLne ids_w_howbound expr env lvs_cont
   = expr (extendVarEnvList env ids_w_howbound) lvs_cont
 
 lookupVarLne :: Id -> LneM HowBound
   = expr (extendVarEnvList env ids_w_howbound) lvs_cont
 
 lookupVarLne :: Id -> LneM HowBound
-lookupVarLne v env lvs_cont
-  = returnLne (
-      case (lookupVarEnv env v) of
-       Just xx -> xx
-       Nothing -> ImportBound
-    ) env lvs_cont
+lookupVarLne v env lvs_cont = returnLne (lookupBinding env v) env lvs_cont
+
+getEnvLne :: LneM (IdEnv HowBound)
+getEnvLne env lvs_cont = returnLne env env lvs_cont
+
+lookupBinding :: IdEnv HowBound -> Id -> HowBound
+lookupBinding env v = case lookupVarEnv env v of
+                       Just xx -> xx
+                       Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound
+
 
 -- The result of lookupLiveVarsForSet, a set of live variables, is
 -- only ever tacked onto a decorated expression. It is never used as
 -- the basis of a control decision, which might give a black hole.
 
 
 -- The result of lookupLiveVarsForSet, a set of live variables, is
 -- only ever tacked onto a decorated expression. It is never used as
 -- the basis of a control decision, which might give a black hole.
 
-freeVarsToLiveVars :: FreeVarsInfo -> LneM (StgLiveVars, IdSet)
+freeVarsToLiveVars :: FreeVarsInfo -> LneM LiveInfo
 freeVarsToLiveVars fvs env live_in_cont
 freeVarsToLiveVars fvs env live_in_cont
-  = returnLne (lvs, cafs) env live_in_cont
+  = returnLne live_info env live_in_cont
   where
   where
-    (lvs_cont, cafs_cont) = live_in_cont -- not a strict pattern match!
-    (local, global) = partition isLocalId (allFVs fvs)
-
-    (lvs_from_fvs, caf_extras) = unzip (map do_one local)
-
-    lvs = unionVarSets lvs_from_fvs
-               `unionVarSet` lvs_cont
-
-    cafs = mkVarSet (filter is_caf_one global) 
-               `unionVarSet` (unionVarSets caf_extras)
-               `unionVarSet` cafs_cont
-
-    do_one v
-      = case (lookupVarEnv env v) of
-             Just (LetBound _ (lvs,cafs) _) -> (extendVarSet lvs v, cafs)
-             Just _                         -> (unitVarSet v, emptyVarSet)
-             Nothing -> pprPanic "lookupLiveVarsForSet/do_one:" (ppr v)
-
-    is_caf_one v
-        = case lookupVarEnv env v of
-               Just (LetBound TopLevelHasCafs (lvs,_) _) ->
-                   ASSERT( isEmptyVarSet lvs ) True
-               Just (LetBound _ _ _) -> False
-               _otherwise          -> mayHaveCafRefs (idCafInfo v)
+    live_info    = foldr unionLiveInfo live_in_cont lvs_from_fvs
+    lvs_from_fvs = map do_one (allFreeIds fvs)
+
+    do_one (v, how_bound)
+      = case how_bound of
+         ImportBound                     -> unitLiveCaf v      -- Only CAF imports are 
+                                                               -- recorded in fvs
+         LetBound TopLet _              
+               | mayHaveCafRefs (idCafInfo v) -> unitLiveCaf v
+               | otherwise                    -> emptyLiveInfo
+
+         LetBound (NestedLet lvs) _      -> lvs        -- lvs already contains v
+                                                       -- (see the invariant on NestedLet)
+
+         _lambda_or_case_binding         -> unitLiveVar v      -- Bound by lambda or case
 \end{code}
 
 %************************************************************************
 \end{code}
 
 %************************************************************************
@@ -921,7 +965,21 @@ freeVarsToLiveVars fvs env live_in_cont
 %************************************************************************
 
 \begin{code}
 %************************************************************************
 
 \begin{code}
-type FreeVarsInfo = VarEnv (Var, TopLevelCafInfo, StgBinderInfo)
+type FreeVarsInfo = VarEnv (Var, HowBound, StgBinderInfo)
+       -- The Var is so we can gather up the free variables
+       -- as a set.
+       --
+       -- The HowBound info just saves repeated lookups;
+       -- we look up just once when we encounter the occurrence.
+       -- INVARIANT: Any ImportBound Ids are HaveCafRef Ids
+       --            Imported Ids without CAF refs are simply
+       --            not put in the FreeVarsInfo for an expression.
+       --            See singletonFVInfo and freeVarsToLiveVars
+       --
+       -- StgBinderInfo records how it occurs; notably, we
+       -- are interested in whether it only occurs in saturated 
+       -- applications, because then we don't need to build a
+       -- curried version.
        -- If f is mapped to noBinderInfo, that means
        -- that f *is* mentioned (else it wouldn't be in the
        -- IdEnv at all), but perhaps in an unsaturated applications.
        -- If f is mapped to noBinderInfo, that means
        -- that f *is* mentioned (else it wouldn't be in the
        -- IdEnv at all), but perhaps in an unsaturated applications.
@@ -932,14 +990,6 @@ type FreeVarsInfo = VarEnv (Var, TopLevelCafInfo, StgBinderInfo)
        --
        -- For ILX we track free var info for type variables too;
        -- hence VarEnv not IdEnv
        --
        -- For ILX we track free var info for type variables too;
        -- hence VarEnv not IdEnv
-
-data TopLevelCafInfo
-  = NotTopLevelBound
-  | TopLevelNoCafs
-  | TopLevelHasCafs
-  deriving Eq
-
-type EscVarsSet = IdSet
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
@@ -947,18 +997,17 @@ emptyFVInfo :: FreeVarsInfo
 emptyFVInfo = emptyVarEnv
 
 singletonFVInfo :: Id -> HowBound -> StgBinderInfo -> FreeVarsInfo
 emptyFVInfo = emptyVarEnv
 
 singletonFVInfo :: Id -> HowBound -> StgBinderInfo -> FreeVarsInfo
+-- Don't record non-CAF imports at all, to keep free-var sets small
 singletonFVInfo id ImportBound info
 singletonFVInfo id ImportBound info
-   | mayHaveCafRefs (idCafInfo id) = unitVarEnv id (id, TopLevelHasCafs, info)
+   | mayHaveCafRefs (idCafInfo id) = unitVarEnv id (id, ImportBound, info)
    | otherwise                            = emptyVarEnv
    | otherwise                            = emptyVarEnv
-singletonFVInfo id (LetBound top_level _ _) info 
-   = unitVarEnv id (id, top_level, info)
-singletonFVInfo id other info
-   = unitVarEnv id (id, NotTopLevelBound, info)
+singletonFVInfo id how_bound info  = unitVarEnv id (id, how_bound, info)
 
 tyvarFVInfo :: TyVarSet -> FreeVarsInfo
 tyvarFVInfo tvs = foldVarSet add emptyFVInfo tvs
         where
 
 tyvarFVInfo :: TyVarSet -> FreeVarsInfo
 tyvarFVInfo tvs = foldVarSet add emptyFVInfo tvs
         where
-         add tv fvs = extendVarEnv fvs tv (tv, NotTopLevelBound, noBinderInfo)
+         add tv fvs = extendVarEnv fvs tv (tv, LambdaBound, noBinderInfo)
+               -- Type variables must be lambda-bound
 
 unionFVInfo :: FreeVarsInfo -> FreeVarsInfo -> FreeVarsInfo
 unionFVInfo fv1 fv2 = plusVarEnv_C plusFVInfo fv1 fv2
 
 unionFVInfo :: FreeVarsInfo -> FreeVarsInfo -> FreeVarsInfo
 unionFVInfo fv1 fv2 = plusVarEnv_C plusFVInfo fv1 fv2
@@ -970,7 +1019,7 @@ minusFVBinders :: [Id] -> FreeVarsInfo -> FreeVarsInfo
 minusFVBinders vs fv = foldr minusFVBinder fv vs
 
 minusFVBinder :: Id -> FreeVarsInfo -> FreeVarsInfo
 minusFVBinders vs fv = foldr minusFVBinder fv vs
 
 minusFVBinder :: Id -> FreeVarsInfo -> FreeVarsInfo
-minusFVBinder v fv | isId v && opt_KeepStgTypes
+minusFVBinder v fv | isId v && opt_RuntimeTypes
                   = (fv `delVarEnv` v) `unionFVInfo` 
                     tyvarFVInfo (tyVarsOfType (idType v))
                   | otherwise = fv `delVarEnv` v
                   = (fv `delVarEnv` v) `unionFVInfo` 
                     tyvarFVInfo (tyVarsOfType (idType v))
                   | otherwise = fv `delVarEnv` v
@@ -984,30 +1033,45 @@ lookupFVInfo :: FreeVarsInfo -> Id -> StgBinderInfo
 -- Find how the given Id is used.
 -- Externally visible things may be used any old how
 lookupFVInfo fvs id 
 -- Find how the given Id is used.
 -- Externally visible things may be used any old how
 lookupFVInfo fvs id 
-  | isExternallyVisibleName (idName id) = noBinderInfo
+  | isExternalName (idName id) = noBinderInfo
   | otherwise = case lookupVarEnv fvs id of
                        Nothing         -> noBinderInfo
                        Just (_,_,info) -> info
 
   | otherwise = case lookupVarEnv fvs id of
                        Nothing         -> noBinderInfo
                        Just (_,_,info) -> info
 
-allFVs :: FreeVarsInfo -> [Id] -- Non-top-level things only
-allFVs fvs = [id | (id,_,_) <- rngVarEnv fvs]
+allFreeIds :: FreeVarsInfo -> [(Id,HowBound)]  -- Both top level and non-top-level Ids
+allFreeIds fvs = [(id,how_bound) | (id,how_bound,_) <- varEnvElts fvs, isId id]
 
 
-getFVs :: FreeVarsInfo -> [Id] -- Non-top-level things only
-getFVs fvs = [id | (id,NotTopLevelBound,_) <- rngVarEnv fvs]
+-- Non-top-level things only, both type variables and ids
+-- (type variables only if opt_RuntimeTypes)
+getFVs :: FreeVarsInfo -> [Var]        
+getFVs fvs = [id | (id, how_bound, _) <- varEnvElts fvs, 
+                   not (topLevelBound how_bound) ]
 
 
-getFVSet :: FreeVarsInfo -> IdSet
+getFVSet :: FreeVarsInfo -> VarSet
 getFVSet fvs = mkVarSet (getFVs fvs)
 
 getFVSet fvs = mkVarSet (getFVs fvs)
 
-plusFVInfo (id1,top1,info1) (id2,top2,info2)
-  = ASSERT (id1 == id2 && top1 == top2)
-    (id1, top1, combineStgBinderInfo info1 info2)
+plusFVInfo (id1,hb1,info1) (id2,hb2,info2)
+  = ASSERT (id1 == id2 && hb1 `check_eq_how_bound` hb2)
+    (id1, hb1, combineStgBinderInfo info1 info2)
+
+#ifdef DEBUG
+-- The HowBound info for a variable in the FVInfo should be consistent
+check_eq_how_bound ImportBound               ImportBound        = True
+check_eq_how_bound LambdaBound               LambdaBound        = True
+check_eq_how_bound (LetBound li1 ar1) (LetBound li2 ar2) = ar1 == ar2 && check_eq_li li1 li2
+check_eq_how_bound hb1               hb2                = False
+
+check_eq_li (NestedLet _) (NestedLet _) = True
+check_eq_li TopLet        TopLet        = True
+check_eq_li li1          li2           = False
+#endif
 \end{code}
 
 Misc.
 \begin{code}
 filterStgBinders :: [Var] -> [Var]
 filterStgBinders bndrs
 \end{code}
 
 Misc.
 \begin{code}
 filterStgBinders :: [Var] -> [Var]
 filterStgBinders bndrs
-  | opt_KeepStgTypes = bndrs
+  | opt_RuntimeTypes = bndrs
   | otherwise       = filter isId bndrs
 \end{code}
 
   | otherwise       = filter isId bndrs
 \end{code}
 
@@ -1035,125 +1099,9 @@ myCollectArgs expr
     go _               as = pprPanic "CoreToStg.myCollectArgs" (ppr expr)
 \end{code}
 
     go _               as = pprPanic "CoreToStg.myCollectArgs" (ppr expr)
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Figuring out CafInfo for an expression}
-%*                                                                     *
-%************************************************************************
-
-hasCafRefs decides whether a top-level closure can point into the dynamic heap.
-We mark such things as `MayHaveCafRefs' because this information is
-used to decide whether a particular closure needs to be referenced
-in an SRT or not.
-
-There are two reasons for setting MayHaveCafRefs:
-       a) The RHS is a CAF: a top-level updatable thunk.
-       b) The RHS refers to something that MayHaveCafRefs
-
-Possible improvement: In an effort to keep the number of CAFs (and 
-hence the size of the SRTs) down, we could also look at the expression and 
-decide whether it requires a small bounded amount of heap, so we can ignore 
-it as a CAF.  In these cases however, we would need to use an additional
-CAF list to keep track of non-collectable CAFs.  
-
 \begin{code}
 \begin{code}
-hasCafRefs  :: IdEnv HowBound -> CoreExpr -> CafInfo
--- Only called for the RHS of top-level lets
-hasCafRefss :: IdEnv HowBound -> [CoreExpr] -> CafInfo
-       -- predicate returns True for a given Id if we look at this Id when
-       -- calculating the result.  Used to *avoid* looking at the CafInfo
-       -- field for an Id that is part of the current recursive group.
-
-hasCafRefs p expr 
-  | isCAF expr || isFastTrue (cafRefs p expr) =  MayHaveCafRefs
-  | otherwise = NoCafRefs
-
-       -- used for recursive groups.  The whole group is set to
-       -- "MayHaveCafRefs" if at least one of the group is a CAF or
-       -- refers to any CAFs.
-hasCafRefss p exprs
-  | any isCAF exprs || isFastTrue (cafRefss p exprs) = MayHaveCafRefs
-  | otherwise = NoCafRefs
-
--- cafRefs compiles to beautiful code :)
-
-cafRefs p (Var id)
-  | isLocalId id = fastBool False
-  | otherwise = 
-      case lookupVarEnv p id of
-       Just (LetBound TopLevelHasCafs _ _) -> fastBool True
-        Just (LetBound _ _ _) -> fastBool False
-       Nothing -> fastBool (cgMayHaveCafRefs (idCgInfo id)) --  imported Ids
-
-cafRefs p (Lit l)           = fastBool False
-cafRefs p (App f a)         = fastOr (cafRefs p f) (cafRefs p) a
-cafRefs p (Lam x e)         = cafRefs p e
-cafRefs p (Let b e)         = fastOr (cafRefss p (rhssOfBind b)) (cafRefs p) e
-cafRefs p (Case e bndr alts) = fastOr (cafRefs p e)    
-                               (cafRefss p) (rhssOfAlts alts)
-cafRefs p (Note n e)        = cafRefs p e
-cafRefs p (Type t)          = fastBool False
-
-cafRefss p []    = fastBool False
-cafRefss p (e:es) = fastOr (cafRefs p e) (cafRefss p) es
-
--- hack for lazy-or over FastBool.
-fastOr a f x = fastBool (isFastTrue a || isFastTrue (f x))
-
-isCAF :: CoreExpr -> Bool
--- Only called for the RHS of top-level lets
-isCAF e = not (rhsIsNonUpd e)
-  {- ToDo: check type for onceness, i.e. non-updatable thunks? -}
-
-
-rhsIsNonUpd :: CoreExpr -> Bool
-  -- True => Value-lambda, constructor, PAP
-  -- This is a bit like CoreUtils.exprIsValue, with the following differences:
-  --   a) scc "foo" (\x -> ...) is updatable (so we catch the right SCC)
-  --
-  --    b) (C x xs), where C is a contructors is updatable if the application is
-  --      dynamic: see isDynConApp
-  -- 
-  --    c) don't look through unfolding of f in (f x).  I'm suspicious of this one
-
-rhsIsNonUpd (Lam b e)          = isId b || rhsIsNonUpd e
-rhsIsNonUpd (Note (SCC _) e)   = False
-rhsIsNonUpd (Note _ e)         = rhsIsNonUpd e
-rhsIsNonUpd other_expr
-  = go other_expr 0 []
-  where
-    go (Var f) n_args args = idAppIsNonUpd f n_args args
-       
-    go (App f a) n_args args
-       | isTypeArg a = go f n_args args
-       | otherwise   = go f (n_args + 1) (a:args)
-
-    go (Note (SCC _) f) n_args args = False
-    go (Note _ f) n_args args       = go f n_args args
-
-    go other n_args args = False
-
-idAppIsNonUpd :: Id -> Int -> [CoreExpr] -> Bool
-idAppIsNonUpd id n_val_args args
-  | Just con <- isDataConId_maybe id = not (isDynConApp con args)
-  | otherwise                       = n_val_args < idArity id
-
-isDynConApp :: DataCon -> [CoreExpr] -> Bool
-isDynConApp con args = isDllName (dataConName con) || any isDynArg args
--- Top-level constructor applications can usually be allocated 
--- statically, but they can't if 
---     a) the constructor, or any of the arguments, come from another DLL
---     b) any of the arguments are LitLits
--- (because we can't refer to static labels in other DLLs).
--- If this happens we simply make the RHS into an updatable thunk, 
--- and 'exectute' it rather than allocating it statically.
--- All this should match the decision in (see CoreToStg.coreToStgRhs)
-
-
-isDynArg :: CoreExpr -> Bool
-isDynArg (Var v)    = isDllName (idName v)
-isDynArg (Note _ e) = isDynArg e
-isDynArg (Lit lit)  = isLitLitLit lit
-isDynArg (App e _)  = isDynArg e       -- must be a type app
-isDynArg (Lam _ e)  = isDynArg e       -- must be a type lam
+stgArity :: Id -> HowBound -> Arity
+stgArity f (LetBound _ arity) = arity
+stgArity f ImportBound       = idArity f
+stgArity f LambdaBound        = 0
 \end{code}
 \end{code}