Skip to content
This repository has been archived by the owner on Aug 15, 2024. It is now read-only.

Breaking: remove TDZScope (refs eslint/eslint#10245) #35

Merged
merged 1 commit into from
Apr 28, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 29 additions & 55 deletions lib/referencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,6 @@ class Referencer extends esrecurse.Visitor {
this.isInnerMethodDefinition = isInnerMethodDefinition;
}

materializeTDZScope(node, iterationNode) {

// http://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation
// TDZ scope hides the declaration's names.
this.scopeManager.__nestTDZScope(node, iterationNode);
this.visitVariableDeclaration(this.currentScope(), Variable.TDZ, iterationNode.left, 0, true);
}

materializeIterationScope(node) {

// Generate iteration scope for upper ForIn/ForOf Statements.
const letOrConstDecl = node.left;

this.scopeManager.__nestForScope(node);
this.visitVariableDeclaration(this.currentScope(), Variable.Variable, letOrConstDecl, 0);
this.visitPattern(letOrConstDecl.declarations[0].id, pattern => {
this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
});
}

referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) {
const scope = this.currentScope();

Expand Down Expand Up @@ -288,7 +268,6 @@ class Referencer extends esrecurse.Visitor {
));
}

// FIXME: Maybe consider TDZ.
this.visit(node.superClass);

this.scopeManager.__nestClassScope(node);
Expand Down Expand Up @@ -326,58 +305,53 @@ class Referencer extends esrecurse.Visitor {

visitForIn(node) {
if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== "var") {
this.materializeTDZScope(node.right, node);
this.visit(node.right);
this.close(node.right);
this.scopeManager.__nestForScope(node);
}

this.materializeIterationScope(node);
this.visit(node.body);
this.close(node);
if (node.left.type === Syntax.VariableDeclaration) {
this.visit(node.left);
this.visitPattern(node.left.declarations[0].id, pattern => {
this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
});
} else {
if (node.left.type === Syntax.VariableDeclaration) {
this.visit(node.left);
this.visitPattern(node.left.declarations[0].id, pattern => {
this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
});
} else {
this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
let maybeImplicitGlobal = null;
this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
let maybeImplicitGlobal = null;

if (!this.currentScope().isStrict) {
maybeImplicitGlobal = {
pattern,
node
};
}
this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false);
});
}
this.visit(node.right);
this.visit(node.body);
if (!this.currentScope().isStrict) {
maybeImplicitGlobal = {
pattern,
node
};
}
this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false);
});
}
this.visit(node.right);
this.visit(node.body);

this.close(node);
}

visitVariableDeclaration(variableTargetScope, type, node, index, fromTDZ) {
visitVariableDeclaration(variableTargetScope, type, node, index) {

// If this was called to initialize a TDZ scope, this needs to make definitions, but doesn't make references.
const decl = node.declarations[index];
const init = decl.init;

this.visitPattern(decl.id, { processRightHandNodes: !fromTDZ }, (pattern, info) => {
variableTargetScope.__define(pattern,
this.visitPattern(decl.id, { processRightHandNodes: true }, (pattern, info) => {
variableTargetScope.__define(
pattern,
new Definition(
type,
pattern,
decl,
node,
index,
node.kind
));
)
);

if (!fromTDZ) {
this.referencingDefaultValue(pattern, info.assignments, null, true);
}
this.referencingDefaultValue(pattern, info.assignments, null, true);
if (init) {
this.currentScope().__referencing(pattern, Reference.WRITE, init, null, !info.topLevel, true);
}
Expand Down
8 changes: 0 additions & 8 deletions lib/scope-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ const ClassScope = Scope.ClassScope;
const SwitchScope = Scope.SwitchScope;
const FunctionScope = Scope.FunctionScope;
const ForScope = Scope.ForScope;
const TDZScope = Scope.TDZScope;
const FunctionExpressionNameScope = Scope.FunctionExpressionNameScope;
const BlockScope = Scope.BlockScope;

Expand Down Expand Up @@ -118,9 +117,6 @@ class ScopeManager {
if (testScope.type === "function" && testScope.functionExpressionScope) {
return false;
}
if (testScope.type === "TDZ") {
return false;
}
return true;
}

Expand Down Expand Up @@ -237,10 +233,6 @@ class ScopeManager {
return this.__nestScope(new ModuleScope(this, this.__currentScope, node));
}

__nestTDZScope(node) {
return this.__nestScope(new TDZScope(this, this.__currentScope, node));
}

__nestFunctionExpressionNameScope(node) {
return this.__nestScope(new FunctionExpressionNameScope(this, this.__currentScope, node));
}
Expand Down
15 changes: 3 additions & 12 deletions lib/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class Scope {
constructor(scopeManager, type, upperScope, block, isMethodDefinition) {

/**
* One of 'TDZ', 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'.
* One of 'module', 'block', 'switch', 'function', 'catch', 'with', 'function', 'class', 'global'.
* @member {String} Scope#type
*/
this.type = type;
Expand Down Expand Up @@ -404,10 +404,8 @@ class Scope {

if (def) {
variable.defs.push(def);
if (def.type !== Variable.TDZ) {
this.__addDeclaredVariablesOfNode(variable, def.node);
this.__addDeclaredVariablesOfNode(variable, def.parent);
}
this.__addDeclaredVariablesOfNode(variable, def.node);
this.__addDeclaredVariablesOfNode(variable, def.parent);
}
if (node) {
variable.identifiers.push(node);
Expand Down Expand Up @@ -631,12 +629,6 @@ class WithScope extends Scope {
}
}

class TDZScope extends Scope {
constructor(scopeManager, upperScope, block) {
super(scopeManager, "TDZ", upperScope, block, false);
}
}

class BlockScope extends Scope {
constructor(scopeManager, upperScope, block) {
super(scopeManager, "block", upperScope, block, false);
Expand Down Expand Up @@ -744,7 +736,6 @@ module.exports = {
FunctionExpressionNameScope,
CatchScope,
WithScope,
TDZScope,
BlockScope,
SwitchScope,
FunctionScope,
Expand Down
1 change: 0 additions & 1 deletion lib/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ Variable.FunctionName = "FunctionName";
Variable.ClassName = "ClassName";
Variable.Variable = "Variable";
Variable.ImportBinding = "ImportBinding";
Variable.TDZ = "TDZ";
Variable.ImplicitGlobalVariable = "ImplicitGlobalVariable";

module.exports = Variable;
Expand Down
65 changes: 22 additions & 43 deletions tests/es6-destructuring-assignments.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe("ES6 destructuring assignments", () => {

const scopeManager = analyze(ast, { ecmaVersion: 6 });

expect(scopeManager.scopes).to.have.length(4); // [global, function, TDZ, for]
expect(scopeManager.scopes).to.have.length(3); // [global, function, for]

let scope = scopeManager.scopes[0];

Expand All @@ -92,22 +92,12 @@ describe("ES6 destructuring assignments", () => {
expect(scope.implicit.left[0].identifier.name).to.equal("array");

scope = scopeManager.scopes[2];
expect(scope.type).to.equal("TDZ");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(1);
expect(scope.references[0].identifier.name).to.equal("array");
expect(scope.references[0].isWrite()).to.be.false;

scope = scopeManager.scopes[3];
expect(scope.type).to.equal("for");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(3);
expect(scope.references).to.have.length(4);
expect(scope.references[0].identifier.name).to.equal("a");
expect(scope.references[0].isWrite()).to.be.true;
expect(scope.references[0].partial).to.be.true;
Expand All @@ -120,6 +110,9 @@ describe("ES6 destructuring assignments", () => {
expect(scope.references[2].isWrite()).to.be.true;
expect(scope.references[2].partial).to.be.true;
expect(scope.references[2].resolved).to.equal(scope.variables[2]);
expect(scope.references[3].identifier.name).to.equal("array");
expect(scope.references[3].isWrite()).to.be.false;
expect(scope.references[3].resolved).to.be.null;
});

it("Pattern with default values in var in ForInStatement", () => {
Expand Down Expand Up @@ -183,36 +176,26 @@ describe("ES6 destructuring assignments", () => {

const scopeManager = analyze(ast, { ecmaVersion: 6 });

expect(scopeManager.scopes).to.have.length(4); // [global, function, TDZ, for]
expect(scopeManager.scopes).to.have.length(3); // [global, function, for]

let scope = scopeManager.scopes[0];

expect(scope.type).to.equal("global");
expect(scope.variables).to.have.length(0);
expect(scope.references).to.have.length(0);
expect(scope.implicit.left).to.have.length(2);
expect(scope.implicit.left[0].identifier.name).to.equal("array");
expect(scope.implicit.left[0].from.type).to.equal("TDZ");
expect(scope.implicit.left[1].identifier.name).to.equal("d");
expect(scope.implicit.left[0].identifier.name).to.equal("d");
expect(scope.implicit.left[0].from.type).to.equal("for");
expect(scope.implicit.left[1].identifier.name).to.equal("array");
expect(scope.implicit.left[1].from.type).to.equal("for");

scope = scopeManager.scopes[2];
expect(scope.type).to.equal("TDZ");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(1);
expect(scope.references[0].identifier.name).to.equal("array");
expect(scope.references[0].isWrite()).to.be.false;

scope = scopeManager.scopes[3];
expect(scope.type).to.equal("for");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(5);
expect(scope.references).to.have.length(6);
expect(scope.references[0].identifier.name).to.equal("c");
expect(scope.references[0].isWrite()).to.be.true;
expect(scope.references[0].writeExpr.name).to.equal("d");
Expand All @@ -235,6 +218,9 @@ describe("ES6 destructuring assignments", () => {
expect(scope.references[4].writeExpr.name).to.equal("array");
expect(scope.references[4].partial).to.be.true;
expect(scope.references[4].resolved).to.equal(scope.variables[2]);
expect(scope.references[5].identifier.name).to.equal("array");
expect(scope.references[5].isWrite()).to.be.false;
expect(scope.references[5].resolved).to.be.null;
});

it("Pattern with nested default values in var in ForInStatement", () => {
Expand Down Expand Up @@ -313,38 +299,28 @@ describe("ES6 destructuring assignments", () => {

const scopeManager = analyze(ast, { ecmaVersion: 6 });

expect(scopeManager.scopes).to.have.length(4); // [global, function, TDZ, for]
expect(scopeManager.scopes).to.have.length(3); // [global, function, for]

let scope = scopeManager.scopes[0];

expect(scope.type).to.equal("global");
expect(scope.variables).to.have.length(0);
expect(scope.references).to.have.length(0);
expect(scope.implicit.left).to.have.length(3);
expect(scope.implicit.left[0].identifier.name).to.equal("array");
expect(scope.implicit.left[0].from.type).to.equal("TDZ");
expect(scope.implicit.left[1].identifier.name).to.equal("d");
expect(scope.implicit.left[0].identifier.name).to.equal("d");
expect(scope.implicit.left[0].from.type).to.equal("for");
expect(scope.implicit.left[1].identifier.name).to.equal("e");
expect(scope.implicit.left[1].from.type).to.equal("for");
expect(scope.implicit.left[2].identifier.name).to.equal("e");
expect(scope.implicit.left[2].identifier.name).to.equal("array");
expect(scope.implicit.left[2].from.type).to.equal("for");

scope = scopeManager.scopes[2];
expect(scope.type).to.equal("TDZ");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(1);
expect(scope.references[0].identifier.name).to.equal("array");
expect(scope.references[0].isWrite()).to.be.false;

scope = scopeManager.scopes[3];
expect(scope.type).to.equal("for");
expect(scope.variables).to.have.length(3);
expect(scope.variables[0].name).to.equal("a");
expect(scope.variables[1].name).to.equal("b");
expect(scope.variables[2].name).to.equal("c");
expect(scope.references).to.have.length(8);
expect(scope.references).to.have.length(9);
expect(scope.references[0].identifier.name).to.equal("b");
expect(scope.references[0].isWrite()).to.be.true;
expect(scope.references[0].writeExpr.name).to.equal("e");
Expand Down Expand Up @@ -379,6 +355,9 @@ describe("ES6 destructuring assignments", () => {
expect(scope.references[7].writeExpr.name).to.equal("array");
expect(scope.references[7].partial).to.be.true;
expect(scope.references[7].resolved).to.equal(scope.variables[2]);
expect(scope.references[8].identifier.name).to.equal("array");
expect(scope.references[8].isWrite()).to.be.false;
expect(scope.references[8].resolved).to.be.null;
});

it("Pattern with default values in var in ForInStatement (separate declarations)", () => {
Expand Down
Loading