From 1f1dcd60b5cb03094e4b27495140e022913e1010 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 5 Apr 2021 11:10:47 -0700 Subject: [PATCH] When reusing input type nodes, only instantiate the type for comparison if it is a this type (#42584) --- src/compiler/checker.ts | 12 ++- ...clarationEmitOverloadedPrivateInference.js | 56 ++++++++++++++ ...tionEmitOverloadedPrivateInference.symbols | 73 +++++++++++++++++++ ...rationEmitOverloadedPrivateInference.types | 68 +++++++++++++++++ ...InternalTypesProduceUniqueTypeParams.types | 4 +- .../reference/jsDeclarationsInterfaces.js | 4 +- ...clarationEmitOverloadedPrivateInference.ts | 22 ++++++ 7 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitOverloadedPrivateInference.js create mode 100644 tests/baselines/reference/declarationEmitOverloadedPrivateInference.symbols create mode 100644 tests/baselines/reference/declarationEmitOverloadedPrivateInference.types create mode 100644 tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 02195f2cb73..dab7364b72b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6005,10 +6005,14 @@ namespace ts { function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { if (type !== errorType && context.enclosingDeclaration) { const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); - if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type)) { - const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled); - if (result) { - return result; + if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation) { + const annotated = getTypeFromTypeNode(annotation); + const thisInstantiated = annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType ? instantiateType(annotated, signature.mapper) : annotated; + if (thisInstantiated === type && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type)) { + const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled); + if (result) { + return result; + } } } } diff --git a/tests/baselines/reference/declarationEmitOverloadedPrivateInference.js b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.js new file mode 100644 index 00000000000..d45313e3a22 --- /dev/null +++ b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.js @@ -0,0 +1,56 @@ +//// [declarationEmitOverloadedPrivateInference.ts] +function noArgs(): string { + return null as any; +} + +function oneArg(input: string): string { + return null as any; +} + +export class Wrapper { + private proxy(fn: (options: T) => U): (options: T) => U; + private proxy(fn: (options?: T) => U, noArgs: true): (options?: T) => U; + + private proxy(fn: (options: T) => U) { + return null as any; + } + + public Proxies = { + Failure: this.proxy(noArgs, true), + Success: this.proxy(oneArg), + }; +} + +//// [declarationEmitOverloadedPrivateInference.js] +"use strict"; +exports.__esModule = true; +exports.Wrapper = void 0; +function noArgs() { + return null; +} +function oneArg(input) { + return null; +} +var Wrapper = /** @class */ (function () { + function Wrapper() { + this.Proxies = { + Failure: this.proxy(noArgs, true), + Success: this.proxy(oneArg) + }; + } + Wrapper.prototype.proxy = function (fn) { + return null; + }; + return Wrapper; +}()); +exports.Wrapper = Wrapper; + + +//// [declarationEmitOverloadedPrivateInference.d.ts] +export declare class Wrapper { + private proxy; + Proxies: { + Failure: (options?: unknown) => string; + Success: (options: string) => string; + }; +} diff --git a/tests/baselines/reference/declarationEmitOverloadedPrivateInference.symbols b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.symbols new file mode 100644 index 00000000000..4b7babe4e92 --- /dev/null +++ b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.symbols @@ -0,0 +1,73 @@ +=== tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts === +function noArgs(): string { +>noArgs : Symbol(noArgs, Decl(declarationEmitOverloadedPrivateInference.ts, 0, 0)) + + return null as any; +} + +function oneArg(input: string): string { +>oneArg : Symbol(oneArg, Decl(declarationEmitOverloadedPrivateInference.ts, 2, 1)) +>input : Symbol(input, Decl(declarationEmitOverloadedPrivateInference.ts, 4, 16)) + + return null as any; +} + +export class Wrapper { +>Wrapper : Symbol(Wrapper, Decl(declarationEmitOverloadedPrivateInference.ts, 6, 1)) + + private proxy(fn: (options: T) => U): (options: T) => U; +>proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 20)) +>fn : Symbol(fn, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 24)) +>options : Symbol(options, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 29)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 20)) +>options : Symbol(options, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 49)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 9, 20)) + + private proxy(fn: (options?: T) => U, noArgs: true): (options?: T) => U; +>proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 20)) +>fn : Symbol(fn, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 24)) +>options : Symbol(options, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 29)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 20)) +>noArgs : Symbol(noArgs, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 47)) +>options : Symbol(options, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 64)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 10, 20)) + + private proxy(fn: (options: T) => U) { +>proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 20)) +>fn : Symbol(fn, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 24)) +>options : Symbol(options, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 29)) +>T : Symbol(T, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 18)) +>U : Symbol(U, Decl(declarationEmitOverloadedPrivateInference.ts, 12, 20)) + + return null as any; + } + + public Proxies = { +>Proxies : Symbol(Wrapper.Proxies, Decl(declarationEmitOverloadedPrivateInference.ts, 14, 5)) + + Failure: this.proxy(noArgs, true), +>Failure : Symbol(Failure, Decl(declarationEmitOverloadedPrivateInference.ts, 16, 22)) +>this.proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>this : Symbol(Wrapper, Decl(declarationEmitOverloadedPrivateInference.ts, 6, 1)) +>proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>noArgs : Symbol(noArgs, Decl(declarationEmitOverloadedPrivateInference.ts, 0, 0)) + + Success: this.proxy(oneArg), +>Success : Symbol(Success, Decl(declarationEmitOverloadedPrivateInference.ts, 17, 42)) +>this.proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>this : Symbol(Wrapper, Decl(declarationEmitOverloadedPrivateInference.ts, 6, 1)) +>proxy : Symbol(Wrapper.proxy, Decl(declarationEmitOverloadedPrivateInference.ts, 8, 22), Decl(declarationEmitOverloadedPrivateInference.ts, 9, 66), Decl(declarationEmitOverloadedPrivateInference.ts, 10, 82)) +>oneArg : Symbol(oneArg, Decl(declarationEmitOverloadedPrivateInference.ts, 2, 1)) + + }; +} diff --git a/tests/baselines/reference/declarationEmitOverloadedPrivateInference.types b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.types new file mode 100644 index 00000000000..f0e49197d6e --- /dev/null +++ b/tests/baselines/reference/declarationEmitOverloadedPrivateInference.types @@ -0,0 +1,68 @@ +=== tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts === +function noArgs(): string { +>noArgs : () => string + + return null as any; +>null as any : any +>null : null +} + +function oneArg(input: string): string { +>oneArg : (input: string) => string +>input : string + + return null as any; +>null as any : any +>null : null +} + +export class Wrapper { +>Wrapper : Wrapper + + private proxy(fn: (options: T) => U): (options: T) => U; +>proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>fn : (options: T) => U +>options : T +>options : T + + private proxy(fn: (options?: T) => U, noArgs: true): (options?: T) => U; +>proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>fn : (options?: T) => U +>options : T +>noArgs : true +>true : true +>options : T + + private proxy(fn: (options: T) => U) { +>proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>fn : (options: T) => U +>options : T + + return null as any; +>null as any : any +>null : null + } + + public Proxies = { +>Proxies : { Failure: (options?: unknown) => string; Success: (options: string) => string; } +>{ Failure: this.proxy(noArgs, true), Success: this.proxy(oneArg), } : { Failure: (options?: unknown) => string; Success: (options: string) => string; } + + Failure: this.proxy(noArgs, true), +>Failure : (options?: unknown) => string +>this.proxy(noArgs, true) : (options?: unknown) => string +>this.proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>this : this +>proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>noArgs : () => string +>true : true + + Success: this.proxy(oneArg), +>Success : (options: string) => string +>this.proxy(oneArg) : (options: string) => string +>this.proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>this : this +>proxy : { (fn: (options: T) => U): (options: T) => U; (fn: (options?: T) => U, noArgs: true): (options?: T) => U; } +>oneArg : (input: string) => string + + }; +} diff --git a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types index 7aff4276be7..b57ceb0b7a4 100644 --- a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types +++ b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types @@ -38,13 +38,13 @@ export const updateIfChanged = (t: T) => { >newU : U return Object.assign( ->Object.assign( >(key: K) => reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }), { map: (updater: (u: U) => U) => set(updater(u)), set }) : ((key: K) => (>(key: K) => (>>(key: K) => (>>>(key: K) => (>>>>(key: K) => (>>>>>(key: K) => (>>>>>>(key: K) => (>>>>>>>(key: K) => (>>>>>>>>(key: K) => (>>>>>>>>>(key: K) => (>>>>>>>>>>(key: K) => any & { map: (updater: (u: Value>>>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>) => U) => T; set: (newU: Value>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => U) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>) => U) => T; set: (newU: Value>>>>>) => T; }) & { map: (updater: (u: Value>>>>) => U) => T; set: (newU: Value>>>>) => T; }) & { map: (updater: (u: Value>>>) => U) => T; set: (newU: Value>>>) => T; }) & { map: (updater: (u: Value>>) => U) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value>) => U) => T; set: (newU: Value>) => T; }) & { map: (updater: (u: Value) => U) => T; set: (newU: Value) => T; }) & { map: (updater: (u: U) => U) => T; set: (newU: U) => T; } +>Object.assign( >(key: K) => reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }), { map: (updater: (u: U) => U) => set(updater(u)), set }) : ((key: K) => (>(key: K) => (>>(key: K) => (>>>(key: K) => (>>>>(key: K) => (>>>>>(key: K) => (>>>>>>(key: K) => (>>>>>>>(key: K) => (>>>>>>>>(key: K) => (>>>>>>>>>(key: K) => (>>>>>>>>>>(key: K) => any & { map: (updater: (u: Value>>>>>>>>>>) => Value>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>) => Value>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>) => Value>>>>>>>>) => T; set: (newU: Value>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>) => Value>>>>>>>) => T; set: (newU: Value>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => Value>>>>>>) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>) => Value>>>>>) => T; set: (newU: Value>>>>>) => T; }) & { map: (updater: (u: Value>>>>) => Value>>>>) => T; set: (newU: Value>>>>) => T; }) & { map: (updater: (u: Value>>>) => Value>>>) => T; set: (newU: Value>>>) => T; }) & { map: (updater: (u: Value>>) => Value>>) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value>) => Value>) => T; set: (newU: Value>) => T; }) & { map: (updater: (u: Value) => Value) => T; set: (newU: Value) => T; }) & { map: (updater: (u: U) => U) => T; set: (newU: U) => T; } >Object.assign : { (target: T, source: U): T & U; (target: T, source1: U, source2: V): T & U & V; (target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; } >Object : ObjectConstructor >assign : { (target: T, source: U): T & U; (target: T, source1: U, source2: V): T & U & V; (target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; } >(key: K) => ->>(key: K) => reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : (key: K) => (>(key: K) => (>>(key: K) => (>>>(key: K) => (>>>>(key: K) => (>>>>>(key: K) => (>>>>>>(key: K) => (>>>>>>>(key: K) => (>>>>>>>>(key: K) => (>>>>>>>>>(key: K) => (>>>>>>>>>>(key: K) => any & { map: (updater: (u: Value>>>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>) => U) => T; set: (newU: Value>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>) => U) => T; set: (newU: Value>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => U) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>) => U) => T; set: (newU: Value>>>>>) => T; }) & { map: (updater: (u: Value>>>>) => U) => T; set: (newU: Value>>>>) => T; }) & { map: (updater: (u: Value>>>) => U) => T; set: (newU: Value>>>) => T; }) & { map: (updater: (u: Value>>) => U) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value>) => U) => T; set: (newU: Value>) => T; }) & { map: (updater: (u: Value) => U) => T; set: (newU: Value) => T; } +>>(key: K) => reduce>(u[key as keyof U] as Value, (v: Value) => { return update(Object.assign(Array.isArray(u) ? [] : {}, u, { [key]: v })); }) : (key: K) => (>(key: K) => (>>(key: K) => (>>>(key: K) => (>>>>(key: K) => (>>>>>(key: K) => (>>>>>>(key: K) => (>>>>>>>(key: K) => (>>>>>>>>(key: K) => (>>>>>>>>>(key: K) => (>>>>>>>>>>(key: K) => any & { map: (updater: (u: Value>>>>>>>>>>) => Value>>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>>) => Value>>>>>>>>>) => T; set: (newU: Value>>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>>) => Value>>>>>>>>) => T; set: (newU: Value>>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>>) => Value>>>>>>>) => T; set: (newU: Value>>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>>) => Value>>>>>>) => T; set: (newU: Value>>>>>>) => T; }) & { map: (updater: (u: Value>>>>>) => Value>>>>>) => T; set: (newU: Value>>>>>) => T; }) & { map: (updater: (u: Value>>>>) => Value>>>>) => T; set: (newU: Value>>>>) => T; }) & { map: (updater: (u: Value>>>) => Value>>>) => T; set: (newU: Value>>>) => T; }) & { map: (updater: (u: Value>>) => Value>>) => T; set: (newU: Value>>) => T; }) & { map: (updater: (u: Value>) => Value>) => T; set: (newU: Value>) => T; }) & { map: (updater: (u: Value) => Value) => T; set: (newU: Value) => T; } >key : K reduce>(u[key as keyof U] as Value, (v: Value) => { diff --git a/tests/baselines/reference/jsDeclarationsInterfaces.js b/tests/baselines/reference/jsDeclarationsInterfaces.js index f7f68846d29..00e78c8286a 100644 --- a/tests/baselines/reference/jsDeclarationsInterfaces.js +++ b/tests/baselines/reference/jsDeclarationsInterfaces.js @@ -135,10 +135,10 @@ export interface B { export interface C { new (): string; new (x: T_1): U_1; - new (x: Q_6): T_1 & Q_6; + new (x: Q_4): T_1 & Q_4; (): number; (x: T_1): U_1; - (x: Q_4): T_1 & Q_4; + (x: Q_3): T_1 & Q_3; field: T_1 & U_1; optionalField?: T_1; readonly readonlyField: T_1 & U_1; diff --git a/tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts b/tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts new file mode 100644 index 00000000000..ea585eb906e --- /dev/null +++ b/tests/cases/compiler/declarationEmitOverloadedPrivateInference.ts @@ -0,0 +1,22 @@ +// @declaration: true +function noArgs(): string { + return null as any; +} + +function oneArg(input: string): string { + return null as any; +} + +export class Wrapper { + private proxy(fn: (options: T) => U): (options: T) => U; + private proxy(fn: (options?: T) => U, noArgs: true): (options?: T) => U; + + private proxy(fn: (options: T) => U) { + return null as any; + } + + public Proxies = { + Failure: this.proxy(noArgs, true), + Success: this.proxy(oneArg), + }; +} \ No newline at end of file