Fix 10472: Invalid emitted code for await expression (#10483)

* Properly emit await expression with yield expression

* Add tests and update baselines

* Move parsing await expression into parse unary-expression

* Update incorrect comment
This commit is contained in:
Yui 2016-08-22 16:37:04 -07:00 committed by GitHub
parent edbeab0ff2
commit 36130ffa64
18 changed files with 489 additions and 9 deletions

View File

@ -1817,6 +1817,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
else if (node.parent.kind === SyntaxKind.ConditionalExpression && (<ConditionalExpression>node.parent).condition === node) {
return true;
}
else if (node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.DeleteExpression ||
node.parent.kind === SyntaxKind.TypeOfExpression || node.parent.kind === SyntaxKind.VoidExpression) {
return true;
}
return false;
}

View File

@ -3381,10 +3381,6 @@ namespace ts {
*
*/
function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
if (isAwaitExpression()) {
return parseAwaitExpression();
}
/**
* ES7 UpdateExpression:
* 1) LeftHandSideExpression[?Yield]
@ -3452,13 +3448,15 @@ namespace ts {
return parseTypeOfExpression();
case SyntaxKind.VoidKeyword:
return parseVoidExpression();
case SyntaxKind.AwaitKeyword:
return parseAwaitExpression();
case SyntaxKind.LessThanToken:
// This is modified UnaryExpression grammar in TypeScript
// UnaryExpression (modified):
// < type > UnaryExpression
return parseTypeAssertion();
case SyntaxKind.AwaitKeyword:
if (isAwaitExpression()) {
return parseAwaitExpression();
}
default:
return parseIncrementExpression();
}
@ -3485,6 +3483,7 @@ namespace ts {
case SyntaxKind.DeleteKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.AwaitKeyword:
return false;
case SyntaxKind.LessThanToken:
// If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression

View File

@ -0,0 +1,47 @@
//// [await_unaryExpression_es6.ts]
async function bar() {
!await 42; // OK
}
async function bar1() {
+await 42; // OK
}
async function bar3() {
-await 42; // OK
}
async function bar4() {
~await 42; // OK
}
//// [await_unaryExpression_es6.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function bar() {
return __awaiter(this, void 0, void 0, function* () {
!(yield 42); // OK
});
}
function bar1() {
return __awaiter(this, void 0, void 0, function* () {
+(yield 42); // OK
});
}
function bar3() {
return __awaiter(this, void 0, void 0, function* () {
-(yield 42); // OK
});
}
function bar4() {
return __awaiter(this, void 0, void 0, function* () {
~(yield 42); // OK
});
}

View File

@ -0,0 +1,25 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts ===
async function bar() {
>bar : Symbol(bar, Decl(await_unaryExpression_es6.ts, 0, 0))
!await 42; // OK
}
async function bar1() {
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6.ts, 3, 1))
+await 42; // OK
}
async function bar3() {
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6.ts, 7, 1))
-await 42; // OK
}
async function bar4() {
>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6.ts, 11, 1))
~await 42; // OK
}

View File

@ -0,0 +1,37 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6.ts ===
async function bar() {
>bar : () => Promise<void>
!await 42; // OK
>!await 42 : boolean
>await 42 : number
>42 : number
}
async function bar1() {
>bar1 : () => Promise<void>
+await 42; // OK
>+await 42 : number
>await 42 : number
>42 : number
}
async function bar3() {
>bar3 : () => Promise<void>
-await 42; // OK
>-await 42 : number
>await 42 : number
>42 : number
}
async function bar4() {
>bar4 : () => Promise<void>
~await 42; // OK
>~await 42 : number
>await 42 : number
>42 : number
}

View File

@ -0,0 +1,56 @@
//// [await_unaryExpression_es6_1.ts]
async function bar() {
!await 42; // OK
}
async function bar1() {
delete await 42; // OK
}
async function bar2() {
delete await 42; // OK
}
async function bar3() {
void await 42;
}
async function bar4() {
+await 42;
}
//// [await_unaryExpression_es6_1.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function bar() {
return __awaiter(this, void 0, void 0, function* () {
!(yield 42); // OK
});
}
function bar1() {
return __awaiter(this, void 0, void 0, function* () {
delete (yield 42); // OK
});
}
function bar2() {
return __awaiter(this, void 0, void 0, function* () {
delete (yield 42); // OK
});
}
function bar3() {
return __awaiter(this, void 0, void 0, function* () {
void (yield 42);
});
}
function bar4() {
return __awaiter(this, void 0, void 0, function* () {
+(yield 42);
});
}

View File

@ -0,0 +1,31 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts ===
async function bar() {
>bar : Symbol(bar, Decl(await_unaryExpression_es6_1.ts, 0, 0))
!await 42; // OK
}
async function bar1() {
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_1.ts, 3, 1))
delete await 42; // OK
}
async function bar2() {
>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_1.ts, 7, 1))
delete await 42; // OK
}
async function bar3() {
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_1.ts, 11, 1))
void await 42;
}
async function bar4() {
>bar4 : Symbol(bar4, Decl(await_unaryExpression_es6_1.ts, 15, 1))
+await 42;
}

View File

@ -0,0 +1,46 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts ===
async function bar() {
>bar : () => Promise<void>
!await 42; // OK
>!await 42 : boolean
>await 42 : number
>42 : number
}
async function bar1() {
>bar1 : () => Promise<void>
delete await 42; // OK
>delete await 42 : boolean
>await 42 : number
>42 : number
}
async function bar2() {
>bar2 : () => Promise<void>
delete await 42; // OK
>delete await 42 : boolean
>await 42 : number
>42 : number
}
async function bar3() {
>bar3 : () => Promise<void>
void await 42;
>void await 42 : undefined
>await 42 : number
>42 : number
}
async function bar4() {
>bar4 : () => Promise<void>
+await 42;
>+await 42 : number
>await 42 : number
>42 : number
}

View File

@ -0,0 +1,38 @@
//// [await_unaryExpression_es6_2.ts]
async function bar1() {
delete await 42;
}
async function bar2() {
delete await 42;
}
async function bar3() {
void await 42;
}
//// [await_unaryExpression_es6_2.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function bar1() {
return __awaiter(this, void 0, void 0, function* () {
delete (yield 42);
});
}
function bar2() {
return __awaiter(this, void 0, void 0, function* () {
delete (yield 42);
});
}
function bar3() {
return __awaiter(this, void 0, void 0, function* () {
void (yield 42);
});
}

View File

@ -0,0 +1,19 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts ===
async function bar1() {
>bar1 : Symbol(bar1, Decl(await_unaryExpression_es6_2.ts, 0, 0))
delete await 42;
}
async function bar2() {
>bar2 : Symbol(bar2, Decl(await_unaryExpression_es6_2.ts, 3, 1))
delete await 42;
}
async function bar3() {
>bar3 : Symbol(bar3, Decl(await_unaryExpression_es6_2.ts, 7, 1))
void await 42;
}

View File

@ -0,0 +1,28 @@
=== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts ===
async function bar1() {
>bar1 : () => Promise<void>
delete await 42;
>delete await 42 : boolean
>await 42 : number
>42 : number
}
async function bar2() {
>bar2 : () => Promise<void>
delete await 42;
>delete await 42 : boolean
>await 42 : number
>42 : number
}
async function bar3() {
>bar3 : () => Promise<void>
void await 42;
>void await 42 : undefined
>await 42 : number
>42 : number
}

View File

@ -0,0 +1,27 @@
tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts(3,7): error TS1109: Expression expected.
tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts(7,7): error TS1109: Expression expected.
==== tests/cases/conformance/async/es6/await_unaryExpression_es6_3.ts (2 errors) ====
async function bar1() {
++await 42; // Error
~~~~~
!!! error TS1109: Expression expected.
}
async function bar2() {
--await 42; // Error
~~~~~
!!! error TS1109: Expression expected.
}
async function bar3() {
var x = 42;
await x++; // OK but shouldn't need parenthesis
}
async function bar4() {
var x = 42;
await x--; // OK but shouldn't need parenthesis
}

View File

@ -0,0 +1,53 @@
//// [await_unaryExpression_es6_3.ts]
async function bar1() {
++await 42; // Error
}
async function bar2() {
--await 42; // Error
}
async function bar3() {
var x = 42;
await x++; // OK but shouldn't need parenthesis
}
async function bar4() {
var x = 42;
await x--; // OK but shouldn't need parenthesis
}
//// [await_unaryExpression_es6_3.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function bar1() {
return __awaiter(this, void 0, void 0, function* () {
++;
yield 42; // Error
});
}
function bar2() {
return __awaiter(this, void 0, void 0, function* () {
--;
yield 42; // Error
});
}
function bar3() {
return __awaiter(this, void 0, void 0, function* () {
var x = 42;
yield x++; // OK but shouldn't need parenthesis
});
}
function bar4() {
return __awaiter(this, void 0, void 0, function* () {
var x = 42;
yield x--; // OK but shouldn't need parenthesis
});
}

View File

@ -20,9 +20,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function f() {
return __awaiter(this, void 0, void 0, function* () {
yield 0;
typeof yield 0;
void yield 0;
yield void typeof void yield 0;
typeof (yield 0);
void (yield 0);
yield void typeof void (yield 0);
yield yield 0;
});
}

View File

@ -0,0 +1,17 @@
// @target: es6
async function bar() {
!await 42; // OK
}
async function bar1() {
+await 42; // OK
}
async function bar3() {
-await 42; // OK
}
async function bar4() {
~await 42; // OK
}

View File

@ -0,0 +1,21 @@
// @target: es6
async function bar() {
!await 42; // OK
}
async function bar1() {
delete await 42; // OK
}
async function bar2() {
delete await 42; // OK
}
async function bar3() {
void await 42;
}
async function bar4() {
+await 42;
}

View File

@ -0,0 +1,13 @@
// @target: es6
async function bar1() {
delete await 42;
}
async function bar2() {
delete await 42;
}
async function bar3() {
void await 42;
}

View File

@ -0,0 +1,19 @@
// @target: es6
async function bar1() {
++await 42; // Error
}
async function bar2() {
--await 42; // Error
}
async function bar3() {
var x = 42;
await x++; // OK but shouldn't need parenthesis
}
async function bar4() {
var x = 42;
await x--; // OK but shouldn't need parenthesis
}