+%************************************************************************
+%* *
+\subsection{Step 1: finding externals}
+%* *
+%************************************************************************
+
+\begin{code}
+findExternalSet :: [CoreBind] -> [IdCoreRule]
+ -> IdEnv Bool -- In domain => external
+ -- Range = True <=> show unfolding
+ -- Step 1 from the notes above
+findExternalSet binds orphan_rules
+ = foldr find init_needed binds
+ where
+ orphan_rule_ids :: IdSet
+ orphan_rule_ids = unionVarSets [ ruleSomeFreeVars isLocalId rule
+ | (_, rule) <- orphan_rules]
+ init_needed :: IdEnv Bool
+ init_needed = mapUFM (\_ -> False) orphan_rule_ids
+ -- The mapUFM is a bit cheesy. It is a cheap way
+ -- to turn the set of orphan_rule_ids, which we use to initialise
+ -- the sweep, into a mapping saying 'don't expose unfolding'
+ -- (When we come to the binding site we may change our mind, of course.)
+
+ find (NonRec id rhs) needed
+ | need_id needed id = addExternal (id,rhs) needed
+ | otherwise = needed
+ find (Rec prs) needed = find_prs prs needed
+
+ -- For a recursive group we have to look for a fixed point
+ find_prs prs needed
+ | null needed_prs = needed
+ | otherwise = find_prs other_prs new_needed
+ where
+ (needed_prs, other_prs) = partition (need_pr needed) prs
+ new_needed = foldr addExternal needed needed_prs
+
+ -- The 'needed' set contains the Ids that are needed by earlier
+ -- interface file emissions. If the Id isn't in this set, and isn't
+ -- exported, there's no need to emit anything
+ need_id needed_set id = id `elemVarEnv` needed_set || isExportedId id
+ need_pr needed_set (id,rhs) = need_id needed_set id
+
+addExternal :: (Id,CoreExpr) -> IdEnv Bool -> IdEnv Bool
+-- The Id is needed; extend the needed set
+-- with it and its dependents (free vars etc)
+addExternal (id,rhs) needed
+ = extendVarEnv (foldVarSet add_occ needed new_needed_ids)
+ id show_unfold
+ where
+ add_occ id needed = extendVarEnv needed id False
+ -- "False" because we don't know we need the Id's unfolding
+ -- We'll override it later when we find the binding site
+
+ new_needed_ids | opt_OmitInterfacePragmas = emptyVarSet
+ | otherwise = worker_ids `unionVarSet`
+ unfold_ids `unionVarSet`
+ spec_ids
+
+ idinfo = idInfo id
+ dont_inline = isNeverInlinePrag (inlinePragInfo idinfo)
+ loop_breaker = isLoopBreaker (occInfo idinfo)
+ bottoming_fn = isBottomingStrictness (strictnessInfo idinfo)
+ spec_ids = rulesRhsFreeVars (specInfo idinfo)
+ worker_info = workerInfo idinfo
+
+ -- Stuff to do with the Id's unfolding
+ -- The simplifier has put an up-to-date unfolding
+ -- in the IdInfo, but the RHS will do just as well
+ unfolding = unfoldingInfo idinfo
+ rhs_is_small = not (neverUnfold unfolding)
+
+ -- We leave the unfolding there even if there is a worker
+ -- In GHCI the unfolding is used by importers
+ -- When writing an interface file, we omit the unfolding
+ -- if there is a worker
+ show_unfold = not bottoming_fn && -- Not necessary
+ not dont_inline &&
+ not loop_breaker &&
+ rhs_is_small && -- Small enough
+ okToUnfoldInHiFile rhs -- No casms etc
+
+ unfold_ids | show_unfold = exprSomeFreeVars isLocalId rhs
+ | otherwise = emptyVarSet
+
+ worker_ids = case worker_info of
+ HasWorker work_id _ -> unitVarSet work_id
+ otherwise -> emptyVarSet
+\end{code}