Expand `exprOkForSpeculation` to include superclass selection
Problem
When debugging #22717 (closed) I happened across this code
class (f ~ CalledFunction g, r ~ CodeResult g, g ~ CallerFunction r f) =>
CallArgs r f g where
LLVM.Core.Instructive.call :: CallArgs r f g => blah
The function call
end up looking like this
call
= \ (@r_a1jZ)
(@f_a1k0)
(@g_a1k1)
($dCallArgs_a1k2 :: CallArgs r_a1jZ f_a1k0 g_a1k1)
(eta_B0 :: Value (FunPtr f_a1k0)) ->
case ghc-prim:GHC.Types.eq_sel
@(*)
@g_a1k1
@(CallerFunction r_a1jZ f_a1k0)
(LLVM.Core.Instructive.$p3CallArgs
@r_a1jZ @f_a1k0 @g_a1k1 $dCallArgs_a1k2)
of co_a1S8
{ __DEFAULT ->
case ghc-prim:GHC.Types.eq_sel
@(*)
@r_a1jZ
@(CodeResult g_a1k1)
(LLVM.Core.Instructive.$p2CallArgs
@r_a1jZ @f_a1k0 @g_a1k1 $dCallArgs_a1k2)
of co_a1S6
{ __DEFAULT ->
case ghc-prim:GHC.Types.eq_sel
@(*)
@f_a1k0
@(CalledFunction g_a1k1)
(LLVM.Core.Instructive.$p1CallArgs
@r_a1jZ @f_a1k0 @g_a1k1 $dCallArgs_a1k2)
of co_a1S4
{ __DEFAULT ->
doCall ...}}}
-- Note: GHC.Types.eq_sel :: (a ~ b) -> (a ~# b)
-- Inside GHC this is eqSCSelId
--
-- $p1CallArgs :: CallArgs r f g -> (f ~ CalledFunction g)
-- This is one of the three superclass selectors for CallArgs
None of those co_a1S8
coercions are used; yet this code persists through the entire compilation pipeline.
Diagnosis
Where does it come from? Answer: the superclass-expansion of Givens. We have [G] d : CallArgs r f g
, and
superclass expansion gives
d2 = $p1CallArgs d
[G] d2 :: f ~ CalledFunction g -- And two more
co = eq_sel d2
[G] co :: f ~# CalledFunction g -- And two more
We get a case
expression, not a let, for the (eq_sel d2)
because it doesn't look ok-for-speculation,
so we can't make a let
.
It happens that these Givens are not used in solving any of the constraints in function call
, but
we nevertheless generate evidence bindings for them.
The constraint solver goes to some effort to eliminate dead evidence: see Note [Delete dead Given evidence bindings]
in GHC.Tc.Solver. But this isn't quite enough: see #15025 (closed). Indeed the example I found in #22717 (closed) has the same cause as #15025 (closed).
Why doesn't the Simplifier get rid of them?
Alas these (useless) case
expressions are not discarded because GHC doesn't consider
eq_sel d
to be ok-for-side-effects. Here's the code in GHC.Core.Opt.Simplify.Iteration:
rebuildCase env scrut case_bndr alts@[Alt _ bndrs rhs] cont
| is_plain_seq -- case e of r -> blah
, exprOkForSideEffects scrut
= simplExprF env rhs cont
And indeed, if we could pass bottom to call
for its dictionary argument,
it would be wrong to discard it. But in fact we can discard it, because a dictionary
is never bottom. (That is a global invariant of Core, exploited by -XDictsStrict
which
we should document better.)
So in fact eq_sel ($p1CallArgs d)
is guaranted to terminate so in fact we could have
generated a let
not a case
in the first place.
Solution
Consider a class op selection (op d)
, where d
is some dictionary,
and the result is a coercion (t1 ~# t2)
. Then this expression should
be ok-for-speculation: since d
is a dictionary, it can't be bottom.