Do expressions transform for switch statements#10070
Do expressions transform for switch statements#10070nicolo-ribaudo merged 13 commits intobabel:masterfrom
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.
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.
Also this should evaluate to 1:
const a = do {
switch (1) {
case 1: 1;
case 2:
}
};There was a problem hiding this comment.
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.
10, because the last statement is a*10
There was a problem hiding this comment.
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.
- 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,Vis set to2(the result ofa = 2).
ii. Sincecase 1isn't followed by a break/return/throw statement,Ris a NormalCompletion and not an AbruptCompletion: for this reason the loop continues running to the following case.
iii. At the second iteration,Vis set to20(the result ofa * 10).
iv. The loop ends, because there are no morecases, and it returns20
There was a problem hiding this comment.
🤦♂️ 🤦♂️ 🤦♂️ 🤦♂️
I just noticed I wrote 10 instead of 20
There was a problem hiding this comment.
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.
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.
@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 BlockStatements, 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.
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.
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.
I suggest check isLastCaseWithConsequent early so that it may skip the whole hasConsequent setup when it is false.
| paths = addCompletionRecords(prevSibling, paths); | ||
| breakStatement.remove(); | ||
| } else { | ||
| breakStatement.replaceWith(switchCase.scope.buildUndefinedNode()); |
There was a problem hiding this comment.
nit: I think it should be breakStatement.scope.buildUndefinedNode().
There was a problem hiding this comment.
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 |
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
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 breaks:
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