Skip to content

Commit

Permalink
disallow 'await' and 'yield' in property and enum member initializer (#…
Browse files Browse the repository at this point in the history
…34892)

* disallow 'await' and 'yield' in property and enum member initializer

* accept baseline changes

* Add a test for #34887

Ensures that this fixes #34887
  • Loading branch information
ajafff authored and rbuckton committed Nov 15, 2019
1 parent 8f40ac0 commit 5321dcb
Show file tree
Hide file tree
Showing 21 changed files with 285 additions and 91 deletions.
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

0 comments on commit 5321dcb

Please sign in to comment.