diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76e81a959790b..fa0d8426435b3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1967,32 +1967,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; + 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); } - 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; - } - 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([]);