Skip to content

Commit a79f598

Browse files
committed
Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
2 parents bb817c7 + d982014 commit a79f598

115 files changed

Lines changed: 348 additions & 175 deletions

File tree

Some content is hidden

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

src/compiler/transformers/es2017.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,10 +775,11 @@ namespace ts {
775775
priority: 5,
776776
text: `
777777
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
778+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
778779
return new (P || (P = Promise))(function (resolve, reject) {
779780
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
780781
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
781-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
782+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
782783
step((generator = generator.apply(thisArg, _arguments || [])).next());
783784
});
784785
};`

src/compiler/transformers/es2018.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,39 @@ namespace ts {
229229
if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
230230
// spread elements emit like so:
231231
// non-spread elements are chunked together into object literals, and then all are passed to __assign:
232-
// { a, ...o, b } => __assign({a}, o, {b});
232+
// { a, ...o, b } => __assign(__assign({a}, o), {b});
233233
// If the first element is a spread element, then the first argument to __assign is {}:
234-
// { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2)
234+
// { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2)
235+
//
236+
// We cannot call __assign with more than two elements, since any element could cause side effects. For
237+
// example:
238+
// var k = { a: 1, b: 2 };
239+
// var o = { a: 3, ...k, b: k.a++ };
240+
// // expected: { a: 1, b: 1 }
241+
// If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before
242+
// `k` is spread and we end up with `{ a: 2, b: 1 }`.
243+
//
244+
// This also occurs for spread elements, not just property assignments:
245+
// var k = { a: 1, get b() { l = { z: 9 }; return 2; } };
246+
// var l = { c: 3 };
247+
// var o = { ...k, ...l };
248+
// // expected: { a: 1, b: 2, z: 9 }
249+
// If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we
250+
// end up with `{ a: 1, b: 2, c: 3 }`
235251
const objects = chunkObjectLiteralElements(node.properties);
236252
if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) {
237253
objects.unshift(createObjectLiteral());
238254
}
239-
return createAssignHelper(context, objects);
255+
let expression: Expression = objects[0];
256+
if (objects.length > 1) {
257+
for (let i = 1; i < objects.length; i++) {
258+
expression = createAssignHelper(context, [expression, objects[i]]);
259+
}
260+
return expression;
261+
}
262+
else {
263+
return createAssignHelper(context, objects);
264+
}
240265
}
241266
return visitEachChild(node, visitor, context);
242267
}

src/testRunner/tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@
7373
"unittests/config/tsconfigParsing.ts",
7474
"unittests/evaluation/asyncArrow.ts",
7575
"unittests/evaluation/asyncGenerator.ts",
76+
"unittests/evaluation/awaiter.ts",
7677
"unittests/evaluation/forAwaitOf.ts",
78+
"unittests/evaluation/objectRest.ts",
7779
"unittests/services/cancellableLanguageServiceOperations.ts",
7880
"unittests/services/colorization.ts",
7981
"unittests/services/convertToAsyncFunction.ts",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
describe("unittests:: evaluation:: awaiter", () => {
2+
// NOTE: This could break if the ECMAScript spec ever changes the timing behavior for Promises (again)
3+
it("await (es5)", async () => {
4+
const result = evaluator.evaluateTypeScript(`
5+
async function a(msg: string) {
6+
await Promise.resolve();
7+
output.push(msg);
8+
}
9+
function b(msg: string) {
10+
return Promise.resolve().then(() => {
11+
output.push(msg);
12+
});
13+
}
14+
export const output: string[] = [];
15+
export async function main() {
16+
const p1 = a('1');
17+
const p2 = b('2');
18+
await Promise.all([p1, p2]);
19+
}
20+
`);
21+
await result.main();
22+
assert.deepEqual(result.output, ["1", "2"]);
23+
});
24+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
describe("unittests:: evaluation:: objectRest", () => {
2+
// https://github.com/microsoft/TypeScript/issues/31469
3+
it("side effects in property assignment", async () => {
4+
const result = evaluator.evaluateTypeScript(`
5+
const k = { a: 1, b: 2 };
6+
const o = { a: 3, ...k, b: k.a++ };
7+
export const output = o;
8+
`);
9+
assert.deepEqual(result.output, { a: 1, b: 1 });
10+
});
11+
it("side effects in during spread", async () => {
12+
const result = evaluator.evaluateTypeScript(`
13+
const k = { a: 1, get b() { l = { c: 9 }; return 2; } };
14+
let l = { c: 3 };
15+
const o = { ...k, ...l };
16+
export const output = o;
17+
`);
18+
assert.deepEqual(result.output, { a: 1, b: 2, c: 9 });
19+
});
20+
it("trailing literal-valued object-literal", async () => {
21+
const result = evaluator.evaluateTypeScript(`
22+
const k = { a: 1 }
23+
const o = { ...k, ...{ b: 2 } };
24+
export const output = o;
25+
`);
26+
assert.deepEqual(result.output, { a: 1, b: 2 });
27+
});
28+
});

tests/baselines/reference/asyncArrowFunction11_es5.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ class A {
99

1010
//// [asyncArrowFunction11_es5.js]
1111
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1213
return new (P || (P = Promise))(function (resolve, reject) {
1314
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1415
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
15-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
16+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1617
step((generator = generator.apply(thisArg, _arguments || [])).next());
1718
});
1819
};

tests/baselines/reference/asyncAwaitIsolatedModules_es5.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ module M {
4242
//// [asyncAwaitIsolatedModules_es5.js]
4343
"use strict";
4444
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
45+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4546
return new (P || (P = Promise))(function (resolve, reject) {
4647
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
4748
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
48-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
49+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
4950
step((generator = generator.apply(thisArg, _arguments || [])).next());
5051
});
5152
};

tests/baselines/reference/asyncAwaitIsolatedModules_es6.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ module M {
4141

4242
//// [asyncAwaitIsolatedModules_es6.js]
4343
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
44+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4445
return new (P || (P = Promise))(function (resolve, reject) {
4546
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
4647
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
47-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
48+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
4849
step((generator = generator.apply(thisArg, _arguments || [])).next());
4950
});
5051
};

tests/baselines/reference/asyncAwait_es5.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ async function f14() {
4848

4949
//// [asyncAwait_es5.js]
5050
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
51+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5152
return new (P || (P = Promise))(function (resolve, reject) {
5253
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5354
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
54-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
55+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
5556
step((generator = generator.apply(thisArg, _arguments || [])).next());
5657
});
5758
};

tests/baselines/reference/asyncAwait_es6.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ async function f14() {
4848

4949
//// [asyncAwait_es6.js]
5050
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
51+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5152
return new (P || (P = Promise))(function (resolve, reject) {
5253
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5354
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
54-
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
55+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
5556
step((generator = generator.apply(thisArg, _arguments || [])).next());
5657
});
5758
};

0 commit comments

Comments
 (0)