Merge pull request #6051 from babel/5709-2
Rewrite parameter transform and drop _blockHoist reliance
This commit is contained in:
commit
47a9ba3440
@ -21,15 +21,15 @@ console.log(unpackObject({
|
||||
}));
|
||||
|
||||
var unpackArray = function (_ref3, _ref4) {
|
||||
var _ref6 = babelHelpers.slicedToArray(_ref3, 3),
|
||||
a = _ref6[0],
|
||||
b = _ref6[1],
|
||||
c = _ref6[2];
|
||||
var _ref5 = babelHelpers.slicedToArray(_ref3, 3),
|
||||
a = _ref5[0],
|
||||
b = _ref5[1],
|
||||
c = _ref5[2];
|
||||
|
||||
var _ref5 = babelHelpers.slicedToArray(_ref4, 3),
|
||||
x = _ref5[0],
|
||||
y = _ref5[1],
|
||||
z = _ref5[2];
|
||||
var _ref6 = babelHelpers.slicedToArray(_ref4, 3),
|
||||
x = _ref6[0],
|
||||
y = _ref6[1],
|
||||
z = _ref6[2];
|
||||
|
||||
return a + b + c;
|
||||
};
|
||||
|
||||
@ -1,185 +0,0 @@
|
||||
import getFunctionArity from "babel-helper-get-function-arity";
|
||||
import callDelegate from "babel-helper-call-delegate";
|
||||
import template from "babel-template";
|
||||
import * as t from "babel-types";
|
||||
|
||||
const buildDefaultParam = template(`
|
||||
let VARIABLE_NAME =
|
||||
ARGUMENTS.length > ARGUMENT_KEY && ARGUMENTS[ARGUMENT_KEY] !== undefined ?
|
||||
ARGUMENTS[ARGUMENT_KEY]
|
||||
:
|
||||
DEFAULT_VALUE;
|
||||
`);
|
||||
|
||||
const buildLooseDefaultParam = template(`
|
||||
if (ASSIGMENT_IDENTIFIER === UNDEFINED) {
|
||||
ASSIGMENT_IDENTIFIER = DEFAULT_VALUE;
|
||||
}
|
||||
`);
|
||||
|
||||
const buildLooseDestructuredDefaultParam = template(`
|
||||
let ASSIGMENT_IDENTIFIER = PARAMETER_NAME === UNDEFINED ? DEFAULT_VALUE : PARAMETER_NAME ;
|
||||
`);
|
||||
|
||||
const buildCutOff = template(`
|
||||
let $0 = $1[$2];
|
||||
`);
|
||||
|
||||
function hasDefaults(node) {
|
||||
for (const param of (node.params: Array<Object>)) {
|
||||
if (!t.isIdentifier(param)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSafeBinding(scope, node) {
|
||||
if (!scope.hasOwnBinding(node.name)) return true;
|
||||
const { kind } = scope.getOwnBinding(node.name);
|
||||
return kind === "param" || kind === "local";
|
||||
}
|
||||
|
||||
const iifeVisitor = {
|
||||
ReferencedIdentifier(path, state) {
|
||||
const { scope, node } = path;
|
||||
if (node.name === "eval" || !isSafeBinding(scope, node)) {
|
||||
state.iife = true;
|
||||
path.stop();
|
||||
}
|
||||
},
|
||||
|
||||
Scope(path) {
|
||||
// different bindings
|
||||
path.skip();
|
||||
},
|
||||
};
|
||||
|
||||
export const visitor = {
|
||||
Function(path) {
|
||||
const { node, scope } = path;
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
// ensure it's a block, useful for arrow functions
|
||||
path.ensureBlock();
|
||||
|
||||
const params = path.get("params");
|
||||
|
||||
if (this.opts.loose) {
|
||||
const body = [];
|
||||
for (let i = 0; i < params.length; ++i) {
|
||||
const param = params[i];
|
||||
if (param.isAssignmentPattern()) {
|
||||
const left = param.get("left");
|
||||
const right = param.get("right");
|
||||
|
||||
const undefinedNode = scope.buildUndefinedNode();
|
||||
|
||||
if (left.isIdentifier()) {
|
||||
body.push(
|
||||
buildLooseDefaultParam({
|
||||
ASSIGMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(left.node);
|
||||
} else if (left.isObjectPattern() || left.isArrayPattern()) {
|
||||
const paramName = scope.generateUidIdentifier();
|
||||
body.push(
|
||||
buildLooseDestructuredDefaultParam({
|
||||
ASSIGMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
PARAMETER_NAME: paramName,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
path.get("body").unshiftContainer("body", body);
|
||||
return;
|
||||
}
|
||||
|
||||
const state = {
|
||||
iife: false,
|
||||
scope: scope,
|
||||
};
|
||||
|
||||
const body = [];
|
||||
|
||||
//
|
||||
const argsIdentifier = t.identifier("arguments");
|
||||
|
||||
// push a default parameter definition
|
||||
function pushDefNode(left, right, i) {
|
||||
const defNode = buildDefaultParam({
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.numericLiteral(i),
|
||||
ARGUMENTS: argsIdentifier,
|
||||
});
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
//
|
||||
const lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
//
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i];
|
||||
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!state.iife && !param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const left = param.get("left");
|
||||
const right = param.get("right");
|
||||
|
||||
//
|
||||
if (i >= lastNonDefaultParam || left.isPattern()) {
|
||||
const placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
} else {
|
||||
node.params[i] = left.node;
|
||||
}
|
||||
|
||||
//
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && !isSafeBinding(scope, right.node)) {
|
||||
// the right hand side references a parameter
|
||||
state.iife = true;
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// add declarations for trailing parameters
|
||||
for (let i = lastNonDefaultParam + 1; i < node.params.length; i++) {
|
||||
const param = node.params[i];
|
||||
if (param._isDefaultPlaceholder) continue;
|
||||
|
||||
const declar = buildCutOff(param, argsIdentifier, t.numericLiteral(i));
|
||||
declar._blockHoist = node.params.length - i;
|
||||
body.push(declar);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(path, scope));
|
||||
path.set("body", t.blockStatement(body));
|
||||
} else {
|
||||
path.get("body").unshiftContainer("body", body);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -1,29 +0,0 @@
|
||||
import * as t from "babel-types";
|
||||
|
||||
export const visitor = {
|
||||
Function(path) {
|
||||
const params: Array = path.get("params");
|
||||
|
||||
// If there's a rest param, no need to loop through it. Also, we need to
|
||||
// hoist one more level to get `declar` at the right spot.
|
||||
const hoistTweak = t.isRestElement(params[params.length - 1]) ? 1 : 0;
|
||||
const outputParamsLength = params.length - hoistTweak;
|
||||
|
||||
for (let i = 0; i < outputParamsLength; i++) {
|
||||
const param = params[i];
|
||||
if (param.isArrayPattern() || param.isObjectPattern()) {
|
||||
const uid = path.scope.generateUidIdentifier("ref");
|
||||
|
||||
const declar = t.variableDeclaration("let", [
|
||||
t.variableDeclarator(param.node, uid),
|
||||
]);
|
||||
declar._blockHoist = outputParamsLength - i;
|
||||
|
||||
path.ensureBlock();
|
||||
path.get("body").unshiftContainer("body", declar);
|
||||
|
||||
param.replaceWith(uid);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -1,32 +1,28 @@
|
||||
import type { NodePath } from "babel-traverse";
|
||||
import { visitors } from "babel-traverse";
|
||||
|
||||
import * as destructuring from "./destructuring";
|
||||
import * as def from "./default";
|
||||
import * as rest from "./rest";
|
||||
import convertFunctionParams from "./params";
|
||||
import convertFunctionRest from "./rest";
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
visitor: visitors.merge([
|
||||
{
|
||||
ArrowFunctionExpression(path) {
|
||||
// In some conversion cases, it may have already been converted to a function while this callback
|
||||
// was queued up.
|
||||
if (!path.isArrowFunctionExpression()) return;
|
||||
visitor: {
|
||||
Function(path) {
|
||||
if (
|
||||
path.isArrowFunctionExpression() &&
|
||||
path
|
||||
.get("params")
|
||||
.some(param => param.isRestElement() || param.isAssignmentPattern())
|
||||
) {
|
||||
// default/rest visitors require access to `arguments`, so it cannot be an arrow
|
||||
path.arrowFunctionToExpression();
|
||||
}
|
||||
|
||||
// default/rest visitors require access to `arguments`
|
||||
const params: Array<NodePath> = path.get("params");
|
||||
for (const param of params) {
|
||||
if (param.isRestElement() || param.isAssignmentPattern()) {
|
||||
path.arrowFunctionToExpression();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
const convertedRest = convertFunctionRest(path);
|
||||
const convertedParams = convertFunctionParams(path, this.opts.loose);
|
||||
|
||||
if (convertedRest || convertedParams) {
|
||||
// Manually reprocess this scope to ensure that the moved params are updated.
|
||||
path.scope.crawl();
|
||||
}
|
||||
},
|
||||
destructuring.visitor,
|
||||
rest.visitor,
|
||||
def.visitor,
|
||||
]),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
162
packages/babel-plugin-transform-es2015-parameters/src/params.js
Normal file
162
packages/babel-plugin-transform-es2015-parameters/src/params.js
Normal file
@ -0,0 +1,162 @@
|
||||
import callDelegate from "babel-helper-call-delegate";
|
||||
import template from "babel-template";
|
||||
import * as t from "babel-types";
|
||||
|
||||
const buildDefaultParam = template(`
|
||||
let VARIABLE_NAME =
|
||||
arguments.length > ARGUMENT_KEY && arguments[ARGUMENT_KEY] !== undefined ?
|
||||
arguments[ARGUMENT_KEY]
|
||||
:
|
||||
DEFAULT_VALUE;
|
||||
`);
|
||||
|
||||
const buildLooseDefaultParam = template(`
|
||||
if (ASSIGNMENT_IDENTIFIER === UNDEFINED) {
|
||||
ASSIGNMENT_IDENTIFIER = DEFAULT_VALUE;
|
||||
}
|
||||
`);
|
||||
|
||||
const buildLooseDestructuredDefaultParam = template(`
|
||||
let ASSIGNMENT_IDENTIFIER = PARAMETER_NAME === UNDEFINED ? DEFAULT_VALUE : PARAMETER_NAME ;
|
||||
`);
|
||||
|
||||
const buildArgumentsAccess = template(`
|
||||
let $0 = arguments[$1];
|
||||
`);
|
||||
|
||||
function isSafeBinding(scope, node) {
|
||||
if (!scope.hasOwnBinding(node.name)) return true;
|
||||
const { kind } = scope.getOwnBinding(node.name);
|
||||
return kind === "param" || kind === "local";
|
||||
}
|
||||
|
||||
const iifeVisitor = {
|
||||
ReferencedIdentifier(path, state) {
|
||||
const { scope, node } = path;
|
||||
if (node.name === "eval" || !isSafeBinding(scope, node)) {
|
||||
state.iife = true;
|
||||
path.stop();
|
||||
}
|
||||
},
|
||||
|
||||
Scope(path) {
|
||||
// different bindings
|
||||
path.skip();
|
||||
},
|
||||
};
|
||||
|
||||
export default function convertFunctionParams(path, loose) {
|
||||
const { node, scope } = path;
|
||||
|
||||
const state = {
|
||||
iife: false,
|
||||
scope: scope,
|
||||
};
|
||||
|
||||
const body = [];
|
||||
|
||||
let firstOptionalIndex = null;
|
||||
|
||||
//
|
||||
const params = path.get("params");
|
||||
|
||||
if (loose) {
|
||||
const body = [];
|
||||
for (let i = 0; i < params.length; ++i) {
|
||||
const param = params[i];
|
||||
if (param.isAssignmentPattern()) {
|
||||
const left = param.get("left");
|
||||
const right = param.get("right");
|
||||
|
||||
const undefinedNode = scope.buildUndefinedNode();
|
||||
|
||||
if (left.isIdentifier()) {
|
||||
body.push(
|
||||
buildLooseDefaultParam({
|
||||
ASSIGNMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(left.node);
|
||||
} else if (left.isObjectPattern() || left.isArrayPattern()) {
|
||||
const paramName = scope.generateUidIdentifier();
|
||||
body.push(
|
||||
buildLooseDestructuredDefaultParam({
|
||||
ASSIGNMENT_IDENTIFIER: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
PARAMETER_NAME: paramName,
|
||||
UNDEFINED: undefinedNode,
|
||||
}),
|
||||
);
|
||||
param.replaceWith(paramName);
|
||||
}
|
||||
}
|
||||
}
|
||||
path.get("body").unshiftContainer("body", body);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i];
|
||||
|
||||
if (param.isAssignmentPattern()) {
|
||||
if (firstOptionalIndex === null) firstOptionalIndex = i;
|
||||
|
||||
const left = param.get("left");
|
||||
const right = param.get("right");
|
||||
|
||||
//
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && !isSafeBinding(scope, right.node)) {
|
||||
// the right hand side references a parameter
|
||||
state.iife = true;
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
const defNode = buildDefaultParam({
|
||||
VARIABLE_NAME: left.node,
|
||||
DEFAULT_VALUE: right.node,
|
||||
ARGUMENT_KEY: t.numericLiteral(i),
|
||||
});
|
||||
body.push(defNode);
|
||||
} else if (firstOptionalIndex !== null) {
|
||||
const defNode = buildArgumentsAccess(param.node, t.numericLiteral(i));
|
||||
body.push(defNode);
|
||||
} else if (param.isObjectPattern() || param.isArrayPattern()) {
|
||||
const uid = path.scope.generateUidIdentifier("ref");
|
||||
|
||||
const defNode = t.variableDeclaration("let", [
|
||||
t.variableDeclarator(param.node, uid),
|
||||
]);
|
||||
body.push(defNode);
|
||||
|
||||
param.replaceWith(uid);
|
||||
}
|
||||
|
||||
if (!state.iife && !param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (body.length === 0) return false;
|
||||
|
||||
// we need to cut off all trailing parameters
|
||||
if (firstOptionalIndex !== null) {
|
||||
node.params = node.params.slice(0, firstOptionalIndex);
|
||||
}
|
||||
|
||||
// ensure it's a block, useful for arrow functions
|
||||
path.ensureBlock();
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(path, scope));
|
||||
path.set("body", t.blockStatement(body));
|
||||
} else {
|
||||
path.get("body").unshiftContainer("body", body);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -220,124 +220,120 @@ function optimiseLengthGetter(path, argsId, offset) {
|
||||
}
|
||||
}
|
||||
|
||||
export const visitor = {
|
||||
Function(path) {
|
||||
const { node, scope } = path;
|
||||
if (!hasRest(node)) return;
|
||||
export default function convertFunctionRest(path) {
|
||||
const { node, scope } = path;
|
||||
if (!hasRest(node)) return false;
|
||||
|
||||
const rest = node.params.pop().argument;
|
||||
const rest = node.params.pop().argument;
|
||||
|
||||
const argsId = t.identifier("arguments");
|
||||
const argsId = t.identifier("arguments");
|
||||
|
||||
// check and optimise for extremely common cases
|
||||
const state = {
|
||||
references: [],
|
||||
offset: node.params.length,
|
||||
// check and optimise for extremely common cases
|
||||
const state = {
|
||||
references: [],
|
||||
offset: node.params.length,
|
||||
|
||||
argumentsNode: argsId,
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
argumentsNode: argsId,
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
|
||||
// candidate member expressions we could optimise if there are no other references
|
||||
candidates: [],
|
||||
// candidate member expressions we could optimise if there are no other references
|
||||
candidates: [],
|
||||
|
||||
// local rest binding name
|
||||
name: rest.name,
|
||||
// local rest binding name
|
||||
name: rest.name,
|
||||
|
||||
/*
|
||||
It may be possible to optimize the output code in certain ways, such as
|
||||
not generating code to initialize an array (perhaps substituting direct
|
||||
references to arguments[i] or arguments.length for reads of the
|
||||
corresponding rest parameter property) or positioning the initialization
|
||||
code so that it may not have to execute depending on runtime conditions.
|
||||
/*
|
||||
It may be possible to optimize the output code in certain ways, such as
|
||||
not generating code to initialize an array (perhaps substituting direct
|
||||
references to arguments[i] or arguments.length for reads of the
|
||||
corresponding rest parameter property) or positioning the initialization
|
||||
code so that it may not have to execute depending on runtime conditions.
|
||||
|
||||
This property tracks eligibility for optimization. "deopted" means give up
|
||||
and don't perform optimization. For example, when any of rest's elements /
|
||||
properties is assigned to at the top level, or referenced at all in a
|
||||
nested function.
|
||||
*/
|
||||
deopted: false,
|
||||
};
|
||||
This property tracks eligibility for optimization. "deopted" means give up
|
||||
and don't perform optimization. For example, when any of rest's elements /
|
||||
properties is assigned to at the top level, or referenced at all in a
|
||||
nested function.
|
||||
*/
|
||||
deopted: false,
|
||||
};
|
||||
|
||||
path.traverse(memberExpressionOptimisationVisitor, state);
|
||||
path.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// There are only "shorthand" references
|
||||
if (!state.deopted && !state.references.length) {
|
||||
for (const { path, cause } of (state.candidates: Array)) {
|
||||
switch (cause) {
|
||||
case "indexGetter":
|
||||
optimiseIndexGetter(path, argsId, state.offset);
|
||||
break;
|
||||
case "lengthGetter":
|
||||
optimiseLengthGetter(path, argsId, state.offset);
|
||||
break;
|
||||
default:
|
||||
path.replaceWith(argsId);
|
||||
}
|
||||
// There are only "shorthand" references
|
||||
if (!state.deopted && !state.references.length) {
|
||||
for (const { path, cause } of (state.candidates: Array)) {
|
||||
switch (cause) {
|
||||
case "indexGetter":
|
||||
optimiseIndexGetter(path, argsId, state.offset);
|
||||
break;
|
||||
case "lengthGetter":
|
||||
optimiseLengthGetter(path, argsId, state.offset);
|
||||
break;
|
||||
default:
|
||||
path.replaceWith(argsId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
state.references = state.references.concat(
|
||||
state.candidates.map(({ path }) => path),
|
||||
state.references = state.references.concat(
|
||||
state.candidates.map(({ path }) => path),
|
||||
);
|
||||
|
||||
const start = t.numericLiteral(node.params.length);
|
||||
const key = scope.generateUidIdentifier("key");
|
||||
const len = scope.generateUidIdentifier("len");
|
||||
|
||||
let arrKey = key;
|
||||
let arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.numericLiteral(0),
|
||||
);
|
||||
}
|
||||
|
||||
const start = t.numericLiteral(node.params.length);
|
||||
const key = scope.generateUidIdentifier("key");
|
||||
const len = scope.generateUidIdentifier("len");
|
||||
const loop = buildRest({
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len,
|
||||
});
|
||||
|
||||
let arrKey = key;
|
||||
let arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
if (state.deopted) {
|
||||
node.body.body.unshift(loop);
|
||||
} else {
|
||||
let target = path
|
||||
.getEarliestCommonAncestorFrom(state.references)
|
||||
.getStatementParent();
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.numericLiteral(0),
|
||||
);
|
||||
}
|
||||
|
||||
const loop = buildRest({
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len,
|
||||
// don't perform the allocation inside a loop
|
||||
target.findParent(path => {
|
||||
if (path.isLoop()) {
|
||||
target = path;
|
||||
} else {
|
||||
// Stop crawling up if this is a function.
|
||||
return path.isFunction();
|
||||
}
|
||||
});
|
||||
|
||||
if (state.deopted) {
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
} else {
|
||||
// perform allocation at the lowest common ancestor of all references
|
||||
loop._blockHoist = 1;
|
||||
target.insertBefore(loop);
|
||||
}
|
||||
|
||||
let target = path
|
||||
.getEarliestCommonAncestorFrom(state.references)
|
||||
.getStatementParent();
|
||||
|
||||
// don't perform the allocation inside a loop
|
||||
target.findParent(path => {
|
||||
if (path.isLoop()) {
|
||||
target = path;
|
||||
} else {
|
||||
// Stop crawling up if this is a function.
|
||||
return path.isFunction();
|
||||
}
|
||||
});
|
||||
|
||||
target.insertBefore(loop);
|
||||
}
|
||||
},
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
function fn(
|
||||
a1,
|
||||
a2 = 4,
|
||||
{a3, a4},
|
||||
a5,
|
||||
{a6, a7} = {}) {
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
function fn(a1) {
|
||||
var a2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4;
|
||||
var _arguments$ = arguments[2],
|
||||
a3 = _arguments$.a3,
|
||||
a4 = _arguments$.a4;
|
||||
var a5 = arguments[3];
|
||||
|
||||
var _ref = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {},
|
||||
a6 = _ref.a6,
|
||||
a7 = _ref.a7;
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
// #3861
|
||||
function t() {
|
||||
var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "default";
|
||||
var _ref = arguments[1];
|
||||
var a = _ref.a,
|
||||
b = _ref.b;
|
||||
var _arguments$ = arguments[1],
|
||||
a = _arguments$.a,
|
||||
b = _arguments$.b;
|
||||
|
||||
for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
||||
args[_key - 2] = arguments[_key];
|
||||
|
||||
@ -28,7 +28,7 @@ function d(thing) {
|
||||
};
|
||||
|
||||
{
|
||||
var _args = thing;
|
||||
var args = thing;
|
||||
foo(thing);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +113,6 @@ export default function({ types: t }) {
|
||||
const declar = t.variableDeclaration("let", [
|
||||
t.variableDeclarator(paramPath.node, uid),
|
||||
]);
|
||||
declar._blockHoist = i ? numParams - i : 1;
|
||||
|
||||
parentPath.ensureBlock();
|
||||
parentPath.get("body").unshiftContainer("body", declar);
|
||||
@ -129,7 +128,7 @@ export default function({ types: t }) {
|
||||
// function a({ b, ...c }) {}
|
||||
Function(path) {
|
||||
const params = path.get("params");
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
for (let i = params.length - 1; i >= 0; i--) {
|
||||
replaceRestElement(params[i].parentPath, params[i], i, params.length);
|
||||
}
|
||||
},
|
||||
|
||||
@ -17,15 +17,15 @@ function a3(_ref3) {
|
||||
c2 = babelHelpers.objectWithoutProperties(_ref3, ["a2", "b2"]);
|
||||
}
|
||||
|
||||
function a4(_ref4, _ref5) {
|
||||
let {
|
||||
a5
|
||||
} = _ref5,
|
||||
c5 = babelHelpers.objectWithoutProperties(_ref5, ["a5"]);
|
||||
function a4(_ref5, _ref4) {
|
||||
let {
|
||||
a3
|
||||
} = _ref5,
|
||||
c3 = babelHelpers.objectWithoutProperties(_ref5, ["a3"]);
|
||||
let {
|
||||
a5
|
||||
} = _ref4,
|
||||
c3 = babelHelpers.objectWithoutProperties(_ref4, ["a3"]);
|
||||
c5 = babelHelpers.objectWithoutProperties(_ref4, ["a5"]);
|
||||
}
|
||||
|
||||
function a5(_ref6) {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
function render(Component) {
|
||||
var text = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
||||
|
||||
var _ref = <Component text={text} />;
|
||||
var text = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '',
|
||||
_ref = <Component text={text} />;
|
||||
|
||||
return function () {
|
||||
return _ref;
|
||||
|
||||
@ -5,11 +5,23 @@ export { default as Identifier } from "./inferer-reference";
|
||||
export function VariableDeclarator() {
|
||||
const id = this.get("id");
|
||||
|
||||
if (id.isIdentifier()) {
|
||||
return this.get("init").getTypeAnnotation();
|
||||
} else {
|
||||
return;
|
||||
if (!id.isIdentifier()) return;
|
||||
const init = this.get("init");
|
||||
|
||||
let type = init.getTypeAnnotation();
|
||||
|
||||
if (type && type.type === "AnyTypeAnnotation") {
|
||||
// Detect "var foo = Array()" calls so we can optimize for arrays vs iterables.
|
||||
if (
|
||||
init.isCallExpression() &&
|
||||
init.get("callee").isIdentifier({ name: "Array" }) &&
|
||||
!init.scope.hasBinding("Array", true /* noGlobals */)
|
||||
) {
|
||||
type = ArrayExpression();
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
export function TypeCastExpression(node) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user