{-
(c) The AQUA Project, Glasgow University, 1993-1998

\section[SimplMonad]{The simplifier Monad}
-}

module SimplMonad (
        -- The monad
        SimplM,
        initSmpl, traceSmpl,
        getSimplRules, getFamEnvs,

        -- Unique supply
        MonadUnique(..), newId, newJoinId,

        -- Counting
        SimplCount, tick, freeTick, checkedTick,
        getSimplCount, zeroSimplCount, pprSimplCount,
        plusSimplCount, isZeroSimplCount
    ) where

import GhcPrelude

import Var              ( Var, isTyVar, mkLocalVar )
import Name             ( mkSystemVarName )
import Id               ( Id, mkSysLocalOrCoVar )
import IdInfo           ( IdDetails(..), vanillaIdInfo, setArityInfo )
import Type             ( Type, mkLamTypes )
import FamInstEnv       ( FamInstEnv )
import CoreSyn          ( RuleEnv(..) )
import UniqSupply
import DynFlags
import CoreMonad
import Outputable
import FastString
import MonadUtils
import ErrUtils as Err
import Panic (throwGhcExceptionIO, GhcException (..))
import BasicTypes          ( IntWithInf, treatZeroAsInf, mkIntWithInf )
import Control.Monad       ( liftM, ap )

{-
************************************************************************
*                                                                      *
\subsection{Monad plumbing}
*                                                                      *
************************************************************************

For the simplifier monad, we want to {\em thread} a unique supply and a counter.
(Command-line switches move around through the explicitly-passed SimplEnv.)
-}

newtype SimplM result
  =  SM  { SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM :: SimplTopEnv  -- Envt that does not change much
                -> UniqSupply   -- We thread the unique supply because
                                -- constantly splitting it is rather expensive
                -> SimplCount
                -> IO (result, UniqSupply, SimplCount)}
  -- we only need IO here for dump output

data SimplTopEnv
  = STE { SimplTopEnv -> DynFlags
st_flags     :: DynFlags
        , SimplTopEnv -> IntWithInf
st_max_ticks :: IntWithInf  -- Max #ticks in this simplifier run
        , SimplTopEnv -> RuleEnv
st_rules     :: RuleEnv
        , SimplTopEnv -> (FamInstEnv, FamInstEnv)
st_fams      :: (FamInstEnv, FamInstEnv) }

initSmpl :: DynFlags -> RuleEnv -> (FamInstEnv, FamInstEnv)
         -> UniqSupply          -- No init count; set to 0
         -> Int                 -- Size of the bindings, used to limit
                                -- the number of ticks we allow
         -> SimplM a
         -> IO (a, SimplCount)

initSmpl :: DynFlags
-> RuleEnv
-> (FamInstEnv, FamInstEnv)
-> UniqSupply
-> Int
-> SimplM a
-> IO (a, SimplCount)
initSmpl dflags :: DynFlags
dflags rules :: RuleEnv
rules fam_envs :: (FamInstEnv, FamInstEnv)
fam_envs us :: UniqSupply
us size :: Int
size m :: SimplM a
m
  = do (result :: a
result, _, count :: SimplCount
count) <- SimplM a
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (a, UniqSupply, SimplCount)
forall result.
SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM SimplM a
m SimplTopEnv
env UniqSupply
us (DynFlags -> SimplCount
zeroSimplCount DynFlags
dflags)
       (a, SimplCount) -> IO (a, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
result, SimplCount
count)
  where
    env :: SimplTopEnv
env = STE :: DynFlags
-> IntWithInf -> RuleEnv -> (FamInstEnv, FamInstEnv) -> SimplTopEnv
STE { st_flags :: DynFlags
st_flags = DynFlags
dflags, st_rules :: RuleEnv
st_rules = RuleEnv
rules
              , st_max_ticks :: IntWithInf
st_max_ticks = DynFlags -> Int -> IntWithInf
computeMaxTicks DynFlags
dflags Int
size
              , st_fams :: (FamInstEnv, FamInstEnv)
st_fams = (FamInstEnv, FamInstEnv)
fam_envs }

computeMaxTicks :: DynFlags -> Int -> IntWithInf
-- Compute the max simplifier ticks as
--     (base-size + pgm-size) * magic-multiplier * tick-factor/100
-- where
--    magic-multiplier is a constant that gives reasonable results
--    base-size is a constant to deal with size-zero programs
computeMaxTicks :: DynFlags -> Int -> IntWithInf
computeMaxTicks dflags :: DynFlags
dflags size :: Int
size
  = Int -> IntWithInf
treatZeroAsInf (Int -> IntWithInf) -> Int -> IntWithInf
forall a b. (a -> b) -> a -> b
$
    Integer -> Int
forall a. Num a => Integer -> a
fromInteger ((Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
base_size)
                  Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int
tick_factor Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
magic_multiplier))
          Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` 100)
  where
    tick_factor :: Int
tick_factor      = DynFlags -> Int
simplTickFactor DynFlags
dflags
    base_size :: Int
base_size        = 100
    magic_multiplier :: Int
magic_multiplier = 40
        -- MAGIC NUMBER, multiplies the simplTickFactor
        -- We can afford to be generous; this is really
        -- just checking for loops, and shouldn't usually fire
        -- A figure of 20 was too small: see Trac #5539.

{-# INLINE thenSmpl #-}
{-# INLINE thenSmpl_ #-}
{-# INLINE returnSmpl #-}


instance Functor SimplM where
    fmap :: (a -> b) -> SimplM a -> SimplM b
fmap = (a -> b) -> SimplM a -> SimplM b
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM

instance Applicative SimplM where
    pure :: a -> SimplM a
pure  = a -> SimplM a
forall a. a -> SimplM a
returnSmpl
    <*> :: SimplM (a -> b) -> SimplM a -> SimplM b
(<*>) = SimplM (a -> b) -> SimplM a -> SimplM b
forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap
    *> :: SimplM a -> SimplM b -> SimplM b
(*>)  = SimplM a -> SimplM b -> SimplM b
forall a b. SimplM a -> SimplM b -> SimplM b
thenSmpl_

instance Monad SimplM where
   >> :: SimplM a -> SimplM b -> SimplM b
(>>)   = SimplM a -> SimplM b -> SimplM b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
(*>)
   >>= :: SimplM a -> (a -> SimplM b) -> SimplM b
(>>=)  = SimplM a -> (a -> SimplM b) -> SimplM b
forall a b. SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl

returnSmpl :: a -> SimplM a
returnSmpl :: a -> SimplM a
returnSmpl e :: a
e = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (a, UniqSupply, SimplCount))
-> SimplM a
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> (a, UniqSupply, SimplCount) -> IO (a, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
e, UniqSupply
us, SimplCount
sc))

thenSmpl  :: SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl_ :: SimplM a -> SimplM b -> SimplM b

thenSmpl :: SimplM a -> (a -> SimplM b) -> SimplM b
thenSmpl m :: SimplM a
m k :: a -> SimplM b
k
  = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
-> SimplM b
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM ((SimplTopEnv
  -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
 -> SimplM b)
-> (SimplTopEnv
    -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
-> SimplM b
forall a b. (a -> b) -> a -> b
$ \st_env :: SimplTopEnv
st_env us0 :: UniqSupply
us0 sc0 :: SimplCount
sc0 -> do
      (m_result :: a
m_result, us1 :: UniqSupply
us1, sc1 :: SimplCount
sc1) <- SimplM a
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (a, UniqSupply, SimplCount)
forall result.
SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM SimplM a
m SimplTopEnv
st_env UniqSupply
us0 SimplCount
sc0
      SimplM b
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (b, UniqSupply, SimplCount)
forall result.
SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM (a -> SimplM b
k a
m_result) SimplTopEnv
st_env UniqSupply
us1 SimplCount
sc1

thenSmpl_ :: SimplM a -> SimplM b -> SimplM b
thenSmpl_ m :: SimplM a
m k :: SimplM b
k
  = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
-> SimplM b
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM ((SimplTopEnv
  -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
 -> SimplM b)
-> (SimplTopEnv
    -> UniqSupply -> SimplCount -> IO (b, UniqSupply, SimplCount))
-> SimplM b
forall a b. (a -> b) -> a -> b
$ \st_env :: SimplTopEnv
st_env us0 :: UniqSupply
us0 sc0 :: SimplCount
sc0 -> do
      (_, us1 :: UniqSupply
us1, sc1 :: SimplCount
sc1) <- SimplM a
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (a, UniqSupply, SimplCount)
forall result.
SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM SimplM a
m SimplTopEnv
st_env UniqSupply
us0 SimplCount
sc0
      SimplM b
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (b, UniqSupply, SimplCount)
forall result.
SimplM result
-> SimplTopEnv
-> UniqSupply
-> SimplCount
-> IO (result, UniqSupply, SimplCount)
unSM SimplM b
k SimplTopEnv
st_env UniqSupply
us1 SimplCount
sc1

-- TODO: this specializing is not allowed
-- {-# SPECIALIZE mapM         :: (a -> SimplM b) -> [a] -> SimplM [b] #-}
-- {-# SPECIALIZE mapAndUnzipM :: (a -> SimplM (b, c)) -> [a] -> SimplM ([b],[c]) #-}
-- {-# SPECIALIZE mapAccumLM   :: (acc -> b -> SimplM (acc,c)) -> acc -> [b] -> SimplM (acc, [c]) #-}

traceSmpl :: String -> SDoc -> SimplM ()
traceSmpl :: String -> SDoc -> SimplM ()
traceSmpl herald :: String
herald doc :: SDoc
doc
  = do { DynFlags
dflags <- SimplM DynFlags
forall (m :: * -> *). HasDynFlags m => m DynFlags
getDynFlags
       ; IO () -> SimplM ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> SimplM ()) -> IO () -> SimplM ()
forall a b. (a -> b) -> a -> b
$ DynFlags -> DumpFlag -> String -> SDoc -> IO ()
Err.dumpIfSet_dyn DynFlags
dflags DumpFlag
Opt_D_dump_simpl_trace "Simpl Trace"
           (SDoc -> Int -> SDoc -> SDoc
hang (String -> SDoc
text String
herald) 2 SDoc
doc) }

{-
************************************************************************
*                                                                      *
\subsection{The unique supply}
*                                                                      *
************************************************************************
-}

instance MonadUnique SimplM where
    getUniqueSupplyM :: SimplM UniqSupply
getUniqueSupplyM
       = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO (UniqSupply, UniqSupply, SimplCount))
-> SimplM UniqSupply
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> case UniqSupply -> (UniqSupply, UniqSupply)
splitUniqSupply UniqSupply
us of
                                (us1 :: UniqSupply
us1, us2 :: UniqSupply
us2) -> (UniqSupply, UniqSupply, SimplCount)
-> IO (UniqSupply, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (UniqSupply
us1, UniqSupply
us2, SimplCount
sc))

    getUniqueM :: SimplM Unique
getUniqueM
       = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (Unique, UniqSupply, SimplCount))
-> SimplM Unique
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> case UniqSupply -> (Unique, UniqSupply)
takeUniqFromSupply UniqSupply
us of
                                (u :: Unique
u, us' :: UniqSupply
us') -> (Unique, UniqSupply, SimplCount)
-> IO (Unique, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (Unique
u, UniqSupply
us', SimplCount
sc))

    getUniquesM :: SimplM [Unique]
getUniquesM
        = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO ([Unique], UniqSupply, SimplCount))
-> SimplM [Unique]
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> case UniqSupply -> (UniqSupply, UniqSupply)
splitUniqSupply UniqSupply
us of
                                (us1 :: UniqSupply
us1, us2 :: UniqSupply
us2) -> ([Unique], UniqSupply, SimplCount)
-> IO ([Unique], UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (UniqSupply -> [Unique]
uniqsFromSupply UniqSupply
us1, UniqSupply
us2, SimplCount
sc))

instance HasDynFlags SimplM where
    getDynFlags :: SimplM DynFlags
getDynFlags = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO (DynFlags, UniqSupply, SimplCount))
-> SimplM DynFlags
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\st_env :: SimplTopEnv
st_env us :: UniqSupply
us sc :: SimplCount
sc -> (DynFlags, UniqSupply, SimplCount)
-> IO (DynFlags, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (SimplTopEnv -> DynFlags
st_flags SimplTopEnv
st_env, UniqSupply
us, SimplCount
sc))

instance MonadIO SimplM where
    liftIO :: IO a -> SimplM a
liftIO m :: IO a
m = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (a, UniqSupply, SimplCount))
-> SimplM a
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM ((SimplTopEnv
  -> UniqSupply -> SimplCount -> IO (a, UniqSupply, SimplCount))
 -> SimplM a)
-> (SimplTopEnv
    -> UniqSupply -> SimplCount -> IO (a, UniqSupply, SimplCount))
-> SimplM a
forall a b. (a -> b) -> a -> b
$ \_ us :: UniqSupply
us sc :: SimplCount
sc -> do
      a
x <- IO a
m
      (a, UniqSupply, SimplCount) -> IO (a, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
x, UniqSupply
us, SimplCount
sc)

getSimplRules :: SimplM RuleEnv
getSimplRules :: SimplM RuleEnv
getSimplRules = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO (RuleEnv, UniqSupply, SimplCount))
-> SimplM RuleEnv
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\st_env :: SimplTopEnv
st_env us :: UniqSupply
us sc :: SimplCount
sc -> (RuleEnv, UniqSupply, SimplCount)
-> IO (RuleEnv, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (SimplTopEnv -> RuleEnv
st_rules SimplTopEnv
st_env, UniqSupply
us, SimplCount
sc))

getFamEnvs :: SimplM (FamInstEnv, FamInstEnv)
getFamEnvs :: SimplM (FamInstEnv, FamInstEnv)
getFamEnvs = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO ((FamInstEnv, FamInstEnv), UniqSupply, SimplCount))
-> SimplM (FamInstEnv, FamInstEnv)
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\st_env :: SimplTopEnv
st_env us :: UniqSupply
us sc :: SimplCount
sc -> ((FamInstEnv, FamInstEnv), UniqSupply, SimplCount)
-> IO ((FamInstEnv, FamInstEnv), UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (SimplTopEnv -> (FamInstEnv, FamInstEnv)
st_fams SimplTopEnv
st_env, UniqSupply
us, SimplCount
sc))

newId :: FastString -> Type -> SimplM Id
newId :: FastString -> Type -> SimplM Id
newId fs :: FastString
fs ty :: Type
ty = do Unique
uniq <- SimplM Unique
forall (m :: * -> *). MonadUnique m => m Unique
getUniqueM
                 Id -> SimplM Id
forall (m :: * -> *) a. Monad m => a -> m a
return (FastString -> Unique -> Type -> Id
mkSysLocalOrCoVar FastString
fs Unique
uniq Type
ty)

newJoinId :: [Var] -> Type -> SimplM Id
newJoinId :: [Id] -> Type -> SimplM Id
newJoinId bndrs :: [Id]
bndrs body_ty :: Type
body_ty
  = do { Unique
uniq <- SimplM Unique
forall (m :: * -> *). MonadUnique m => m Unique
getUniqueM
       ; let name :: Name
name       = Unique -> FastString -> Name
mkSystemVarName Unique
uniq (String -> FastString
fsLit "$j")
             join_id_ty :: Type
join_id_ty = [Id] -> Type -> Type
mkLamTypes [Id]
bndrs Type
body_ty  -- Note [Funky mkLamTypes]
             arity :: Int
arity      = [Id] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((Id -> Bool) -> [Id] -> [Id]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Id -> Bool) -> Id -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Id -> Bool
isTyVar) [Id]
bndrs)
             join_arity :: Int
join_arity = [Id] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Id]
bndrs
             details :: IdDetails
details    = Int -> IdDetails
JoinId Int
join_arity
             id_info :: IdInfo
id_info    = IdInfo
vanillaIdInfo IdInfo -> Int -> IdInfo
`setArityInfo` Int
arity
--                                        `setOccInfo` strongLoopBreaker

       ; Id -> SimplM Id
forall (m :: * -> *) a. Monad m => a -> m a
return (IdDetails -> Name -> Type -> IdInfo -> Id
mkLocalVar IdDetails
details Name
name Type
join_id_ty IdInfo
id_info) }

{-
************************************************************************
*                                                                      *
\subsection{Counting up what we've done}
*                                                                      *
************************************************************************
-}

getSimplCount :: SimplM SimplCount
getSimplCount :: SimplM SimplCount
getSimplCount = (SimplTopEnv
 -> UniqSupply
 -> SimplCount
 -> IO (SimplCount, UniqSupply, SimplCount))
-> SimplM SimplCount
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> (SimplCount, UniqSupply, SimplCount)
-> IO (SimplCount, UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return (SimplCount
sc, UniqSupply
us, SimplCount
sc))

tick :: Tick -> SimplM ()
tick :: Tick -> SimplM ()
tick t :: Tick
t = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO ((), UniqSupply, SimplCount))
-> SimplM ()
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\st_env :: SimplTopEnv
st_env us :: UniqSupply
us sc :: SimplCount
sc -> let sc' :: SimplCount
sc' = DynFlags -> Tick -> SimplCount -> SimplCount
doSimplTick (SimplTopEnv -> DynFlags
st_flags SimplTopEnv
st_env) Tick
t SimplCount
sc
                              in SimplCount
sc' SimplCount
-> IO ((), UniqSupply, SimplCount)
-> IO ((), UniqSupply, SimplCount)
forall a b. a -> b -> b
`seq` ((), UniqSupply, SimplCount) -> IO ((), UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return ((), UniqSupply
us, SimplCount
sc'))

checkedTick :: Tick -> SimplM ()
-- Try to take a tick, but fail if too many
checkedTick :: Tick -> SimplM ()
checkedTick t :: Tick
t
  = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO ((), UniqSupply, SimplCount))
-> SimplM ()
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\st_env :: SimplTopEnv
st_env us :: UniqSupply
us sc :: SimplCount
sc ->
           if SimplTopEnv -> IntWithInf
st_max_ticks SimplTopEnv
st_env IntWithInf -> IntWithInf -> Bool
forall a. Ord a => a -> a -> Bool
<= Int -> IntWithInf
mkIntWithInf (SimplCount -> Int
simplCountN SimplCount
sc)
           then GhcException -> IO ((), UniqSupply, SimplCount)
forall a. GhcException -> IO a
throwGhcExceptionIO (GhcException -> IO ((), UniqSupply, SimplCount))
-> GhcException -> IO ((), UniqSupply, SimplCount)
forall a b. (a -> b) -> a -> b
$
                  String -> SDoc -> GhcException
PprProgramError "Simplifier ticks exhausted" (SimplCount -> SDoc
msg SimplCount
sc)
           else let sc' :: SimplCount
sc' = DynFlags -> Tick -> SimplCount -> SimplCount
doSimplTick (SimplTopEnv -> DynFlags
st_flags SimplTopEnv
st_env) Tick
t SimplCount
sc
                in SimplCount
sc' SimplCount
-> IO ((), UniqSupply, SimplCount)
-> IO ((), UniqSupply, SimplCount)
forall a b. a -> b -> b
`seq` ((), UniqSupply, SimplCount) -> IO ((), UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return ((), UniqSupply
us, SimplCount
sc'))
  where
    msg :: SimplCount -> SDoc
msg sc :: SimplCount
sc = [SDoc] -> SDoc
vcat
      [ String -> SDoc
text "When trying" SDoc -> SDoc -> SDoc
<+> Tick -> SDoc
forall a. Outputable a => a -> SDoc
ppr Tick
t
      , String -> SDoc
text "To increase the limit, use -fsimpl-tick-factor=N (default 100)."
      , SDoc
space
      , String -> SDoc
text "If you need to increase the limit substantially, please file a"
      , String -> SDoc
text "bug report and indicate the factor you needed."
      , SDoc
space
      , String -> SDoc
text "If GHC was unable to complete compilation even"
               SDoc -> SDoc -> SDoc
<+> String -> SDoc
text "with a very large factor"
      , String -> SDoc
text "(a thousand or more), please consult the"
                SDoc -> SDoc -> SDoc
<+> SDoc -> SDoc
doubleQuotes (String -> SDoc
text "Known bugs or infelicities")
      , String -> SDoc
text "section in the Users Guide before filing a report. There are a"
      , String -> SDoc
text "few situations unlikely to occur in practical programs for which"
      , String -> SDoc
text "simplifier non-termination has been judged acceptable."
      , SDoc
space
      , SimplCount -> SDoc
pp_details SimplCount
sc
      , SimplCount -> SDoc
pprSimplCount SimplCount
sc ]
    pp_details :: SimplCount -> SDoc
pp_details sc :: SimplCount
sc
      | SimplCount -> Bool
hasDetailedCounts SimplCount
sc = SDoc
empty
      | Bool
otherwise = String -> SDoc
text "To see detailed counts use -ddump-simpl-stats"


freeTick :: Tick -> SimplM ()
-- Record a tick, but don't add to the total tick count, which is
-- used to decide when nothing further has happened
freeTick :: Tick -> SimplM ()
freeTick t :: Tick
t
   = (SimplTopEnv
 -> UniqSupply -> SimplCount -> IO ((), UniqSupply, SimplCount))
-> SimplM ()
forall result.
(SimplTopEnv
 -> UniqSupply -> SimplCount -> IO (result, UniqSupply, SimplCount))
-> SimplM result
SM (\_st_env :: SimplTopEnv
_st_env us :: UniqSupply
us sc :: SimplCount
sc -> let sc' :: SimplCount
sc' = Tick -> SimplCount -> SimplCount
doFreeSimplTick Tick
t SimplCount
sc
                           in SimplCount
sc' SimplCount
-> IO ((), UniqSupply, SimplCount)
-> IO ((), UniqSupply, SimplCount)
forall a b. a -> b -> b
`seq` ((), UniqSupply, SimplCount) -> IO ((), UniqSupply, SimplCount)
forall (m :: * -> *) a. Monad m => a -> m a
return ((), UniqSupply
us, SimplCount
sc'))