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
Check shadow variable to identifier in default parameters #10053
Conversation
When there is a variable declaration inside the function body, which shares its name to a referenced identifier in default parameter expression, the function body should be wrapped into iife, otherwise the binding in default parameter scope will be shadowed by function body.
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/10901/ |
1 similar comment
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/10901/ |
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 think that a better approach would be to rename the inner x
binding using path.scope.rename("x")
, to avoid the IIFE:
let x = "outside";
function outer(a = () => x) {
let x = "inside";
return a();
}
let x = "outside";
function outer(a = () => x) {
let x = "inside";
return a();
}
outer();
// -->
var x = "outside";
function outer() {
var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {
return x;
};
var _x = "inside";
return a();
}
outer();
If it turns out to be difficult/buggy, I'm ok with the behavior implemented by this PR since this is a very rare edge case.
Related: #2471 |
Hi Nicolò, Thanks for the quick response. The issue 2471 is still reproducible on master. I would try to look into this in couple of days. At first glance, renaming the inner binding looks better as it prevents from IIFE performance penalties. Where could I know all the possible values and the meaning of |
Hi Nicolò, I have tried to use Though issue #2471 is related, I would suggest move things forward and try to fix them on different PR. Any thoughts? |
if (node.name === "eval" || !isSafeBinding(scope, node)) { | ||
if ( | ||
node.name === "eval" || | ||
!isSafeBinding(scope, node) || |
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.
This should be considered a workaround hotfix because the ReferencedIdentifier in params initializers should point to the parent of the function scope. Since path.scope
is not accurate here, we have to do a hotfix and check state.scope
again.
The ideal fix should construct a separate scope for parameter initializer.
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.
✅
When there is a variable declaration inside the function body, which shares its name to a referenced identifier in default parameter expression, the function body should be wrapped into iife, otherwise the binding in default parameter scope will be shadowed by function body.
On the example,
As is illustrated, there are 3 scopes in this program. Variable
x
in scope B will borrow from scope P. However, since there isx
declared in scope A, we should wrap body in scope A to IIFE, otherwise the transformed code will havex
in scope B borrowed from scope A, which is incorrect.Here we check if it is a safe binding with respect to the function scope. Note that unlike the path scope changing within the traverse, this scope reference is invariant and always refers to the function declaration scope (in our example, it is scope A).