Skip to content

Transform arrow function in variable declaration to named function #16001

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

Closed
wants to merge 2 commits into from
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 24 additions & 7 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1679,17 +1679,18 @@ namespace ts {
*
* @param node An ArrowFunction node.
*/
function visitArrowFunction(node: ArrowFunction) {
function visitArrowFunction(node: ArrowFunction, functionName?: Identifier) {
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
enableSubstitutionsForCapturedThis();
}
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const ancestorFacts = enterSubtree(HierarchyFacts.ArrowFunctionExcludes, HierarchyFacts.ArrowFunctionIncludes);

const func = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*name*/ functionName,
/*typeParameters*/ undefined,
visitParameterList(node.parameters, visitor, context),
/*type*/ undefined,
Expand All @@ -1708,7 +1709,7 @@ namespace ts {
*
* @param node a FunctionExpression node.
*/
function visitFunctionExpression(node: FunctionExpression): Expression {
function visitFunctionExpression(node: FunctionExpression, functionName?: Identifier): Expression {
const ancestorFacts = getEmitFlags(node) & EmitFlags.AsyncFunctionBody
? enterSubtree(HierarchyFacts.AsyncFunctionBodyExcludes, HierarchyFacts.AsyncFunctionBodyIncludes)
: enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
Expand All @@ -1721,7 +1722,7 @@ namespace ts {
: visitFunctionBodyDownLevel(node);
const name = hierarchyFacts & HierarchyFacts.NewTarget
? getLocalName(node)
: node.name;
: (functionName && !node.name) ? functionName : node.name;

exitSubtree(ancestorFacts, HierarchyFacts.PropagateNewTargetMask, HierarchyFacts.None);
convertedLoopState = savedConvertedLoopState;
Expand Down Expand Up @@ -2164,7 +2165,24 @@ namespace ts {
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
const ancestorFacts = enterSubtree(HierarchyFacts.ExportedVariableStatement, HierarchyFacts.None);
let updated: VisitResult<VariableDeclaration>;
if (isBindingPattern(node.name)) {

if (isArrowFunction(node.initializer)) {
const clonedNode = getMutableClone(node);
const name = (clonedNode.name && (<Identifier>clonedNode.name).text) ? createIdentifier((<Identifier>clonedNode.name).text) : undefined;
if (name) {
name.parent = clonedNode.initializer;
}
clonedNode.initializer = visitArrowFunction((<ArrowFunction>node.initializer), name);
updated = clonedNode;
} else if (isFunctionExpression(node.initializer)) {
const clonedNode = getMutableClone(node);
const name = (clonedNode.name && (<Identifier>clonedNode.name).text) ? createIdentifier((<Identifier>clonedNode.name).text) : undefined;
if (name) {
name.parent = clonedNode.initializer;
}
clonedNode.initializer = visitFunctionExpression(<FunctionExpression>node.initializer, name);
updated = clonedNode;
} else if (isBindingPattern(node.name)) {
updated = flattenDestructuringBinding(
node,
visitor,
Expand All @@ -2173,8 +2191,7 @@ namespace ts {
/*value*/ undefined,
(ancestorFacts & HierarchyFacts.ExportedVariableStatement) !== 0
);
}
else {
} else {
updated = visitEachChild(node, visitor, context);
}

Expand Down
16 changes: 16 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3764,6 +3764,22 @@ namespace ts {
|| kind === SyntaxKind.OmittedExpression;
}

export function isArrowFunction(node?: Node): node is ArrowFunction {
if (node) {
return node.kind === SyntaxKind.ArrowFunction;
}

return false;
}

export function isFunctionExpression(node?: Node): node is FunctionExpression {
if (node) {
return node.kind === SyntaxKind.FunctionExpression;
}

return false;
}


/**
* Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/ArrowFunction1.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ var v = (a: ) => {
};

//// [ArrowFunction1.js]
var v = function (a) {
var v = function v(a) {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/ArrowFunction3.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ var v = (a): => {
};

//// [ArrowFunction3.js]
var v = function (a) {
var v = function v(a) {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/ArrowFunction4.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ var v = (a, b) => {
};

//// [ArrowFunction4.js]
var v = function (a, b) {
var v = function v(a, b) {
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/ArrowFunctionExpression1.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
var v = (public x: string) => { };

//// [ArrowFunctionExpression1.js]
var v = function (x) { };
var v = function v(x) { };
2 changes: 1 addition & 1 deletion tests/baselines/reference/ClassDeclaration26.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ var C = (function () {
}
return C;
}());
var constructor = function () { };
var constructor = function constructor() { };
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ exports.VisualizationModel = VisualizationModel;
"use strict";
exports.__esModule = true;
var moduleA = require("./aliasUsageInFunctionExpression_moduleA");
var f = function (x) { return x; };
var f = function f(x) { return x; };
f = function (x) { return moduleA; };
2 changes: 1 addition & 1 deletion tests/baselines/reference/aliasUsedAsNameValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ exports.__esModule = true;
///<reference path='aliasUsedAsNameValue_1.ts' />
var mod = require("./aliasUsedAsNameValue_0");
var b = require("./aliasUsedAsNameValue_1");
exports.a = function () {
exports.a = function a() {
//var x = mod.id; // TODO needed hack that mod is loaded
b.b(mod);
};
2 changes: 1 addition & 1 deletion tests/baselines/reference/ambiguousGenericAssertion1.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var r3 = <<T>(x: T) => T>f; // ambiguous, appears to the parser as a << operatio

//// [ambiguousGenericAssertion1.js]
function f(x) { return null; }
var r = function (x) { return x; };
var r = function r(x) { return x; };
var r2 = f; // valid
var r3 = << T > (x), T;
T > f; // ambiguous, appears to the parser as a << operation
2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayAssignmentTest1.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ var i1 = c1;
var c2 = new C2();
var c3 = new C3();
var o1 = { one: 1 };
var f1 = function () { return new C1(); };
var f1 = function f1() { return new C1(); };
var arr_any = [];
var arr_i1 = [];
var arr_c1 = [];
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayAssignmentTest2.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ var i1 = c1;
var c2 = new C2();
var c3 = new C3();
var o1 = { one: 1 };
var f1 = function () { return new C1(); };
var f1 = function f1() { return new C1(); };
var arr_any = [];
var arr_i1 = [];
var arr_c1 = [];
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/arrowFunctionContexts.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ var __extends = (this && this.__extends) || (function () {
var _this = this;
// Arrow function used in with statement
with (window) {
var p = function () { return _this; };
var p = function p() { return _this; };
}
// Arrow function as argument to super call
var Base = (function () {
Expand All @@ -128,7 +128,7 @@ var Derived = (function (_super) {
// Arrow function as function argument
window.setTimeout(function () { return null; }, 100);
// Arrow function as value in array literal
var obj = function (n) { return ''; };
var obj = function obj(n) { return ''; };
var obj; // OK
var arr = [function (n) { return ''; }];
var arr; // Incorrect error here (bug 829597)
Expand All @@ -143,15 +143,15 @@ var E;
var M;
(function (M) {
M.a = function (s) { return ''; };
var b = function (s) { return s; };
var b = function b(s) { return s; };
})(M || (M = {}));
// Repeat above for module members that are functions? (necessary to redo all of them?)
var M2;
(function (M2) {
var _this = this;
// Arrow function used in with statement
with (window) {
var p = function () { return _this; };
var p = function p() { return _this; };
}
// Arrow function as argument to super call
var Base = (function () {
Expand All @@ -170,7 +170,7 @@ var M2;
// Arrow function as function argument
window.setTimeout(function () { return null; }, 100);
// Arrow function as value in array literal
var obj = function (n) { return ''; };
var obj = function obj(n) { return ''; };
var obj; // OK
var arr = [function (n) { return ''; }];
var arr; // Incorrect error here (bug 829597)
Expand All @@ -185,13 +185,13 @@ var M2;
var M;
(function (M) {
M.a = function (s) { return ''; };
var b = function (s) { return s; };
var b = function b(s) { return s; };
})(M || (M = {}));
})(M2 || (M2 = {}));
// <Identifier>(ParamList) => { ... } is a generic arrow function
var generic1 = function (n) { return [n]; };
var generic1 = function generic1(n) { return [n]; };
var generic1; // Incorrect error, Bug 829597
var generic2 = function (n) { return [n]; };
var generic2 = function generic2(n) { return [n]; };
var generic2;
// <Identifier> ((ParamList) => { ... } ) is a type assertion to an arrow function
var asserted1 = (function (n) { return [n]; });
Expand Down
54 changes: 27 additions & 27 deletions tests/baselines/reference/arrowFunctionExpressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,45 +101,45 @@ function tryCatchFn() {

//// [arrowFunctionExpressions.js]
// ArrowFormalParameters => AssignmentExpression is equivalent to ArrowFormalParameters => { return AssignmentExpression; }
var a = function (p) { return p.length; };
var a = function (p) { return p.length; };
var a = function a(p) { return p.length; };
var a = function a(p) { return p.length; };
// Identifier => Block is equivalent to(Identifier) => Block
var b = function (j) { return 0; };
var b = function (j) { return 0; };
var b = function b(j) { return 0; };
var b = function b(j) { return 0; };
// Identifier => AssignmentExpression is equivalent to(Identifier) => AssignmentExpression
var c;
var d = function (n) { return c = n; };
var d = function (n) { return c = n; };
var d = function d(n) { return c = n; };
var d = function d(n) { return c = n; };
var d;
// Binding patterns in arrow functions
var p1 = function (_a) {
var p1 = function p1(_a) {
var a = _a[0];
};
var p2 = function (_a) {
var p2 = function p2(_a) {
var a = _a.slice(0);
};
var p3 = function (_a) {
var p3 = function p3(_a) {
var a = _a[1];
};
var p4 = function (_a) {
var p4 = function p4(_a) {
var a = _a.slice(1);
};
var p5 = function (_a) {
var p5 = function p5(_a) {
var _b = _a[0], a = _b === void 0 ? 1 : _b;
};
var p6 = function (_a) {
var p6 = function p6(_a) {
var a = _a.a;
};
var p7 = function (_a) {
var p7 = function p7(_a) {
var b = _a.a.b;
};
var p8 = function (_a) {
var p8 = function p8(_a) {
var _b = _a.a, a = _b === void 0 ? 1 : _b;
};
var p9 = function (_a) {
var p9 = function p9(_a) {
var _b = _a.a, _c = (_b === void 0 ? { b: 1 } : _b).b, b = _c === void 0 ? 1 : _c;
};
var p10 = function (_a) {
var p10 = function p10(_a) {
var _b = _a[0], value = _b.value, done = _b.done;
};
// Arrow function used in class member initializer
Expand All @@ -152,35 +152,35 @@ var MyClass = (function () {
}
MyClass.prototype.fn = function () {
var _this = this;
var m = function (n) { return n + 1; };
var p = function (n) { return n && _this; };
var m = function m(n) { return n + 1; };
var p = function p(n) { return n && _this; };
};
return MyClass;
}());
// Arrow function used in arrow function
var arrrr = function () { return function (m) { return function () { return function (n) { return m + n; }; }; }; };
var arrrr = function arrrr() { return function (m) { return function () { return function (n) { return m + n; }; }; }; };
var e = arrrr()(3)()(4);
var e;
// Arrow function used in arrow function used in function
function someFn() {
var arr = function (n) { return function (p) { return p * n; }; };
var arr = function arr(n) { return function (p) { return p * n; }; };
arr(3)(4).toExponential();
}
// Arrow function used in function
function someOtherFn() {
var arr = function (n) { return '' + n; };
var arr = function arr(n) { return '' + n; };
arr(4).charAt(0);
}
// Arrow function used in nested function in function
function outerFn() {
function innerFn() {
var arrowFn = function () { };
var arrowFn = function arrowFn() { };
var p = arrowFn();
var p;
}
}
// Arrow function used in nested function in arrow function
var f = function (n) {
var f = function f(n) {
function fn(x) {
return function () { return n + x; };
}
Expand All @@ -190,7 +190,7 @@ var g = f('')();
var g;
// Arrow function used in nested function in arrow function in nested function
function someOuterFn() {
var arr = function (n) {
var arr = function arr(n) {
function innerFn() {
return function () { return n.length; };
}
Expand All @@ -204,12 +204,12 @@ h.toExponential();
function tryCatchFn() {
var _this = this;
try {
var x = function () { return _this; };
var x = function x() { return _this; };
}
catch (e) {
var t = function () { return e + _this; };
var t = function t() { return e + _this; };
}
finally {
var m = function () { return _this + ''; };
var m = function m() { return _this + ''; };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ var square = (x: number) => x * x;

//// [arrowFunctionMissingCurlyWithSemicolon.js]
// Should error at semicolon.
var f = function () { return ; };
var f = function f() { return ; };
var b = 1 * 2 * 3 * 4;
var square = function (x) { return x * x; };
var square = function square(x) { return x * x; };
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
var v = a => <any>{}

//// [arrowFunctionWithObjectLiteralBody1.js]
var v = function (a) { return ({}); };
var v = function v(a) { return ({}); };
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
var v = a => <any><any>{}

//// [arrowFunctionWithObjectLiteralBody2.js]
var v = function (a) { return ({}); };
var v = function v(a) { return ({}); };
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var c = () => ({ name: "foo", message: "bar" });
var d = () => ((<Error>({ name: "foo", message: "bar" })));

//// [arrowFunctionWithObjectLiteralBody5.js]
var a = function () { return ({ name: "foo", message: "bar" }); };
var b = function () { return ({ name: "foo", message: "bar" }); };
var c = function () { return ({ name: "foo", message: "bar" }); };
var d = function () { return (({ name: "foo", message: "bar" })); };
var a = function a() { return ({ name: "foo", message: "bar" }); };
var b = function b() { return ({ name: "foo", message: "bar" }); };
var c = function c() { return ({ name: "foo", message: "bar" }); };
var d = function d() { return (({ name: "foo", message: "bar" })); };
Loading