-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Make implicit function variables safe as arguments (fixes #10889) #13750
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
Conversation
… contextual closures if they wrap a context function of the expected type. Add a runtime test to probe for stackoverflow if this optimization is not performed.
CLA is now signed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly stylistic comments, and some explanatory comments should be added. Otherwise code LGTM.
import reporting.trace | ||
import config.Printers.{ transforms => debug } | ||
|
||
/** Abstract base class of ByNameClosures and ElimByName, factoring out the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy paste error here. The phase needs an detailed explanation.
|
||
def transformArg(arg: Tree, formal: Type): Tree = { | ||
val veryFormal = formal.widenDealias | ||
if(defn.isContextFunctionType(veryFormal) && untpd.isContextualClosure(arg)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Scala 3 conditionals in new code. Never use if(
without a space.
trace(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) { | ||
|
||
def transformArg(arg: Tree, formal: Type): Tree = { | ||
val veryFormal = formal.widenDealias |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why veryFormal
? Maybe formalw
, or simply formal1
?
@@ -73,6 +73,7 @@ class Compiler { | |||
new ProtectedAccessors, // Add accessors for protected members | |||
new ExtensionMethods, // Expand methods of value classes with extension methods | |||
new UncacheGivenAliases, // Avoid caching RHS of simple parameterless given aliases | |||
new ElimRedundantContextualClosure, // Unwrapped context closures if the contents is already a context closure of compatible type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd shorten the name to ElimContextClosures
. Also, the comment should be active form.
new ElimRedundantContextualClosure, // Unwrapped context closures if the contents is already a context closure of compatible type | |
new ElimContextClosures, // Unwrap context closure arguments that contain already a context closure of compatible type |
new ElimRedundantContextualClosure, // Unwrapped context closures if the contents is already a context closure of compatible type | |
new ElimRedundantContextualClosure, // Unwrapped context closures if the contents is already a context closure of compatible type |
val bodyIsContextual = defn.isContextFunctionType(underlyingBodyType) | ||
val bodyTypeMatches = TypeComparer.isSubType(underlyingBodyType, veryFormal) | ||
if(bodyIsContextual && bodyTypeMatches) { | ||
body |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop the redundant braces. We tend to use Scala 3 style throughout in new code.
test performance please |
Is there a standard methodology I should follow for the performance testing? |
That was a command to the bot 😀 Performance test should start automatically. But something seems to be wrong again /cc @anatoliykmetyuk |
I believe all comments have now been addressed. =) |
test performance please |
performance test scheduled: 1 job(s) in queue, 0 running. |
Looks like the bot crashed again. Last fix wasn't addressing the current cause of crash. I've restarted the bot and will investigate more after the weekend. |
Performance test finished successfully: Visit https://dotty-bench.epfl.ch/13750/ to see the changes. Benchmarks is based on merging with master (54ff628) |
compiler/src/dotty/tools/dotc/transform/ElimContextClosures.scala
Outdated
Show resolved
Hide resolved
compiler/src/dotty/tools/dotc/transform/ElimContextClosures.scala
Outdated
Show resolved
Hide resolved
trace(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) { | ||
|
||
def transformArg(arg: Tree, formal: Type): Tree = { | ||
val formal1 = formal.widenDealias |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, widen
is enough here. isContextFunction
and isSubType
already do dealiasing. (It's better to be consistent here since otherwise the next people looking at the compiler see multiple styles and get confused).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably this applies to underlyingBodyType
as well as formal1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorted in 009f18b.
def transformArg(arg: Tree, formal: Type): Tree = { | ||
val formal1 = formal.widenDealias | ||
if defn.isContextFunctionType(formal1) && untpd.isContextualClosure(arg) then | ||
val body = unsplice(closureBody(arg)) match { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to start like this
unsplice(closureBody(arg)) match
case Apply(Select(body, nme.apply, _) =>
... // transformation code
case _ =>
arg
If the argument is not a nested closure there's no need to go through the following tests, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
closureBody
returns arg
if arg
is not a closure, so we would have to essentially reimplement the closureBody
logic inline here to make sure we aren't destructuring a random Apply
for no reason. I assumed checking the outer structure first with this if
would be more efficient / cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I meant: after the if defn.isContextFunctionType
..., instead of val body = ...
continue with what I suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I see now, yes. Should be addressed in 009f18b.
Comment formatting + typos. Co-authored-by: odersky <[email protected]>
@odersky - I believe all requested changes have been addressed. |
// (1 byte / frame is conservative even for a z80) | ||
retryN(maxStackSize)(testTxn.asInstanceOf[AtomicOp[Boolean]]) == safeRetryN(maxStackSize)(testTxn) | ||
} catch { | ||
case e:StackOverflowError => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it easier to just probe stack depth with new Throwable().getStackTrace
? for n
and n+1
recursions.
(Generally wary of tests for SOE and OOM.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I see what you have in mind, can you be a little bit more explicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apologies in advance if I'm missing the whole point, I'm still reading the issue. I was thinking of https://github.com/scala/scala/blob/2.13.x/test/junit/scala/collection/IteratorTest.scala#L36 although counting frames is subject to optimizations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sure, we could have the return value from testTxn
be the current stack depth and then check retryN
with different iteration counts. Happy to do that if it's preferable.
Tests are failing after 009f18b, so this needs to be addressed. |
@odersky - do you have an alternative hypothesis as to the cause, besides one of those |
No did not look into it
On Fri, 3 Dec 2021 at 17:17, Thomas Dickerson ***@***.***> wrote:
@odersky <https://github.com/odersky> - do you have an alternative
hypothesis as to the cause, besides one of those widenDealiases was
actually needed?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#13750 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGCKVQHAQ5IEPLMOUU627TUPDUTJANCNFSM5GAP3GAQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
--
Martin Odersky
Professor, Programming Methods Group (LAMP)
Faculty IC, EPFL
Station 14, Lausanne, Switzerland
|
We seem to have deeper problems here. I rebased the PR to current master but several tests fail, including run/tagless.scala. And that holds for all commits, not just the last ones. |
Actually, I took a look and will follow up the PR. The current solution strips too much. |
This could be generalized. We could add a general form of eta-reduction
if |
In https://github.com/lampepfl/dotty/blob/master/tests/pos/i2671.scala, checking The curious one is The change for CBN was to defer evaluation of the arg; the feature request here is "just an optimization". But I'm willing to call it eta-reduction. The missed opportunity in Wonder Woman: 1984 was not giving Diana an assistant at the museum named "Etta Reduction". |
Eta reduction only applies if |
Fixes scala#10889. Alternative to scala#13750, from which the test is taken.
Fixes scala#10889. Alternative to scala#13750, from which the test is taken.
Address #10889 by adding an optimizer pass to remove synthesized contextual closures if they wrap a context function of the expected type. Add a runtime test to probe for stackoverflow if this optimization is not performed.
Fixes #10889