From aae31158384bafe0d37480aa8e2068353436f62e Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Thu, 5 Jan 2023 18:12:56 -0300 Subject: [PATCH] Call `getTypeOfSymbol` in `getNarrowedTypeOfSymbol` to avoid running into circularities when computing types (#51914) --- src/compiler/checker.ts | 3 +- src/harness/fourslashImpl.ts | 11 +++++++ src/harness/fourslashInterfaceImpl.ts | 4 +++ .../fourslash/circularGetTypeAtLocation.ts | 30 +++++++++++++++++++ tests/cases/fourslash/fourslash.ts | 1 + 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/circularGetTypeAtLocation.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30eb32a7ac4..2ae210a8ba6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27083,6 +27083,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNarrowedTypeOfSymbol(symbol: Symbol, location: Identifier) { + const type = getTypeOfSymbol(symbol); const declaration = symbol.valueDeclaration; if (declaration) { // If we have a non-rest binding element with no initializer declared as a const variable or a const-like @@ -27163,7 +27164,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - return getTypeOfSymbol(symbol); + return type; } function checkIdentifier(node: Identifier, checkMode: CheckMode | undefined): Type { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 0f35cf2549a..e7379faaf11 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -1144,6 +1144,17 @@ export class TestState { } } + public verifyTypeAtLocation(range: Range, expected: string): void { + const node = this.goToAndGetNode(range); + const checker = this.getChecker(); + const type = checker.getTypeAtLocation(node); + + const actual = checker.typeToString(type); + if (actual !== expected) { + this.raiseError(displayExpectedAndActualString(expected, actual)); + } + } + public verifyBaselineFindAllReferences(...markerNames: string[]) { ts.Debug.assert(markerNames.length > 0, "Must pass at least one marker name to `verifyBaselineFindAllReferences()`"); this.verifyBaselineFindAllReferencesWorker("", markerNames); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index e403a4555ac..15d42ad6b96 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -354,6 +354,10 @@ export class Verify extends VerifyNegatable { this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected); } + public typeAtLocation(range: FourSlash.Range, expected: string) { + this.state.verifyTypeAtLocation(range, expected); + } + public baselineFindAllReferences(...markerNames: string[]) { this.state.verifyBaselineFindAllReferences(...markerNames); } diff --git a/tests/cases/fourslash/circularGetTypeAtLocation.ts b/tests/cases/fourslash/circularGetTypeAtLocation.ts new file mode 100644 index 00000000000..4e7779905c9 --- /dev/null +++ b/tests/cases/fourslash/circularGetTypeAtLocation.ts @@ -0,0 +1,30 @@ +/// + +// Issue #48313 + +// @strict: true +// @target: esnext +// @Filename: /file.tsx +//// export function working(baseVersion?: string): number[] { +//// const toRelease: number[] = []; +//// const baseRelease: number[] = []; +//// return baseRelease.map((_, index) => { +//// const toPart = toRelease[index] ?? 0; +//// [|toPart|]; // this is the "working" log +//// return 0; +//// }); +//// } +//// +//// export function broken(baseVersion?: string): number[] { +//// const toRelease: number[] = []; +//// const baseRelease: number[] = []; +//// return baseRelease.map((_, index) => { +//// const toPart = toRelease[index] ?? 0; +//// [|toPart|]; // this is the "broken" log +//// return toPart + (baseVersion === undefined ? 0 : 1); +//// }); +//// } + +const [r_ok, r_bad] = test.ranges(); +verify.typeAtLocation(r_ok, "number"); +verify.typeAtLocation(r_bad, "number"); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 262d2327d2f..7353ce9b4da 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -335,6 +335,7 @@ declare namespace FourSlashInterface { baselineGetFileReferences(fileName: string): void; symbolAtLocation(startRange: Range, ...declarationRanges: Range[]): void; typeOfSymbolAtLocation(range: Range, symbol: any, expected: string): void; + typeAtLocation(range: Range, expected: string): void; /** @deprecated Use baselineFindAllReferences instead */ singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[] | string): void; rangesAreOccurrences(isWriteAccess?: boolean, ranges?: Range[]): void;