diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5eb14081e2a3c..518ebce5d73bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -276,7 +276,6 @@ import { getDirectoryPath, getEffectiveBaseTypeNode, getEffectiveConstraintOfTypeParameter, - getEffectiveContainerForJSDocTemplateTag, getEffectiveImplementsTypeNodes, getEffectiveInitializer, getEffectiveJSDocHost, @@ -16217,9 +16216,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint; } + function getEffectiveTypeParameterHost(typeParameter: TypeParameter) { + const declarations = typeParameter.symbol.declarations; + if (!declarations || declarations.length !== 1) { + return; + } + const tpDeclaration = getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter); + if (!tpDeclaration) { + // Type parameter is the this type, and its declaration is the class declaration. + return typeParameter.isThisType ? declarations[0].parent : undefined; + } + return isJSDocTemplateTag(tpDeclaration.parent) ? getEffectiveJSDocHost(tpDeclaration.parent) : tpDeclaration.parent; + } + function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol | undefined { - const tp = getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter)!; - const host = isJSDocTemplateTag(tp.parent) ? getEffectiveContainerForJSDocTemplateTag(tp.parent) : tp.parent; + const host = getEffectiveTypeParameterHost(typeParameter); return host && getSymbolOfNode(host); } @@ -20190,7 +20201,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // type parameter, or if the node contains type queries that we can't prove couldn't contain references to the type parameter, // we consider the type parameter possibly referenced. if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) { - const container = tp.symbol.declarations[0].parent; + const container = getEffectiveTypeParameterHost(tp); for (let n = node; n !== container; n = n.parent) { if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) { return true; @@ -20211,12 +20222,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const firstIdentifier = getFirstIdentifier(entityName); if (!isThisIdentifier(firstIdentifier)) { // Don't attempt to analyze typeof this.xxx const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier); - const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called - const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent : // Type parameter is a regular type parameter, e.g. foo - tp.isThisType ? tpDeclaration : // Type parameter is the this type, and its declaration is the class declaration. - undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation. - if (firstIdentifierSymbol.declarations && tpScope) { - return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) || + const tpHost = getEffectiveTypeParameterHost(tp); + if (firstIdentifierSymbol.declarations && tpHost) { + return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpHost)) || some((node as TypeQueryNode).typeArguments, containsReference); } } @@ -36138,8 +36146,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (candidate.typeParameters) { // If we are *inside the body of candidate*, we need to create a clone of `candidate` with differing type parameter identities, // so our inference results for this call doesn't pollute expression types referencing the outer type parameter! - const paramLocation = candidate.typeParameters[0].symbol.declarations?.[0]?.parent; - const candidateParameterContext = paramLocation || (candidate.declaration && isConstructorDeclaration(candidate.declaration) ? candidate.declaration.parent : candidate.declaration); + const paramHost = getEffectiveTypeParameterHost(candidate.typeParameters[0]); + const candidateParameterContext = paramHost || (candidate.declaration && isConstructorDeclaration(candidate.declaration) ? candidate.declaration.parent : candidate.declaration); if (candidateParameterContext && findAncestor(node, a => a === candidateParameterContext)) { candidate = getImplementationSignature(candidate); } diff --git a/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.symbols b/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.symbols new file mode 100644 index 0000000000000..ae52eea8f04c6 --- /dev/null +++ b/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.symbols @@ -0,0 +1,70 @@ +//// [tests/cases/compiler/inferFromReturnOfContextSensitiveFnJsDoc1.ts] //// + +=== index.js === +/** + * @template S + * @param {(arg0: { observer: EO }) => S} callback + * @param {Options} [options] + * @returns {VC} + */ +/* + * @type { (fn: (arg0: { observer: EO; }) => S, options?: Options) => VC } + */ +function define(callback, options) { +>define : Symbol(define, Decl(index.js, 0, 0)) +>callback : Symbol(callback, Decl(index.js, 9, 16)) +>options : Symbol(options, Decl(index.js, 9, 25)) + + const { name } = options ?? {}; +>name : Symbol(name, Decl(index.js, 10, 9)) +>options : Symbol(options, Decl(index.js, 9, 25)) + + const observer = new EO(); +>observer : Symbol(observer, Decl(index.js, 11, 7)) +>EO : Symbol(EO, Decl(index.js, 28, 1)) + + const state = callback({ observer }); +>state : Symbol(state, Decl(index.js, 12, 7)) +>callback : Symbol(callback, Decl(index.js, 9, 16)) +>observer : Symbol(observer, Decl(index.js, 12, 26)) + + return new VC(state); +>VC : Symbol(VC, Decl(index.js, 14, 1)) +>state : Symbol(state, Decl(index.js, 12, 7)) +} + +/** + * @template S + */ +class VC { +>VC : Symbol(VC, Decl(index.js, 14, 1)) + + /** @type {S} */ + state; +>state : Symbol(VC.state, Decl(index.js, 19, 10)) + + /** + * @param {S} state + */ + constructor(state) { +>state : Symbol(state, Decl(index.js, 25, 14)) + + this.state = state; +>this.state : Symbol(VC.state, Decl(index.js, 19, 10)) +>this : Symbol(VC, Decl(index.js, 14, 1)) +>state : Symbol(VC.state, Decl(index.js, 19, 10)) +>state : Symbol(state, Decl(index.js, 25, 14)) + } +} + +/** @typedef {{ name?: string }} Options */ + +class EO {} +>EO : Symbol(EO, Decl(index.js, 28, 1)) + +const v1 = define((arg0) => true, { name: "default" }); +>v1 : Symbol(v1, Decl(index.js, 34, 5)) +>define : Symbol(define, Decl(index.js, 0, 0)) +>arg0 : Symbol(arg0, Decl(index.js, 34, 19)) +>name : Symbol(name, Decl(index.js, 34, 35)) + diff --git a/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.types b/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.types new file mode 100644 index 0000000000000..03f766224f8e7 --- /dev/null +++ b/tests/baselines/reference/inferFromReturnOfContextSensitiveFnJsDoc1.types @@ -0,0 +1,118 @@ +//// [tests/cases/compiler/inferFromReturnOfContextSensitiveFnJsDoc1.ts] //// + +=== index.js === +/** + * @template S + * @param {(arg0: { observer: EO }) => S} callback + * @param {Options} [options] + * @returns {VC} + */ +/* + * @type { (fn: (arg0: { observer: EO; }) => S, options?: Options) => VC } + */ +function define(callback, options) { +>define : (callback: (arg0: { observer: EO; }) => S, options?: Options) => VC +> : ^ ^^ ^^ ^^ ^^^ ^^^^^ +>callback : (arg0: { observer: EO; }) => S +> : ^ ^^ ^^^^^ +>options : Options | undefined +> : ^^^^^^^^^^^^^^^^^^^ + + const { name } = options ?? {}; +>name : string | undefined +> : ^^^^^^^^^^^^^^^^^^ +>options ?? {} : Options +> : ^^^^^^^ +>options : Options | undefined +> : ^^^^^^^^^^^^^^^^^^^ +>{} : {} +> : ^^ + + const observer = new EO(); +>observer : EO +> : ^^ +>new EO() : EO +> : ^^ +>EO : typeof EO +> : ^^^^^^^^^ + + const state = callback({ observer }); +>state : S +> : ^ +>callback({ observer }) : S +> : ^ +>callback : (arg0: { observer: EO; }) => S +> : ^ ^^ ^^^^^ +>{ observer } : { observer: EO; } +> : ^^^^^^^^^^^^^^^^^ +>observer : EO +> : ^^ + + return new VC(state); +>new VC(state) : VC +> : ^^^^^ +>VC : typeof VC +> : ^^^^^^^^^ +>state : S +> : ^ +} + +/** + * @template S + */ +class VC { +>VC : VC +> : ^^^^^ + + /** @type {S} */ + state; +>state : S +> : ^ + + /** + * @param {S} state + */ + constructor(state) { +>state : S +> : ^ + + this.state = state; +>this.state = state : S +> : ^ +>this.state : S +> : ^ +>this : this +> : ^^^^ +>state : S +> : ^ +>state : S +> : ^ + } +} + +/** @typedef {{ name?: string }} Options */ + +class EO {} +>EO : EO +> : ^^ + +const v1 = define((arg0) => true, { name: "default" }); +>v1 : VC +> : ^^^^^^^^^^^ +>define((arg0) => true, { name: "default" }) : VC +> : ^^^^^^^^^^^ +>define : (callback: (arg0: { observer: EO; }) => S, options?: Options) => VC +> : ^ ^^ ^^ ^^ ^^^ ^^^^^ +>(arg0) => true : (arg0: { observer: EO; }) => boolean +> : ^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +>arg0 : { observer: EO; } +> : ^^^^^^^^^^^^ ^^^ +>true : true +> : ^^^^ +>{ name: "default" } : { name: string; } +> : ^^^^^^^^^^^^^^^^^ +>name : string +> : ^^^^^^ +>"default" : "default" +> : ^^^^^^^^^ + diff --git a/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.symbols b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.symbols new file mode 100644 index 0000000000000..1457313eabf5e --- /dev/null +++ b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.symbols @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts] //// + +=== inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts === +class S { +>S : Symbol(S, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 0)) +>T : Symbol(T, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 8)) + + set: Set; +>set : Symbol(S.set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 12)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 8)) + + constructor(set: Set) { +>set : Symbol(set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 3, 14)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 8)) + + this.set = set; +>this.set : Symbol(S.set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 12)) +>this : Symbol(S, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 0)) +>set : Symbol(S.set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 12)) +>set : Symbol(set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 3, 14)) + } + + array() { +>array : Symbol(S.array, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 5, 3)) + + return new S(new Set([...this.set].map((item) => [item]))); +>S : Symbol(S, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 0)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>[...this.set].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>this.set : Symbol(S.set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 12)) +>this : Symbol(S, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 0)) +>set : Symbol(S.set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 12)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 8, 44)) +>item : Symbol(item, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 8, 44)) + } +} + +function sArray(set: Set) { +>sArray : Symbol(sArray, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 10, 1)) +>T : Symbol(T, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 12, 16)) +>set : Symbol(set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 12, 19)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>T : Symbol(T, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 12, 16)) + + return new S(new Set([...set].map((item) => [item]))); +>S : Symbol(S, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 0, 0)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>[...set].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>set : Symbol(set, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 12, 19)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 13, 37)) +>item : Symbol(item, Decl(inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts, 13, 37)) +} + diff --git a/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.types b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.types new file mode 100644 index 0000000000000..e2d259b1e4510 --- /dev/null +++ b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.types @@ -0,0 +1,109 @@ +//// [tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts] //// + +=== Performance Stats === +Type Count: 1,000 +Instantiation count: 2,500 + +=== inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts === +class S { +>S : S +> : ^^^^ + + set: Set; +>set : Set +> : ^^^^^^ + + constructor(set: Set) { +>set : Set +> : ^^^^^^ + + this.set = set; +>this.set = set : Set +> : ^^^^^^ +>this.set : Set +> : ^^^^^^ +>this : this +> : ^^^^ +>set : Set +> : ^^^^^^ +>set : Set +> : ^^^^^^ + } + + array() { +>array : () => S +> : ^^^^^^^^^^^^ + + return new S(new Set([...this.set].map((item) => [item]))); +>new S(new Set([...this.set].map((item) => [item]))) : S +> : ^^^^^^ +>S : typeof S +> : ^^^^^^^^ +>new Set([...this.set].map((item) => [item])) : Set +> : ^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[...this.set].map((item) => [item]) : T[][] +> : ^^^^^ +>[...this.set].map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>[...this.set] : T[] +> : ^^^ +>...this.set : T +> : ^ +>this.set : Set +> : ^^^^^^ +>this : this +> : ^^^^ +>set : Set +> : ^^^^^^ +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>(item) => [item] : (item: T) => T[] +> : ^ ^^^^^^^^^^^ +>item : T +> : ^ +>[item] : T[] +> : ^^^ +>item : T +> : ^ + } +} + +function sArray(set: Set) { +>sArray : (set: Set) => S +> : ^ ^^ ^^ ^^^^^^^^^^^ +>set : Set +> : ^^^^^^ + + return new S(new Set([...set].map((item) => [item]))); +>new S(new Set([...set].map((item) => [item]))) : S +> : ^^^^^^ +>S : typeof S +> : ^^^^^^^^ +>new Set([...set].map((item) => [item])) : Set +> : ^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[...set].map((item) => [item]) : T[][] +> : ^^^^^ +>[...set].map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>[...set] : T[] +> : ^^^ +>...set : T +> : ^ +>set : Set +> : ^^^^^^ +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>(item) => [item] : (item: T) => T[] +> : ^ ^^^^^^^^^^^ +>item : T +> : ^ +>[item] : T[] +> : ^^^ +>item : T +> : ^ +} + diff --git a/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.symbols b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.symbols new file mode 100644 index 0000000000000..09db3cd52d7f6 --- /dev/null +++ b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.symbols @@ -0,0 +1,65 @@ +//// [tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.ts] //// + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/60988 + +/** + * @template [T = any] + */ +class S { +>S : Symbol(S, Decl(index.js, 0, 0)) + + /** + * @type {Set} + */ + set; +>set : Symbol(S.set, Decl(index.js, 5, 9)) + + /** + * @param {Set} set + */ + constructor(set) { +>set : Symbol(set, Decl(index.js, 15, 13)) + + this.set = set; +>this.set : Symbol(S.set, Decl(index.js, 5, 9)) +>this : Symbol(S, Decl(index.js, 0, 0)) +>set : Symbol(S.set, Decl(index.js, 5, 9)) +>set : Symbol(set, Decl(index.js, 15, 13)) + } + + array() { +>array : Symbol(S.array, Decl(index.js, 17, 2)) + + return new S(new Set([...this.set].map(item => [item]))); +>S : Symbol(S, Decl(index.js, 0, 0)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>[...this.set].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>this.set : Symbol(S.set, Decl(index.js, 5, 9)) +>this : Symbol(S, Decl(index.js, 0, 0)) +>set : Symbol(S.set, Decl(index.js, 5, 9)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(index.js, 20, 41)) +>item : Symbol(item, Decl(index.js, 20, 41)) + } +} + +/** + * @template [T = any] + * @param {Set} set + */ +const sArray = (set) => { +>sArray : Symbol(sArray, Decl(index.js, 28, 5)) +>set : Symbol(set, Decl(index.js, 28, 16)) + + return new S(new Set([...set].map(item => [item]))); +>S : Symbol(S, Decl(index.js, 0, 0)) +>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.collection.d.ts, --, --)) +>[...set].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>set : Symbol(set, Decl(index.js, 28, 16)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(index.js, 29, 35)) +>item : Symbol(item, Decl(index.js, 29, 35)) + +}; + diff --git a/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.types b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.types new file mode 100644 index 0000000000000..e3f30480a102f --- /dev/null +++ b/tests/baselines/reference/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.types @@ -0,0 +1,127 @@ +//// [tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.ts] //// + +=== Performance Stats === +Type Count: 1,000 +Instantiation count: 2,500 + +=== index.js === +// https://github.com/microsoft/TypeScript/issues/60988 + +/** + * @template [T = any] + */ +class S { +>S : S +> : ^^^^ + + /** + * @type {Set} + */ + set; +>set : Set +> : ^^^^^^ + + /** + * @param {Set} set + */ + constructor(set) { +>set : Set +> : ^^^^^^ + + this.set = set; +>this.set = set : Set +> : ^^^^^^ +>this.set : Set +> : ^^^^^^ +>this : this +> : ^^^^ +>set : Set +> : ^^^^^^ +>set : Set +> : ^^^^^^ + } + + array() { +>array : () => S +> : ^^^^^^^^^^^^ + + return new S(new Set([...this.set].map(item => [item]))); +>new S(new Set([...this.set].map(item => [item]))) : S +> : ^^^^^^ +>S : typeof S +> : ^^^^^^^^ +>new Set([...this.set].map(item => [item])) : Set +> : ^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[...this.set].map(item => [item]) : T[][] +> : ^^^^^ +>[...this.set].map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>[...this.set] : T[] +> : ^^^ +>...this.set : T +> : ^ +>this.set : Set +> : ^^^^^^ +>this : this +> : ^^^^ +>set : Set +> : ^^^^^^ +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>item => [item] : (item: T) => T[] +> : ^ ^^^^^^^^^^^ +>item : T +> : ^ +>[item] : T[] +> : ^^^ +>item : T +> : ^ + } +} + +/** + * @template [T = any] + * @param {Set} set + */ +const sArray = (set) => { +>sArray : (set: Set) => S +> : ^ ^^^^^^^^ ^^ ^^^^^^^^^^^ +>(set) => { return new S(new Set([...set].map(item => [item])));} : (set: Set) => S +> : ^ ^^^^^^^^ ^^ ^^^^^^^^^^^ +>set : Set +> : ^^^^^^ + + return new S(new Set([...set].map(item => [item]))); +>new S(new Set([...set].map(item => [item]))) : S +> : ^^^^^^ +>S : typeof S +> : ^^^^^^^^ +>new Set([...set].map(item => [item])) : Set +> : ^^^^^^^^ +>Set : SetConstructor +> : ^^^^^^^^^^^^^^ +>[...set].map(item => [item]) : T[][] +> : ^^^^^ +>[...set].map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>[...set] : T[] +> : ^^^ +>...set : T +> : ^ +>set : Set +> : ^^^^^^ +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +> : ^ ^^ ^^^ ^^^^^ ^^ ^^ ^^^^^^^^^^^^^ ^^^ ^^^^^^^^ +>item => [item] : (item: T) => T[] +> : ^ ^^^^^^^^^^^ +>item : T +> : ^ +>[item] : T[] +> : ^^^ +>item : T +> : ^ + +}; + diff --git a/tests/baselines/reference/selfCallGenericJsDoc1.errors.txt b/tests/baselines/reference/selfCallGenericJsDoc1.errors.txt new file mode 100644 index 0000000000000..40fbd67c146d2 --- /dev/null +++ b/tests/baselines/reference/selfCallGenericJsDoc1.errors.txt @@ -0,0 +1,24 @@ +index.js(13,42): error TS2345: Argument of type 'Children' is not assignable to parameter of type 'any[]'. + Type '{ children: Children[] | undefined; }' is missing the following properties from type 'any[]': length, pop, push, concat, and 16 more. + + +==== index.js (1 errors) ==== + /** + * @template T + * @typedef {T & { children: Children[] | undefined }} Children + */ + + /** + * @template T + * @param {Children[]} groups item and groups + */ + export const spaceLimited = (groups) => { + for (let i = 0; i < groups.length; i++) { + const group = groups[i]; + spaceLimited(/** @type {Children} */(group.children)); // should error + ~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type 'Children' is not assignable to parameter of type 'any[]'. +!!! error TS2345: Type '{ children: Children[] | undefined; }' is missing the following properties from type 'any[]': length, pop, push, concat, and 16 more. + } + }; + \ No newline at end of file diff --git a/tests/baselines/reference/selfCallGenericJsDoc1.symbols b/tests/baselines/reference/selfCallGenericJsDoc1.symbols new file mode 100644 index 0000000000000..94c6ef09ec13f --- /dev/null +++ b/tests/baselines/reference/selfCallGenericJsDoc1.symbols @@ -0,0 +1,37 @@ +//// [tests/cases/compiler/selfCallGenericJsDoc1.ts] //// + +=== index.js === +/** + * @template T + * @typedef {T & { children: Children[] | undefined }} Children + */ + +/** + * @template T + * @param {Children[]} groups item and groups + */ +export const spaceLimited = (groups) => { +>spaceLimited : Symbol(spaceLimited, Decl(index.js, 9, 12)) +>groups : Symbol(groups, Decl(index.js, 9, 29)) + + for (let i = 0; i < groups.length; i++) { +>i : Symbol(i, Decl(index.js, 10, 9)) +>i : Symbol(i, Decl(index.js, 10, 9)) +>groups.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>groups : Symbol(groups, Decl(index.js, 9, 29)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>i : Symbol(i, Decl(index.js, 10, 9)) + + const group = groups[i]; +>group : Symbol(group, Decl(index.js, 11, 7)) +>groups : Symbol(groups, Decl(index.js, 9, 29)) +>i : Symbol(i, Decl(index.js, 10, 9)) + + spaceLimited(/** @type {Children} */(group.children)); // should error +>spaceLimited : Symbol(spaceLimited, Decl(index.js, 9, 12)) +>group.children : Symbol(children, Decl(index.js, 2, 18)) +>group : Symbol(group, Decl(index.js, 11, 7)) +>children : Symbol(children, Decl(index.js, 2, 18)) + } +}; + diff --git a/tests/baselines/reference/selfCallGenericJsDoc1.types b/tests/baselines/reference/selfCallGenericJsDoc1.types new file mode 100644 index 0000000000000..0632b48bab3e6 --- /dev/null +++ b/tests/baselines/reference/selfCallGenericJsDoc1.types @@ -0,0 +1,66 @@ +//// [tests/cases/compiler/selfCallGenericJsDoc1.ts] //// + +=== index.js === +/** + * @template T + * @typedef {T & { children: Children[] | undefined }} Children + */ + +/** + * @template T + * @param {Children[]} groups item and groups + */ +export const spaceLimited = (groups) => { +>spaceLimited : (groups: Children[]) => void +> : ^ ^^ ^^ ^^^^^^^^^ +>(groups) => { for (let i = 0; i < groups.length; i++) { const group = groups[i]; spaceLimited(/** @type {Children} */(group.children)); // should error }} : (groups: Children[]) => void +> : ^ ^^ ^^ ^^^^^^^^^ +>groups : Children[] +> : ^^^^^^^^^^^^^ + + for (let i = 0; i < groups.length; i++) { +>i : number +> : ^^^^^^ +>0 : 0 +> : ^ +>i < groups.length : boolean +> : ^^^^^^^ +>i : number +> : ^^^^^^ +>groups.length : number +> : ^^^^^^ +>groups : Children[] +> : ^^^^^^^^^^^^^ +>length : number +> : ^^^^^^ +>i++ : number +> : ^^^^^^ +>i : number +> : ^^^^^^ + + const group = groups[i]; +>group : Children +> : ^^^^^^^^^^^ +>groups[i] : Children +> : ^^^^^^^^^^^ +>groups : Children[] +> : ^^^^^^^^^^^^^ +>i : number +> : ^^^^^^ + + spaceLimited(/** @type {Children} */(group.children)); // should error +>spaceLimited(/** @type {Children} */(group.children)) : void +> : ^^^^ +>spaceLimited : (groups: Children[]) => void +> : ^ ^^ ^^ ^^^^^^^^^ +>(group.children) : Children +> : ^^^^^^^^^^^ +>group.children : Children[] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>group : Children +> : ^^^^^^^^^^^ +>children : Children[] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + } +}; + diff --git a/tests/cases/compiler/inferFromReturnOfContextSensitiveFnJsDoc1.ts b/tests/cases/compiler/inferFromReturnOfContextSensitiveFnJsDoc1.ts new file mode 100644 index 0000000000000..b82b4807c1eec --- /dev/null +++ b/tests/cases/compiler/inferFromReturnOfContextSensitiveFnJsDoc1.ts @@ -0,0 +1,42 @@ +// @strict: true +// @noEmit: true +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +/** + * @template S + * @param {(arg0: { observer: EO }) => S} callback + * @param {Options} [options] + * @returns {VC} + */ +/* + * @type { (fn: (arg0: { observer: EO; }) => S, options?: Options) => VC } + */ +function define(callback, options) { + const { name } = options ?? {}; + const observer = new EO(); + const state = callback({ observer }); + return new VC(state); +} + +/** + * @template S + */ +class VC { + /** @type {S} */ + state; + /** + * @param {S} state + */ + constructor(state) { + this.state = state; + } +} + +/** @typedef {{ name?: string }} Options */ + +class EO {} + +const v1 = define((arg0) => true, { name: "default" }); \ No newline at end of file diff --git a/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts b/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts new file mode 100644 index 0000000000000..9af21e29bb47b --- /dev/null +++ b/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResult2.ts @@ -0,0 +1,20 @@ +// @strict: true +// @noEmit: true +// @target: esnext +// @lib: esnext + +class S { + set: Set; + + constructor(set: Set) { + this.set = set; + } + + array() { + return new S(new Set([...this.set].map((item) => [item]))); + } +} + +function sArray(set: Set) { + return new S(new Set([...set].map((item) => [item]))); +} diff --git a/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.ts b/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.ts new file mode 100644 index 0000000000000..04d5a8260ef68 --- /dev/null +++ b/tests/cases/compiler/inferenceOuterResultNotIncorrectlyInstantiatedWithInnerResultJsDoc1.ts @@ -0,0 +1,40 @@ +// @strict: true +// @noEmit: true +// @target: esnext +// @lib: esnext +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +// https://github.com/microsoft/TypeScript/issues/60988 + +/** + * @template [T = any] + */ +class S { + + /** + * @type {Set} + */ + set; + + /** + * @param {Set} set + */ + constructor(set) { + this.set = set; + } + + array() { + return new S(new Set([...this.set].map(item => [item]))); + } +} + +/** + * @template [T = any] + * @param {Set} set + */ +const sArray = (set) => { + return new S(new Set([...set].map(item => [item]))); +}; diff --git a/tests/cases/compiler/selfCallGenericJsDoc1.ts b/tests/cases/compiler/selfCallGenericJsDoc1.ts new file mode 100644 index 0000000000000..ab39019b20aaf --- /dev/null +++ b/tests/cases/compiler/selfCallGenericJsDoc1.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noEmit: true +// @checkJs: true +// @allowJs: true + +// @filename: index.js + +/** + * @template T + * @typedef {T & { children: Children[] | undefined }} Children + */ + +/** + * @template T + * @param {Children[]} groups item and groups + */ +export const spaceLimited = (groups) => { + for (let i = 0; i < groups.length; i++) { + const group = groups[i]; + spaceLimited(/** @type {Children} */(group.children)); // should error + } +};