From 8b8cc97ecf3982abba7bb28d06d8cce47f5790e3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 4 Jun 2018 12:26:12 -0700 Subject: [PATCH 1/2] Simplify parseJSDocIdentifierName It now always creates a missing node. The one place that depended on it returning undefined, parseJSDocTypeNameWithNamespace, now returns undefined before calling parseJSDocIdentifierName. --- src/compiler/parser.ts | 116 +++++++----------- .../reference/jsdocTemplateTag3.types | 2 +- 2 files changed, 47 insertions(+), 71 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2e75775fbd845..7bbd3cf462a2c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6496,54 +6496,43 @@ namespace ts { const tagName = parseJSDocIdentifierName(); skipWhitespace(); - if (!tagName) { - return; - } let tag: JSDocTag | undefined; - if (tagName) { - switch (tagName.escapedText) { - case "augments": - case "extends": - tag = parseAugmentsTag(atToken, tagName); - break; - case "class": - case "constructor": - tag = parseClassTag(atToken, tagName); - break; - case "arg": - case "argument": - case "param": - return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent); - case "return": - case "returns": - tag = parseReturnTag(atToken, tagName); - break; - case "template": - tag = parseTemplateTag(atToken, tagName); - break; - case "type": - tag = parseTypeTag(atToken, tagName); - break; - case "typedef": - tag = parseTypedefTag(atToken, tagName, indent); - break; - case "callback": - tag = parseCallbackTag(atToken, tagName, indent); - break; - default: - tag = parseUnknownTag(atToken, tagName); - break; - } - } - else { - tag = parseUnknownTag(atToken, tagName); + switch (tagName.escapedText) { + case "augments": + case "extends": + tag = parseAugmentsTag(atToken, tagName); + break; + case "class": + case "constructor": + tag = parseClassTag(atToken, tagName); + break; + case "arg": + case "argument": + case "param": + return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent); + case "return": + case "returns": + tag = parseReturnTag(atToken, tagName); + break; + case "template": + tag = parseTemplateTag(atToken, tagName); + break; + case "type": + tag = parseTypeTag(atToken, tagName); + break; + case "typedef": + tag = parseTypedefTag(atToken, tagName, indent); + break; + case "callback": + tag = parseCallbackTag(atToken, tagName, indent); + break; + default: + tag = parseUnknownTag(atToken, tagName); + break; } + Debug.assert(!!tag); - if (!tag) { - // a badly malformed tag should not be added to the list of tags - return; - } if (!tag.comment) { // some tags, like typedef and callback, have already parsed their comments earlier tag.comment = parseTagComments(indent + tag.end - tag.pos); @@ -6773,11 +6762,11 @@ namespace ts { } function parsePropertyAccessEntityNameExpression() { - let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(/*createIfMissing*/ true); + let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression; prop.expression = node; - prop.name = parseJSDocIdentifierName()!; // TODO: GH#18217 + prop.name = parseJSDocIdentifierName(); node = finishNode(prop); } return node; @@ -6842,9 +6831,11 @@ namespace ts { function parseJSDocTypeNameWithNamespace(nested?: boolean) { const pos = scanner.getTokenPos(); + if (!tokenIsIdentifierOrKeyword(token())) { + return undefined; + } const typeNameOrNamespaceName = parseJSDocIdentifierName(); - - if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) { + if (parseOptional(SyntaxKind.DotToken)) { const jsDocNamespaceNode = createNode(SyntaxKind.ModuleDeclaration, pos); if (nested) { jsDocNamespaceNode.flags |= NodeFlags.NestedNamespace; @@ -6854,7 +6845,7 @@ namespace ts { return finishNode(jsDocNamespaceNode); } - if (typeNameOrNamespaceName && nested) { + if (nested) { typeNameOrNamespaceName.isInJSDocNamespace = true; } return typeNameOrNamespaceName; @@ -6965,9 +6956,6 @@ namespace ts { const tagName = parseJSDocIdentifierName(); skipWhitespace(); - if (!tagName) { - return false; - } let t: PropertyLikeParse; switch (tagName.escapedText) { case "type": @@ -6992,7 +6980,7 @@ namespace ts { return tag; } - function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag | undefined { + function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag { // the template tag looks like '@template {Constraint} T,U,V' let constraint: JSDocTypeExpression | undefined; if (token() === SyntaxKind.OpenBraceToken) { @@ -7004,11 +6992,7 @@ namespace ts { const typeParametersPos = getNodePos(); while (true) { const typeParameter = createNode(SyntaxKind.TypeParameter); - if (!tokenIsIdentifierOrKeyword(token())) { - parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); - return undefined; - } - typeParameter.name = parseJSDocIdentifierName()!; + typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); skipWhitespace(); finishNode(typeParameter); typeParameters.push(typeParameter); @@ -7039,7 +7023,7 @@ namespace ts { } function parseJSDocEntityName(): EntityName { - let entity: EntityName = parseJSDocIdentifierName(/*createIfMissing*/ true); + let entity: EntityName = parseJSDocIdentifierName(); if (parseOptional(SyntaxKind.OpenBracketToken)) { parseExpected(SyntaxKind.CloseBracketToken); // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. @@ -7047,7 +7031,7 @@ namespace ts { // but it's not worth it to enforce that restriction. } while (parseOptional(SyntaxKind.DotToken)) { - const name = parseJSDocIdentifierName(/*createIfMissing*/ true); + const name = parseJSDocIdentifierName(); if (parseOptional(SyntaxKind.OpenBracketToken)) { parseExpected(SyntaxKind.CloseBracketToken); } @@ -7056,17 +7040,9 @@ namespace ts { return entity; } - function parseJSDocIdentifierName(): Identifier | undefined; - function parseJSDocIdentifierName(createIfMissing: true): Identifier; - function parseJSDocIdentifierName(createIfMissing = false): Identifier | undefined { + function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { if (!tokenIsIdentifierOrKeyword(token())) { - if (createIfMissing) { - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); - } - else { - parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - return undefined; - } + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); } const pos = scanner.getTokenPos(); diff --git a/tests/baselines/reference/jsdocTemplateTag3.types b/tests/baselines/reference/jsdocTemplateTag3.types index 63e8498d84aac..e26b847519e2b 100644 --- a/tests/baselines/reference/jsdocTemplateTag3.types +++ b/tests/baselines/reference/jsdocTemplateTag3.types @@ -89,7 +89,7 @@ f({ a: 12 }, undefined, undefined, 101, 'nope'); * @param {T} x */ function g(x) { } ->g : (x: T) => void +>g : <(Missing) extends any, T>(x: T) => void >x : T From e722e9e9c00040d345886da855adda8e4e192905 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 5 Jun 2018 14:02:06 -0700 Subject: [PATCH 2/2] Remove assert It is adequately proven at compile time. --- src/compiler/parser.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7bbd3cf462a2c..ec7b601c77267 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6531,7 +6531,6 @@ namespace ts { tag = parseUnknownTag(atToken, tagName); break; } - Debug.assert(!!tag); if (!tag.comment) { // some tags, like typedef and callback, have already parsed their comments earlier