-
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1538,25 +1538,30 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { | |
|
||
def doReturnToLabel(l: LabelIdent): js.Tree = { | ||
val newLhs = env.lhsForLabeledExpr(l) | ||
val body = pushLhsInto(newLhs, rhs, Set.empty) | ||
if (newLhs.hasNothingType) { | ||
/* A touch of peephole dead code elimination. | ||
* This is actually necessary to avoid dangling breaks to eliminated | ||
* labels, as in issue #2307. | ||
*/ | ||
body | ||
pushLhsInto(newLhs, rhs, tailPosLabels) | ||
} else if (tailPosLabels.contains(l.name)) { | ||
body | ||
} else if (env.isDefaultBreakTarget(l.name)) { | ||
js.Block(body, js.Break(None)) | ||
} else if (env.isDefaultContinueTarget(l.name)) { | ||
js.Block(body, js.Continue(None)) | ||
pushLhsInto(newLhs, rhs, tailPosLabels) | ||
} else { | ||
usedLabels += l.name | ||
val transformedLabel = Some(transformLabelIdent(l)) | ||
val jump = | ||
if (env.isLabelTurnedIntoContinue(l.name)) js.Continue(transformedLabel) | ||
else js.Break(transformedLabel) | ||
val body = pushLhsInto(newLhs, rhs, Set.empty) | ||
|
||
val jump = if (env.isDefaultBreakTarget(l.name)) { | ||
js.Break(None) | ||
} else if (env.isDefaultContinueTarget(l.name)) { | ||
js.Continue(None) | ||
} else { | ||
usedLabels += l.name | ||
val transformedLabel = Some(transformLabelIdent(l)) | ||
if (env.isLabelTurnedIntoContinue(l.name)) | ||
js.Continue(transformedLabel) | ||
else | ||
js.Break(transformedLabel) | ||
} | ||
|
||
js.Block(body, jump) | ||
} | ||
} | ||
|
@@ -1597,7 +1602,10 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { | |
case Lhs.Assign(lhs) => | ||
doAssign(lhs, rhs) | ||
case Lhs.ReturnFromFunction => | ||
js.Return(transformExpr(rhs, env.expectedReturnType)) | ||
if (env.expectedReturnType == VoidType) | ||
js.Block(transformStat(rhs, tailPosLabels = Set.empty), js.Return(js.Undefined())) | ||
else | ||
js.Return(transformExpr(rhs, env.expectedReturnType)) | ||
case Lhs.Return(l) => | ||
doReturnToLabel(l) | ||
case Lhs.Throw => | ||
|
@@ -2016,29 +2024,44 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { | |
redo(CreateJSClass(className, newCaptureValues))(env) | ||
} | ||
|
||
case _ => | ||
if (lhs == Lhs.Discard) { | ||
/* Go "back" to transformStat() after having dived into | ||
* expression statements. Remember that Lhs.Discard is a trick that | ||
* we use to "add" all the code of pushLhsInto() to transformStat(). | ||
*/ | ||
rhs match { | ||
case _:Skip | _:VarDef | _:Assign | _:While | | ||
_:Debugger | _:JSSuperConstructorCall | _:JSDelete | | ||
_:StoreModule | Transient(_:SystemArrayCopy) => | ||
transformStat(rhs, tailPosLabels) | ||
case _ => | ||
throw new IllegalArgumentException( | ||
"Illegal tree in JSDesugar.pushLhsInto():\n" + | ||
"lhs = " + lhs + "\n" + | ||
"rhs = " + rhs + " of class " + rhs.getClass) | ||
} | ||
} else { | ||
throw new IllegalArgumentException( | ||
"Illegal tree in JSDesugar.pushLhsInto():\n" + | ||
"lhs = " + lhs + "\n" + | ||
"rhs = " + rhs + " of class " + rhs.getClass) | ||
// Statement-only trees | ||
|
||
case _:Skip | _:VarDef | _:Assign | _:While | _:Debugger | | ||
_:JSSuperConstructorCall | _:JSDelete | _:StoreModule | | ||
Transient(_:SystemArrayCopy) => | ||
/* Go "back" to transformStat() after having dived into | ||
* expression statements. This can only happen for Lhs.Discard and | ||
* for Lhs.Return's whose target is a statement. | ||
*/ | ||
lhs match { | ||
case Lhs.Discard => | ||
transformStat(rhs, tailPosLabels) | ||
case Lhs.ReturnFromFunction => | ||
/* 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 (otherwise doReturnToLabel would have | ||
* eliminated the lhs). That means there is no point trying to | ||
* avoid the `js.Return(js.Undefined())`. | ||
*/ | ||
js.Block( | ||
transformStat(rhs, tailPosLabels = Set.empty), | ||
js.Return(js.Undefined())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, sorry, I wasn't clear. I understand why 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 Maybe that warrants a comment :P |
||
case Lhs.Return(l) => | ||
doReturnToLabel(l) | ||
|
||
case _:Lhs.VarDef | _:Lhs.Assign | Lhs.Throw => | ||
throw new IllegalArgumentException( | ||
"Illegal tree in FunctionEmitter.pushLhsInto():\n" + | ||
"lhs = " + lhs + "\n" + | ||
"rhs = " + rhs + " of class " + rhs.getClass) | ||
} | ||
|
||
case _ => | ||
throw new IllegalArgumentException( | ||
"Illegal tree in FunctionEmitter.pushLhsInto():\n" + | ||
"lhs = " + lhs + "\n" + | ||
"rhs = " + rhs + " of class " + rhs.getClass) | ||
}) | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.