Skip to content

Commit

Permalink
Limit node flag to expressions to not mess up incremental parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbranch committed Jan 15, 2020
1 parent 3514184 commit a0691da
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1865,7 +1865,7 @@ namespace ts {
}

function checkSymbolUsageInExpressionContext(symbol: Symbol, name: __String, useSite: Node) {
if (!(useSite.flags & (NodeFlags.Ambient | NodeFlags.InNonEmittingNode)) && useSite.parent.kind !== SyntaxKind.ExportSpecifier) {
if (!(useSite.flags & (NodeFlags.Ambient | NodeFlags.InNonEmittingExpression)) && useSite.parent.kind !== SyntaxKind.ExportSpecifier) {
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(symbol);
if (typeOnlyDeclaration) {
const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier
Expand Down
59 changes: 20 additions & 39 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1444,13 +1444,16 @@ namespace ts {
token() === SyntaxKind.NumericLiteral;
}

function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
function parsePropertyNameWorker(allowComputedPropertyNames: boolean, computedNameIsNonEmitting: boolean): PropertyName {
if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
const node = <StringLiteral | NumericLiteral>parseLiteralNode();
node.text = internIdentifier(node.text);
return node;
}
if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) {
if (computedNameIsNonEmitting) {
return doInsideOfContext(NodeFlags.InNonEmittingExpression, parseComputedPropertyName);
}
return parseComputedPropertyName();
}
if (token() === SyntaxKind.PrivateIdentifier) {
Expand All @@ -1459,8 +1462,8 @@ namespace ts {
return parseIdentifierName();
}

function parsePropertyName(): PropertyName {
return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true);
function parsePropertyName(computedNameIsNonEmitting: boolean): PropertyName {
return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true, computedNameIsNonEmitting);
}

function parseComputedPropertyName(): ComputedPropertyName {
Expand Down Expand Up @@ -2563,7 +2566,7 @@ namespace ts {
function parseTypeQuery(): TypeQueryNode {
const node = <TypeQueryNode>createNode(SyntaxKind.TypeQuery);
parseExpected(SyntaxKind.TypeOfKeyword);
node.exprName = parseEntityName(/*allowReservedWords*/ true);
node.exprName = doInsideOfContext(NodeFlags.InNonEmittingExpression, () => parseEntityName(/*allowReservedWords*/ true));
return finishNode(node);
}

Expand Down Expand Up @@ -2814,7 +2817,7 @@ namespace ts {
}

function parsePropertyOrMethodSignature(node: PropertySignature | MethodSignature): PropertySignature | MethodSignature {
node.name = parsePropertyName();
node.name = parsePropertyName(/*computedNameIsNonEmitting*/ true);
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
node.kind = SyntaxKind.MethodSignature;
Expand Down Expand Up @@ -3362,10 +3365,7 @@ namespace ts {
function parseType(): TypeNode {
// The rules about 'yield' only apply to actual code/expression contexts. They don't
// apply to 'type' contexts. So we disable these parameters here before moving on.
return doOutsideOfContext(
NodeFlags.TypeExcludesFlags,
() => doInsideOfContext(NodeFlags.InNonEmittingNode, parseTypeWorker)
);
return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker);
}

function parseTypeWorker(noConditionalTypes?: boolean): TypeNode {
Expand Down Expand Up @@ -5002,7 +5002,7 @@ namespace ts {

const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
const tokenIsIdentifier = isIdentifier();
node.name = parsePropertyName();
node.name = parsePropertyName(/*computedNameIsNonEmitting*/ false);
// Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
(<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
(<MethodDeclaration>node).exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
Expand Down Expand Up @@ -5712,9 +5712,9 @@ namespace ts {
case SyntaxKind.ClassKeyword:
return parseClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.InterfaceKeyword:
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseInterfaceDeclaration(<InterfaceDeclaration>node));
return parseInterfaceDeclaration(<InterfaceDeclaration>node);
case SyntaxKind.TypeKeyword:
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseTypeAliasDeclaration(<TypeAliasDeclaration>node));
return parseTypeAliasDeclaration(<TypeAliasDeclaration>node);
case SyntaxKind.EnumKeyword:
return parseEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.GlobalKeyword:
Expand Down Expand Up @@ -5779,7 +5779,7 @@ namespace ts {
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
const tokenIsIdentifier = isIdentifier();
const propertyName = parsePropertyName();
const propertyName = parsePropertyName(/*computedNameIsNonEmitting*/ false);
if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {
node.name = <Identifier>propertyName;
}
Expand Down Expand Up @@ -5953,12 +5953,8 @@ namespace ts {

function parsePropertyOrMethodDeclaration(node: PropertyDeclaration | MethodDeclaration): PropertyDeclaration | MethodDeclaration {
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
if (node.modifiers && some(node.modifiers, isAbstractModifier)) {
node.name = doInsideOfContext(NodeFlags.InNonEmittingNode, parsePropertyName);
}
else {
node.name = parsePropertyName();
}
const isAbstract = !!node.modifiers && some(node.modifiers, isAbstractModifier);
node.name = parsePropertyName(isAbstract);

// Note: this is not legal as per the grammar. But we allow it in the parser and
// report an error in the grammar checker.
Expand All @@ -5971,7 +5967,7 @@ namespace ts {

function parseAccessorDeclaration(node: AccessorDeclaration, kind: AccessorDeclaration["kind"]): AccessorDeclaration {
node.kind = kind;
node.name = parsePropertyName();
node.name = parsePropertyName(/*computedNameIsNonEmitting*/ false);
fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None);
return finishNode(node);
Expand Down Expand Up @@ -6277,7 +6273,7 @@ namespace ts {
// or any time an integer literal initializer is encountered.
function parseEnumMember(): EnumMember {
const node = <EnumMember>createNodeWithJSDoc(SyntaxKind.EnumMember);
node.name = parsePropertyName();
node.name = parsePropertyName(/*computedNameIsNonEmitting*/ false);
node.initializer = allowInAnd(parseInitializer);
return finishNode(node);
}
Expand Down Expand Up @@ -6396,35 +6392,23 @@ namespace ts {
(isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())
) {
isTypeOnly = true;
identifier = isIdentifier() ? doInsideOfContext(NodeFlags.InNonEmittingNode, parseIdentifier) : undefined;
node.flags |= NodeFlags.InNonEmittingNode;
identifier = isIdentifier() ? parseIdentifier() : undefined;
}

if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {
return parseImportEqualsDeclaration(<ImportEqualsDeclaration>node, identifier, isTypeOnly);
}

// Import statement
if (isTypeOnly) {
return doInsideOfContext(
NodeFlags.InNonEmittingNode,
() => parseImportDeclarationRest(node as ImportDeclaration, afterImportPos, identifier, isTypeOnly)
);
}

return parseImportDeclarationRest(node as ImportDeclaration, afterImportPos, identifier, isTypeOnly);
}

function parseImportDeclarationRest(node: ImportDeclaration, afterImportPos: number, name: Identifier | undefined, isTypeOnly: boolean): ImportDeclaration {
node.kind = SyntaxKind.ImportDeclaration;
// ImportDeclaration:
// import ImportClause from ModuleSpecifier ;
// import ModuleSpecifier;
if (name || // import id
if (identifier || // import id
token() === SyntaxKind.AsteriskToken || // import *
token() === SyntaxKind.OpenBraceToken // import {
) {
(<ImportDeclaration>node).importClause = parseImportClause(name, afterImportPos, isTypeOnly);
(<ImportDeclaration>node).importClause = parseImportClause(identifier, afterImportPos, isTypeOnly);
parseExpected(SyntaxKind.FromKeyword);
}

Expand Down Expand Up @@ -6587,9 +6571,6 @@ namespace ts {
function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration {
node.kind = SyntaxKind.ExportDeclaration;
node.isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
if (node.isTypeOnly) {
return doInsideOfContext(NodeFlags.InNonEmittingNode, () => parseExportDeclarationWorker(node));
}
return parseExportDeclarationWorker(node);
}

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,15 +574,15 @@ namespace ts {
/* @internal */ InWithStatement = 1 << 24, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 25, // If node was parsed in a Json
/* @internal */ TypeCached = 1 << 26, // If a type was cached for node at any point
/* @internal */ InNonEmittingNode = 1 << 27, // If a node was in a context where expressions are never emitted: type queries, abstract members, computed property names of types.
/* @internal */ InNonEmittingExpression = 1 << 27, // If a node was in a context where expressions are never emitted: type queries, abstract members, computed property names of types.

BlockScoped = Let | Const,

ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions,

// Parsing context flags
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient,
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient | InNonEmittingExpression,

// Exclude these flags when parsing a Type
TypeExcludesFlags = YieldContext | AwaitContext,
Expand Down

0 comments on commit a0691da

Please sign in to comment.