Arity decrease through eta reduction
While working on !8277 (merged)/#20836 (closed) I came up with the following program:
import GHC.Exts
f, g :: a -> a
f = g
g x = f x
{-# NOINLINE f #-}
{-# NOINLINE g #-}
main = lazy g `seq` putStrLn "done"
(The lazy is just so that we don't discard the seq.)
The program should print done and return rapidly. Yet if you compile it with optimisations, you'll see <<loop>> instead.
The reason is that GHC eta-reduces \x -> f x to f, because f has arity 1 (just like g). But in doing so, it reduces the arity of g and consequently of f to 0! Immediately after in the next
Rec {
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
f [InlPrag=NOINLINE] :: forall a. a -> a
[LclId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
f = g
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
g [InlPrag=NOINLINE, Occ=LoopBreaker] :: forall a. a -> a
[LclId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)}]
g = f
end Rec }
And that of course lets us fall into a black hole if we evaluate g, when before it would stop at the lambda.
(Not only has arity decreased to 0, we also keep saying Value=True for a very long time, hence the seq won't survive even after we eta-expanded. That's probably an issue that wouldn't arise if we didn't eta-reduce in the first place.)
In !8277 (comment 432209), @simonpj suggests
A plausible solution is to retreat on
Note [Arity robustness]and zap arity info inzapFragileIdInfo; test for perf regressions (incl nofib).
We should do that.