-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Inliner fails to properly reduce pure case classes in a few situations #8306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I found an extra case under the same theme: When the macro is accessed via the cake patterntrait Cake {
case class A(i: Int)
inline def dummy: Int =
inline A(3) match {
case A(i) => i
}
}
object Test extends Cake {
println(code"${ dummy }")
} Result: val Cake_this : Test.type = this
{
val $scrutinee1 = Cake_this.A(3)
val i : 3 = 3 // notice the extraction does actually work...
// problem is a lot of stuff is left after
i
} Note: the same macro definitions reduce properly when accessed directly. |
I've discovered that the cases where Actually, there is not a single case where the construction of The reason for this is the purity check - the case class constructions are considered impure and thus not considered for removal by Given my interest in this issue is precisely because I want all that redundant code to go away, I will try to change that and see what happens. That said, I'm almost done fixing the other logic bugs causing most of the cases in this issue to not even appear to work. For ease of reviewing I will probably make 2 PRs, one with the little inliner logic fixes and one with whatever comes of my attempts at tweaking the purity checker. I'm learning all this as I go, so comments / criticism are welcome (especially if I missed some tricky internal compiler semantics!). |
One more comment before I turn in for the night: what I found from some experiments with the purity checking code. It seems safe to add one extra case to I found an existing case that covers direct constructor calls to classes that satisfy Perhaps this does not need 2 PRs in the end - it's much less of a breaking change than I feared. TODOs I'm leaving for tomorrow:
|
I take back my previous update about just declaring case class applications to be pure... they're not, because accessing the apply method can cause object initialisation. 😢 So in actuality this change shouldn't be touching the purity checker - it should be special-casing these purity checks only for the inliner. As such I'll be refactoring my change into the inliner, calling it On the bright side, once the inliner thinks case class application is pure (and no-one else does!) all the other problems in this issue seem to have working fixes. The cake pattern case is fixed by the case class application special case, and causing case class projections to inline without a match was not a particularly problematic change. |
…ass applications in various situations This is a collection of related changes, all to ensure that the inliner is capable of properly eliding case class constructions in various situations. Specific intended changes: - allow NewInstance.unapply to look past type ascriptions - change all purity checks to consider, for the inliner only, case class applications (when the apply method is synthetic and the case class has no constructor body) pure, or "elideable", despite the fact that the operation is almost always idempotent in the general case. - make reduceInlineMatch's reduceSubPatterns procedure set the defTree for the accessor projections it generates, so nested Unapply patterns can look in defTree to find and possible inline the appropriate subtree of the scrutinee expression - make the typedSelect override able to reduce projections without a corresponding inline match, so that if inlining produces SomeCaseClass(x=3).x the case class construction has a change to be elided (only in an inline context) This commit also includes a series of test cases which use compiletime.show to pretty-print the resulting inlined AST of a series of inline expansions. To avoid cases where a malformed AST pretty-prints but causes bad codegen, the computed run-time value is also printed. One last thing I tested manually was that the bytecode matched the pretty-printing. Mid-work on this commit I found that the pretty printer was hiding several cases where redundant code was left in but not showing up when pretty-printed. This is partially tested by the case where full inlining is not possible, which would also include a redundant binding for the scrutinee if that issue were still present.
…ass applications in various situations This is a collection of related changes, all to ensure that the inliner is capable of properly eliding case class constructions in various situations. Specific intended changes: - allow NewInstance.unapply to look past type ascriptions - change all purity checks to consider, for the inliner only, case class applications (when the apply method is synthetic and the case class has no constructor body) pure, or "elideable", despite the fact that the operation is almost always idempotent in the general case. - make reduceInlineMatch's reduceSubPatterns procedure set the defTree for the accessor projections it generates, so nested Unapply patterns can look in defTree to find and possible inline the appropriate subtree of the scrutinee expression - make the typedSelect override able to reduce projections without a corresponding inline match, so that if inlining produces SomeCaseClass(x=3).x the case class construction has a change to be elided (only in an inline context) This commit also includes a series of test cases which use compiletime.show to pretty-print the resulting inlined AST of a series of inline expansions. To avoid cases where a malformed AST pretty-prints but causes bad codegen, the computed run-time value is also printed. One last thing I tested manually was that the bytecode matched the pretty-printing. Mid-work on this commit I found that the pretty printer was hiding several cases where redundant code was left in but not showing up when pretty-printed. This is partially tested by the case where full inlining is not possible, which would also include a redundant binding for the scrutinee if that issue were still present.
Fix #8306: Ensure the inliner can elide effectively pure case class applications in various situations
Setup:
Note: results are paraphrased, removing some of the more verbose types and qualifications. Assume all the code snippets below are inside some arbitrary inline method that has
A
andB
in scope.The expected result for all cases is:
3
Inline match around type ascriptions
Result:
Inline match with nested patterns
Result:
Notice how it keeps
$scrutinee1
around despite no references to it, which might be a bug on its own.Projecting without an inline match
Result:
It's unclear if this last one is by design, but since this kind of compile-time case class manipulation/destructuring feels like constant folding (and basically is), I've included it.
The text was updated successfully, but these errors were encountered: