Error on template tag inside callback/overload/typedef tag (#54118)

This commit is contained in:
Nathan Shively-Sanders
2023-05-04 09:51:43 -07:00
committed by GitHub
parent 7c378dbab3
commit 840a0bfc08
7 changed files with 491 additions and 9 deletions
+4
View File
@@ -6592,6 +6592,10 @@
"category": "Error",
"code": 8038
},
"A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag": {
"category": "Error",
"code": 8039
},
"Declaration emit for this file requires using private name '{0}'. An explicit type annotation may unblock declaration emit.": {
"category": "Error",
+20 -9
View File
@@ -9140,12 +9140,15 @@ namespace Parser {
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
const pos = getNodePos();
let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
let child: JSDocPropertyLikeTag | JSDocTypeTag | JSDocTemplateTag | false;
let children: JSDocPropertyLikeTag[] | undefined;
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
children = append(children, child);
}
else if (child.kind === SyntaxKind.JSDocTemplateTag) {
parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag);
}
}
if (children) {
const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos);
@@ -9291,11 +9294,14 @@ namespace Parser {
let end: number | undefined;
if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
let child: JSDocTypeTag | JSDocPropertyTag | false;
let child: JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false;
let childTypeTag: JSDocTypeTag | undefined;
let jsDocPropertyTags: JSDocPropertyTag[] | undefined;
let hasChildren = false;
while (child = tryParse(() => parseChildPropertyTag(indent))) {
if (child.kind === SyntaxKind.JSDocTemplateTag) {
break;
}
hasChildren = true;
if (child.kind === SyntaxKind.JSDocTypeTag) {
if (childTypeTag) {
@@ -9359,12 +9365,15 @@ namespace Parser {
return typeNameOrNamespaceName;
}
function parseCallbackTagParameters(indent: number) {
const pos = getNodePos();
let child: JSDocParameterTag | false;
let child: JSDocParameterTag | JSDocTemplateTag | false;
let parameters;
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag | JSDocTemplateTag)) {
if (child.kind === SyntaxKind.JSDocTemplateTag) {
parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag);
break;
}
parameters = append(parameters, child);
}
return createNodeArray(parameters || [], pos);
@@ -9420,10 +9429,10 @@ namespace Parser {
}
function parseChildPropertyTag(indent: number) {
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false;
}
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false {
let canParseTag = true;
let seenAsterisk = false;
while (true) {
@@ -9459,13 +9468,13 @@ namespace Parser {
}
}
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false {
Debug.assert(token() === SyntaxKind.AtToken);
const start = scanner.getTokenFullStart();
nextTokenJSDoc();
const tagName = parseJSDocIdentifierName();
skipWhitespace();
const indentText = skipWhitespaceOrAsterisk();
let t: PropertyLikeParse;
switch (tagName.escapedText) {
case "type":
@@ -9479,6 +9488,8 @@ namespace Parser {
case "param":
t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;
break;
case "template":
return parseTemplateTag(start, tagName, indent, indentText);
default:
return false;
}
@@ -0,0 +1,96 @@
error TS-1: Pre-emit (11) and post-emit (13) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!
tests/cases/conformance/jsdoc/templateInsideCallback.js(2,13): error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
tests/cases/conformance/jsdoc/templateInsideCallback.js(9,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
tests/cases/conformance/jsdoc/templateInsideCallback.js(10,12): error TS2304: Cannot find name 'T'.
tests/cases/conformance/jsdoc/templateInsideCallback.js(15,11): error TS2315: Type 'Call' is not generic.
tests/cases/conformance/jsdoc/templateInsideCallback.js(17,18): error TS7006: Parameter 'x' implicitly has an 'any' type.
tests/cases/conformance/jsdoc/templateInsideCallback.js(23,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
tests/cases/conformance/jsdoc/templateInsideCallback.js(30,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
tests/cases/conformance/jsdoc/templateInsideCallback.js(32,12): error TS2304: Cannot find name 'T'.
tests/cases/conformance/jsdoc/templateInsideCallback.js(33,16): error TS2304: Cannot find name 'T'.
tests/cases/conformance/jsdoc/templateInsideCallback.js(38,5): error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
tests/cases/conformance/jsdoc/templateInsideCallback.js(39,12): error TS2304: Cannot find name 'T'.
!!! error TS-1: Pre-emit (11) and post-emit (13) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!
!!! related TS-1: The excess diagnostics are:
!!! related TS7012 tests/cases/conformance/jsdoc/templateInsideCallback.js:29:5: This overload implicitly returns the type 'any' because it lacks a return type annotation.
!!! related TS7012 tests/cases/conformance/jsdoc/templateInsideCallback.js:37:5: This overload implicitly returns the type 'any' because it lacks a return type annotation.
==== tests/cases/conformance/jsdoc/templateInsideCallback.js (11 errors) ====
/**
* @typedef Oops
~~~~
!!! error TS8021: JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
~~~~~~~~
!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
* @param {T} x
~
!!! error TS2304: Cannot find name 'T'.
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
~~~~~~~
!!! error TS2315: Type 'Call' is not generic.
*/
const identity = x => x;
~
!!! error TS7006: Parameter 'x' implicitly has an 'any' type.
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
~~~~~~~~
!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
~~~~~~~~
!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
* @template U
* @param {T[]} array
~
!!! error TS2304: Cannot find name 'T'.
* @param {(x: T) => U[]} iterable
~
!!! error TS2304: Cannot find name 'T'.
* @returns {U[]}
*/
/**
* @overload
* @template T
~~~~~~~~
!!! error TS8039: A JSDoc '@template' tag may not follow a '@typedef', '@callback', or '@overload' tag
* @param {T[][]} array
~
!!! error TS2304: Cannot find name 'T'.
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}
@@ -0,0 +1,141 @@
//// [templateInsideCallback.js]
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
const identity = x => x;
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
* @template U
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @overload
* @template T
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}
//// [templateInsideCallback.js]
"use strict";
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
var identity = function (x) { return x; };
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
* @template U
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @overload
* @template T
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable) {
if (iterable === void 0) { iterable = identity; }
/** @type {unknown[]} */
var result = [];
for (var i = 0; i < array.length; i += 1) {
result.push.apply(result, /** @type {unknown[]} */ (iterable(array[i])));
}
return result;
}
//// [templateInsideCallback.d.ts]
declare function flatMap<U>(): any;
declare function flatMap(): any;
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
declare const identity: any;
type Nested = {
oh: {
no: number;
noooooo: string;
};
};
type Oops = any;
type Call = () => any;
@@ -0,0 +1,80 @@
=== tests/cases/conformance/jsdoc/templateInsideCallback.js ===
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
const identity = x => x;
>identity : Symbol(identity, Decl(templateInsideCallback.js, 16, 5))
>x : Symbol(x, Decl(templateInsideCallback.js, 16, 16))
>x : Symbol(x, Decl(templateInsideCallback.js, 16, 16))
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
* @template U
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @overload
* @template T
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : Symbol(flatMap, Decl(templateInsideCallback.js, 16, 24))
>array : Symbol(array, Decl(templateInsideCallback.js, 46, 17))
>iterable : Symbol(iterable, Decl(templateInsideCallback.js, 46, 23))
>identity : Symbol(identity, Decl(templateInsideCallback.js, 16, 5))
/** @type {unknown[]} */
const result = [];
>result : Symbol(result, Decl(templateInsideCallback.js, 48, 7))
for (let i = 0; i < array.length; i += 1) {
>i : Symbol(i, Decl(templateInsideCallback.js, 49, 10))
>i : Symbol(i, Decl(templateInsideCallback.js, 49, 10))
>array.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>array : Symbol(array, Decl(templateInsideCallback.js, 46, 17))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>i : Symbol(i, Decl(templateInsideCallback.js, 49, 10))
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>result : Symbol(result, Decl(templateInsideCallback.js, 48, 7))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>iterable : Symbol(iterable, Decl(templateInsideCallback.js, 46, 23))
>array : Symbol(array, Decl(templateInsideCallback.js, 46, 17))
>i : Symbol(i, Decl(templateInsideCallback.js, 49, 10))
}
return result;
>result : Symbol(result, Decl(templateInsideCallback.js, 48, 7))
}
@@ -0,0 +1,91 @@
=== tests/cases/conformance/jsdoc/templateInsideCallback.js ===
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
const identity = x => x;
>identity : any
>x => x : <T>(x: any) => any
>x : any
>x : any
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
* @template U
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @overload
* @template T
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
>flatMap : { <U>(): any; (): any; }
>array : unknown[]
>iterable : (x: unknown) => unknown
>identity : any
/** @type {unknown[]} */
const result = [];
>result : unknown[]
>[] : never[]
for (let i = 0; i < array.length; i += 1) {
>i : number
>0 : 0
>i < array.length : boolean
>i : number
>array.length : number
>array : unknown[]
>length : number
>i += 1 : number
>i : number
>1 : 1
result.push(.../** @type {unknown[]} */(iterable(array[i])));
>result.push(.../** @type {unknown[]} */(iterable(array[i]))) : number
>result.push : (...items: unknown[]) => number
>result : unknown[]
>push : (...items: unknown[]) => number
>.../** @type {unknown[]} */(iterable(array[i])) : unknown
>(iterable(array[i])) : unknown[]
>iterable(array[i]) : unknown
>iterable : (x: unknown) => unknown
>array[i] : unknown
>array : unknown[]
>i : number
}
return result;
>result : unknown[]
}
@@ -0,0 +1,59 @@
// @checkJs: true
// @strict: true
// @outDir: dist/
// @declaration: true
// @filename: templateInsideCallback.js
/**
* @typedef Oops
* @template T
* @property {T} a
* @property {T} b
*/
/**
* @callback Call
* @template T
* @param {T} x
* @returns {T}
*/
/**
* @template T
* @type {Call<T>}
*/
const identity = x => x;
/**
* @typedef Nested
* @property {Object} oh
* @property {number} oh.no
* @template T
* @property {string} oh.noooooo
*/
/**
* @overload
* @template T
* @template U
* @param {T[]} array
* @param {(x: T) => U[]} iterable
* @returns {U[]}
*/
/**
* @overload
* @template T
* @param {T[][]} array
* @returns {T[]}
*/
/**
* @param {unknown[]} array
* @param {(x: unknown) => unknown} iterable
* @returns {unknown[]}
*/
function flatMap(array, iterable = identity) {
/** @type {unknown[]} */
const result = [];
for (let i = 0; i < array.length; i += 1) {
result.push(.../** @type {unknown[]} */(iterable(array[i])));
}
return result;
}