From 5aef7afade0f7c8eec9737ea89a63a89332e0b79 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Thu, 4 Jun 2015 22:43:50 +0100 Subject: [PATCH] fix remaining AssignmentExpression LHS ReferencedIdentifier bugs --- .../transformation/helpers/name-method.js | 29 +++++++---- .../transformers/es6/spec.block-scoping.js | 51 +++++++++++++++---- src/babel/traversal/path/modification.js | 4 ++ src/babel/types/retrievers.js | 18 ++++--- 4 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/babel/transformation/helpers/name-method.js b/src/babel/transformation/helpers/name-method.js index fd8d0e0658..6ac4785a04 100644 --- a/src/babel/transformation/helpers/name-method.js +++ b/src/babel/transformation/helpers/name-method.js @@ -2,18 +2,29 @@ import getFunctionArity from "./get-function-arity"; import * as util from "../../util"; import * as t from "../../types"; +function visitIdentifier(context, node, scope, state) { + // check if this node matches our function id + if (node.name !== state.name) return; + + // check that we don't have a local variable declared as that removes the need + // for the wrapper + var localDeclar = scope.getBindingIdentifier(state.name); + if (localDeclar !== state.outerDeclar) return; + + state.selfReference = true; + context.stop(); +} + var visitor = { ReferencedIdentifier(node, parent, scope, state) { - // check if this node matches our function id - if (node.name !== state.name) return; + visitIdentifier(this, node, scope, state); + }, - // check that we don't have a local variable declared as that removes the need - // for the wrapper - var localDeclar = scope.getBindingIdentifier(state.name); - if (localDeclar !== state.outerDeclar) return; - - state.selfReference = true; - this.stop(); + AssignmentExpression(node, parent, scope, state) { + var ids = this.getBindingIdentifiers(); + for (var name in ids) { + visitIdentifier(this, ids[name], scope, state); + } } }; diff --git a/src/babel/transformation/transformers/es6/spec.block-scoping.js b/src/babel/transformation/transformers/es6/spec.block-scoping.js index 04aa5cc3c0..348e8e1e11 100644 --- a/src/babel/transformation/transformers/es6/spec.block-scoping.js +++ b/src/babel/transformation/transformers/es6/spec.block-scoping.js @@ -1,28 +1,59 @@ import * as t from "../../../types"; +function buildAssert(node, file) { + return t.callExpression( + file.addHelper("temporal-assert-defined"), + [node, t.literal(node.name), file.addHelper("temporal-undefined")] + ); +} + +function references(node, scope, state) { + var declared = state.letRefs[node.name]; + if (!declared) return false; + + // declared node is different in this scope + return scope.getBindingIdentifier(node.name) === declared; +} + var visitor = { ReferencedIdentifier(node, parent, scope, state) { if (t.isFor(parent) && parent.left === node) return; - var declared = state.letRefs[node.name]; - if (!declared) return; + if (!references(node, scope, state)) return; - // declared node is different in this scope - if (scope.getBindingIdentifier(node.name) !== declared) return; - - var assert = t.callExpression( - state.file.addHelper("temporal-assert-defined"), - [node, t.literal(node.name), state.file.addHelper("temporal-undefined")] - ); + var assert = buildAssert(node, state.file); this.skip(); - if (t.isAssignmentExpression(parent) || t.isUpdateExpression(parent)) { + if (t.isUpdateExpression(parent)) { if (parent._ignoreBlockScopingTDZ) return; this.parentPath.replaceWith(t.sequenceExpression([assert, parent])); } else { return t.logicalExpression("&&", assert, node); } + }, + + AssignmentExpression: { + exit(node, parent, scope, state) { + if (node._ignoreBlockScopingTDZ) return; + + var nodes = []; + var ids = this.getBindingIdentifiers(); + + for (var name in ids) { + var id = ids[name]; + + if (references(id, scope, state)) { + nodes.push(buildAssert(id, state.file)); + } + } + + if (nodes.length) { + node._ignoreBlockScopingTDZ = true; + nodes.push(node); + return nodes.map(t.expressionStatement); + } + } } }; diff --git a/src/babel/traversal/path/modification.js b/src/babel/traversal/path/modification.js index 97040a9840..ea0bb4263d 100644 --- a/src/babel/traversal/path/modification.js +++ b/src/babel/traversal/path/modification.js @@ -119,6 +119,10 @@ export function updateSiblingKeys(fromIndex, incrementBy) { } } +/** + * Description + */ + /** * Description */ diff --git a/src/babel/types/retrievers.js b/src/babel/types/retrievers.js index 10fbaeaa25..14bd70d260 100644 --- a/src/babel/types/retrievers.js +++ b/src/babel/types/retrievers.js @@ -30,27 +30,33 @@ export function getBindingIdentifiers(node: Object): Object { } getBindingIdentifiers.keys = { + ComprehensionBlock: "left", CatchClause: "param", UnaryExpression: "argument", AssignmentExpression: "left", + ImportSpecifier: "local", ImportNamespaceSpecifier: "local", ImportDefaultSpecifier: "local", - VariableDeclarator: "id", + ImportDeclaration: "specifiers", + FunctionDeclaration: "id", FunctionExpression: "id", + ClassDeclaration: "id", ClassExpression: "id", + SpreadElement: "argument", RestElement: "argument", UpdateExpression: "argument", + SpreadProperty: "argument", Property: "value", - ComprehensionBlock: "left", + AssignmentPattern: "left", - ComprehensionExpression: "blocks", - ImportDeclaration: "specifiers", - VariableDeclaration: "declarations", ArrayPattern: "elements", - ObjectPattern: "properties" + ObjectPattern: "properties", + + VariableDeclaration: "declarations", + VariableDeclarator: "id" };