module CoreTidy (
        tidyExpr, tidyRules, tidyUnfolding
    ) where
#include "HsVersions.h"
import GhcPrelude
import CoreSyn
import CoreSeq ( seqUnfolding )
import Id
import IdInfo
import Demand ( zapUsageEnvSig )
import Type( tidyType, tidyVarBndr )
import Coercion( tidyCo )
import Var
import VarEnv
import UniqFM
import Name hiding (tidyNameOcc)
import SrcLoc
import Maybes
import Data.List
tidyBind :: TidyEnv
         -> CoreBind
         ->  (TidyEnv, CoreBind)
tidyBind env (NonRec bndr rhs)
  = tidyLetBndr env env bndr =: \ (env', bndr') ->
    (env', NonRec bndr' (tidyExpr env' rhs))
tidyBind env (Rec prs)
  = let
       (bndrs, rhss)  = unzip prs
       (env', bndrs') = mapAccumL (tidyLetBndr env') env bndrs
    in
    map (tidyExpr env') rhss =: \ rhss' ->
    (env', Rec (zip bndrs' rhss'))
tidyExpr :: TidyEnv -> CoreExpr -> CoreExpr
tidyExpr env (Var v)       = Var (tidyVarOcc env v)
tidyExpr env (Type ty)     = Type (tidyType env ty)
tidyExpr env (Coercion co) = Coercion (tidyCo env co)
tidyExpr _   (Lit lit)     = Lit lit
tidyExpr env (App f a)     = App (tidyExpr env f) (tidyExpr env a)
tidyExpr env (Tick t e)    = Tick (tidyTickish env t) (tidyExpr env e)
tidyExpr env (Cast e co)   = Cast (tidyExpr env e) (tidyCo env co)
tidyExpr env (Let b e)
  = tidyBind env b      =: \ (env', b') ->
    Let b' (tidyExpr env' e)
tidyExpr env (Case e b ty alts)
  = tidyBndr env b  =: \ (env', b) ->
    Case (tidyExpr env e) b (tidyType env ty)
         (map (tidyAlt env') alts)
tidyExpr env (Lam b e)
  = tidyBndr env b      =: \ (env', b) ->
    Lam b (tidyExpr env' e)
tidyAlt :: TidyEnv -> CoreAlt -> CoreAlt
tidyAlt env (con, vs, rhs)
  = tidyBndrs env vs    =: \ (env', vs) ->
    (con, vs, tidyExpr env' rhs)
tidyTickish :: TidyEnv -> Tickish Id -> Tickish Id
tidyTickish env (Breakpoint ix ids) = Breakpoint ix (map (tidyVarOcc env) ids)
tidyTickish _   other_tickish       = other_tickish
tidyRules :: TidyEnv -> [CoreRule] -> [CoreRule]
tidyRules _   [] = []
tidyRules env (rule : rules)
  = tidyRule env rule           =: \ rule ->
    tidyRules env rules         =: \ rules ->
    (rule : rules)
tidyRule :: TidyEnv -> CoreRule -> CoreRule
tidyRule _   rule@(BuiltinRule {}) = rule
tidyRule env rule@(Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs,
                          ru_fn = fn, ru_rough = mb_ns })
  = tidyBndrs env bndrs         =: \ (env', bndrs) ->
    map (tidyExpr env') args    =: \ args ->
    rule { ru_bndrs = bndrs, ru_args = args,
           ru_rhs   = tidyExpr env' rhs,
           ru_fn    = tidyNameOcc env fn,
           ru_rough = map (fmap (tidyNameOcc env')) mb_ns }
tidyNameOcc :: TidyEnv -> Name -> Name
tidyNameOcc (_, var_env) n = case lookupUFM var_env n of
                                Nothing -> n
                                Just v  -> idName v
tidyVarOcc :: TidyEnv -> Var -> Var
tidyVarOcc (_, var_env) v = lookupVarEnv var_env v `orElse` v
tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var)
tidyBndr env var
  | isTyCoVar var = tidyVarBndr env var
  | otherwise     = tidyIdBndr env var
tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var])
tidyBndrs env vars = mapAccumL tidyBndr env vars
tidyIdBndr :: TidyEnv -> Id -> (TidyEnv, Id)
tidyIdBndr env@(tidy_env, var_env) id
  = 
    
    case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') ->
    let
        
        
        
        
        ty'      = tidyType env (idType id)
        name'    = mkInternalName (idUnique id) occ' noSrcSpan
        id'      = mkLocalIdWithInfo name' ty' new_info
        var_env' = extendVarEnv var_env id id'
        
        new_info = vanillaIdInfo `setOccInfo` occInfo old_info
                                 `setUnfoldingInfo` new_unf
                                  
                                 `setOneShotInfo` oneShotInfo old_info
        old_info = idInfo id
        old_unf  = unfoldingInfo old_info
        new_unf  = zapUnfolding old_unf  
    in
    ((tidy_env', var_env'), id')
   }
tidyLetBndr :: TidyEnv         
            -> TidyEnv         
            -> Id -> (TidyEnv, Id)
tidyLetBndr rec_tidy_env env@(tidy_env, var_env) id
  = case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') ->
    let
        ty'      = tidyType env (idType id)
        name'    = mkInternalName (idUnique id) occ' noSrcSpan
        details  = idDetails id
        id'      = mkLocalVar details name' ty' new_info
        var_env' = extendVarEnv var_env id id'
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        old_info = idInfo id
        new_info = vanillaIdInfo
                    `setOccInfo`        occInfo old_info
                    `setArityInfo`      arityInfo old_info
                    `setStrictnessInfo` zapUsageEnvSig (strictnessInfo old_info)
                    `setDemandInfo`     demandInfo old_info
                    `setInlinePragInfo` inlinePragInfo old_info
                    `setUnfoldingInfo`  new_unf
        old_unf = unfoldingInfo old_info
        new_unf | isStableUnfolding old_unf = tidyUnfolding rec_tidy_env old_unf old_unf
                | otherwise                 = zapUnfolding old_unf
                                              
    in
    ((tidy_env', var_env'), id') }
tidyUnfolding :: TidyEnv -> Unfolding -> Unfolding -> Unfolding
tidyUnfolding tidy_env df@(DFunUnfolding { df_bndrs = bndrs, df_args = args }) _
  = df { df_bndrs = bndrs', df_args = map (tidyExpr tidy_env') args }
  where
    (tidy_env', bndrs') = tidyBndrs tidy_env bndrs
tidyUnfolding tidy_env
              unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src })
              unf_from_rhs
  | isStableSource src
  = seqIt $ unf { uf_tmpl = tidyExpr tidy_env unf_rhs }    
    
    
    
  | otherwise
  = unf_from_rhs
  where seqIt unf = seqUnfolding unf `seq` unf
tidyUnfolding _ unf _ = unf     
(=:) :: a -> (a -> b) -> b
m =: k = m `seq` k m