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
Restore traversal context after enter / traverse #13813
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/49081/ |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit f11e12d:
|
// before calling the enter visitor, but it can be true in case of | ||
// a requeued node (e.g. by .replaceWith()) that is then marked | ||
// with .skip(). | ||
if (this.shouldSkip || this.call("enter") || this.shouldSkip) { | ||
if (this.shouldSkip || this.call("enter")) { |
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.
If this.enter("enter")
is false
, either fns
is empty (no visitors), or all the visitors does not change the traverse flags. If fns
is empty, then this.shouldSkip
would not be changed at all. If all the visitors do not change traversal flags, then this.shouldSkip
should equals to this.shouldSkip
before enter
hook is called. Therefore the second this.shouldSkip
check is redundant.
Does this also fix #12631? |
Thanks for the reminder. I check out the reproduction repo: The traversal context does change after |
@@ -0,0 +1,11 @@ | |||
async function main() { | |||
async () => { |
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.
Is it intentional that this function is no longer invoked?
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.
Kind of. Personally I prefer the minimal AST structure that can reproduce the bug. In this case we are not testing the runtime semantics so the simpler the input code is, the easier to reason about what is going on. You can verify that the original code example also works on the PR REPL.
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.
Very epic thanks for explaining
Could we also benchmark, for example, compiling https://github.com/babel/babel/blob/main/packages/babel-parser/src/parser/expression.js with |
I added a real-world benchmark, the current PR is 3% (not statistically significant) slower than main branch. The minimal sample size for benchmark is 100.
|
In this PR we restores the context after
call("enter")
andtraverse.node
. The current AST operations we provided did not guarantee that the traversal context is perserved, let alone users may even change the associated context. The traversal context is crucial to sub-traverse in order to isolate visitors / traverse states from the root traverse.See also #13801 (comment) for how the leaked traversal context causes confusing errors.
I add a benchmark case to access the performance impact of this PR. The benchmark is a worst case scenario because context is changed in every node visitor. Compared to 7.15.4, Babel traverse in this PR is 10% slower. In the real world most context change happen in sub traverse, preserving context will ensure global visitors are not invoked in sub traverse so the real world performance should be better than this.
Benchmark Results