2 % (c) The University of Glasgow 2006
3 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1998
5 \section[IdInfo]{@IdInfos@: Non-essential information about @Ids@}
7 (And a pretty good illustration of quite a few things wrong with
12 -- * The IdDetails type
13 IdDetails(..), pprIdDetails,
17 vanillaIdInfo, noCafIdInfo,
18 seqIdInfo, megaSeqIdInfo,
20 -- ** Zapping various forms of Info
21 zapLamInfo, zapDemandInfo, zapFragileInfo,
23 -- ** The ArityInfo type
26 arityInfo, setArityInfo, ppArityInfo,
28 -- ** Demand and strictness Info
29 newStrictnessInfo, setNewStrictnessInfo,
30 newDemandInfo, setNewDemandInfo, pprNewStrictness,
34 -- ** Old strictness Info
36 mkStrictnessInfo, noStrictnessInfo,
37 ppStrictnessInfo, isBottomingStrictness,
38 strictnessInfo, setStrictnessInfo,
40 oldStrictnessFromNew, newStrictnessFromOld,
43 demandInfo, setDemandInfo,
46 -- ** Old Constructed Product Result Info
48 cprInfo, setCprInfo, ppCprInfo, noCprInfo,
49 cprInfoFromNewStrictness,
53 unfoldingInfo, setUnfoldingInfo, setUnfoldingInfoLazily,
55 -- ** The InlinePragInfo type
57 inlinePragInfo, setInlinePragInfo,
59 -- ** The OccInfo type
61 isFragileOcc, isDeadOcc, isLoopBreaker,
65 insideLam, notInsideLam, oneBranch, notOneBranch,
67 -- ** The SpecInfo type
69 isEmptySpecInfo, specInfoFreeVars,
70 specInfoRules, seqSpecInfo, setSpecInfoHead,
71 specInfo, setSpecInfo,
73 -- ** The CAFInfo type
75 ppCafInfo, mayHaveCafRefs,
78 -- ** The LBVarInfo type
80 noLBVarInfo, hasNoLBVarInfo,
81 lbvarInfo, setLBVarInfo,
84 TickBoxOp(..), TickBoxId,
87 import CoreSyn ( CoreRule, setRuleIdName, seqRules, Unfolding, noUnfolding )
104 #ifdef OLD_STRICTNESS
106 import qualified Demand
111 -- infixl so you can say (id `set` a `set` b)
112 infixl 1 `setSpecInfo`,
119 `setNewStrictnessInfo`,
120 `setAllStrictnessInfo`,
122 #ifdef OLD_STRICTNESS
125 , `setStrictnessInfo`
129 %************************************************************************
131 \subsection{New strictness info}
133 %************************************************************************
138 -- | Set old and new strictness information together
139 setAllStrictnessInfo :: IdInfo -> Maybe StrictSig -> IdInfo
140 setAllStrictnessInfo info Nothing
141 = info { newStrictnessInfo = Nothing
142 #ifdef OLD_STRICTNESS
143 , strictnessInfo = NoStrictnessInfo
144 , cprInfo = NoCPRInfo
148 setAllStrictnessInfo info (Just sig)
149 = info { newStrictnessInfo = Just sig
150 #ifdef OLD_STRICTNESS
151 , strictnessInfo = oldStrictnessFromNew sig
152 , cprInfo = cprInfoFromNewStrictness sig
156 seqNewStrictnessInfo :: Maybe StrictSig -> ()
157 seqNewStrictnessInfo Nothing = ()
158 seqNewStrictnessInfo (Just ty) = seqStrictSig ty
160 pprNewStrictness :: Maybe StrictSig -> SDoc
161 pprNewStrictness Nothing = empty
162 pprNewStrictness (Just sig) = ppr sig
164 #ifdef OLD_STRICTNESS
165 oldStrictnessFromNew :: StrictSig -> Demand.StrictnessInfo
166 oldStrictnessFromNew sig = mkStrictnessInfo (map oldDemand dmds, isBotRes res_info)
168 (dmds, res_info) = splitStrictSig sig
170 cprInfoFromNewStrictness :: StrictSig -> CprInfo
171 cprInfoFromNewStrictness sig = case strictSigResInfo sig of
175 newStrictnessFromOld :: Name -> Arity -> Demand.StrictnessInfo -> CprInfo -> StrictSig
176 newStrictnessFromOld name arity (Demand.StrictnessInfo ds res) cpr
177 | listLengthCmp ds arity /= GT -- length ds <= arity
178 -- Sometimes the old strictness analyser has more
179 -- demands than the arity justifies
180 = mk_strict_sig name arity $
181 mkTopDmdType (map newDemand ds) (newRes res cpr)
183 newStrictnessFromOld name arity other cpr
184 = -- Either no strictness info, or arity is too small
185 -- In either case we can't say anything useful
186 mk_strict_sig name arity $
187 mkTopDmdType (replicate arity lazyDmd) (newRes False cpr)
189 mk_strict_sig name arity dmd_ty
190 = WARN( arity /= dmdTypeDepth dmd_ty, ppr name <+> (ppr arity $$ ppr dmd_ty) )
193 newRes True _ = BotRes
194 newRes False ReturnsCPR = retCPR
195 newRes False NoCPRInfo = TopRes
197 newDemand :: Demand.Demand -> NewDemand.Demand
198 newDemand (WwLazy True) = Abs
199 newDemand (WwLazy False) = lazyDmd
200 newDemand WwStrict = evalDmd
201 newDemand (WwUnpack unpk ds) = Eval (Prod (map newDemand ds))
202 newDemand WwPrim = lazyDmd
203 newDemand WwEnum = evalDmd
205 oldDemand :: NewDemand.Demand -> Demand.Demand
206 oldDemand Abs = WwLazy True
207 oldDemand Top = WwLazy False
208 oldDemand Bot = WwStrict
209 oldDemand (Box Bot) = WwStrict
210 oldDemand (Box Abs) = WwLazy False
211 oldDemand (Box (Eval _)) = WwStrict -- Pass box only
212 oldDemand (Defer d) = WwLazy False
213 oldDemand (Eval (Prod ds)) = WwUnpack True (map oldDemand ds)
214 oldDemand (Eval (Poly _)) = WwStrict
215 oldDemand (Call _) = WwStrict
217 #endif /* OLD_STRICTNESS */
222 seqNewDemandInfo :: Maybe Demand -> ()
223 seqNewDemandInfo Nothing = ()
224 seqNewDemandInfo (Just dmd) = seqDemand dmd
228 %************************************************************************
232 %************************************************************************
235 -- | The 'IdDetails' of an 'Id' give stable, and necessary,
236 -- information about the Id.
240 -- | The 'Id' for a record selector
242 { sel_tycon :: TyCon -- ^ For a data type family, this is the /instance/ 'TyCon'
243 -- not the family 'TyCon'
244 , sel_naughty :: Bool -- True <=> a "naughty" selector which can't actually exist, for example @x@ in:
245 -- data T = forall a. MkT { x :: a }
246 } -- See Note [Naughty record selectors] in TcTyClsDecls
248 | DataConWorkId DataCon -- ^ The 'Id' is for a data constructor /worker/
249 | DataConWrapId DataCon -- ^ The 'Id' is for a data constructor /wrapper/
251 -- [the only reasons we need to know is so that
252 -- a) to support isImplicitId
253 -- b) when desugaring a RecordCon we can get
254 -- from the Id back to the data con]
256 | ClassOpId Class -- ^ The 'Id' is an superclass selector or class operation of a class
258 | PrimOpId PrimOp -- ^ The 'Id' is for a primitive operator
259 | FCallId ForeignCall -- ^ The 'Id' is for a foreign call
261 | TickBoxOpId TickBoxOp -- ^ The 'Id' is for a HPC tick box (both traditional and binary)
263 | DFunId Bool -- ^ A dictionary function.
264 -- True <=> the class has only one method, so may be
265 -- implemented with a newtype, so it might be bad
266 -- to be strict on this dictionary
269 instance Outputable IdDetails where
272 pprIdDetails :: IdDetails -> SDoc
273 pprIdDetails VanillaId = empty
274 pprIdDetails other = brackets (pp other)
276 pp VanillaId = panic "pprIdDetails"
277 pp (DataConWorkId _) = ptext (sLit "DataCon")
278 pp (DataConWrapId _) = ptext (sLit "DataConWrapper")
279 pp (ClassOpId {}) = ptext (sLit "ClassOp")
280 pp (PrimOpId _) = ptext (sLit "PrimOp")
281 pp (FCallId _) = ptext (sLit "ForeignCall")
282 pp (TickBoxOpId _) = ptext (sLit "TickBoxOp")
283 pp (DFunId b) = ptext (sLit "DFunId") <>
284 ppWhen b (ptext (sLit "(newtype)"))
285 pp (RecSelId { sel_naughty = is_naughty })
286 = brackets $ ptext (sLit "RecSel")
287 <> ppWhen is_naughty (ptext (sLit "(naughty)"))
291 %************************************************************************
293 \subsection{The main IdInfo type}
295 %************************************************************************
298 -- | An 'IdInfo' gives /optional/ information about an 'Id'. If
299 -- present it never lies, but it may not be present, in which case there
300 -- is always a conservative assumption which can be made.
302 -- Two 'Id's may have different info even though they have the same
303 -- 'Unique' (and are hence the same 'Id'); for example, one might lack
304 -- the properties attached to the other.
306 -- The 'IdInfo' gives information about the value, or definition, of the
307 -- 'Id'. It does not contain information about the 'Id''s usage,
308 -- except for 'demandInfo' and 'lbvarInfo'.
311 arityInfo :: !ArityInfo, -- ^ 'Id' arity
312 specInfo :: SpecInfo, -- ^ Specialisations of the 'Id's function which exist
313 -- See Note [Specialisations and RULES in IdInfo]
314 #ifdef OLD_STRICTNESS
315 cprInfo :: CprInfo, -- ^ If the 'Id's function always constructs a product result
316 demandInfo :: Demand.Demand, -- ^ Whether or not the 'Id' is definitely demanded
317 strictnessInfo :: StrictnessInfo, -- ^ 'Id' strictness properties
319 unfoldingInfo :: Unfolding, -- ^ The 'Id's unfolding
320 cafInfo :: CafInfo, -- ^ 'Id' CAF info
321 lbvarInfo :: LBVarInfo, -- ^ Info about a lambda-bound variable, if the 'Id' is one
322 inlinePragInfo :: InlinePragma, -- ^ Any inline pragma atached to the 'Id'
323 occInfo :: OccInfo, -- ^ How the 'Id' occurs in the program
325 newStrictnessInfo :: Maybe StrictSig, -- ^ Id strictness information. Reason for Maybe:
326 -- the DmdAnal phase needs to know whether
327 -- this is the first visit, so it can assign botSig.
328 -- Other customers want topSig. So @Nothing@ is good.
330 newDemandInfo :: Maybe Demand -- ^ Id demand information. Similarly we want to know
331 -- if there's no known demand yet, for when we are looking
335 -- | Just evaluate the 'IdInfo' to WHNF
336 seqIdInfo :: IdInfo -> ()
337 seqIdInfo (IdInfo {}) = ()
339 -- | Evaluate all the fields of the 'IdInfo' that are generally demanded by the
341 megaSeqIdInfo :: IdInfo -> ()
343 = seqSpecInfo (specInfo info) `seq`
345 -- Omitting this improves runtimes a little, presumably because
346 -- some unfoldings are not calculated at all
347 -- seqUnfolding (unfoldingInfo info) `seq`
349 seqNewDemandInfo (newDemandInfo info) `seq`
350 seqNewStrictnessInfo (newStrictnessInfo info) `seq`
352 #ifdef OLD_STRICTNESS
353 Demand.seqDemand (demandInfo info) `seq`
354 seqStrictnessInfo (strictnessInfo info) `seq`
355 seqCpr (cprInfo info) `seq`
358 seqCaf (cafInfo info) `seq`
359 seqLBVar (lbvarInfo info) `seq`
360 seqOccInfo (occInfo info)
366 setSpecInfo :: IdInfo -> SpecInfo -> IdInfo
367 setSpecInfo info sp = sp `seq` info { specInfo = sp }
368 setInlinePragInfo :: IdInfo -> InlinePragma -> IdInfo
369 setInlinePragInfo info pr = pr `seq` info { inlinePragInfo = pr }
370 setOccInfo :: IdInfo -> OccInfo -> IdInfo
371 setOccInfo info oc = oc `seq` info { occInfo = oc }
372 #ifdef OLD_STRICTNESS
373 setStrictnessInfo info st = st `seq` info { strictnessInfo = st }
375 -- Try to avoid spack leaks by seq'ing
377 setUnfoldingInfoLazily :: IdInfo -> Unfolding -> IdInfo
378 setUnfoldingInfoLazily info uf -- Lazy variant to avoid looking at the
379 = -- unfolding of an imported Id unless necessary
380 info { unfoldingInfo = uf } -- (In this case the demand-zapping is redundant.)
382 setUnfoldingInfo :: IdInfo -> Unfolding -> IdInfo
383 setUnfoldingInfo info uf
384 -- We do *not* seq on the unfolding info, For some reason, doing so
385 -- actually increases residency significantly.
386 = info { unfoldingInfo = uf }
388 #ifdef OLD_STRICTNESS
389 setDemandInfo info dd = info { demandInfo = dd }
390 setCprInfo info cp = info { cprInfo = cp }
393 setArityInfo :: IdInfo -> ArityInfo -> IdInfo
394 setArityInfo info ar = info { arityInfo = ar }
395 setCafInfo :: IdInfo -> CafInfo -> IdInfo
396 setCafInfo info caf = info { cafInfo = caf }
398 setLBVarInfo :: IdInfo -> LBVarInfo -> IdInfo
399 setLBVarInfo info lb = {-lb `seq`-} info { lbvarInfo = lb }
401 setNewDemandInfo :: IdInfo -> Maybe Demand -> IdInfo
402 setNewDemandInfo info dd = dd `seq` info { newDemandInfo = dd }
403 setNewStrictnessInfo :: IdInfo -> Maybe StrictSig -> IdInfo
404 setNewStrictnessInfo info dd = dd `seq` info { newStrictnessInfo = dd }
409 -- | Basic 'IdInfo' that carries no useful information whatsoever
410 vanillaIdInfo :: IdInfo
413 cafInfo = vanillaCafInfo,
414 arityInfo = unknownArity,
415 #ifdef OLD_STRICTNESS
418 strictnessInfo = NoStrictnessInfo,
420 specInfo = emptySpecInfo,
421 unfoldingInfo = noUnfolding,
422 lbvarInfo = NoLBVarInfo,
423 inlinePragInfo = defaultInlinePragma,
425 newDemandInfo = Nothing,
426 newStrictnessInfo = Nothing
429 -- | More informative 'IdInfo' we can use when we know the 'Id' has no CAF references
430 noCafIdInfo :: IdInfo
431 noCafIdInfo = vanillaIdInfo `setCafInfo` NoCafRefs
432 -- Used for built-in type Ids in MkId.
436 %************************************************************************
438 \subsection[arity-IdInfo]{Arity info about an @Id@}
440 %************************************************************************
442 For locally-defined Ids, the code generator maintains its own notion
443 of their arities; so it should not be asking... (but other things
444 besides the code-generator need arity info!)
447 -- | An 'ArityInfo' of @n@ tells us that partial application of this
448 -- 'Id' to up to @n-1@ value arguments does essentially no work.
450 -- That is not necessarily the same as saying that it has @n@ leading
451 -- lambdas, because coerces may get in the way.
453 -- The arity might increase later in the compilation process, if
454 -- an extra lambda floats up to the binding site.
455 type ArityInfo = Arity
457 -- | It is always safe to assume that an 'Id' has an arity of 0
458 unknownArity :: Arity
459 unknownArity = 0 :: Arity
461 ppArityInfo :: Int -> SDoc
462 ppArityInfo 0 = empty
463 ppArityInfo n = hsep [ptext (sLit "Arity"), int n]
466 %************************************************************************
468 \subsection{Inline-pragma information}
470 %************************************************************************
473 -- | Tells when the inlining is active.
474 -- When it is active the thing may be inlined, depending on how
477 -- If there was an @INLINE@ pragma, then as a separate matter, the
478 -- RHS will have been made to look small with a Core inline 'Note'
480 -- The default 'InlinePragInfo' is 'AlwaysActive', so the info serves
481 -- entirely as a way to inhibit inlining until we want it
482 type InlinePragInfo = InlinePragma
486 %************************************************************************
490 %************************************************************************
492 Note [Specialisations and RULES in IdInfo]
493 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
494 Generally speaking, a GlobalIdshas an *empty* SpecInfo. All their
495 RULES are contained in the globally-built rule-base. In principle,
496 one could attach the to M.f the RULES for M.f that are defined in M.
497 But we don't do that for instance declarations and so we just treat
500 The EXCEPTION is PrimOpIds, which do have rules in their IdInfo. That is
501 jsut for convenience really.
503 However, LocalIds may have non-empty SpecInfo. We treat them
505 a) they might be nested, in which case a global table won't work
506 b) the RULE might mention free variables, which we use to keep things alive
508 In TidyPgm, when the LocalId becomes a GlobalId, its RULES are stripped off
509 and put in the global list.
512 -- | Records the specializations of this 'Id' that we know about
513 -- in the form of rewrite 'CoreRule's that target them
517 VarSet -- Locally-defined free vars of *both* LHS and RHS
518 -- of rules. I don't think it needs to include the
520 -- Note [Rule dependency info] in OccurAnal
522 -- | Assume that no specilizations exist: always safe
523 emptySpecInfo :: SpecInfo
524 emptySpecInfo = SpecInfo [] emptyVarSet
526 isEmptySpecInfo :: SpecInfo -> Bool
527 isEmptySpecInfo (SpecInfo rs _) = null rs
529 -- | Retrieve the locally-defined free variables of both the left and
530 -- right hand sides of the specialization rules
531 specInfoFreeVars :: SpecInfo -> VarSet
532 specInfoFreeVars (SpecInfo _ fvs) = fvs
534 specInfoRules :: SpecInfo -> [CoreRule]
535 specInfoRules (SpecInfo rules _) = rules
537 -- | Change the name of the function the rule is keyed on on all of the 'CoreRule's
538 setSpecInfoHead :: Name -> SpecInfo -> SpecInfo
539 setSpecInfoHead fn (SpecInfo rules fvs)
540 = SpecInfo (map (setRuleIdName fn) rules) fvs
542 seqSpecInfo :: SpecInfo -> ()
543 seqSpecInfo (SpecInfo rules fvs) = seqRules rules `seq` seqVarSet fvs
546 %************************************************************************
548 \subsection[CG-IdInfo]{Code generator-related information}
550 %************************************************************************
553 -- CafInfo is used to build Static Reference Tables (see simplStg/SRT.lhs).
555 -- | Records whether an 'Id' makes Constant Applicative Form references
557 = MayHaveCafRefs -- ^ Indicates that the 'Id' is for either:
559 -- 1. A function or static constructor
560 -- that refers to one or more CAFs, or
562 -- 2. A real live CAF
564 | NoCafRefs -- ^ A function or static constructor
565 -- that refers to no CAFs.
568 -- | Assumes that the 'Id' has CAF references: definitely safe
569 vanillaCafInfo :: CafInfo
570 vanillaCafInfo = MayHaveCafRefs
572 mayHaveCafRefs :: CafInfo -> Bool
573 mayHaveCafRefs MayHaveCafRefs = True
574 mayHaveCafRefs _ = False
576 seqCaf :: CafInfo -> ()
577 seqCaf c = c `seq` ()
579 instance Outputable CafInfo where
582 ppCafInfo :: CafInfo -> SDoc
583 ppCafInfo NoCafRefs = ptext (sLit "NoCafRefs")
584 ppCafInfo MayHaveCafRefs = empty
587 %************************************************************************
589 \subsection[cpr-IdInfo]{Constructed Product Result info about an @Id@}
591 %************************************************************************
594 #ifdef OLD_STRICTNESS
595 -- | If the @Id@ is a function then it may have Constructed Product Result
596 -- (CPR) info. A CPR analysis phase detects whether:
598 -- 1. The function's return value has a product type, i.e. an algebraic type
599 -- with a single constructor. Examples of such types are tuples and boxed
602 -- 2. The function always 'constructs' the value that it is returning. It
603 -- must do this on every path through, and it's OK if it calls another
604 -- function which constructs the result.
606 -- If this is the case then we store a template which tells us the
607 -- function has the CPR property and which components of the result are
610 = NoCPRInfo -- ^ No, this function does not return a constructed product
611 | ReturnsCPR -- ^ Yes, this function returns a constructed product
613 -- Implicitly, this means "after the function has been applied
614 -- to all its arguments", so the worker\/wrapper builder in
615 -- WwLib.mkWWcpr checks that that it is indeed saturated before
616 -- making use of the CPR info
618 -- We used to keep nested info about sub-components, but
619 -- we never used it so I threw it away
621 -- | It's always safe to assume that an 'Id' does not have the CPR property
623 noCprInfo = NoCPRInfo
625 seqCpr :: CprInfo -> ()
626 seqCpr ReturnsCPR = ()
627 seqCpr NoCPRInfo = ()
629 ppCprInfo NoCPRInfo = empty
630 ppCprInfo ReturnsCPR = ptext (sLit "__M")
632 instance Outputable CprInfo where
635 instance Show CprInfo where
636 showsPrec p c = showsPrecSDoc p (ppr c)
640 %************************************************************************
642 \subsection[lbvar-IdInfo]{Lambda-bound var info about an @Id@}
644 %************************************************************************
647 -- | If the 'Id' is a lambda-bound variable then it may have lambda-bound
648 -- variable info. Sometimes we know whether the lambda binding this variable
649 -- is a \"one-shot\" lambda; that is, whether it is applied at most once.
651 -- This information may be useful in optimisation, as computations may
652 -- safely be floated inside such a lambda without risk of duplicating
654 data LBVarInfo = NoLBVarInfo -- ^ No information
655 | IsOneShotLambda -- ^ The lambda is applied at most once).
657 -- | It is always safe to assume that an 'Id' has no lambda-bound variable information
658 noLBVarInfo :: LBVarInfo
659 noLBVarInfo = NoLBVarInfo
661 hasNoLBVarInfo :: LBVarInfo -> Bool
662 hasNoLBVarInfo NoLBVarInfo = True
663 hasNoLBVarInfo IsOneShotLambda = False
665 seqLBVar :: LBVarInfo -> ()
666 seqLBVar l = l `seq` ()
668 pprLBVarInfo :: LBVarInfo -> SDoc
669 pprLBVarInfo NoLBVarInfo = empty
670 pprLBVarInfo IsOneShotLambda = ptext (sLit "OneShot")
672 instance Outputable LBVarInfo where
675 instance Show LBVarInfo where
676 showsPrec p c = showsPrecSDoc p (ppr c)
680 %************************************************************************
682 \subsection{Bulk operations on IdInfo}
684 %************************************************************************
687 -- | This is used to remove information on lambda binders that we have
688 -- setup as part of a lambda group, assuming they will be applied all at once,
689 -- but turn out to be part of an unsaturated lambda as in e.g:
691 -- > (\x1. \x2. e) arg1
692 zapLamInfo :: IdInfo -> Maybe IdInfo
693 zapLamInfo info@(IdInfo {occInfo = occ, newDemandInfo = demand})
694 | is_safe_occ occ && is_safe_dmd demand
697 = Just (info {occInfo = safe_occ, newDemandInfo = Nothing})
699 -- The "unsafe" occ info is the ones that say I'm not in a lambda
700 -- because that might not be true for an unsaturated lambda
701 is_safe_occ (OneOcc in_lam _ _) = in_lam
702 is_safe_occ _other = True
704 safe_occ = case occ of
705 OneOcc _ once int_cxt -> OneOcc insideLam once int_cxt
708 is_safe_dmd Nothing = True
709 is_safe_dmd (Just dmd) = not (isStrictDmd dmd)
713 -- | Remove demand info on the 'IdInfo' if it is present, otherwise return @Nothing@
714 zapDemandInfo :: IdInfo -> Maybe IdInfo
715 zapDemandInfo info@(IdInfo {newDemandInfo = dmd})
716 | isJust dmd = Just (info {newDemandInfo = Nothing})
717 | otherwise = Nothing
721 zapFragileInfo :: IdInfo -> Maybe IdInfo
722 -- ^ Zap info that depends on free variables
724 = Just (info `setSpecInfo` emptySpecInfo
725 `setUnfoldingInfo` noUnfolding
726 `setOccInfo` if isFragileOcc occ then NoOccInfo else occ)
731 %************************************************************************
733 \subsection{TickBoxOp}
735 %************************************************************************
740 -- | Tick box for Hpc-style coverage
742 = TickBox Module {-# UNPACK #-} !TickBoxId
744 instance Outputable TickBoxOp where
745 ppr (TickBox mod n) = ptext (sLit "tick") <+> ppr (mod,n)