\end{itemize}
\begin{code}
+{-# LANGUAGE DeriveDataTypeable #-}
+
module BasicTypes(
Version, bumpVersion, initialVersion,
Arity,
+
+ FunctionOrData(..),
- DeprecTxt,
+ WarningTxt(..),
Fixity(..), FixityDirection(..),
defaultFixity, maxPrecedence,
RecFlag(..), isRec, isNonRec, boolToRecFlag,
+ RuleName,
+
TopLevelFlag(..), isTopLevel, isNotTopLevel,
OverlapFlag(..),
TupCon(..), tupleParens,
- OccInfo(..), seqOccInfo, isFragileOcc, isOneOcc,
+ OccInfo(..), seqOccInfo, zapFragileOcc, isOneOcc,
isDeadOcc, isLoopBreaker, isNonRuleLoopBreaker, isNoOcc,
+ nonRuleLoopBreaker,
InsideLam, insideLam, notInsideLam,
OneBranch, oneBranch, notOneBranch,
EP(..),
- StrictnessMark(..), isMarkedUnboxed, isMarkedStrict,
+ HsBang(..), isBanged, isMarkedUnboxed,
+ StrictnessMark(..), isMarkedStrict,
- CompilerPhase,
- Activation(..), isActive, isNeverActive, isAlwaysActive,
- InlineSpec(..), defaultInlineSpec, alwaysInlineSpec, neverInlineSpec,
+ DefMethSpec(..),
+
+ CompilerPhase(..), PhaseNum,
+ Activation(..), isActive, isActiveIn,
+ isNeverActive, isAlwaysActive, isEarlyActive,
+ RuleMatchInfo(..), isConLike, isFunLike,
+ InlineSpec(..),
+ InlinePragma(..), defaultInlinePragma, alwaysInlinePragma,
+ neverInlinePragma, dfunInlinePragma,
+ isDefaultInlinePragma,
+ isInlinePragma, isInlinablePragma, isAnyInlinePragma,
+ inlinePragmaSpec, inlinePragmaSat,
+ inlinePragmaActivation, inlinePragmaRuleMatchInfo,
+ setInlinePragmaActivation, setInlinePragmaRuleMatchInfo,
SuccessFlag(..), succeeded, failed, successIf
) where
-#include "HsVersions.h"
-
-import FastString( FastString )
+import FastString
import Outputable
+
+import Data.Data hiding (Fixity)
\end{code}
%************************************************************************
type Arity = Int
\end{code}
+%************************************************************************
+%* *
+\subsection[FunctionOrData]{FunctionOrData}
+%* *
+%************************************************************************
+
+\begin{code}
+data FunctionOrData = IsFunction | IsData
+ deriving (Eq, Ord, Data, Typeable)
+
+instance Outputable FunctionOrData where
+ ppr IsFunction = text "(function)"
+ ppr IsData = text "(data)"
+\end{code}
+
%************************************************************************
%* *
\begin{code}
-type DeprecTxt = FastString -- reason/explanation for deprecation
+-- reason/explanation from a WARNING or DEPRECATED pragma
+data WarningTxt = WarningTxt [FastString]
+ | DeprecatedTxt [FastString]
+ deriving (Eq, Data, Typeable)
+
+instance Outputable WarningTxt where
+ ppr (WarningTxt ws) = doubleQuotes (vcat (map ftext ws))
+ ppr (DeprecatedTxt ds) = text "Deprecated:" <+>
+ doubleQuotes (vcat (map ftext ds))
\end{code}
%************************************************************************
\begin{code}
newtype IPName name = IPName name -- ?x
- deriving( Eq, Ord ) -- Ord is used in the IP name cache finite map
- -- (used in HscTypes.OrigIParamCache)
+ deriving( Eq, Ord, Data, Typeable )
+ -- Ord is used in the IP name cache finite map
+ -- (used in HscTypes.OrigIParamCache)
ipNameName :: IPName name -> name
ipNameName (IPName n) = n
ppr (IPName n) = char '?' <> ppr n -- Ordinary implicit parameters
\end{code}
+%************************************************************************
+%* *
+ Rules
+%* *
+%************************************************************************
+
+\begin{code}
+type RuleName = FastString
+\end{code}
%************************************************************************
%* *
\begin{code}
------------------------
data Fixity = Fixity Int FixityDirection
+ deriving (Data, Typeable)
instance Outputable Fixity where
ppr (Fixity prec dir) = hcat [ppr dir, space, int prec]
------------------------
data FixityDirection = InfixL | InfixR | InfixN
- deriving(Eq)
+ deriving (Eq, Data, Typeable)
instance Outputable FixityDirection where
- ppr InfixL = ptext SLIT("infixl")
- ppr InfixR = ptext SLIT("infixr")
- ppr InfixN = ptext SLIT("infix")
+ ppr InfixL = ptext (sLit "infixl")
+ ppr InfixR = ptext (sLit "infixr")
+ ppr InfixN = ptext (sLit "infix")
------------------------
-maxPrecedence = (9::Int)
+maxPrecedence :: Int
+maxPrecedence = 9
+defaultFixity :: Fixity
defaultFixity = Fixity maxPrecedence InfixL
negateFixity, funTyFixity :: Fixity
isTopLevel NotTopLevel = False
instance Outputable TopLevelFlag where
- ppr TopLevel = ptext SLIT("<TopLevel>")
- ppr NotTopLevel = ptext SLIT("<NotTopLevel>")
+ ppr TopLevel = ptext (sLit "<TopLevel>")
+ ppr NotTopLevel = ptext (sLit "<NotTopLevel>")
\end{code}
data Boxity
= Boxed
| Unboxed
- deriving( Eq )
+ deriving( Eq, Data, Typeable )
isBoxed :: Boxity -> Bool
isBoxed Boxed = True
%* *
%************************************************************************
-\begin{code}
+\begin{code}
data RecFlag = Recursive
| NonRecursive
- deriving( Eq )
+ deriving( Eq, Data, Typeable )
isRec :: RecFlag -> Bool
isRec Recursive = True
boolToRecFlag False = NonRecursive
instance Outputable RecFlag where
- ppr Recursive = ptext SLIT("Recursive")
- ppr NonRecursive = ptext SLIT("NonRecursive")
+ ppr Recursive = ptext (sLit "Recursive")
+ ppr NonRecursive = ptext (sLit "NonRecursive")
\end{code}
%************************************************************************
--
-- Example: constraint (Foo [Int])
-- instances (Foo [Int])
+
-- (Foo [a]) OverlapOk
-- Since the second instance has the OverlapOk flag,
-- the first instance will be chosen (otherwise
instance Outputable OverlapFlag where
ppr NoOverlap = empty
- ppr OverlapOk = ptext SLIT("[overlap ok]")
- ppr Incoherent = ptext SLIT("[incoherent]")
+ ppr OverlapOk = ptext (sLit "[overlap ok]")
+ ppr Incoherent = ptext (sLit "[incoherent]")
\end{code}
tupleParens :: Boxity -> SDoc -> SDoc
tupleParens Boxed p = parens p
-tupleParens Unboxed p = ptext SLIT("(#") <+> p <+> ptext SLIT("#)")
+tupleParens Unboxed p = ptext (sLit "(#") <+> p <+> ptext (sLit "#)")
\end{code}
%************************************************************************
defn of OccInfo here, safely at the bottom
\begin{code}
+-- | Identifier occurrence information
data OccInfo
- = NoOccInfo -- Many occurrences, or unknown
+ = NoOccInfo -- ^ There are many occurrences, or unknown occurences
- | IAmDead -- Marks unused variables. Sometimes useful for
+ | IAmDead -- ^ Marks unused variables. Sometimes useful for
-- lambda and case-bound variables.
- | OneOcc -- Occurs exactly once, not inside a rule
+ | OneOcc
!InsideLam
!OneBranch
- !InterestingCxt
+ !InterestingCxt -- ^ Occurs exactly once, not inside a rule
- | IAmALoopBreaker -- Used by the occurrence analyser to mark loop-breakers
- -- in a group of recursive definitions
- !RulesOnly -- True <=> This loop breaker mentions the other binders
- -- in its recursive group only in its RULES, not
- -- in its rhs
- -- See OccurAnal Note [RulesOnly]
+ -- | This identifier breaks a loop of mutually recursive functions. The field
+ -- marks whether it is only a loop breaker due to a reference in a rule
+ | IAmALoopBreaker -- Note [LoopBreaker OccInfo]
+ !RulesOnly -- True <=> This is a weak or rules-only loop breaker
+ -- See OccurAnal Note [Weak loop breakers]
type RulesOnly = Bool
\end{code}
+Note [LoopBreaker OccInfo]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+An OccInfo of (IAmLoopBreaker False) is used by the occurrence
+analyser in two ways:
+ (a) to mark loop-breakers in a group of recursive
+ definitions (hence the name)
+ (b) to mark binders that must not be inlined in this phase
+ (perhaps it has a NOINLINE pragma)
+Things with (IAmLoopBreaker False) do not get an unfolding
+pinned on to them, so they are completely opaque.
+
+See OccurAnal Note [Weak loop breakers] for (IAmLoopBreaker True).
+
\begin{code}
isNoOcc :: OccInfo -> Bool
isNoOcc NoOccInfo = True
-isNoOcc other = False
+isNoOcc _ = False
seqOccInfo :: OccInfo -> ()
seqOccInfo occ = occ `seq` ()
type InsideLam = Bool -- True <=> Occurs inside a non-linear lambda
-- Substituting a redex for this occurrence is
-- dangerous because it might duplicate work.
+insideLam, notInsideLam :: InsideLam
insideLam = True
notInsideLam = False
-----------------
type OneBranch = Bool -- True <=> Occurs in only one case branch
-- so no code-duplication issue to worry about
+oneBranch, notOneBranch :: OneBranch
oneBranch = True
notOneBranch = False
isLoopBreaker :: OccInfo -> Bool
isLoopBreaker (IAmALoopBreaker _) = True
-isLoopBreaker other = False
+isLoopBreaker _ = False
isNonRuleLoopBreaker :: OccInfo -> Bool
-isNonRuleLoopBreaker (IAmALoopBreaker False) = True -- Loop-breaker that breaks a non-rule cycle
-isNonRuleLoopBreaker other = False
+isNonRuleLoopBreaker (IAmALoopBreaker False) = True -- Loop-breaker that breaks a non-rule cycle
+isNonRuleLoopBreaker _ = False
+
+nonRuleLoopBreaker :: OccInfo
+nonRuleLoopBreaker = IAmALoopBreaker False
isDeadOcc :: OccInfo -> Bool
isDeadOcc IAmDead = True
-isDeadOcc other = False
+isDeadOcc _ = False
-isOneOcc (OneOcc _ _ _) = True
-isOneOcc other = False
+isOneOcc :: OccInfo -> Bool
+isOneOcc (OneOcc {}) = True
+isOneOcc _ = False
-isFragileOcc :: OccInfo -> Bool
-isFragileOcc (OneOcc _ _ _) = True
-isFragileOcc other = False
+zapFragileOcc :: OccInfo -> OccInfo
+zapFragileOcc (OneOcc {}) = NoOccInfo
+zapFragileOcc occ = occ
\end{code}
\begin{code}
instance Outputable OccInfo where
-- only used for debugging; never parsed. KSW 1999-07
ppr NoOccInfo = empty
- ppr (IAmALoopBreaker ro) = ptext SLIT("LoopBreaker") <> if ro then char '!' else empty
- ppr IAmDead = ptext SLIT("Dead")
+ ppr (IAmALoopBreaker ro) = ptext (sLit "LoopBreaker") <> if ro then char '!' else empty
+ ppr IAmDead = ptext (sLit "Dead")
ppr (OneOcc inside_lam one_branch int_cxt)
- = ptext SLIT("Once") <> pp_lam <> pp_br <> pp_args
+ = ptext (sLit "Once") <> pp_lam <> pp_br <> pp_args
where
pp_lam | inside_lam = char 'L'
| otherwise = empty
%************************************************************************
%* *
-\subsection{Strictness indication}
+ Strictness indication
%* *
%************************************************************************
e.g. data T = MkT !Int !(Bool,Bool)
\begin{code}
-data StrictnessMark -- Used in interface decls only
- = MarkedStrict
- | MarkedUnboxed
- | NotMarkedStrict
- deriving( Eq )
+-------------------------
+-- HsBang describes what the *programmer* wrote
+-- This info is retained in the DataCon.dcStrictMarks field
+data HsBang = HsNoBang
-isMarkedUnboxed MarkedUnboxed = True
-isMarkedUnboxed other = False
+ | HsStrict
-isMarkedStrict NotMarkedStrict = False
-isMarkedStrict other = True -- All others are strict
+ | HsUnpack -- {-# UNPACK #-} ! (GHC extension, meaning "unbox")
+
+ | HsUnpackFailed -- An UNPACK pragma that we could not make
+ -- use of, because the type isn't unboxable;
+ -- equivalant to HsStrict except for checkValidDataCon
+ deriving (Eq, Data, Typeable)
+
+instance Outputable HsBang where
+ ppr HsNoBang = empty
+ ppr HsStrict = char '!'
+ ppr HsUnpack = ptext (sLit "{-# UNPACK #-} !")
+ ppr HsUnpackFailed = ptext (sLit "{-# UNPACK (failed) #-} !")
+
+isBanged :: HsBang -> Bool
+isBanged HsNoBang = False
+isBanged _ = True
+
+isMarkedUnboxed :: HsBang -> Bool
+isMarkedUnboxed HsUnpack = True
+isMarkedUnboxed _ = False
+
+-------------------------
+-- StrictnessMark is internal only, used to indicate strictness
+-- of the DataCon *worker* fields
+data StrictnessMark = MarkedStrict | NotMarkedStrict
instance Outputable StrictnessMark where
- ppr MarkedStrict = ptext SLIT("!")
- ppr MarkedUnboxed = ptext SLIT("!!")
- ppr NotMarkedStrict = ptext SLIT("_")
+ ppr MarkedStrict = ptext (sLit "!")
+ ppr NotMarkedStrict = empty
+
+isMarkedStrict :: StrictnessMark -> Bool
+isMarkedStrict NotMarkedStrict = False
+isMarkedStrict _ = True -- All others are strict
\end{code}
%************************************************************************
%* *
+ Default method specfication
+%* *
+%************************************************************************
+
+The DefMethSpec enumeration just indicates what sort of default method
+is used for a class. It is generated from source code, and present in
+interface files; it is converted to Class.DefMeth before begin put in a
+Class object.
+
+\begin{code}
+data DefMethSpec = NoDM -- No default method
+ | VanillaDM -- Default method given with polymorphic code
+ | GenericDM -- Default method given with generic code
+
+instance Outputable DefMethSpec where
+ ppr NoDM = empty
+ ppr VanillaDM = ptext (sLit "{- Has default method -}")
+ ppr GenericDM = ptext (sLit "{- Has generic default method -}")
+\end{code}
+
+%************************************************************************
+%* *
\subsection{Success flag}
%* *
%************************************************************************
\begin{code}
data SuccessFlag = Succeeded | Failed
+instance Outputable SuccessFlag where
+ ppr Succeeded = ptext (sLit "Succeeded")
+ ppr Failed = ptext (sLit "Failed")
+
successIf :: Bool -> SuccessFlag
successIf True = Succeeded
successIf False = Failed
When a rule or inlining is active
\begin{code}
-type CompilerPhase = Int -- Compilation phase
- -- Phases decrease towards zero
- -- Zero is the last phase
+type PhaseNum = Int -- Compilation phase
+ -- Phases decrease towards zero
+ -- Zero is the last phase
+
+data CompilerPhase
+ = Phase PhaseNum
+ | InitialPhase -- The first phase -- number = infinity!
+
+instance Outputable CompilerPhase where
+ ppr (Phase n) = int n
+ ppr InitialPhase = ptext (sLit "InitialPhase")
data Activation = NeverActive
| AlwaysActive
- | ActiveBefore CompilerPhase -- Active only *before* this phase
- | ActiveAfter CompilerPhase -- Active in this phase and later
- deriving( Eq ) -- Eq used in comparing rules in HsDecls
-
-data InlineSpec
- = Inline
- Activation -- Says during which phases inlining is allowed
- Bool -- True <=> make the RHS look small, so that when inlining
- -- is enabled, it will definitely actually happen
- deriving( Eq )
+ | ActiveBefore PhaseNum -- Active only *before* this phase
+ | ActiveAfter PhaseNum -- Active in this phase and later
+ deriving( Eq, Data, Typeable ) -- Eq used in comparing rules in HsDecls
+
+data RuleMatchInfo = ConLike -- See Note [CONLIKE pragma]
+ | FunLike
+ deriving( Eq, Data, Typeable, Show )
+ -- Show needed for Lexer.x
+
+data InlinePragma -- Note [InlinePragma]
+ = InlinePragma
+ { inl_inline :: InlineSpec
+
+ , inl_sat :: Maybe Arity -- Just n <=> Inline only when applied to n
+ -- explicit (non-type, non-dictionary) args
+ -- That is, inl_sat describes the number of *source-code*
+ -- arguments the thing must be applied to. We add on the
+ -- number of implicit, dictionary arguments when making
+ -- the InlineRule, and don't look at inl_sat further
+
+ , inl_act :: Activation -- Says during which phases inlining is allowed
+
+ , inl_rule :: RuleMatchInfo -- Should the function be treated like a constructor?
+ } deriving( Eq, Data, Typeable )
+
+data InlineSpec -- What the user's INLINE pragama looked like
+ = Inline
+ | Inlinable
+ | NoInline
+ | EmptyInlineSpec
+ deriving( Eq, Data, Typeable, Show )
+ -- Show needed for Lexer.x
+\end{code}
+
+Note [InlinePragma]
+~~~~~~~~~~~~~~~~~~~
+This data type mirrors what you can write in an INLINE or NOINLINE pragma in
+the source program.
-defaultInlineSpec = Inline AlwaysActive False -- Inlining is OK, but not forced
-alwaysInlineSpec = Inline AlwaysActive True -- INLINE always
-neverInlineSpec = Inline NeverActive False -- NOINLINE
+If you write nothing at all, you get defaultInlinePragma:
+ inl_inline = False
+ inl_act = AlwaysActive
+ inl_rule = FunLike
+
+It's not possible to get that combination by *writing* something, so
+if an Id has defaultInlinePragma it means the user didn't specify anything.
+
+If inl_inline = True, then the Id should have an InlineRule unfolding.
+
+Note [CONLIKE pragma]
+~~~~~~~~~~~~~~~~~~~~~
+The ConLike constructor of a RuleMatchInfo is aimed at the following.
+Consider first
+ {-# RULE "r/cons" forall a as. r (a:as) = f (a+1) #-}
+ g b bs = let x = b:bs in ..x...x...(r x)...
+Now, the rule applies to the (r x) term, because GHC "looks through"
+the definition of 'x' to see that it is (b:bs).
+
+Now consider
+ {-# RULE "r/f" forall v. r (f v) = f (v+1) #-}
+ g v = let x = f v in ..x...x...(r x)...
+Normally the (r x) would *not* match the rule, because GHC would be
+scared about duplicating the redex (f v), so it does not "look
+through" the bindings.
+
+However the CONLIKE modifier says to treat 'f' like a constructor in
+this situation, and "look through" the unfolding for x. So (r x)
+fires, yielding (f (v+1)).
+
+This is all controlled with a user-visible pragma:
+ {-# NOINLINE CONLIKE [1] f #-}
+
+The main effects of CONLIKE are:
+
+ - The occurrence analyser (OccAnal) and simplifier (Simplify) treat
+ CONLIKE thing like constructors, by ANF-ing them
+
+ - New function coreUtils.exprIsExpandable is like exprIsCheap, but
+ additionally spots applications of CONLIKE functions
+
+ - A CoreUnfolding has a field that caches exprIsExpandable
+
+ - The rule matcher consults this field. See
+ Note [Expanding variables] in Rules.lhs.
+
+\begin{code}
+isConLike :: RuleMatchInfo -> Bool
+isConLike ConLike = True
+isConLike _ = False
+
+isFunLike :: RuleMatchInfo -> Bool
+isFunLike FunLike = True
+isFunLike _ = False
+
+isEmptyInlineSpec :: InlineSpec -> Bool
+isEmptyInlineSpec EmptyInlineSpec = True
+isEmptyInlineSpec _ = False
+
+defaultInlinePragma, alwaysInlinePragma, neverInlinePragma, dfunInlinePragma
+ :: InlinePragma
+defaultInlinePragma = InlinePragma { inl_act = AlwaysActive
+ , inl_rule = FunLike
+ , inl_inline = EmptyInlineSpec
+ , inl_sat = Nothing }
+
+alwaysInlinePragma = defaultInlinePragma { inl_inline = Inline }
+neverInlinePragma = defaultInlinePragma { inl_act = NeverActive }
+
+inlinePragmaSpec :: InlinePragma -> InlineSpec
+inlinePragmaSpec = inl_inline
+
+-- A DFun has an always-active inline activation so that
+-- exprIsConApp_maybe can "see" its unfolding
+-- (However, its actual Unfolding is a DFunUnfolding, which is
+-- never inlined other than via exprIsConApp_maybe.)
+dfunInlinePragma = defaultInlinePragma { inl_act = AlwaysActive
+ , inl_rule = ConLike }
+
+isDefaultInlinePragma :: InlinePragma -> Bool
+isDefaultInlinePragma (InlinePragma { inl_act = activation
+ , inl_rule = match_info
+ , inl_inline = inline })
+ = isEmptyInlineSpec inline && isAlwaysActive activation && isFunLike match_info
+
+isInlinePragma :: InlinePragma -> Bool
+isInlinePragma prag = case inl_inline prag of
+ Inline -> True
+ _ -> False
+
+isInlinablePragma :: InlinePragma -> Bool
+isInlinablePragma prag = case inl_inline prag of
+ Inlinable -> True
+ _ -> False
+
+isAnyInlinePragma :: InlinePragma -> Bool
+-- INLINE or INLINABLE
+isAnyInlinePragma prag = case inl_inline prag of
+ Inline -> True
+ Inlinable -> True
+ _ -> False
+
+inlinePragmaSat :: InlinePragma -> Maybe Arity
+inlinePragmaSat = inl_sat
+
+inlinePragmaActivation :: InlinePragma -> Activation
+inlinePragmaActivation (InlinePragma { inl_act = activation }) = activation
+
+inlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo
+inlinePragmaRuleMatchInfo (InlinePragma { inl_rule = info }) = info
+
+setInlinePragmaActivation :: InlinePragma -> Activation -> InlinePragma
+setInlinePragmaActivation prag activation = prag { inl_act = activation }
+
+setInlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo -> InlinePragma
+setInlinePragmaRuleMatchInfo prag info = prag { inl_rule = info }
instance Outputable Activation where
- ppr AlwaysActive = empty -- The default
+ ppr AlwaysActive = brackets (ptext (sLit "ALWAYS"))
+ ppr NeverActive = brackets (ptext (sLit "NEVER"))
ppr (ActiveBefore n) = brackets (char '~' <> int n)
ppr (ActiveAfter n) = brackets (int n)
- ppr NeverActive = ptext SLIT("NEVER")
-
+
+instance Outputable RuleMatchInfo where
+ ppr ConLike = ptext (sLit "CONLIKE")
+ ppr FunLike = ptext (sLit "FUNLIKE")
+
instance Outputable InlineSpec where
- ppr (Inline act True) = ptext SLIT("INLINE") <> ppr act
- ppr (Inline act False) = ptext SLIT("NOINLINE") <> ppr act
+ ppr Inline = ptext (sLit "INLINE")
+ ppr NoInline = ptext (sLit "NOINLINE")
+ ppr Inlinable = ptext (sLit "INLINABLE")
+ ppr EmptyInlineSpec = empty
+
+instance Outputable InlinePragma where
+ ppr (InlinePragma { inl_inline = inline, inl_act = activation
+ , inl_rule = info, inl_sat = mb_arity })
+ = ppr inline <> pp_act inline activation <+> pp_sat <+> pp_info
+ where
+ pp_act Inline AlwaysActive = empty
+ pp_act NoInline NeverActive = empty
+ pp_act _ act = ppr act
+
+ pp_sat | Just ar <- mb_arity = parens (ptext (sLit "sat-args=") <> int ar)
+ | otherwise = empty
+ pp_info | isFunLike info = empty
+ | otherwise = ppr info
isActive :: CompilerPhase -> Activation -> Bool
-isActive p NeverActive = False
-isActive p AlwaysActive = True
-isActive p (ActiveAfter n) = p <= n
-isActive p (ActiveBefore n) = p > n
-
-isNeverActive, isAlwaysActive :: Activation -> Bool
+isActive InitialPhase AlwaysActive = True
+isActive InitialPhase (ActiveBefore {}) = True
+isActive InitialPhase _ = False
+isActive (Phase p) act = isActiveIn p act
+
+isActiveIn :: PhaseNum -> Activation -> Bool
+isActiveIn _ NeverActive = False
+isActiveIn _ AlwaysActive = True
+isActiveIn p (ActiveAfter n) = p <= n
+isActiveIn p (ActiveBefore n) = p > n
+
+isNeverActive, isAlwaysActive, isEarlyActive :: Activation -> Bool
isNeverActive NeverActive = True
-isNeverActive act = False
+isNeverActive _ = False
isAlwaysActive AlwaysActive = True
-isAlwaysActive other = False
+isAlwaysActive _ = False
+
+isEarlyActive AlwaysActive = True
+isEarlyActive (ActiveBefore {}) = True
+isEarlyActive _ = False
\end{code}