\section[Id]{@Ids@: Value and constructor identifiers}
\begin{code}
+-- |
+-- #name_types#
+-- GHC uses several kinds of name internally:
+--
+-- * 'OccName.OccName': see "OccName#name_types"
+--
+-- * 'RdrName.RdrName': see "RdrName#name_types"
+--
+-- * 'Name.Name': see "Name#name_types"
+--
+-- * 'Id.Id' represents names that not only have a 'Name.Name' but also a 'TypeRep.Type' and some additional
+-- details (a 'IdInfo.IdInfo' and one of 'Var.LocalIdDetails' or 'IdInfo.GlobalIdDetails') that
+-- are added, modified and inspected by various compiler passes. These 'Var.Var' names may either
+-- be global or local, see "Var#globalvslocal"
+--
+-- * 'Var.Var': see "Var#name_types"
module Id (
-- * The main types
Id, DictId,
-- ** Simple construction
mkGlobalId, mkVanillaGlobal, mkVanillaGlobalWithInfo,
- mkLocalId, mkLocalIdWithInfo,
+ mkLocalId, mkLocalIdWithInfo, mkExportedLocalId,
mkSysLocal, mkSysLocalM, mkUserLocal, mkUserLocalM,
+ mkTemplateLocals, mkTemplateLocalsNum, mkTemplateLocal,
+ mkWorkerId,
-- ** Taking an Id apart
- idName, idType, idUnique, idInfo,
- isId, globalIdDetails, idPrimRep,
+ idName, idType, idUnique, idInfo, idDetails,
+ isId, idPrimRep,
recordSelectorFieldLabel,
-- ** Modifying an Id
- setIdName, setIdUnique, Id.setIdType, setIdExported, setIdNotExported,
- globaliseId, setIdInfo, lazySetIdInfo, modifyIdInfo, maybeModifyIdInfo,
+ setIdName, setIdUnique, Id.setIdType,
+ setIdExported, setIdNotExported,
+ globaliseId, localiseId,
+ setIdInfo, lazySetIdInfo, modifyIdInfo, maybeModifyIdInfo,
zapLamIdInfo, zapDemandIdInfo, zapFragileIdInfo, transferPolyIdInfo,
+
-- ** Predicates on Ids
isImplicitId, isDeadBinder, isDictId, isStrictId,
isPrimOpId, isPrimOpId_maybe,
isFCallId, isFCallId_maybe,
isDataConWorkId, isDataConWorkId_maybe, isDataConId_maybe, idDataCon,
- isBottomingId, idIsFrom,
+ isConLikeId, isBottomingId, idIsFrom,
isTickBoxOp, isTickBoxOp_maybe,
hasNoBinding,
-- ** Inline pragma stuff
- idInlinePragma, setInlinePragma, modifyInlinePragma,
-
+ idInlinePragma, setInlinePragma, modifyInlinePragma,
+ idInlineActivation, setInlineActivation, idRuleMatchInfo,
- -- ** One shot lambda stuff
+ -- ** One-shot lambdas
isOneShotBndr, isOneShotLambda, isStateHackType,
setOneShotLambda, clearOneShotLambda,
- -- ** IdInfo stuff
- setIdUnfolding,
- setIdArity,
- setIdNewDemandInfo,
- setIdNewStrictness, zapIdNewStrictness,
- setIdWorkerInfo,
- setIdSpecialisation,
- setIdCafInfo,
- setIdOccInfo,
-
- -- ** Id demand information
-#ifdef OLD_STRICTNESS
- idDemandInfo,
- idStrictness,
- idCprInfo,
- setIdStrictness,
- setIdDemandInfo,
- setIdCprInfo,
-#endif
-
+ -- ** Reading 'IdInfo' fields
idArity,
idNewDemandInfo, idNewDemandInfo_maybe,
idNewStrictness, idNewStrictness_maybe,
idOccInfo,
#ifdef OLD_STRICTNESS
- newStrictnessFromOld -- Temporary
+ idDemandInfo,
+ idStrictness,
+ idCprInfo,
#endif
+ -- ** Writing 'IdInfo' fields
+ setIdUnfolding,
+ setIdArity,
+ setIdNewDemandInfo,
+ setIdNewStrictness, zapIdNewStrictness,
+ setIdWorkerInfo,
+ setIdSpecialisation,
+ setIdCafInfo,
+ setIdOccInfo, zapIdOccInfo,
+
+#ifdef OLD_STRICTNESS
+ setIdStrictness,
+ setIdDemandInfo,
+ setIdCprInfo,
+#endif
) where
#include "HsVersions.h"
-import {-# SOURCE #-} CoreSyn ( CoreRule, Unfolding )
+import CoreSyn ( CoreRule, Unfolding )
import IdInfo
import BasicTypes
+
+-- Imported and re-exported
+import Var( Var, Id, DictId,
+ idInfo, idDetails, globaliseId,
+ isId, isLocalId, isGlobalId, isExportedId )
import qualified Var
-import Var
+
import TyCon
import Type
import TcType
-import TysPrim
+import TysPrim
#ifdef OLD_STRICTNESS
import qualified Demand
#endif
import Unique
import UniqSupply
import FastString
+import Util( count )
import StaticFlags
-- infixl so you can say (id `set` a `set` b)
,`setIdDemandInfo`
#endif
\end{code}
+
%************************************************************************
%* *
\subsection{Basic Id manipulation}
idName = Var.varName
idUnique :: Id -> Unique
-idUnique = varUnique
+idUnique = Var.varUnique
idType :: Id -> Kind
-idType = varType
+idType = Var.varType
-setIdUnique :: Id -> Unique -> Id
-setIdUnique = setVarUnique
+idPrimRep :: Id -> PrimRep
+idPrimRep id = typePrimRep (idType id)
setIdName :: Id -> Name -> Id
-setIdName = setVarName
+setIdName = Var.setVarName
+
+setIdUnique :: Id -> Unique -> Id
+setIdUnique = Var.setVarUnique
+-- | Not only does this set the 'Id' 'Type', it also evaluates the type to try and
+-- reduce space usage
setIdType :: Id -> Type -> Id
setIdType id ty = seqType ty `seq` Var.setVarType id ty
setIdExported :: Id -> Id
-setIdExported = setIdVarExported
+setIdExported = Var.setIdExported
setIdNotExported :: Id -> Id
-setIdNotExported = setIdVarNotExported
-
-globaliseId :: GlobalIdDetails -> Id -> Id
-globaliseId = globaliseIdVar
-
-idInfo :: Id -> IdInfo
-idInfo = varIdInfo
+setIdNotExported = Var.setIdNotExported
+
+localiseId :: Id -> Id
+-- Make an with the same unique and type as the
+-- incoming Id, but with an *Internal* Name and *LocalId* flavour
+localiseId id
+ | isLocalId id && isInternalName name
+ = id
+ | otherwise
+ = mkLocalIdWithInfo (localiseName name) (idType id) (idInfo id)
+ where
+ name = idName id
lazySetIdInfo :: Id -> IdInfo -> Id
-lazySetIdInfo = lazySetVarIdInfo
+lazySetIdInfo = Var.lazySetIdInfo
setIdInfo :: Id -> IdInfo -> Id
setIdInfo id info = seqIdInfo info `seq` (lazySetIdInfo id info)
Anyway, we removed it in March 2008.
\begin{code}
--- | Create a global Id. Global identifiers are those that are imported or are data constructors/destructors.
-mkGlobalId :: GlobalIdDetails -> Name -> Type -> IdInfo -> Id
-mkGlobalId = mkGlobalIdVar
+-- | For an explanation of global vs. local 'Id's, see "Var#globalvslocal"
+mkGlobalId :: IdDetails -> Name -> Type -> IdInfo -> Id
+mkGlobalId = Var.mkGlobalVar
+-- | Make a global 'Id' without any extra information at all
mkVanillaGlobal :: Name -> Type -> Id
mkVanillaGlobal name ty = mkVanillaGlobalWithInfo name ty vanillaIdInfo
+-- | Make a global 'Id' with no global information but some generic 'IdInfo'
mkVanillaGlobalWithInfo :: Name -> Type -> IdInfo -> Id
-mkVanillaGlobalWithInfo = mkGlobalId VanillaGlobal
+mkVanillaGlobalWithInfo = mkGlobalId VanillaId
--- | Create a local Id. Local identifiers are those bound at the top level of the current module or in an expression.
+-- | For an explanation of global vs. local 'Id's, see "Var#globalvslocal"
mkLocalId :: Name -> Type -> Id
mkLocalId name ty = mkLocalIdWithInfo name ty vanillaIdInfo
mkLocalIdWithInfo :: Name -> Type -> IdInfo -> Id
-mkLocalIdWithInfo = mkLocalIdVar
+mkLocalIdWithInfo name ty info = Var.mkLocalVar VanillaId name ty info
+ -- Note [Free type variables]
--- | Create a local Id that is marked as exported. This prevents things attached to it from being removed as dead code.
+-- | Create a local 'Id' that is marked as exported.
+-- This prevents things attached to it from being removed as dead code.
mkExportedLocalId :: Name -> Type -> Id
-mkExportedLocalId name ty = mkExportedLocalIdVar name ty vanillaIdInfo
+mkExportedLocalId name ty = Var.mkExportedLocalVar VanillaId name ty vanillaIdInfo
-- Note [Free type variables]
--- | Create a system local Id. These are local Ids that are created by the compiler out of thin air
+-- | Create a system local 'Id'. These are local 'Id's (see "Var#globalvslocal")
+-- that are created by the compiler out of thin air
mkSysLocal :: FastString -> Unique -> Type -> Id
mkSysLocal fs uniq ty = mkLocalId (mkSystemVarName uniq fs) ty
mkSysLocalM fs ty = getUniqueM >>= (\uniq -> return (mkSysLocal fs uniq ty))
--- | Create a user local Id. These are local Id with a name and location that the user might recognize
+-- | Create a user local 'Id'. These are local 'Id's (see "Var#globalvslocal") with a name and location that the user might recognize
mkUserLocal :: OccName -> Unique -> Type -> SrcSpan -> Id
mkUserLocal occ uniq ty loc = mkLocalId (mkInternalName uniq occ loc) ty
mkUserLocalM :: MonadUnique m => OccName -> Type -> SrcSpan -> m Id
mkUserLocalM occ ty loc = getUniqueM >>= (\uniq -> return (mkUserLocal occ uniq ty loc))
+
\end{code}
Make some local @Ids@ for a template @CoreExpr@. These have bogus
instantiated before use.
\begin{code}
--- | Make a "wild Id". This is typically used when you need a binder that you don't expect to use
-mkWildId :: Type -> Id
-mkWildId ty = mkSysLocal (fsLit "wild") (mkBuiltinUnique 1) ty
-
+-- | Workers get local names. "CoreTidy" will externalise these if necessary
mkWorkerId :: Unique -> Id -> Type -> Id
--- | Workers get local names. CoreTidy will externalise these if necessary
mkWorkerId uniq unwrkr ty
= mkLocalId wkr_name ty
where
wkr_name = mkInternalName uniq (mkWorkerOcc (getOccName unwrkr)) (getSrcSpan unwrkr)
--- | Create a "template local": a family of system local Ids in bijection with Ints, typically used in unfoldings
+-- | Create a /template local/: a family of system local 'Id's in bijection with @Int@s, typically used in unfoldings
mkTemplateLocal :: Int -> Type -> Id
mkTemplateLocal i ty = mkSysLocal (fsLit "tpl") (mkBuiltinUnique i) ty
-- | Create a template local for a series of type, but start from a specified template local
mkTemplateLocalsNum :: Int -> [Type] -> [Id]
--- The Int gives the starting point for unique allocation
mkTemplateLocalsNum n tys = zipWith mkTemplateLocal [n..] tys
\end{code}
%************************************************************************
%* *
-\subsection[Id-general-funs]{General @Id@-related functions}
-%* *
-%************************************************************************
-
-\begin{code}
-idPrimRep :: Id -> PrimRep
-idPrimRep id = typePrimRep (idType id)
-
-globalIdDetails :: Id -> GlobalIdDetails
-globalIdDetails = globalIdVarDetails
-
-isId :: Id -> Bool
-isId = isIdVar
-
-isLocalId :: Id -> Bool
-isLocalId = isLocalIdVar
-
-isGlobalId :: Id -> Bool
-isGlobalId = isGlobalIdVar
-
-isExportedId :: Var -> Bool
-isExportedId = isExportedIdVar
-\end{code}
-
-
-%************************************************************************
-%* *
\subsection{Special Ids}
%* *
%************************************************************************
\begin{code}
+-- | If the 'Id' is that for a record selector, extract the 'sel_tycon' and label. Panic otherwise
recordSelectorFieldLabel :: Id -> (TyCon, FieldLabel)
recordSelectorFieldLabel id
- = case globalIdDetails id of
- RecordSelId { sel_tycon = tycon, sel_label = lbl } -> (tycon,lbl)
+ = case Var.idDetails id of
+ RecSelId { sel_tycon = tycon } -> (tycon, idName id)
_ -> panic "recordSelectorFieldLabel"
isRecordSelector :: Id -> Bool
isFCallId_maybe :: Id -> Maybe ForeignCall
isDataConWorkId_maybe :: Id -> Maybe DataCon
-isRecordSelector id = case globalIdDetails id of
- RecordSelId {} -> True
+isRecordSelector id = case Var.idDetails id of
+ RecSelId {} -> True
_ -> False
-isNaughtyRecordSelector id = case globalIdDetails id of
- RecordSelId { sel_naughty = n } -> n
+isNaughtyRecordSelector id = case Var.idDetails id of
+ RecSelId { sel_naughty = n } -> n
_ -> False
-isClassOpId_maybe id = case globalIdDetails id of
+isClassOpId_maybe id = case Var.idDetails id of
ClassOpId cls -> Just cls
_other -> Nothing
-isPrimOpId id = case globalIdDetails id of
+isPrimOpId id = case Var.idDetails id of
PrimOpId _ -> True
_ -> False
-isPrimOpId_maybe id = case globalIdDetails id of
+isPrimOpId_maybe id = case Var.idDetails id of
PrimOpId op -> Just op
_ -> Nothing
-isFCallId id = case globalIdDetails id of
+isFCallId id = case Var.idDetails id of
FCallId _ -> True
_ -> False
-isFCallId_maybe id = case globalIdDetails id of
+isFCallId_maybe id = case Var.idDetails id of
FCallId call -> Just call
_ -> Nothing
-isDataConWorkId id = case globalIdDetails id of
+isDataConWorkId id = case Var.idDetails id of
DataConWorkId _ -> True
_ -> False
-isDataConWorkId_maybe id = case globalIdDetails id of
+isDataConWorkId_maybe id = case Var.idDetails id of
DataConWorkId con -> Just con
_ -> Nothing
isDataConId_maybe :: Id -> Maybe DataCon
-isDataConId_maybe id = case globalIdDetails id of
+isDataConId_maybe id = case Var.idDetails id of
DataConWorkId con -> Just con
DataConWrapId con -> Just con
_ -> Nothing
idDataCon :: Id -> DataCon
--- ^ Get from either the worker or the wrapper to the DataCon.
--- Currently used only in the desugarer.
---
--- INVARIANT: @idDataCon (dataConWrapId d) = d@
+-- ^ Get from either the worker or the wrapper 'Id' to the 'DataCon'. Currently used only in the desugarer.
--
--- (Remember, dataConWrapId can return either the wrapper or the worker.)
-idDataCon id = isDataConId_maybe id `orElse` pprPanic "idDataCon" (ppr id
+-- INVARIANT: @idDataCon (dataConWrapId d) = d@: remember, 'dataConWrapId' can return either the wrapper or the worker
+idDataCon id = isDataConId_maybe id `orElse` pprPanic "idDataCon" (ppr id)
isDictId :: Id -> Bool
isDictId id = isDictTy (idType id)
hasNoBinding :: Id -> Bool
--- ^ Returns True of an Id which may not have a
--- binding, even though it is defined in this module.
+-- ^ Returns @True@ of an 'Id' which may not have a
+-- binding, even though it is defined in this module.
+
-- Data constructor workers used to be things of this kind, but
-- they aren't any more. Instead, we inject a binding for
-- them at the CorePrep stage.
-- EXCEPT: unboxed tuples, which definitely have no binding
-hasNoBinding id = case globalIdDetails id of
+hasNoBinding id = case Var.idDetails id of
PrimOpId _ -> True -- See Note [Primop wrappers]
FCallId _ -> True
DataConWorkId dc -> isUnboxedTupleCon dc
_ -> False
isImplicitId :: Id -> Bool
--- ^ isImplicitId tells whether an Id's info is implied by other
+-- ^ 'isImplicitId' tells whether an 'Id's info is implied by other
-- declarations, so we don't need to put its signature in an interface
-- file, even if it's mentioned in some other interface unfolding.
isImplicitId id
- = case globalIdDetails id of
- RecordSelId {} -> True
+ = case Var.idDetails id of
FCallId _ -> True
+ ClassOpId _ -> True
PrimOpId _ -> True
- ClassOpId _ -> True
DataConWorkId _ -> True
DataConWrapId _ -> True
-- These are are implied by their type or class decl;
\begin{code}
isTickBoxOp :: Id -> Bool
isTickBoxOp id =
- case globalIdDetails id of
+ case Var.idDetails id of
TickBoxOpId _ -> True
_ -> False
isTickBoxOp_maybe :: Id -> Maybe TickBoxOp
isTickBoxOp_maybe id =
- case globalIdDetails id of
+ case Var.idDetails id of
TickBoxOpId tick -> Just tick
_ -> Nothing
\end{code}
zapIdNewStrictness :: Id -> Id
zapIdNewStrictness id = modifyIdInfo (`setNewStrictnessInfo` Nothing) id
--- | This predicate says whether the id has a strict demand placed on it or
+-- | This predicate says whether the 'Id' has a strict demand placed on it or
-- has a type such that it can always be evaluated strictly (e.g., an
-- unlifted type, but see the comment for 'isStrictType'). We need to
--- check separately whether <id> has a so-called "strict type" because if
--- the demand for <id> hasn't been computed yet but <id> has a strict
--- type, we still want @isStrictId <id>@ to be True.
+-- check separately whether the 'Id' has a so-called \"strict type\" because if
+-- the demand for the given @id@ hasn't been computed yet but @id@ has a strict
+-- type, we still want @isStrictId id@ to be @True@.
isStrictId :: Id -> Bool
isStrictId id
= ASSERT2( isId id, text "isStrictId: not an id: " <+> ppr id )
setIdOccInfo :: Id -> OccInfo -> Id
setIdOccInfo id occ_info = modifyIdInfo (`setOccInfo` occ_info) id
+
+zapIdOccInfo :: Id -> Id
+zapIdOccInfo b = b `setIdOccInfo` NoOccInfo
\end{code}
OK not to if optimisation is switched off.
\begin{code}
-idInlinePragma :: Id -> InlinePragInfo
+idInlinePragma :: Id -> InlinePragma
idInlinePragma id = inlinePragInfo (idInfo id)
-setInlinePragma :: Id -> InlinePragInfo -> Id
+setInlinePragma :: Id -> InlinePragma -> Id
setInlinePragma id prag = modifyIdInfo (`setInlinePragInfo` prag) id
-modifyInlinePragma :: Id -> (InlinePragInfo -> InlinePragInfo) -> Id
+modifyInlinePragma :: Id -> (InlinePragma -> InlinePragma) -> Id
modifyInlinePragma id fn = modifyIdInfo (\info -> info `setInlinePragInfo` (fn (inlinePragInfo info))) id
+
+idInlineActivation :: Id -> Activation
+idInlineActivation id = inlinePragmaActivation (idInlinePragma id)
+
+setInlineActivation :: Id -> Activation -> Id
+setInlineActivation id act = modifyInlinePragma id (\(InlinePragma _ match_info) -> InlinePragma act match_info)
+
+idRuleMatchInfo :: Id -> RuleMatchInfo
+idRuleMatchInfo id = inlinePragmaRuleMatchInfo (idInlinePragma id)
+
+isConLikeId :: Id -> Bool
+isConLikeId id = isDataConWorkId id || isConLike (idRuleMatchInfo id)
\end{code}
idLBVarInfo :: Id -> LBVarInfo
idLBVarInfo id = lbvarInfo (idInfo id)
+-- | Returns whether the lambda associated with the 'Id' is certainly applied at most once
+-- OR we are applying the \"state hack\" which makes it appear as if theis is the case for
+-- lambdas used in @IO@. You should prefer using this over 'isOneShotLambda'
isOneShotBndr :: Id -> Bool
-- This one is the "business end", called externally.
-- Its main purpose is to encapsulate the Horrible State Hack
isOneShotBndr id = isOneShotLambda id || isStateHackType (idType id)
+-- | Should we apply the state hack to values of this 'Type'?
isStateHackType :: Type -> Bool
isStateHackType ty
| opt_NoStateHack
-- spot that fill_in has arity 2 (and when Keith is done, we will) but we can't yet.
--- The OneShotLambda functions simply fiddle with the IdInfo flag
+-- | Returns whether the lambda associated with the 'Id' is certainly applied at most once.
+-- You probably want to use 'isOneShotBndr' instead
isOneShotLambda :: Id -> Bool
isOneShotLambda id = case idLBVarInfo id of
IsOneShotLambda -> True
| isOneShotLambda id = modifyIdInfo (`setLBVarInfo` NoLBVarInfo) id
| otherwise = id
+-- The OneShotLambda functions simply fiddle with the IdInfo flag
-- But watch out: this may change the type of something else
-- f = \x -> e
-- If we change the one-shot-ness of x, f's type changes
g' = /\a. rhs
f = /\a. ...[g' a/g]
-we *do not* want to lose the strictness information on g. Nor arity.
+we *do not* want to lose g's
+ * strictness information
+ * arity
+ * inline pragma (though that is bit more debatable)
It's simple to retain strictness and arity, but not so simple to retain
- worker info
- rules
+ * worker info
+ * rules
so we simply discard those. Sooner or later this may bite us.
This transfer is used in two places:
FloatOut (long-distance let-floating)
SimplUtils.abstractFloats (short-distance let-floating)
+If we abstract wrt one or more *value* binders, we must modify the
+arity and strictness info before transferring it. E.g.
+ f = \x. e
+-->
+ g' = \y. \x. e
+ + substitute (g' y) for g
+Notice that g' has an arity one more than the original g
+
\begin{code}
-transferPolyIdInfo :: Id -> Id -> Id
-transferPolyIdInfo old_id new_id
+transferPolyIdInfo :: Id -- Original Id
+ -> [Var] -- Abstract wrt these variables
+ -> Id -- New Id
+ -> Id
+transferPolyIdInfo old_id abstract_wrt new_id
= modifyIdInfo transfer new_id
where
- old_info = idInfo old_id
- transfer new_info = new_info `setNewStrictnessInfo` (newStrictnessInfo old_info)
- `setArityInfo` (arityInfo old_info)
+ arity_increase = count isId abstract_wrt -- Arity increases by the
+ -- number of value binders
+
+ old_info = idInfo old_id
+ old_arity = arityInfo old_info
+ old_inline_prag = inlinePragInfo old_info
+ new_arity = old_arity + arity_increase
+ old_strictness = newStrictnessInfo old_info
+ new_strictness = fmap (increaseStrictSigArity arity_increase) old_strictness
+
+ transfer new_info = new_info `setNewStrictnessInfo` new_strictness
+ `setArityInfo` new_arity
+ `setInlinePragInfo` old_inline_prag
\end{code}
-