summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core.hs
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2022-05-26 16:11:58 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-01-17 19:04:50 -0500
commit4322de246d35091e5e95a3a87fb4c1f9b7a61ee9 (patch)
tree092cd0e518b59d5fc0d666c6f1bf56e0b3c421c2 /compiler/GHC/Core.hs
parentf4d50bafb7e14f76273aaf6f634815d5628ccc86 (diff)
downloadhaskell-wip/rules-module.tar.gz
Split up `GHC.Core` somewhatwip/rules-module
- `GHC.Core.Annotated` now contains annotated Core - `GHC.Core.Rules` now contains the rules definitions - `GHC.Core.Orphans` now contains the orphans *something* - `GHC.Core.Unfoldings` now contains the unfoldings defintions - The old `GHC.Core.Rules`, which was about applying rules, is now `GHC.Core.Rules.Apply`. Compare with `GHC.Core.Simplify.Inlin` which was also about operations not the data structures and simple predictes themselves (which is `GHC.Core.Unfold`).
Diffstat (limited to 'compiler/GHC/Core.hs')
-rw-r--r--compiler/GHC/Core.hs774
1 files changed, 1 insertions, 773 deletions
diff --git a/compiler/GHC/Core.hs b/compiler/GHC/Core.hs
index 92b34ffc21..1c45e8de9b 100644
--- a/compiler/GHC/Core.hs
+++ b/compiler/GHC/Core.hs
@@ -50,65 +50,19 @@ module GHC.Core (
isValArg, isTypeArg, isCoArg, isTyCoArg, valArgCount, valBndrCount,
isRuntimeArg, isRuntimeVar,
-
- -- * Unfolding data types
- Unfolding(..), UnfoldingCache(..), UnfoldingGuidance(..), UnfoldingSource(..),
-
- -- ** Constructing 'Unfolding's
- noUnfolding, bootUnfolding, evaldUnfolding, mkOtherCon,
- unSaturatedOk, needSaturated, boringCxtOk, boringCxtNotOk,
-
- -- ** Predicates and deconstruction on 'Unfolding'
- unfoldingTemplate, expandUnfolding_maybe,
- maybeUnfoldingTemplate, otherCons,
- isValueUnfolding, isEvaldUnfolding, isCheapUnfolding,
- isExpandableUnfolding, isConLikeUnfolding, isCompulsoryUnfolding,
- isStableUnfolding, isStableUserUnfolding, isStableSystemUnfolding,
- isInlineUnfolding, isBootUnfolding,
- hasCoreUnfolding, hasSomeUnfolding,
- canUnfold, neverUnfoldGuidance, isStableSource,
-
- -- * Annotated expression data types
- AnnExpr, AnnExpr'(..), AnnBind(..), AnnAlt(..),
-
- -- ** Operations on annotated expressions
- collectAnnArgs, collectAnnArgsTicks,
-
- -- ** Operations on annotations
- deAnnotate, deAnnotate', deAnnAlt, deAnnBind,
- collectAnnBndrs, collectNAnnBndrs,
-
- -- * Orphanhood
- IsOrphan(..), isOrphan, notOrphan, chooseOrphanAnchor,
-
- -- * Core rule data types
- CoreRule(..),
- RuleName, RuleFun, IdUnfoldingFun, InScopeEnv, RuleOpts,
-
- -- ** Operations on 'CoreRule's
- ruleArity, ruleName, ruleIdName, ruleActivation,
- setRuleIdName, ruleModule,
- isBuiltinRule, isLocalRule, isAutoRule,
) where
import GHC.Prelude
import GHC.Platform
-import GHC.Types.Var.Env( InScopeSet )
import GHC.Types.Var
import GHC.Core.Type
import GHC.Core.Coercion
-import GHC.Core.Rules.Config ( RuleOpts )
-import GHC.Types.Name
-import GHC.Types.Name.Set
import GHC.Types.Literal
import GHC.Types.Tickish
import GHC.Core.DataCon
-import GHC.Unit.Module
-import GHC.Types.Basic
-import GHC.Types.Unique.Set
+import GHC.Types.Basic (Arity, JoinArity)
-import GHC.Utils.Binary
import GHC.Utils.Misc
import GHC.Utils.Outputable
import GHC.Utils.Panic
@@ -984,641 +938,9 @@ type OutAlt = CoreAlt
type OutArg = CoreArg
type MOutCoercion = MCoercion
-
-{-
-************************************************************************
-* *
- Orphans
-* *
-************************************************************************
--}
-
--- | Is this instance an orphan? If it is not an orphan, contains an 'OccName'
--- witnessing the instance's non-orphanhood.
--- See Note [Orphans]
-data IsOrphan
- = IsOrphan
- | NotOrphan !OccName -- The OccName 'n' witnesses the instance's non-orphanhood
- -- In that case, the instance is fingerprinted as part
- -- of the definition of 'n's definition
- deriving Data
-
--- | Returns true if 'IsOrphan' is orphan.
-isOrphan :: IsOrphan -> Bool
-isOrphan IsOrphan = True
-isOrphan _ = False
-
--- | Returns true if 'IsOrphan' is not an orphan.
-notOrphan :: IsOrphan -> Bool
-notOrphan NotOrphan{} = True
-notOrphan _ = False
-
-chooseOrphanAnchor :: NameSet -> IsOrphan
--- Something (rule, instance) is relate to all the Names in this
--- list. Choose one of them to be an "anchor" for the orphan. We make
--- the choice deterministic to avoid gratuitous changes in the ABI
--- hash (#4012). Specifically, use lexicographic comparison of
--- OccName rather than comparing Uniques
---
--- NB: 'minimum' use Ord, and (Ord OccName) works lexicographically
---
-chooseOrphanAnchor local_names
- | isEmptyNameSet local_names = IsOrphan
- | otherwise = NotOrphan (minimum occs)
- where
- occs = map nameOccName $ nonDetEltsUniqSet local_names
- -- It's OK to use nonDetEltsUFM here, see comments above
-
-instance Binary IsOrphan where
- put_ bh IsOrphan = putByte bh 0
- put_ bh (NotOrphan n) = do
- putByte bh 1
- put_ bh n
- get bh = do
- h <- getByte bh
- case h of
- 0 -> return IsOrphan
- _ -> do
- n <- get bh
- return $ NotOrphan n
-
-{-
-Note [Orphans]
-~~~~~~~~~~~~~~
-Class instances, rules, and family instances are divided into orphans
-and non-orphans. Roughly speaking, an instance/rule is an orphan if
-its left hand side mentions nothing defined in this module. Orphan-hood
-has two major consequences
-
- * A module that contains orphans is called an "orphan module". If
- the module being compiled depends (transitively) on an orphan
- module M, then M.hi is read in regardless of whether M is otherwise
- needed. This is to ensure that we don't miss any instance decls in
- M. But it's painful, because it means we need to keep track of all
- the orphan modules below us.
-
- * The "visible orphan modules" are all the orphan module in the transitive
- closure of the imports of this module.
-
- * During instance lookup, we filter orphan instances depending on
- whether or not the instance is in a visible orphan module.
-
- * A non-orphan is not finger-printed separately. Instead, for
- fingerprinting purposes it is treated as part of the entity it
- mentions on the LHS. For example
- data T = T1 | T2
- instance Eq T where ....
- The instance (Eq T) is incorporated as part of T's fingerprint.
-
- In contrast, orphans are all fingerprinted together in the
- mi_orph_hash field of the ModIface.
-
- See GHC.Iface.Recomp.addFingerprints.
-
-Orphan-hood is computed
- * For class instances:
- when we make a ClsInst in GHC.Core.InstEnv.mkLocalInstance
- (because it is needed during instance lookup)
- See Note [When exactly is an instance decl an orphan?]
- in GHC.Core.InstEnv
-
- * For rules
- when we generate a CoreRule (GHC.Core.Rules.mkRule)
-
- * For family instances:
- when we generate an IfaceFamInst (GHC.Iface.Make.instanceToIfaceInst)
-
-Orphan-hood is persisted into interface files, in ClsInst, FamInst,
-and CoreRules.
-
--}
-
-{-
-************************************************************************
-* *
-\subsection{Rewrite rules}
-* *
-************************************************************************
-
-The CoreRule type and its friends are dealt with mainly in GHC.Core.Rules, but
-GHC.Core.FVs, GHC.Core.Subst, GHC.Core.Ppr, GHC.Core.Tidy also inspect the
-representation.
--}
-
-
--- | A 'CoreRule' is:
---
--- * \"Local\" if the function it is a rule for is defined in the
--- same module as the rule itself.
---
--- * \"Orphan\" if nothing on the LHS is defined in the same module
--- as the rule itself
-data CoreRule
- = Rule {
- ru_name :: RuleName, -- ^ Name of the rule, for communication with the user
- ru_act :: Activation, -- ^ When the rule is active
-
- -- Rough-matching stuff
- -- see comments with InstEnv.ClsInst( is_cls, is_rough )
- ru_fn :: !Name, -- ^ Name of the 'GHC.Types.Id.Id' at the head of this rule
- ru_rough :: [Maybe Name], -- ^ Name at the head of each argument to the left hand side
-
- -- Proper-matching stuff
- -- see comments with InstEnv.ClsInst( is_tvs, is_tys )
- ru_bndrs :: [CoreBndr], -- ^ Variables quantified over
- ru_args :: [CoreExpr], -- ^ Left hand side arguments
-
- -- And the right-hand side
- ru_rhs :: CoreExpr, -- ^ Right hand side of the rule
- -- Occurrence info is guaranteed correct
- -- See Note [OccInfo in unfoldings and rules]
-
- -- Locality
- ru_auto :: Bool, -- ^ @True@ <=> this rule is auto-generated
- -- (notably by Specialise or SpecConstr)
- -- @False@ <=> generated at the user's behest
- -- See Note [Trimming auto-rules] in "GHC.Iface.Tidy"
- -- for the sole purpose of this field.
-
- ru_origin :: !Module, -- ^ 'Module' the rule was defined in, used
- -- to test if we should see an orphan rule.
-
- ru_orphan :: !IsOrphan, -- ^ Whether or not the rule is an orphan.
-
- ru_local :: Bool -- ^ @True@ iff the fn at the head of the rule is
- -- defined in the same module as the rule
- -- and is not an implicit 'Id' (like a record selector,
- -- class operation, or data constructor). This
- -- is different from 'ru_orphan', where a rule
- -- can avoid being an orphan if *any* Name in
- -- LHS of the rule was defined in the same
- -- module as the rule.
- }
-
- -- | Built-in rules are used for constant folding
- -- and suchlike. They have no free variables.
- -- A built-in rule is always visible (there is no such thing as
- -- an orphan built-in rule.)
- | BuiltinRule {
- ru_name :: RuleName, -- ^ As above
- ru_fn :: Name, -- ^ As above
- ru_nargs :: Int, -- ^ Number of arguments that 'ru_try' consumes,
- -- if it fires, including type arguments
- ru_try :: RuleFun
- -- ^ This function does the rewrite. It given too many
- -- arguments, it simply discards them; the returned 'CoreExpr'
- -- is just the rewrite of 'ru_fn' applied to the first 'ru_nargs' args
- }
- -- See Note [Extra args in the target] in GHC.Core.Rules
-
--- | The 'InScopeSet' in the 'InScopeEnv' is a /superset/ of variables that are
--- currently in scope. See Note [The InScopeSet invariant].
-type RuleFun = RuleOpts -> InScopeEnv -> Id -> [CoreExpr] -> Maybe CoreExpr
-type InScopeEnv = (InScopeSet, IdUnfoldingFun)
-
-type IdUnfoldingFun = Id -> Unfolding
--- A function that embodies how to unfold an Id if you need
--- to do that in the Rule. The reason we need to pass this info in
--- is that whether an Id is unfoldable depends on the simplifier phase
-
-isBuiltinRule :: CoreRule -> Bool
-isBuiltinRule (BuiltinRule {}) = True
-isBuiltinRule _ = False
-
-isAutoRule :: CoreRule -> Bool
-isAutoRule (BuiltinRule {}) = False
-isAutoRule (Rule { ru_auto = is_auto }) = is_auto
-
--- | The number of arguments the 'ru_fn' must be applied
--- to before the rule can match on it
-ruleArity :: CoreRule -> Int
-ruleArity (BuiltinRule {ru_nargs = n}) = n
-ruleArity (Rule {ru_args = args}) = length args
-
-ruleName :: CoreRule -> RuleName
-ruleName = ru_name
-
-ruleModule :: CoreRule -> Maybe Module
-ruleModule Rule { ru_origin } = Just ru_origin
-ruleModule BuiltinRule {} = Nothing
-
-ruleActivation :: CoreRule -> Activation
-ruleActivation (BuiltinRule { }) = AlwaysActive
-ruleActivation (Rule { ru_act = act }) = act
-
--- | The 'Name' of the 'GHC.Types.Id.Id' at the head of the rule left hand side
-ruleIdName :: CoreRule -> Name
-ruleIdName = ru_fn
-
-isLocalRule :: CoreRule -> Bool
-isLocalRule = ru_local
-
--- | Set the 'Name' of the 'GHC.Types.Id.Id' at the head of the rule left hand side
-setRuleIdName :: Name -> CoreRule -> CoreRule
-setRuleIdName nm ru = ru { ru_fn = nm }
-
{-
************************************************************************
* *
- Unfoldings
-* *
-************************************************************************
-
-The @Unfolding@ type is declared here to avoid numerous loops
-
-Note [Never put `OtherCon` unfoldings on lambda binders]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Based on #21496 we never attach unfoldings of any kind to lambda binders.
-It's just too easy for the call site to change and invalidate the unfolding.
-E.g. the caller of the lambda drops a seq (e.g. because the lambda is strict in it's binder)
-which in turn makes the OtherCon[] unfolding a lie.
-So unfoldings on lambda binders can never really be trusted when on lambda binders if there
-is the chance of the call site to change. So it's easiest to just never attach any
-to lambda binders to begin with, as well as stripping them off if we e.g. float out
-and expression while abstracting over some arguments.
--}
-
--- | Records the /unfolding/ of an identifier, which is approximately the form the
--- identifier would have if we substituted its definition in for the identifier.
--- This type should be treated as abstract everywhere except in "GHC.Core.Unfold"
-data Unfolding
- = NoUnfolding -- ^ We have no information about the unfolding.
-
- | BootUnfolding -- ^ We have no information about the unfolding, because
- -- this 'Id' came from an @hi-boot@ file.
- -- See Note [Inlining and hs-boot files] in "GHC.CoreToIface"
- -- for what this is used for.
-
- | OtherCon [AltCon] -- ^ It ain't one of these constructors.
- -- @OtherCon xs@ also indicates that something has been evaluated
- -- and hence there's no point in re-evaluating it.
- -- @OtherCon []@ is used even for non-data-type values
- -- to indicated evaluated-ness. Notably:
- --
- -- > data C = C !(Int -> Int)
- -- > case x of { C f -> ... }
- --
- -- Here, @f@ gets an @OtherCon []@ unfolding.
-
- | DFunUnfolding { -- The Unfolding of a DFunId
- -- See Note [DFun unfoldings]
- -- df = /\a1..am. \d1..dn. MkD t1 .. tk
- -- (op1 a1..am d1..dn)
- -- (op2 a1..am d1..dn)
- df_bndrs :: [Var], -- The bound variables [a1..m],[d1..dn]
- df_con :: DataCon, -- The dictionary data constructor (never a newtype datacon)
- df_args :: [CoreExpr] -- Args of the data con: types, superclasses and methods,
- } -- in positional order
-
- | CoreUnfolding { -- An unfolding for an Id with no pragma,
- -- or perhaps a NOINLINE pragma
- -- (For NOINLINE, the phase, if any, is in the
- -- InlinePragInfo for this Id.)
- uf_tmpl :: CoreExpr, -- Template; occurrence info is correct
- uf_src :: UnfoldingSource, -- Where the unfolding came from
- uf_is_top :: Bool, -- True <=> top level binding
- uf_cache :: UnfoldingCache, -- Cache of flags computable from the expr
- -- See Note [Tying the 'CoreUnfolding' knot]
- uf_guidance :: UnfoldingGuidance -- Tells about the *size* of the template.
- }
- -- ^ An unfolding with redundant cached information. Parameters:
- --
- -- uf_tmpl: Template used to perform unfolding;
- -- NB: Occurrence info is guaranteed correct:
- -- see Note [OccInfo in unfoldings and rules]
- --
- -- uf_is_top: Is this a top level binding?
- --
- -- uf_is_value: 'exprIsHNF' template (cached); it is ok to discard a 'seq' on
- -- this variable
- --
- -- uf_is_work_free: Does this waste only a little work if we expand it inside an inlining?
- -- Basically this is a cached version of 'exprIsWorkFree'
- --
- -- uf_guidance: Tells us about the /size/ of the unfolding template
-
-
--- | Properties of a 'CoreUnfolding' that could be computed on-demand from its template.
--- See Note [UnfoldingCache]
-data UnfoldingCache
- = UnfoldingCache {
- uf_is_value :: !Bool, -- exprIsHNF template (cached); it is ok to discard
- -- a `seq` on this variable
- uf_is_conlike :: !Bool, -- True <=> applicn of constructor or CONLIKE function
- -- Cached version of exprIsConLike
- uf_is_work_free :: !Bool, -- True <=> doesn't waste (much) work to expand
- -- inside an inlining
- -- Cached version of exprIsCheap
- uf_expandable :: !Bool -- True <=> can expand in RULE matching
- -- Cached version of exprIsExpandable
- }
- deriving (Eq)
-
--- | 'UnfoldingGuidance' says when unfolding should take place
-data UnfoldingGuidance
- = UnfWhen { -- Inline without thinking about the *size* of the uf_tmpl
- -- Used (a) for small *and* cheap unfoldings
- -- (b) for INLINE functions
- -- See Note [INLINE for small functions] in GHC.Core.Unfold
- ug_arity :: Arity, -- Number of value arguments expected
-
- ug_unsat_ok :: Bool, -- True <=> ok to inline even if unsaturated
- ug_boring_ok :: Bool -- True <=> ok to inline even if the context is boring
- -- So True,True means "always"
- }
-
- | UnfIfGoodArgs { -- Arose from a normal Id; the info here is the
- -- result of a simple analysis of the RHS
-
- ug_args :: [Int], -- Discount if the argument is evaluated.
- -- (i.e., a simplification will definitely
- -- be possible). One elt of the list per *value* arg.
-
- ug_size :: Int, -- The "size" of the unfolding.
-
- ug_res :: Int -- Scrutinee discount: the discount to subtract if the thing is in
- } -- a context (case (thing args) of ...),
- -- (where there are the right number of arguments.)
-
- | UnfNever -- The RHS is big, so don't inline it
- deriving (Eq)
-
-{- Note [UnfoldingCache]
-~~~~~~~~~~~~~~~~~~~~~~~~
-The UnfoldingCache field of an Unfolding holds four (strict) booleans,
-all derived from the uf_tmpl field of the unfolding.
-
-* We serialise the UnfoldingCache to and from interface files, for
- reasons described in Note [Tying the 'CoreUnfolding' knot] in
- GHC.IfaceToCore
-
-* Because it is a strict data type, we must be careful not to
- pattern-match on it until we actually want its values. E.g
- GHC.Core.Unfold.callSiteInline/tryUnfolding are careful not to force
- it unnecessarily. Just saves a bit of work.
-
-* When `seq`ing Core to eliminate space leaks, to suffices to `seq` on
- the cache, but not its fields, because it is strict in all fields.
-
-Note [Historical note: unfoldings for wrappers]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We used to have a nice clever scheme in interface files for
-wrappers. A wrapper's unfolding can be reconstructed from its worker's
-id and its strictness. This decreased .hi file size (sometimes
-significantly, for modules like GHC.Classes with many high-arity w/w
-splits) and had a slight corresponding effect on compile times.
-
-However, when we added the second demand analysis, this scheme lead to
-some Core lint errors. The second analysis could change the strictness
-signatures, which sometimes resulted in a wrapper's regenerated
-unfolding applying the wrapper to too many arguments.
-
-Instead of repairing the clever .hi scheme, we abandoned it in favor
-of simplicity. The .hi sizes are usually insignificant (excluding the
-+1M for base libraries), and compile time barely increases (~+1% for
-nofib). The nicer upshot is that the UnfoldingSource no longer mentions
-an Id, so, eg, substitutions need not traverse them.
-
-
-Note [DFun unfoldings]
-~~~~~~~~~~~~~~~~~~~~~~
-The Arity in a DFunUnfolding is total number of args (type and value)
-that the DFun needs to produce a dictionary. That's not necessarily
-related to the ordinary arity of the dfun Id, esp if the class has
-one method, so the dictionary is represented by a newtype. Example
-
- class C a where { op :: a -> Int }
- instance C a -> C [a] where op xs = op (head xs)
-
-The instance translates to
-
- $dfCList :: forall a. C a => C [a] -- Arity 2!
- $dfCList = /\a.\d. $copList {a} d |> co
-
- $copList :: forall a. C a => [a] -> Int -- Arity 2!
- $copList = /\a.\d.\xs. op {a} d (head xs)
-
-Now we might encounter (op (dfCList {ty} d) a1 a2)
-and we want the (op (dfList {ty} d)) rule to fire, because $dfCList
-has all its arguments, even though its (value) arity is 2. That's
-why we record the number of expected arguments in the DFunUnfolding.
-
-Note that although it's an Arity, it's most convenient for it to give
-the *total* number of arguments, both type and value. See the use
-site in exprIsConApp_maybe.
--}
-
--- Constants for the UnfWhen constructor
-needSaturated, unSaturatedOk :: Bool
-needSaturated = False
-unSaturatedOk = True
-
-boringCxtNotOk, boringCxtOk :: Bool
-boringCxtOk = True
-boringCxtNotOk = False
-
-------------------------------------------------
-noUnfolding :: Unfolding
--- ^ There is no known 'Unfolding'
-evaldUnfolding :: Unfolding
--- ^ This unfolding marks the associated thing as being evaluated
-
-noUnfolding = NoUnfolding
-evaldUnfolding = OtherCon []
-
--- | There is no known 'Unfolding', because this came from an
--- hi-boot file.
-bootUnfolding :: Unfolding
-bootUnfolding = BootUnfolding
-
-mkOtherCon :: [AltCon] -> Unfolding
-mkOtherCon = OtherCon
-
--- | Retrieves the template of an unfolding: panics if none is known
-unfoldingTemplate :: Unfolding -> CoreExpr
-unfoldingTemplate = uf_tmpl
-
--- | Retrieves the template of an unfolding if possible
--- maybeUnfoldingTemplate is used mainly when specialising, and we do
--- want to specialise DFuns, so it's important to return a template
--- for DFunUnfoldings
-maybeUnfoldingTemplate :: Unfolding -> Maybe CoreExpr
-maybeUnfoldingTemplate (CoreUnfolding { uf_tmpl = expr })
- = Just expr
-maybeUnfoldingTemplate (DFunUnfolding { df_bndrs = bndrs, df_con = con, df_args = args })
- = Just (mkLams bndrs (mkApps (Var (dataConWorkId con)) args))
-maybeUnfoldingTemplate _
- = Nothing
-
--- | The constructors that the unfolding could never be:
--- returns @[]@ if no information is available
-otherCons :: Unfolding -> [AltCon]
-otherCons (OtherCon cons) = cons
-otherCons _ = []
-
--- | Determines if it is certainly the case that the unfolding will
--- yield a value (something in HNF): returns @False@ if unsure
-isValueUnfolding :: Unfolding -> Bool
- -- Returns False for OtherCon
-isValueUnfolding (CoreUnfolding { uf_cache = cache }) = uf_is_value cache
-isValueUnfolding (DFunUnfolding {}) = True
-isValueUnfolding _ = False
-
--- | Determines if it possibly the case that the unfolding will
--- yield a value. Unlike 'isValueUnfolding' it returns @True@
--- for 'OtherCon'
-isEvaldUnfolding :: Unfolding -> Bool
- -- Returns True for OtherCon
-isEvaldUnfolding (OtherCon _) = True
-isEvaldUnfolding (DFunUnfolding {}) = True
-isEvaldUnfolding (CoreUnfolding { uf_cache = cache }) = uf_is_value cache
-isEvaldUnfolding _ = False
-
--- | @True@ if the unfolding is a constructor application, the application
--- of a CONLIKE function or 'OtherCon'
-isConLikeUnfolding :: Unfolding -> Bool
-isConLikeUnfolding (OtherCon _) = True
-isConLikeUnfolding (CoreUnfolding { uf_cache = cache }) = uf_is_conlike cache
-isConLikeUnfolding _ = False
-
--- | Is the thing we will unfold into certainly cheap?
-isCheapUnfolding :: Unfolding -> Bool
-isCheapUnfolding (CoreUnfolding { uf_cache = cache }) = uf_is_work_free cache
-isCheapUnfolding _ = False
-
-isExpandableUnfolding :: Unfolding -> Bool
-isExpandableUnfolding (CoreUnfolding { uf_cache = cache }) = uf_expandable cache
-isExpandableUnfolding _ = False
-
-expandUnfolding_maybe :: Unfolding -> Maybe CoreExpr
--- Expand an expandable unfolding; this is used in rule matching
--- See Note [Expanding variables] in GHC.Core.Rules
--- The key point here is that CONLIKE things can be expanded
-expandUnfolding_maybe (CoreUnfolding { uf_cache = cache, uf_tmpl = rhs })
- | uf_expandable cache
- = Just rhs
-expandUnfolding_maybe _ = Nothing
-
-isCompulsoryUnfolding :: Unfolding -> Bool
-isCompulsoryUnfolding (CoreUnfolding { uf_src = src }) = isCompulsorySource src
-isCompulsoryUnfolding _ = False
-
-isStableUnfolding :: Unfolding -> Bool
--- True of unfoldings that should not be overwritten
--- by a CoreUnfolding for the RHS of a let-binding
-isStableUnfolding (CoreUnfolding { uf_src = src }) = isStableSource src
-isStableUnfolding (DFunUnfolding {}) = True
-isStableUnfolding _ = False
-
-isStableUserUnfolding :: Unfolding -> Bool
--- True of unfoldings that arise from an INLINE or INLINEABLE pragma
-isStableUserUnfolding (CoreUnfolding { uf_src = src }) = isStableUserSource src
-isStableUserUnfolding _ = False
-
-isStableSystemUnfolding :: Unfolding -> Bool
--- True of unfoldings that arise from an INLINE or INLINEABLE pragma
-isStableSystemUnfolding (CoreUnfolding { uf_src = src }) = isStableSystemSource src
-isStableSystemUnfolding _ = False
-
-isInlineUnfolding :: Unfolding -> Bool
--- ^ True of a /stable/ unfolding that is
--- (a) always inlined; that is, with an `UnfWhen` guidance, or
--- (b) a DFunUnfolding which never needs to be inlined
-isInlineUnfolding (CoreUnfolding { uf_src = src, uf_guidance = guidance })
- | isStableSource src
- , UnfWhen {} <- guidance
- = True
-
-isInlineUnfolding (DFunUnfolding {})
- = True
-
--- Default case
-isInlineUnfolding _ = False
-
-
--- | Only returns False if there is no unfolding information available at all
-hasSomeUnfolding :: Unfolding -> Bool
-hasSomeUnfolding NoUnfolding = False
-hasSomeUnfolding BootUnfolding = False
-hasSomeUnfolding _ = True
-
-isBootUnfolding :: Unfolding -> Bool
-isBootUnfolding BootUnfolding = True
-isBootUnfolding _ = False
-
-neverUnfoldGuidance :: UnfoldingGuidance -> Bool
-neverUnfoldGuidance UnfNever = True
-neverUnfoldGuidance _ = False
-
-hasCoreUnfolding :: Unfolding -> Bool
--- An unfolding "has Core" if it contains a Core expression, which
--- may mention free variables. See Note [Fragile unfoldings]
-hasCoreUnfolding (CoreUnfolding {}) = True
-hasCoreUnfolding (DFunUnfolding {}) = True
-hasCoreUnfolding _ = False
- -- NoUnfolding, BootUnfolding, OtherCon have no Core
-
-canUnfold :: Unfolding -> Bool
-canUnfold (CoreUnfolding { uf_guidance = g }) = not (neverUnfoldGuidance g)
-canUnfold _ = False
-
-{- Note [Fragile unfoldings]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-An unfolding is "fragile" if it mentions free variables (and hence would
-need substitution) or might be affected by optimisation. The non-fragile
-ones are
-
- NoUnfolding, BootUnfolding
-
- OtherCon {} If we know this binder (say a lambda binder) will be
- bound to an evaluated thing, we want to retain that
- info in simpleOptExpr; see #13077.
-
-We consider even a StableUnfolding as fragile, because it needs substitution.
-
-Note [Stable unfoldings]
-~~~~~~~~~~~~~~~~~~~~~~~~
-When you say
- {-# INLINE f #-}
- f x = <rhs>
-you intend that calls (f e) are replaced by <rhs>[e/x] So we
-should capture (\x.<rhs>) in the Unfolding of 'f', and never meddle
-with it. Meanwhile, we can optimise <rhs> to our heart's content,
-leaving the original unfolding intact in Unfolding of 'f'. For example
- all xs = foldr (&&) True xs
- any p = all . map p {-# INLINE any #-}
-We optimise any's RHS fully, but leave the stable unfolding for `any`
-saying "all . map p", which deforests well at the call site.
-
-So INLINE pragma gives rise to a stable unfolding, which captures the
-original RHS.
-
-Moreover, it's only used when 'f' is applied to the
-specified number of arguments; that is, the number of argument on
-the LHS of the '=' sign in the original source definition.
-For example, (.) is now defined in the libraries like this
- {-# INLINE (.) #-}
- (.) f g = \x -> f (g x)
-so that it'll inline when applied to two arguments. If 'x' appeared
-on the left, thus
- (.) f g x = f (g x)
-it'd only inline when applied to three arguments. This slightly-experimental
-change was requested by Roman, but it seems to make sense.
-
-Note [OccInfo in unfoldings and rules]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In unfoldings and rules, we guarantee that the template is occ-analysed,
-so that the occurrence info on the binders is correct. This is important,
-because the Simplifier does not re-analyse the template when using it. If
-the occurrence info is wrong
- - We may get more simplifier iterations than necessary, because
- once-occ info isn't there
- - More seriously, we may get an infinite loop if there's a Rec
- without a loop breaker marked
-
-
-************************************************************************
-* *
AltCon
* *
************************************************************************
@@ -2110,97 +1432,3 @@ valBndrCount = count isId
-- | The number of argument expressions that are values rather than types at their top level
valArgCount :: [Arg b] -> Int
valArgCount = count isValArg
-
-{-
-************************************************************************
-* *
-\subsection{Annotated core}
-* *
-************************************************************************
--}
-
--- | Annotated core: allows annotation at every node in the tree
-type AnnExpr bndr annot = (annot, AnnExpr' bndr annot)
-
--- | A clone of the 'Expr' type but allowing annotation at every tree node
-data AnnExpr' bndr annot
- = AnnVar Id
- | AnnLit Literal
- | AnnLam bndr (AnnExpr bndr annot)
- | AnnApp (AnnExpr bndr annot) (AnnExpr bndr annot)
- | AnnCase (AnnExpr bndr annot) bndr Type [AnnAlt bndr annot]
- | AnnLet (AnnBind bndr annot) (AnnExpr bndr annot)
- | AnnCast (AnnExpr bndr annot) (annot, Coercion)
- -- Put an annotation on the (root of) the coercion
- | AnnTick CoreTickish (AnnExpr bndr annot)
- | AnnType Type
- | AnnCoercion Coercion
-
--- | A clone of the 'Alt' type but allowing annotation at every tree node
-data AnnAlt bndr annot = AnnAlt AltCon [bndr] (AnnExpr bndr annot)
-
--- | A clone of the 'Bind' type but allowing annotation at every tree node
-data AnnBind bndr annot
- = AnnNonRec bndr (AnnExpr bndr annot)
- | AnnRec [(bndr, AnnExpr bndr annot)]
-
--- | Takes a nested application expression and returns the function
--- being applied and the arguments to which it is applied
-collectAnnArgs :: AnnExpr b a -> (AnnExpr b a, [AnnExpr b a])
-collectAnnArgs expr
- = go expr []
- where
- go (_, AnnApp f a) as = go f (a:as)
- go e as = (e, as)
-
-collectAnnArgsTicks :: (CoreTickish -> Bool) -> AnnExpr b a
- -> (AnnExpr b a, [AnnExpr b a], [CoreTickish])
-collectAnnArgsTicks tickishOk expr
- = go expr [] []
- where
- go (_, AnnApp f a) as ts = go f (a:as) ts
- go (_, AnnTick t e) as ts | tickishOk t
- = go e as (t:ts)
- go e as ts = (e, as, reverse ts)
-
-deAnnotate :: AnnExpr bndr annot -> Expr bndr
-deAnnotate (_, e) = deAnnotate' e
-
-deAnnotate' :: AnnExpr' bndr annot -> Expr bndr
-deAnnotate' (AnnType t) = Type t
-deAnnotate' (AnnCoercion co) = Coercion co
-deAnnotate' (AnnVar v) = Var v
-deAnnotate' (AnnLit lit) = Lit lit
-deAnnotate' (AnnLam binder body) = Lam binder (deAnnotate body)
-deAnnotate' (AnnApp fun arg) = App (deAnnotate fun) (deAnnotate arg)
-deAnnotate' (AnnCast e (_,co)) = Cast (deAnnotate e) co
-deAnnotate' (AnnTick tick body) = Tick tick (deAnnotate body)
-
-deAnnotate' (AnnLet bind body)
- = Let (deAnnBind bind) (deAnnotate body)
-deAnnotate' (AnnCase scrut v t alts)
- = Case (deAnnotate scrut) v t (map deAnnAlt alts)
-
-deAnnAlt :: AnnAlt bndr annot -> Alt bndr
-deAnnAlt (AnnAlt con args rhs) = Alt con args (deAnnotate rhs)
-
-deAnnBind :: AnnBind b annot -> Bind b
-deAnnBind (AnnNonRec var rhs) = NonRec var (deAnnotate rhs)
-deAnnBind (AnnRec pairs) = Rec [(v,deAnnotate rhs) | (v,rhs) <- pairs]
-
--- | As 'collectBinders' but for 'AnnExpr' rather than 'Expr'
-collectAnnBndrs :: AnnExpr bndr annot -> ([bndr], AnnExpr bndr annot)
-collectAnnBndrs e
- = collect [] e
- where
- collect bs (_, AnnLam b body) = collect (b:bs) body
- collect bs body = (reverse bs, body)
-
--- | As 'collectNBinders' but for 'AnnExpr' rather than 'Expr'
-collectNAnnBndrs :: Int -> AnnExpr bndr annot -> ([bndr], AnnExpr bndr annot)
-collectNAnnBndrs orig_n e
- = collect orig_n [] e
- where
- collect 0 bs body = (reverse bs, body)
- collect n bs (_, AnnLam b body) = collect (n-1) (b:bs) body
- collect _ _ _ = pprPanic "collectNBinders" $ int orig_n