Skip to content

Commit 5321dcb

Browse files
ajafffrbuckton
authored andcommitted
disallow 'await' and 'yield' in property and enum member initializer (microsoft#34892)
* disallow 'await' and 'yield' in property and enum member initializer * accept baseline changes * Add a test for microsoft#34887 Ensures that this fixes microsoft#34887
1 parent 8f40ac0 commit 5321dcb

21 files changed

+285
-91
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26315,8 +26315,7 @@ namespace ts {
2631526315
const span = getSpanOfTokenAtPosition(sourceFile, node.pos);
2631626316
const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
2631726317
const func = getContainingFunction(node);
26318-
if (func && func.kind !== SyntaxKind.Constructor) {
26319-
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
26318+
if (func && func.kind !== SyntaxKind.Constructor && (getFunctionFlags(func) & FunctionFlags.Async) === 0) {
2632026319
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
2632126320
addRelatedInfo(diagnostic, relatedInfo);
2632226321
}
@@ -27128,28 +27127,10 @@ namespace ts {
2712827127
return [ effectiveLeft, effectiveRight ];
2712927128
}
2713027129

27131-
function isYieldExpressionInClass(node: YieldExpression): boolean {
27132-
let current: Node = node;
27133-
let parent = node.parent;
27134-
while (parent) {
27135-
if (isFunctionLike(parent) && current === (<FunctionLikeDeclaration>parent).body) {
27136-
return false;
27137-
}
27138-
else if (isClassLike(current)) {
27139-
return true;
27140-
}
27141-
27142-
current = parent;
27143-
parent = parent.parent;
27144-
}
27145-
27146-
return false;
27147-
}
27148-
2714927130
function checkYieldExpression(node: YieldExpression): Type {
2715027131
// Grammar checking
2715127132
if (produceDiagnostics) {
27152-
if (!(node.flags & NodeFlags.YieldContext) || isYieldExpressionInClass(node)) {
27133+
if (!(node.flags & NodeFlags.YieldContext)) {
2715327134
grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body);
2715427135
}
2715527136

src/compiler/parser.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,10 @@ namespace ts {
10291029
return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
10301030
}
10311031

1032+
function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T {
1033+
return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
1034+
}
1035+
10321036
function inContext(flags: NodeFlags) {
10331037
return (contextFlags & flags) !== 0;
10341038
}
@@ -5865,19 +5869,7 @@ namespace ts {
58655869
node.exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
58665870
}
58675871
node.type = parseTypeAnnotation();
5868-
5869-
// For instance properties specifically, since they are evaluated inside the constructor,
5870-
// we do *not * want to parse yield expressions, so we specifically turn the yield context
5871-
// off. The grammar would look something like this:
5872-
//
5873-
// MemberVariableDeclaration[Yield]:
5874-
// AccessibilityModifier_opt PropertyName TypeAnnotation_opt Initializer_opt[In];
5875-
// AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initializer_opt[In, ?Yield];
5876-
//
5877-
// The checker may still error in the static case to explicitly disallow the yield expression.
5878-
node.initializer = hasModifier(node, ModifierFlags.Static)
5879-
? allowInAnd(parseInitializer)
5880-
: doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseInitializer);
5872+
node.initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);
58815873

58825874
parseSemicolon();
58835875
return finishNode(node);
@@ -6213,7 +6205,7 @@ namespace ts {
62136205
parseExpected(SyntaxKind.EnumKeyword);
62146206
node.name = parseIdentifier();
62156207
if (parseExpected(SyntaxKind.OpenBraceToken)) {
6216-
node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember);
6208+
node.members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember));
62176209
parseExpected(SyntaxKind.CloseBraceToken);
62186210
}
62196211
else {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tests/cases/conformance/enums/awaitAndYield.ts(3,15): error TS1308: 'await' expression is only allowed within an async function.
2+
tests/cases/conformance/enums/awaitAndYield.ts(4,15): error TS1163: A 'yield' expression is only allowed in a generator body.
3+
4+
5+
==== tests/cases/conformance/enums/awaitAndYield.ts (2 errors) ====
6+
async function* test(x: Promise<number>) {
7+
enum E {
8+
foo = await x,
9+
~~~~~
10+
!!! error TS1308: 'await' expression is only allowed within an async function.
11+
baz = yield 1,
12+
~~~~~
13+
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
14+
}
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//// [awaitAndYield.ts]
2+
async function* test(x: Promise<number>) {
3+
enum E {
4+
foo = await x,
5+
baz = yield 1,
6+
}
7+
}
8+
9+
//// [awaitAndYield.js]
10+
async function* test(x) {
11+
let E;
12+
(function (E) {
13+
E[E["foo"] = await x] = "foo";
14+
E[E["baz"] = yield 1] = "baz";
15+
})(E || (E = {}));
16+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(3,9): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
2+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(3,21): error TS1308: 'await' expression is only allowed within an async function.
3+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(4,16): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
4+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(4,28): error TS1308: 'await' expression is only allowed within an async function.
5+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(6,9): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
6+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(6,21): error TS1163: A 'yield' expression is only allowed in a generator body.
7+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(7,16): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
8+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(7,28): error TS1163: A 'yield' expression is only allowed in a generator body.
9+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(11,9): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
10+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(11,21): error TS1308: 'await' expression is only allowed within an async function.
11+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(12,16): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
12+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(12,28): error TS1308: 'await' expression is only allowed within an async function.
13+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(14,9): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
14+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(14,21): error TS1163: A 'yield' expression is only allowed in a generator body.
15+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(15,16): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
16+
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(15,28): error TS1163: A 'yield' expression is only allowed in a generator body.
17+
18+
19+
==== tests/cases/conformance/classes/awaitAndYieldInProperty.ts (16 errors) ====
20+
async function* test(x: Promise<string>) {
21+
class C {
22+
[await x] = await x;
23+
~~~~~~~~~
24+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
25+
~~~~~
26+
!!! error TS1308: 'await' expression is only allowed within an async function.
27+
static [await x] = await x;
28+
~~~~~~~~~
29+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
30+
~~~~~
31+
!!! error TS1308: 'await' expression is only allowed within an async function.
32+
33+
[yield 1] = yield 2;
34+
~~~~~~~~~
35+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
36+
~~~~~
37+
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
38+
static [yield 3] = yield 4;
39+
~~~~~~~~~
40+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
41+
~~~~~
42+
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
43+
}
44+
45+
return class {
46+
[await x] = await x;
47+
~~~~~~~~~
48+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
49+
~~~~~
50+
!!! error TS1308: 'await' expression is only allowed within an async function.
51+
static [await x] = await x;
52+
~~~~~~~~~
53+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
54+
~~~~~
55+
!!! error TS1308: 'await' expression is only allowed within an async function.
56+
57+
[yield 1] = yield 2;
58+
~~~~~~~~~
59+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
60+
~~~~~
61+
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
62+
static [yield 3] = yield 4;
63+
~~~~~~~~~
64+
!!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.
65+
~~~~~
66+
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
67+
}
68+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [awaitAndYieldInProperty.ts]
2+
async function* test(x: Promise<string>) {
3+
class C {
4+
[await x] = await x;
5+
static [await x] = await x;
6+
7+
[yield 1] = yield 2;
8+
static [yield 3] = yield 4;
9+
}
10+
11+
return class {
12+
[await x] = await x;
13+
static [await x] = await x;
14+
15+
[yield 1] = yield 2;
16+
static [yield 3] = yield 4;
17+
}
18+
}
19+
20+
//// [awaitAndYieldInProperty.js]
21+
async function* test(x) {
22+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
23+
class C {
24+
constructor() {
25+
this[_a] = await x;
26+
this[_c] = yield 2;
27+
}
28+
}
29+
_a = await x, _b = await x, _c = yield 1, _d = yield 3;
30+
C[_b] = await x;
31+
C[_d] = yield 4;
32+
return _j = class {
33+
constructor() {
34+
this[_e] = await x;
35+
this[_g] = yield 2;
36+
}
37+
},
38+
_e = await x,
39+
_f = await x,
40+
_g = yield 1,
41+
_h = yield 3,
42+
_j[_f] = await x,
43+
_j[_h] = yield 4,
44+
_j;
45+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/awaitInClassInAsyncFunction.ts(9,15): error TS1308: 'await' expression is only allowed within an async function.
2+
3+
4+
==== tests/cases/compiler/awaitInClassInAsyncFunction.ts (1 errors) ====
5+
// https://github.com/microsoft/TypeScript/issues/34887
6+
7+
async function bar() {
8+
return 2;
9+
}
10+
11+
async function foo() {
12+
return new class {
13+
baz = await bar();
14+
~~~~~
15+
!!! error TS1308: 'await' expression is only allowed within an async function.
16+
};
17+
}
18+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [awaitInClassInAsyncFunction.ts]
2+
// https://github.com/microsoft/TypeScript/issues/34887
3+
4+
async function bar() {
5+
return 2;
6+
}
7+
8+
async function foo() {
9+
return new class {
10+
baz = await bar();
11+
};
12+
}
13+
14+
15+
//// [awaitInClassInAsyncFunction.js]
16+
// https://github.com/microsoft/TypeScript/issues/34887
17+
async function bar() {
18+
return 2;
19+
}
20+
async function foo() {
21+
return new class {
22+
constructor() {
23+
this.baz = await bar();
24+
}
25+
};
26+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/compiler/awaitInClassInAsyncFunction.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/34887
3+
4+
async function bar() {
5+
>bar : Symbol(bar, Decl(awaitInClassInAsyncFunction.ts, 0, 0))
6+
7+
return 2;
8+
}
9+
10+
async function foo() {
11+
>foo : Symbol(foo, Decl(awaitInClassInAsyncFunction.ts, 4, 1))
12+
13+
return new class {
14+
baz = await bar();
15+
>baz : Symbol((Anonymous class).baz, Decl(awaitInClassInAsyncFunction.ts, 7, 22))
16+
>bar : Symbol(bar, Decl(awaitInClassInAsyncFunction.ts, 0, 0))
17+
18+
};
19+
}
20+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/awaitInClassInAsyncFunction.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/34887
3+
4+
async function bar() {
5+
>bar : () => Promise<number>
6+
7+
return 2;
8+
>2 : 2
9+
}
10+
11+
async function foo() {
12+
>foo : () => Promise<(Anonymous class)>
13+
14+
return new class {
15+
>new class { baz = await bar(); } : (Anonymous class)
16+
>class { baz = await bar(); } : typeof (Anonymous class)
17+
18+
baz = await bar();
19+
>baz : number
20+
>await bar() : number
21+
>bar() : Promise<number>
22+
>bar : () => Promise<number>
23+
24+
};
25+
}
26+

tests/baselines/reference/generatorTypeCheck39.errors.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts(5,16): error TS1163: A 'yield' expression is only allowed in a generator body.
21
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts(6,11): error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.
32
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts(7,13): error TS1163: A 'yield' expression is only allowed in a generator body.
43

54

6-
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts (3 errors) ====
5+
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts (2 errors) ====
76
function decorator(x: any) {
87
return y => { };
98
}
109
function* g() {
1110
@decorator(yield 0)
12-
~~~~~
13-
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
1411
class C {
1512
~
1613
!!! error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.

tests/baselines/reference/generatorTypeCheck40.errors.txt

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

tests/baselines/reference/generatorTypeCheck55.errors.txt

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

tests/baselines/reference/generatorTypeCheck56.errors.txt

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

tests/baselines/reference/generatorTypeCheck59.errors.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts(3,11): error TS1163: A 'yield' expression is only allowed in a generator body.
21
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts(4,9): error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.
32

43

5-
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts (2 errors) ====
4+
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts (1 errors) ====
65
function* g() {
76
class C {
87
@(yield "")
9-
~~~~~
10-
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
118
m() { }
129
~
1310
!!! error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.

0 commit comments

Comments
 (0)