Skip to content

Commit eed1576

Browse files
author
Yui
committed
Merge pull request #1627 from Microsoft/emitArrowFunctionES6
Emit arrow function es6
2 parents 3f3e974 + 122d587 commit eed1576

File tree

59 files changed

+856
-73
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+856
-73
lines changed

src/compiler/checker.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -4861,6 +4861,16 @@ module ts {
48614861
function checkIdentifier(node: Identifier): Type {
48624862
var symbol = getResolvedSymbol(node);
48634863

4864+
// As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects.
4865+
// Although in down-level emit of arrow function, we emit it using function expression which means that
4866+
// arguments objects will be bound to the inner object; emitting arrow function natively in ES6, arguments objects
4867+
// will be bound to non-arrow function that contain this arrow function. This results in inconsistent behavior.
4868+
// To avoid that we will give an error to users if they use arguments objects in arrow function so that they
4869+
// can explicitly bound arguments objects
4870+
if (symbol === argumentsSymbol && getContainingFunction(node).kind === SyntaxKind.ArrowFunction) {
4871+
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression);
4872+
}
4873+
48644874
if (symbol.flags & SymbolFlags.Import) {
48654875
var symbolLinks = getSymbolLinks(symbol);
48664876
if (!symbolLinks.referenced) {
@@ -4915,7 +4925,9 @@ module ts {
49154925
// Now skip arrow functions to get the "real" owner of 'this'.
49164926
if (container.kind === SyntaxKind.ArrowFunction) {
49174927
container = getThisContainer(container, /* includeArrowFunctions */ false);
4918-
needToCaptureLexicalThis = true;
4928+
4929+
// When targeting es6, arrow function lexically bind "this" so we do not need to do the work of binding "this" in emitted code
4930+
needToCaptureLexicalThis = (languageVersion < ScriptTarget.ES6);
49194931
}
49204932

49214933
switch (container.kind) {

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -452,5 +452,6 @@ module ts {
452452
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
453453
yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported.", isEarly: true },
454454
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported.", isEarly: true },
455+
The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression: { code: 9002, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function. Consider using a standard function expression." },
455456
};
456457
}

src/compiler/diagnosticMessages.json

+7-3
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@
16121612
"Property '{0}' does not exist on 'const' enum '{1}'.": {
16131613
"category": "Error",
16141614
"code": 4088,
1615-
"isEarly": true
1615+
"isEarly": true
16161616
},
16171617
"The current host does not support the '{0}' option.": {
16181618
"category": "Error",
@@ -1902,11 +1902,15 @@
19021902
"'yield' expressions are not currently supported.": {
19031903
"category": "Error",
19041904
"code": 9000,
1905-
"isEarly": true
1905+
"isEarly": true
19061906
},
19071907
"Generators are not currently supported.": {
19081908
"category": "Error",
19091909
"code": 9001,
1910-
"isEarly": true
1910+
"isEarly": true
1911+
},
1912+
"The 'arguments' object cannot be referenced in an arrow function. Consider using a standard function expression.": {
1913+
"category": "Error",
1914+
"code": 9002
19111915
}
19121916
}

src/compiler/emitter.ts

+31-3
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,6 @@ module ts {
14871487

14881488
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compilerOnSave feature
14891489
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult {
1490-
// var program = resolver.getProgram();
14911490
var compilerOptions = host.getCompilerOptions();
14921491
var languageVersion = compilerOptions.target || ScriptTarget.ES3;
14931492
var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined;
@@ -3240,6 +3239,10 @@ module ts {
32403239
emitSignatureAndBody(node);
32413240
}
32423241

3242+
function shouldEmitAsArrowFunction(node: FunctionLikeDeclaration): boolean {
3243+
return node.kind === SyntaxKind.ArrowFunction && languageVersion >= ScriptTarget.ES6;
3244+
}
3245+
32433246
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
32443247
if (nodeIsMissing(node.body)) {
32453248
return emitPinnedOrTripleSlashComments(node);
@@ -3249,7 +3252,13 @@ module ts {
32493252
// Methods will emit the comments as part of emitting method declaration
32503253
emitLeadingComments(node);
32513254
}
3252-
write("function ");
3255+
3256+
// For targeting below es6, emit functions-like declaration including arrow function using function keyword.
3257+
// When targeting ES6, emit arrow function natively in ES6 by omitting function keyword and using fat arrow instead
3258+
if (!shouldEmitAsArrowFunction(node)) {
3259+
write("function ");
3260+
}
3261+
32533262
if (node.kind === SyntaxKind.FunctionDeclaration || (node.kind === SyntaxKind.FunctionExpression && node.name)) {
32543263
emit(node.name);
32553264
}
@@ -3280,14 +3289,32 @@ module ts {
32803289
decreaseIndent();
32813290
}
32823291

3292+
function emitSignatureParametersForArrow(node: FunctionLikeDeclaration) {
3293+
// Check whether the parameter list needs parentheses and preserve no-parenthesis
3294+
if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) {
3295+
emit(node.parameters[0]);
3296+
return;
3297+
}
3298+
emitSignatureParameters(node);
3299+
}
3300+
32833301
function emitSignatureAndBody(node: FunctionLikeDeclaration) {
32843302
var saveTempCount = tempCount;
32853303
var saveTempVariables = tempVariables;
32863304
var saveTempParameters = tempParameters;
32873305
tempCount = 0;
32883306
tempVariables = undefined;
32893307
tempParameters = undefined;
3290-
emitSignatureParameters(node);
3308+
3309+
// When targeting ES6, emit arrow function natively in ES6
3310+
if (shouldEmitAsArrowFunction(node)) {
3311+
emitSignatureParametersForArrow(node);
3312+
write(" =>");
3313+
}
3314+
else {
3315+
emitSignatureParameters(node);
3316+
}
3317+
32913318
write(" {");
32923319
scopeEmitStart(node);
32933320
increaseIndent();
@@ -3299,6 +3326,7 @@ module ts {
32993326
startIndex = emitDirectivePrologues((<Block>node.body).statements, /*startWithNewLine*/ true);
33003327
}
33013328
var outPos = writer.getTextPos();
3329+
33023330
emitCaptureThisForNodeIfNecessary(node);
33033331
emitDefaultValueAssignments(node);
33043332
emitRestParameter(node);

src/harness/harness.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ module Utils {
107107
export function memoize<T extends Function>(f: T): T {
108108
var cache: { [idx: string]: any } = {};
109109

110-
return <any>(() => {
110+
return <any>(function () {
111111
var key = Array.prototype.join.call(arguments);
112112
var cachedResult = cache[key];
113113
if (cachedResult) {

src/harness/loggedIO.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ module Playback {
138138

139139
function recordReplay<T extends Function>(original: T, underlying: any) {
140140
function createWrapper(record: T, replay: T): T {
141-
return <any>(() => {
141+
return <any>(function () {
142142
if (replayLog !== undefined) {
143143
return replay.apply(undefined, arguments);
144144
} else if (recordLog !== undefined) {

src/harness/projectsRunner.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class ProjectRunner extends RunnerBase {
186186
function createCompilerHost(): ts.CompilerHost {
187187
return {
188188
getSourceFile,
189-
getDefaultLibFilename: options => options.target === ts.ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts",
189+
getDefaultLibFilename: options => Harness.Compiler.defaultLibFileName,
190190
writeFile,
191191
getCurrentDirectory,
192192
getCanonicalFileName: Harness.Compiler.getCanonicalFileName,

tests/baselines/reference/computedPropertyNames29.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ var C = (function () {
1515
function C() {
1616
}
1717
C.prototype.bar = function () {
18-
var _this = this;
19-
(function () {
18+
(() => {
2019
var obj = {
21-
[_this.bar()]() {
20+
[this.bar()]() {
2221
} // needs capture
2322
};
2423
});

tests/baselines/reference/computedPropertyNames3.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var C = (function () {
1616
}
1717
C.prototype[0 + 1] = function () {
1818
};
19-
C[function () {
19+
C[() => {
2020
}] = function () {
2121
};
2222
Object.defineProperty(C.prototype, delete id, {

tests/baselines/reference/computedPropertyNames30.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var C = (function (_super) {
3131
__extends(C, _super);
3232
function C() {
3333
_super.call(this);
34-
(function () {
34+
(() => {
3535
var obj = {
3636
// Ideally, we would capture this. But the reference is
3737
// illegal, and not capturing this is consistent with

tests/baselines/reference/computedPropertyNames31.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var C = (function (_super) {
3737
}
3838
C.prototype.foo = function () {
3939
var _this = this;
40-
(function () {
40+
(() => {
4141
var obj = {
4242
[_super.prototype.bar.call(_this)]() {
4343
} // needs capture

tests/baselines/reference/computedPropertyNamesContextualType1.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ var o = {
1414
["" + 0](y) {
1515
return y.length;
1616
},
17-
["" + 1]: function (y) { return y.length; }
17+
["" + 1]: y => { return y.length; }
1818
};

tests/baselines/reference/computedPropertyNamesContextualType2.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ var o = {
1414
[+"foo"](y) {
1515
return y.length;
1616
},
17-
[+"bar"]: function (y) { return y.length; }
17+
[+"bar"]: y => { return y.length; }
1818
};

tests/baselines/reference/computedPropertyNamesContextualType3.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ var o = {
1313
[+"foo"](y) {
1414
return y.length;
1515
},
16-
[+"bar"]: function (y) { return y.length; }
16+
[+"bar"]: y => { return y.length; }
1717
};

tests/baselines/reference/computedPropertyNamesContextualType6.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ foo({
1616
//// [computedPropertyNamesContextualType6.js]
1717
foo({
1818
p: "",
19-
0: function () {
19+
0: () => {
2020
},
2121
["hi" + "bye"]: true,
2222
[0 + 1]: 0,

tests/baselines/reference/computedPropertyNamesContextualType7.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ foo({
1616
//// [computedPropertyNamesContextualType7.js]
1717
foo({
1818
p: "",
19-
0: function () {
19+
0: () => {
2020
},
2121
["hi" + "bye"]: true,
2222
[0 + 1]: 0,

tests/baselines/reference/constDeclarations-scopes.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ function F() {
223223
const c = 0;
224224
n = c;
225225
}
226-
var F2 = function () {
226+
var F2 = () => {
227227
const c = 0;
228228
n = c;
229229
};
@@ -272,7 +272,7 @@ var o = {
272272
const c = 0;
273273
n = c;
274274
},
275-
f2: function () {
275+
f2: () => {
276276
const c = 0;
277277
n = c;
278278
}

tests/baselines/reference/constDeclarations-validContexts.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ const c18 = 0;
186186
function F() {
187187
const c19 = 0;
188188
}
189-
var F2 = function () {
189+
var F2 = () => {
190190
const c20 = 0;
191191
};
192192
var F3 = function () {
@@ -226,7 +226,7 @@ var o = {
226226
f() {
227227
const c28 = 0;
228228
},
229-
f2: function () {
229+
f2: () => {
230230
const c29 = 0;
231231
}
232232
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [emitArrowFunction.ts]
2+
var f1 = () => { }
3+
var f2 = (x: string, y: string) => { }
4+
var f3 = (x: string, y: number, ...rest) => { }
5+
var f4 = (x: string, y: number, z = 10) => { }
6+
function foo(func: () => boolean) { }
7+
foo(() => true);
8+
foo(() => { return false; });
9+
10+
//// [emitArrowFunction.js]
11+
var f1 = function () {
12+
};
13+
var f2 = function (x, y) {
14+
};
15+
var f3 = function (x, y) {
16+
var rest = [];
17+
for (var _i = 2; _i < arguments.length; _i++) {
18+
rest[_i - 2] = arguments[_i];
19+
}
20+
};
21+
var f4 = function (x, y, z) {
22+
if (z === void 0) { z = 10; }
23+
};
24+
function foo(func) {
25+
}
26+
foo(function () { return true; });
27+
foo(function () {
28+
return false;
29+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== tests/cases/conformance/es6/arrowFunction/emitArrowFunction.ts ===
2+
var f1 = () => { }
3+
>f1 : () => void
4+
>() => { } : () => void
5+
6+
var f2 = (x: string, y: string) => { }
7+
>f2 : (x: string, y: string) => void
8+
>(x: string, y: string) => { } : (x: string, y: string) => void
9+
>x : string
10+
>y : string
11+
12+
var f3 = (x: string, y: number, ...rest) => { }
13+
>f3 : (x: string, y: number, ...rest: any[]) => void
14+
>(x: string, y: number, ...rest) => { } : (x: string, y: number, ...rest: any[]) => void
15+
>x : string
16+
>y : number
17+
>rest : any[]
18+
19+
var f4 = (x: string, y: number, z = 10) => { }
20+
>f4 : (x: string, y: number, z?: number) => void
21+
>(x: string, y: number, z = 10) => { } : (x: string, y: number, z?: number) => void
22+
>x : string
23+
>y : number
24+
>z : number
25+
26+
function foo(func: () => boolean) { }
27+
>foo : (func: () => boolean) => void
28+
>func : () => boolean
29+
30+
foo(() => true);
31+
>foo(() => true) : void
32+
>foo : (func: () => boolean) => void
33+
>() => true : () => boolean
34+
35+
foo(() => { return false; });
36+
>foo(() => { return false; }) : void
37+
>foo : (func: () => boolean) => void
38+
>() => { return false; } : () => boolean
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [emitArrowFunctionAsIs.ts]
2+
var arrow1 = a => { };
3+
var arrow2 = (a) => { };
4+
5+
var arrow3 = (a, b) => { };
6+
7+
//// [emitArrowFunctionAsIs.js]
8+
var arrow1 = function (a) {
9+
};
10+
var arrow2 = function (a) {
11+
};
12+
var arrow3 = function (a, b) {
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/es6/arrowFunction/emitArrowFunctionAsIs.ts ===
2+
var arrow1 = a => { };
3+
>arrow1 : (a: any) => void
4+
>a => { } : (a: any) => void
5+
>a : any
6+
7+
var arrow2 = (a) => { };
8+
>arrow2 : (a: any) => void
9+
>(a) => { } : (a: any) => void
10+
>a : any
11+
12+
var arrow3 = (a, b) => { };
13+
>arrow3 : (a: any, b: any) => void
14+
>(a, b) => { } : (a: any, b: any) => void
15+
>a : any
16+
>b : any
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [emitArrowFunctionAsIsES6.ts]
2+
var arrow1 = a => { };
3+
var arrow2 = (a) => { };
4+
5+
var arrow3 = (a, b) => { };
6+
7+
//// [emitArrowFunctionAsIsES6.js]
8+
var arrow1 = a => {
9+
};
10+
var arrow2 = (a) => {
11+
};
12+
var arrow3 = (a, b) => {
13+
};

0 commit comments

Comments
 (0)