Skip to content

disallow 'await' and 'yield' in property and enum member initializer #34892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 2 additions & 21 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26315,8 +26315,7 @@ namespace ts {
const span = getSpanOfTokenAtPosition(sourceFile, node.pos);
const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
const func = getContainingFunction(node);
if (func && func.kind !== SyntaxKind.Constructor) {
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
if (func && func.kind !== SyntaxKind.Constructor && (getFunctionFlags(func) & FunctionFlags.Async) === 0) {
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
addRelatedInfo(diagnostic, relatedInfo);
}
Expand Down Expand Up @@ -27128,28 +27127,10 @@ namespace ts {
return [ effectiveLeft, effectiveRight ];
}

function isYieldExpressionInClass(node: YieldExpression): boolean {
let current: Node = node;
let parent = node.parent;
while (parent) {
if (isFunctionLike(parent) && current === (<FunctionLikeDeclaration>parent).body) {
return false;
}
else if (isClassLike(current)) {
return true;
}

current = parent;
parent = parent.parent;
}

return false;
}

function checkYieldExpression(node: YieldExpression): Type {
// Grammar checking
if (produceDiagnostics) {
if (!(node.flags & NodeFlags.YieldContext) || isYieldExpressionInClass(node)) {
if (!(node.flags & NodeFlags.YieldContext)) {
grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_body);
}

Expand Down
20 changes: 6 additions & 14 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,10 @@ namespace ts {
return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
}

function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T {
return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
}

function inContext(flags: NodeFlags) {
return (contextFlags & flags) !== 0;
}
Expand Down Expand Up @@ -5865,19 +5869,7 @@ namespace ts {
node.exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
}
node.type = parseTypeAnnotation();

// For instance properties specifically, since they are evaluated inside the constructor,
// we do *not * want to parse yield expressions, so we specifically turn the yield context
// off. The grammar would look something like this:
//
// MemberVariableDeclaration[Yield]:
// AccessibilityModifier_opt PropertyName TypeAnnotation_opt Initializer_opt[In];
// AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initializer_opt[In, ?Yield];
//
// The checker may still error in the static case to explicitly disallow the yield expression.
node.initializer = hasModifier(node, ModifierFlags.Static)
? allowInAnd(parseInitializer)
: doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseInitializer);
node.initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);

parseSemicolon();
return finishNode(node);
Expand Down Expand Up @@ -6213,7 +6205,7 @@ namespace ts {
parseExpected(SyntaxKind.EnumKeyword);
node.name = parseIdentifier();
if (parseExpected(SyntaxKind.OpenBraceToken)) {
node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember);
node.members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember));
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
Expand Down
15 changes: 15 additions & 0 deletions tests/baselines/reference/awaitAndYield.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
tests/cases/conformance/enums/awaitAndYield.ts(3,15): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/conformance/enums/awaitAndYield.ts(4,15): error TS1163: A 'yield' expression is only allowed in a generator body.


==== tests/cases/conformance/enums/awaitAndYield.ts (2 errors) ====
async function* test(x: Promise<number>) {
enum E {
foo = await x,
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
baz = yield 1,
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}
}
16 changes: 16 additions & 0 deletions tests/baselines/reference/awaitAndYield.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [awaitAndYield.ts]
async function* test(x: Promise<number>) {
enum E {
foo = await x,
baz = yield 1,
}
}

//// [awaitAndYield.js]
async function* test(x) {
let E;
(function (E) {
E[E["foo"] = await x] = "foo";
E[E["baz"] = yield 1] = "baz";
})(E || (E = {}));
}
68 changes: 68 additions & 0 deletions tests/baselines/reference/awaitAndYieldInProperty.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(3,21): error TS1308: 'await' expression is only allowed within an async function.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(4,28): error TS1308: 'await' expression is only allowed within an async function.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(6,21): error TS1163: A 'yield' expression is only allowed in a generator body.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(7,28): error TS1163: A 'yield' expression is only allowed in a generator body.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(11,21): error TS1308: 'await' expression is only allowed within an async function.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(12,28): error TS1308: 'await' expression is only allowed within an async function.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(14,21): error TS1163: A 'yield' expression is only allowed in a generator body.
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.
tests/cases/conformance/classes/awaitAndYieldInProperty.ts(15,28): error TS1163: A 'yield' expression is only allowed in a generator body.


==== tests/cases/conformance/classes/awaitAndYieldInProperty.ts (16 errors) ====
async function* test(x: Promise<string>) {
class C {
[await x] = await x;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
static [await x] = await x;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.

[yield 1] = yield 2;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
static [yield 3] = yield 4;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}

return class {
[await x] = await x;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
static [await x] = await x;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.

[yield 1] = yield 2;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
static [yield 3] = yield 4;
~~~~~~~~~
!!! 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.
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}
}
45 changes: 45 additions & 0 deletions tests/baselines/reference/awaitAndYieldInProperty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// [awaitAndYieldInProperty.ts]
async function* test(x: Promise<string>) {
class C {
[await x] = await x;
static [await x] = await x;

[yield 1] = yield 2;
static [yield 3] = yield 4;
}

return class {
[await x] = await x;
static [await x] = await x;

[yield 1] = yield 2;
static [yield 3] = yield 4;
}
}

//// [awaitAndYieldInProperty.js]
async function* test(x) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
class C {
constructor() {
this[_a] = await x;
this[_c] = yield 2;
}
}
_a = await x, _b = await x, _c = yield 1, _d = yield 3;
C[_b] = await x;
C[_d] = yield 4;
return _j = class {
constructor() {
this[_e] = await x;
this[_g] = yield 2;
}
},
_e = await x,
_f = await x,
_g = yield 1,
_h = yield 3,
_j[_f] = await x,
_j[_h] = yield 4,
_j;
}
18 changes: 18 additions & 0 deletions tests/baselines/reference/awaitInClassInAsyncFunction.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
tests/cases/compiler/awaitInClassInAsyncFunction.ts(9,15): error TS1308: 'await' expression is only allowed within an async function.


==== tests/cases/compiler/awaitInClassInAsyncFunction.ts (1 errors) ====
// https://github.com/microsoft/TypeScript/issues/34887

async function bar() {
return 2;
}

async function foo() {
return new class {
baz = await bar();
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
};
}

26 changes: 26 additions & 0 deletions tests/baselines/reference/awaitInClassInAsyncFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//// [awaitInClassInAsyncFunction.ts]
// https://github.com/microsoft/TypeScript/issues/34887

async function bar() {
return 2;
}

async function foo() {
return new class {
baz = await bar();
};
}


//// [awaitInClassInAsyncFunction.js]
// https://github.com/microsoft/TypeScript/issues/34887
async function bar() {
return 2;
}
async function foo() {
return new class {
constructor() {
this.baz = await bar();
}
};
}
20 changes: 20 additions & 0 deletions tests/baselines/reference/awaitInClassInAsyncFunction.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/compiler/awaitInClassInAsyncFunction.ts ===
// https://github.com/microsoft/TypeScript/issues/34887

async function bar() {
>bar : Symbol(bar, Decl(awaitInClassInAsyncFunction.ts, 0, 0))

return 2;
}

async function foo() {
>foo : Symbol(foo, Decl(awaitInClassInAsyncFunction.ts, 4, 1))

return new class {
baz = await bar();
>baz : Symbol((Anonymous class).baz, Decl(awaitInClassInAsyncFunction.ts, 7, 22))
>bar : Symbol(bar, Decl(awaitInClassInAsyncFunction.ts, 0, 0))

};
}

26 changes: 26 additions & 0 deletions tests/baselines/reference/awaitInClassInAsyncFunction.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=== tests/cases/compiler/awaitInClassInAsyncFunction.ts ===
// https://github.com/microsoft/TypeScript/issues/34887

async function bar() {
>bar : () => Promise<number>

return 2;
>2 : 2
}

async function foo() {
>foo : () => Promise<(Anonymous class)>

return new class {
>new class { baz = await bar(); } : (Anonymous class)
>class { baz = await bar(); } : typeof (Anonymous class)

baz = await bar();
>baz : number
>await bar() : number
>bar() : Promise<number>
>bar : () => Promise<number>

};
}

5 changes: 1 addition & 4 deletions tests/baselines/reference/generatorTypeCheck39.errors.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts(5,16): error TS1163: A 'yield' expression is only allowed in a generator body.
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.
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts(7,13): error TS1163: A 'yield' expression is only allowed in a generator body.


==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts (3 errors) ====
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck39.ts (2 errors) ====
function decorator(x: any) {
return y => { };
}
function* g() {
@decorator(yield 0)
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
class C {
~
!!! 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.
Expand Down
9 changes: 0 additions & 9 deletions tests/baselines/reference/generatorTypeCheck40.errors.txt

This file was deleted.

9 changes: 0 additions & 9 deletions tests/baselines/reference/generatorTypeCheck55.errors.txt

This file was deleted.

13 changes: 0 additions & 13 deletions tests/baselines/reference/generatorTypeCheck56.errors.txt

This file was deleted.

5 changes: 1 addition & 4 deletions tests/baselines/reference/generatorTypeCheck59.errors.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts(3,11): error TS1163: A 'yield' expression is only allowed in a generator body.
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.


==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts (2 errors) ====
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck59.ts (1 errors) ====
function* g() {
class C {
@(yield "")
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
m() { }
~
!!! 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.
Expand Down
Loading