-
Notifications
You must be signed in to change notification settings - Fork 396
Allow Return
arg to be a void
if the target Labeled
is a void
.
#5074
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
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.
Only questions :P
linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala
Show resolved
Hide resolved
case Lhs.ReturnFromFunction => | ||
js.Block( | ||
transformStat(rhs, tailPosLabels = Set.empty), | ||
js.Return(js.Undefined())) |
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.
It feels odd that we do not have tail label optimization here, but IIUC that's on par with the status quo.
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.
We can't have tail label optimization here. Indeed, there is control-flow-disrupting code after the transformed rhs
, namely this js.Return(js.Undefined())
. The labels that are in tail position after the js.Return(js.Undefined())
are definitely not in tail position of the rhs
.
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, sorry, I wasn't clear. I understand why tailPosLabels = Set.empty
is necessary.
What I didn't get is why there is no attempt to eliminate the return we are emitting itself here.
But I think now I understand: We only get here if an actual label is transformed to an Lhs.ReturnFromFunction
. If the function we are translating has void return type (and no top-level label), we invoke transformStat
immediately.
Maybe that warrants a comment :P
linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala
Show resolved
Hide resolved
037e161
to
5a9dd4e
Compare
Updated with the requested comment + commit message explanation. |
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.
Just a suggested clarification of a comment.
/* If we get here, it is because desugarToFunctionInternal() | ||
* found a top-level Labeled and eliminated it. Therefore, unless | ||
* we're mistaken, by construction we cannot be in tail position | ||
* of the whole function. That means there is no point trying to |
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.
* of the whole function. That means there is no point trying to | |
* of the whole function (otherwise doReturnToLabel would have | |
* eliminated the lhs). That means there is no point trying to |
Previously, even if the target label of a `Return` declared a `void` result type, the argument to the `Return` had to be an expression, with a non-`void` type. Because of that rule, we generated fake `Undefined()` arguments to the `Return`s. In this commit, we remove that restriction. This simplifies the IR specification and removes some ad hoc code paths to generate the fake `Undefined()`. We do have to add some handling in the JS function emitter. The Wasm function emitter requires no change. The changes in `doReturnToLabel()` are necessary to maintain the status quo in terms of the emitted JS. My understanding is that before, we would get a lot of `Block(stats, Return(Undefined))` which are now `Return(Block(stats))`. If the `stats` contain `If`s and other branches, the new `Return` can be pushed down a lot more. When it wasn't pushed down, we would have regular fall-through behavior without `js.Break`s. Now with the `Return`s pushed down, we get a lot of `js.Break`s that are not actually necessary. The new optimization in `doReturnToLabel()` removes them.
5a9dd4e
to
bb4f6da
Compare
And port the changes that were made to the compiler backend. Most nobably, the changes from the following upstream PRs: * Introduce non-nullable reference types in the IR. scala-js/scala-js#5018 * Opt: Remove useless *Ident indirections in the IR model. scala-js/scala-js#5092 * Merge the IR node This into VarRef, with a magic LocalName. scala-js/scala-js#5090 * Merge several IR nodes into UnaryOp. scala-js/scala-js#5088 * Restrict usages of StoreModule even further. scala-js/scala-js#5059 * Allow Return arg to be a void if the target Labeled is a void. scala-js/scala-js#5074 * Rename NoType to VoidType and print it as "void". scala-js/scala-js#5061
And port the changes that were made to the compiler backend. Most notably, the changes from the following upstream PRs: * Introduce non-nullable reference types in the IR. scala-js/scala-js#5018 * Opt: Remove useless *Ident indirections in the IR model. scala-js/scala-js#5092 * Merge the IR node This into VarRef, with a magic LocalName. scala-js/scala-js#5090 * Merge several IR nodes into UnaryOp. scala-js/scala-js#5088 * Restrict usages of StoreModule even further. scala-js/scala-js#5059 * Allow Return arg to be a void if the target Labeled is a void. scala-js/scala-js#5074 * Rename NoType to VoidType and print it as "void". scala-js/scala-js#5061
And port the changes that were made to the compiler backend. Most notably, the changes from the following upstream PRs: * scala-js/scala-js#5018 * scala-js/scala-js#5092 * scala-js/scala-js#5090 * scala-js/scala-js#5088 * scala-js/scala-js#5059 * scala-js/scala-js#5074 * scala-js/scala-js#5061
Previously, even if the target label of a
Return
declared avoid
result type, the argument to theReturn
had to be an expression, with a non-void
type. Because of that rule, we generated fakeUndefined()
arguments to theReturn
s.In this commit, we remove that restriction. This simplifies the IR specification and removes some ad hoc code paths to generate the fake
Undefined()
. We do have to add some handling in the JS function emitter. The Wasm function emitter requires no change.The changes in
doReturnToLabel()
are necessary to maintain the status quo in terms of the emitted JS. My understanding is that before, we would get a lot ofBlock(stats, Return(Undefined))
which are nowReturn(Block(stats))
. If thestats
containIf
s and other branches, the newReturn
can be pushed down a lot more. When it wasn't pushed down, we would have regular fall-through behavior withoutjs.Break
s. Now with theReturn
s pushed down, we get a lot ofjs.Break
s that are not actually necessary. The new optimization indoReturnToLabel()
removes them.