WIP - Do expressions transform for switch statements #6975
WIP - Do expressions transform for switch statements #6975rajasekarm wants to merge 8 commits intobabel:masterfrom rajasekarm:bug-3872
Conversation
rajasekarm
commented
Dec 5, 2017
| Q | A |
|---|---|
| Fixed Issues? | #3872 |
| Patch: Bug Fix? | |
| Major: Breaking Change? | |
| Minor: New Feature? | |
| Tests Added + Pass? | Yes |
| Documentation PR | |
| Any Dependency Changes? | |
| License | MIT |
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/6170/ |
xtuc
left a comment
There was a problem hiding this comment.
Great job 👍
I was wondering why we needed to change babel-traverse for that but it's because the do-expression uses our internal
| ); | ||
| } else { | ||
| const finalStatement = cases[i].get("consequent")[consequentLength - 1]; | ||
| const isBreakStatement = |
There was a problem hiding this comment.
hasBreakStatement would suit here better imho
| paths, | ||
| ); | ||
| } else { | ||
| const finalStatement = cases[i].get("consequent")[consequentLength - 1]; |
There was a problem hiding this comment.
maybe something like lastCaseStatement?
| paths, | ||
| ); | ||
| } else { | ||
| const finalStatement = cases[i].get("consequent")[consequentLength - 1]; |
There was a problem hiding this comment.
we should also check if consequentLength - 1 is a valid index, accessing -1 may cause deoptimizations in v8
| function completionRecordForSwitch(cases, paths) { | ||
| for (let i = 0, caseLen = cases.length; i < caseLen; i++) { | ||
| const consequentLength = cases[i].get("consequent").length; | ||
| const isDefaultStatement = !cases[i].get("test").type; |
There was a problem hiding this comment.
a more explicit check of cases[i].get("test").type === null could be used
also isDefaultCase would be more descriptive
| } | ||
|
|
||
| function completionRecordForSwitch(cases, paths) { | ||
| for (let i = 0, caseLen = cases.length; i < caseLen; i++) { |
There was a problem hiding this comment.
is there any reason to cache caseLen here?
There was a problem hiding this comment.
I would prefer to cache the array length always. Your views please.
There was a problem hiding this comment.
This should be a for (const case of cases) {} loop. You make no use of the loop variables other than cases[i].
|
@nicolo-ribaudo @Andarist I'll update the PR and keep posted here. |
| const isDefaultCase = switchcase.get("test").type === null; | ||
| if (isDefaultCase) { | ||
| paths = addCompletionRecords( | ||
| switchcase.get("consequent")[consequentLength - 1], |
There was a problem hiding this comment.
this code path is not guarded against accessing -1 index
There was a problem hiding this comment.
updated the code to break the loop, if it has zero element
| const lastCaseStatement = switchcase.get("consequent")[ | ||
| consequentLength - 1 | ||
| ]; | ||
| const hasBreakStatement = |
There was a problem hiding this comment.
as latter IfStatements are both checking against hasBreakStatement you could just continue here for !hasBreakStatement and remove those checks below
also the mentioned IfStatements should form if/else imho
|
I forgot about something @nicolo-ribaudo's example should become an |
|
I've few doubts, after @nicolo-ribaudo comment with the below example, Example 1: Example 2: Expected output: I read the the spec of switch case,, so as per spec the code should be transformed as below to get the proper evaluated output. but it create confusion if there is change in structure of source code. Whats is the possible/right solution? |
|
That transformation wouldn't work, since var a = function() {
switch(0) {
case 0: return "foo";
case 1: return;
}
}() || "bar"If a case clause's first statement is I think you may need to loop over the case declarations from last to first, otherwise the |
Your exampleI simplified a bit your example: REPL (removed the Actual: abar foo Note that:var a = function () {
switch (0) {
case 0:
"foo";
}
}();returns |
|
@xtuc but as per ECMA spec, last expression in the case block should be returned if there is no break statement. |
| const hasBreakStatement = | ||
| lastCaseStatement && lastCaseStatement.isBreakStatement(); | ||
|
|
||
| if (hasBreakStatement) { |
There was a problem hiding this comment.
All these checks are the same of lines 62-80?
| ); | ||
| } | ||
|
|
||
| if (!hasBreakStatement && consequentLength) { |
There was a problem hiding this comment.
Only if the first statement of the following case is break.
e.g.
let a = do {
switch(0) {
case 0:
"foo";
case 1:
"bar";
break;
}
};Should be "bar".
|
@rajzshkr so the behavior I explained here #6975 (comment) is a bug, do we agree? |
|
@xtuc Yup. The example in the comment should output as |
There was a problem hiding this comment.
Consequent could be not just ExpressionStatement, but BlockStatement. Inside this block, we can have break, which should return the value above.
switch(0) {
case 0: {
0;
break;
}
case 1: "foo"; break;
}for now, will return undefined, because we didn't override break for this case and output is:
case 0: {
0;
break;
}|
@yavorsky I've noted this issue also, I'll update the PR. |
|
@rajzshkr Will you update this recently? |
|
Any one can pick his progress? |