Skip to content
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

Don't throw when destructuring into a var named as an import #10628

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -224,6 +224,10 @@ const rewriteReferencesVisitor = {
seen.add(path.node);

const left = path.get("left");

// No change needed
if (left.isMemberExpression()) return;

if (left.isIdentifier()) {
// Simple update-assign foo += 1; export { foo };
// => exports.foo = (foo += 1);
Expand All @@ -234,9 +238,9 @@ const rewriteReferencesVisitor = {
return;
}

const exportedNames = exported.get(localName) || [];
const exportedNames = exported.get(localName);
const importData = imported.get(localName);
if (exportedNames.length > 0 || importData) {
if (exportedNames?.length > 0 || importData) {
assert(path.node.operator === "=", "Path was not simplified");

const assignment = path.node;
Expand All @@ -259,13 +263,14 @@ const rewriteReferencesVisitor = {
);
requeueInParent(path);
}
} else if (left.isMemberExpression()) {
// No change needed
} else {
const ids = left.getOuterBindingIdentifiers();
const id = Object.keys(ids)
.filter(localName => imported.has(localName))
.pop();
const programScopeIds = Object.keys(ids).filter(
localName =>
scope.getBinding(localName) === path.scope.getBinding(localName),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider to guard with scope.hasBinding to avoid unnecessary path.scope.getBinding.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to do it and found a bug which, if fixed, would break @babel/plugin-transform-runtime <= 7.6 😢

This is what currently happens:

  1. The imports are analyzed
  2. The imports are removed -> The bindings are removed
  3. References to imported bindings are rewritten (this file)
    i) When we are comparing the bindings, the global one is undefined
    ii) If the local binding is undefined, it hasn't been redefined.

I tried to swap 2 and 3, but I still can optimize away the check for the local binding because @babel/transform-runtime doesn't register the import it injects in the scope tracker.

);
const id = programScopeIds.find(localName => imported.has(localName));

if (id) {
path.node.right = t.sequenceExpression([
path.node.right,
Expand All @@ -276,14 +281,7 @@ const rewriteReferencesVisitor = {
// Complex ({a, b, c} = {}); export { a, c };
// => ({a, b, c} = {}), (exports.a = a, exports.c = c);
const items = [];
Object.keys(ids).forEach(localName => {
// redeclared in this scope
if (
scope.getBinding(localName) !== path.scope.getBinding(localName)
) {
return;
}

programScopeIds.forEach(localName => {
const exportedNames = exported.get(localName) || [];
if (exportedNames.length > 0) {
items.push(
Expand Down
@@ -0,0 +1,12 @@
import { foo } from "x";

function f(foo) {
foo = 2;
[foo] = [];
({ foo } = {});
}


foo = 2;
[foo] = [];
({ foo } = {});
@@ -0,0 +1,23 @@
"use strict";

var _x = require("x");

function f(foo) {
foo = 2;
[foo] = [];
({
foo
} = {});
}

_x.foo = (2, function () {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow up PR, this could be left as foo since we are throwing anyway.

throw new Error('"' + "foo" + '" is read-only.');
}());
[foo] = ([], function () {
throw new Error('"' + "foo" + '" is read-only.');
}());
({
foo
} = ({}, function () {
throw new Error('"' + "foo" + '" is read-only.');
}()));