Fixed an issue with errors not being correctly reported after completion requests in functions within nested calls (#54944)

This commit is contained in:
Mateusz Burzyński
2023-09-14 00:48:40 +02:00
committed by GitHub
parent 05fdb5f671
commit 21b8892d21
3 changed files with 189 additions and 4 deletions

View File

@@ -1836,20 +1836,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
};
function runWithoutResolvedSignatureCaching<T>(node: Node | undefined, fn: () => T): T {
const cachedSignatures = [];
const cachedResolvedSignatures = [];
const cachedTypes = [];
while (node) {
if (isCallLikeExpression(node)) {
if (isCallLikeExpression(node) || isFunctionLike(node)) {
const nodeLinks = getNodeLinks(node);
const resolvedSignature = nodeLinks.resolvedSignature;
cachedSignatures.push([nodeLinks, resolvedSignature] as const);
cachedResolvedSignatures.push([nodeLinks, resolvedSignature] as const);
nodeLinks.resolvedSignature = undefined;
}
if (isFunctionLike(node)) {
const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(node));
const type = symbolLinks.type;
cachedTypes.push([symbolLinks, type] as const);
symbolLinks.type = undefined;
}
node = node.parent;
}
const result = fn();
for (const [nodeLinks, resolvedSignature] of cachedSignatures) {
for (const [nodeLinks, resolvedSignature] of cachedResolvedSignatures) {
nodeLinks.resolvedSignature = resolvedSignature;
}
for (const [symbolLinks, type] of cachedTypes) {
symbolLinks.type = type;
}
return result;
}

View File

@@ -0,0 +1,121 @@
Syntactic Diagnostics for file '/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts':
==== /tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts (0 errors) ====
type ActionFunction<
TExpressionEvent extends { type: string },
out TEvent extends { type: string }
> = {
({ event }: { event: TExpressionEvent }): void;
_out_TEvent?: TEvent;
};
interface MachineConfig<TEvent extends { type: string }> {
types: {
events: TEvent;
};
on: {
[K in TEvent["type"]]?: ActionFunction<
Extract<TEvent, { type: K }>,
TEvent
>;
};
}
declare function raise<
TExpressionEvent extends { type: string },
TEvent extends { type: string }
>(
resolve: ({ event }: { event: TExpressionEvent }) => TEvent
): {
({ event }: { event: TExpressionEvent }): void;
_out_TEvent?: TEvent;
};
declare function createMachine<TEvent extends { type: string }>(
config: MachineConfig<TEvent>
): void;
createMachine({
types: {
events: {} as { type: "FOO" } | { type: "BAR" },
},
on: {
FOO: raise(({ event }) => {
return {
type: "BAR" as const,
};
}),
},
});
Semantic Diagnostics for file '/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts':
/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts(41,5): error TS2322: Type '{ ({ event }: { event: { type: "FOO"; }; }): void; _out_TEvent?: { type: "BARx"; } | undefined; }' is not assignable to type 'ActionFunction<{ type: "FOO"; }, { type: "FOO"; } | { type: "BAR"; }>'.
Types of property '_out_TEvent' are incompatible.
Type '{ type: "BARx"; } | undefined' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; } | undefined'.
Type '{ type: "BARx"; }' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; } | undefined'.
Type '{ type: "BARx"; }' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; }'.
Type '{ type: "BARx"; }' is not assignable to type '{ type: "BAR"; }'.
Types of property 'type' are incompatible.
Type '"BARx"' is not assignable to type '"BAR"'.
==== /tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts (1 errors) ====
type ActionFunction<
TExpressionEvent extends { type: string },
out TEvent extends { type: string }
> = {
({ event }: { event: TExpressionEvent }): void;
_out_TEvent?: TEvent;
};
interface MachineConfig<TEvent extends { type: string }> {
types: {
events: TEvent;
};
on: {
[K in TEvent["type"]]?: ActionFunction<
Extract<TEvent, { type: K }>,
TEvent
>;
};
}
declare function raise<
TExpressionEvent extends { type: string },
TEvent extends { type: string }
>(
resolve: ({ event }: { event: TExpressionEvent }) => TEvent
): {
({ event }: { event: TExpressionEvent }): void;
_out_TEvent?: TEvent;
};
declare function createMachine<TEvent extends { type: string }>(
config: MachineConfig<TEvent>
): void;
createMachine({
types: {
events: {} as { type: "FOO" } | { type: "BAR" },
},
on: {
FOO: raise(({ event }) => {
~~~
!!! error TS2322: Type '{ ({ event }: { event: { type: "FOO"; }; }): void; _out_TEvent?: { type: "BARx"; } | undefined; }' is not assignable to type 'ActionFunction<{ type: "FOO"; }, { type: "FOO"; } | { type: "BAR"; }>'.
!!! error TS2322: Types of property '_out_TEvent' are incompatible.
!!! error TS2322: Type '{ type: "BARx"; } | undefined' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; } | undefined'.
!!! error TS2322: Type '{ type: "BARx"; }' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; } | undefined'.
!!! error TS2322: Type '{ type: "BARx"; }' is not assignable to type '{ type: "FOO"; } | { type: "BAR"; }'.
!!! error TS2322: Type '{ type: "BARx"; }' is not assignable to type '{ type: "BAR"; }'.
!!! error TS2322: Types of property 'type' are incompatible.
!!! error TS2322: Type '"BARx"' is not assignable to type '"BAR"'.
!!! related TS6500 /tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall2.ts:14:7: The expected type comes from property 'FOO' which is declared here on type '{ FOO?: ActionFunction<{ type: "FOO"; }, { type: "FOO"; } | { type: "BAR"; }> | undefined; BAR?: ActionFunction<{ type: "BAR"; }, { type: "FOO"; } | { type: "BAR"; }> | undefined; }'
return {
type: "BAR" as const,
};
}),
},
});

View File

@@ -0,0 +1,54 @@
///<reference path="fourslash.ts"/>
// @strict: true
////
//// type ActionFunction<
//// TExpressionEvent extends { type: string },
//// out TEvent extends { type: string }
//// > = {
//// ({ event }: { event: TExpressionEvent }): void;
//// _out_TEvent?: TEvent;
//// };
////
//// interface MachineConfig<TEvent extends { type: string }> {
//// types: {
//// events: TEvent;
//// };
//// on: {
//// [K in TEvent["type"]]?: ActionFunction<
//// Extract<TEvent, { type: K }>,
//// TEvent
//// >;
//// };
//// }
////
//// declare function raise<
//// TExpressionEvent extends { type: string },
//// TEvent extends { type: string }
//// >(
//// resolve: ({ event }: { event: TExpressionEvent }) => TEvent
//// ): {
//// ({ event }: { event: TExpressionEvent }): void;
//// _out_TEvent?: TEvent;
//// };
////
//// declare function createMachine<TEvent extends { type: string }>(
//// config: MachineConfig<TEvent>
//// ): void;
////
//// createMachine({
//// types: {
//// events: {} as { type: "FOO" } | { type: "BAR" },
//// },
//// on: {
//// [|/*error*/FOO|]: raise(({ event }) => {
//// return {
//// type: "BAR/*1*/" as const,
//// };
//// }),
//// },
//// });
goTo.marker("1");
edit.insert(`x`)
verify.completions({ exact: ["FOO", "BAR"] });
verify.baselineSyntacticAndSemanticDiagnostics()