From d4363163b624b4913cde78243c2bd95ddef6e1c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 3 Aug 2023 11:18:29 +0200 Subject: [PATCH 1/5] Transfer all declared symbols onto the type from the interface that extends another --- src/compiler/checker.ts | 2 +- ...DeclaredUsingIndexSignatureOnInterfaceWithBase.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/quickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 97c272990aca6..f9822bc6afe87 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12583,7 +12583,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypes = getBaseTypes(source); if (baseTypes.length) { if (source.symbol && members === getMembersOfSymbol(source.symbol)) { - members = createSymbolTable(source.declaredProperties); + members = createSymbolTable(arrayFrom(members.values())); } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); diff --git a/tests/cases/fourslash/quickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase.ts b/tests/cases/fourslash/quickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase.ts new file mode 100644 index 0000000000000..e55088eb64dd2 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase.ts @@ -0,0 +1,12 @@ +/// + +// https://github.com/microsoft/TypeScript/issues/55251 + +//// interface P {} +//// interface B extends P { +//// [k: string]: number; +//// } +//// declare const b: B; +//// b.t/*1*/est = 10; + +verify.quickInfoAt("1", "(index) B[string]: number"); From aa36cbc60dafa7f9de7e29ebdffea8d964511166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 3 Aug 2023 20:04:12 +0200 Subject: [PATCH 2/5] Make `createSymbolTable` accept `Iterable` --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9822bc6afe87..e8ecb5e887cc8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12583,7 +12583,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypes = getBaseTypes(source); if (baseTypes.length) { if (source.symbol && members === getMembersOfSymbol(source.symbol)) { - members = createSymbolTable(arrayFrom(members.values())); + members = createSymbolTable(members.values()); } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 436fb32872c6e..44227e2228419 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -594,7 +594,7 @@ export function getDeclarationsOfKind(symbol: Symbol, kin } /** @internal */ -export function createSymbolTable(symbols?: readonly Symbol[]): SymbolTable { +export function createSymbolTable(symbols?: Iterable): SymbolTable { const result = new Map<__String, Symbol>(); if (symbols) { for (const symbol of symbols) { From 8f6da4b7b6e6e728844c4965eb597e1f1a5611ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 19 Aug 2023 10:04:52 +0200 Subject: [PATCH 3/5] dont transfer type parameter symbols --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 10 ++- ...mberCalledTheSameAsItsOwnTypeParam.symbols | 75 +++++++++++++++++++ ...MemberCalledTheSameAsItsOwnTypeParam.types | 45 +++++++++++ ...ithMemberCalledTheSameAsItsOwnTypeParam.ts | 25 +++++++ 5 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.symbols create mode 100644 tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.types create mode 100644 tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf18e9e61d455..af507b89e9fb5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12829,7 +12829,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypes = getBaseTypes(source); if (baseTypes.length) { if (source.symbol && members === getMembersOfSymbol(source.symbol)) { - members = createSymbolTable(members.values()); + members = createSymbolTable(members.values(), SymbolFlags.TypeParameter); } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a3d050c634b6d..e5e6f6ed0cb3c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -594,11 +594,17 @@ export function getDeclarationsOfKind(symbol: Symbol, kin } /** @internal */ -export function createSymbolTable(symbols?: Iterable): SymbolTable { +export function createSymbolTable(symbols: Iterable, excludes?: SymbolFlags): SymbolTable; +/** @internal */ +export function createSymbolTable(symbols?: Iterable): SymbolTable; +/** @internal */ +export function createSymbolTable(symbols?: Iterable, excludes: SymbolFlags = 0): SymbolTable { const result = new Map<__String, Symbol>(); if (symbols) { for (const symbol of symbols) { - result.set(symbol.escapedName, symbol); + if (!(symbol.flags & excludes)) { + result.set(symbol.escapedName, symbol); + } } } return result; diff --git a/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.symbols b/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.symbols new file mode 100644 index 0000000000000..dca9748d6539b --- /dev/null +++ b/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.symbols @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts] //// + +=== classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts === +interface IObserver { +>IObserver : Symbol(IObserver, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 0, 0)) + + handleChange(observable: IObservable, change: TChange): void; +>handleChange : Symbol(IObserver.handleChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 0, 21)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 14)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 16)) +>observable : Symbol(observable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 26)) +>IObservable : Symbol(IObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 2, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 14)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 16)) +>change : Symbol(change, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 62)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 1, 16)) +} + +interface IObservable { +>IObservable : Symbol(IObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 2, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 22)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 24), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 5, 10)) + + get(): T; +>get : Symbol(IObservable.get, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 45)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 22)) + + readonly TChange: TChange; +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 24), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 5, 10)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 4, 24), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 5, 10)) +} + +export interface IReader { +>IReader : Symbol(IReader, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 7, 1)) + + readObservable(observable: IObservable): T; +>readObservable : Symbol(IReader.readObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 9, 26)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 10, 16)) +>observable : Symbol(observable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 10, 19)) +>IObservable : Symbol(IObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 2, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 10, 16)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 10, 16)) +} + +export abstract class ConvenientObservable implements IObservable { +>ConvenientObservable : Symbol(ConvenientObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 11, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 43)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 45), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 91)) +>IObservable : Symbol(IObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 2, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 43)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 45), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 91)) + + get TChange(): TChange { return null!; } +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 45), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 91)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 45), Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 91)) + + public abstract get(): T; +>get : Symbol(ConvenientObservable.get, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 14, 41)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 13, 43)) +} + +export abstract class BaseObservable extends ConvenientObservable { +>BaseObservable : Symbol(BaseObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 16, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 18, 37)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 18, 39)) +>ConvenientObservable : Symbol(ConvenientObservable, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 11, 1)) +>T : Symbol(T, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 18, 37)) +>TChange : Symbol(TChange, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 18, 39)) + + protected readonly observers = new Set(); +>observers : Symbol(BaseObservable.observers, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 18, 98)) +>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, --, --)) +>IObserver : Symbol(IObserver, Decl(classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts, 0, 0)) +} + diff --git a/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.types b/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.types new file mode 100644 index 0000000000000..706dc2d2a501f --- /dev/null +++ b/tests/baselines/reference/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.types @@ -0,0 +1,45 @@ +//// [tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts] //// + +=== classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts === +interface IObserver { + handleChange(observable: IObservable, change: TChange): void; +>handleChange : (observable: IObservable, change: TChange) => void +>observable : IObservable +>change : TChange +} + +interface IObservable { + get(): T; +>get : () => T + + readonly TChange: TChange; +>TChange : TChange +} + +export interface IReader { + readObservable(observable: IObservable): T; +>readObservable : (observable: IObservable) => T +>observable : IObservable +} + +export abstract class ConvenientObservable implements IObservable { +>ConvenientObservable : ConvenientObservable + + get TChange(): TChange { return null!; } +>TChange : TChange +>null! : never + + public abstract get(): T; +>get : () => T +} + +export abstract class BaseObservable extends ConvenientObservable { +>BaseObservable : BaseObservable +>ConvenientObservable : ConvenientObservable + + protected readonly observers = new Set(); +>observers : Set +>new Set() : Set +>Set : SetConstructor +} + diff --git a/tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts b/tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts new file mode 100644 index 0000000000000..a5ab28856660f --- /dev/null +++ b/tests/cases/compiler/classExtendingAbstractClassWithMemberCalledTheSameAsItsOwnTypeParam.ts @@ -0,0 +1,25 @@ +// @strict: true +// @lib: esnext +// @noEmit: true + +interface IObserver { + handleChange(observable: IObservable, change: TChange): void; +} + +interface IObservable { + get(): T; + readonly TChange: TChange; +} + +export interface IReader { + readObservable(observable: IObservable): T; +} + +export abstract class ConvenientObservable implements IObservable { + get TChange(): TChange { return null!; } + public abstract get(): T; +} + +export abstract class BaseObservable extends ConvenientObservable { + protected readonly observers = new Set(); +} From 31d14c0003cadf5ed88665d63ed0cedaac743269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 21 Aug 2023 23:13:39 +0200 Subject: [PATCH 4/5] revert `createSymbolTable` change --- src/compiler/checker.ts | 8 +++++++- src/compiler/utilities.ts | 10 ++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6c7408d185496..e5e451d6529d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12829,7 +12829,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypes = getBaseTypes(source); if (baseTypes.length) { if (source.symbol && members === getMembersOfSymbol(source.symbol)) { - members = createSymbolTable(members.values(), SymbolFlags.TypeParameter); + const symbolTable = createSymbolTable(); + // copy all symbols (except type parameters), including the ones with internal names like `InternalSymbolName.Index` + for (const symbol of members.values()) { + if (!(symbol.flags & SymbolFlags.TypeParameter)) { + symbolTable.set(symbol.escapedName, symbol); + } + } } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e5e6f6ed0cb3c..2edd5b0243bc8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -594,17 +594,11 @@ export function getDeclarationsOfKind(symbol: Symbol, kin } /** @internal */ -export function createSymbolTable(symbols: Iterable, excludes?: SymbolFlags): SymbolTable; -/** @internal */ -export function createSymbolTable(symbols?: Iterable): SymbolTable; -/** @internal */ -export function createSymbolTable(symbols?: Iterable, excludes: SymbolFlags = 0): SymbolTable { +export function createSymbolTable(symbols?: readonly Symbol[]): SymbolTable { const result = new Map<__String, Symbol>(); if (symbols) { for (const symbol of symbols) { - if (!(symbol.flags & excludes)) { - result.set(symbol.escapedName, symbol); - } + result.set(symbol.escapedName, symbol); } } return result; From 26cd2f493783a2008f7642270d2b8dba1c84e075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 21 Aug 2023 23:54:46 +0200 Subject: [PATCH 5/5] Actually set members to the created symbol table --- src/compiler/checker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e5e451d6529d8..22f71ef3f209f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12836,6 +12836,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbolTable.set(symbol.escapedName, symbol); } } + members = symbolTable; } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments);