Skip to content

Commit 36130ff

Browse files
authored
Fix 10472: Invalid emitted code for await expression (microsoft#10483)
* Properly emit await expression with yield expression * Add tests and update baselines * Move parsing await expression into parse unary-expression * Update incorrect comment
1 parent edbeab0 commit 36130ff

18 files changed

+489
-9
lines changed

src/compiler/emitter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
18171817
else if (node.parent.kind === SyntaxKind.ConditionalExpression && (<ConditionalExpression>node.parent).condition === node) {
18181818
return true;
18191819
}
1820+
else if (node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.DeleteExpression ||
1821+
node.parent.kind === SyntaxKind.TypeOfExpression || node.parent.kind === SyntaxKind.VoidExpression) {
1822+
return true;
1823+
}
18201824

18211825
return false;
18221826
}

src/compiler/parser.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,10 +3381,6 @@ namespace ts {
33813381
*
33823382
*/
33833383
function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
3384-
if (isAwaitExpression()) {
3385-
return parseAwaitExpression();
3386-
}
3387-
33883384
/**
33893385
* ES7 UpdateExpression:
33903386
* 1) LeftHandSideExpression[?Yield]
@@ -3452,13 +3448,15 @@ namespace ts {
34523448
return parseTypeOfExpression();
34533449
case SyntaxKind.VoidKeyword:
34543450
return parseVoidExpression();
3455-
case SyntaxKind.AwaitKeyword:
3456-
return parseAwaitExpression();
34573451
case SyntaxKind.LessThanToken:
34583452
// This is modified UnaryExpression grammar in TypeScript
34593453
// UnaryExpression (modified):
34603454
// < type > UnaryExpression
34613455
return parseTypeAssertion();
3456+
case SyntaxKind.AwaitKeyword:
3457+
if (isAwaitExpression()) {
3458+
return parseAwaitExpression();
3459+
}
34623460
default:
34633461
return parseIncrementExpression();
34643462
}
@@ -3485,6 +3483,7 @@ namespace ts {
34853483
case SyntaxKind.DeleteKeyword:
34863484
case SyntaxKind.TypeOfKeyword:
34873485
case SyntaxKind.VoidKeyword:
3486+
case SyntaxKind.AwaitKeyword:
34883487
return false;
34893488
case SyntaxKind.LessThanToken:
34903489
// If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [await_unaryExpression_es6.ts]
2+
3+
async function bar() {
4+
!await 42; // OK
5+
}
6+
7+
async function bar1() {
8+
+await 42; // OK
9+
}
10+
11+
async function bar3() {
12+
-await 42; // OK
13+
}
14+
15+
async function bar4() {
16+
~await 42; // OK
17+
}
18+
19+
//// [await_unaryExpression_es6.js]
20+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21+
return new (P || (P = Promise))(function (resolve, reject) {
22+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
23+
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
24+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
25+
step((generator = generator.apply(thisArg, _arguments)).next());
26+
});
27+
};
28+
function bar() {
29+
return __awaiter(this, void 0, void 0, function* () {
30+
!(yield 42); // OK
31+
});
32+
}
33+
function bar1() {
34+
return __awaiter(this, void 0, void 0, function* () {
35+
+(yield 42); // OK
36+
});
37+
}
38+
function bar3() {
39+
return __awaiter(this, void 0, void 0, function* () {
40+
-(yield 42); // OK
41+
});
42+
}
43+
function bar4() {
44+
return __awaiter(this, void 0, void 0, function* () {
45+
~(yield 42); // OK
46+
});
47+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts ===
2+
3+
async function bar() {
4+
>bar : Symbol(bar, Decl(await_unaryExpression_es6.ts, 0, 0))
5+
6+
!await 42; // OK
7+
}
8+
9+
async function bar1() {
10+
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6.ts, 3, 1))
11+
12+
+await 42; // OK
13+
}
14+
15+
async function bar3() {
16+
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6.ts, 7, 1))
17+
18+
-await 42; // OK
19+
}
20+
21+
async function bar4() {
22+
>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6.ts, 11, 1))
23+
24+
~await 42; // OK
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts ===
2+
3+
async function bar() {
4+
>bar : () => Promise<void>
5+
6+
!await 42; // OK
7+
>!await 42 : boolean
8+
>await 42 : number
9+
>42 : number
10+
}
11+
12+
async function bar1() {
13+
>bar1 : () => Promise<void>
14+
15+
+await 42; // OK
16+
>+await 42 : number
17+
>await 42 : number
18+
>42 : number
19+
}
20+
21+
async function bar3() {
22+
>bar3 : () => Promise<void>
23+
24+
-await 42; // OK
25+
>-await 42 : number
26+
>await 42 : number
27+
>42 : number
28+
}
29+
30+
async function bar4() {
31+
>bar4 : () => Promise<void>
32+
33+
~await 42; // OK
34+
>~await 42 : number
35+
>await 42 : number
36+
>42 : number
37+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//// [await_unaryExpression_es6_1.ts]
2+
3+
async function bar() {
4+
!await 42; // OK
5+
}
6+
7+
async function bar1() {
8+
delete await 42; // OK
9+
}
10+
11+
async function bar2() {
12+
delete await 42; // OK
13+
}
14+
15+
async function bar3() {
16+
void await 42;
17+
}
18+
19+
async function bar4() {
20+
+await 42;
21+
}
22+
23+
//// [await_unaryExpression_es6_1.js]
24+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
25+
return new (P || (P = Promise))(function (resolve, reject) {
26+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
27+
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
28+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
29+
step((generator = generator.apply(thisArg, _arguments)).next());
30+
});
31+
};
32+
function bar() {
33+
return __awaiter(this, void 0, void 0, function* () {
34+
!(yield 42); // OK
35+
});
36+
}
37+
function bar1() {
38+
return __awaiter(this, void 0, void 0, function* () {
39+
delete (yield 42); // OK
40+
});
41+
}
42+
function bar2() {
43+
return __awaiter(this, void 0, void 0, function* () {
44+
delete (yield 42); // OK
45+
});
46+
}
47+
function bar3() {
48+
return __awaiter(this, void 0, void 0, function* () {
49+
void (yield 42);
50+
});
51+
}
52+
function bar4() {
53+
return __awaiter(this, void 0, void 0, function* () {
54+
+(yield 42);
55+
});
56+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts ===
2+
3+
async function bar() {
4+
>bar : Symbol(bar, Decl(await_unaryExpression_es6_1.ts, 0, 0))
5+
6+
!await 42; // OK
7+
}
8+
9+
async function bar1() {
10+
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_1.ts, 3, 1))
11+
12+
delete await 42; // OK
13+
}
14+
15+
async function bar2() {
16+
>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_1.ts, 7, 1))
17+
18+
delete await 42; // OK
19+
}
20+
21+
async function bar3() {
22+
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_1.ts, 11, 1))
23+
24+
void await 42;
25+
}
26+
27+
async function bar4() {
28+
>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6_1.ts, 15, 1))
29+
30+
+await 42;
31+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts ===
2+
3+
async function bar() {
4+
>bar : () => Promise<void>
5+
6+
!await 42; // OK
7+
>!await 42 : boolean
8+
>await 42 : number
9+
>42 : number
10+
}
11+
12+
async function bar1() {
13+
>bar1 : () => Promise<void>
14+
15+
delete await 42; // OK
16+
>delete await 42 : boolean
17+
>await 42 : number
18+
>42 : number
19+
}
20+
21+
async function bar2() {
22+
>bar2 : () => Promise<void>
23+
24+
delete await 42; // OK
25+
>delete await 42 : boolean
26+
>await 42 : number
27+
>42 : number
28+
}
29+
30+
async function bar3() {
31+
>bar3 : () => Promise<void>
32+
33+
void await 42;
34+
>void await 42 : undefined
35+
>await 42 : number
36+
>42 : number
37+
}
38+
39+
async function bar4() {
40+
>bar4 : () => Promise<void>
41+
42+
+await 42;
43+
>+await 42 : number
44+
>await 42 : number
45+
>42 : number
46+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [await_unaryExpression_es6_2.ts]
2+
3+
async function bar1() {
4+
delete await 42;
5+
}
6+
7+
async function bar2() {
8+
delete await 42;
9+
}
10+
11+
async function bar3() {
12+
void await 42;
13+
}
14+
15+
//// [await_unaryExpression_es6_2.js]
16+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17+
return new (P || (P = Promise))(function (resolve, reject) {
18+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
19+
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
20+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
21+
step((generator = generator.apply(thisArg, _arguments)).next());
22+
});
23+
};
24+
function bar1() {
25+
return __awaiter(this, void 0, void 0, function* () {
26+
delete (yield 42);
27+
});
28+
}
29+
function bar2() {
30+
return __awaiter(this, void 0, void 0, function* () {
31+
delete (yield 42);
32+
});
33+
}
34+
function bar3() {
35+
return __awaiter(this, void 0, void 0, function* () {
36+
void (yield 42);
37+
});
38+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts ===
2+
3+
async function bar1() {
4+
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_2.ts, 0, 0))
5+
6+
delete await 42;
7+
}
8+
9+
async function bar2() {
10+
>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_2.ts, 3, 1))
11+
12+
delete await 42;
13+
}
14+
15+
async function bar3() {
16+
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_2.ts, 7, 1))
17+
18+
void await 42;
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts ===
2+
3+
async function bar1() {
4+
>bar1 : () => Promise<void>
5+
6+
delete await 42;
7+
>delete await 42 : boolean
8+
>await 42 : number
9+
>42 : number
10+
}
11+
12+
async function bar2() {
13+
>bar2 : () => Promise<void>
14+
15+
delete await 42;
16+
>delete await 42 : boolean
17+
>await 42 : number
18+
>42 : number
19+
}
20+
21+
async function bar3() {
22+
>bar3 : () => Promise<void>
23+
24+
void await 42;
25+
>void await 42 : undefined
26+
>await 42 : number
27+
>42 : number
28+
}

0 commit comments

Comments
 (0)