summaryrefslogtreecommitdiff
path: root/compiler/stgSyn
diff options
context:
space:
mode:
authorKavon Farvardin <kavon@farvard.in>2018-09-23 15:29:37 -0500
committerKavon Farvardin <kavon@farvard.in>2018-09-23 15:29:37 -0500
commit84c2ad99582391005b5e873198b15e9e9eb4f78d (patch)
treecaa8c2f2ec7e97fbb4977263c6817c9af5025cf4 /compiler/stgSyn
parent8ddb47cfcf5776e9a3c55fd37947c8a95e00fa12 (diff)
parente68b439fe5de61b9a2ca51af472185c62ccb8b46 (diff)
downloadhaskell-wip/T13904.tar.gz
update to current master againwip/T13904
Diffstat (limited to 'compiler/stgSyn')
-rw-r--r--compiler/stgSyn/CoreToStg.hs257
-rw-r--r--compiler/stgSyn/StgLint.hs526
-rw-r--r--compiler/stgSyn/StgSyn.hs39
3 files changed, 373 insertions, 449 deletions
diff --git a/compiler/stgSyn/CoreToStg.hs b/compiler/stgSyn/CoreToStg.hs
index 900d23f7b5..fdd8d5bef3 100644
--- a/compiler/stgSyn/CoreToStg.hs
+++ b/compiler/stgSyn/CoreToStg.hs
@@ -11,12 +11,15 @@
-- And, as we have the info in hand, we may convert some lets to
-- let-no-escapes.
-module CoreToStg ( coreToStg, coreExprToStg ) where
+module CoreToStg ( coreToStg ) where
#include "HsVersions.h"
+import GhcPrelude
+
import CoreSyn
-import CoreUtils ( exprType, findDefault, isJoinBind )
+import CoreUtils ( exprType, findDefault, isJoinBind
+ , exprIsTickedString_maybe )
import CoreArity ( manifestArity )
import StgSyn
@@ -27,10 +30,10 @@ import MkId ( coercionTokenId )
import Id
import IdInfo
import DataCon
-import CostCentre ( noCCS )
+import CostCentre
import VarEnv
import Module
-import Name ( isExternalName, nameOccName )
+import Name ( isExternalName, nameOccName, nameModule_maybe )
import OccName ( occNameFS )
import BasicTypes ( Arity )
import TysWiredIn ( unboxedUnitDataCon )
@@ -44,7 +47,9 @@ import ForeignCall
import Demand ( isUsedOnce )
import PrimOp ( PrimCall(..) )
import UniqFM
+import SrcLoc ( mkGeneralSrcSpan )
+import Data.List.NonEmpty (nonEmpty, toList)
import Data.Maybe (isJust, fromMaybe)
import Control.Monad (liftM, ap)
@@ -126,15 +131,6 @@ import Control.Monad (liftM, ap)
--
-- The CafInfo has already been calculated during the CoreTidy pass.
--
--- During CoreToStg, we then pin onto each binding and case expression, a
--- list of Ids which represents the "live" CAFs at that point. The meaning
--- of "live" here is the same as for live variables, see above (which is
--- why it's convenient to collect CAF information here rather than elsewhere).
---
--- The later SRT pass takes these lists of Ids and uses them to construct
--- the actual nested SRTs, and replaces the lists of Ids with (offset,length)
--- pairs.
-
-- Note [What is a non-escaping let]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
@@ -194,61 +190,99 @@ import Control.Monad (liftM, ap)
-- in
-- ...(x b)...
+-- Note [Cost-centre initialization plan]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--
+-- Previously `coreToStg` was initializing cost-centre stack fields as `noCCS`,
+-- and the fields were then fixed by a seperate pass `stgMassageForProfiling`.
+-- We now initialize these correctly. The initialization works like this:
+--
+-- - For non-top level bindings always use `currentCCS`.
+--
+-- - For top-level bindings, check if the binding is a CAF
+--
+-- - CAF: If -fcaf-all is enabled, create a new CAF just for this CAF
+-- and use it. Note that these new cost centres need to be
+-- collected to be able to generate cost centre initialization
+-- code, so `coreToTopStgRhs` now returns `CollectedCCs`.
+--
+-- If -fcaf-all is not enabled, use "all CAFs" cost centre.
+--
+-- - Non-CAF: Top-level (static) data is not counted in heap profiles; nor
+-- do we set CCCS from it; so we just slam in
+-- dontCareCostCentre.
+
-- --------------------------------------------------------------
-- Setting variable info: top-level, binds, RHSs
-- --------------------------------------------------------------
-coreToStg :: DynFlags -> Module -> CoreProgram -> [StgTopBinding]
+coreToStg :: DynFlags -> Module -> CoreProgram
+ -> ([StgTopBinding], CollectedCCs)
coreToStg dflags this_mod pgm
- = pgm'
- where (_, _, pgm') = coreTopBindsToStg dflags this_mod emptyVarEnv pgm
+ = (pgm', final_ccs)
+ where
+ (_, _, (local_ccs, local_cc_stacks), pgm')
+ = coreTopBindsToStg dflags this_mod emptyVarEnv emptyCollectedCCs pgm
+
+ prof = WayProf `elem` ways dflags
-coreExprToStg :: CoreExpr -> StgExpr
-coreExprToStg expr
- = new_expr where (new_expr,_) = initCts emptyVarEnv (coreToStgExpr expr)
+ final_ccs
+ | prof && gopt Opt_AutoSccsOnIndividualCafs dflags
+ = (local_ccs,local_cc_stacks) -- don't need "all CAFs" CC
+ | prof
+ = (all_cafs_cc:local_ccs, all_cafs_ccs:local_cc_stacks)
+ | otherwise
+ = emptyCollectedCCs
+ (all_cafs_cc, all_cafs_ccs) = getAllCAFsCC this_mod
coreTopBindsToStg
:: DynFlags
-> Module
-> IdEnv HowBound -- environment for the bindings
+ -> CollectedCCs
-> CoreProgram
- -> (IdEnv HowBound, FreeVarsInfo, [StgTopBinding])
+ -> (IdEnv HowBound, FreeVarsInfo, CollectedCCs, [StgTopBinding])
-coreTopBindsToStg _ _ env [] = (env, emptyFVInfo, [])
-coreTopBindsToStg dflags this_mod env (b:bs)
- = (env2, fvs2, b':bs')
+coreTopBindsToStg _ _ env ccs []
+ = (env, emptyFVInfo, ccs, [])
+coreTopBindsToStg dflags this_mod env ccs (b:bs)
+ = (env2, fvs2, ccs2, b':bs')
where
-- Notice the mutually-recursive "knot" here:
-- env accumulates down the list of binds,
-- fvs accumulates upwards
- (env1, fvs2, b' ) = coreTopBindToStg dflags this_mod env fvs1 b
- (env2, fvs1, bs') = coreTopBindsToStg dflags this_mod env1 bs
+ (env1, fvs2, ccs1, b' ) =
+ coreTopBindToStg dflags this_mod env fvs1 ccs b
+ (env2, fvs1, ccs2, bs') =
+ coreTopBindsToStg dflags this_mod env1 ccs1 bs
coreTopBindToStg
:: DynFlags
-> Module
-> IdEnv HowBound
-> FreeVarsInfo -- Info about the body
+ -> CollectedCCs
-> CoreBind
- -> (IdEnv HowBound, FreeVarsInfo, StgTopBinding)
+ -> (IdEnv HowBound, FreeVarsInfo, CollectedCCs, StgTopBinding)
-coreTopBindToStg _ _ env body_fvs (NonRec id (Lit (MachStr str)))
+coreTopBindToStg _ _ env body_fvs ccs (NonRec id e)
+ | Just str <- exprIsTickedString_maybe e
-- top-level string literal
+ -- See Note [CoreSyn top-level string literals] in CoreSyn
= let
env' = extendVarEnv env id how_bound
how_bound = LetBound TopLet 0
- in (env', body_fvs, StgTopStringLit id str)
+ in (env', body_fvs, ccs, StgTopStringLit id str)
-coreTopBindToStg dflags this_mod env body_fvs (NonRec id rhs)
+coreTopBindToStg dflags this_mod env body_fvs ccs (NonRec id rhs)
= let
env' = extendVarEnv env id how_bound
how_bound = LetBound TopLet $! manifestArity rhs
- (stg_rhs, fvs') =
- initCts env $ do
- (stg_rhs, fvs') <- coreToTopStgRhs dflags this_mod body_fvs (id,rhs)
- return (stg_rhs, fvs')
+ (stg_rhs, fvs', ccs') =
+ initCts env $
+ coreToTopStgRhs dflags ccs this_mod body_fvs (id,rhs)
bind = StgTopLifted $ StgNonRec id stg_rhs
in
@@ -257,9 +291,9 @@ coreTopBindToStg dflags this_mod env body_fvs (NonRec id rhs)
-- as well as 'id', but that led to a black hole
-- where printing the assertion error tripped the
-- assertion again!
- (env', fvs' `unionFVInfo` body_fvs, bind)
+ (env', fvs' `unionFVInfo` body_fvs, ccs', bind)
-coreTopBindToStg dflags this_mod env body_fvs (Rec pairs)
+coreTopBindToStg dflags this_mod env body_fvs ccs (Rec pairs)
= ASSERT( not (null pairs) )
let
binders = map fst pairs
@@ -268,16 +302,21 @@ coreTopBindToStg dflags this_mod env body_fvs (Rec pairs)
| (b, rhs) <- pairs ]
env' = extendVarEnvList env extra_env'
- (stg_rhss, fvs')
+ -- generate StgTopBindings, accumulate body_fvs and CAF cost centres
+ -- created for CAFs
+ ((fvs', ccs'), stg_rhss)
= initCts env' $ do
- (stg_rhss, fvss') <- mapAndUnzipM (coreToTopStgRhs dflags this_mod body_fvs) pairs
- let fvs' = unionFVInfos fvss'
- return (stg_rhss, fvs')
+ mapAccumLM (\(fvs, ccs) rhs -> do
+ (rhs', fvs', ccs') <-
+ coreToTopStgRhs dflags ccs this_mod body_fvs rhs
+ return ((fvs' `unionFVInfo` fvs, ccs'), rhs'))
+ (body_fvs, ccs)
+ pairs
bind = StgTopLifted $ StgRec (zip binders stg_rhss)
in
ASSERT2(consistentCafInfo (head binders) bind, ppr binders)
- (env', fvs' `unionFVInfo` body_fvs, bind)
+ (env', fvs' `unionFVInfo` body_fvs, ccs', bind)
-- Assertion helper: this checks that the CafInfo on the Id matches
@@ -297,18 +336,23 @@ consistentCafInfo id bind
coreToTopStgRhs
:: DynFlags
+ -> CollectedCCs
-> Module
-> FreeVarsInfo -- Free var info for the scope of the binding
-> (Id,CoreExpr)
- -> CtsM (StgRhs, FreeVarsInfo)
+ -> CtsM (StgRhs, FreeVarsInfo, CollectedCCs)
-coreToTopStgRhs dflags this_mod scope_fv_info (bndr, rhs)
+coreToTopStgRhs dflags ccs this_mod scope_fv_info (bndr, rhs)
= do { (new_rhs, rhs_fvs) <- coreToStgExpr rhs
- ; let stg_rhs = mkTopStgRhs dflags this_mod rhs_fvs bndr bndr_info new_rhs
- stg_arity = stgRhsArity stg_rhs
+ ; let (stg_rhs, ccs') =
+ mkTopStgRhs dflags this_mod ccs rhs_fvs bndr bndr_info new_rhs
+ stg_arity =
+ stgRhsArity stg_rhs
+
; return (ASSERT2( arity_ok stg_arity, mk_arity_msg stg_arity) stg_rhs,
- rhs_fvs) }
+ rhs_fvs,
+ ccs') }
where
bndr_info = lookupFVInfo scope_fv_info bndr
@@ -331,14 +375,6 @@ coreToTopStgRhs dflags this_mod scope_fv_info (bndr, rhs)
text "Id arity:" <+> ppr id_arity,
text "STG arity:" <+> ppr stg_arity]
-mkTopStgRhs :: DynFlags -> Module -> FreeVarsInfo
- -> Id -> StgBinderInfo -> StgExpr
- -> StgRhs
-
-mkTopStgRhs dflags this_mod = mkStgRhs' con_updateable
- -- Dynamic StgConApps are updatable
- where con_updateable con args = isDllConApp dflags this_mod con args
-
-- ---------------------------------------------------------------------------
-- Expressions
-- ---------------------------------------------------------------------------
@@ -354,9 +390,10 @@ coreToStgExpr
-- on these components, but it in turn is not scrutinised as the basis for any
-- decisions. Hence no black holes.
--- No LitInteger's should be left by the time this is called. CorePrep
--- should have converted them all to a real core representation.
-coreToStgExpr (Lit (LitInteger {})) = panic "coreToStgExpr: LitInteger"
+-- No LitInteger's or LitNatural's should be left by the time this is called.
+-- CorePrep should have converted them all to a real core representation.
+coreToStgExpr (Lit (LitNumber LitNumInteger _ _)) = panic "coreToStgExpr: LitInteger"
+coreToStgExpr (Lit (LitNumber LitNumNatural _ _)) = panic "coreToStgExpr: LitNatural"
coreToStgExpr (Lit l) = return (StgLit l, emptyFVInfo)
coreToStgExpr (Var v) = coreToStgApp Nothing v [] []
coreToStgExpr (Coercion _) = coreToStgApp Nothing coercionTokenId [] []
@@ -374,9 +411,10 @@ coreToStgExpr expr@(Lam _ _)
extendVarEnvCts [ (a, LambdaBound) | a <- args' ] $ do
(body, body_fvs) <- coreToStgExpr body
let
- fvs = args' `minusFVBinders` body_fvs
- result_expr | null args' = body
- | otherwise = StgLam args' body
+ fvs = args' `minusFVBinders` body_fvs
+ result_expr = case nonEmpty args' of
+ Nothing -> body
+ Just args'' -> StgLam args'' body
return (result_expr, fvs)
@@ -718,36 +756,85 @@ coreToStgRhs scope_fv_info (bndr, rhs) = do
where
bndr_info = lookupFVInfo scope_fv_info bndr
-mkStgRhs :: FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr -> StgRhs
-mkStgRhs = mkStgRhs' con_updateable
- where con_updateable _ _ = False
+-- Generate a top-level RHS. Any new cost centres generated for CAFs will be
+-- appended to `CollectedCCs` argument.
+mkTopStgRhs :: DynFlags -> Module -> CollectedCCs
+ -> FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr
+ -> (StgRhs, CollectedCCs)
-mkStgRhs' :: (DataCon -> [StgArg] -> Bool)
- -> FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr -> StgRhs
-mkStgRhs' con_updateable rhs_fvs bndr binder_info rhs
+mkTopStgRhs dflags this_mod ccs rhs_fvs bndr binder_info rhs
| StgLam bndrs body <- rhs
- = StgRhsClosure noCCS binder_info
- (getFVs rhs_fvs)
- ReEntrant
- bndrs body
- | isJoinId bndr -- must be nullary join point
- = ASSERT(idJoinArity bndr == 0)
- StgRhsClosure noCCS binder_info
- (getFVs rhs_fvs)
- ReEntrant -- ignored for LNE
- [] rhs
+ = -- StgLam can't have empty arguments, so not CAF
+ ( StgRhsClosure dontCareCCS binder_info
+ (getFVs rhs_fvs)
+ ReEntrant
+ (toList bndrs) body
+ , ccs )
+
| StgConApp con args _ <- unticked_rhs
- , not (con_updateable con args)
+ , -- Dynamic StgConApps are updatable
+ not (isDllConApp dflags this_mod con args)
= -- CorePrep does this right, but just to make sure
ASSERT2( not (isUnboxedTupleCon con || isUnboxedSumCon con)
, ppr bndr $$ ppr con $$ ppr args)
- StgRhsCon noCCS con args
+ ( StgRhsCon dontCareCCS con args, ccs )
+
+ -- Otherwise it's a CAF, see Note [Cost-centre initialization plan].
+ | gopt Opt_AutoSccsOnIndividualCafs dflags
+ = ( StgRhsClosure caf_ccs binder_info
+ (getFVs rhs_fvs)
+ upd_flag [] rhs
+ , collectCC caf_cc caf_ccs ccs )
+
| otherwise
- = StgRhsClosure noCCS binder_info
- (getFVs rhs_fvs)
- upd_flag [] rhs
- where
+ = ( StgRhsClosure all_cafs_ccs binder_info
+ (getFVs rhs_fvs)
+ upd_flag [] rhs
+ , ccs )
+
+ where
+ (_, unticked_rhs) = stripStgTicksTop (not . tickishIsCode) rhs
+
+ upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry
+ | otherwise = Updatable
+
+ -- CAF cost centres generated for -fcaf-all
+ caf_cc = mkAutoCC bndr modl
+ caf_ccs = mkSingletonCCS caf_cc
+ -- careful: the binder might be :Main.main,
+ -- which doesn't belong to module mod_name.
+ -- bug #249, tests prof001, prof002
+ modl | Just m <- nameModule_maybe (idName bndr) = m
+ | otherwise = this_mod
+
+ -- default CAF cost centre
+ (_, all_cafs_ccs) = getAllCAFsCC this_mod
+
+-- Generate a non-top-level RHS. Cost-centre is always currentCCS,
+-- see Note [Cost-centre initialzation plan].
+mkStgRhs :: FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr -> StgRhs
+mkStgRhs rhs_fvs bndr binder_info rhs
+ | StgLam bndrs body <- rhs
+ = StgRhsClosure currentCCS binder_info
+ (getFVs rhs_fvs)
+ ReEntrant
+ (toList bndrs) body
+
+ | isJoinId bndr -- must be a nullary join point
+ = ASSERT(idJoinArity bndr == 0)
+ StgRhsClosure currentCCS binder_info
+ (getFVs rhs_fvs)
+ ReEntrant -- ignored for LNE
+ [] rhs
+
+ | StgConApp con args _ <- unticked_rhs
+ = StgRhsCon currentCCS con args
+ | otherwise
+ = StgRhsClosure currentCCS binder_info
+ (getFVs rhs_fvs)
+ upd_flag [] rhs
+ where
(_, unticked_rhs) = stripStgTicksTop (not . tickishIsCode) rhs
upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry
@@ -903,6 +990,14 @@ lookupBinding env v = case lookupVarEnv env v of
Just xx -> xx
Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound
+getAllCAFsCC :: Module -> (CostCentre, CostCentreStack)
+getAllCAFsCC this_mod =
+ let
+ span = mkGeneralSrcSpan (mkFastString "<entire-module>") -- XXX do better
+ all_cafs_cc = mkAllCafsCC this_mod span
+ all_cafs_ccs = mkSingletonCCS all_cafs_cc
+ in
+ (all_cafs_cc, all_cafs_ccs)
-- ---------------------------------------------------------------------------
-- Free variable information
diff --git a/compiler/stgSyn/StgLint.hs b/compiler/stgSyn/StgLint.hs
index cbfd11b8d9..58f14a1b3f 100644
--- a/compiler/stgSyn/StgLint.hs
+++ b/compiler/stgSyn/StgLint.hs
@@ -1,74 +1,80 @@
-{-
+{- |
(c) The GRASP/AQUA Project, Glasgow University, 1993-1998
-\section[StgLint]{A ``lint'' pass to check for Stg correctness}
--}
+A lint pass to check basic STG invariants:
+
+- Variables should be defined before used.
+
+- Let bindings should not have unboxed types (unboxed bindings should only
+ appear in case), except when they're join points (see Note [CoreSyn let/app
+ invariant] and #14117).
+
+- If linting after unarisation, invariants listed in Note [Post-unarisation
+ invariants].
+
+Because we don't have types and coercions in STG we can't really check types
+here.
+
+Some history:
-{-# LANGUAGE CPP #-}
+StgLint used to check types, but it never worked and so it was disabled in 2000
+with this note:
+
+ WARNING:
+ ~~~~~~~~
+
+ This module has suffered bit-rot; it is likely to yield lint errors
+ for Stg code that is currently perfectly acceptable for code
+ generation. Solution: don't use it! (KSW 2000-05).
+
+Since then there were some attempts at enabling it again, as summarised in
+#14787. It's finally decided that we remove all type checking and only look for
+basic properties listed above.
+-}
module StgLint ( lintStgTopBindings ) where
+import GhcPrelude
+
import StgSyn
+import DynFlags
import Bag ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )
-import Id ( Id, idType, isLocalId )
+import Id ( Id, idType, isLocalId, isJoinId )
import VarSet
import DataCon
import CoreSyn ( AltCon(..) )
-import PrimOp ( primOpType )
-import Literal ( literalType )
-import Maybes
import Name ( getSrcLoc )
import ErrUtils ( MsgDoc, Severity(..), mkLocMessage )
import Type
import RepType
-import TyCon
-import Util
import SrcLoc
import Outputable
+import qualified ErrUtils as Err
+import Control.Applicative ((<|>))
import Control.Monad
-#include "HsVersions.h"
-
-{-
-Checks for
- (a) *some* type errors
- (b) locally-defined variables used but not defined
-
-
-Note: unless -dverbose-stg is on, display of lint errors will result
-in "panic: bOGUS_LVs".
-
-WARNING:
-~~~~~~~~
-
-This module has suffered bit-rot; it is likely to yield lint errors
-for Stg code that is currently perfectly acceptable for code
-generation. Solution: don't use it! (KSW 2000-05).
-
-
-************************************************************************
-* *
-\subsection{``lint'' for various constructs}
-* *
-************************************************************************
-
-@lintStgTopBindings@ is the top-level interface function.
--}
+lintStgTopBindings :: DynFlags
+ -> Bool -- ^ have we run Unarise yet?
+ -> String -- ^ who produced the STG?
+ -> [StgTopBinding]
+ -> IO ()
-lintStgTopBindings :: String -> [StgTopBinding] -> [StgTopBinding]
-
-lintStgTopBindings whodunnit binds
+lintStgTopBindings dflags unarised whodunnit binds
= {-# SCC "StgLint" #-}
- case (initL (lint_binds binds)) of
- Nothing -> binds
- Just msg -> pprPanic "" (vcat [
- text "*** Stg Lint ErrMsgs: in" <+>
- text whodunnit <+> text "***",
- msg,
- text "*** Offending Program ***",
- pprStgTopBindings binds,
- text "*** End of Offense ***"])
+ case initL unarised (lint_binds binds) of
+ Nothing ->
+ return ()
+ Just msg -> do
+ putLogMsg dflags NoReason Err.SevDump noSrcSpan
+ (defaultDumpStyle dflags)
+ (vcat [ text "*** Stg Lint ErrMsgs: in" <+>
+ text whodunnit <+> text "***",
+ msg,
+ text "*** Offending Program ***",
+ pprStgTopBindings binds,
+ text "*** End of Offense ***"])
+ Err.ghcExit dflags 1
where
lint_binds :: [StgTopBinding] -> LintM ()
@@ -81,13 +87,12 @@ lintStgTopBindings whodunnit binds
lint_bind (StgTopLifted bind) = lintStgBinds bind
lint_bind (StgTopStringLit v _) = return [v]
-lintStgArg :: StgArg -> LintM (Maybe Type)
-lintStgArg (StgLitArg lit) = return (Just (literalType lit))
-lintStgArg (StgVarArg v) = lintStgVar v
+lintStgArg :: StgArg -> LintM ()
+lintStgArg (StgLitArg _) = return ()
+lintStgArg (StgVarArg v) = lintStgVar v
-lintStgVar :: Id -> LintM (Maybe Kind)
-lintStgVar v = do checkInScope v
- return (Just (idType v))
+lintStgVar :: Id -> LintM ()
+lintStgVar id = checkInScope id
lintStgBinds :: StgBinding -> LintM [Id] -- Returns the binders
lintStgBinds (StgNonRec binder rhs) = do
@@ -104,80 +109,50 @@ lintStgBinds (StgRec pairs)
lint_binds_help :: (Id, StgRhs) -> LintM ()
lint_binds_help (binder, rhs)
= addLoc (RhsOf binder) $ do
- -- Check the rhs
- _maybe_rhs_ty <- lintStgRhs rhs
-
- -- Check binder doesn't have unlifted type
- checkL (not (isUnliftedType binder_ty))
+ lintStgRhs rhs
+ -- Check binder doesn't have unlifted type or it's a join point
+ checkL (isJoinId binder || not (isUnliftedType (idType binder)))
(mkUnliftedTyMsg binder rhs)
- -- Check match to RHS type
- -- Actually we *can't* check the RHS type, because
- -- unsafeCoerce means it really might not match at all
- -- notably; eg x::Int = (error @Bool "urk") |> unsafeCoerce...
- -- case maybe_rhs_ty of
- -- Nothing -> return ()
- -- Just rhs_ty -> checkTys binder_ty
- -- rhs_ty
- --- (mkRhsMsg binder rhs_ty)
-
- return ()
- where
- binder_ty = idType binder
-
-lintStgRhs :: StgRhs -> LintM (Maybe Type) -- Just ty => type is exact
+lintStgRhs :: StgRhs -> LintM ()
lintStgRhs (StgRhsClosure _ _ _ _ [] expr)
= lintStgExpr expr
lintStgRhs (StgRhsClosure _ _ _ _ binders expr)
= addLoc (LambdaBodyOf binders) $
- addInScopeVars binders $ runMaybeT $ do
- body_ty <- MaybeT $ lintStgExpr expr
- return (mkFunTys (map idType binders) body_ty)
+ addInScopeVars binders $
+ lintStgExpr expr
lintStgRhs rhs@(StgRhsCon _ con args) = do
- -- TODO: Check arg_tys
when (isUnboxedTupleCon con || isUnboxedSumCon con) $
addErrL (text "StgRhsCon is an unboxed tuple or sum application" $$
ppr rhs)
- runMaybeT $ do
- arg_tys <- mapM (MaybeT . lintStgArg) args
- MaybeT $ checkFunApp con_ty arg_tys (mkRhsConMsg con_ty arg_tys)
- where
- con_ty = dataConRepType con
-
-lintStgExpr :: StgExpr -> LintM (Maybe Type) -- Just ty => type is exact
+ mapM_ lintStgArg args
+ mapM_ checkPostUnariseConArg args
-lintStgExpr (StgLit l) = return (Just (literalType l))
+lintStgExpr :: StgExpr -> LintM ()
-lintStgExpr e@(StgApp fun args) = runMaybeT $ do
- fun_ty <- MaybeT $ lintStgVar fun
- arg_tys <- mapM (MaybeT . lintStgArg) args
- MaybeT $ checkFunApp fun_ty arg_tys (mkFunAppMsg fun_ty arg_tys e)
+lintStgExpr (StgLit _) = return ()
-lintStgExpr e@(StgConApp con args _arg_tys) = runMaybeT $ do
- -- TODO: Check arg_tys
- arg_tys <- mapM (MaybeT . lintStgArg) args
- MaybeT $ checkFunApp con_ty arg_tys (mkFunAppMsg con_ty arg_tys e)
- where
- con_ty = dataConRepType con
+lintStgExpr (StgApp fun args) = do
+ lintStgVar fun
+ mapM_ lintStgArg args
-lintStgExpr e@(StgOpApp (StgPrimOp op) args _) = runMaybeT $ do
- arg_tys <- mapM (MaybeT . lintStgArg) args
- MaybeT $ checkFunApp op_ty arg_tys (mkFunAppMsg op_ty arg_tys e)
- where
- op_ty = primOpType op
+lintStgExpr app@(StgConApp con args _arg_tys) = do
+ -- unboxed sums should vanish during unarise
+ lf <- getLintFlags
+ when (lf_unarised lf && isUnboxedSumCon con) $
+ addErrL (text "Unboxed sum after unarise:" $$
+ ppr app)
+ mapM_ lintStgArg args
+ mapM_ checkPostUnariseConArg args
-lintStgExpr (StgOpApp _ args res_ty) = runMaybeT $ do
- -- We don't have enough type information to check
- -- the application for StgFCallOp and StgPrimCallOp; ToDo
- _maybe_arg_tys <- mapM (MaybeT . lintStgArg) args
- return res_ty
+lintStgExpr (StgOpApp _ args _) =
+ mapM_ lintStgArg args
-lintStgExpr (StgLam bndrs _) = do
- addErrL (text "Unexpected StgLam" <+> ppr bndrs)
- return Nothing
+lintStgExpr lam@(StgLam _ _) =
+ addErrL (text "Unexpected StgLam" <+> ppr lam)
lintStgExpr (StgLet binds body) = do
binders <- lintStgBinds binds
@@ -193,78 +168,25 @@ lintStgExpr (StgLetNoEscape binds body) = do
lintStgExpr (StgTick _ expr) = lintStgExpr expr
-lintStgExpr (StgCase scrut bndr alts_type alts) = runMaybeT $ do
- _ <- MaybeT $ lintStgExpr scrut
+lintStgExpr (StgCase scrut bndr alts_type alts) = do
+ lintStgExpr scrut
- in_scope <- MaybeT $ liftM Just $
- case alts_type of
- AlgAlt tc -> check_bndr (tyConPrimRep tc) >> return True
- PrimAlt rep -> check_bndr [rep] >> return True
- MultiValAlt _ -> return False -- Binder is always dead in this case
- PolyAlt -> return True
+ lf <- getLintFlags
+ let in_scope = stgCaseBndrInScope alts_type (lf_unarised lf)
- MaybeT $ addInScopeVars [bndr | in_scope] $
- lintStgAlts alts scrut_ty
- where
- scrut_ty = idType bndr
- scrut_reps = typePrimRep scrut_ty
- check_bndr reps = checkL (scrut_reps == reps) bad_bndr
- where
- bad_bndr = mkDefltMsg bndr reps
-
-lintStgAlts :: [StgAlt]
- -> Type -- Type of scrutinee
- -> LintM (Maybe Type) -- Just ty => type is accurage
-
-lintStgAlts alts scrut_ty = do
- maybe_result_tys <- mapM (lintAlt scrut_ty) alts
-
- -- Check the result types
- case catMaybes (maybe_result_tys) of
- [] -> return Nothing
-
- (first_ty:_tys) -> do -- mapM_ check tys
- return (Just first_ty)
- where
- -- check ty = checkTys first_ty ty (mkCaseAltMsg alts)
- -- We can't check that the alternatives have the
- -- same type, because they don't, with unsafeCoerce#
-
-lintAlt :: Type -> (AltCon, [Id], StgExpr) -> LintM (Maybe Type)
-lintAlt _ (DEFAULT, _, rhs)
- = lintStgExpr rhs
-
-lintAlt scrut_ty (LitAlt lit, _, rhs) = do
- checkTys (literalType lit) scrut_ty (mkAltMsg1 scrut_ty)
- lintStgExpr rhs
-
-lintAlt scrut_ty (DataAlt con, args, rhs) = do
- case splitTyConApp_maybe scrut_ty of
- Just (tycon, tys_applied) | isAlgTyCon tycon &&
- not (isNewTyCon tycon) -> do
- let
- cons = tyConDataCons tycon
- arg_tys = dataConInstArgTys con tys_applied
- -- This does not work for existential constructors
-
- checkL (con `elem` cons) (mkAlgAltMsg2 scrut_ty con)
- checkL (args `lengthIs` dataConRepArity con) (mkAlgAltMsg3 con args)
- when (isVanillaDataCon con) $
- mapM_ check (zipEqual "lintAlgAlt:stg" arg_tys args)
- return ()
- _ ->
- addErrL (mkAltMsg1 scrut_ty)
-
- addInScopeVars args $
- lintStgExpr rhs
- where
- check (ty, arg) = checkTys ty (idType arg) (mkAlgAltMsg4 ty arg)
+ addInScopeVars [bndr | in_scope] (mapM_ lintAlt alts)
+
+lintAlt :: (AltCon, [Id], StgExpr) -> LintM ()
+
+lintAlt (DEFAULT, _, rhs) =
+ lintStgExpr rhs
- -- elem: yes, the elem-list here can sometimes be long-ish,
- -- but as it's use-once, probably not worth doing anything different
- -- We give it its own copy, so it isn't overloaded.
- elem _ [] = False
- elem x (y:ys) = x==y || elem x ys
+lintAlt (LitAlt _, _, rhs) =
+ lintStgExpr rhs
+
+lintAlt (DataAlt _, bndrs, rhs) = do
+ mapM_ checkPostUnariseBndr bndrs
+ addInScopeVars bndrs (lintStgExpr rhs)
{-
************************************************************************
@@ -275,12 +197,17 @@ lintAlt scrut_ty (DataAlt con, args, rhs) = do
-}
newtype LintM a = LintM
- { unLintM :: [LintLocInfo] -- Locations
+ { unLintM :: LintFlags
+ -> [LintLocInfo] -- Locations
-> IdSet -- Local vars in scope
-> Bag MsgDoc -- Error messages so far
-> (a, Bag MsgDoc) -- Result and error messages (if any)
}
+data LintFlags = LintFlags { lf_unarised :: !Bool
+ -- ^ have we run the unariser yet?
+ }
+
data LintLocInfo
= RhsOf Id -- The variable bound
| LambdaBodyOf [Id] -- The lambda-binder
@@ -303,20 +230,22 @@ pp_binders bs
pp_binder b
= hsep [ppr b, dcolon, ppr (idType b)]
-initL :: LintM a -> Maybe MsgDoc
-initL (LintM m)
- = case (m [] emptyVarSet emptyBag) of { (_, errs) ->
+initL :: Bool -> LintM a -> Maybe MsgDoc
+initL unarised (LintM m)
+ = case (m lf [] emptyVarSet emptyBag) of { (_, errs) ->
if isEmptyBag errs then
Nothing
else
Just (vcat (punctuate blankLine (bagToList errs)))
}
+ where
+ lf = LintFlags unarised
instance Functor LintM where
fmap = liftM
instance Applicative LintM where
- pure a = LintM $ \_loc _scope errs -> (a, errs)
+ pure a = LintM $ \_lf _loc _scope errs -> (a, errs)
(<*>) = ap
(*>) = thenL_
@@ -325,21 +254,59 @@ instance Monad LintM where
(>>) = (*>)
thenL :: LintM a -> (a -> LintM b) -> LintM b
-thenL m k = LintM $ \loc scope errs
- -> case unLintM m loc scope errs of
- (r, errs') -> unLintM (k r) loc scope errs'
+thenL m k = LintM $ \lf loc scope errs
+ -> case unLintM m lf loc scope errs of
+ (r, errs') -> unLintM (k r) lf loc scope errs'
thenL_ :: LintM a -> LintM b -> LintM b
-thenL_ m k = LintM $ \loc scope errs
- -> case unLintM m loc scope errs of
- (_, errs') -> unLintM k loc scope errs'
+thenL_ m k = LintM $ \lf loc scope errs
+ -> case unLintM m lf loc scope errs of
+ (_, errs') -> unLintM k lf loc scope errs'
checkL :: Bool -> MsgDoc -> LintM ()
checkL True _ = return ()
checkL False msg = addErrL msg
+-- Case alts shouldn't have unboxed sum, unboxed tuple, or void binders.
+checkPostUnariseBndr :: Id -> LintM ()
+checkPostUnariseBndr bndr = do
+ lf <- getLintFlags
+ when (lf_unarised lf) $
+ forM_ (checkPostUnariseId bndr) $ \unexpected ->
+ addErrL $
+ text "After unarisation, binder " <>
+ ppr bndr <> text " has " <> text unexpected <> text " type " <>
+ ppr (idType bndr)
+
+-- Arguments shouldn't have sum, tuple, or void types.
+checkPostUnariseConArg :: StgArg -> LintM ()
+checkPostUnariseConArg arg = case arg of
+ StgLitArg _ ->
+ return ()
+ StgVarArg id -> do
+ lf <- getLintFlags
+ when (lf_unarised lf) $
+ forM_ (checkPostUnariseId id) $ \unexpected ->
+ addErrL $
+ text "After unarisation, arg " <>
+ ppr id <> text " has " <> text unexpected <> text " type " <>
+ ppr (idType id)
+
+-- Post-unarisation args and case alt binders should not have unboxed tuple,
+-- unboxed sum, or void types. Return what the binder is if it is one of these.
+checkPostUnariseId :: Id -> Maybe String
+checkPostUnariseId id =
+ let
+ id_ty = idType id
+ is_sum, is_tuple, is_void :: Maybe String
+ is_sum = guard (isUnboxedSumType id_ty) >> return "unboxed sum"
+ is_tuple = guard (isUnboxedTupleType id_ty) >> return "unboxed tuple"
+ is_void = guard (isVoidTy id_ty) >> return "void"
+ in
+ is_sum <|> is_tuple <|> is_void
+
addErrL :: MsgDoc -> LintM ()
-addErrL msg = LintM $ \loc _scope errs -> ((), addErr errs msg loc)
+addErrL msg = LintM $ \_lf loc _scope errs -> ((), addErr errs msg loc)
addErr :: Bag MsgDoc -> MsgDoc -> [LintLocInfo] -> Bag MsgDoc
addErr errs_so_far msg locs
@@ -350,185 +317,26 @@ addErr errs_so_far msg locs
mk_msg [] = msg
addLoc :: LintLocInfo -> LintM a -> LintM a
-addLoc extra_loc m = LintM $ \loc scope errs
- -> unLintM m (extra_loc:loc) scope errs
+addLoc extra_loc m = LintM $ \lf loc scope errs
+ -> unLintM m lf (extra_loc:loc) scope errs
addInScopeVars :: [Id] -> LintM a -> LintM a
-addInScopeVars ids m = LintM $ \loc scope errs
+addInScopeVars ids m = LintM $ \lf loc scope errs
-> let
new_set = mkVarSet ids
- in unLintM m loc (scope `unionVarSet` new_set) errs
-
-{-
-Checking function applications: we only check that the type has the
-right *number* of arrows, we don't actually compare the types. This
-is because we can't expect the types to be equal - the type
-applications and type lambdas that we use to calculate accurate types
-have long since disappeared.
--}
+ in unLintM m lf loc (scope `unionVarSet` new_set) errs
-checkFunApp :: Type -- The function type
- -> [Type] -- The arg type(s)
- -> MsgDoc -- Error message
- -> LintM (Maybe Type) -- Just ty => result type is accurate
-
-checkFunApp fun_ty arg_tys msg
- = do { case mb_msg of
- Just msg -> addErrL msg
- Nothing -> return ()
- ; return mb_ty }
- where
- (mb_ty, mb_msg) = cfa True fun_ty arg_tys
-
- cfa :: Bool -> Type -> [Type] -> (Maybe Type -- Accurate result?
- , Maybe MsgDoc) -- Errors?
-
- cfa accurate fun_ty [] -- Args have run out; that's fine
- = (if accurate then Just fun_ty else Nothing, Nothing)
-
- cfa accurate fun_ty arg_tys@(arg_ty':arg_tys')
- | Just (arg_ty, res_ty) <- splitFunTy_maybe fun_ty
- = if accurate && not (arg_ty `stgEqType` arg_ty')
- then (Nothing, Just msg) -- Arg type mismatch
- else cfa accurate res_ty arg_tys'
-
- | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty
- = cfa False fun_ty' arg_tys
-
- | Just (tc,tc_args) <- splitTyConApp_maybe fun_ty
- , isNewTyCon tc
- = if tc_args `lengthLessThan` tyConArity tc
- then WARN( True, text "cfa: unsaturated newtype" <+> ppr fun_ty $$ msg )
- (Nothing, Nothing) -- This is odd, but I've seen it
- else cfa False (newTyConInstRhs tc tc_args) arg_tys
-
- | Just tc <- tyConAppTyCon_maybe fun_ty
- , not (isTypeFamilyTyCon tc) -- Definite error
- = (Nothing, Just msg) -- Too many args
-
- | otherwise
- = (Nothing, Nothing)
-
-stgEqType :: Type -> Type -> Bool
--- Compare types, but crudely because we have discarded
--- both casts and type applications, so types might look
--- different but be the same. So reply "True" if in doubt.
--- "False" means that the types are definitely different.
---
--- Fundamentally this is a losing battle because of unsafeCoerce
-
-stgEqType orig_ty1 orig_ty2
- = gos orig_ty1 orig_ty2
- where
- gos :: Type -> Type -> Bool
- gos ty1 ty2
- -- These have no prim rep
- | isRuntimeRepKindedTy ty1 && isRuntimeRepKindedTy ty2
- = True
-
- -- We have a unary type
- | [_] <- reps1, [_] <- reps2
- = go ty1 ty2
-
- -- In the case of a tuple just compare prim reps
- | otherwise
- = reps1 == reps2
- where
- reps1 = typePrimRep ty1
- reps2 = typePrimRep ty2
-
- go :: UnaryType -> UnaryType -> Bool
- go ty1 ty2
- | Just (tc1, tc_args1) <- splitTyConApp_maybe ty1
- , Just (tc2, tc_args2) <- splitTyConApp_maybe ty2
- , let res = if tc1 == tc2
- then equalLength tc_args1 tc_args2
- && and (zipWith gos tc_args1 tc_args2)
- else -- TyCons don't match; but don't bleat if either is a
- -- family TyCon because a coercion might have made it
- -- equal to something else
- (isFamilyTyCon tc1 || isFamilyTyCon tc2)
- = if res then True
- else
- pprTrace "stgEqType: unequal" (vcat [ppr ty1, ppr ty2])
- False
-
- | otherwise = True -- Conservatively say "fine".
- -- Type variables in particular
+getLintFlags :: LintM LintFlags
+getLintFlags = LintM $ \lf _loc _scope errs -> (lf, errs)
checkInScope :: Id -> LintM ()
-checkInScope id = LintM $ \loc scope errs
+checkInScope id = LintM $ \_lf loc scope errs
-> if isLocalId id && not (id `elemVarSet` scope) then
- ((), addErr errs (hsep [ppr id, text "is out of scope"]) loc)
+ ((), addErr errs (hsep [ppr id, dcolon, ppr (idType id),
+ text "is out of scope"]) loc)
else
((), errs)
-checkTys :: Type -> Type -> MsgDoc -> LintM ()
-checkTys ty1 ty2 msg = LintM $ \loc _scope errs
- -> if (ty1 `stgEqType` ty2)
- then ((), errs)
- else ((), addErr errs msg loc)
-
-_mkCaseAltMsg :: [StgAlt] -> MsgDoc
-_mkCaseAltMsg _alts
- = ($$) (text "In some case alternatives, type of alternatives not all same:")
- (Outputable.empty) -- LATER: ppr alts
-
-mkDefltMsg :: Id -> [PrimRep] -> MsgDoc
-mkDefltMsg bndr reps
- = ($$) (text "Binder of a case expression doesn't match representation of scrutinee:")
- (ppr bndr $$ ppr (idType bndr) $$ ppr reps)
-
-mkFunAppMsg :: Type -> [Type] -> StgExpr -> MsgDoc
-mkFunAppMsg fun_ty arg_tys expr
- = vcat [text "In a function application, function type doesn't match arg types:",
- hang (text "Function type:") 4 (ppr fun_ty),
- hang (text "Arg types:") 4 (vcat (map (ppr) arg_tys)),
- hang (text "Expression:") 4 (ppr expr)]
-
-mkRhsConMsg :: Type -> [Type] -> MsgDoc
-mkRhsConMsg fun_ty arg_tys
- = vcat [text "In a RHS constructor application, con type doesn't match arg types:",
- hang (text "Constructor type:") 4 (ppr fun_ty),
- hang (text "Arg types:") 4 (vcat (map (ppr) arg_tys))]
-
-mkAltMsg1 :: Type -> MsgDoc
-mkAltMsg1 ty
- = ($$) (text "In a case expression, type of scrutinee does not match patterns")
- (ppr ty)
-
-mkAlgAltMsg2 :: Type -> DataCon -> MsgDoc
-mkAlgAltMsg2 ty con
- = vcat [
- text "In some algebraic case alternative, constructor is not a constructor of scrutinee type:",
- ppr ty,
- ppr con
- ]
-
-mkAlgAltMsg3 :: DataCon -> [Id] -> MsgDoc
-mkAlgAltMsg3 con alts
- = vcat [
- text "In some algebraic case alternative, number of arguments doesn't match constructor:",
- ppr con,
- ppr alts
- ]
-
-mkAlgAltMsg4 :: Type -> Id -> MsgDoc
-mkAlgAltMsg4 ty arg
- = vcat [
- text "In some algebraic case alternative, type of argument doesn't match data constructor:",
- ppr ty,
- ppr arg
- ]
-
-_mkRhsMsg :: Id -> Type -> MsgDoc
-_mkRhsMsg binder ty
- = vcat [hsep [text "The type of this binder doesn't match the type of its RHS:",
- ppr binder],
- hsep [text "Binder's type:", ppr (idType binder)],
- hsep [text "Rhs type:", ppr ty]
- ]
-
mkUnliftedTyMsg :: Id -> StgRhs -> SDoc
mkUnliftedTyMsg binder rhs
= (text "Let(rec) binder" <+> quotes (ppr binder) <+>
diff --git a/compiler/stgSyn/StgSyn.hs b/compiler/stgSyn/StgSyn.hs
index 15181f3e5d..eb905f7456 100644
--- a/compiler/stgSyn/StgSyn.hs
+++ b/compiler/stgSyn/StgSyn.hs
@@ -39,12 +39,15 @@ module StgSyn (
isDllConApp,
stgArgType,
stripStgTicksTop,
+ stgCaseBndrInScope,
pprStgBinding, pprStgTopBindings
) where
#include "HsVersions.h"
+import GhcPrelude
+
import CoreSyn ( AltCon, Tickish )
import CostCentre ( CostCentreStack )
import Data.ByteString ( ByteString )
@@ -68,6 +71,8 @@ import RepType ( typePrimRep1 )
import Unique ( Unique )
import Util
+import Data.List.NonEmpty ( NonEmpty, toList )
+
{-
************************************************************************
* *
@@ -151,6 +156,18 @@ stripStgTicksTop p = go []
where go ts (StgTick t e) | p t = go (t:ts) e
go ts other = (reverse ts, other)
+-- | Given an alt type and whether the program is unarised, return whether the
+-- case binder is in scope.
+--
+-- Case binders of unboxed tuple or unboxed sum type always dead after the
+-- unariser has run. See Note [Post-unarisation invariants].
+stgCaseBndrInScope :: AltType -> Bool {- ^ unarised? -} -> Bool
+stgCaseBndrInScope alt_ty unarised =
+ case alt_ty of
+ AlgAlt _ -> True
+ PrimAlt _ -> True
+ MultiValAlt _ -> not unarised
+ PolyAlt -> True
{-
************************************************************************
@@ -219,7 +236,7 @@ finished it encodes (\x -> e) as (let f = \x -> e in f)
-}
| StgLam
- [bndr]
+ (NonEmpty bndr)
StgExpr -- Body of lambda
{-
@@ -547,6 +564,7 @@ data AltType
= PolyAlt -- Polymorphic (a lifted type variable)
| MultiValAlt Int -- Multi value of this arity (unboxed tuple or sum)
-- the arity could indeed be 1 for unary unboxed tuple
+ -- or enum-like unboxed sums
| AlgAlt TyCon -- Algebraic data type; the AltCons will be DataAlts
| PrimAlt PrimRep -- Primitive data type; the AltCons (if any) will be LitAlts
@@ -665,8 +683,8 @@ pprGenStgBinding (StgNonRec bndr rhs)
4 (ppr rhs <> semi)
pprGenStgBinding (StgRec pairs)
- = vcat $ ifPprDebug (text "{- StgRec (begin) -}") :
- map (ppr_bind) pairs ++ [ifPprDebug (text "{- StgRec (end) -}")]
+ = vcat $ whenPprDebug (text "{- StgRec (begin) -}") :
+ map (ppr_bind) pairs ++ [whenPprDebug (text "{- StgRec (end) -}")]
where
ppr_bind (bndr, expr)
= hang (hsep [pprBndr LetBind bndr, equals])
@@ -718,7 +736,7 @@ pprStgExpr (StgOpApp op args _)
= hsep [ pprStgOp op, brackets (interppSP args)]
pprStgExpr (StgLam bndrs body)
- = sep [ char '\\' <+> ppr_list (map (pprBndr LambdaBind) bndrs)
+ = sep [ char '\\' <+> ppr_list (map (pprBndr LambdaBind) (toList bndrs))
<+> text "->",
pprStgExpr body ]
where ppr_list = brackets . fsep . punctuate comma
@@ -738,7 +756,7 @@ pprStgExpr (StgLet srt (StgNonRec bndr (StgRhsClosure cc bi free_vars upd_flag a
(hang (hcat [text "let { ", ppr bndr, ptext (sLit " = "),
ppr cc,
pp_binder_info bi,
- text " [", ifPprDebug (interppSP free_vars), ptext (sLit "] \\"),
+ text " [", whenPprDebug (interppSP free_vars), ptext (sLit "] \\"),
ppr upd_flag, text " [",
interppSP args, char ']'])
8 (sep [hsep [ppr rhs, text "} in"]]))
@@ -774,7 +792,7 @@ pprStgExpr (StgTick tickish expr)
pprStgExpr (StgCase expr bndr alt_type alts)
= sep [sep [text "case",
nest 4 (hsep [pprStgExpr expr,
- ifPprDebug (dcolon <+> ppr alt_type)]),
+ whenPprDebug (dcolon <+> ppr alt_type)]),
text "of", pprBndr CaseBind bndr, char '{'],
nest 2 (vcat (map pprStgAlt alts)),
char '}']
@@ -801,9 +819,11 @@ pprStgRhs :: (OutputableBndr bndr, Outputable bdee, Ord bdee)
-- special case
pprStgRhs (StgRhsClosure cc bi [free_var] upd_flag [{-no args-}] (StgApp func []))
- = hsep [ ppr cc,
+ = sdocWithDynFlags $ \dflags ->
+ hsep [ ppr cc,
pp_binder_info bi,
- brackets (ifPprDebug (ppr free_var)),
+ if not $ gopt Opt_SuppressStgFreeVars dflags
+ then brackets (ppr free_var) else empty,
text " \\", ppr upd_flag, ptext (sLit " [] "), ppr func ]
-- general case
@@ -811,7 +831,8 @@ pprStgRhs (StgRhsClosure cc bi free_vars upd_flag args body)
= sdocWithDynFlags $ \dflags ->
hang (hsep [if gopt Opt_SccProfilingOn dflags then ppr cc else empty,
pp_binder_info bi,
- ifPprDebug (brackets (interppSP free_vars)),
+ if not $ gopt Opt_SuppressStgFreeVars dflags
+ then brackets (interppSP free_vars) else empty,
char '\\' <> ppr upd_flag, brackets (interppSP args)])
4 (ppr body)