Honour INLINE pragmas on 0-arity bindings
Currently if we see
x = factorial 200
{-# INLINE x #-}
f y = ...x...
we won't inline x
, lest we duplicate the work of factorial 200
. But this caution has some bad consequences:
- Suppose
x
is used exactly once, not inside a lambda, thus
x = blah
{-# INLINE x #-}
g = ...x...
Then, if there is no INLINE pragma,
x
will get inlined (bypreInlineUnconditionally
. But if there is an INLINE pragma, currentlyx
is not inlined bypreInlineUnconditionally
: seeNote [Stable unfoldings and preInlineUnconditionally]
inSimplUtils
. This is insane!
- INLINE says "inline me at every saturated call", where "saturated" is determined by the number of arguments syntactically to the left of the "=" in the source bindings. In this case, there are no arguments to the left, so every occurrence is saturated. So it's inconsistent not to inline.
- Occasionally it's very important to inline
x
: see Trac #15519 (closed) for a real-world example. Ignoring the users explicit instruction to do so seems silly.
Bottom line: if a 0-ary binding has an INLINE pragma, I think we should inline it at every use site
- Regardless of the work duplication
- Including inside lambdas
Note, however, that there is a real risk that full laziness will float it right back out again. Consider again
x = factorial 200
{-# INLINE x #-}
f y = ...x...
After inlining we get
f y = ...(factorial 200)...
but it's entirely possible that full laziness will do
lvl23 = factorial 200
f y = ...lvl23...
That's a problem for another day. Presumably the reason the user wanted to inline it was to get some rule to fire, and this change gives at least some chance that will happen, and makes INLINE behave consistently.