From 2670d969fb1f8a0131f2f0b89dee6ded9a284a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 30 Apr 2024 23:23:31 +0200 Subject: [PATCH 1/2] Fixed a ghost error popping up after completions request caching a wrong contextual function type --- src/compiler/checker.ts | 56 +++++++++++-------- ...letionsRequestWithinGenericFunction4.ts.ts | 32 +++++++++++ 2 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 tests/cases/fourslash/noErrorsAfterCompletionsRequestWithinGenericFunction4.ts.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba85f4ab655fc..1c1b18ba6537d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1923,32 +1923,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function runWithoutResolvedSignatureCaching(node: Node | undefined, fn: () => T): T { + const cachedResolvedSignatures = []; + const cachedTypes: (readonly [SymbolLinks, Type | undefined])[] = []; node = findAncestor(node, isCallLikeOrFunctionLikeExpression); - if (node) { - const cachedResolvedSignatures = []; - const cachedTypes = []; - while (node) { - const nodeLinks = getNodeLinks(node); - cachedResolvedSignatures.push([nodeLinks, nodeLinks.resolvedSignature] as const); - nodeLinks.resolvedSignature = undefined; - if (isFunctionExpressionOrArrowFunction(node)) { - const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(node)); - const type = symbolLinks.type; - cachedTypes.push([symbolLinks, type] as const); - symbolLinks.type = undefined; - } - node = findAncestor(node.parent, isCallLikeOrFunctionLikeExpression); - } - const result = fn(); - for (const [nodeLinks, resolvedSignature] of cachedResolvedSignatures) { - nodeLinks.resolvedSignature = resolvedSignature; - } - for (const [symbolLinks, type] of cachedTypes) { - symbolLinks.type = type; + if (!node) { + return fn(); + } + while (node) { + const nodeLinks = getNodeLinks(node); + cachedResolvedSignatures.push([nodeLinks, nodeLinks.resolvedSignature, nodeLinks.flags] as const); + nodeLinks.resolvedSignature = undefined; + nodeLinks.flags = NodeCheckFlags.None; + if (isFunctionExpressionOrArrowFunction(node)) { + resetCachedSymbolTypes(node); + for (const parameter of node.parameters) { + resetCachedSymbolTypes(parameter); + } } - return result; + node = findAncestor(node.parent, isCallLikeOrFunctionLikeExpression); + } + const result = fn(); + for (const [nodeLinks, resolvedSignature, nodeCheckFlags] of cachedResolvedSignatures) { + nodeLinks.resolvedSignature = resolvedSignature; + nodeLinks.flags = nodeCheckFlags; + } + for (const [symbolLinks, type] of cachedTypes) { + symbolLinks.type = type; + } + return result; + + function resetCachedSymbolTypes(declaration: Declaration) { + const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(declaration)); + const type = symbolLinks.type; + + cachedTypes.push([symbolLinks, type] as const); + symbolLinks.type = undefined; } - return fn(); } function runWithInferenceBlockedFromSourceNode(node: Node | undefined, fn: () => T): T { diff --git a/tests/cases/fourslash/noErrorsAfterCompletionsRequestWithinGenericFunction4.ts.ts b/tests/cases/fourslash/noErrorsAfterCompletionsRequestWithinGenericFunction4.ts.ts new file mode 100644 index 0000000000000..6568bb6fe4d3b --- /dev/null +++ b/tests/cases/fourslash/noErrorsAfterCompletionsRequestWithinGenericFunction4.ts.ts @@ -0,0 +1,32 @@ +/// + +// @strict: true +// @target: esnext +// @lib: esnext + +//// type ObjectFromEntries = T extends readonly [ +//// infer Key extends string | number | symbol, +//// infer Value, +//// ][] +//// ? { [key in Key]: Value } +//// : never; +//// +//// type KeyValuePairs = { +//// [K in keyof T]: [K, T[K]]; +//// }[keyof T]; +//// +//// declare function mapObjectEntries< +//// const T extends object, +//// const TMapped extends [string | number | symbol, unknown], +//// >( +//// obj: T, +//// mapper: ([a, b]: KeyValuePairs) => TMapped, +//// ): ObjectFromEntries; +//// +//// mapObjectEntries({ a: 1, b: 2 }, ([x, y]) => ["a/*1*/", y]); + +verify.completions({ + marker: "1", + exact: ["a"], +}); +verify.getSemanticDiagnostics([]); From b91b8eae055acb0781e9e4ac7260235084689943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 30 Apr 2024 23:34:41 +0200 Subject: [PATCH 2/2] fmt --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c1b18ba6537d..9a076d1f08e08 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1955,7 +1955,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resetCachedSymbolTypes(declaration: Declaration) { const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(declaration)); const type = symbolLinks.type; - + cachedTypes.push([symbolLinks, type] as const); symbolLinks.type = undefined; }