ghc-9.6.0.20230210: The GHC API
Safe HaskellSafe-Inferred
LanguageHaskell2010

GHC.Types.Demand

Description

A language to express the evaluation context of an expression as a Demand and track how an expression evaluates free variables and arguments in turn as a DmdType.

Lays out the abstract domain for GHC.Core.Opt.DmdAnal.

Synopsis

Demands

data Boxity Source #

Constructors

Boxed 
Unboxed 

Instances

Instances details
Data Boxity Source # 
Instance details

Defined in Language.Haskell.Syntax.Basic

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Boxity -> c Boxity Source #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Boxity Source #

toConstr :: Boxity -> Constr Source #

dataTypeOf :: Boxity -> DataType Source #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Boxity) Source #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Boxity) Source #

gmapT :: (forall b. Data b => b -> b) -> Boxity -> Boxity Source #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Boxity -> r Source #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Boxity -> r Source #

gmapQ :: (forall d. Data d => d -> u) -> Boxity -> [u] Source #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Boxity -> u Source #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity Source #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity Source #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity Source #

Binary Boxity Source # 
Instance details

Defined in GHC.Types.Basic

Outputable Boxity Source # 
Instance details

Defined in GHC.Types.Basic

Methods

ppr :: Boxity -> SDoc Source #

Eq Boxity Source # 
Instance details

Defined in Language.Haskell.Syntax.Basic

Methods

(==) :: Boxity -> Boxity -> Bool #

(/=) :: Boxity -> Boxity -> Bool #

data Card where Source #

Describes an interval of evaluation cardinalities. See Note [Evaluation cardinalities] See Note [Bit vector representation for Card]

Bundled Patterns

pattern C_00 :: Card

Absent, {0}. Pretty-printed as A.

pattern C_01 :: Card

Used at most once, {0,1}. Pretty-printed as M.

pattern C_0N :: Card

Every possible cardinality; the top element, {0,1,n}. Pretty-printed as L.

pattern C_10 :: Card

Bottom, {}. Pretty-printed as A.

pattern C_11 :: Card

Strict and used once, {1}. Pretty-printed as 1.

pattern C_1N :: Card

Strict and used (possibly) many times, {1,n}. Pretty-printed as S.

Instances

Instances details
Show Card Source # 
Instance details

Defined in GHC.Types.Demand

Binary Card Source # 
Instance details

Defined in GHC.Types.Demand

Outputable Card Source #

See Note [Demand notation] Current syntax was discussed in #19016.

Instance details

Defined in GHC.Types.Demand

Methods

ppr :: Card -> SDoc Source #

Eq Card Source # 
Instance details

Defined in GHC.Types.Demand

Methods

(==) :: Card -> Card -> Bool #

(/=) :: Card -> Card -> Bool #

type CardNonAbs = Card Source #

A subtype of Card for which the upper bound is never 0 (no C_00 or C_10). The only four inhabitants are C_01, C_0N, C_11, C_1N. Membership can be tested with isCardNonAbs. See D and Call for use sites and explanation.

type CardNonOnce = Card Source #

A subtype of Card for which the upper bound is never 1 (no C_01 or C_11). The only four inhabitants are C_00, C_0N, C_10, C_1N. Membership can be tested with isCardNonOnce. See Poly for use sites and explanation.

data Demand Source #

A demand describes

  • How many times a variable is evaluated, via a Cardinality, and
  • How deep its value was evaluated in turn, via a SubDemand.

Examples (using Note [Demand notation]):

  • seq puts demand 1A on its first argument: It evaluates the argument strictly (1), but not any deeper (A).
  • fst puts demand 1P(1L,A) on its argument: It evaluates the argument pair strictly and the first component strictly, but no nested info beyond that (L). Its second argument is not used at all.
  • $ puts demand 1C(1,L) on its first argument: It calls (C) the argument function with one argument, exactly once (1). No info on how the result of that call is evaluated (L).
  • maybe puts demand MC(M,L) on its second argument: It evaluates the argument function at most once ((M)aybe) and calls it once when it is evaluated.
  • fst p + fst p puts demand SP(SL,A) on p: It's 1P(1L,A) multiplied by two, so we get S (used at least once, possibly multiple times).

This data type is quite similar to Scaled SubDemand, but it's scaled by Card, which is an interval on Multiplicity, the upper bound of which could be used to infer uniqueness types. Also we treat AbsDmd and BotDmd specially, as the concept of a SubDemand doesn't apply when there isn't any evaluation at all. If you don't care, simply use (:*).

Constructors

BotDmd

A bottoming demand, produced by a diverging function (C_10), hence there is no SubDemand that describes how it was evaluated.

AbsDmd

An absent demand: Evaluated exactly 0 times (C_00), hence there is no SubDemand that describes how it was evaluated.

Bundled Patterns

pattern (:*) :: HasDebugCallStack => Card -> SubDemand -> Demand

c :* sd is a demand that says "evaluated c times, and any trace in which it is evaluated will evaluate at least as deep as sd".

Matching on this pattern synonym is a complete match. If the matched demand was AbsDmd, it will match as C_00 :* seqSubDmd. If the matched demand was BotDmd, it will match as C_10 :* botSubDmd. The builder of this pattern synonym simply discards the SubDemand if the Card was absent and returns AbsDmd or BotDmd instead. It will assert that the discarded sub-demand was seqSubDmd and botSubDmd, respectively.

Call sites should consider whether they really want to look at the SubDemand of an absent demand and match on AbsDmd and/or BotDmd otherwise. Really, any other SubDemand would be allowed and might work better, depending on context.

Instances

Instances details
Binary Demand Source # 
Instance details

Defined in GHC.Types.Demand

Outputable Demand Source #

See Note [Demand notation]

Instance details

Defined in GHC.Types.Demand

Methods

ppr :: Demand -> SDoc Source #

Eq Demand Source # 
Instance details

Defined in GHC.Types.Demand

Methods

(==) :: Demand -> Demand -> Bool #

(/=) :: Demand -> Demand -> Bool #

data SubDemand Source #

A sub-demand describes an evaluation context (in the sense of an operational semantics), e.g. how deep the denoted thing is going to be evaluated. See Demand for examples.

See Note [SubDemand denotes at least one evaluation] for a more detailed description of what a sub-demand means.

See Note [Demand notation] for the extensively used short-hand notation. See also Note [Why Boxity in SubDemand and not in Demand?].

Constructors

Poly !Boxity !CardNonOnce

Polymorphic demand, the denoted thing is evaluated arbitrarily deep, with the specified cardinality at every level. The Boxity applies only to the outer evaluation context as well as all inner evaluation context. See Note [Boxity in Poly] for why we want it to carry Boxity. Expands to Call via viewCall and to Prod via viewProd.

Poly b n is semantically equivalent to Prod b [n :* Poly b n, ...] or Call n (Poly Boxed n)@. viewCall and viewProd do these rewrites.

In Note [Demand notation]: L === P(L,L,...) and L === C(L), B === P(B,B,...) and B === C(B), !A === !P(A,A,...) and !A === C(A), and so on.

We'll only see Poly with C_10 (B), C_00 (A), C_0N (L) and sometimes C_1N (S) through plusSubDmd, never C_01 (M) or C_11 (1) (grep the source code). Hence CardNonOnce, which is closed under lub and plus.

Why doesn't this constructor simply carry a Demand instead of its fields? See Note [Call SubDemand vs. evaluation Demand].

Prod !Boxity ![Demand]

Prod b ds describes the evaluation context of a case scrutinisation on an expression of product type, where the product components are evaluated according to ds. The Boxity b says whether or not the box of the product was used.

Instances

Instances details
Binary SubDemand Source # 
Instance details

Defined in GHC.Types.Demand

Outputable SubDemand Source #

See Note [Demand notation]

Instance details

Defined in GHC.Types.Demand

Methods

ppr :: SubDemand -> SDoc Source #

Eq SubDemand Source #

We have to respect Poly rewrites through viewCall and viewProd.

Instance details

Defined in GHC.Types.Demand

mkProd :: Boxity -> [Demand] -> SubDemand Source #

A smart constructor for Prod, applying rewrite rules along the semantic equality Prod b [n :* Poly Boxed n, ...] === Poly b n, simplifying to Poly SubDemands when possible. Examples:

  • Rewrites P(L,L) (e.g., arguments Boxed, [L,L]) to L
  • Rewrites !P(L!L,L!L) (e.g., arguments Unboxed, [L!L,L!L]) to !L
  • Does not rewrite P(1L), P(L!L), !P(L) or P(L,A)

viewProd :: Arity -> SubDemand -> Maybe (Boxity, [Demand]) Source #

viewProd n sd interprets sd as a Prod of arity n, expanding Poly demands as necessary.

Algebra

Least upper bound

lubCard :: Card -> Card -> Card Source #

Denotes on Card.

lubDmd :: Demand -> Demand -> Demand Source #

Denotes on Demand.

Plus

plusCard :: Card -> Card -> Card Source #

Denotes + on lower and upper bounds of Card.

plusDmd :: Demand -> Demand -> Demand Source #

Denotes + on Demand.

Multiply

multCard :: Card -> Card -> Card Source #

Denotes * on lower and upper bounds of Card.

Predicates on Cardinalities and Demands

isAbs :: Card -> Bool Source #

True = upper bound is 0.

isUsedOnce :: Card -> Bool Source #

True = upper bound is 1.

isStrict :: Card -> Bool Source #

True = lower bound is 1.

isUsedOnceDmd :: Demand -> Bool Source #

Is the value used at most once?

isStrUsedDmd :: Demand -> Bool Source #

Not absent and used strictly. See Note [Strict demands]

isStrictDmd :: Demand -> Bool Source #

Contrast with isStrictUsedDmd. See Note [Strict demands]

isTopDmd :: Demand -> Bool Source #

Used to suppress pretty-printing of an uninformative demand

isWeakDmd :: Demand -> Bool Source #

We try to avoid tracking weak free variable demands in strictness signatures for analysis performance reasons. See Note [Lazy and unleashable free variables] in GHC.Core.Opt.DmdAnal.

onlyBoxedArguments :: DmdSig -> Bool Source #

True when the signature indicates all arguments are boxed

Special demands

Demands used in PrimOp signatures

lazyApply1Dmd :: Demand Source #

First argument of catch#: MC(M,L). Evaluates its arg lazily, but then applies it exactly once to one argument.

lazyApply2Dmd :: Demand Source #

Second argument of catch#: MC(M,C(1,L)). Calls its arg lazily, but then applies it exactly once to an additional argument.

strictOnceApply1Dmd :: Demand Source #

First argument of 'GHC.Exts.maskAsyncExceptions#': 1C(1,L). Called exactly once.

strictManyApply1Dmd :: Demand Source #

First argument of 'GHC.Exts.atomically#': SC(S,L). Called at least once, possibly many times.

Other Demand operations

oneifyCard :: Card -> Card Source #

Intersect with [0,1].

oneifyDmd :: Demand -> Demand Source #

Make a Demand evaluated at-most-once.

strictifyDmd :: Demand -> Demand Source #

Make a Demand evaluated at-least-once (e.g. strict).

strictifyDictDmd :: Type -> Demand -> Demand Source #

If the argument is a used non-newtype dictionary, give it strict demand. Also split the product type & demand and recur in order to similarly strictify the argument's contained used non-newtype superclass dictionaries. We use the demand as our recursive measure to guarantee termination.

lazifyDmd :: Demand -> Demand Source #

Make a Demand lazy.

peelCallDmd :: SubDemand -> (Card, SubDemand) Source #

Peels one call level from the sub-demand, and also returns how many times we entered the lambda body.

mkCalledOnceDmd :: SubDemand -> SubDemand Source #

Wraps the SubDemand with a one-shot call demand: d -> C(1,d).

mkCalledOnceDmds :: Arity -> SubDemand -> SubDemand Source #

mkCalledOnceDmds n d returns C(1,C1...C(1,d)) where there are n C1's.

subDemandIfEvaluated :: Demand -> SubDemand Source #

Extract the SubDemand of a Demand. PRECONDITION: The SubDemand must be used in a context where the expression denoted by the Demand is under evaluation.

Extracting one-shot information

argOneShots Source #

Arguments

:: Demand

depending on saturation

-> [OneShotInfo] 

See Note [Computing one-shot info]

argsOneShots :: DmdSig -> Arity -> [[OneShotInfo]] Source #

See Note [Computing one-shot info]

saturatedByOneShots :: Int -> Demand -> Bool Source #

saturatedByOneShots n C(M,C(M,...)) = True = There are at least n nested C(M,..) calls. See Note [Demand on the worker] in GHC.Core.Opt.WorkWrap

Manipulating Boxity of a Demand

unboxDeeplyDmd :: Demand -> Demand Source #

Sets Boxity to Unboxed for the Demand, recursing into Prods. Don't recurse into lazy arguments; see GHC.Core.Opt.DmdAnal Note [No lazy, Unboxed demands in demand signature]

Demand environments

keepAliveDmdEnv :: DmdEnv -> IdSet -> DmdEnv Source #

keepAliveDmdType dt vs makes sure that the Ids in vs have some usage in the returned demand types -- they are not Absent. See Note [Absence analysis for stable unfoldings and RULES] in GHC.Core.Opt.DmdAnal.

Divergence

data Divergence Source #

Divergence characterises whether something surely diverges. Models a subset lattice of the following exhaustive set of divergence results:

n
nontermination (e.g. loops)
i
throws imprecise exception
p
throws precise exceTtion
c
converges (reduces to WHNF).

The different lattice elements correspond to different subsets, indicated by juxtaposition of indicators (e.g. nc definitely doesn't throw an exception, and may or may not reduce to WHNF).

            Dunno (nipc)
                 |
           ExnOrDiv (nip)
                 |
           Diverges (ni)

As you can see, we don't distinguish n and i. See Note [Precise exceptions and strictness analysis] for why p is so special compared to i.

Constructors

Diverges

Definitely throws an imprecise exception or diverges.

ExnOrDiv

Definitely throws a *precise* exception, an imprecise exception or diverges. Never converges, hence isDeadEndDiv! See scenario 1 in Note [Precise exceptions and strictness analysis].

Dunno

Might diverge, throw any kind of exception or converge.

Instances

Instances details
Binary Divergence Source # 
Instance details

Defined in GHC.Types.Demand

Outputable Divergence Source # 
Instance details

Defined in GHC.Types.Demand

Methods

ppr :: Divergence -> SDoc Source #

Eq Divergence Source # 
Instance details

Defined in GHC.Types.Demand

isDeadEndDiv :: Divergence -> Bool Source #

True if the Divergence indicates that evaluation will not return. See Note [Dead ends].

Demand types

data DmdType Source #

Characterises how an expression

  • Evaluates its free variables (dt_env)
  • Evaluates its arguments (dt_args)
  • Diverges on every code path or not (dt_div)

Equality is defined modulo defaultFvDmds in dt_env. See Note [Demand type Equality].

Constructors

DmdType 

Fields

Instances

Instances details
Binary DmdType Source # 
Instance details

Defined in GHC.Types.Demand

Outputable DmdType Source # 
Instance details

Defined in GHC.Types.Demand

Methods

ppr :: DmdType -> SDoc Source #

Eq DmdType Source #

See Note [Demand type Equality].

Instance details

Defined in GHC.Types.Demand

Methods

(==) :: DmdType -> DmdType -> Bool #

(/=) :: DmdType -> DmdType -> Bool #

Algebra

nopDmdType :: DmdType Source #

The demand type of doing nothing (lazy, absent, no Divergence information). Note that it is 'not' the top of the lattice (which would be "may use everything"), so it is (no longer) called topDmdType.

lubDmdType :: DmdType -> DmdType -> DmdType Source #

Compute the least upper bound of two DmdTypes elicited /by the same incoming demand/!

PlusDmdArg

Other operations

deferAfterPreciseException :: DmdType -> DmdType Source #

When e is evaluated after executing an IO action that may throw a precise exception, we act as if there is an additional control flow path that is taken if e throws a precise exception. The demand type of this control flow path * is lazy and absent (topDmd) and boxed in all free variables and arguments * has exnDiv Divergence result See Note [Precise exceptions and strictness analysis]

So we can simply take a variant of nopDmdType, exnDmdType. Why not nopDmdType? Because then the result of e can never be exnDiv! That means failure to drop dead-ends, see #18086.

Demand signatures

newtype DmdSig Source #

The depth of the wrapped DmdType encodes the arity at which it is safe to unleash. Better construct this through mkDmdSigForArity. See Note [Understanding DmdType and DmdSig]

Constructors

DmdSig DmdType 

Instances

Instances details
Binary DmdSig Source # 
Instance details

Defined in GHC.Types.Demand

Outputable DmdSig Source # 
Instance details

Defined in GHC.Types.Demand

Methods

ppr :: DmdSig -> SDoc Source #

Eq DmdSig Source # 
Instance details

Defined in GHC.Types.Demand

Methods

(==) :: DmdSig -> DmdSig -> Bool #

(/=) :: DmdSig -> DmdSig -> Bool #

mkDmdSigForArity :: Arity -> DmdType -> DmdSig Source #

Turns a DmdType computed for the particular Arity into a DmdSig unleashable at that arity. See Note [Understanding DmdType and DmdSig].

isBottomingSig :: DmdSig -> Bool Source #

True if the signature diverges or throws an imprecise exception in a saturated call. NB: In constrast to isDeadEndSig this returns False for exnDiv. See Note [Dead ends] and Note [Precise vs imprecise exceptions].

isDeadEndSig :: DmdSig -> Bool Source #

True if the signature diverges or throws an exception in a saturated call. See Note [Dead ends].

isDeadEndAppSig :: DmdSig -> Int -> Bool Source #

Returns true if an application to n value args would diverge or throw an exception.

If a function having botDiv is applied to a less number of arguments than its syntactic arity, we cannot say for sure that it is going to diverge. Hence this function conservatively returns False in that case. See Note [Dead ends].

Handling arity adjustments

prependArgsDmdSig :: Int -> DmdSig -> DmdSig Source #

Add extra (topDmd) arguments to a strictness signature. In contrast to etaConvertDmdSig, this prepends additional argument demands. This is used by FloatOut.

etaConvertDmdSig :: Arity -> DmdSig -> DmdSig Source #

We are expanding (x y. e) to (x y z. e z) or reducing from the latter to the former (when the Simplifier identifies a new join points, for example). In contrast to prependArgsDmdSig, this appends extra arg demands if necessary. This works by looking at the DmdType (which was produced under a call demand for the old arity) and trying to transfer as many facts as we can to the call demand of new arity. An arity increase (resulting in a stronger incoming demand) can retain much of the info, while an arity decrease (a weakening of the incoming demand) must fall back to a conservative default.

Demand transformers from demand signatures

type DmdTransformer = SubDemand -> DmdType Source #

A demand transformer is a monotone function from an incoming evaluation context (SubDemand) to a DmdType, describing how the denoted thing (i.e. expression, function) uses its arguments and free variables, and whether it diverges.

See Note [Understanding DmdType and DmdSig] and Note [What are demand signatures?].

dmdTransformSig :: DmdSig -> DmdTransformer Source #

Extrapolate a demand signature (DmdSig) into a DmdTransformer.

Given a function's DmdSig and a SubDemand for the evaluation context, return how the function evaluates its free variables and arguments.

dmdTransformDataConSig :: [StrictnessMark] -> DmdTransformer Source #

A special DmdTransformer for data constructors that feeds product demands into the constructor arguments.

dmdTransformDictSelSig :: DmdSig -> DmdTransformer Source #

A special DmdTransformer for dictionary selectors that feeds the demand on the result into the indicated dictionary component (if saturated). See Note [Demand transformer for a dictionary selector].

Trim to a type shape

data TypeShape Source #

Instances

Instances details
Outputable TypeShape Source # 
Instance details

Defined in GHC.Types.Demand

Methods

ppr :: TypeShape -> SDoc Source #

trimBoxity :: Demand -> Demand Source #

Drop all boxity

seqing stuff

Zapping usage information

zapDmdEnvSig :: DmdSig -> DmdSig Source #

Remove the demand environment from the signature.

zapUsedOnceDemand :: Demand -> Demand Source #

Remove all `C_01 :*` info (but not CM sub-demands) from the demand

zapUsedOnceSig :: DmdSig -> DmdSig Source #

Remove all `C_01 :*` info (but not CM sub-demands) from the strictness signature