Disallow yield expressions inside a class

This commit is contained in:
Jason Freeman
2015-05-11 17:40:38 -07:00
parent 670ad05eec
commit cb198aa7f2
24 changed files with 287 additions and 11 deletions
+19 -1
View File
@@ -8023,9 +8023,27 @@ module ts {
}
}
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 (current.kind === SyntaxKind.ClassDeclaration || current.kind === SyntaxKind.ClassExpression) {
return true;
}
current = parent;
parent = parent.parent;
}
return false;
}
function checkYieldExpression(node: YieldExpression): Type {
// Grammar checking
if (!(node.parserContextFlags & ParserContextFlags.Yield)) {
if (!(node.parserContextFlags & ParserContextFlags.Yield) || isYieldExpressionInClass(node)) {
grammarErrorOnFirstToken(node, Diagnostics.A_yield_expression_is_only_allowed_in_a_generator_declaration);
}
+14 -1
View File
@@ -4010,7 +4010,20 @@ module ts {
property.name = name;
property.questionToken = questionToken;
property.type = parseTypeAnnotation();
property.initializer = allowInAnd(parseNonParameterInitializer);
// For initializers, we always want to allow 'in' expressions. 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 Initialiser_opt[In];
// AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initialiser_opt[In, ?Yield];
//
// The checker may still error in the static case to explicitly disallow the yield expression.
property.initializer = modifiers && modifiers.flags & NodeFlags.Static
? allowInAnd(parseNonParameterInitializer)
: doOutsideOfContext(ParserContextFlags.Yield | ParserContextFlags.DisallowIn, parseNonParameterInitializer);
parseSemicolon();
return finishNode(property);
}
+3 -9
View File
@@ -530,11 +530,6 @@ module ts {
return traverse(body);
function traverse(node: Node): void {
// Yield expressions may occur in decorators
if (node.decorators) {
forEach(node.decorators, traverse);
}
switch (node.kind) {
case SyntaxKind.YieldExpression:
visitor(<YieldExpression>node);
@@ -546,18 +541,17 @@ module ts {
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.ClassDeclaration:
// These are not allowed inside a generator now, but eventually they may be allowed
// as local types. Regardless, any yield statements contained within them should be
// skipped in this traversal.
return;
case SyntaxKind.ClassDeclaration:
// A class declaration/expression may extend a yield expression
forEach((<ClassDeclaration>node).heritageClauses, traverse);
return;
default:
if (isFunctionLike(node)) {
let name = (<FunctionLikeDeclaration>node).name;
if (name && name.kind === SyntaxKind.ComputedPropertyName) {
// Note that we will not include methods/accessors of a class because they would require
// first descending into the class. This is by design.
traverse((<ComputedPropertyName>name).expression);
return;
}