Allow rules to fire on workers / WW can break rule matching.
The problem
Currently rules only are recognized for the wrapper for any function that has been WWed.
This can cause rules to fail to fire, in cases where the wrapper is inlined before rules triggered.
A basic example
That is a rule like plus (0,y) = y
will not fire on an application of $wplus 0 x
.
This could for example arise if we the zero becomes only visible late once other things have inlined and simplified.
This could in theory be solved.
At the time of the construction of a worker it wouldn't be hard to also construct "reverse-workers". A way to construct a wrapper application from a worker application essentially.
To do so we need to store with the worker:
- The name of the wrapper
- A way to construct a wrapper application from the worker.
For a full example imagine that we have:
{-# NOINLINE plus #-}
plus (x,y) = case $wplus x y of r -> I# r
$wplus x y = x +# y
If the simplifier comes across $wplus 0 x
we have to reconstruct the original arguments of the wrapper from the application, and have to account for CPR. What is needed for this to work:
- We need to store what the wrapper was so that relevant rules can be found.
- We need a function of
[CoreArg] -> [CoreArg]
that when applied to the workers args gives us the wrappers args. Conceptually simple but perhaps hard to encode in interface files. - We need to apply the cpr part of the wrapper to the final RHS.
For $wplus
that would would be:
(plus
,(\[x,y] -> [(,) (type x) (type y) x y)]
,\rhs -> (case rhs of I# x -> x)
Encoding the construction function for arguments and the cpr wrapper in interface files is probably hard. We would also need to execute them whenever we want to check if rules apply to a worker so this could be rather costly.
I'm not sure if this would be worthwhile. It would certainly be a larger project and I have no plans to dive into this any further.