    {-
    (c) The University of Glasgow 2006
    (c) The GRASP/AQUA Project, Glasgow University, 1992-1998

    Utility functions on @Core@ syntax
    -}

    {-# LANGUAGE CPP #-}
    {-# OPTIONS_GHC -Wno-incomplete-record-updates #-}
    module GHC.Core.Subst (
            -- * Main data types
            Subst(..), -- Implementation exported for supercompiler's Renaming.hs only
            TvSubstEnv, IdSubstEnv, InScopeSet,

            -- ** Substituting into expressions and related types
            deShadowBinds, substRuleInfo, substRulesForImportedIds,
            substTy, substCo, substExpr, substExprSC, substBind, substBindSC,
            substUnfolding, substUnfoldingSC,
            lookupIdSubst, lookupTCvSubst, substIdType, substIdOcc,
            substTickish, substDVarSet, substIdInfo,

            -- ** Operations on substitutions
            emptySubst, mkEmptySubst, mkSubst, mkOpenSubst, substInScope, isEmptySubst,
            extendIdSubst, extendIdSubstList, extendTCvSubst, extendTvSubstList,
            extendSubst, extendSubstList, extendSubstWithVar, zapSubstEnv,
            extendInScope, extendInScopeList, extendInScopeIds,
            isInScope, setInScope, getTCvSubst, extendTvSubst, extendCvSubst,
            delBndr, delBndrs,

            -- ** Substituting and cloning binders
            substBndr, substBndrs, substRecBndrs, substTyVarBndr, substCoVarBndr,
            cloneBndr, cloneBndrs, cloneIdBndr, cloneIdBndrs, cloneRecIdBndrs,

        ) where

    #include "HsVersions.h"

    import GHC.Prelude

    import GHC.Core
    import GHC.Core.FVs
    import GHC.Core.Seq
    import GHC.Core.Utils
    import qualified GHC.Core.Type as Type
    import qualified GHC.Core.Coercion as Coercion

            -- We are defining local versions
    import GHC.Core.Type hiding
       ( substTy, extendTvSubst, extendCvSubst, extendTvSubstList
       , isInScope, substTyVarBndr, cloneTyVarBndr )
    import GHC.Core.Coercion hiding ( substCo, substCoVarBndr )

    import GHC.Builtin.Names
    import GHC.Types.Var.Set
    import GHC.Types.Var.Env
    import GHC.Types.Id
    import GHC.Types.Name     ( Name )
    import GHC.Types.Var
    import GHC.Types.Tickish
    import GHC.Types.Id.Info
    import GHC.Types.Unique.Supply
    import GHC.Data.Maybe
    import GHC.Utils.Misc
    import GHC.Utils.Outputable
    import GHC.Utils.Panic
    import Data.List (mapAccumL)
    import GHC.Driver.Ppr

    {-
    ************************************************************************
    *                                                                      *
    \subsection{Substitutions}
    *                                                                      *
    ************************************************************************
    -}

    -- | A substitution environment, containing 'Id', 'TyVar', and 'CoVar'
    -- substitutions.
    --
    -- Some invariants apply to how you use the substitution:
    --
    -- 1. Note [The substitution invariant] in "GHC.Core.TyCo.Subst"
    --
    -- 2. Note [Substitutions apply only once] in "GHC.Core.TyCo.Subst"
    data Subst
      = Subst InScopeSet  -- Variables in scope (both Ids and TyVars) /after/
                          -- applying the substitution
              IdSubstEnv  -- Substitution from NcIds to CoreExprs
              TvSubstEnv  -- Substitution from TyVars to Types
              CvSubstEnv  -- Substitution from CoVars to Coercions

            -- INVARIANT 1: See TyCoSubst Note [The substitution invariant]
            -- This is what lets us deal with name capture properly
            -- It's a hard invariant to check...
            --
            -- INVARIANT 2: The substitution is apply-once; see Note [Apply once] with
            --              Types.TvSubstEnv
            --
            -- INVARIANT 3: See Note [Extending the Subst]

    {-
    Note [Extending the Subst]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    For a core Subst, which binds Ids as well, we make a different choice for Ids
    than we do for TyVars.

    For TyVars, see Note [Extending the TCvSubst] in GHC.Core.TyCo.Subst.

    For Ids, we have a different invariant
            The IdSubstEnv is extended *only* when the Unique on an Id changes
            Otherwise, we just extend the InScopeSet

    In consequence:

    * If all subst envs are empty, substExpr would be a
      no-op, so substExprSC ("short cut") does nothing.

      However, substExpr still goes ahead and substitutes.  Reason: we may
      want to replace existing Ids with new ones from the in-scope set, to
      avoid space leaks.

    * In substIdBndr, we extend the IdSubstEnv only when the unique changes

    * If the CvSubstEnv, TvSubstEnv and IdSubstEnv are all empty,
      substExpr does nothing (Note that the above rule for substIdBndr
      maintains this property.  If the incoming envts are both empty, then
      substituting the type and IdInfo can't change anything.)

    * In lookupIdSubst, we *must* look up the Id in the in-scope set, because
      it may contain non-trivial changes.  Example:
            (/\a. \x:a. ...x...) Int
      We extend the TvSubstEnv with [a |-> Int]; but x's unique does not change
      so we only extend the in-scope set.  Then we must look up in the in-scope
      set when we find the occurrence of x.

    * The requirement to look up the Id in the in-scope set means that we
      must NOT take no-op short cut when the IdSubst is empty.
      We must still look up every Id in the in-scope set.

    * (However, we don't need to do so for expressions found in the IdSubst
      itself, whose range is assumed to be correct wrt the in-scope set.)

    Why do we make a different choice for the IdSubstEnv than the
    TvSubstEnv and CvSubstEnv?

    * For Ids, we change the IdInfo all the time (e.g. deleting the
      unfolding), and adding it back later, so using the TyVar convention
      would entail extending the substitution almost all the time

    * The simplifier wants to look up in the in-scope set anyway, in case it
      can see a better unfolding from an enclosing case expression

    * For TyVars, only coercion variables can possibly change, and they are
      easy to spot
    -}

    -- | An environment for substituting for 'Id's
    type IdSubstEnv = IdEnv CoreExpr   -- Domain is NcIds, i.e. not coercions

    ----------------------------
    isEmptySubst :: Subst -> Bool
    isEmptySubst :: Subst -> Bool
    isEmptySubst (Subst InScopeSet
    _ IdSubstEnv
    id_env TvSubstEnv
    tv_env CvSubstEnv
    cv_env)
      = IdSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv IdSubstEnv
    id_env Bool -> Bool -> Bool
    && TvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv TvSubstEnv
    tv_env Bool -> Bool -> Bool
    && CvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv CvSubstEnv
    cv_env

    emptySubst :: Subst
    emptySubst :: Subst
    emptySubst = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    emptyInScopeSet IdSubstEnv
    forall a. VarEnv a
    emptyVarEnv TvSubstEnv
    forall a. VarEnv a
    emptyVarEnv CvSubstEnv
    forall a. VarEnv a
    emptyVarEnv

    mkEmptySubst :: InScopeSet -> Subst
    mkEmptySubst :: InScopeSet -> Subst
    mkEmptySubst InScopeSet
    in_scope = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    forall a. VarEnv a
    emptyVarEnv TvSubstEnv
    forall a. VarEnv a
    emptyVarEnv CvSubstEnv
    forall a. VarEnv a
    emptyVarEnv

    mkSubst :: InScopeSet -> TvSubstEnv -> CvSubstEnv -> IdSubstEnv -> Subst
    mkSubst :: InScopeSet -> TvSubstEnv -> CvSubstEnv -> IdSubstEnv -> Subst
    mkSubst InScopeSet
    in_scope TvSubstEnv
    tvs CvSubstEnv
    cvs IdSubstEnv
    ids = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs

    -- | Find the in-scope set: see "GHC.Core.TyCo.Subst" Note [The substitution invariant]
    substInScope :: Subst -> InScopeSet
    substInScope :: Subst -> InScopeSet
    substInScope (Subst InScopeSet
    in_scope IdSubstEnv
    _ TvSubstEnv
    _ CvSubstEnv
    _) = InScopeSet
    in_scope

    -- | Remove all substitutions for 'Id's and 'Var's that might have been built up
    -- while preserving the in-scope set
    zapSubstEnv :: Subst -> Subst
    zapSubstEnv :: Subst -> Subst
    zapSubstEnv (Subst InScopeSet
    in_scope IdSubstEnv
    _ TvSubstEnv
    _ CvSubstEnv
    _) = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    forall a. VarEnv a
    emptyVarEnv TvSubstEnv
    forall a. VarEnv a
    emptyVarEnv CvSubstEnv
    forall a. VarEnv a
    emptyVarEnv

    -- | Add a substitution for an 'Id' to the 'Subst': you must ensure that the in-scope set is
    -- such that TyCoSubst Note [The substitution invariant]
    -- holds after extending the substitution like this
    extendIdSubst :: Subst -> Id -> CoreExpr -> Subst
    -- ToDo: add an ASSERT that fvs(subst-result) is already in the in-scope set
    extendIdSubst :: Subst -> Id -> CoreExpr -> Subst
    extendIdSubst (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    v CoreExpr
    r
      = ASSERT2( isNonCoVarId v, ppr v $$ ppr r )
        InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope (IdSubstEnv -> Id -> CoreExpr -> IdSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv IdSubstEnv
    ids Id
    v CoreExpr
    r) TvSubstEnv
    tvs CvSubstEnv
    cvs

    -- | Adds multiple 'Id' substitutions to the 'Subst': see also 'extendIdSubst'
    extendIdSubstList :: Subst -> [(Id, CoreExpr)] -> Subst
    extendIdSubstList :: Subst -> [(Id, CoreExpr)] -> Subst
    extendIdSubstList (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) [(Id, CoreExpr)]
    prs
      = ASSERT( all (isNonCoVarId . fst) prs )
        InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope (IdSubstEnv -> [(Id, CoreExpr)] -> IdSubstEnv
    forall a. VarEnv a -> [(Id, a)] -> VarEnv a
    extendVarEnvList IdSubstEnv
    ids [(Id, CoreExpr)]
    prs) TvSubstEnv
    tvs CvSubstEnv
    cvs

    -- | Add a substitution for a 'TyVar' to the 'Subst'
    -- The 'TyVar' *must* be a real TyVar, and not a CoVar
    -- You must ensure that the in-scope set is such that
    -- "GHC.Core.TyCo.Subst" Note [The substitution invariant] holds
    -- after extending the substitution like this.
    extendTvSubst :: Subst -> TyVar -> Type -> Subst
    extendTvSubst :: Subst -> Id -> Type -> Subst
    extendTvSubst (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    tv Type
    ty
      = ASSERT( isTyVar tv )
        InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids (TvSubstEnv -> Id -> Type -> TvSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv TvSubstEnv
    tvs Id
    tv Type
    ty) CvSubstEnv
    cvs

    -- | Adds multiple 'TyVar' substitutions to the 'Subst': see also 'extendTvSubst'
    extendTvSubstList :: Subst -> [(TyVar,Type)] -> Subst
    extendTvSubstList :: Subst -> [(Id, Type)] -> Subst
    extendTvSubstList Subst
    subst [(Id, Type)]
    vrs
      = (Subst -> (Id, Type) -> Subst) -> Subst -> [(Id, Type)] -> Subst
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' Subst -> (Id, Type) -> Subst
    extend Subst
    subst [(Id, Type)]
    vrs
      where
        extend :: Subst -> (Id, Type) -> Subst
    extend Subst
    subst (Id
    v, Type
    r) = Subst -> Id -> Type -> Subst
    extendTvSubst Subst
    subst Id
    v Type
    r

    -- | Add a substitution from a 'CoVar' to a 'Coercion' to the 'Subst':
    -- you must ensure that the in-scope set satisfies
    -- "GHC.Core.TyCo.Subst" Note [The substitution invariant]
    -- after extending the substitution like this
    extendCvSubst :: Subst -> CoVar -> Coercion -> Subst
    extendCvSubst :: Subst -> Id -> Coercion -> Subst
    extendCvSubst (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    v Coercion
    r
      = ASSERT( isCoVar v )
        InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs (CvSubstEnv -> Id -> Coercion -> CvSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv CvSubstEnv
    cvs Id
    v Coercion
    r)

    -- | Add a substitution appropriate to the thing being substituted
    --   (whether an expression, type, or coercion). See also
    --   'extendIdSubst', 'extendTvSubst', 'extendCvSubst'
    extendSubst :: Subst -> Var -> CoreArg -> Subst
    extendSubst :: Subst -> Id -> CoreExpr -> Subst
    extendSubst Subst
    subst Id
    var CoreExpr
    arg
      = case CoreExpr
    arg of
          Type Type
    ty     -> ASSERT( isTyVar var ) extendTvSubst subst var ty
          Coercion Coercion
    co -> ASSERT( isCoVar var ) extendCvSubst subst var co
          CoreExpr
    _           -> ASSERT( isId    var ) extendIdSubst subst var arg

    extendSubstWithVar :: Subst -> Var -> Var -> Subst
    extendSubstWithVar :: Subst -> Id -> Id -> Subst
    extendSubstWithVar Subst
    subst Id
    v1 Id
    v2
      | Id -> Bool
    isTyVar Id
    v1 = ASSERT( isTyVar v2 ) extendTvSubst subst v1 (mkTyVarTy v2)
      | Id -> Bool
    isCoVar Id
    v1 = ASSERT( isCoVar v2 ) extendCvSubst subst v1 (mkCoVarCo v2)
      | Bool
    otherwise  = ASSERT( isId    v2 ) extendIdSubst subst v1 (Var v2)

    -- | Add a substitution as appropriate to each of the terms being
    --   substituted (whether expressions, types, or coercions). See also
    --   'extendSubst'.
    extendSubstList :: Subst -> [(Var,CoreArg)] -> Subst
    extendSubstList :: Subst -> [(Id, CoreExpr)] -> Subst
    extendSubstList Subst
    subst []              = Subst
    subst
    extendSubstList Subst
    subst ((Id
    var,CoreExpr
    rhs):[(Id, CoreExpr)]
    prs) = Subst -> [(Id, CoreExpr)] -> Subst
    extendSubstList (Subst -> Id -> CoreExpr -> Subst
    extendSubst Subst
    subst Id
    var CoreExpr
    rhs) [(Id, CoreExpr)]
    prs

    -- | Find the substitution for an 'Id' in the 'Subst'
    lookupIdSubst :: HasDebugCallStack => Subst -> Id -> CoreExpr
    lookupIdSubst :: HasDebugCallStack => Subst -> Id -> CoreExpr
    lookupIdSubst (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    _ CvSubstEnv
    _) Id
    v
      | Bool -> Bool
    not (Id -> Bool
    isLocalId Id
    v) = Id -> CoreExpr
    forall b. Id -> Expr b
    Var Id
    v
      | Just CoreExpr
    e  <- IdSubstEnv -> Id -> Maybe CoreExpr
    forall a. VarEnv a -> Id -> Maybe a
    lookupVarEnv IdSubstEnv
    ids       Id
    v = CoreExpr
    e
      | Just Id
    v' <- InScopeSet -> Id -> Maybe Id
    lookupInScope InScopeSet
    in_scope Id
    v = Id -> CoreExpr
    forall b. Id -> Expr b
    Var Id
    v'

      | Bool
    otherwise = WARN( True, text "GHC.Core.Subst.lookupIdSubst" <+> ppr v
                                 $$ ppr in_scope)
                    Id -> CoreExpr
    forall b. Id -> Expr b
    Var Id
    v

    -- | Find the substitution for a 'TyVar' in the 'Subst'
    lookupTCvSubst :: Subst -> TyVar -> Type
    lookupTCvSubst :: Subst -> Id -> Type
    lookupTCvSubst (Subst InScopeSet
    _ IdSubstEnv
    _ TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    v
      | Id -> Bool
    isTyVar Id
    v
      = TvSubstEnv -> Id -> Maybe Type
    forall a. VarEnv a -> Id -> Maybe a
    lookupVarEnv TvSubstEnv
    tvs Id
    v Maybe Type -> Type -> Type
    forall a. Maybe a -> a -> a
    `orElse` Id -> Type
    Type.mkTyVarTy Id
    v
      | Bool
    otherwise
      = Coercion -> Type
    mkCoercionTy (Coercion -> Type) -> Coercion -> Type
    forall a b. (a -> b) -> a -> b
    $ CvSubstEnv -> Id -> Maybe Coercion
    forall a. VarEnv a -> Id -> Maybe a
    lookupVarEnv CvSubstEnv
    cvs Id
    v Maybe Coercion -> Coercion -> Coercion
    forall a. Maybe a -> a -> a
    `orElse` Id -> Coercion
    mkCoVarCo Id
    v

    delBndr :: Subst -> Var -> Subst
    delBndr :: Subst -> Id -> Subst
    delBndr (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    v
      | Id -> Bool
    isCoVar Id
    v = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs (CvSubstEnv -> Id -> CvSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    delVarEnv CvSubstEnv
    cvs Id
    v)
      | Id -> Bool
    isTyVar Id
    v = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids (TvSubstEnv -> Id -> TvSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    delVarEnv TvSubstEnv
    tvs Id
    v) CvSubstEnv
    cvs
      | Bool
    otherwise = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope (IdSubstEnv -> Id -> IdSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    delVarEnv IdSubstEnv
    ids Id
    v) TvSubstEnv
    tvs CvSubstEnv
    cvs

    delBndrs :: Subst -> [Var] -> Subst
    delBndrs :: Subst -> [Id] -> Subst
    delBndrs (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) [Id]
    vs
      = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope (IdSubstEnv -> [Id] -> IdSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    delVarEnvList IdSubstEnv
    ids [Id]
    vs) (TvSubstEnv -> [Id] -> TvSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    delVarEnvList TvSubstEnv
    tvs [Id]
    vs) (CvSubstEnv -> [Id] -> CvSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    delVarEnvList CvSubstEnv
    cvs [Id]
    vs)
          -- Easiest thing is just delete all from all!

    -- | Simultaneously substitute for a bunch of variables
    --   No left-right shadowing
    --   ie the substitution for   (\x \y. e) a1 a2
    --      so neither x nor y scope over a1 a2
    mkOpenSubst :: InScopeSet -> [(Var,CoreArg)] -> Subst
    mkOpenSubst :: InScopeSet -> [(Id, CoreExpr)] -> Subst
    mkOpenSubst InScopeSet
    in_scope [(Id, CoreExpr)]
    pairs = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope
                                       ([(Id, CoreExpr)] -> IdSubstEnv
    forall a. [(Id, a)] -> VarEnv a
    mkVarEnv [(Id
    id,CoreExpr
    e)  | (Id
    id, CoreExpr
    e) <- [(Id, CoreExpr)]
    pairs, Id -> Bool
    isId Id
    id])
                                       ([(Id, Type)] -> TvSubstEnv
    forall a. [(Id, a)] -> VarEnv a
    mkVarEnv [(Id
    tv,Type
    ty) | (Id
    tv, Type Type
    ty) <- [(Id, CoreExpr)]
    pairs])
                                       ([(Id, Coercion)] -> CvSubstEnv
    forall a. [(Id, a)] -> VarEnv a
    mkVarEnv [(Id
    v,Coercion
    co)  | (Id
    v, Coercion Coercion
    co) <- [(Id, CoreExpr)]
    pairs])

    ------------------------------
    isInScope :: Var -> Subst -> Bool
    isInScope :: Id -> Subst -> Bool
    isInScope Id
    v (Subst InScopeSet
    in_scope IdSubstEnv
    _ TvSubstEnv
    _ CvSubstEnv
    _) = Id
    v Id -> InScopeSet -> Bool
    `elemInScopeSet` InScopeSet
    in_scope

    -- | Add the 'Var' to the in-scope set: as a side effect,
    -- and remove any existing substitutions for it
    extendInScope :: Subst -> Var -> Subst
    extendInScope :: Subst -> Id -> Subst
    extendInScope (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    v
      = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst (InScopeSet
    in_scope InScopeSet -> Id -> InScopeSet
    `extendInScopeSet` Id
    v)
              (IdSubstEnv
    ids IdSubstEnv -> Id -> IdSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    `delVarEnv` Id
    v) (TvSubstEnv
    tvs TvSubstEnv -> Id -> TvSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    `delVarEnv` Id
    v) (CvSubstEnv
    cvs CvSubstEnv -> Id -> CvSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    `delVarEnv` Id
    v)

    -- | Add the 'Var's to the in-scope set: see also 'extendInScope'
    extendInScopeList :: Subst -> [Var] -> Subst
    extendInScopeList :: Subst -> [Id] -> Subst
    extendInScopeList (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) [Id]
    vs
      = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst (InScopeSet
    in_scope InScopeSet -> [Id] -> InScopeSet
    `extendInScopeSetList` [Id]
    vs)
              (IdSubstEnv
    ids IdSubstEnv -> [Id] -> IdSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    `delVarEnvList` [Id]
    vs) (TvSubstEnv
    tvs TvSubstEnv -> [Id] -> TvSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    `delVarEnvList` [Id]
    vs) (CvSubstEnv
    cvs CvSubstEnv -> [Id] -> CvSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    `delVarEnvList` [Id]
    vs)

    -- | Optimized version of 'extendInScopeList' that can be used if you are certain
    -- all the things being added are 'Id's and hence none are 'TyVar's or 'CoVar's
    extendInScopeIds :: Subst -> [Id] -> Subst
    extendInScopeIds :: Subst -> [Id] -> Subst
    extendInScopeIds (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) [Id]
    vs
      = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst (InScopeSet
    in_scope InScopeSet -> [Id] -> InScopeSet
    `extendInScopeSetList` [Id]
    vs)
              (IdSubstEnv
    ids IdSubstEnv -> [Id] -> IdSubstEnv
    forall a. VarEnv a -> [Id] -> VarEnv a
    `delVarEnvList` [Id]
    vs) TvSubstEnv
    tvs CvSubstEnv
    cvs

    setInScope :: Subst -> InScopeSet -> Subst
    setInScope :: Subst -> InScopeSet -> Subst
    setInScope (Subst InScopeSet
    _ IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs) InScopeSet
    in_scope = InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs

    -- Pretty printing, for debugging only

    instance Outputable Subst where
      ppr :: Subst -> SDoc
    ppr (Subst InScopeSet
    in_scope IdSubstEnv
    ids TvSubstEnv
    tvs CvSubstEnv
    cvs)
            =  String -> SDoc
    text String
    "<InScope =" SDoc -> SDoc -> SDoc
    <+> SDoc
    in_scope_doc
            SDoc -> SDoc -> SDoc
    $$ String -> SDoc
    text String
    " IdSubst   =" SDoc -> SDoc -> SDoc
    <+> IdSubstEnv -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr IdSubstEnv
    ids
            SDoc -> SDoc -> SDoc
    $$ String -> SDoc
    text String
    " TvSubst   =" SDoc -> SDoc -> SDoc
    <+> TvSubstEnv -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr TvSubstEnv
    tvs
            SDoc -> SDoc -> SDoc
    $$ String -> SDoc
    text String
    " CvSubst   =" SDoc -> SDoc -> SDoc
    <+> CvSubstEnv -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CvSubstEnv
    cvs
             SDoc -> SDoc -> SDoc
    <> Char -> SDoc
    char Char
    '>'
        where
        in_scope_doc :: SDoc
    in_scope_doc = VarSet -> ([Id] -> SDoc) -> SDoc
    pprVarSet (InScopeSet -> VarSet
    getInScopeVars InScopeSet
    in_scope) (SDoc -> SDoc
    braces (SDoc -> SDoc) -> ([Id] -> SDoc) -> [Id] -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [SDoc] -> SDoc
    fsep ([SDoc] -> SDoc) -> ([Id] -> [SDoc]) -> [Id] -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Id -> SDoc) -> [Id] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr)

    {-
    ************************************************************************
    *                                                                      *
            Substituting expressions
    *                                                                      *
    ************************************************************************
    -}

    substExprSC :: HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    -- Just like substExpr, but a no-op if the substitution is empty
    -- Note that this does /not/ replace occurrences of free vars with
    -- their canonical representatives in the in-scope set
    substExprSC :: HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    substExprSC Subst
    subst CoreExpr
    orig_expr
      | Subst -> Bool
    isEmptySubst Subst
    subst = CoreExpr
    orig_expr
      | Bool
    otherwise          = -- pprTrace "enter subst-expr" (doc $$ ppr orig_expr) $
                             HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst CoreExpr
    orig_expr

    -- | substExpr applies a substitution to an entire 'CoreExpr'. Remember,
    -- you may only apply the substitution /once/:
    -- See Note [Substitutions apply only once] in "GHC.Core.TyCo.Subst"
    --
    -- Do *not* attempt to short-cut in the case of an empty substitution!
    -- See Note [Extending the Subst]
    substExpr :: HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
       -- HasDebugCallStack so we can track failures in lookupIdSubst
    substExpr :: HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst CoreExpr
    expr
      = CoreExpr -> CoreExpr
    go CoreExpr
    expr
      where
        go :: CoreExpr -> CoreExpr
    go (Var Id
    v)         = HasDebugCallStack => Subst -> Id -> CoreExpr
    Subst -> Id -> CoreExpr
    lookupIdSubst Subst
    subst Id
    v
        go (Type Type
    ty)       = Type -> CoreExpr
    forall b. Type -> Expr b
    Type (Subst -> Type -> Type
    substTy Subst
    subst Type
    ty)
        go (Coercion Coercion
    co)   = Coercion -> CoreExpr
    forall b. Coercion -> Expr b
    Coercion (HasCallStack => Subst -> Coercion -> Coercion
    Subst -> Coercion -> Coercion
    substCo Subst
    subst Coercion
    co)
        go (Lit Literal
    lit)       = Literal -> CoreExpr
    forall b. Literal -> Expr b
    Lit Literal
    lit
        go (App CoreExpr
    fun CoreExpr
    arg)   = CoreExpr -> CoreExpr -> CoreExpr
    forall b. Expr b -> Expr b -> Expr b
    App (CoreExpr -> CoreExpr
    go CoreExpr
    fun) (CoreExpr -> CoreExpr
    go CoreExpr
    arg)
        go (Tick CoreTickish
    tickish CoreExpr
    e) = CoreTickish -> CoreExpr -> CoreExpr
    mkTick (Subst -> CoreTickish -> CoreTickish
    substTickish Subst
    subst CoreTickish
    tickish) (CoreExpr -> CoreExpr
    go CoreExpr
    e)
        go (Cast CoreExpr
    e Coercion
    co)     = CoreExpr -> Coercion -> CoreExpr
    forall b. Expr b -> Coercion -> Expr b
    Cast (CoreExpr -> CoreExpr
    go CoreExpr
    e) (HasCallStack => Subst -> Coercion -> Coercion
    Subst -> Coercion -> Coercion
    substCo Subst
    subst Coercion
    co)
           -- Do not optimise even identity coercions
           -- Reason: substitution applies to the LHS of RULES, and
           --         if you "optimise" an identity coercion, you may
           --         lose a binder. We optimise the LHS of rules at
           --         construction time

        go (Lam Id
    bndr CoreExpr
    body) = Id -> CoreExpr -> CoreExpr
    forall b. b -> Expr b -> Expr b
    Lam Id
    bndr' (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst' CoreExpr
    body)
                           where
                             (Subst
    subst', Id
    bndr') = Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst Id
    bndr

        go (Let Bind Id
    bind CoreExpr
    body) = Bind Id -> CoreExpr -> CoreExpr
    forall b. Bind b -> Expr b -> Expr b
    Let Bind Id
    bind' (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst' CoreExpr
    body)
                           where
                             (Subst
    subst', Bind Id
    bind') = HasDebugCallStack => Subst -> Bind Id -> (Subst, Bind Id)
    Subst -> Bind Id -> (Subst, Bind Id)
    substBind Subst
    subst Bind Id
    bind

        go (Case CoreExpr
    scrut Id
    bndr Type
    ty [Alt Id]
    alts) = CoreExpr -> Id -> Type -> [Alt Id] -> CoreExpr
    forall b. Expr b -> b -> Type -> [Alt b] -> Expr b
    Case (CoreExpr -> CoreExpr
    go CoreExpr
    scrut) Id
    bndr' (Subst -> Type -> Type
    substTy Subst
    subst Type
    ty) ((Alt Id -> Alt Id) -> [Alt Id] -> [Alt Id]
    forall a b. (a -> b) -> [a] -> [b]
    map (Subst -> Alt Id -> Alt Id
    go_alt Subst
    subst') [Alt Id]
    alts)
                                     where
                                     (Subst
    subst', Id
    bndr') = Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst Id
    bndr

        go_alt :: Subst -> Alt Id -> Alt Id
    go_alt Subst
    subst (Alt AltCon
    con [Id]
    bndrs CoreExpr
    rhs) = AltCon -> [Id] -> CoreExpr -> Alt Id
    forall b. AltCon -> [b] -> Expr b -> Alt b
    Alt AltCon
    con [Id]
    bndrs' (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst' CoreExpr
    rhs)
                                     where
                                       (Subst
    subst', [Id]
    bndrs') = Subst -> [Id] -> (Subst, [Id])
    substBndrs Subst
    subst [Id]
    bndrs

    -- | Apply a substitution to an entire 'CoreBind', additionally returning an updated 'Subst'
    -- that should be used by subsequent substitutions.
    substBind, substBindSC :: HasDebugCallStack => Subst -> CoreBind -> (Subst, CoreBind)

    substBindSC :: HasDebugCallStack => Subst -> Bind Id -> (Subst, Bind Id)
    substBindSC Subst
    subst Bind Id
    bind    -- Short-cut if the substitution is empty
      | Bool -> Bool
    not (Subst -> Bool
    isEmptySubst Subst
    subst)
      = HasDebugCallStack => Subst -> Bind Id -> (Subst, Bind Id)
    Subst -> Bind Id -> (Subst, Bind Id)
    substBind Subst
    subst Bind Id
    bind
      | Bool
    otherwise
      = case Bind Id
    bind of
           NonRec Id
    bndr CoreExpr
    rhs -> (Subst
    subst', Id -> CoreExpr -> Bind Id
    forall b. b -> Expr b -> Bind b
    NonRec Id
    bndr' CoreExpr
    rhs)
              where
                (Subst
    subst', Id
    bndr') = Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst Id
    bndr
           Rec [(Id, CoreExpr)]
    pairs -> (Subst
    subst', [(Id, CoreExpr)] -> Bind Id
    forall b. [(b, Expr b)] -> Bind b
    Rec ([Id]
    bndrs' [Id] -> [CoreExpr] -> [(Id, CoreExpr)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` [CoreExpr]
    rhss'))
              where
                ([Id]
    bndrs, [CoreExpr]
    rhss)    = [(Id, CoreExpr)] -> ([Id], [CoreExpr])
    forall a b. [(a, b)] -> ([a], [b])
    unzip [(Id, CoreExpr)]
    pairs
                (Subst
    subst', [Id]
    bndrs') = Subst -> [Id] -> (Subst, [Id])
    substRecBndrs Subst
    subst [Id]
    bndrs
                rhss' :: [CoreExpr]
    rhss' | Subst -> Bool
    isEmptySubst Subst
    subst'
                      = [CoreExpr]
    rhss
                      | Bool
    otherwise
                      = (CoreExpr -> CoreExpr) -> [CoreExpr] -> [CoreExpr]
    forall a b. (a -> b) -> [a] -> [b]
    map (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst') [CoreExpr]
    rhss

    substBind :: HasDebugCallStack => Subst -> Bind Id -> (Subst, Bind Id)
    substBind Subst
    subst (NonRec Id
    bndr CoreExpr
    rhs)
      = (Subst
    subst', Id -> CoreExpr -> Bind Id
    forall b. b -> Expr b -> Bind b
    NonRec Id
    bndr' (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst CoreExpr
    rhs))
      where
        (Subst
    subst', Id
    bndr') = Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst Id
    bndr

    substBind Subst
    subst (Rec [(Id, CoreExpr)]
    pairs)
       = (Subst
    subst', [(Id, CoreExpr)] -> Bind Id
    forall b. [(b, Expr b)] -> Bind b
    Rec ([Id]
    bndrs' [Id] -> [CoreExpr] -> [(Id, CoreExpr)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` [CoreExpr]
    rhss'))
       where
           ([Id]
    bndrs, [CoreExpr]
    rhss)    = [(Id, CoreExpr)] -> ([Id], [CoreExpr])
    forall a b. [(a, b)] -> ([a], [b])
    unzip [(Id, CoreExpr)]
    pairs
           (Subst
    subst', [Id]
    bndrs') = Subst -> [Id] -> (Subst, [Id])
    substRecBndrs Subst
    subst [Id]
    bndrs
           rhss' :: [CoreExpr]
    rhss' = (CoreExpr -> CoreExpr) -> [CoreExpr] -> [CoreExpr]
    forall a b. (a -> b) -> [a] -> [b]
    map (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst') [CoreExpr]
    rhss

    -- | De-shadowing the program is sometimes a useful pre-pass. It can be done simply
    -- by running over the bindings with an empty substitution, because substitution
    -- returns a result that has no-shadowing guaranteed.
    --
    -- (Actually, within a single /type/ there might still be shadowing, because
    -- 'substTy' is a no-op for the empty substitution, but that's probably OK.)
    --
    -- [Aug 09] This function is not used in GHC at the moment, but seems so
    --          short and simple that I'm going to leave it here
    deShadowBinds :: CoreProgram -> CoreProgram
    deShadowBinds :: CoreProgram -> CoreProgram
    deShadowBinds CoreProgram
    binds = (Subst, CoreProgram) -> CoreProgram
    forall a b. (a, b) -> b
    snd ((Subst -> Bind Id -> (Subst, Bind Id))
    -> Subst -> CoreProgram -> (Subst, CoreProgram)
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL HasDebugCallStack => Subst -> Bind Id -> (Subst, Bind Id)
    Subst -> Bind Id -> (Subst, Bind Id)
    substBind Subst
    emptySubst CoreProgram
    binds)

    {-
    ************************************************************************
    *                                                                      *
            Substituting binders
    *                                                                      *
    ************************************************************************

    Remember that substBndr and friends are used when doing expression
    substitution only.  Their only business is substitution, so they
    preserve all IdInfo (suitably substituted).  For example, we *want* to
    preserve occ info in rules.
    -}

    -- | Substitutes a 'Var' for another one according to the 'Subst' given, returning
    -- the result and an updated 'Subst' that should be used by subsequent substitutions.
    -- 'IdInfo' is preserved by this process, although it is substituted into appropriately.
    substBndr :: Subst -> Var -> (Subst, Var)
    substBndr :: Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst Id
    bndr
      | Id -> Bool
    isTyVar Id
    bndr  = Subst -> Id -> (Subst, Id)
    substTyVarBndr Subst
    subst Id
    bndr
      | Id -> Bool
    isCoVar Id
    bndr  = Subst -> Id -> (Subst, Id)
    substCoVarBndr Subst
    subst Id
    bndr
      | Bool
    otherwise     = SDoc -> Subst -> Subst -> Id -> (Subst, Id)
    substIdBndr (String -> SDoc
    text String
    "var-bndr") Subst
    subst Subst
    subst Id
    bndr

    -- | Applies 'substBndr' to a number of 'Var's, accumulating a new 'Subst' left-to-right
    substBndrs :: Subst -> [Var] -> (Subst, [Var])
    substBndrs :: Subst -> [Id] -> (Subst, [Id])
    substBndrs Subst
    subst [Id]
    bndrs = (Subst -> Id -> (Subst, Id)) -> Subst -> [Id] -> (Subst, [Id])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL Subst -> Id -> (Subst, Id)
    substBndr Subst
    subst [Id]
    bndrs

    -- | Substitute in a mutually recursive group of 'Id's
    substRecBndrs :: Subst -> [Id] -> (Subst, [Id])
    substRecBndrs :: Subst -> [Id] -> (Subst, [Id])
    substRecBndrs Subst
    subst [Id]
    bndrs
      = (Subst
    new_subst, [Id]
    new_bndrs)
      where         -- Here's the reason we need to pass rec_subst to subst_id
        (Subst
    new_subst, [Id]
    new_bndrs) = (Subst -> Id -> (Subst, Id)) -> Subst -> [Id] -> (Subst, [Id])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL (SDoc -> Subst -> Subst -> Id -> (Subst, Id)
    substIdBndr (String -> SDoc
    text String
    "rec-bndr") Subst
    new_subst) Subst
    subst [Id]
    bndrs

    substIdBndr :: SDoc
                -> Subst            -- ^ Substitution to use for the IdInfo
                -> Subst -> Id      -- ^ Substitution and Id to transform
                -> (Subst, Id)      -- ^ Transformed pair
                                    -- NB: unfolding may be zapped

    substIdBndr :: SDoc -> Subst -> Subst -> Id -> (Subst, Id)
    substIdBndr SDoc
    _doc Subst
    rec_subst subst :: Subst
    subst@(Subst InScopeSet
    in_scope IdSubstEnv
    env TvSubstEnv
    tvs CvSubstEnv
    cvs) Id
    old_id
      = -- pprTrace "substIdBndr" (doc $$ ppr old_id $$ ppr in_scope) $
        (InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst (InScopeSet
    in_scope InScopeSet -> Id -> InScopeSet
    `extendInScopeSet` Id
    new_id) IdSubstEnv
    new_env TvSubstEnv
    tvs CvSubstEnv
    cvs, Id
    new_id)
      where
        id1 :: Id
    id1 = InScopeSet -> Id -> Id
    uniqAway InScopeSet
    in_scope Id
    old_id      -- id1 is cloned if necessary
        id2 :: Id
    id2 | Bool
    no_type_change = Id
    id1
            | Bool
    otherwise      = (Type -> Type) -> Id -> Id
    updateIdTypeAndMult (Subst -> Type -> Type
    substTy Subst
    subst) Id
    id1

        old_ty :: Type
    old_ty = Id -> Type
    idType Id
    old_id
        old_w :: Type
    old_w = Id -> Type
    idMult Id
    old_id
        no_type_change :: Bool
    no_type_change = (TvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv TvSubstEnv
    tvs Bool -> Bool -> Bool
    && CvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv CvSubstEnv
    cvs) Bool -> Bool -> Bool
    ||
                         (Type -> Bool
    noFreeVarsOfType Type
    old_ty Bool -> Bool -> Bool
    && Type -> Bool
    noFreeVarsOfType Type
    old_w)

            -- new_id has the right IdInfo
            -- The lazy-set is because we're in a loop here, with
            -- rec_subst, when dealing with a mutually-recursive group
        new_id :: Id
    new_id = Maybe IdInfo -> Id -> Id
    maybeModifyIdInfo Maybe IdInfo
    mb_new_info Id
    id2
        mb_new_info :: Maybe IdInfo
    mb_new_info = Subst -> Id -> IdInfo -> Maybe IdInfo
    substIdInfo Subst
    rec_subst Id
    id2 (HasDebugCallStack => Id -> IdInfo
    Id -> IdInfo
    idInfo Id
    id2)
            -- NB: unfolding info may be zapped

            -- Extend the substitution if the unique has changed
            -- See the notes with substTyVarBndr for the delVarEnv
        new_env :: IdSubstEnv
    new_env | Bool
    no_change = IdSubstEnv -> Id -> IdSubstEnv
    forall a. VarEnv a -> Id -> VarEnv a
    delVarEnv IdSubstEnv
    env Id
    old_id
                | Bool
    otherwise = IdSubstEnv -> Id -> CoreExpr -> IdSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv IdSubstEnv
    env Id
    old_id (Id -> CoreExpr
    forall b. Id -> Expr b
    Var Id
    new_id)

        no_change :: Bool
    no_change = Id
    id1 Id -> Id -> Bool
    forall a. Eq a => a -> a -> Bool
    == Id
    old_id
            -- See Note [Extending the Subst]
            -- it's /not/ necessary to check mb_new_info and no_type_change

    {-
    Now a variant that unconditionally allocates a new unique.
    It also unconditionally zaps the OccInfo.
    -}

    -- | Very similar to 'substBndr', but it always allocates a new 'Unique' for
    -- each variable in its output.  It substitutes the IdInfo though.
    cloneIdBndr :: Subst -> UniqSupply -> Id -> (Subst, Id)
    cloneIdBndr :: Subst -> UniqSupply -> Id -> (Subst, Id)
    cloneIdBndr Subst
    subst UniqSupply
    us Id
    old_id
      = Subst -> Subst -> (Id, Unique) -> (Subst, Id)
    clone_id Subst
    subst Subst
    subst (Id
    old_id, UniqSupply -> Unique
    uniqFromSupply UniqSupply
    us)

    -- | Applies 'cloneIdBndr' to a number of 'Id's, accumulating a final
    -- substitution from left to right
    cloneIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
    cloneIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
    cloneIdBndrs Subst
    subst UniqSupply
    us [Id]
    ids
      = (Subst -> (Id, Unique) -> (Subst, Id))
    -> Subst -> [(Id, Unique)] -> (Subst, [Id])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL (Subst -> Subst -> (Id, Unique) -> (Subst, Id)
    clone_id Subst
    subst) Subst
    subst ([Id]
    ids [Id] -> [Unique] -> [(Id, Unique)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` UniqSupply -> [Unique]
    uniqsFromSupply UniqSupply
    us)

    cloneBndrs :: Subst -> UniqSupply -> [Var] -> (Subst, [Var])
    -- Works for all kinds of variables (typically case binders)
    -- not just Ids
    cloneBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
    cloneBndrs Subst
    subst UniqSupply
    us [Id]
    vs
      = (Subst -> (Id, Unique) -> (Subst, Id))
    -> Subst -> [(Id, Unique)] -> (Subst, [Id])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL (\Subst
    subst (Id
    v, Unique
    u) -> Subst -> Unique -> Id -> (Subst, Id)
    cloneBndr Subst
    subst Unique
    u Id
    v) Subst
    subst ([Id]
    vs [Id] -> [Unique] -> [(Id, Unique)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` UniqSupply -> [Unique]
    uniqsFromSupply UniqSupply
    us)

    cloneBndr :: Subst -> Unique -> Var -> (Subst, Var)
    cloneBndr :: Subst -> Unique -> Id -> (Subst, Id)
    cloneBndr Subst
    subst Unique
    uniq Id
    v
      | Id -> Bool
    isTyVar Id
    v = Subst -> Id -> Unique -> (Subst, Id)
    cloneTyVarBndr Subst
    subst Id
    v Unique
    uniq
      | Bool
    otherwise = Subst -> Subst -> (Id, Unique) -> (Subst, Id)
    clone_id Subst
    subst Subst
    subst (Id
    v,Unique
    uniq)  -- Works for coercion variables too

    -- | Clone a mutually recursive group of 'Id's
    cloneRecIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
    cloneRecIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])
    cloneRecIdBndrs Subst
    subst UniqSupply
    us [Id]
    ids
      = (Subst
    subst', [Id]
    ids')
      where
        (Subst
    subst', [Id]
    ids') = (Subst -> (Id, Unique) -> (Subst, Id))
    -> Subst -> [(Id, Unique)] -> (Subst, [Id])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL (Subst -> Subst -> (Id, Unique) -> (Subst, Id)
    clone_id Subst
    subst') Subst
    subst
                                   ([Id]
    ids [Id] -> [Unique] -> [(Id, Unique)]
    forall a b. [a] -> [b] -> [(a, b)]
    `zip` UniqSupply -> [Unique]
    uniqsFromSupply UniqSupply
    us)

    -- Just like substIdBndr, except that it always makes a new unique
    -- It is given the unique to use
    clone_id    :: Subst                    -- Substitution for the IdInfo
                -> Subst -> (Id, Unique)    -- Substitution and Id to transform
                -> (Subst, Id)              -- Transformed pair

    clone_id :: Subst -> Subst -> (Id, Unique) -> (Subst, Id)
    clone_id Subst
    rec_subst subst :: Subst
    subst@(Subst InScopeSet
    in_scope IdSubstEnv
    idvs TvSubstEnv
    tvs CvSubstEnv
    cvs) (Id
    old_id, Unique
    uniq)
      = (InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst (InScopeSet
    in_scope InScopeSet -> Id -> InScopeSet
    `extendInScopeSet` Id
    new_id) IdSubstEnv
    new_idvs TvSubstEnv
    tvs CvSubstEnv
    new_cvs, Id
    new_id)
      where
        id1 :: Id
    id1     = Id -> Unique -> Id
    setVarUnique Id
    old_id Unique
    uniq
        id2 :: Id
    id2     = Subst -> Id -> Id
    substIdType Subst
    subst Id
    id1
        new_id :: Id
    new_id  = Maybe IdInfo -> Id -> Id
    maybeModifyIdInfo (Subst -> Id -> IdInfo -> Maybe IdInfo
    substIdInfo Subst
    rec_subst Id
    id2 (HasDebugCallStack => Id -> IdInfo
    Id -> IdInfo
    idInfo Id
    old_id)) Id
    id2
        (IdSubstEnv
    new_idvs, CvSubstEnv
    new_cvs) | Id -> Bool
    isCoVar Id
    old_id = (IdSubstEnv
    idvs, CvSubstEnv -> Id -> Coercion -> CvSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv CvSubstEnv
    cvs Id
    old_id (Id -> Coercion
    mkCoVarCo Id
    new_id))
                            | Bool
    otherwise      = (IdSubstEnv -> Id -> CoreExpr -> IdSubstEnv
    forall a. VarEnv a -> Id -> a -> VarEnv a
    extendVarEnv IdSubstEnv
    idvs Id
    old_id (Id -> CoreExpr
    forall b. Id -> Expr b
    Var Id
    new_id), CvSubstEnv
    cvs)

    {-
    ************************************************************************
    *                                                                      *
                    Types and Coercions
    *                                                                      *
    ************************************************************************

    For types and coercions we just call the corresponding functions in
    Type and Coercion, but we have to repackage the substitution, from a
    Subst to a TCvSubst.
    -}

    substTyVarBndr :: Subst -> TyVar -> (Subst, TyVar)
    substTyVarBndr :: Subst -> Id -> (Subst, Id)
    substTyVarBndr (Subst InScopeSet
    in_scope IdSubstEnv
    id_env TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    tv
      = case HasCallStack => TCvSubst -> Id -> (TCvSubst, Id)
    TCvSubst -> Id -> (TCvSubst, Id)
    Type.substTyVarBndr (InScopeSet -> TvSubstEnv -> CvSubstEnv -> TCvSubst
    TCvSubst InScopeSet
    in_scope TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    tv of
            (TCvSubst InScopeSet
    in_scope' TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    tv')
               -> (InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope' IdSubstEnv
    id_env TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    tv')

    cloneTyVarBndr :: Subst -> TyVar -> Unique -> (Subst, TyVar)
    cloneTyVarBndr :: Subst -> Id -> Unique -> (Subst, Id)
    cloneTyVarBndr (Subst InScopeSet
    in_scope IdSubstEnv
    id_env TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    tv Unique
    uniq
      = case TCvSubst -> Id -> Unique -> (TCvSubst, Id)
    Type.cloneTyVarBndr (InScopeSet -> TvSubstEnv -> CvSubstEnv -> TCvSubst
    TCvSubst InScopeSet
    in_scope TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    tv Unique
    uniq of
            (TCvSubst InScopeSet
    in_scope' TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    tv')
               -> (InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope' IdSubstEnv
    id_env TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    tv')

    substCoVarBndr :: Subst -> CoVar -> (Subst, CoVar)
    substCoVarBndr :: Subst -> Id -> (Subst, Id)
    substCoVarBndr (Subst InScopeSet
    in_scope IdSubstEnv
    id_env TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    cv
      = case HasCallStack => TCvSubst -> Id -> (TCvSubst, Id)
    TCvSubst -> Id -> (TCvSubst, Id)
    Coercion.substCoVarBndr (InScopeSet -> TvSubstEnv -> CvSubstEnv -> TCvSubst
    TCvSubst InScopeSet
    in_scope TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    cv of
            (TCvSubst InScopeSet
    in_scope' TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    cv')
               -> (InScopeSet -> IdSubstEnv -> TvSubstEnv -> CvSubstEnv -> Subst
    Subst InScopeSet
    in_scope' IdSubstEnv
    id_env TvSubstEnv
    tv_env' CvSubstEnv
    cv_env', Id
    cv')

    -- | See 'GHC.Core.Type.substTy'.
    substTy :: Subst -> Type -> Type
    substTy :: Subst -> Type -> Type
    substTy Subst
    subst Type
    ty = TCvSubst -> Type -> Type
    Type.substTyUnchecked (Subst -> TCvSubst
    getTCvSubst Subst
    subst) Type
    ty

    getTCvSubst :: Subst -> TCvSubst
    getTCvSubst :: Subst -> TCvSubst
    getTCvSubst (Subst InScopeSet
    in_scope IdSubstEnv
    _ TvSubstEnv
    tenv CvSubstEnv
    cenv) = InScopeSet -> TvSubstEnv -> CvSubstEnv -> TCvSubst
    TCvSubst InScopeSet
    in_scope TvSubstEnv
    tenv CvSubstEnv
    cenv

    -- | See 'Coercion.substCo'
    substCo :: HasCallStack => Subst -> Coercion -> Coercion
    substCo :: HasCallStack => Subst -> Coercion -> Coercion
    substCo Subst
    subst Coercion
    co = HasCallStack => TCvSubst -> Coercion -> Coercion
    TCvSubst -> Coercion -> Coercion
    Coercion.substCo (Subst -> TCvSubst
    getTCvSubst Subst
    subst) Coercion
    co

    {-
    ************************************************************************
    *                                                                      *
    \section{IdInfo substitution}
    *                                                                      *
    ************************************************************************
    -}

    substIdType :: Subst -> Id -> Id
    substIdType :: Subst -> Id -> Id
    substIdType subst :: Subst
    subst@(Subst InScopeSet
    _ IdSubstEnv
    _ TvSubstEnv
    tv_env CvSubstEnv
    cv_env) Id
    id
      | (TvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv TvSubstEnv
    tv_env Bool -> Bool -> Bool
    && CvSubstEnv -> Bool
    forall a. VarEnv a -> Bool
    isEmptyVarEnv CvSubstEnv
    cv_env)
        Bool -> Bool -> Bool
    || (Type -> Bool
    noFreeVarsOfType Type
    old_ty Bool -> Bool -> Bool
    && Type -> Bool
    noFreeVarsOfType Type
    old_w) = Id
    id
      | Bool
    otherwise   =
          (Type -> Type) -> Id -> Id
    updateIdTypeAndMult (Subst -> Type -> Type
    substTy Subst
    subst) Id
    id
            -- The tyCoVarsOfType is cheaper than it looks
            -- because we cache the free tyvars of the type
            -- in a Note in the id's type itself
      where
        old_ty :: Type
    old_ty = Id -> Type
    idType Id
    id
        old_w :: Type
    old_w  = Id -> Type
    varMult Id
    id

    ------------------
    -- | Substitute into some 'IdInfo' with regard to the supplied new 'Id'.
    substIdInfo :: Subst -> Id -> IdInfo -> Maybe IdInfo
    substIdInfo :: Subst -> Id -> IdInfo -> Maybe IdInfo
    substIdInfo Subst
    subst Id
    new_id IdInfo
    info
      | Bool
    nothing_to_do = Maybe IdInfo
    forall a. Maybe a
    Nothing
      | Bool
    otherwise     = IdInfo -> Maybe IdInfo
    forall a. a -> Maybe a
    Just (IdInfo
    info IdInfo -> RuleInfo -> IdInfo
    `setRuleInfo`      Subst -> Id -> RuleInfo -> RuleInfo
    substRuleInfo Subst
    subst Id
    new_id RuleInfo
    old_rules
                                   IdInfo -> Unfolding -> IdInfo
    `setUnfoldingInfo` Subst -> Unfolding -> Unfolding
    substUnfolding Subst
    subst Unfolding
    old_unf)
      where
        old_rules :: RuleInfo
    old_rules     = IdInfo -> RuleInfo
    ruleInfo IdInfo
    info
        old_unf :: Unfolding
    old_unf       = IdInfo -> Unfolding
    unfoldingInfo IdInfo
    info
        nothing_to_do :: Bool
    nothing_to_do = RuleInfo -> Bool
    isEmptyRuleInfo RuleInfo
    old_rules Bool -> Bool -> Bool
    && Bool -> Bool
    not (Unfolding -> Bool
    hasCoreUnfolding Unfolding
    old_unf)

    ------------------
    -- | Substitutes for the 'Id's within an unfolding
    -- NB: substUnfolding /discards/ any unfolding without
    --     without a Stable source.  This is usually what we want,
    --     but it may be a bit unexpected
    substUnfolding, substUnfoldingSC :: Subst -> Unfolding -> Unfolding
            -- Seq'ing on the returned Unfolding is enough to cause
            -- all the substitutions to happen completely

    substUnfoldingSC :: Subst -> Unfolding -> Unfolding
    substUnfoldingSC Subst
    subst Unfolding
    unf       -- Short-cut version
      | Subst -> Bool
    isEmptySubst Subst
    subst = Unfolding
    unf
      | Bool
    otherwise          = Subst -> Unfolding -> Unfolding
    substUnfolding Subst
    subst Unfolding
    unf

    substUnfolding :: Subst -> Unfolding -> Unfolding
    substUnfolding Subst
    subst df :: Unfolding
    df@(DFunUnfolding { df_bndrs :: Unfolding -> [Id]
    df_bndrs = [Id]
    bndrs, df_args :: Unfolding -> [CoreExpr]
    df_args = [CoreExpr]
    args })
      = Unfolding
    df { df_bndrs :: [Id]
    df_bndrs = [Id]
    bndrs', df_args :: [CoreExpr]
    df_args = [CoreExpr]
    args' }
      where
        (Subst
    subst',[Id]
    bndrs') = Subst -> [Id] -> (Subst, [Id])
    substBndrs Subst
    subst [Id]
    bndrs
        args' :: [CoreExpr]
    args'           = (CoreExpr -> CoreExpr) -> [CoreExpr] -> [CoreExpr]
    forall a b. (a -> b) -> [a] -> [b]
    map (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst') [CoreExpr]
    args

    substUnfolding Subst
    subst unf :: Unfolding
    unf@(CoreUnfolding { uf_tmpl :: Unfolding -> CoreExpr
    uf_tmpl = CoreExpr
    tmpl, uf_src :: Unfolding -> UnfoldingSource
    uf_src = UnfoldingSource
    src })
            -- Retain an InlineRule!
      | Bool -> Bool
    not (UnfoldingSource -> Bool
    isStableSource UnfoldingSource
    src)  -- Zap an unstable unfolding, to save substitution work
      = Unfolding
    NoUnfolding
      | Bool
    otherwise                 -- But keep a stable one!
      = CoreExpr -> ()
    seqExpr CoreExpr
    new_tmpl () -> Unfolding -> Unfolding
    `seq`
        Unfolding
    unf { uf_tmpl :: CoreExpr
    uf_tmpl = CoreExpr
    new_tmpl }
      where
        new_tmpl :: CoreExpr
    new_tmpl = HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst CoreExpr
    tmpl

    substUnfolding Subst
    _ Unfolding
    unf = Unfolding
    unf      -- NoUnfolding, OtherCon

    ------------------
    substIdOcc :: Subst -> Id -> Id
    -- These Ids should not be substituted to non-Ids
    substIdOcc :: Subst -> Id -> Id
    substIdOcc Subst
    subst Id
    v = case HasDebugCallStack => Subst -> Id -> CoreExpr
    Subst -> Id -> CoreExpr
    lookupIdSubst Subst
    subst Id
    v of
                            Var Id
    v' -> Id
    v'
                            CoreExpr
    other  -> String -> SDoc -> Id
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "substIdOcc" ([SDoc] -> SDoc
    vcat [Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    v SDoc -> SDoc -> SDoc
    <+> CoreExpr -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr CoreExpr
    other, Subst -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Subst
    subst])

    ------------------
    -- | Substitutes for the 'Id's within the 'RuleInfo' given the new function 'Id'
    substRuleInfo :: Subst -> Id -> RuleInfo -> RuleInfo
    substRuleInfo :: Subst -> Id -> RuleInfo -> RuleInfo
    substRuleInfo Subst
    subst Id
    new_id (RuleInfo [CoreRule]
    rules DVarSet
    rhs_fvs)
      = [CoreRule] -> DVarSet -> RuleInfo
    RuleInfo ((CoreRule -> CoreRule) -> [CoreRule] -> [CoreRule]
    forall a b. (a -> b) -> [a] -> [b]
    map (Subst -> (Name -> Name) -> CoreRule -> CoreRule
    substRule Subst
    subst Name -> Name
    subst_ru_fn) [CoreRule]
    rules)
                      (Subst -> DVarSet -> DVarSet
    substDVarSet Subst
    subst DVarSet
    rhs_fvs)
      where
        subst_ru_fn :: Name -> Name
    subst_ru_fn = Name -> Name -> Name
    forall a b. a -> b -> a
    const (Id -> Name
    idName Id
    new_id)

    ------------------
    substRulesForImportedIds :: Subst -> [CoreRule] -> [CoreRule]
    substRulesForImportedIds :: Subst -> [CoreRule] -> [CoreRule]
    substRulesForImportedIds Subst
    subst [CoreRule]
    rules
      = (CoreRule -> CoreRule) -> [CoreRule] -> [CoreRule]
    forall a b. (a -> b) -> [a] -> [b]
    map (Subst -> (Name -> Name) -> CoreRule -> CoreRule
    substRule Subst
    subst Name -> Name
    forall {a} {a}. Outputable a => a -> a
    not_needed) [CoreRule]
    rules
      where
        not_needed :: a -> a
    not_needed a
    name = String -> SDoc -> a
    forall a. HasCallStack => String -> SDoc -> a
    pprPanic String
    "substRulesForImportedIds" (a -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr a
    name)

    ------------------
    substRule :: Subst -> (Name -> Name) -> CoreRule -> CoreRule

    -- The subst_ru_fn argument is applied to substitute the ru_fn field
    -- of the rule:
    --    - Rules for *imported* Ids never change ru_fn
    --    - Rules for *local* Ids are in the IdInfo for that Id,
    --      and the ru_fn field is simply replaced by the new name
    --      of the Id
    substRule :: Subst -> (Name -> Name) -> CoreRule -> CoreRule
    substRule Subst
    _ Name -> Name
    _ rule :: CoreRule
    rule@(BuiltinRule {}) = CoreRule
    rule
    substRule Subst
    subst Name -> Name
    subst_ru_fn rule :: CoreRule
    rule@(Rule { ru_bndrs :: CoreRule -> [Id]
    ru_bndrs = [Id]
    bndrs, ru_args :: CoreRule -> [CoreExpr]
    ru_args = [CoreExpr]
    args
                                           , ru_fn :: CoreRule -> Name
    ru_fn = Name
    fn_name, ru_rhs :: CoreRule -> CoreExpr
    ru_rhs = CoreExpr
    rhs
                                           , ru_local :: CoreRule -> Bool
    ru_local = Bool
    is_local })
      = CoreRule
    rule { ru_bndrs :: [Id]
    ru_bndrs = [Id]
    bndrs'
             , ru_fn :: Name
    ru_fn    = if Bool
    is_local
                            then Name -> Name
    subst_ru_fn Name
    fn_name
                            else Name
    fn_name
             , ru_args :: [CoreExpr]
    ru_args  = (CoreExpr -> CoreExpr) -> [CoreExpr] -> [CoreExpr]
    forall a b. (a -> b) -> [a] -> [b]
    map (HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst') [CoreExpr]
    args
             , ru_rhs :: CoreExpr
    ru_rhs   = HasDebugCallStack => Subst -> CoreExpr -> CoreExpr
    Subst -> CoreExpr -> CoreExpr
    substExpr Subst
    subst' CoreExpr
    rhs }
               -- Do NOT optimise the RHS (previously we did simplOptExpr here)
               -- See Note [Substitute lazily]
      where
        (Subst
    subst', [Id]
    bndrs') = Subst -> [Id] -> (Subst, [Id])
    substBndrs Subst
    subst [Id]
    bndrs

    ------------------
    substDVarSet :: Subst -> DVarSet -> DVarSet
    substDVarSet :: Subst -> DVarSet -> DVarSet
    substDVarSet Subst
    subst DVarSet
    fvs
      = [Id] -> DVarSet
    mkDVarSet ([Id] -> DVarSet) -> [Id] -> DVarSet
    forall a b. (a -> b) -> a -> b
    $ ([Id], VarSet) -> [Id]
    forall a b. (a, b) -> a
    fst (([Id], VarSet) -> [Id]) -> ([Id], VarSet) -> [Id]
    forall a b. (a -> b) -> a -> b
    $ (Id -> ([Id], VarSet) -> ([Id], VarSet))
    -> ([Id], VarSet) -> [Id] -> ([Id], VarSet)
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    foldr (Subst -> Id -> ([Id], VarSet) -> ([Id], VarSet)
    subst_fv Subst
    subst) ([], VarSet
    emptyVarSet) ([Id] -> ([Id], VarSet)) -> [Id] -> ([Id], VarSet)
    forall a b. (a -> b) -> a -> b
    $ DVarSet -> [Id]
    dVarSetElems DVarSet
    fvs
      where
      subst_fv :: Subst -> Id -> ([Id], VarSet) -> ([Id], VarSet)
    subst_fv Subst
    subst Id
    fv ([Id], VarSet)
    acc
         | Id -> Bool
    isId Id
    fv = CoreExpr -> FV
    expr_fvs (HasDebugCallStack => Subst -> Id -> CoreExpr
    Subst -> Id -> CoreExpr
    lookupIdSubst Subst
    subst Id
    fv) Id -> Bool
    isLocalVar VarSet
    emptyVarSet (([Id], VarSet) -> ([Id], VarSet))
    -> ([Id], VarSet) -> ([Id], VarSet)
    forall a b. (a -> b) -> a -> b
    $! ([Id], VarSet)
    acc
         | Bool
    otherwise = Type -> FV
    tyCoFVsOfType (Subst -> Id -> Type
    lookupTCvSubst Subst
    subst Id
    fv) (Bool -> Id -> Bool
    forall a b. a -> b -> a
    const Bool
    True) VarSet
    emptyVarSet (([Id], VarSet) -> ([Id], VarSet))
    -> ([Id], VarSet) -> ([Id], VarSet)
    forall a b. (a -> b) -> a -> b
    $! ([Id], VarSet)
    acc

    ------------------
    substTickish :: Subst -> CoreTickish -> CoreTickish
    substTickish :: Subst -> CoreTickish -> CoreTickish
    substTickish Subst
    subst (Breakpoint XBreakpoint 'TickishPassCore
    ext Int
    n [XTickishId 'TickishPassCore]
    ids)
       = XBreakpoint 'TickishPassCore
    -> Int -> [XTickishId 'TickishPassCore] -> CoreTickish
    forall (pass :: TickishPass).
    XBreakpoint pass -> Int -> [XTickishId pass] -> GenTickish pass
    Breakpoint XBreakpoint 'TickishPassCore
    ext Int
    n ((Id -> Id) -> [Id] -> [Id]
    forall a b. (a -> b) -> [a] -> [b]
    map Id -> Id
    do_one [Id]
    [XTickishId 'TickishPassCore]
    ids)
     where
        do_one :: Id -> Id
    do_one = HasDebugCallStack => CoreExpr -> Id
    CoreExpr -> Id
    getIdFromTrivialExpr (CoreExpr -> Id) -> (Id -> CoreExpr) -> Id -> Id
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HasDebugCallStack => Subst -> Id -> CoreExpr
    Subst -> Id -> CoreExpr
    lookupIdSubst Subst
    subst
    substTickish Subst
    _subst CoreTickish
    other = CoreTickish
    other

    {- Note [Substitute lazily]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The functions that substitute over IdInfo must be pretty lazy, because
    they are knot-tied by substRecBndrs.

    One case in point was #10627 in which a rule for a function 'f'
    referred to 'f' (at a different type) on the RHS.  But instead of just
    substituting in the rhs of the rule, we were calling simpleOptExpr, which
    looked at the idInfo for 'f'; result <<loop>>.

    In any case we don't need to optimise the RHS of rules, or unfoldings,
    because the simplifier will do that.

    Another place this went wrong was in `substRuleInfo`, which would immediately force
    the lazy call to substExpr, which led to an infinite loop (as reported by #20112).

    This time the call stack looked something like:

    * `substRecBndrs`
    * `substIdBndr`
    * `substIdInfo`
    * `substRuleInfo`
    * `substRule`
    * `substExpr`
    * `mkTick`
    * `isSaturatedConApp`
    * Look at `IdInfo` for thing we are currently substituting because the rule is attached to `transpose` and mentions it in the `RHS` of the rule.

    and the rule was

    {-# RULES
    "transpose/overlays1" forall xs. transpose (overlays1 xs) = overlays1 (fmap transpose xs)
    #-}

    This rule was attached to `transpose`, but also mentions itself in the RHS so we have
    to be careful to not force the `IdInfo` for transpose when dealing with the RHS of the rule.

    Note [substTickish]
    ~~~~~~~~~~~~~~~~~~~~~~
    A Breakpoint contains a list of Ids.  What happens if we ever want to
    substitute an expression for one of these Ids?

    First, we ensure that we only ever substitute trivial expressions for
    these Ids, by marking them as NoOccInfo in the occurrence analyser.
    Then, when substituting for the Id, we unwrap any type applications
    and abstractions to get back to an Id, with getIdFromTrivialExpr.

    Second, we have to ensure that we never try to substitute a literal
    for an Id in a breakpoint.  We ensure this by never storing an Id with
    an unlifted type in a Breakpoint - see GHC.HsToCore.Coverage.mkTickish.
    Breakpoints can't handle free variables with unlifted types anyway.
    -}

    {-
    Note [Worker inlining]
    ~~~~~~~~~~~~~~~~~~~~~~
    A worker can get substituted away entirely.
            - it might be trivial
            - it might simply be very small
    We do not treat an InlWrapper as an 'occurrence' in the occurrence
    analyser, so it's possible that the worker is not even in scope any more.

    In all these cases we simply drop the special case, returning to
    InlVanilla.  The WARN is just so I can see if it happens a lot.
    -}