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
Do expressions transform for switch statements #10070
Do expressions transform for switch statements #10070
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/11197/ |
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/10927/ |
breakStatement.replaceWith(switchCase.scope.buildUndefinedNode()); | ||
paths = addCompletionRecords(breakStatement, paths); | ||
} | ||
} else if (consequent.length > 0 && isDefaultCase) { |
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.
default
cases have nothing special, they should be handled exactly like case
:
This should evaluate to 1
:
const a = do {
switch (2) {
default: 0;
case 1: 1; break;
}
};
This should evaluate to 1
:
const a = do {
switch (1) {
case 1: 1;
}
};
The check should probably be more like if (isLastStatement) {
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.
Also this should evaluate to 1:
const a = do {
switch (1) {
case 1: 1;
case 2:
}
};
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.
So can I say that the lastStatement is an expression statement , then no fall through, else will fall through say:
let a = 1
const b = do {
switch (1) {
case 1: a = 2;
case 2: a * 10;
}
So b = ?
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.
10, because the last statement is a*10
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.
ok. interesting. is this documented somewhere within https://github.com/tc39/proposal-do-expressions? or where do I find the spec for this?
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.
- Switch expressions evaluate to the result of their block: https://tc39.es/ecma262/#sec-switch-statement-runtime-semantics-evaluation steps 7 and 9
- It delegates to https://tc39.es/ecma262/#sec-runtime-semantics-caseblockevaluation, in the
CaseBlock: { CaseClauses }
section.
i. At the first iteration of step 4 of that algorithm,V
is set to2
(the result ofa = 2
).
ii. Sincecase 1
isn't followed by a break/return/throw statement,R
is a NormalCompletion and not an AbruptCompletion: for this reason the loop continues running to the following case.
iii. At the second iteration,V
is set to20
(the result ofa * 10
).
iv. The loop ends, because there are no morecase
s, and it returns20
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 just noticed I wrote 10 instead of 20
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 realised reading the ECMA262 Spec is giving me more confusion 🤦♂ 🤦♂ 🤦♂, but I guess I roughly know what you trying to point out. And I think we should document more in the do-expression proposal docs
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.
Btw, you can already "test" do expression in any browser.
do { ANYTHING }
is
eval(`{
ANYTHING
}`);
"b"; | ||
case 3: | ||
{} | ||
{ break; } |
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.
@nicolo-ribaudo i need some help over here, i've figured this as a plausible test case, but I not sure how i should transform this.
Previously, what I did is to find the BreakStatement
, and turn the statement before BreakStatement
as a completionPath, which would then be transformed into a return statement.
Problem I've created right now is that the previous statement could be anything from BlockStatement
to nested BlockStatement
s, and I need to find the "last statement"
which I am kind stuck on how I should go for this...
not entirely sure I am in the right direction, that's why I am seeking some help over here
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 about how to solve it, but it isn't a problem just for switchs. It's a problem for everything which uses break
.
e.g.
let a = do {
while (1) {
1;
break;
2;
}
};
I think that we should try to fix it separately since it is a really hard problem and this PR is already a big improvement.
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.
OK I guess I shall disable that test case then
@nicolo-ribaudo any update on this? |
breakStatement.replaceWith(switchCase.scope.buildUndefinedNode()); | ||
paths = addCompletionRecords(breakStatement, paths); | ||
} | ||
} else { |
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 suggest check isLastCaseWithConsequent
early so that it may skip the whole hasConsequent
setup when it is false.
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.
@JLHwung updated!
paths = addCompletionRecords(prevSibling, paths); | ||
breakStatement.remove(); | ||
} else { | ||
breakStatement.replaceWith(switchCase.scope.buildUndefinedNode()); |
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.
nit: I think it should be breakStatement.scope.buildUndefinedNode()
.
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.
@JLHwung sure!
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.
After #10243 they will be logically equivalent: buildUndefinedNode
does not depend on scope any more. It is by reviewing this PR that I find the room for improvements in buildUndefinedNode
.
2bc5df7
to
39be06f
Compare
@nicolo-ribaudo bump |
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 don't think that switch/break
support is perfect yet. For example, it doesn't work with this code:
let a = do {
switch (11) {
case 1:
{ 2; { break } }
}
};
That said, it is a general problem with nested break
s:
let a = do {
if (1) block: { 2; { break block } }
};
This PR already does a good job by special-casing case x: { ... }
, which is a common way of using switch
statements. In the future, we shouldn't special case it and properly fix break
support.
Rebased #6975, fixed PR review issues