Parse JSDoc ...T and T= only at top-level JSDoc (#22661)

* Parse JSDoc ...T and T= only at top-level JSDoc

...T and T= should only be legal at the top level of a type, and only in
JSDoc, since at least T= is ambiguous elsewhere. This PR changes parsing
to make that happen. The resulting parse tree is now simpler, allowing
me to get rid of some code I had to add in the checker.

* Extract JSDoc type parsing into its own function

* PR comments:return from parseJSDocType
This commit is contained in:
Nathan Shively-Sanders 2018-03-16 16:08:42 -07:00 committed by GitHub
parent 5fd3ed2c10
commit bb23e9601f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 56 additions and 114 deletions

View File

@ -6574,14 +6574,7 @@ namespace ts {
// node.type should only be a JSDocOptionalType when node is a parameter of a JSDocFunctionType
node.type && node.type.kind === SyntaxKind.JSDocOptionalType
|| getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) =>
isBracketed || !!typeExpression && skipJSDocPrefixTypes(typeExpression.type).kind === SyntaxKind.JSDocOptionalType));
}
function skipJSDocPrefixTypes(type: TypeNode): TypeNode {
while (type.kind === SyntaxKind.JSDocNullableType || type.kind === SyntaxKind.JSDocNonNullableType) {
type = (type as JSDocNullableType | JSDocNonNullableType).type;
}
return type;
isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType));
}
function tryFindAmbientModule(moduleName: string, withAugmentations: boolean) {

View File

@ -2204,11 +2204,18 @@ namespace ts {
}
function parseJSDocAllType(): JSDocAllType {
const result = <JSDocAllType>createNode(SyntaxKind.JSDocAllType);
const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType;
nextToken();
return finishNode(result);
}
function parseJSDocNonNullableType(): TypeNode {
const result = createNode(SyntaxKind.JSDocNonNullableType) as JSDocNonNullableType;
nextToken();
result.type = parseNonArrayType();
return finishNode(result);
}
function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
const pos = scanner.getStartPos();
// skip the ?
@ -2259,15 +2266,22 @@ namespace ts {
parameter.name = parseIdentifierName();
parseExpected(SyntaxKind.ColonToken);
}
parameter.type = parseType();
parameter.type = parseJSDocType();
return finishNode(parameter);
}
function parseJSDocNodeWithType(kind: SyntaxKind.JSDocVariadicType | SyntaxKind.JSDocNonNullableType): TypeNode {
const result = createNode(kind) as JSDocVariadicType | JSDocNonNullableType;
nextToken();
result.type = parseNonArrayType();
return finishNode(result);
function parseJSDocType() {
const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
let type = parseType();
if (dotdotdot) {
const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType;
variadic.type = type;
type = finishNode(variadic);
}
if (token() === SyntaxKind.EqualsToken) {
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type);
}
return type;
}
function parseTypeQuery(): TypeQueryNode {
@ -2732,7 +2746,7 @@ namespace ts {
case SyntaxKind.FunctionKeyword:
return parseJSDocFunctionType();
case SyntaxKind.ExclamationToken:
return parseJSDocNodeWithType(SyntaxKind.JSDocNonNullableType);
return parseJSDocNonNullableType();
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
@ -2817,13 +2831,6 @@ namespace ts {
let type = parseNonArrayType();
while (!scanner.hasPrecedingLineBreak()) {
switch (token()) {
case SyntaxKind.EqualsToken:
// only parse postfix = inside jsdoc, because it's ambiguous elsewhere
if (!(contextFlags & NodeFlags.JSDoc)) {
return type;
}
type = createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type);
break;
case SyntaxKind.ExclamationToken:
type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type);
break;
@ -2889,12 +2896,6 @@ namespace ts {
return parseTypeOperator(operator);
case SyntaxKind.InferKeyword:
return parseInferType();
case SyntaxKind.DotDotDotToken: {
const result = createNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
nextToken();
result.type = parsePostfixTypeOrHigher();
return finishNode(result);
}
}
return parsePostfixTypeOrHigher();
}
@ -6156,7 +6157,7 @@ namespace ts {
const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
result.type = doInsideOfContext(NodeFlags.JSDoc, parseType);
result.type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
if (!mayOmitBraces || hasBrace) {
parseExpected(SyntaxKind.CloseBraceToken);
}

View File

@ -7,22 +7,16 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(11,12): error TS255
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(13,14): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(14,11): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(15,8): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,5): error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'.
Type 'boolean[]' is not assignable to type 'false'.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(17,11): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,11): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(17,17): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(18,5): error TS2322: Type 'undefined' is not assignable to type 'number | null'.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(18,17): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'number | null'.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,17): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(20,16): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(21,16): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(22,16): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(23,17): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8020: JSDoc types can only be used inside documentation comments.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(22,17): error TS8020: JSDoc types can only be used inside documentation comments.
==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (21 errors) ====
==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (16 errors) ====
// grammar error from checker
var ara: Array.<number> = [1,2,3];
~
@ -56,14 +50,6 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS802
var g: function(number, number): number = (n,m) => n + m;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
var variadic: ...boolean = [true, false, true];
~~~~~~~~
!!! error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'.
!!! error TS2322: Type 'boolean[]' is not assignable to type 'false'.
~~~~~~~~~~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
~~~~~~~~~~
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
var most: !string = 'definite';
~~~~~~~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
@ -85,10 +71,5 @@ tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS802
var anys: Array<*>;
~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
var vars: Array<...number>;
~~~~~~~~~
!!! error TS8020: JSDoc types can only be used inside documentation comments.
~~~~~~~~~
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.

View File

@ -14,7 +14,6 @@ function hof2(f: function(this: number, string): string) {
var whatevs: * = 1001;
var ques: ? = 'what';
var g: function(number, number): number = (n,m) => n + m;
var variadic: ...boolean = [true, false, true];
var most: !string = 'definite';
var postfixdef: number! = 101;
var postfixopt: number? = undefined;
@ -22,7 +21,6 @@ var postfixopt: number? = undefined;
var nns: Array<?number>;
var dns: Array<!number>;
var anys: Array<*>;
var vars: Array<...number>;
@ -42,11 +40,9 @@ function hof2(f) {
var whatevs = 1001;
var ques = 'what';
var g = function (n, m) { return n + m; };
var variadic = [true, false, true];
var most = 'definite';
var postfixdef = 101;
var postfixopt = undefined;
var nns;
var dns;
var anys;
var vars;

View File

@ -45,33 +45,26 @@ var g: function(number, number): number = (n,m) => n + m;
>n : Symbol(n, Decl(jsdocDisallowedInTypescript.ts, 14, 43))
>m : Symbol(m, Decl(jsdocDisallowedInTypescript.ts, 14, 45))
var variadic: ...boolean = [true, false, true];
>variadic : Symbol(variadic, Decl(jsdocDisallowedInTypescript.ts, 15, 3))
var most: !string = 'definite';
>most : Symbol(most, Decl(jsdocDisallowedInTypescript.ts, 16, 3))
>most : Symbol(most, Decl(jsdocDisallowedInTypescript.ts, 15, 3))
var postfixdef: number! = 101;
>postfixdef : Symbol(postfixdef, Decl(jsdocDisallowedInTypescript.ts, 17, 3))
>postfixdef : Symbol(postfixdef, Decl(jsdocDisallowedInTypescript.ts, 16, 3))
var postfixopt: number? = undefined;
>postfixopt : Symbol(postfixopt, Decl(jsdocDisallowedInTypescript.ts, 18, 3))
>postfixopt : Symbol(postfixopt, Decl(jsdocDisallowedInTypescript.ts, 17, 3))
>undefined : Symbol(undefined)
var nns: Array<?number>;
>nns : Symbol(nns, Decl(jsdocDisallowedInTypescript.ts, 20, 3))
>nns : Symbol(nns, Decl(jsdocDisallowedInTypescript.ts, 19, 3))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
var dns: Array<!number>;
>dns : Symbol(dns, Decl(jsdocDisallowedInTypescript.ts, 21, 3))
>dns : Symbol(dns, Decl(jsdocDisallowedInTypescript.ts, 20, 3))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
var anys: Array<*>;
>anys : Symbol(anys, Decl(jsdocDisallowedInTypescript.ts, 22, 3))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
var vars: Array<...number>;
>vars : Symbol(vars, Decl(jsdocDisallowedInTypescript.ts, 23, 3))
>anys : Symbol(anys, Decl(jsdocDisallowedInTypescript.ts, 21, 3))
>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))

View File

@ -64,13 +64,6 @@ var g: function(number, number): number = (n,m) => n + m;
>n : number
>m : number
var variadic: ...boolean = [true, false, true];
>variadic : boolean | undefined
>[true, false, true] : boolean[]
>true : true
>false : false
>true : true
var most: !string = 'definite';
>most : string
>'definite' : "definite"
@ -95,8 +88,4 @@ var anys: Array<*>;
>anys : any[]
>Array : T[]
var vars: Array<...number>;
>vars : (number | undefined)[]
>Array : T[]

View File

@ -1,13 +1,12 @@
tests/cases/conformance/jsdoc/prefixPostfix.js(8,13): error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
tests/cases/conformance/jsdoc/prefixPostfix.js(8,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(9,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(10,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(11,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(12,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(13,12): error TS1014: A rest parameter must be last in a parameter list.
tests/cases/conformance/jsdoc/prefixPostfix.js(14,12): error TS1014: A rest parameter must be last in a parameter list.
==== tests/cases/conformance/jsdoc/prefixPostfix.js (7 errors) ====
==== tests/cases/conformance/jsdoc/prefixPostfix.js (6 errors) ====
/**
* @param {number![]} x - number[]
* @param {!number[]} y - number[]
@ -15,9 +14,6 @@ tests/cases/conformance/jsdoc/prefixPostfix.js(14,12): error TS1014: A rest para
* @param {number?[]} a - (number | null)[]
* @param {?number[]} b - number[] | null
* @param {(number[])?} c - number[] | null
* @param {?...number} d - number[] | null
~~~~~~~~~
!!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature.
* @param {...?number} e - (number | null)[]
~~~~~~~~~~
!!! error TS1014: A rest parameter must be last in a parameter list.
@ -38,6 +34,6 @@ tests/cases/conformance/jsdoc/prefixPostfix.js(14,12): error TS1014: A rest para
!!! error TS1014: A rest parameter must be last in a parameter list.
* @param {...number?[]!} k - (number[] | null)[]
*/
function f(x, y, z, a, b, c, d, e, f, g, h, i, j, k) {
function f(x, y, z, a, b, c, e, f, g, h, i, j, k) {
}

View File

@ -6,7 +6,6 @@
* @param {number?[]} a - (number | null)[]
* @param {?number[]} b - number[] | null
* @param {(number[])?} c - number[] | null
* @param {?...number} d - number[] | null
* @param {...?number} e - (number | null)[]
* @param {...number?} f - number[] | null
* @param {...number!?} g - number[] | null
@ -15,21 +14,20 @@
* @param {...number![]?} j - number[][] | null
* @param {...number?[]!} k - (number[] | null)[]
*/
function f(x, y, z, a, b, c, d, e, f, g, h, i, j, k) {
function f(x, y, z, a, b, c, e, f, g, h, i, j, k) {
>f : Symbol(f, Decl(prefixPostfix.js, 0, 0))
>x : Symbol(x, Decl(prefixPostfix.js, 16, 11))
>y : Symbol(y, Decl(prefixPostfix.js, 16, 13))
>z : Symbol(z, Decl(prefixPostfix.js, 16, 16))
>a : Symbol(a, Decl(prefixPostfix.js, 16, 19))
>b : Symbol(b, Decl(prefixPostfix.js, 16, 22))
>c : Symbol(c, Decl(prefixPostfix.js, 16, 25))
>d : Symbol(d, Decl(prefixPostfix.js, 16, 28))
>e : Symbol(e, Decl(prefixPostfix.js, 16, 31))
>f : Symbol(f, Decl(prefixPostfix.js, 16, 34))
>g : Symbol(g, Decl(prefixPostfix.js, 16, 37))
>h : Symbol(h, Decl(prefixPostfix.js, 16, 40))
>i : Symbol(i, Decl(prefixPostfix.js, 16, 43))
>j : Symbol(j, Decl(prefixPostfix.js, 16, 46))
>k : Symbol(k, Decl(prefixPostfix.js, 16, 49))
>x : Symbol(x, Decl(prefixPostfix.js, 15, 11))
>y : Symbol(y, Decl(prefixPostfix.js, 15, 13))
>z : Symbol(z, Decl(prefixPostfix.js, 15, 16))
>a : Symbol(a, Decl(prefixPostfix.js, 15, 19))
>b : Symbol(b, Decl(prefixPostfix.js, 15, 22))
>c : Symbol(c, Decl(prefixPostfix.js, 15, 25))
>e : Symbol(e, Decl(prefixPostfix.js, 15, 28))
>f : Symbol(f, Decl(prefixPostfix.js, 15, 31))
>g : Symbol(g, Decl(prefixPostfix.js, 15, 34))
>h : Symbol(h, Decl(prefixPostfix.js, 15, 37))
>i : Symbol(i, Decl(prefixPostfix.js, 15, 40))
>j : Symbol(j, Decl(prefixPostfix.js, 15, 43))
>k : Symbol(k, Decl(prefixPostfix.js, 15, 46))
}

View File

@ -6,7 +6,6 @@
* @param {number?[]} a - (number | null)[]
* @param {?number[]} b - number[] | null
* @param {(number[])?} c - number[] | null
* @param {?...number} d - number[] | null
* @param {...?number} e - (number | null)[]
* @param {...number?} f - number[] | null
* @param {...number!?} g - number[] | null
@ -15,15 +14,14 @@
* @param {...number![]?} j - number[][] | null
* @param {...number?[]!} k - (number[] | null)[]
*/
function f(x, y, z, a, b, c, d, e, f, g, h, i, j, k) {
>f : (x: number[], y: number[], z: number[], a: (number | null)[], b: number[] | null, c: number[] | null, d: number | null | undefined, e: number | null | undefined, f: number | null | undefined, g: number | null | undefined, h: number | null | undefined, i: number[] | undefined, j: number[] | null | undefined, k: (number | null)[] | undefined) => void
function f(x, y, z, a, b, c, e, f, g, h, i, j, k) {
>f : (x: number[], y: number[], z: number[], a: (number | null)[], b: number[] | null, c: number[] | null, e: number | null | undefined, f: number | null | undefined, g: number | null | undefined, h: number | null | undefined, i: number[] | undefined, j: number[] | null | undefined, k: (number | null)[] | undefined) => void
>x : number[]
>y : number[]
>z : number[]
>a : (number | null)[]
>b : number[] | null
>c : number[] | null
>d : number | null | undefined
>e : number | null | undefined
>f : number | null | undefined
>g : number | null | undefined

View File

@ -15,7 +15,6 @@ function hof2(f: function(this: number, string): string) {
var whatevs: * = 1001;
var ques: ? = 'what';
var g: function(number, number): number = (n,m) => n + m;
var variadic: ...boolean = [true, false, true];
var most: !string = 'definite';
var postfixdef: number! = 101;
var postfixopt: number? = undefined;
@ -23,5 +22,4 @@ var postfixopt: number? = undefined;
var nns: Array<?number>;
var dns: Array<!number>;
var anys: Array<*>;
var vars: Array<...number>;

View File

@ -13,7 +13,6 @@
* @param {number?[]} a - (number | null)[]
* @param {?number[]} b - number[] | null
* @param {(number[])?} c - number[] | null
* @param {?...number} d - number[] | null
* @param {...?number} e - (number | null)[]
* @param {...number?} f - number[] | null
* @param {...number!?} g - number[] | null
@ -22,5 +21,5 @@
* @param {...number![]?} j - number[][] | null
* @param {...number?[]!} k - (number[] | null)[]
*/
function f(x, y, z, a, b, c, d, e, f, g, h, i, j, k) {
function f(x, y, z, a, b, c, e, f, g, h, i, j, k) {
}