isImplicitId, isDeadBinder, isDictId, isStrictId,
isExportedId, isLocalId, isGlobalId,
isRecordSelector, isNaughtyRecordSelector,
- isClassOpId_maybe, isDFunId,
+ isClassOpId_maybe, isDFunId, dfunNSilent,
isPrimOpId, isPrimOpId_maybe,
isFCallId, isFCallId_maybe,
isDataConWorkId, isDataConWorkId_maybe, isDataConId_maybe, idDataCon,
idOccInfo,
-- ** Writing 'IdInfo' fields
+ setIdUnfoldingLazily,
setIdUnfolding,
setIdArity,
setIdDemandInfo,
import StaticFlags
-- infixl so you can say (id `set` a `set` b)
-infixl 1 `setIdUnfolding`,
+infixl 1 `setIdUnfoldingLazily`,
+ `setIdUnfolding`,
`setIdArity`,
`setIdOccInfo`,
`setIdDemandInfo`,
-- 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
+ | ASSERT( isId id ) isLocalId id && isInternalName name
= id
| otherwise
= mkLocalIdWithInfo (localiseName name) (idType id) (idInfo id)
_ -> False
isDFunId id = case Var.idDetails id of
- DFunId _ -> True
- _ -> False
+ DFunId {} -> True
+ _ -> False
+
+dfunNSilent :: Id -> Int
+dfunNSilent id = case Var.idDetails id of
+ DFunId ns _ -> ns
+ _ -> pprTrace "dfunSilent: not a dfun:" (ppr id) 0
isPrimOpId_maybe id = case Var.idDetails id of
PrimOpId op -> Just op
-- Expose the unfolding if there is one, including for loop breakers
realIdUnfolding id = unfoldingInfo (idInfo id)
+setIdUnfoldingLazily :: Id -> Unfolding -> Id
+setIdUnfoldingLazily id unfolding = modifyIdInfo (`setUnfoldingInfoLazily` unfolding) id
+
setIdUnfolding :: Id -> Unfolding -> Id
setIdUnfolding id unfolding = modifyIdInfo (`setUnfoldingInfo` unfolding) id
Note [transferPolyIdInfo]
~~~~~~~~~~~~~~~~~~~~~~~~~
-Suppose we have
+This transfer is used in two places:
+ FloatOut (long-distance let-floating)
+ SimplUtils.abstractFloats (short-distance let-floating)
+
+Consider the short-distance let-floating:
f = /\a. let g = rhs in ...
-where g has interesting strictness information. Then if we float thus
+Then if we float thus
g' = /\a. rhs
- f = /\a. ...[g' a/g]
+ f = /\a. ...[g' a/g]....
we *do not* want to lose g's
* strictness information
* arity
* inline pragma (though that is bit more debatable)
+ * occurrence info
+
+Mostly this is just an optimisation, but it's *vital* to
+transfer the occurrence info. Consider
+
+ NonRec { f = /\a. let Rec { g* = ..g.. } in ... }
-It's simple to retain strictness and arity, but not so simple to retain
+where the '*' means 'LoopBreaker'. Then if we float we must get
+
+ Rec { g'* = /\a. ...(g' a)... }
+ NonRec { f = /\a. ...[g' a/g]....}
+
+where g' is also marked as LoopBreaker. If not, terrible things
+can happen if we re-simplify the binding (and the Simplifier does
+sometimes simplify a term twice); see Trac #4345.
+
+It's not so simple to retain
* 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
old_info = idInfo old_id
old_arity = arityInfo old_info
old_inline_prag = inlinePragInfo old_info
+ old_occ_info = occInfo old_info
new_arity = old_arity + arity_increase
old_strictness = strictnessInfo old_info
new_strictness = fmap (increaseStrictSigArity arity_increase) old_strictness
transfer new_info = new_info `setStrictnessInfo` new_strictness
`setArityInfo` new_arity
`setInlinePragInfo` old_inline_prag
+ `setOccInfo` old_occ_info
\end{code}