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

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

* accept baseline changes

* Add a test for #34887

Ensures that this fixes #34887
This commit is contained in:
Klaus Meinhardt 2019-11-15 02:44:48 +01:00 committed by Ron Buckton
parent 8f40ac06cc
commit 5321dcb09f
21 changed files with 285 additions and 91 deletions

View File

@ -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);
}
@ -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);
}

View File

@ -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;
}
@ -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);
@ -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 {

View File

@ -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.
}
}

View File

@ -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 = {}));
}

View File

@ -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.
}
}

View File

@ -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;
}

View File

@ -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.
};
}

View File

@ -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();
}
};
}

View File

@ -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))
};
}

View File

@ -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>
};
}

View File

@ -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.

View File

@ -1,9 +0,0 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck40.ts(2,22): error TS1163: A 'yield' expression is only allowed in a generator body.
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck40.ts (1 errors) ====
function* g() {
class C extends (yield 0) { }
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}

View File

@ -1,9 +0,0 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck55.ts(2,30): error TS1163: A 'yield' expression is only allowed in a generator body.
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck55.ts (1 errors) ====
function* g() {
var x = class C extends (yield) {};
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}

View File

@ -1,13 +0,0 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck56.ts(3,11): error TS1163: A 'yield' expression is only allowed in a generator body.
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck56.ts (1 errors) ====
function* g() {
var x = class C {
*[yield 0]() {
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
yield 0;
}
};
}

View File

@ -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.

View File

@ -1,9 +0,0 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck60.ts(2,22): error TS1163: A 'yield' expression is only allowed in a generator body.
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck60.ts (1 errors) ====
function* g() {
class C extends (yield) {};
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
}

View File

@ -1,12 +1,9 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck61.ts(2,7): error TS1163: A 'yield' expression is only allowed in a generator body.
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck61.ts(3,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/generatorTypeCheck61.ts (2 errors) ====
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck61.ts (1 errors) ====
function * g() {
@(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.

View File

@ -20,7 +20,6 @@ tests/cases/conformance/parser/ecmascript2018/asyncGenerators/nestedFunctionExpr
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldAsTypeIsStrictError.ts(4,16): error TS1213: Identifier expected. 'yield' is a reserved word in strict mode. Class definitions are automatically in strict mode.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInClassComputedPropertyIsError.ts(2,14): error TS1213: Identifier expected. 'yield' is a reserved word in strict mode. Class definitions are automatically in strict mode.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInClassComputedPropertyIsError.ts(2,14): error TS2693: 'yield' only refers to a type, but is being used as a value here.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInParameterInitializerIsError.ts(2,19): error TS1163: A 'yield' expression is only allowed in a generator body.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInParameterInitializerIsError.ts(2,19): error TS2523: 'yield' expressions cannot be used in a parameter initializer.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldParameterIsError.ts(2,15): error TS1138: Parameter declaration expected.
tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldParameterIsError.ts(2,15): error TS2693: 'yield' only refers to a type, but is being used as a value here.
@ -77,12 +76,10 @@ tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldStarMissingVa
!!! error TS2524: 'await' expressions cannot be used in a parameter initializer.
}
}
==== tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInParameterInitializerIsError.ts (2 errors) ====
==== tests/cases/conformance/parser/ecmascript2018/asyncGenerators/yieldInParameterInitializerIsError.ts (1 errors) ====
class C7 {
async * f(a = yield) {
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
~~~~~
!!! error TS2523: 'yield' expressions cannot be used in a parameter initializer.
}
}

View File

@ -0,0 +1,12 @@
// @target: esnext
// https://github.com/microsoft/TypeScript/issues/34887
async function bar() {
return 2;
}
async function foo() {
return new class {
baz = await bar();
};
}

View File

@ -0,0 +1,19 @@
// @target: es2019
// @noTypesAndSymbols: true
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;
}
}

View File

@ -0,0 +1,8 @@
// @target: ES2019
// @noTypesAndSymbols: true
async function* test(x: Promise<number>) {
enum E {
foo = await x,
baz = yield 1,
}
}