[project @ 2001-11-01 13:20:05 by simonpj]
[ghc-hetmet.git] / ghc / compiler / simplCore / SetLevels.lhs
index ca22634..6cd9efb 100644 (file)
@@ -7,27 +7,39 @@
                        Overview
                ***************************
 
-* We attach binding levels to Core bindings, in preparation for floating
-  outwards (@FloatOut@).
+1. We attach binding levels to Core bindings, in preparation for floating
+   outwards (@FloatOut@).
 
-* We also let-ify many expressions (notably case scrutinees), so they
-  will have a fighting chance of being floated sensible.
+2. We also let-ify many expressions (notably case scrutinees), so they
+   will have a fighting chance of being floated sensible.
 
-* We clone the binders of any floatable let-binding, so that when it is
-  floated out it will be unique.  (This used to be done by the simplifier
-  but the latter now only ensures that there's no shadowing.)
-  NOTE: Very tiresomely, we must apply this substitution to
-       the rules stored inside a variable too.
+3. We clone the binders of any floatable let-binding, so that when it is
+   floated out it will be unique.  (This used to be done by the simplifier
+   but the latter now only ensures that there's no shadowing; indeed, even 
+   that may not be true.)
 
-  We do *not* clone top-level bindings, because some of them must not change,
-  but we *do* clone bindings that are heading for the top level
+   NOTE: this can't be done using the uniqAway idea, because the variable
+        must be unique in the whole program, not just its current scope,
+        because two variables in different scopes may float out to the
+        same top level place
 
-* In the expression
+   NOTE: Very tiresomely, we must apply this substitution to
+        the rules stored inside a variable too.
+
+   We do *not* clone top-level bindings, because some of them must not change,
+   but we *do* clone bindings that are heading for the top level
+
+4. In the expression
        case x of wild { p -> ...wild... }
-  we substitute x for wild in the RHS of the case alternatives:
+   we substitute x for wild in the RHS of the case alternatives:
        case x of wild { p -> ...x... }
-  This means that a sub-expression involving x is not "trapped" inside the RHS.
-  And it's not inconvenient because we already have a substitution.
+   This means that a sub-expression involving x is not "trapped" inside the RHS.
+   And it's not inconvenient because we already have a substitution.
+
+  Note that this is EXACTLY BACKWARDS from the what the simplifier does.
+  The simplifier tries to get rid of occurrences of x, in favour of wild,
+  in the hope that there will only be one remaining occurrence of x, namely
+  the scrutinee of the case, and we can inline it.  
 
 \begin{code}
 module SetLevels (
@@ -42,22 +54,20 @@ module SetLevels (
 
 import CoreSyn
 
-import CoreUtils       ( exprType, exprIsTrivial, exprIsBottom )
+import CoreUtils       ( exprType, exprIsTrivial, exprIsBottom, mkPiTypes )
 import CoreFVs         -- all of it
-import Id              ( Id, idType, idFreeTyVars, mkSysLocal, isOneShotLambda, modifyIdInfo, 
+import Subst
+import Id              ( Id, idType, mkSysLocal, isOneShotLambda, zapDemandIdInfo,
                          idSpecialisation, idWorkerInfo, setIdInfo
                        )
-import IdInfo          ( workerExists, vanillaIdInfo )
-import Var             ( Var, TyVar, setVarUnique )
-import VarEnv
-import Subst
+import IdInfo          ( workerExists, vanillaIdInfo, )
+import Var             ( Var )
 import VarSet
+import VarEnv
 import Name            ( getOccName )
 import OccName         ( occNameUserString )
-import Type            ( isUnLiftedType, mkPiType, Type )
+import Type            ( isUnLiftedType, Type )
 import BasicTypes      ( TopLevelFlag(..) )
-import VarSet
-import VarEnv
 import UniqSupply
 import Util            ( sortLt, isSingleton, count )
 import Outputable
@@ -70,7 +80,9 @@ import Outputable
 %************************************************************************
 
 \begin{code}
-data Level = Level Int -- Level number of enclosing lambdas
+data Level = InlineCtxt        -- A level that's used only for
+                       -- the context parameter ctxt_lvl
+          | Level Int  -- Level number of enclosing lambdas
                   Int  -- Number of big-lambda and/or case expressions between
                        -- here and the nearest enclosing lambda
 \end{code}
@@ -95,43 +107,69 @@ The main function @lvlExpr@ carries a ``context level'' (@ctxt_lvl@).
 That's meant to be the level number of the enclosing binder in the
 final (floated) program.  If the level number of a sub-expression is
 less than that of the context, then it might be worth let-binding the
-sub-expression so that it will indeed float. This context level starts
-at @Level 0 0@.
+sub-expression so that it will indeed float.  
+
+If you can float to level @Level 0 0@ worth doing so because then your
+allocation becomes static instead of dynamic.  We always start with
+context @Level 0 0@.  @InlineCtxt@ very similar to @Level 0 0@, but is
+used for one purpose: to say "don't float anything out of here".
+That's exactly what we want for the body of an INLINE, where we don't
+want to float anything out at all.  See notes with lvlMFE below.
+
 
 \begin{code}
 type LevelledExpr  = TaggedExpr Level
-type LevelledArg   = TaggedArg Level
 type LevelledBind  = TaggedBind Level
 
-tOP_LEVEL = Level 0 0
+tOP_LEVEL   = Level 0 0
+iNLINE_CTXT = InlineCtxt
 
 incMajorLvl :: Level -> Level
+incMajorLvl InlineCtxt                 = Level 1 0
 incMajorLvl (Level major minor) = Level (major+1) 0
 
 incMinorLvl :: Level -> Level
+incMinorLvl InlineCtxt                 = Level 0 1
 incMinorLvl (Level major minor) = Level major (minor+1)
 
 maxLvl :: Level -> Level -> Level
+maxLvl InlineCtxt l2  = l2
+maxLvl l1  InlineCtxt = l1
 maxLvl l1@(Level maj1 min1) l2@(Level maj2 min2)
   | (maj1 > maj2) || (maj1 == maj2 && min1 > min2) = l1
   | otherwise                                     = l2
 
 ltLvl :: Level -> Level -> Bool
+ltLvl any_lvl   InlineCtxt  = False
+ltLvl InlineCtxt (Level _ _) = True
 ltLvl (Level maj1 min1) (Level maj2 min2)
   = (maj1 < maj2) || (maj1 == maj2 && min1 < min2)
 
 ltMajLvl :: Level -> Level -> Bool
     -- Tells if one level belongs to a difft *lambda* level to another
+ltMajLvl any_lvl       InlineCtxt     = False
+ltMajLvl InlineCtxt    (Level maj2 _) = 0 < maj2
 ltMajLvl (Level maj1 _) (Level maj2 _) = maj1 < maj2
 
 isTopLvl :: Level -> Bool
 isTopLvl (Level 0 0) = True
-isTopLvl other       = False
+isTopLvl other      = False
+
+isInlineCtxt :: Level -> Bool
+isInlineCtxt InlineCtxt = True
+isInlineCtxt other     = False
 
 instance Outputable Level where
+  ppr InlineCtxt      = text "<INLINE>"
   ppr (Level maj min) = hcat [ char '<', int maj, char ',', int min, char '>' ]
+
+instance Eq Level where
+  InlineCtxt       == InlineCtxt        = True
+  (Level maj1 min1) == (Level maj2 min2) = maj1==maj2 && min1==min2
+  l1               == l2                = False
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection{Main level-setting code}
@@ -202,13 +240,18 @@ lvlExpr _ env (_, AnnVar v)   = returnLvl (lookupVar env v)
 lvlExpr _ env (_, AnnLit lit) = returnLvl (Lit lit)
 
 lvlExpr ctxt_lvl env (_, AnnApp fun arg)
-  = lvlExpr ctxt_lvl env fun           `thenLvl` \ fun' ->
+  = lvl_fun fun                                `thenLvl` \ fun' ->
     lvlMFE  False ctxt_lvl env arg     `thenLvl` \ arg' ->
     returnLvl (App fun' arg')
+  where
+    lvl_fun (_, AnnCase _ _ _) = lvlMFE True ctxt_lvl env fun
+    lvl_fun other             = lvlExpr ctxt_lvl env fun
+       -- We don't do MFE on partial applications generally,
+       -- but we do if the function is big and hairy, like a case
 
 lvlExpr ctxt_lvl env (_, AnnNote InlineMe expr)
-       -- Don't float anything out of an InlineMe
-  = lvlExpr tOP_LEVEL env expr                 `thenLvl` \ expr' ->
+-- Don't float anything out of an InlineMe; hence the iNLINE_CTXT
+  = lvlExpr iNLINE_CTXT env expr       `thenLvl` \ expr' ->
     returnLvl (Note InlineMe expr')
 
 lvlExpr ctxt_lvl env (_, AnnNote note expr)
@@ -243,7 +286,6 @@ lvlExpr ctxt_lvl env (_, AnnCase expr case_bndr alts)
     mapLvl (lvl_alt alts_env) alts     `thenLvl` \ alts' ->
     returnLvl (Case expr' (case_bndr, incd_lvl) alts')
   where
-      expr_type = exprType (deAnnotate expr)
       incd_lvl  = incMinorLvl ctxt_lvl
 
       lvl_alt alts_env (con, bs, rhs)
@@ -284,18 +326,11 @@ lvlMFE strict_ctxt ctxt_lvl env (_, AnnType ty)
 
 lvlMFE strict_ctxt ctxt_lvl env ann_expr@(fvs, _)
   |  isUnLiftedType ty                         -- Can't let-bind it
-  || not (dest_lvl `ltMajLvl` ctxt_lvl)                -- Does not escape a value lambda
-       -- A decision to float entails let-binding this thing, and we only do 
-       -- that if we'll escape a value lambda.  I considered doing it if it
-       -- would make the thing go to top level, but I found things like
-       --      concat = /\ a -> foldr ..a.. (++) []
-       -- was getting turned into
-       --      concat = /\ a -> lvl a
-       --      lvl    = /\ a -> foldr ..a.. (++) []
-       -- which is pretty stupid.  So for now at least, I don't let-bind things
-       -- simply because they could go to top level.
+  || not good_destination
   || exprIsTrivial expr                                -- Is trivial
   || (strict_ctxt && exprIsBottom expr)                -- Strict context and is bottom
+                                               --  e.g. \x -> error "foo"
+                                               -- No gain from floating this
   =    -- Don't float it out
     lvlExpr ctxt_lvl env ann_expr
 
@@ -309,6 +344,24 @@ lvlMFE strict_ctxt ctxt_lvl env ann_expr@(fvs, _)
     ty       = exprType expr
     dest_lvl = destLevel env fvs (isFunction ann_expr)
     abs_vars = abstractVars dest_lvl env fvs
+
+    good_destination =  dest_lvl `ltMajLvl` ctxt_lvl   -- Escapes a value lambda
+                    || (isTopLvl dest_lvl              -- Goes to the top
+                        && not (isInlineCtxt ctxt_lvl) -- Don't float out of an __inline__ context
+                        && not strict_ctxt)            --   or from a strict context   
+       -- A decision to float entails let-binding this thing, and we only do 
+       -- that if we'll escape a value lambda, or will go to the top level.
+       -- But beware (a):
+       --      x = __inline__ (f (g y))
+       -- Here we don't want to float the (g y); otherwise it'll get outside the
+       --      __inline__ envelope, and may never get inlined
+       --
+       -- Also beware (b):
+       --      concat = /\ a -> foldr ..a.. (++) []
+       -- was getting turned into
+       --      concat = /\ a -> lvl a
+       --      lvl    = /\ a -> foldr ..a.. (++) []
+       -- which is pretty stupid.  Hence the strict_ctxt test
 \end{code}
 
 
@@ -331,8 +384,8 @@ lvlBind :: TopLevelFlag             -- Used solely to decide whether to clone
 lvlBind top_lvl ctxt_lvl env (AnnNonRec bndr rhs@(rhs_fvs,_))
   | null abs_vars
   =    -- No type abstraction; clone existing binder
-    lvlExpr ctxt_lvl env rhs                   `thenLvl` \ rhs' ->
-    cloneVar top_lvl env bndr dest_lvl         `thenLvl` \ (env', bndr') ->
+    lvlExpr dest_lvl env rhs                   `thenLvl` \ rhs' ->
+    cloneVar top_lvl env bndr ctxt_lvl dest_lvl        `thenLvl` \ (env', bndr') ->
     returnLvl (NonRec (bndr', dest_lvl) rhs', env') 
 
   | otherwise
@@ -356,8 +409,8 @@ lvlBind top_lvl ctxt_lvl env (AnnNonRec bndr rhs@(rhs_fvs,_))
 \begin{code}
 lvlBind top_lvl ctxt_lvl env (AnnRec pairs)
   | null abs_vars
-  = cloneVars top_lvl env bndrs dest_lvl       `thenLvl` \ (new_env, new_bndrs) ->
-    mapLvl (lvlExpr ctxt_lvl new_env) rhss     `thenLvl` \ new_rhss ->
+  = cloneRecVars top_lvl env bndrs ctxt_lvl dest_lvl   `thenLvl` \ (new_env, new_bndrs) ->
+    mapLvl (lvlExpr ctxt_lvl new_env) rhss             `thenLvl` \ new_rhss ->
     returnLvl (Rec ((new_bndrs `zip` repeat dest_lvl) `zip` new_rhss), new_env)
 
   | isSingleton pairs && count isId abs_vars > 1
@@ -376,7 +429,7 @@ lvlBind top_lvl ctxt_lvl env (AnnRec pairs)
        (rhs_lvl, abs_vars_w_lvls) = lvlLamBndrs dest_lvl abs_vars
        rhs_env = extendLvlEnv env abs_vars_w_lvls
     in
-    cloneVar NotTopLevel rhs_env bndr rhs_lvl  `thenLvl` \ (rhs_env', new_bndr) ->
+    cloneVar NotTopLevel rhs_env bndr rhs_lvl rhs_lvl  `thenLvl` \ (rhs_env', new_bndr) ->
     let
        (lam_bndrs, rhs_body)     = collect_binders rhs
         (body_lvl, new_lam_bndrs) = lvlLamBndrs rhs_lvl lam_bndrs
@@ -390,9 +443,9 @@ lvlBind top_lvl ctxt_lvl env (AnnRec pairs)
                                                (mkVarApps (Var new_bndr) lam_bndrs))],
               poly_env)
 
-  | otherwise
-  = newPolyBndrs dest_lvl env abs_vars bndrs   `thenLvl` \ (new_env, new_bndrs) ->
-    mapLvl (lvlFloatRhs abs_vars dest_lvl new_env) rhss        `thenLvl` \ new_rhss ->
+  | otherwise  -- Non-null abs_vars
+  = newPolyBndrs dest_lvl env abs_vars bndrs           `thenLvl` \ (new_env, new_bndrs) ->
+    mapLvl (lvlFloatRhs abs_vars dest_lvl new_env) rhss `thenLvl` \ new_rhss ->
     returnLvl (Rec ((new_bndrs `zip` repeat dest_lvl) `zip` new_rhss), new_env)
 
   where
@@ -428,6 +481,8 @@ lvlFloatRhs abs_vars dest_lvl env rhs
 \begin{code}
 lvlLamBndrs :: Level -> [CoreBndr] -> (Level, [(CoreBndr, Level)])
 -- Compute the levels for the binders of a lambda group
+-- The binders returned are exactly the same as the ones passed,
+-- but they are now paired with a level
 lvlLamBndrs lvl [] 
   = (lvl, [])
 
@@ -455,25 +510,6 @@ lvlLamBndrs lvl bndrs
 \end{code}
 
 \begin{code}
-abstractVars :: Level -> LevelEnv -> VarSet -> [Var]
-       -- Find the variables in fvs, free vars of the target expresion,
-       -- whose level is less than than the supplied level
-       -- These are the ones we are going to abstract out
-abstractVars dest_lvl env fvs
-  = uniq (sortLt lt [var | fv <- varSetElems fvs, var <- absVarsOf dest_lvl env fv])
-  where
-       -- Sort the variables so we don't get 
-       -- mixed-up tyvars and Ids; it's just messy
-    v1 `lt` v2 = case (isId v1, isId v2) of
-                  (True, False) -> False
-                  (False, True) -> True
-                  other         -> v1 < v2     -- Same family
-    uniq :: [Var] -> [Var]
-       -- Remove adjacent duplicates; the sort will have brought them together
-    uniq (v1:v2:vs) | v1 == v2  = uniq (v2:vs)
-                   | otherwise = v1 : uniq (v2:vs)
-    uniq vs = vs
-
   -- Destintion level is the max Id level of the expression
   -- (We'll abstract the type variables, if any.)
 destLevel :: LevelEnv -> VarSet -> Bool -> Level
@@ -514,14 +550,16 @@ isFunction other                 = False
 \begin{code}
 type LevelEnv = (Bool,                                 -- True <=> Float lambdas too
                 VarEnv Level,                  -- Domain is *post-cloned* TyVars and Ids
-                SubstEnv,                      -- Domain is pre-cloned Ids
+                Subst,                         -- Domain is pre-cloned Ids; tracks the in-scope set
+                                               --      so that subtitution is capture-avoiding
                 IdEnv ([Var], LevelledExpr))   -- Domain is pre-cloned Ids
        -- We clone let-bound variables so that they are still
        -- distinct when floated out; hence the SubstEnv/IdEnv.
+        -- (see point 3 of the module overview comment).
        -- We also use these envs when making a variable polymorphic
        -- because we want to float it out past a big lambda.
        --
-       -- The two Envs always implement the same mapping, but the
+       -- The SubstEnv and IdEnv always implement the same mapping, but the
        -- SubstEnv maps to CoreExpr and the IdEnv to LevelledExpr
        -- Since the range is always a variable or type application,
        -- there is never any difference between the two, but sadly
@@ -537,43 +575,65 @@ type LevelEnv = (Bool,                            -- True <=> Float lambdas too
        -- The domain of the VarEnv Level is the *post-cloned* Ids
 
 initialEnv :: Bool -> LevelEnv
-initialEnv float_lams = (float_lams, emptyVarEnv, emptySubstEnv, emptyVarEnv)
+initialEnv float_lams = (float_lams, emptyVarEnv, emptySubst, emptyVarEnv)
 
 floatLams :: LevelEnv -> Bool
 floatLams (float_lams, _, _, _) = float_lams
 
 extendLvlEnv :: LevelEnv -> [(Var,Level)] -> LevelEnv
-       -- Used when *not* cloning
-extendLvlEnv (float_lams, lvl_env, subst_env, id_env) prs
-  = (float_lams, foldl add lvl_env prs, subst_env, id_env)
+-- Used when *not* cloning
+extendLvlEnv (float_lams, lvl_env, subst, id_env) prs
+  = (float_lams,
+     foldl add_lvl lvl_env prs,
+     foldl del_subst subst prs,
+     foldl del_id id_env prs)
   where
-    add env (v,l) = extendVarEnv env v l
+    add_lvl   env (v,l) = extendVarEnv env v l
+    del_subst env (v,_) = extendInScope env v
+    del_id    env (v,_) = delVarEnv env v
+  -- We must remove any clone for this variable name in case of
+  -- shadowing.  This bit me in the following case
+  -- (in nofib/real/gg/Spark.hs):
+  -- 
+  --   case ds of wild {
+  --     ... -> case e of wild {
+  --              ... -> ... wild ...
+  --            }
+  --   }
+  -- 
+  -- The inside occurrence of @wild@ was being replaced with @ds@,
+  -- incorrectly, because the SubstEnv was still lying around.  Ouch!
+  -- KSW 2000-07.
 
 -- extendCaseBndrLvlEnv adds the mapping case-bndr->scrut-var if it can
+-- (see point 4 of the module overview comment)
+extendCaseBndrLvlEnv (float_lams, lvl_env, subst, id_env) (Var scrut_var) case_bndr lvl
+  = (float_lams,
+     extendVarEnv lvl_env case_bndr lvl,
+     extendSubst subst case_bndr (DoneEx (Var scrut_var)),
+     extendVarEnv id_env case_bndr ([scrut_var], Var scrut_var))
+     
 extendCaseBndrLvlEnv env scrut case_bndr lvl
-  = case scrut of
-       Var v -> extendCloneLvlEnv lvl env [(case_bndr, v)]
-       other -> extendLvlEnv          env [(case_bndr,lvl)]
+  = extendLvlEnv          env [(case_bndr,lvl)]
 
-extendPolyLvlEnv dest_lvl (float_lams, lvl_env, subst_env, id_env) abs_vars bndr_pairs
+extendPolyLvlEnv dest_lvl (float_lams, lvl_env, subst, id_env) abs_vars bndr_pairs
   = (float_lams,
-     foldl add_lvl   lvl_env   bndr_pairs,
-     foldl add_subst subst_env bndr_pairs,
-     foldl add_id    id_env    bndr_pairs)
+     foldl add_lvl   lvl_env bndr_pairs,
+     foldl add_subst subst   bndr_pairs,
+     foldl add_id    id_env  bndr_pairs)
   where
-     add_lvl   env (v,v') = extendVarEnv   env v' dest_lvl
-     add_subst env (v,v') = extendSubstEnv env v (DoneEx (mkVarApps (Var v') abs_vars))
-     add_id    env (v,v') = extendVarEnv   env v ((v':abs_vars), mkVarApps (Var v') abs_vars)
+     add_lvl   env (v,v') = extendVarEnv env v' dest_lvl
+     add_subst env (v,v') = extendSubst  env v (DoneEx (mkVarApps (Var v') abs_vars))
+     add_id    env (v,v') = extendVarEnv env v ((v':abs_vars), mkVarApps (Var v') abs_vars)
 
-extendCloneLvlEnv lvl (float_lams, lvl_env, subst_env, id_env) bndr_pairs
+extendCloneLvlEnv lvl (float_lams, lvl_env, _, id_env) new_subst bndr_pairs
   = (float_lams,
-     foldl add_lvl lvl_env bndr_pairs,
-     foldl add_subst subst_env bndr_pairs,
-     foldl add_id    id_env    bndr_pairs)
+     foldl add_lvl   lvl_env bndr_pairs,
+     new_subst,
+     foldl add_id    id_env  bndr_pairs)
   where
-     add_lvl   env (v,v') = extendVarEnv   env v' lvl
-     add_subst env (v,v') = extendSubstEnv env v (DoneEx (Var v'))
-     add_id    env (v,v') = extendVarEnv   env v ([v'], Var v')
+     add_lvl   env (v,v') = extendVarEnv env v' lvl
+     add_id    env (v,v') = extendVarEnv env v ([v'], Var v')
 
 
 maxIdLevel :: LevelEnv -> VarSet -> Level
@@ -595,13 +655,33 @@ lookupVar (_, _, _, id_env) v = case lookupVarEnv id_env v of
                                       Just (_, expr) -> expr
                                       other          -> Var v
 
+abstractVars :: Level -> LevelEnv -> VarSet -> [Var]
+       -- Find the variables in fvs, free vars of the target expresion,
+       -- whose level is greater than the destination level
+       -- These are the ones we are going to abstract out
+abstractVars dest_lvl env fvs
+  = uniq (sortLt lt [var | fv <- varSetElems fvs, var <- absVarsOf dest_lvl env fv])
+  where
+       -- Sort the variables so we don't get 
+       -- mixed-up tyvars and Ids; it's just messy
+    v1 `lt` v2 = case (isId v1, isId v2) of
+                  (True, False) -> False
+                  (False, True) -> True
+                  other         -> v1 < v2     -- Same family
+
+    uniq :: [Var] -> [Var]
+       -- Remove adjacent duplicates; the sort will have brought them together
+    uniq (v1:v2:vs) | v1 == v2  = uniq (v2:vs)
+                   | otherwise = v1 : uniq (v2:vs)
+    uniq vs = vs
+
 absVarsOf :: Level -> LevelEnv -> Var -> [Var]
-       -- If f is free in the exression, and f maps to poly_f a b c in the
+       -- If f is free in the expression, and f maps to poly_f a b c in the
        -- current substitution, then we must report a b c as candidate type
        -- variables
 absVarsOf dest_lvl (_, lvl_env, _, id_env) v 
   | isId v
-  = [final_av | av <- lookup_avs v, abstract_me av, final_av <- add_tyvars av]
+  = [zap av2 | av1 <- lookup_avs v, av2 <- add_tyvars av1, abstract_me av2]
 
   | otherwise
   = if abstract_me v then [v] else []
@@ -615,15 +695,16 @@ absVarsOf dest_lvl (_, lvl_env, _, id_env) v
                        Just (abs_vars, _) -> abs_vars
                        Nothing            -> [v]
 
-       -- We are going to lambda-abstract, so nuke any IdInfo,
-       -- and add the tyvars of the Id
-    add_tyvars v | isId v    =  zap v  : varSetElems (idFreeTyVars v)
+    add_tyvars v | isId v    = v : varSetElems (idFreeTyVars v)
                 | otherwise = [v]
 
-    zap v = WARN( workerExists (idWorkerInfo v)
-                 || not (isEmptyCoreRules (idSpecialisation v)),
-                 text "absVarsOf: discarding info on" <+> ppr v )
-           setIdInfo v vanillaIdInfo
+       -- We are going to lambda-abstract, so nuke any IdInfo,
+       -- and add the tyvars of the Id (if necessary)
+    zap v | isId v = WARN( workerExists (idWorkerInfo v) ||
+                          not (isEmptyCoreRules (idSpecialisation v)),
+                          text "absVarsOf: discarding info on" <+> ppr v )
+                    setIdInfo v vanillaIdInfo
+         | otherwise = v
 \end{code}
 
 \begin{code}
@@ -637,7 +718,7 @@ mapLvl              = mapUs
 
 \begin{code}
 newPolyBndrs dest_lvl env abs_vars bndrs
-  = getUniquesUs (length bndrs)                `thenLvl` \ uniqs ->
+  = getUniquesUs               `thenLvl` \ uniqs ->
     let
        new_bndrs = zipWith mk_poly_bndr bndrs uniqs
     in
@@ -646,7 +727,7 @@ newPolyBndrs dest_lvl env abs_vars bndrs
     mk_poly_bndr bndr uniq = mkSysLocal (_PK_ str) uniq poly_ty
                           where
                             str     = "poly_" ++ occNameUserString (getOccName bndr)
-                            poly_ty = foldr mkPiType (idType bndr) abs_vars
+                            poly_ty = mkPiTypes abs_vars (idType bndr)
        
 
 newLvlVar :: String 
@@ -654,38 +735,41 @@ newLvlVar :: String
          -> LvlM Id
 newLvlVar str vars body_ty     
   = getUniqueUs        `thenLvl` \ uniq ->
-    returnUs (mkSysLocal (_PK_ str) uniq (foldr mkPiType body_ty vars))
+    returnUs (mkSysLocal (_PK_ str) uniq (mkPiTypes vars body_ty))
     
 -- The deeply tiresome thing is that we have to apply the substitution
 -- to the rules inside each Id.  Grr.  But it matters.
 
-cloneVar :: TopLevelFlag -> LevelEnv -> Id -> Level -> LvlM (LevelEnv, Id)
-cloneVar TopLevel env v lvl
+cloneVar :: TopLevelFlag -> LevelEnv -> Id -> Level -> Level -> LvlM (LevelEnv, Id)
+cloneVar TopLevel env v ctxt_lvl dest_lvl
   = returnUs (env, v)  -- Don't clone top level things
-cloneVar NotTopLevel env v lvl
-  = getUniqueUs        `thenLvl` \ uniq ->
+cloneVar NotTopLevel env@(_,_,subst,_) v ctxt_lvl dest_lvl
+  = ASSERT( isId v )
+    getUs      `thenLvl` \ us ->
     let
-      v'        = setVarUnique v uniq
-      v''       = subst_id_info env v'
-      env'      = extendCloneLvlEnv lvl env [(v,v'')]
+      (subst', v1) = substAndCloneId subst us v
+      v2          = zap_demand ctxt_lvl dest_lvl v1
+      env'        = extendCloneLvlEnv dest_lvl env subst' [(v,v2)]
     in
-    returnUs (env', v'')
+    returnUs (env', v2)
 
-cloneVars :: TopLevelFlag -> LevelEnv -> [Id] -> Level -> LvlM (LevelEnv, [Id])
-cloneVars TopLevel env vs lvl 
+cloneRecVars :: TopLevelFlag -> LevelEnv -> [Id] -> Level -> Level -> LvlM (LevelEnv, [Id])
+cloneRecVars TopLevel env vs ctxt_lvl dest_lvl 
   = returnUs (env, vs) -- Don't clone top level things
-cloneVars NotTopLevel env vs lvl
-  = getUniquesUs (length vs)   `thenLvl` \ uniqs ->
+cloneRecVars NotTopLevel env@(_,_,subst,_) vs ctxt_lvl dest_lvl
+  = ASSERT( all isId vs )
+    getUs                      `thenLvl` \ us ->
     let
-      vs'       = zipWith setVarUnique vs uniqs
-      vs''      = map (subst_id_info env') vs'
-      env'      = extendCloneLvlEnv lvl env (vs `zip` vs'')
+      (subst', vs1) = substAndCloneRecIds subst us vs
+      vs2          = map (zap_demand ctxt_lvl dest_lvl) vs1
+      env'         = extendCloneLvlEnv dest_lvl env subst' (vs `zip` vs2)
     in
-    returnUs (env', vs'')
+    returnUs (env', vs2)
 
-subst_id_info (_, _, subst_env, _) v
-    = modifyIdInfo (\info -> substIdInfo subst info info) v
-  where
-    subst = mkSubst emptyVarSet subst_env
+       -- VERY IMPORTANT: we must zap the demand info 
+       -- if the thing is going to float out past a lambda
+zap_demand dest_lvl ctxt_lvl id
+  | ctxt_lvl == dest_lvl = id                  -- Stays put
+  | otherwise           = zapDemandIdInfo id   -- Floats out
 \end{code}