8000 Merge pull request #3066 from tinganho/newWithSpread · myrtleTree33/TypeScript@5bea6a9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5bea6a9

Browse files
committed
Merge pull request microsoft#3066 from tinganho/newWithSpread
New with spread
2 parents 0287d2f + ccd3de3 commit 5bea6a9

25 files changed

+2993
-109
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ tests/services/baselines/local/*
2121
tests/baselines/prototyping/local/*
2222
tests/baselines/rwc/*
2323
tests/baselines/test262/*
24+
tests/baselines/reference/projectOutput/*
2425
tests/baselines/local/projectOutput/*
2526
tests/services/baselines/prototyping/local/*
2627
tests/services/browser/typescriptServices.js

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6605,7 +6605,7 @@ module ts {
66056605
result.splice(spliceIndex, 0, signature);
66066606
}
66076607
}
6608-
6608+
66096609
function getSpreadArgumentIndex(args: Expression[]): number {
66106610
for (let i = 0; i < args.length; i++) {
66116611
if (args[i].kind === SyntaxKind.SpreadElementExpression) {
@@ -7127,10 +7127,10 @@ module ts {
71277127
}
71287128

71297129
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
7130-
if (node.arguments && languageVersion < ScriptTarget.ES6) {
7130+
if (node.arguments && languageVersion < ScriptTarget.ES5) {
71317131
let spreadIndex = getSpreadArgumentIndex(node.arguments);
71327132
if (spreadIndex >= 0) {
7133-
error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher);
7133+
error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher);
71347134
}
71357135
}
71367136

@@ -7148,7 +7148,7 @@ module ts {
71487148
// If ConstructExpr's apparent type(section 3.8.1) is an object type with one or
71497149
// more construct signatures, the expression is processed in the same manner as a
71507150
// function call, but using the construct signatures as the initial set of candidate
7151-
// signatures for overload resolution.The result type of the function call becomes
7151+
// signatures for overload resolution. The result type of the function call becomes
71527152
// the result type of the operation.
71537153
expressionType = getApparentType(expressionType);
71547154
if (expressionType === unknownType) {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ module ts {
334334
The_0_operator_cannot_be_applied_to_type_symbol: { code: 2469, category: DiagnosticCategory.Error, key: "The '{0}' operator cannot be applied to type 'symbol'." },
335335
Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object: { code: 2470, category: DiagnosticCategory.Error, key: "'Symbol' reference does not refer to the global Symbol constructor object." },
336336
A_computed_property_name_of_the_form_0_must_be_of_type_symbol: { code: 2471, category: DiagnosticCategory.Error, key: "A computed property name of the form '{0}' must be of type 'symbol'." },
337-
Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher: { code: 2472, category: DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher." },
337+
Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher: { code: 2472, category: DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 5 and higher." },
338338
Enum_declarations_must_all_be_const_or_non_const: { code: 2473, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
339339
In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 2474, category: DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression." },
340340
const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment: { code: 2475, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment." },

src/compiler/diagnosticMessages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@
13241324
"category": "Error",
13251325
"code": 2471
13261326
},
1327-
"Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.": {
1327+
"Spread operator in 'new' expressions is only available when targeting ECMAScript 5 and higher.": {
13281328
"category": "Error",
13291329
"code": 2472
13301330
},

src/compiler/emitter.ts

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,24 +1366,24 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
13661366
return true;
13671367
}
13681368

1369-
function emitListWithSpread(elements: Expression[], alwaysCopy: boolean, multiLine: boolean, trailingComma: boolean) {
1369+
function emitListWithSpread(elements: Expression[], needsUniqueCopy: boolean, multiLine: boolean, trailingComma: boolean, useConcat: boolean) {
13701370
let pos = 0;
13711371
let group = 0;
13721372
let length = elements.length;
13731373
while (pos < length) {
13741374
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
1375-
if (group === 1) {
1375+
if (group === 1 && useConcat) {
13761376
write(".concat(");
13771377
}
1378-
else if (group > 1) {
1378+
else if (group > 0) {
13791379
write(", ");
13801380
}
13811381
let e = elements[pos];
13821382
if (e.kind === SyntaxKind.SpreadElementExpression) {
13831383
e = (<SpreadElementExpression>e).expression;
13841384
emitParenthesizedIf(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccessOrInvocation(e));
13851385
pos++;
1386-
if (pos === length && group === 0 && alwaysCopy && e.kind !== SyntaxKind.ArrayLiteralExpression) {
1386+
if (pos === length && group === 0 && needsUniqueCopy && e.kind !== SyntaxKind.ArrayLiteralExpression) {
13871387
write(".slice()");
13881388
}
13891389
}
@@ -1406,7 +1406,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14061406
group++;
14071407
}
14081408
if (group > 1) {
1409-
write(")");
1409+
if(useConcat) {
1410+
write(")");
1411+
}
14101412
}
14111413
}
14121414

@@ -1425,8 +1427,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14251427
write("]");
14261428
}
14271429
else {
1428-
emitListWithSpread(elements, /*alwaysCopy*/ true, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0,
1429-
/*trailingComma*/ elements.hasTrailingComma);
1430+
emitListWithSpread(elements, /*needsUniqueCopy*/ true, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0,
1431+
/*trailingComma*/ elements.hasTrailingComma, /*useConcat*/ true);
14301432
}
14311433
}
14321434

@@ -1850,7 +1852,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
18501852
write("void 0");
18511853
}
18521854
write(", ");
1853-
emitListWithSpread(node.arguments, /*alwaysCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false);
1855+
emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false, /*useConcat*/ true);
18541856
write(")");
18551857
}
18561858

@@ -1886,11 +1888,44 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
18861888

18871889
function emitNewExpression(node: NewExpression) {
18881890
write("new ");
1889-
emit(node.expression);
1890-
if (node.arguments) {
1891+
1892+
// Spread operator logic can be supported in new expressions in ES5 using a combination
1893+
// of Function.prototype.bind() and Function.prototype.apply().
1894+
//
1895+
// Example:
1896+
//
1897+
// var arguments = [1, 2, 3, 4, 5];
1898+
// new Array(...arguments);
1899+
//
1900+
// Could be transpiled into ES5:
1901+
//
1902+
// var arguments = [1, 2, 3, 4, 5];
1903+
// new (Array.bind.apply(Array, [void 0].concat(arguments)));
1904+
//
1905+
// `[void 0]` is the first argument which represents `thisArg` to the bind method above.
1906+
// And `thisArg` will be set to the return value of the constructor when instantiated
1907+
// with the new operator — regardless of any value we set `thisArg` to. Thus, we set it
1908+
// to an undefined, `void 0`.
1909+
if (languageVersion === ScriptTarget.ES5 &&
1910+
node.arguments &&
1911+
hasSpreadElement(node.arguments)) {
1912+
18911913
write("(");
1892-
emitCommaList(node.arguments);
1893-
write(")");
1914+
let target = emitCallTarget(node.expression);
1915+
write(".bind.apply(");
1916+
emit(target);
1917+
write(", [void 0].concat(");
1918+
emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiline*/ false, /*trailingComma*/ false, /*useConcat*/ false);
1919+
write(")))");
1920+
write("()");
1921+
}
1922+
else {
1923+
emit(node.expression);
1924+
if (node.arguments) {
1925+
write("(");
1926+
emitCommaList(node.arguments);
1927+
write(")");
1928+
}
18941929
}
18951930
}
18961931

tests/baselines/reference/callWithSpread.errors.txt

Lines changed: 0 additions & 59 deletions
This file was deleted.

tests/baselines/reference/callWithSpread.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ class D extends C {
4848
super.foo(1, 2, ...a);
4949
}
5050
}
51-
52-
// Only supported in when target is ES6
53-
var c = new C(1, 2, ...a);
5451

5552

5653
//// [callWithSpread.js]
@@ -112,6 +109,4 @@ var D = (function (_super) {
112109
};
113110
return D;
114111
})(C);
115-
// Only supported in when target is ES6
116-
var c = new C(1, 2, ...a);
117112
var _a, _b, _c;

0 commit comments

Comments
 (0)
0