CoreUtils

ghc-8.4.4: The GHC API

Safe Haskell | None
Language | Haskell2010

CoreUtils

Contents

- Constructing expressions
- Taking expressions apart
- Properties of expressions
- Equality
- Eta reduction
- Manipulating data constructors and types
- Working with ticks
- StaticPtr
- Join points

Description

Commonly useful utilites for manipulating the Core language

Synopsis

- mkCast :: CoreExpr -> Coercion -> CoreExpr
- mkTick :: Tickish Id -> CoreExpr -> CoreExpr
- mkTicks :: [Tickish Id] -> CoreExpr -> CoreExpr
- mkTickNoHNF :: Tickish Id -> CoreExpr -> CoreExpr
- tickHNFArgs :: Tickish Id -> CoreExpr -> CoreExpr
- bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr
- needsCaseBinding :: Type -> CoreExpr -> Bool
- mkAltExpr :: AltCon -> [CoreBndr] -> [Type] -> CoreExpr
- findDefault :: [(AltCon, [a], b)] -> ([(AltCon, [a], b)], Maybe b)
- addDefault :: [(AltCon, [a], b)] -> Maybe b -> [(AltCon, [a], b)]
- findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b)
- isDefaultAlt :: (AltCon, a, b) -> Bool
- mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)]
- trimConArgs :: AltCon -> [CoreArg] -> [CoreArg]
- filterAlts :: TyCon -> [Type] -> [AltCon] -> [(AltCon, [Var], a)] -> ([AltCon], [(AltCon, [Var], a)])
- combineIdenticalAlts :: [AltCon] -> [CoreAlt] -> (Bool, [AltCon], [CoreAlt])
- refineDefaultAlt :: [Unique] -> TyCon -> [Type] -> [AltCon] -> [CoreAlt] -> (Bool, [CoreAlt])
- exprType :: CoreExpr -> Type
- coreAltType :: CoreAlt -> Type
- coreAltsType :: [CoreAlt] -> Type
- isExprLevPoly :: CoreExpr -> Bool
- exprIsDupable :: DynFlags -> CoreExpr -> Bool
- exprIsTrivial :: CoreExpr -> Bool
- getIdFromTrivialExpr :: CoreExpr -> Id
- exprIsBottom :: CoreExpr -> Bool
- getIdFromTrivialExpr_maybe :: CoreExpr -> Maybe Id
- exprIsCheap :: CoreExpr -> Bool
- exprIsExpandable :: CoreExpr -> Bool
- exprIsCheapX :: CheapAppFun -> CoreExpr -> Bool
- type CheapAppFun = Id -> Arity -> Bool
- exprIsHNF :: CoreExpr -> Bool
- exprOkForSpeculation :: CoreExpr -> Bool
- exprOkForSideEffects :: CoreExpr -> Bool
- exprIsWorkFree :: CoreExpr -> Bool
- exprIsBig :: Expr b -> Bool
- exprIsConLike :: CoreExpr -> Bool
- rhsIsStatic :: Platform -> (Name -> Bool) -> (Integer -> CoreExpr) -> CoreExpr -> Bool
- isCheapApp :: CheapAppFun
- isExpandableApp :: CheapAppFun
- exprIsTickedString :: CoreExpr -> Bool
- exprIsTickedString_maybe :: CoreExpr -> Maybe ByteString
- exprIsTopLevelBindable :: CoreExpr -> Type -> Bool
- altsAreExhaustive :: [Alt b] -> Bool
- cheapEqExpr :: Expr b -> Expr b -> Bool
- cheapEqExpr' :: (Tickish Id -> Bool) -> Expr b -> Expr b -> Bool
- eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool
- diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc]
- diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> ([SDoc], RnEnv2)
- tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr
- exprToType :: CoreExpr -> Type
- exprToCoercion_maybe :: CoreExpr -> Maybe Coercion
- applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type
- applyTypeToArg :: Type -> CoreExpr -> Type
- dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
- dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
- isEmptyTy :: Type -> Bool
- stripTicksTop :: (Tickish Id -> Bool) -> Expr b -> ([Tickish Id], Expr b)
- stripTicksTopE :: (Tickish Id -> Bool) -> Expr b -> Expr b
- stripTicksTopT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]
- stripTicksE :: (Tickish Id -> Bool) -> Expr b -> Expr b
- stripTicksT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]
- collectMakeStaticArgs :: CoreExpr -> Maybe (CoreExpr, Type, CoreExpr, CoreExpr)
- isJoinBind :: CoreBind -> Bool

# Constructing expressions

mkCast :: CoreExpr -> Coercion -> CoreExpr #

Wrap the given expression in the coercion safely, dropping identity coercions and coalescing nested coercions

mkTick :: Tickish Id -> CoreExpr -> CoreExpr #

Wraps the given expression in the source annotation, dropping the annotation if possible.

mkTicks :: [Tickish Id] -> CoreExpr -> CoreExpr #

mkTickNoHNF :: Tickish Id -> CoreExpr -> CoreExpr #

tickHNFArgs :: Tickish Id -> CoreExpr -> CoreExpr #

bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr #

`bindNonRec x r b` produces either:

    let x = r in b

or:

    case r of x { _DEFAULT_ -> b }

depending on whether we have to use a `case` or `let` binding for the expression (see `needsCaseBinding`). It's used by the desugarer to avoid building bindings that give Core Lint a heart attack, although actually the simplifier deals with them perfectly well. See also `mkCoreLet`

needsCaseBinding :: Type -> CoreExpr -> Bool #

Tests whether we have to use a `case` rather than `let` binding for this expression as per the invariants of `CoreExpr`: see CoreSyn

mkAltExpr #

Arguments

:: AltCon | Case alternative constructor
-> [CoreBndr] | Things bound by the pattern match
-> [Type] | The type arguments to the case alternative
-> CoreExpr |

This guy constructs the value that the scrutinee must have given that you are in one particular branch of a case

# Taking expressions apart

findDefault :: [(AltCon, [a], b)] -> ([(AltCon, [a], b)], Maybe b) #

Extract the default case alternative

addDefault :: [(AltCon, [a], b)] -> Maybe b -> [(AltCon, [a], b)] #

findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b) #

Find the case alternative corresponding to a particular constructor: panics if no such constructor exists

isDefaultAlt :: (AltCon, a, b) -> Bool #

mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)] #

Merge alternatives preserving order; alternatives in the first argument shadow ones in the second

trimConArgs :: AltCon -> [CoreArg] -> [CoreArg] #

Given:

    case (C a b x y) of
           C b x y -> ...

We want to drop the leading type argument of the scrutinee leaving the arguments to match against the pattern

filterAlts #

Arguments

:: TyCon | Type constructor of scrutinee's type (used to prune possibilities)
-> [Type] | And its type arguments
-> [AltCon] | `imposs_cons`: constructors known to be impossible due to the form of the scrutinee
-> [(AltCon, [Var], a)] | Alternatives
-> ([AltCon], [(AltCon, [Var], a)]) |

combineIdenticalAlts :: [AltCon] -> [CoreAlt] -> (Bool, [AltCon], [CoreAlt]) #

refineDefaultAlt :: [Unique] -> TyCon -> [Type] -> [AltCon] -> [CoreAlt] -> (Bool, [CoreAlt]) #

# Properties of expressions

exprType :: CoreExpr -> Type #

Recover the type of a well-typed Core expression. Fails when applied to the actual `Type` expression as it cannot really be said to have a type

coreAltType :: CoreAlt -> Type #

Returns the type of the alternatives right hand side

coreAltsType :: [CoreAlt] -> Type #

Returns the type of the first alternative, which should be the same as for all alternatives

isExprLevPoly :: CoreExpr -> Bool #

Is this expression levity polymorphic? This should be the same as saying (isKindLevPoly . typeKind . exprType) but much faster.

exprIsDupable :: DynFlags -> CoreExpr -> Bool #

exprIsTrivial :: CoreExpr -> Bool #

getIdFromTrivialExpr :: CoreExpr -> Id #

exprIsBottom :: CoreExpr -> Bool #

getIdFromTrivialExpr_maybe :: CoreExpr -> Maybe Id #

exprIsCheap :: CoreExpr -> Bool #

exprIsExpandable :: CoreExpr -> Bool #

exprIsCheapX :: CheapAppFun -> CoreExpr -> Bool #

type CheapAppFun = Id -> Arity -> Bool #

exprIsHNF :: CoreExpr -> Bool #

exprIsHNF returns true for expressions that are certainly already evaluated to head normal form. This is used to decide whether it's ok to change:

    case x of _ -> e

into:

    e

and to decide whether it's safe to discard a `seq`.

So, it does not treat variables as evaluated, unless they say they are. However, it does treat partial applications and constructor applications as values, even if their arguments are non-trivial, provided the argument type is lifted. For example, both of these are values:

    (:) (f x) (map f xs)
    map (...redex...)

because `seq` on such things completes immediately.

For unlifted argument types, we have to be careful:

    C (f x :: Int#)

Suppose `f x` diverges; then `C (f x)` is not a value. However this can't happen: see CoreSyn. This invariant states that arguments of unboxed type must be ok-for-speculation (or trivial).

exprOkForSpeculation :: CoreExpr -> Bool #

`exprOkForSpeculation` returns True of an expression that is:

- Safe to evaluate even if normal order eval might not evaluate the expression at all, or
- Safe not to evaluate even if normal order would do so

It is usually called on arguments of unlifted type, but not always In particular, Simplify.rebuildCase calls it on lifted types when a 'case' is a plain `seq`. See the example in Note [exprOkForSpeculation: case expressions] below

Precisely, it returns `True` iff: a) The expression guarantees to terminate, b) soon, c) without causing a write side effect (e.g. writing a mutable variable) d) without throwing a Haskell exception e) without risking an unchecked runtime exception (array out of bounds, divide by zero)

For `exprOkForSideEffects` the list is the same, but omitting (e).

Note that exprIsHNF implies exprOkForSpeculation exprOkForSpeculation implies exprOkForSideEffects

See Note [PrimOp can_fail and has_side_effects] in PrimOp and Note [Transformations affected by can_fail and has_side_effects]

As an example of the considerations in this test, consider:

    let x = case y# +# 1# of { r# -> I# r# }
    in E

being translated to:

    case y# +# 1# of { r# ->
       let x = I# r#
       in E
    }

We can only do this if the `y + 1` is ok for speculation: it has no side effects, and can't diverge or raise an exception.

exprOkForSideEffects :: CoreExpr -> Bool #

`exprOkForSpeculation` returns True of an expression that is:

- Safe to evaluate even if normal order eval might not evaluate the expression at all, or
- Safe not to evaluate even if normal order would do so

It is usually called on arguments of unlifted type, but not always In particular, Simplify.rebuildCase calls it on lifted types when a 'case' is a plain `seq`. See the example in Note [exprOkForSpeculation: case expressions] below

Precisely, it returns `True` iff: a) The expression guarantees to terminate, b) soon, c) without causing a write side effect (e.g. writing a mutable variable) d) without throwing a Haskell exception e) without risking an unchecked runtime exception (array out of bounds, divide by zero)

For `exprOkForSideEffects` the list is the same, but omitting (e).

Note that exprIsHNF implies exprOkForSpeculation exprOkForSpeculation implies exprOkForSideEffects

See Note [PrimOp can_fail and has_side_effects] in PrimOp and Note [Transformations affected by can_fail and has_side_effects]

As an example of the considerations in this test, consider:

    let x = case y# +# 1# of { r# -> I# r# }
    in E

being translated to:

    case y# +# 1# of { r# ->
       let x = I# r#
       in E
    }

We can only do this if the `y + 1` is ok for speculation: it has no side effects, and can't diverge or raise an exception.

exprIsWorkFree :: CoreExpr -> Bool #

exprIsBig :: Expr b -> Bool #

Returns `True` of expressions that are too big to be compared by `cheapEqExpr`

exprIsConLike :: CoreExpr -> Bool #

Similar to `exprIsHNF` but includes CONLIKE functions as well as data constructors. Conlike arguments are considered interesting by the inliner.

rhsIsStatic :: Platform -> (Name -> Bool) -> (Integer -> CoreExpr) -> CoreExpr -> Bool #

This function is called only on *top-level* right-hand sides. Returns `True` if the RHS can be allocated statically in the output, with no thunks involved at all.

isCheapApp :: CheapAppFun #

isExpandableApp :: CheapAppFun #

exprIsTickedString :: CoreExpr -> Bool #

Check if the expression is zero or more Ticks wrapped around a literal string.

exprIsTickedString_maybe :: CoreExpr -> Maybe ByteString #

Extract a literal string from an expression that is zero or more Ticks wrapped around a literal string. Returns Nothing if the expression has a different shape. Used to "look through" Ticks in places that need to handle literal strings.

exprIsTopLevelBindable :: CoreExpr -> Type -> Bool #

Can we bind this `CoreExpr` at the top level?

altsAreExhaustive :: [Alt b] -> Bool #

# Equality

cheapEqExpr :: Expr b -> Expr b -> Bool #

A cheap equality test which bales out fast! If it returns `True` the arguments are definitely equal, otherwise, they may or may not be equal.

See also `exprIsBig`

cheapEqExpr' :: (Tickish Id -> Bool) -> Expr b -> Expr b -> Bool #

Cheap expression equality test, can ignore ticks by type.

eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool #

diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc] #

Finds differences between core expressions, modulo alpha and renaming. Setting `top` means that the `IdInfo` of bindings will be checked for differences as well.

diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> ([SDoc], RnEnv2) #

Finds differences between core bindings, see `diffExpr`.

The main problem here is that while we expect the binds to have the same order in both lists, this is not guaranteed. To do this properly we'd either have to do some sort of unification or check all possible mappings, which would be seriously expensive. So instead we simply match single bindings as far as we can. This leaves us just with mutually recursive and/or mismatching bindings, which we then speculatively match by ordering them. It's by no means perfect, but gets the job done well enough.

# Eta reduction

tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr #

# Manipulating data constructors and types

exprToType :: CoreExpr -> Type #

If the expression is a `Type`, converts. Otherwise, panics. NB: This does not convert `Coercion` to `CoercionTy`.

exprToCoercion_maybe :: CoreExpr -> Maybe Coercion #

If the expression is a `Coercion`, converts.

applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type #

A more efficient version of `applyTypeToArg` when we have several arguments. The first argument is just for debugging, and gives some context

applyTypeToArg :: Type -> CoreExpr -> Type #

Determines the type resulting from applying an expression with given type to a given argument expression

dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id]) #

dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id]) #

isEmptyTy :: Type -> Bool #

True if the type has no non-bottom elements, e.g. when it is an empty datatype, or a GADT with non-satisfiable type parameters, e.g. Int :~: Bool. See Note [Bottoming expressions]

See Note [No alternatives lint check] for another use of this function.

# Working with ticks

stripTicksTop :: (Tickish Id -> Bool) -> Expr b -> ([Tickish Id], Expr b) #

Strip ticks satisfying a predicate from top of an expression

stripTicksTopE :: (Tickish Id -> Bool) -> Expr b -> Expr b #

Strip ticks satisfying a predicate from top of an expression, returning the remaining expression

stripTicksTopT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id] #

Strip ticks satisfying a predicate from top of an expression, returning the ticks

stripTicksE :: (Tickish Id -> Bool) -> Expr b -> Expr b #

Completely strip ticks satisfying a predicate from an expression. Note this is O(n) in the size of the expression!

stripTicksT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id] #

# StaticPtr

collectMakeStaticArgs :: CoreExpr -> Maybe (CoreExpr, Type, CoreExpr, CoreExpr) #

`collectMakeStaticArgs (makeStatic t srcLoc e)` yields `Just (makeStatic, t, srcLoc, e)`.

Returns `Nothing` for every other expression.

# Join points

isJoinBind :: CoreBind -> Bool #

Does this binding bind a join point (or a recursive group of join points)?