track arrays to avoid turning something into an array multiple times - closes #757

This commit is contained in:
Sebastian McKenzie
2015-02-12 21:30:48 +11:00
parent e9cfd2df3e
commit e7f6572a3b
15 changed files with 99 additions and 37 deletions

View File

@@ -226,24 +226,6 @@ File.prototype.debug = function (msg) {
util.debug(parts);
};
File.prototype.toArray = function (node, i, forceHelperName) {
if (t.isArrayExpression(node)) {
return node;
} else if (t.isIdentifier(node) && node.name === "arguments") {
return t.callExpression(t.memberExpression(this.addHelper("slice"), t.identifier("call")), [node]);
} else {
var helperName = "to-array";
var args = [node];
if (i === true) {
helperName = "to-consumable-array";
} else if (i) {
args.push(t.literal(i));
helperName = "sliced-to-array";
}
return t.callExpression(this.addHelper(helperName), args);
}
};
File.prototype.getModuleFormatter = function (type) {
var ModuleFormatter = isFunction(type) ? type : transform.moduleFormatters[type];

View File

@@ -144,12 +144,14 @@ DestructuringTransformer.prototype.pushArrayPattern = function (pattern, parentI
// if we have a rest then we need all the elements
var count = !hasRest(pattern) && pattern.elements.length;
var toArray = this.file.toArray(parentId, count);
var toArray = this.scope.toArray(parentId, count);
var _parentId = this.scope.generateUidBasedOnNode(parentId, this.file);
var _parentId = this.scope.generateUidBasedOnNode(parentId);
this.nodes.push(this.buildVariableDeclaration(_parentId, toArray));
parentId = _parentId;
this.scope.assignTypeGeneric(parentId.name, "Array");
for (var i = 0; i < pattern.elements.length; i++) {
var elem = pattern.elements[i];
@@ -159,7 +161,7 @@ DestructuringTransformer.prototype.pushArrayPattern = function (pattern, parentI
var newPatternId;
if (t.isRestElement(elem)) {
newPatternId = this.file.toArray(parentId);
newPatternId = this.scope.toArray(parentId);
if (i > 0) {
newPatternId = t.callExpression(t.memberExpression(newPatternId, t.identifier("slice")), [t.literal(i)]);

View File

@@ -60,6 +60,8 @@ exports.Function = function (node, parent, scope) {
node.body.body.unshift(restDeclar);
}
scope.assignTypeGeneric(rest.name, "Array");
var loop = util.template("rest", {
ARGUMENTS: argsId,
ARRAY_KEY: arrKey,

View File

@@ -5,8 +5,8 @@ var t = require("../../../types");
exports.check = t.isSpreadElement;
var getSpreadLiteral = function (spread, file) {
return file.toArray(spread.argument, true);
var getSpreadLiteral = function (spread, scope) {
return scope.toArray(spread.argument, true);
};
var hasSpread = function (nodes) {
@@ -18,7 +18,7 @@ var hasSpread = function (nodes) {
return false;
};
var build = function (props, file) {
var build = function (props, scope) {
var nodes = [];
var _props = [];
@@ -33,7 +33,7 @@ var build = function (props, file) {
var prop = props[i];
if (t.isSpreadElement(prop)) {
push();
nodes.push(getSpreadLiteral(prop, file));
nodes.push(getSpreadLiteral(prop, scope));
} else {
_props.push(prop);
}
@@ -44,11 +44,11 @@ var build = function (props, file) {
return nodes;
};
exports.ArrayExpression = function (node, parent, scope, file) {
exports.ArrayExpression = function (node, parent, scope) {
var elements = node.elements;
if (!hasSpread(elements)) return;
var nodes = build(elements, file);
var nodes = build(elements, scope);
var first = nodes.shift();
if (!t.isArrayExpression(first)) {
@@ -59,7 +59,7 @@ exports.ArrayExpression = function (node, parent, scope, file) {
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
};
exports.CallExpression = function (node, parent, scope, file) {
exports.CallExpression = function (node, parent, scope) {
var args = node.arguments;
if (!hasSpread(args)) return;
@@ -71,7 +71,7 @@ exports.CallExpression = function (node, parent, scope, file) {
if (args.length === 1 && args[0].argument.name === "arguments") {
nodes = [args[0].argument];
} else {
nodes = build(args, file);
nodes = build(args, scope);
}
var first = nodes.shift();
@@ -105,7 +105,7 @@ exports.NewExpression = function (node, parent, scope, file) {
var nativeType = t.isIdentifier(node.callee) && includes(t.NATIVE_TYPE_NAMES, node.callee.name);
var nodes = build(args, file);
var nodes = build(args, scope);
if (nativeType) {
nodes.unshift(t.arrayExpression([t.literal(null)]));

View File

@@ -31,7 +31,6 @@ module.exports = {
"es6.objectSuper": require("./es6/object-super"),
"es7.objectRestSpread": require("./es7/object-rest-spread"),
"es7.exponentiationOperator": require("./es7/exponentiation-operator"),
"es6.spread": require("./es6/spread"),
"es6.templateLiterals": require("./es6/template-literals"),
"es5.properties.mutators": require("./es5/properties.mutators"),
@@ -50,6 +49,9 @@ module.exports = {
// needs to be before `es6.parameters.default` as default parameters will destroy the rest param
"es6.parameters.rest": require("./es6/parameters.rest"),
// needs to be after `es6.parameters.rest` as we use `toArray` and avoid turning an already known array into one
"es6.spread": require("./es6/spread"),
// needs to be before `es6.blockScoping` as default parameters have a TDZ
"es6.parameters.default": require("./es6/parameters.default"),

View File

@@ -198,6 +198,25 @@ Scope.prototype.inferType = function (node) {
}
};
Scope.prototype.isTypeGeneric = function (name, genericName) {
var info = this.getBindingInfo(name);
if (!info) return false;
var type = info.typeAnnotation;
return t.isGenericTypeAnnotation(type) && t.isIdentifier(type.id, { name: genericName });
};
Scope.prototype.assignTypeGeneric = function (name, type) {
this.assignType(name, t.genericTypeAnnotation(t.identifier(type)));
};
Scope.prototype.assignType = function (name, type) {
var info = this.getBindingInfo(name);
if (!info) return;
info.identifier.typeAnnotation = info.typeAnnotation = type;
};
Scope.prototype.getTypeAnnotation = function (key, id, node) {
var type;
@@ -215,6 +234,32 @@ Scope.prototype.getTypeAnnotation = function (key, id, node) {
}
};
Scope.prototype.toArray = function (node, i) {
var file = this.file;
if (t.isIdentifier(node) && this.isTypeGeneric(node.name, "Array")) {
return node;
}
if (t.isArrayExpression(node)) {
return node;
}
if (t.isIdentifier(node, { name: "arguments" })) {
return t.callExpression(t.memberExpression(file.addHelper("slice"), t.identifier("call")), [node]);
}
var helperName = "to-array";
var args = [node];
if (i === true) {
helperName = "to-consumable-array";
} else if (i) {
args.push(t.literal(i));
helperName = "sliced-to-array";
}
return t.callExpression(file.addHelper(helperName), args);
};
Scope.prototype.clearOwnBinding = function (name) {
delete this.bindings[name];
};

View File

@@ -59,6 +59,11 @@
"generator": false
},
"GenericTypeAnnotation": {
"id": null,
"typeParameters": null
},
"Identifier": {
"name": null
},