Reduce Boolean Blindness
Motivation
There are many places in GHC's code base that are prone to boolean blindness. Here's BasicTypes.OccInfo
, for example (this situation has been fixed in !2210 (closed), but I bet there are many other instances):
-- | identifier Occurrence Information
data OccInfo
= ManyOccs { occ_tail :: !TailCallInfo }
| IAmDead
| OneOcc { occ_in_lam :: !InsideLam
, occ_one_br :: !OneBranch
, occ_int_cxt :: !InterestingCxt
, occ_tail :: !TailCallInfo }
-- ^ Occurs exactly once (per branch), not inside a rule
-- | This identifier breaks a loop of mutually recursive functions. The field
-- marks whether it is only a loop breaker due to a reference in a rule
| IAmALoopBreaker { occ_rules_only :: !RulesOnly
, occ_tail :: !TailCallInfo }
type RulesOnly = Bool
-- | Interesting Context
type InterestingCxt = Bool -- True <=> Function: is applied
-- Data value: scrutinised by a case with
-- at least one non-DEFAULT branch
-- | Inside Lambda
type InsideLam = Bool -- True <=> Occurs inside a non-linear lambda
-- Substituting a redex for this occurrence is
-- dangerous because it might duplicate work.
insideLam, notInsideLam :: InsideLam
insideLam = True
notInsideLam = False
type OneBranch = Bool -- True <=> Occurs in only one case branch
-- so no code-duplication issue to worry about
oneBranch, notOneBranch :: OneBranch
oneBranch = True
notOneBranch = False
data TailCallInfo = AlwaysTailCalled JoinArity -- See Note [TailCallInfo]
| NoTailCallInfo
Not only do booleans force us to repeat the same documentation all over the place, also we define bindings like oneBranch/notOneBranch
anyway to make our lives easier.
Proposal
Simply define the proper ADTs, like we do for TailCallInfo
(which notably gets by without any dead documentation) or TopLevelFlag
. Provide a conversion function to Bool
in cases where we want that.