[project @ 2001-10-18 16:29:12 by simonpj]
[ghc-hetmet.git] / ghc / compiler / coreSyn / CoreTidy.lhs
index e959574..bc3dd71 100644 (file)
@@ -5,52 +5,52 @@
 
 \begin{code}
 module CoreTidy (
 
 \begin{code}
 module CoreTidy (
-       tidyCorePgm, tidyExpr, 
+       tidyCorePgm, tidyExpr, tidyCoreExpr,
        tidyBndr, tidyBndrs
     ) where
 
 #include "HsVersions.h"
 
        tidyBndr, tidyBndrs
     ) where
 
 #include "HsVersions.h"
 
-import CmdLineOpts     ( DynFlags, DynFlag(..), opt_OmitInterfacePragmas, dopt )
+import CmdLineOpts     ( DynFlags, DynFlag(..), opt_OmitInterfacePragmas )
 import CoreSyn
 import CoreUnfold      ( noUnfolding, mkTopUnfolding, okToUnfoldInHiFile )
 import CoreFVs         ( ruleSomeFreeVars, exprSomeFreeVars )
 import CoreSyn
 import CoreUnfold      ( noUnfolding, mkTopUnfolding, okToUnfoldInHiFile )
 import CoreFVs         ( ruleSomeFreeVars, exprSomeFreeVars )
+import PprCore         ( pprIdCoreRule )
 import CoreLint                ( showPass, endPass )
 import VarEnv
 import VarSet
 import Var             ( Id, Var )
 import CoreLint                ( showPass, endPass )
 import VarEnv
 import VarSet
 import Var             ( Id, Var )
-import Id              ( idType, idInfo, idName, isExportedId,
-                         mkVanillaId, mkId, isLocalId,
-                         setIdStrictness, setIdDemandInfo,
+import Id              ( idType, idInfo, idName, isExportedId, 
+                         idSpecialisation, idUnique, 
+                         mkVanillaGlobal, isLocalId, 
+                         isImplicitId, mkUserLocal, setIdInfo
                        ) 
                        ) 
-import IdInfo          ( constantIdInfo,
-                         specInfo, setSpecInfo, 
-                         cprInfo, setCprInfo,
-                         inlinePragInfo, setInlinePragInfo, isNeverInlinePrag,
-                         strictnessInfo, setStrictnessInfo, isBottomingStrictness,
-                         unfoldingInfo, setUnfoldingInfo, 
-                         demandInfo, 
-                         occInfo, isLoopBreaker,
-                         workerInfo, setWorkerInfo, WorkerInfo(..)
-                       )
+import IdInfo          {- loads of stuff -}
+import NewDemand       ( isBottomingSig, topSig )
+import BasicTypes      ( isNeverActive )
 import Name            ( getOccName, nameOccName, globaliseName, setNameOcc, 
 import Name            ( getOccName, nameOccName, globaliseName, setNameOcc, 
-                         localiseName, mkLocalName, isGlobalName
+                         localiseName, isGlobalName, setNameUnique
                        )
                        )
+import NameEnv         ( filterNameEnv )
 import OccName         ( TidyOccEnv, initTidyOccEnv, tidyOccName )
 import OccName         ( TidyOccEnv, initTidyOccEnv, tidyOccName )
-import Type            ( tidyTopType, tidyType, tidyTyVar )
+import Type            ( tidyTopType, tidyType, tidyTyVarBndr )
 import Module          ( Module, moduleName )
 import Module          ( Module, moduleName )
-import HscTypes                ( PersistentCompilerState( pcs_PRS ), PersistentRenamerState( prsOrig ),
-                         OrigNameEnv( origNames ), OrigNameNameEnv
+import HscTypes                ( PersistentCompilerState( pcs_PRS ), 
+                         PersistentRenamerState( prsOrig ),
+                         NameSupply( nsNames, nsUniqs ),
+                         TypeEnv, extendTypeEnvList, typeEnvIds,
+                         ModDetails(..), TyThing(..)
                        )
                        )
-import Unique          ( Uniquable(..) )
 import FiniteMap       ( lookupFM, addToFM )
 import FiniteMap       ( lookupFM, addToFM )
-import Maybes          ( maybeToBool, orElse )
-import ErrUtils                ( showPass )
+import Maybes          ( orElse )
+import ErrUtils                ( showPass, dumpIfSet_core )
 import SrcLoc          ( noSrcLoc )
 import UniqFM          ( mapUFM )
 import SrcLoc          ( noSrcLoc )
 import UniqFM          ( mapUFM )
-import Outputable
+import UniqSupply      ( splitUniqSupply, uniqFromSupply )
 import List            ( partition )
 import Util            ( mapAccumL )
 import List            ( partition )
 import Util            ( mapAccumL )
+import Maybe           ( isJust )
+import Outputable
 \end{code}
 
 
 \end{code}
 
 
@@ -79,27 +79,43 @@ exported with their unfoldings, so we produce not an IdSet but an
 IdEnv Bool
 
 
 IdEnv Bool
 
 
-
 Step 2: Tidy the program
 ~~~~~~~~~~~~~~~~~~~~~~~~
 Step 2: Tidy the program
 ~~~~~~~~~~~~~~~~~~~~~~~~
-Next we traverse the bindings top to bottom.  For each top-level
+Next we traverse the bindings top to bottom.  For each *top-level*
 binder
 
 binder
 
-  - Make all external Ids have Global names and vice versa
+ 1. Make it into a GlobalId
+
+ 2. Give it a system-wide Unique.
+    [Even non-exported things need system-wide Uniques because the
+    byte-code generator builds a single Name->BCO symbol table.]
+
+    We use the NameSupply kept in the PersistentRenamerState as the
+    source of such system-wide uniques.
+
+    For external Ids, use the original-name cache in the NameSupply 
+    to ensure that the unique assigned is the same as the Id had 
+    in any previous compilation run.
+  
+ 3. If it's an external Id, make it have a global Name, otherwise
+    make it have a local Name.
     This is used by the code generator to decide whether
     to make the label externally visible
 
     This is used by the code generator to decide whether
     to make the label externally visible
 
-  - Give external ids a "tidy" occurrence name.  This means
+ 4. Give external Ids a "tidy" occurrence name.  This means
     we can print them in interface files without confusing 
     "x" (unique 5) with "x" (unique 10).
   
     we can print them in interface files without confusing 
     "x" (unique 5) with "x" (unique 10).
   
-  - Give external Ids the same Unique as they had before
-    if the name is in the renamer's name cache
-  
-  - Give the Id its final IdInfo; in ptic, 
-       * Its flavour becomes ConstantId, reflecting the fact that
-         from now on we regard it as a constant, not local, Id
+ 5. Give it its UTTERLY FINAL IdInfo; in ptic, 
+       * Its IdDetails becomes VanillaGlobal, reflecting the fact that
+         from now on we regard it as a global, not local, Id
+
        * its unfolding, if it should have one
        * its unfolding, if it should have one
+       
+       * its arity, computed from the number of visible lambdas
+
+       * its CAF info, computed from what is free in its RHS
+
                
 Finally, substitute these new top-level binders consistently
 throughout, including in unfoldings.  We also tidy binders in
                
 Finally, substitute these new top-level binders consistently
 throughout, including in unfoldings.  We also tidy binders in
@@ -108,27 +124,19 @@ RHSs, so that they print nicely in interfaces.
 \begin{code}
 tidyCorePgm :: DynFlags -> Module
            -> PersistentCompilerState
 \begin{code}
 tidyCorePgm :: DynFlags -> Module
            -> PersistentCompilerState
-           -> [CoreBind] -> [IdCoreRule]
-           -> IO (PersistentCompilerState, [CoreBind], [IdCoreRule])
-tidyCorePgm dflags mod pcs binds_in orphans_in
+           -> CgInfoEnv                -- Information from the back end,
+                                       -- to be splatted into the IdInfo
+           -> ModDetails
+           -> IO (PersistentCompilerState, ModDetails)
+
+tidyCorePgm dflags mod pcs cg_info_env
+           (ModDetails { md_types = env_tc, md_insts = insts_tc, 
+                         md_binds = binds_in, md_rules = orphans_in })
   = do { showPass dflags "Tidy Core"
 
   = do { showPass dflags "Tidy Core"
 
-       ; let ext_ids = findExternalSet binds_in orphans_in
-
-       ; let ((orig_env', occ_env, subst_env), binds_out) 
-                 = mapAccumL (tidyTopBind mod ext_ids) init_tidy_env binds_in
-
-       ; let orphans_out = tidyIdRules (occ_env,subst_env) orphans_in
+       ; let ext_ids   = findExternalSet   binds_in orphans_in
+       ; let ext_rules = findExternalRules binds_in orphans_in ext_ids
 
 
-       ; let pcs' = pcs { pcs_PRS = prs { prsOrig = orig { origNames = orig_env' }}}
-
-       ; endPass dflags "Tidy Core" (dopt Opt_D_dump_simpl dflags || 
-                                     dopt Opt_D_verbose_core2core dflags)
-                 binds_out
-
-       ; return (pcs', binds_out, orphans_out)
-       }
-  where
        -- We also make sure to avoid any exported binders.  Consider
        --      f{-u1-} = 1     -- Local decl
        --      ...
        -- We also make sure to avoid any exported binders.  Consider
        --      f{-u1-} = 1     -- Local decl
        --      ...
@@ -137,31 +145,137 @@ tidyCorePgm dflags mod pcs binds_in orphans_in
        -- The second exported decl must 'get' the name 'f', so we
        -- have to put 'f' in the avoids list before we get to the first
        -- decl.  tidyTopId then does a no-op on exported binders.
        -- The second exported decl must 'get' the name 'f', so we
        -- have to put 'f' in the avoids list before we get to the first
        -- decl.  tidyTopId then does a no-op on exported binders.
-    prs                  = pcs_PRS pcs
-    orig         = prsOrig prs
-    orig_env     = origNames orig
+       ; let   prs           = pcs_PRS pcs
+               orig_ns       = prsOrig prs
+
+               init_tidy_env = (orig_ns, initTidyOccEnv avoids, emptyVarEnv)
+               avoids        = [getOccName name | bndr <- typeEnvIds env_tc,
+                                                  let name = idName bndr,
+                                                  isGlobalName name]
+               -- In computing our "avoids" list, we must include
+               --      all implicit Ids
+               --      all things with global names (assigned once and for
+               --                                      all by the renamer)
+               -- since their names are "taken".
+               -- The type environment is a convenient source of such things.
+
+       ; let ((orig_ns', occ_env, subst_env), tidy_binds) 
+                       = mapAccumL (tidyTopBind mod ext_ids cg_info_env) 
+                                   init_tidy_env binds_in
+
+       ; let tidy_rules = tidyIdRules (occ_env,subst_env) ext_rules
+
+       ; let prs' = prs { prsOrig = orig_ns' }
+             pcs' = pcs { pcs_PRS = prs' }
+
+       ; let final_ids  = [ id 
+                          | bind <- tidy_binds
+                          , id <- bindersOf bind
+                          , isGlobalName (idName id)]
+
+               -- Dfuns are local Ids that might have
+               -- changed their unique during tidying
+       ; let lookup_dfun_id id = lookupVarEnv subst_env id `orElse` 
+                                 pprPanic "lookup_dfun_id" (ppr id)
+
+
+       ; let tidy_type_env = mkFinalTypeEnv env_tc final_ids
+             tidy_dfun_ids = map lookup_dfun_id insts_tc
+
+       ; let tidy_details = ModDetails { md_types = tidy_type_env,
+                                         md_rules = tidy_rules,
+                                         md_insts = tidy_dfun_ids,
+                                         md_binds = tidy_binds }
+
+       ; endPass dflags "Tidy Core" Opt_D_dump_simpl tidy_binds
+       ; dumpIfSet_core dflags Opt_D_dump_simpl
+               "Tidy Core Rules"
+               (vcat (map pprIdCoreRule tidy_rules))
+
+       ; return (pcs', tidy_details)
+       }
 
 
-    init_tidy_env = (orig_env, initTidyOccEnv avoids, emptyVarEnv)
-    avoids       = [getOccName bndr | bndr <- bindersOfBinds binds_in,
-                                      isGlobalName (idName bndr)]
+tidyCoreExpr :: CoreExpr -> IO CoreExpr
+tidyCoreExpr expr = return (tidyExpr emptyTidyEnv expr)
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
+\subsection{Write a new interface file}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+mkFinalTypeEnv :: TypeEnv      -- From typechecker
+              -> [Id]          -- Final Ids
+              -> TypeEnv
+
+mkFinalTypeEnv type_env final_ids
+  = extendTypeEnvList (filterNameEnv keep_it type_env)
+                     (map AnId final_ids)
+  where
+       -- The competed type environment is gotten from
+       --      a) keeping the types and classes
+       --      b) removing all Ids, 
+       --      c) adding Ids with correct IdInfo, including unfoldings,
+       --              gotten from the bindings
+       -- From (c) we keep only those Ids with Global names;
+       --          the CoreTidy pass makes sure these are all and only
+       --          the externally-accessible ones
+       -- This truncates the type environment to include only the 
+       -- exported Ids and things needed from them, which saves space
+       --
+       -- However, we do keep things like constructors, which should not appear 
+       -- in interface files, because they are needed by importing modules when
+       -- using the compilation manager
+
+       -- We keep implicit Ids, because they won't appear 
+       -- in the bindings from which final_ids are derived!
+    keep_it (AnId id) = isImplicitId id        -- Remove all Ids except implicit ones
+    keep_it other     = True           -- Keep all TyCons and Classes
+\end{code}
+
+\begin{code}
+findExternalRules :: [CoreBind]
+                 -> [IdCoreRule] -- Orphan rules
+                 -> IdEnv a      -- Ids that are exported, so we need their rules
+                 -> [IdCoreRule]
+  -- The complete rules are gotten by combining
+  --   a) the orphan rules
+  --   b) rules embedded in the top-level Ids
+findExternalRules binds orphan_rules ext_ids
+  | opt_OmitInterfacePragmas = []
+  | otherwise
+  = orphan_rules ++ local_rules
+  where
+    local_rules  = [ (id, rule)
+                  | id <- bindersOfBinds binds,
+                    id `elemVarEnv` ext_ids,
+                    rule <- rulesRules (idSpecialisation id),
+                    not (isBuiltinRule rule)
+                       -- We can't print builtin rules in interface files
+                       -- Since they are built in, an importing module
+                       -- will have access to them anyway
+                ]
+\end{code}
+
+%************************************************************************
+%*                                                                     *
 \subsection{Step 1: finding externals}
 %*                                                                     * 
 %************************************************************************
 
 \begin{code}
 findExternalSet :: [CoreBind] -> [IdCoreRule]
 \subsection{Step 1: finding externals}
 %*                                                                     * 
 %************************************************************************
 
 \begin{code}
 findExternalSet :: [CoreBind] -> [IdCoreRule]
-               -> IdEnv Bool   -- True <=> show unfolding
+               -> IdEnv Bool   -- In domain => external
+                               -- Range = True <=> show unfolding
        -- Step 1 from the notes above
 findExternalSet binds orphan_rules
   = foldr find init_needed binds
   where
     orphan_rule_ids :: IdSet
        -- Step 1 from the notes above
 findExternalSet binds orphan_rules
   = foldr find init_needed binds
   where
     orphan_rule_ids :: IdSet
-    orphan_rule_ids = unionVarSets [ ruleSomeFreeVars isIdAndLocal rule 
+    orphan_rule_ids = unionVarSets [ ruleSomeFreeVars isLocalId rule 
                                   | (_, rule) <- orphan_rules]
     init_needed :: IdEnv Bool
     init_needed = mapUFM (\_ -> False) orphan_rule_ids
                                   | (_, rule) <- orphan_rules]
     init_needed :: IdEnv Bool
     init_needed = mapUFM (\_ -> False) orphan_rule_ids
@@ -189,8 +303,6 @@ findExternalSet binds orphan_rules
     need_id needed_set id       = id `elemVarEnv` needed_set || isExportedId id 
     need_pr needed_set (id,rhs)        = need_id needed_set id
 
     need_id needed_set id       = id `elemVarEnv` needed_set || isExportedId id 
     need_pr needed_set (id,rhs)        = need_id needed_set id
 
-isIdAndLocal id = isId id && isLocalId id
-
 addExternal :: (Id,CoreExpr) -> IdEnv Bool -> IdEnv Bool
 -- The Id is needed; extend the needed set
 -- with it and its dependents (free vars etc)
 addExternal :: (Id,CoreExpr) -> IdEnv Bool -> IdEnv Bool
 -- The Id is needed; extend the needed set
 -- with it and its dependents (free vars etc)
@@ -208,9 +320,9 @@ addExternal (id,rhs) needed
                                                spec_ids
 
     idinfo        = idInfo id
                                                spec_ids
 
     idinfo        = idInfo id
-    dont_inline           = isNeverInlinePrag (inlinePragInfo idinfo)
+    dont_inline           = isNeverActive (inlinePragInfo idinfo)
     loop_breaker   = isLoopBreaker (occInfo idinfo)
     loop_breaker   = isLoopBreaker (occInfo idinfo)
-    bottoming_fn   = isBottomingStrictness (strictnessInfo idinfo)
+    bottoming_fn   = isBottomingSig (newStrictnessInfo idinfo `orElse` topSig)
     spec_ids      = rulesRhsFreeVars (specInfo idinfo)
     worker_info           = workerInfo idinfo
 
     spec_ids      = rulesRhsFreeVars (specInfo idinfo)
     worker_info           = workerInfo idinfo
 
@@ -230,7 +342,7 @@ addExternal (id,rhs) needed
                  rhs_is_small           &&     -- Small enough
                  okToUnfoldInHiFile rhs        -- No casms etc
 
                  rhs_is_small           &&     -- Small enough
                  okToUnfoldInHiFile rhs        -- No casms etc
 
-    unfold_ids | show_unfold = exprSomeFreeVars isIdAndLocal rhs
+    unfold_ids | show_unfold = exprSomeFreeVars isLocalId rhs
               | otherwise   = emptyVarSet
 
     worker_ids = case worker_info of
               | otherwise   = emptyVarSet
 
     worker_ids = case worker_info of
@@ -247,55 +359,68 @@ addExternal (id,rhs) needed
 
 
 \begin{code}
 
 
 \begin{code}
-type TopTidyEnv = (OrigNameNameEnv, TidyOccEnv, VarEnv Var)
+type TopTidyEnv = (NameSupply, TidyOccEnv, VarEnv Var)
 
 -- TopTidyEnv: when tidying we need to know
 
 -- TopTidyEnv: when tidying we need to know
---   * orig_env: Any pre-ordained Names.  These may have arisen because the
+--   * ns: The NameSupply, containing a unique supply and any pre-ordained Names.  
+--       These may have arisen because the
 --       renamer read in an interface file mentioning M.$wf, say,
 --       and assigned it unique r77.  If, on this compilation, we've
 --       invented an Id whose name is $wf (but with a different unique)
 --       we want to rename it to have unique r77, so that we can do easy
 --       comparisons with stuff from the interface file
 --       renamer read in an interface file mentioning M.$wf, say,
 --       and assigned it unique r77.  If, on this compilation, we've
 --       invented an Id whose name is $wf (but with a different unique)
 --       we want to rename it to have unique r77, so that we can do easy
 --       comparisons with stuff from the interface file
-
---   * occ_env: The TidyOccEnv, which tells us which local occurrences are 'used'
-
+--
+--   * occ_env: The TidyOccEnv, which tells us which local occurrences 
+--     are 'used'
+--
 --   * subst_env: A Var->Var mapping that substitutes the new Var for the old
 \end{code}
 
 
 \begin{code}
 tidyTopBind :: Module
 --   * subst_env: A Var->Var mapping that substitutes the new Var for the old
 \end{code}
 
 
 \begin{code}
 tidyTopBind :: Module
-           -> IdEnv Bool       -- Domain = Ids that should be exernal
+           -> IdEnv Bool       -- Domain = Ids that should be external
                                -- True <=> their unfolding is external too
                                -- True <=> their unfolding is external too
+           -> CgInfoEnv
            -> TopTidyEnv -> CoreBind
            -> (TopTidyEnv, CoreBind)
 
            -> TopTidyEnv -> CoreBind
            -> (TopTidyEnv, CoreBind)
 
-tidyTopBind mod ext_ids env (NonRec bndr rhs)
-  = (env', NonRec bndr' rhs')
+tidyTopBind mod ext_ids cg_info_env top_tidy_env (NonRec bndr rhs)
+  = ((orig,occ,subst) , NonRec bndr' rhs')
   where
   where
-    rhs'         = tidyTopRhs env rhs
-    (env', bndr') = tidyTopBinder mod ext_ids env rhs' env bndr
+    ((orig,occ,subst), bndr')
+        = tidyTopBinder mod ext_ids cg_info_env 
+                        rec_tidy_env rhs' top_tidy_env bndr
+    rec_tidy_env = (occ,subst)
+    rhs' = tidyExpr rec_tidy_env rhs
 
 
-tidyTopBind mod ext_ids env (Rec prs)
+tidyTopBind mod ext_ids cg_info_env top_tidy_env (Rec prs)
   = (final_env, Rec prs')
   where
   = (final_env, Rec prs')
   where
-    (final_env, prs')     = mapAccumL do_one env prs
-    do_one env (bndr,rhs) = (env', (bndr', rhs'))
-                         where
-                           rhs'          = tidyTopRhs final_env rhs
-                           (env', bndr') = tidyTopBinder mod ext_ids final_env
-                                                         rhs env bndr
-
-tidyTopRhs :: TopTidyEnv -> CoreExpr -> CoreExpr
-       -- Just an impedence matcher
-tidyTopRhs (_, occ_env, subst_env) rhs = tidyExpr (occ_env, subst_env) rhs
-
-tidyTopBinder :: Module -> IdEnv Bool
-             -> TopTidyEnv -> CoreExpr
+    (final_env@(_,occ,subst), prs') = mapAccumL do_one top_tidy_env prs
+    rec_tidy_env = (occ,subst)
+
+    do_one top_tidy_env (bndr,rhs) 
+       = ((orig,occ,subst), (bndr',rhs'))
+       where
+       ((orig,occ,subst), bndr')
+          = tidyTopBinder mod ext_ids cg_info_env
+               rec_tidy_env rhs' top_tidy_env bndr
+
+        rhs' = tidyExpr rec_tidy_env rhs
+
+tidyTopBinder :: Module -> IdEnv Bool -> CgInfoEnv
+             -> TidyEnv -> CoreExpr
+                       -- The TidyEnv is used to tidy the IdInfo
+                       -- The expr is the already-tided RHS
+                       -- Both are knot-tied: don't look at them!
              -> TopTidyEnv -> Id -> (TopTidyEnv, Id)
              -> TopTidyEnv -> Id -> (TopTidyEnv, Id)
-tidyTopBinder mod ext_ids env_idinfo rhs (orig_env, occ_env, subst_env) id
+  -- NB: tidyTopBinder doesn't affect the unique supply
+
+tidyTopBinder mod ext_ids cg_info_env rec_tidy_env rhs
+             env@(ns2, occ_env2, subst_env2) id
        -- This function is the heart of Step 2
        -- This function is the heart of Step 2
-       -- The second env is the one to use for the IdInfo
+       -- The rec_tidy_env is the one to use for the IdInfo
        -- It's necessary because when we are dealing with a recursive
        -- group, a variable late in the group might be mentioned
        -- in the IdInfo of one early in the group
        -- It's necessary because when we are dealing with a recursive
        -- group, a variable late in the group might be mentioned
        -- in the IdInfo of one early in the group
@@ -304,85 +429,133 @@ tidyTopBinder mod ext_ids env_idinfo rhs (orig_env, occ_env, subst_env) id
        
   = ((orig_env', occ_env', subst_env'), id')
   where
        
   = ((orig_env', occ_env', subst_env'), id')
   where
-    (orig_env', occ_env', name') = tidyTopName mod orig_env occ_env 
+    (orig_env', occ_env', name') = tidyTopName mod ns2 occ_env2
                                               is_external
                                               (idName id)
                                               is_external
                                               (idName id)
-    ty'               = tidyTopType (idType id)
-    idinfo'    = tidyIdInfo env_idinfo is_external unfold_info id
-    id'               = mkId name' ty' idinfo'
-    subst_env' = extendVarEnv subst_env id id'
+    ty'           = tidyTopType (idType id)
+    idinfo = tidyTopIdInfo rec_tidy_env is_external 
+                          (idInfo id) unfold_info
+                          (lookupCgInfo cg_info_env name')
+
+    id' = mkVanillaGlobal name' ty' idinfo
+
+    subst_env' = extendVarEnv subst_env2 id id'
 
     maybe_external = lookupVarEnv ext_ids id
 
     maybe_external = lookupVarEnv ext_ids id
-    is_external    = maybeToBool maybe_external
+    is_external    = isJust maybe_external
 
     -- Expose an unfolding if ext_ids tells us to
     show_unfold = maybe_external `orElse` False
     unfold_info | show_unfold = mkTopUnfolding rhs
                | otherwise   = noUnfolding
 
 
     -- Expose an unfolding if ext_ids tells us to
     show_unfold = maybe_external `orElse` False
     unfold_info | show_unfold = mkTopUnfolding rhs
                | otherwise   = noUnfolding
 
-tidyIdInfo (_, occ_env, subst_env) is_external unfold_info id
 
 
+-- tidyTopIdInfo creates the final IdInfo for top-level
+-- binders.  There are two delicate pieces:
+--
+--  * Arity.  We assume that the simplifier has just run, so
+--     that there is a reasonable arity on each binder.
+--     After CoreTidy, this arity must not change any more.
+--     Indeed, CorePrep must eta expand where necessary to make
+--     the manifest arity equal to the claimed arity.
+--
+-- * CAF info, which comes from the CoreToStg pass via a knot.
+--     The CAF info will not be looked at by the downstream stuff:
+--     it *generates* it, and knot-ties it back.  It will only be
+--     looked at by (a) MkIface when generating an interface file
+--                  (b) In GHCi, importing modules
+--     Nevertheless, we add the info here so that it propagates to all
+--     occurrences of the binders in RHSs, and hence to occurrences in
+--     unfoldings, which are inside Ids imported by GHCi. Ditto RULES.
+--     
+--     An alterative would be to do a second pass over the unfoldings 
+--     of Ids, and rules, right at the top, but that would be a pain.
+
+tidyTopIdInfo tidy_env is_external idinfo unfold_info cg_info
   | opt_OmitInterfacePragmas || not is_external
   | opt_OmitInterfacePragmas || not is_external
-       -- No IdInfo if the Id isn't 
-  = constantIdInfo
-
-  | otherwise
-  = constantIdInfo `setCprInfo`         cprInfo core_idinfo
-                  `setStrictnessInfo`   strictnessInfo core_idinfo
-                  `setInlinePragInfo`   inlinePragInfo core_idinfo
-                  `setUnfoldingInfo`    unfold_info
-                  `setWorkerInfo`       tidyWorker tidy_env (workerInfo core_idinfo)
-                  `setSpecInfo`         tidyRules tidy_env (specInfo core_idinfo)
-  where
-    tidy_env    = (occ_env, subst_env)
-    core_idinfo = idInfo id
-
-tidyTopName mod orig_env occ_env external name
-  | global && internal = (orig_env, occ_env,  localiseName name)
-  | local  && internal = (orig_env, occ_env', setNameOcc name occ')
-  | global && external = (orig_env, occ_env,  name)
-  | local  && external = globalise
+       -- Only basic info if the Id isn't external, or if we don't have -O
+  = basic_info
+
+  | otherwise  -- Add extra optimisation info
+  = basic_info
+       `setInlinePragInfo`    inlinePragInfo idinfo
+       `setUnfoldingInfo`     unfold_info
+       `setWorkerInfo`        tidyWorker tidy_env (workerInfo idinfo)
+               -- NB: we throw away the Rules
+               -- They have already been extracted by findExternalRules
+  
   where
   where
+       -- baasic_info is attached to every top-level binder
+    basic_info = vanillaIdInfo 
+                       `setCgInfo`            cg_info
+                       `setArityInfo`         arityInfo idinfo
+                       `setNewStrictnessInfo` newStrictnessInfo idinfo
+
+-- This is where we set names to local/global based on whether they really are 
+-- externally visible (see comment at the top of this module).  If the name
+-- was previously local, we have to give it a unique occurrence name if
+-- we intend to globalise it.
+tidyTopName mod ns occ_env external name
+  | global && internal = (ns, occ_env, localiseName name)
+
+  | global && external = (ns, occ_env, name)
+       -- Global names are assumed to have been allocated by the renamer,
+       -- so they already have the "right" unique
+       -- And it's a system-wide unique too
+
+  | local  && internal = (ns { nsUniqs = us2 }, occ_env', unique_name)
+       -- Even local, internal names must get a unique occurrence, because
+       -- if we do -split-objs we globalise the name later, in the code generator
+       --
+       -- Similarly, we must make sure it has a system-wide Unique, because
+       -- the byte-code generator builds a system-wide Name->BCO symbol table
+
+  | local  && external = case lookupFM ns_names key of
+                          Just orig -> (ns,                                        occ_env', orig)
+                          Nothing   -> (ns { nsUniqs = us2, nsNames = ns_names' }, occ_env', global_name)
        -- If we want to globalise a currently-local name, check
        -- whether we have already assigned a unique for it.
        -- If we want to globalise a currently-local name, check
        -- whether we have already assigned a unique for it.
-       -- If so, use it; if not, extend the table
-    globalise = case lookupFM orig_env key of
-                 Just orig -> (orig_env,                         occ_env', orig)
-                 Nothing   -> (addToFM orig_env key global_name, occ_env', global_name)
+       -- If so, use it; if not, extend the table.
+       -- This is needed when *re*-compiling a module in GHCi; we want to
+       -- use the same name for externally-visible things as we did before.
 
 
-    (occ_env', occ') = tidyOccName occ_env (nameOccName name)
-    key                     = (moduleName mod, occ')
-    global_name      = globaliseName (setNameOcc name occ') mod
+  where
     global          = isGlobalName name
     local           = not global
     internal        = not external
 
     global          = isGlobalName name
     local           = not global
     internal        = not external
 
-tidyIdRules :: TidyEnv -> [IdCoreRule] -> [IdCoreRule]
-tidyIdRules env rules
-  = [ (tidyVarOcc env fn, tidyRule env rule) | (fn,rule) <- rules  ]
+    (occ_env', occ') = tidyOccName occ_env (nameOccName name)
+    key                     = (moduleName mod, occ')
+    ns_names        = nsNames ns
+    ns_uniqs        = nsUniqs ns
+    (us1, us2)      = splitUniqSupply ns_uniqs
+    unique_name             = setNameUnique (setNameOcc name occ') (uniqFromSupply us1)
+    global_name      = globaliseName unique_name mod
+    ns_names'       = addToFM ns_names key global_name
 
 
 
 
+------------  Worker  --------------
 tidyWorker tidy_env (HasWorker work_id wrap_arity) 
   = HasWorker (tidyVarOcc tidy_env work_id) wrap_arity
 tidyWorker tidy_env (HasWorker work_id wrap_arity) 
   = HasWorker (tidyVarOcc tidy_env work_id) wrap_arity
-tidyWorker tidy_env NoWorker
+tidyWorker tidy_env other
   = NoWorker
 
   = NoWorker
 
-tidyRules :: TidyEnv -> CoreRules -> CoreRules
-tidyRules env (Rules rules fvs) 
-  = Rules (map (tidyRule env) rules)
-         (foldVarSet tidy_set_elem emptyVarSet fvs)
-  where
-    tidy_set_elem var new_set = extendVarSet new_set (tidyVarOcc env var)
+------------  Rules  --------------
+tidyIdRules :: TidyEnv -> [IdCoreRule] -> [IdCoreRule]
+tidyIdRules env [] = []
+tidyIdRules env ((fn,rule) : rules)
+  = tidyRule env rule                  =: \ rule ->
+    tidyIdRules env rules      =: \ rules ->
+     ((tidyVarOcc env fn, rule) : rules)
 
 tidyRule :: TidyEnv -> CoreRule -> CoreRule
 
 tidyRule :: TidyEnv -> CoreRule -> CoreRule
-tidyRule env rule@(BuiltinRule _) = rule
-tidyRule env (Rule name vars tpl_args rhs)
-  = (Rule name vars' (map (tidyExpr env') tpl_args) (tidyExpr env' rhs))
-  where
-    (env', vars') = tidyBndrs env vars
+tidyRule env rule@(BuiltinRule _ _) = rule
+tidyRule env (Rule name act vars tpl_args rhs)
+  = tidyBndrs env vars                 =: \ (env', vars) ->
+    map (tidyExpr env') tpl_args       =: \ tpl_args ->
+     (Rule name act vars tpl_args (tidyExpr env' rhs))
 \end{code}
 
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection{Step 2: inner tidying
 %************************************************************************
 %*                                                                     *
 \subsection{Step 2: inner tidying
@@ -392,51 +565,42 @@ tidyRule env (Rule name vars tpl_args rhs)
 \begin{code}
 tidyBind :: TidyEnv
         -> CoreBind
 \begin{code}
 tidyBind :: TidyEnv
         -> CoreBind
-        -> (TidyEnv, CoreBind)
+        ->  (TidyEnv, CoreBind)
+
 tidyBind env (NonRec bndr rhs)
 tidyBind env (NonRec bndr rhs)
-  = let
-       (env', bndr') = tidyBndr env bndr
-       rhs'          = tidyExpr env' rhs
-       -- We use env' when tidying the RHS even though it's not
-       -- strictly necessary; it makes the tidied code pretty 
-       -- hard to read if we don't!
-    in
-    (env', NonRec bndr' rhs')
+  = tidyLetBndr env (bndr,rhs)         =: \ (env', bndr') ->
+    (env', NonRec bndr' (tidyExpr env' rhs))
 
 tidyBind env (Rec prs)
 
 tidyBind env (Rec prs)
-  = (final_env, Rec prs')
-  where
-    (final_env, prs')     = mapAccumL do_one env prs
-    do_one env (bndr,rhs) = (env', (bndr', rhs'))
-                         where
-                           (env', bndr') = tidyBndr env bndr
-                           rhs'          = tidyExpr final_env rhs
+  = mapAccumL tidyLetBndr env prs      =: \ (env', bndrs') ->
+    map (tidyExpr env') (map snd prs)  =: \ rhss' ->
+    (env', Rec (zip bndrs' rhss'))
 
 
-tidyExpr env (Type ty)      = Type (tidyType env ty)
-tidyExpr env (Lit lit)      = Lit lit
-tidyExpr env (App f a)       = App (tidyExpr env f) (tidyExpr env a)
-tidyExpr env (Note n e)      = Note (tidyNote env n) (tidyExpr env e)
 
 
-tidyExpr env (Let b e)       = Let b' (tidyExpr env' e)
-                            where
-                              (env', b') = tidyBind env b
+tidyExpr env (Var v)           =  Var (tidyVarOcc env v)
+tidyExpr env (Type ty)         =  Type (tidyType env ty)
+tidyExpr env (Lit lit)         =  Lit lit
+tidyExpr env (App f a)         =  App (tidyExpr env f) (tidyExpr env a)
+tidyExpr env (Note n e) =  Note (tidyNote env n) (tidyExpr env e)
 
 
-tidyExpr env (Case e b alts) = Case (tidyExpr env e) b' (map (tidyAlt env') alts)
-                            where
-                              (env', b') = tidyBndr env b
+tidyExpr env (Let b e) 
+  = tidyBind env b     =: \ (env', b') ->
+    Let b' (tidyExpr env' e)
 
 
-tidyExpr env (Var v)         = Var (tidyVarOcc env v)
+tidyExpr env (Case e b alts)
+  = tidyBndr env b     =: \ (env', b) ->
+    Case (tidyExpr env e) b (map (tidyAlt env') alts)
 
 
-tidyExpr env (Lam b e)      = Lam b' (tidyExpr env' e)
-                            where
-                              (env', b') = tidyBndr env b
+tidyExpr env (Lam b e)
+  = tidyBndr env b     =: \ (env', b) ->
+    Lam b (tidyExpr env' e)
 
 
-tidyAlt env (con, vs, rhs)   = (con, vs', tidyExpr env' rhs)
-                            where
-                              (env', vs') = tidyBndrs env vs
 
 
-tidyNote env (Coerce t1 t2)  = Coerce (tidyType env t1) (tidyType env t2)
+tidyAlt env (con, vs, rhs)
+  = tidyBndrs env vs   =: \ (env', vs) ->
+    (con, vs, tidyExpr env' rhs)
 
 
+tidyNote env (Coerce t1 t2)  = Coerce (tidyType env t1) (tidyType env t2)
 tidyNote env note            = note
 \end{code}
 
 tidyNote env note            = note
 \end{code}
 
@@ -452,35 +616,62 @@ tidyVarOcc (_, var_env) v = case lookupVarEnv var_env v of
                                  Just v' -> v'
                                  Nothing -> v
 
                                  Just v' -> v'
                                  Nothing -> v
 
+-- tidyBndr is used for lambda and case binders
 tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var)
 tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var)
-tidyBndr env var | isTyVar var = tidyTyVar env var
-                | otherwise   = tidyId    env var
+tidyBndr env var
+  | isTyVar var = tidyTyVarBndr env var
+  | otherwise   = tidyIdBndr env var
 
 tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var])
 tidyBndrs env vars = mapAccumL tidyBndr env vars
 
 
 tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var])
 tidyBndrs env vars = mapAccumL tidyBndr env vars
 
-tidyId :: TidyEnv -> Id -> (TidyEnv, Id)
-tidyId env@(tidy_env, var_env) id
+tidyLetBndr :: TidyEnv -> (Id, CoreExpr) -> (TidyEnv, Var)
+-- Used for local (non-top-level) let(rec)s
+tidyLetBndr env (id,rhs) 
+  = ((tidy_env,new_var_env), final_id)
+  where
+    ((tidy_env,var_env), new_id) = tidyIdBndr env id
+
+       -- We need to keep around any interesting strictness and demand info
+       -- because later on we may need to use it when converting to A-normal form.
+       -- eg.
+       --      f (g x),  where f is strict in its argument, will be converted
+       --      into  case (g x) of z -> f z  by CorePrep, but only if f still
+       --      has its strictness info.
+       --
+       -- Similarly for the demand info - on a let binder, this tells 
+       -- CorePrep to turn the let into a case.
+       --
+       -- Similarly arity info for eta expansion in CorePrep
+    final_id = new_id `setIdInfo` new_info
+    idinfo   = idInfo id
+    new_info = vanillaIdInfo 
+               `setArityInfo`          arityInfo idinfo
+               `setNewStrictnessInfo`  newStrictnessInfo idinfo
+               `setNewDemandInfo`      newDemandInfo idinfo
+
+    -- Override the env we get back from tidyId with the new IdInfo
+    -- so it gets propagated to the usage sites.
+    new_var_env = extendVarEnv var_env id final_id
+
+tidyIdBndr :: TidyEnv -> Id -> (TidyEnv, Id)
+tidyIdBndr env@(tidy_env, var_env) id
   =    -- Non-top-level variables
     let 
        -- Give the Id a fresh print-name, *and* rename its type
   =    -- Non-top-level variables
     let 
        -- Give the Id a fresh print-name, *and* rename its type
-       -- The SrcLoc isn't important now, though we could extract it from the Id
-       name'             = mkLocalName (getUnique id) occ' noSrcLoc
+       -- The SrcLoc isn't important now, 
+       -- though we could extract it from the Id
+       -- 
+       -- All nested Ids now have the same IdInfo, namely none,
+       -- which should save some space.
        (tidy_env', occ') = tidyOccName tidy_env (getOccName id)
         ty'              = tidyType env (idType id)
        (tidy_env', occ') = tidyOccName tidy_env (getOccName id)
         ty'              = tidyType env (idType id)
-       idinfo            = idInfo id
-       id'               = mkVanillaId name' ty'
-                           `setIdStrictness` strictnessInfo idinfo
-                           `setIdDemandInfo` demandInfo idinfo
-                       -- NB: This throws away the IdInfo of the Id, which we
-                       -- no longer need.  That means we don't need to
-                       -- run over it with env, nor renumber it.
-                       --
-                       -- The exception is strictness and demand info, which 
-                       -- is used to decide whether to use let or case for
-                       -- function arguments and let bindings
-
+       id'               = mkUserLocal occ' (idUnique id) ty' noSrcLoc
        var_env'          = extendVarEnv var_env id id'
     in
        var_env'          = extendVarEnv var_env id id'
     in
-    ((tidy_env', var_env'), id')
+     ((tidy_env', var_env'), id')
+\end{code}
+
+\begin{code}
+m =: k = m `seq` k m
 \end{code}
 \end{code}