GHC.Types.Demand

ghc-lib-parser-9.14.1.20251220: The GHC API, decoupled from GHC versions

Safe Haskell | Ignore
Language | GHC2021

GHC.Types.Demand

Contents

- Demands
  - Algebra
    - Least upper bound
    - Greatest lower bound
    - Plus
    - Multiply
  - Predicates on `Card`inalities and `Demand`s
  - Special demands
    - Demands used in PrimOp signatures
  - Other `Demand` operations
  - Extracting one-shot information
  - Manipulating Boxity of a Demand
- Divergence
- Demand environments
- Demand types
  - Algebra
  - Other operations
- Demand signatures
  - Handling arity adjustments
- Demand transformers from demand signatures
- Trim to a type shape
- `seq`ing stuff
- Zapping usage information

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

- data Boxity
  - = Boxed
  - | Unboxed
- data Card where
  - pattern C_00 :: Card
  - pattern C_01 :: Card
  - pattern C_0N :: Card
  - pattern C_10 :: Card
  - pattern C_11 :: Card
  - pattern C_1N :: Card
- type CardNonAbs = Card
- type CardNonOnce = Card
- data Demand where
  - BotDmd
  - AbsDmd
  - pattern (:*) :: HasDebugCallStack => Card -> SubDemand -> Demand
- data SubDemand
  - = Poly !Boxity !CardNonOnce
  - | Prod !Boxity ![Demand]
- mkProd :: Boxity -> [Demand] -> SubDemand
- viewProd :: Arity -> SubDemand -> Maybe (Boxity, [Demand])
- absDmd :: Demand
- topDmd :: Demand
- botDmd :: Demand
- seqDmd :: Demand
- topSubDmd :: SubDemand
- lubCard :: Card -> Card -> Card
- lubDmd :: Demand -> Demand -> Demand
- lubSubDmd :: SubDemand -> SubDemand -> SubDemand
- glbCard :: Card -> Card -> Card
- plusCard :: Card -> Card -> Card
- plusDmd :: Demand -> Demand -> Demand
- plusSubDmd :: SubDemand -> SubDemand -> SubDemand
- multCard :: Card -> Card -> Card
- multDmd :: Card -> Demand -> Demand
- multSubDmd :: Card -> SubDemand -> SubDemand
- isAbs :: Card -> Bool
- isAtMostOnce :: Card -> Bool
- isStrict :: Card -> Bool
- isAbsDmd :: Demand -> Bool
- isAtMostOnceDmd :: Demand -> Bool
- isStrUsedDmd :: Demand -> Bool
- isStrictDmd :: Demand -> Bool
- isTopDmd :: Demand -> Bool
- isWeakDmd :: Demand -> Bool
- onlyBoxedArguments :: DmdSig -> Bool
- evalDmd :: Demand
- lazyApply1Dmd :: Demand
- lazyApply2Dmd :: Demand
- strictOnceApply1Dmd :: Demand
- strictManyApply1Dmd :: Demand
- oneifyCard :: Card -> Card
- oneifyDmd :: Demand -> Demand
- strictifyDmd :: Demand -> Demand
- strictifyDictDmd :: Type -> Demand -> Demand
- lazifyDmd :: Demand -> Demand
- floatifyDmd :: Demand -> Demand
- peelCallDmd :: SubDemand -> (Card, SubDemand)
- peelManyCalls :: Arity -> SubDemand -> (Card, SubDemand)
- mkCalledOnceDmd :: SubDemand -> SubDemand
- mkCalledOnceDmds :: Arity -> SubDemand -> SubDemand
- strictCallArity :: SubDemand -> Arity
- mkWorkerDemand :: Int -> Demand
- subDemandIfEvaluated :: Demand -> SubDemand
- callCards :: SubDemand -> [Card]
- argOneShots :: Demand -> [OneShotInfo]
- argsOneShots :: DmdSig -> Arity -> [[OneShotInfo]]
- saturatedByOneShots :: Int -> Demand -> Bool
- unboxDeeplyDmd :: Demand -> Demand
- data Divergence
  - = Diverges
  - | ExnOrDiv
  - | Dunno
- topDiv :: Divergence
- botDiv :: Divergence
- exnDiv :: Divergence
- lubDivergence :: Divergence -> Divergence -> Divergence
- isDeadEndDiv :: Divergence -> Bool
- data DmdEnv = DE {
  - de_fvs :: !(VarEnv Demand)
  - de_div :: !Divergence
  }
- addVarDmdEnv :: DmdEnv -> Id -> Demand -> DmdEnv
- mkTermDmdEnv :: VarEnv Demand -> DmdEnv
- nopDmdEnv :: DmdEnv
- plusDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv
- plusDmdEnvs :: [DmdEnv] -> DmdEnv
- multDmdEnv :: Card -> DmdEnv -> DmdEnv
- reuseEnv :: DmdEnv -> DmdEnv
- data DmdType = DmdType {
  - dt_env :: !DmdEnv
  - dt_args :: ![Demand]
  }
- dmdTypeDepth :: DmdType -> Arity
- nopDmdType :: DmdType
- botDmdType :: DmdType
- lubDmdType :: DmdType -> DmdType -> DmdType
- plusDmdType :: DmdType -> DmdEnv -> DmdType
- multDmdType :: Card -> DmdType -> DmdType
- discardArgDmds :: DmdType -> DmdEnv
- peelFV :: DmdType -> Var -> (DmdType, Demand)
- findIdDemand :: DmdType -> Var -> Demand
- addDemand :: Demand -> DmdType -> DmdType
- splitDmdTy :: DmdType -> (Demand, DmdType)
- deferAfterPreciseException :: DmdType -> DmdType
- newtype DmdSig = DmdSig DmdType
- mkDmdSigForArity :: Arity -> DmdType -> DmdSig
- mkClosedDmdSig :: [Demand] -> Divergence -> DmdSig
- mkVanillaDmdSig :: Arity -> Divergence -> DmdSig
- splitDmdSig :: DmdSig -> ([Demand], Divergence)
- dmdSigDmdEnv :: DmdSig -> DmdEnv
- hasDemandEnvSig :: DmdSig -> Bool
- nopSig :: DmdSig
- botSig :: DmdSig
- isNopSig :: DmdSig -> Bool
- isBottomingSig :: DmdSig -> Bool
- isDeadEndSig :: DmdSig -> Bool
- isDeadEndAppSig :: DmdSig -> Int -> Bool
- trimBoxityDmdSig :: DmdSig -> DmdSig
- transferArgBoxityDmdSig :: DmdSig -> DmdSig -> DmdSig
- prependArgsDmdSig :: Int -> DmdSig -> DmdSig
- etaConvertDmdSig :: Arity -> DmdSig -> DmdSig
- type DmdTransformer = SubDemand -> DmdType
- dmdTransformSig :: DmdSig -> DmdTransformer
- dmdTransformDataConSig :: [StrictnessMark] -> DmdTransformer
- dmdTransformDictSelSig :: DmdSig -> DmdTransformer
- data TypeShape
  - = TsFun TypeShape
  - | TsProd [TypeShape]
  - | TsUnk
- trimToType :: Demand -> TypeShape -> Demand
- trimBoxity :: Demand -> Demand
- seqDemand :: Demand -> ()
- seqDemandList :: [Demand] -> ()
- seqDmdType :: DmdType -> ()
- seqDmdSig :: DmdSig -> ()
- zapUsageDemand :: Demand -> Demand
- zapDmdEnvSig :: DmdSig -> DmdSig
- zapUsedOnceDemand :: Demand -> Demand
- zapUsedOnceSig :: DmdSig -> DmdSig

# Demands

data Boxity #

Constructors

Boxed |
Unboxed |

#### Instances

Instances details

Data Boxity # |
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 # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Boxity # toConstr :: Boxity -> Constr # dataTypeOf :: Boxity -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Boxity) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Boxity) # gmapT :: (forall b. Data b => b -> b) -> Boxity -> Boxity # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Boxity -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Boxity -> r # gmapQ :: (forall d. Data d => d -> u) -> Boxity -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Boxity -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Boxity -> m Boxity #
Binary Boxity # |
Instance details Defined in GHC.Types.Basic Methods put_ :: WriteBinHandle -> Boxity -> IO () # put :: WriteBinHandle -> Boxity -> IO (Bin Boxity) # get :: ReadBinHandle -> IO Boxity #
Outputable Boxity # |
Instance details Defined in GHC.Types.Basic Methods ppr :: Boxity -> SDoc #
Eq Boxity # |
Instance details Defined in Language.Haskell.Syntax.Basic Methods (==) :: Boxity -> Boxity -> Bool # (/=) :: Boxity -> Boxity -> Bool #

data Card where #

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 # |
Instance details Defined in GHC.Types.Demand Methods showsPrec :: Int -> Card -> ShowS # show :: Card -> String # showList :: [Card] -> ShowS #
Binary Card # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> Card -> IO () # put :: WriteBinHandle -> Card -> IO (Bin Card) # get :: ReadBinHandle -> IO Card #
Outputable Card # | See Note [Demand notation] Current syntax was discussed in #19016.
Instance details Defined in GHC.Types.Demand Methods ppr :: Card -> SDoc #
Eq Card # |
Instance details Defined in GHC.Types.Demand Methods (==) :: Card -> Card -> Bool # (/=) :: Card -> Card -> Bool #

type CardNonAbs = Card #

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 #

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 #

A demand describes

- How many times a variable is evaluated, via a `Card`inality, and
- How deep its value was evaluated in turn, via a `SubDemand`.

See also Note [Demand notation] and Note [Demand examples].

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 # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> Demand -> IO () # put :: WriteBinHandle -> Demand -> IO (Bin Demand) # get :: ReadBinHandle -> IO Demand #
Outputable Demand # | See Note [Demand notation]
Instance details Defined in GHC.Types.Demand Methods ppr :: Demand -> SDoc #
Eq Demand # |
Instance details Defined in GHC.Types.Demand Methods (==) :: Demand -> Demand -> Bool # (/=) :: Demand -> Demand -> Bool #

data SubDemand #

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 # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> SubDemand -> IO () # put :: WriteBinHandle -> SubDemand -> IO (Bin SubDemand) # get :: ReadBinHandle -> IO SubDemand #
Outputable SubDemand # | See Note [Demand notation]
Instance details Defined in GHC.Types.Demand Methods ppr :: SubDemand -> SDoc #
Eq SubDemand # | We have to respect Poly rewrites through `viewCall` and `viewProd`.
Instance details Defined in GHC.Types.Demand Methods (==) :: SubDemand -> SubDemand -> Bool # (/=) :: SubDemand -> SubDemand -> Bool #

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

A smart constructor for `Prod`, applying rewrite rules along the semantic equality `Prod b [n :* Poly Boxed n, ...] === Poly b n`, simplifying to `Poly` `SubDemand`s 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]) #

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

## Algebra

absDmd :: Demand #

topDmd :: Demand #

botDmd :: Demand #

seqDmd :: Demand #

topSubDmd :: SubDemand #

### Least upper bound

lubCard :: Card -> Card -> Card #

Denotes `∪` on `Card`.

lubDmd :: Demand -> Demand -> Demand #

Denotes `∪` on `Demand`.

lubSubDmd :: SubDemand -> SubDemand -> SubDemand #

### Greatest lower bound

glbCard :: Card -> Card -> Card #

Denotes `∩` on `Card`.

### Plus

plusCard :: Card -> Card -> Card #

Denotes `+` on lower and upper bounds of `Card`.

plusDmd :: Demand -> Demand -> Demand #

Denotes `+` on `Demand`.

plusSubDmd :: SubDemand -> SubDemand -> SubDemand #

### Multiply

multCard :: Card -> Card -> Card #

Denotes `*` on lower and upper bounds of `Card`.

multDmd :: Card -> Demand -> Demand #

multSubDmd :: Card -> SubDemand -> SubDemand #

## Predicates on `Card`inalities and `Demand`s

isAbs :: Card -> Bool #

True = upper bound is 0.

isAtMostOnce :: Card -> Bool #

True = upper bound is 1.

isStrict :: Card -> Bool #

True = lower bound is 1.

isAbsDmd :: Demand -> Bool #

isAtMostOnceDmd :: Demand -> Bool #

Is the value used at most once?

isStrUsedDmd :: Demand -> Bool #

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

isStrictDmd :: Demand -> Bool #

Contrast with isStrictUsedDmd. See Note [Strict demands]

isTopDmd :: Demand -> Bool #

Used to suppress pretty-printing of an uninformative demand

isWeakDmd :: Demand -> Bool #

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 #

True when the signature indicates all arguments are boxed

## Special demands

evalDmd :: Demand #

### Demands used in PrimOp signatures

lazyApply1Dmd :: Demand #

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

lazyApply2Dmd :: Demand #

Second argument of catch#: `MC(1,C(1,L))`. Evaluates its arg lazily, but then applies it exactly once to two arguments.

strictOnceApply1Dmd :: Demand #

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

strictManyApply1Dmd :: Demand #

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

## Other `Demand` operations

oneifyCard :: Card -> Card #

Intersect with [0,1].

oneifyDmd :: Demand -> Demand #

Make a `Demand` evaluated at-most-once.

strictifyDmd :: Demand -> Demand #

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

strictifyDictDmd :: Type -> Demand -> Demand #

If the argument is a guaranteed-terminating type (i.e. a non-newtype dictionary) give it strict demand. This is sound because terminating types can't be bottom: See GHC.Core Note [NON-BOTTOM-DICTS invariant] 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 #

Make a `Demand` lazy.

floatifyDmd :: Demand -> Demand #

Adjust the demand on a binding that may float outwards See Note [Floatifying demand info when floating]

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

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

peelManyCalls :: Arity -> SubDemand -> (Card, SubDemand) #

mkCalledOnceDmd :: SubDemand -> SubDemand #

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

mkCalledOnceDmds :: Arity -> SubDemand -> SubDemand #

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

strictCallArity :: SubDemand -> Arity #

mkWorkerDemand :: Int -> Demand #

subDemandIfEvaluated :: Demand -> SubDemand #

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

callCards :: SubDemand -> [Card] #

See Note [Computing one-shot info]

argOneShots #

Arguments

:: Demand | depending on saturation
-> [OneShotInfo] |

See Note [Computing one-shot info]

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

See Note [Computing one-shot info]

saturatedByOneShots :: Int -> Demand -> Bool #

`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 #

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

# Divergence

data Divergence #

`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 exception
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 # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> Divergence -> IO () # put :: WriteBinHandle -> Divergence -> IO (Bin Divergence) # get :: ReadBinHandle -> IO Divergence #
Outputable Divergence # |
Instance details Defined in GHC.Types.Demand Methods ppr :: Divergence -> SDoc #
Eq Divergence # |
Instance details Defined in GHC.Types.Demand Methods (==) :: Divergence -> Divergence -> Bool # (/=) :: Divergence -> Divergence -> Bool #

topDiv :: Divergence #

botDiv :: Divergence #

exnDiv :: Divergence #

lubDivergence :: Divergence -> Divergence -> Divergence #

isDeadEndDiv :: Divergence -> Bool #

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

# Demand environments

data DmdEnv #

Captures the result of an evaluation of an expression, by

- Listing how the free variables of that expression have been evaluated (`de_fvs`)
- Saying whether or not evaluation would surely diverge (`de_div`)

See Note [Demand env Equality].

Constructors

DE |
Fields de_fvs :: !(VarEnv Demand) de_div :: !Divergence

#### Instances

Instances details

Binary DmdEnv # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> DmdEnv -> IO () # put :: WriteBinHandle -> DmdEnv -> IO (Bin DmdEnv) # get :: ReadBinHandle -> IO DmdEnv #
Outputable DmdEnv # |
Instance details Defined in GHC.Types.Demand Methods ppr :: DmdEnv -> SDoc #
Eq DmdEnv # |
Instance details Defined in GHC.Types.Demand Methods (==) :: DmdEnv -> DmdEnv -> Bool # (/=) :: DmdEnv -> DmdEnv -> Bool #

addVarDmdEnv :: DmdEnv -> Id -> Demand -> DmdEnv #

mkTermDmdEnv :: VarEnv Demand -> DmdEnv #

Build a potentially terminating `DmdEnv` from a finite map that says what has been evaluated so far

nopDmdEnv :: DmdEnv #

plusDmdEnv :: DmdEnv -> DmdEnv -> DmdEnv #

plusDmdEnvs :: [DmdEnv] -> DmdEnv #

`DmdEnv` is a monoid via `plusDmdEnv` and `nopDmdEnv`; this is its `msum`

multDmdEnv :: Card -> DmdEnv -> DmdEnv #

reuseEnv :: DmdEnv -> DmdEnv #

# Demand types

data DmdType #

Characterises how an expression

- Evaluates its free variables (`dt_env`) including divergence info
- Evaluates its arguments (`dt_args`)

Constructors

DmdType |
Fields dt_env :: !DmdEnv Demands on free variables. See Note [Demand type Divergence] dt_args :: ![Demand] Demand on arguments

#### Instances

Instances details

Binary DmdType # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> DmdType -> IO () # put :: WriteBinHandle -> DmdType -> IO (Bin DmdType) # get :: ReadBinHandle -> IO DmdType #
Outputable DmdType # |
Instance details Defined in GHC.Types.Demand Methods ppr :: DmdType -> SDoc #
Eq DmdType # | See Note [Demand env Equality].
Instance details Defined in GHC.Types.Demand Methods (==) :: DmdType -> DmdType -> Bool # (/=) :: DmdType -> DmdType -> Bool #

dmdTypeDepth :: DmdType -> Arity #

## Algebra

nopDmdType :: DmdType #

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.

botDmdType :: DmdType #

lubDmdType :: DmdType -> DmdType -> DmdType #

Compute the least upper bound of two `DmdType`s elicited /by the same incoming demand/!

plusDmdType :: DmdType -> DmdEnv -> DmdType #

multDmdType :: Card -> DmdType -> DmdType #

discardArgDmds :: DmdType -> DmdEnv #

## Other operations

peelFV :: DmdType -> Var -> (DmdType, Demand) #

findIdDemand :: DmdType -> Var -> Demand #

addDemand :: Demand -> DmdType -> DmdType #

splitDmdTy :: DmdType -> (Demand, DmdType) #

deferAfterPreciseException :: DmdType -> DmdType #

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 #

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 # |
Instance details Defined in GHC.Types.Demand Methods put_ :: WriteBinHandle -> DmdSig -> IO () # put :: WriteBinHandle -> DmdSig -> IO (Bin DmdSig) # get :: ReadBinHandle -> IO DmdSig #
Outputable DmdSig # |
Instance details Defined in GHC.Types.Demand Methods ppr :: DmdSig -> SDoc #
Eq DmdSig # |
Instance details Defined in GHC.Types.Demand Methods (==) :: DmdSig -> DmdSig -> Bool # (/=) :: DmdSig -> DmdSig -> Bool #

mkDmdSigForArity :: Arity -> DmdType -> DmdSig #

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

mkClosedDmdSig :: [Demand] -> Divergence -> DmdSig #

mkVanillaDmdSig :: Arity -> Divergence -> DmdSig #

splitDmdSig :: DmdSig -> ([Demand], Divergence) #

dmdSigDmdEnv :: DmdSig -> DmdEnv #

hasDemandEnvSig :: DmdSig -> Bool #

nopSig :: DmdSig #

botSig :: DmdSig #

isNopSig :: DmdSig -> Bool #

isBottomingSig :: DmdSig -> Bool #

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 #

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

isDeadEndAppSig :: DmdSig -> Int -> Bool #

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].

trimBoxityDmdSig :: DmdSig -> DmdSig #

transferArgBoxityDmdSig :: DmdSig -> DmdSig -> DmdSig #

## Handling arity adjustments

prependArgsDmdSig :: Int -> DmdSig -> DmdSig #

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 #

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 #

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 [DmdSig: demand signatures, and demand-sig arity]

dmdTransformSig :: DmdSig -> DmdTransformer #

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 #

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

dmdTransformDictSelSig :: DmdSig -> DmdTransformer #

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 #

Constructors

TsFun TypeShape |
TsProd [TypeShape] |
TsUnk |

#### Instances

Instances details

Outputable TypeShape # |
Instance details Defined in GHC.Types.Demand Methods ppr :: TypeShape -> SDoc #

trimToType :: Demand -> TypeShape -> Demand #

trimBoxity :: Demand -> Demand #

Drop all boxity

# `seq`ing stuff

seqDemand :: Demand -> () #

seqDemandList :: [Demand] -> () #

seqDmdType :: DmdType -> () #

seqDmdSig :: DmdSig -> () #

# Zapping usage information

zapUsageDemand :: Demand -> Demand #

zapDmdEnvSig :: DmdSig -> DmdSig #

Remove the demand environment from the signature.

zapUsedOnceDemand :: Demand -> Demand #

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

zapUsedOnceSig :: DmdSig -> DmdSig #

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