Skip to content

Commit 5bf0585

Browse files
committed
Fixed more ghost errors after LSP requests caching wrong contextual and parameter types
1 parent c6a1812 commit 5bf0585

File tree

3 files changed

+166
-21
lines changed

3 files changed

+166
-21
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,27 +1971,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19711971
function runWithoutResolvedSignatureCaching<T>(node: Node | undefined, fn: () => T): T {
19721972
node = findAncestor(node, isCallLikeOrFunctionLikeExpression);
19731973
if (node) {
1974-
const cachedResolvedSignatures = [];
1975-
const cachedTypes = [];
1976-
while (node) {
1977-
const nodeLinks = getNodeLinks(node);
1978-
cachedResolvedSignatures.push([nodeLinks, nodeLinks.resolvedSignature] as const);
1979-
nodeLinks.resolvedSignature = undefined;
1980-
if (isFunctionExpressionOrArrowFunction(node)) {
1981-
const symbolLinks = getSymbolLinks(getSymbolOfDeclaration(node));
1982-
const type = symbolLinks.type;
1983-
cachedTypes.push([symbolLinks, type] as const);
1984-
symbolLinks.type = undefined;
1985-
}
1986-
node = findAncestor(node.parent, isCallLikeOrFunctionLikeExpression);
1987-
}
1974+
sourceFileWithoutResolvedSignatureCaching = getSourceFileOfNode(node);
19881975
const result = fn();
1989-
for (const [nodeLinks, resolvedSignature] of cachedResolvedSignatures) {
1990-
nodeLinks.resolvedSignature = resolvedSignature;
1991-
}
1992-
for (const [symbolLinks, type] of cachedTypes) {
1993-
symbolLinks.type = type;
1994-
}
1976+
sourceFileWithoutResolvedSignatureCaching = undefined;
1977+
symbolLinksWithoutResolvedSignatureCaching = undefined;
1978+
nodeLinksWithoutResolvedSignatureCaching = undefined;
19951979
return result;
19961980
}
19971981
return fn();
@@ -2342,7 +2326,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
23422326
var maximumSuggestionCount = 10;
23432327
var mergedSymbols: Symbol[] = [];
23442328
var symbolLinks: SymbolLinks[] = [];
2329+
var symbolLinksWithoutResolvedSignatureCaching: SymbolLinks[] | undefined;
23452330
var nodeLinks: NodeLinks[] = [];
2331+
var nodeLinksWithoutResolvedSignatureCaching: NodeLinks[] | undefined;
2332+
var sourceFileWithoutResolvedSignatureCaching: SourceFile | undefined;
23462333
var flowLoopCaches: Map<string, Type>[] = [];
23472334
var flowLoopNodes: FlowNode[] = [];
23482335
var flowLoopKeys: string[] = [];
@@ -2917,12 +2904,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29172904
function getSymbolLinks(symbol: Symbol): SymbolLinks {
29182905
if (symbol.flags & SymbolFlags.Transient) return (symbol as TransientSymbol).links;
29192906
const id = getSymbolId(symbol);
2907+
if (sourceFileWithoutResolvedSignatureCaching && symbol.valueDeclaration && (isFunctionExpressionOrArrowFunction(symbol.valueDeclaration) || tryGetRootParameterDeclaration(symbol.valueDeclaration)) && getSourceFileOfNode(symbol.valueDeclaration) === sourceFileWithoutResolvedSignatureCaching) {
2908+
symbolLinksWithoutResolvedSignatureCaching ??= [];
2909+
return symbolLinksWithoutResolvedSignatureCaching[id] ??= new SymbolLinks();
2910+
}
29202911
return symbolLinks[id] ??= new SymbolLinks();
29212912
}
29222913

29232914
function getNodeLinks(node: Node): NodeLinks {
29242915
const nodeId = getNodeId(node);
2925-
return nodeLinks[nodeId] || (nodeLinks[nodeId] = new (NodeLinks as any)());
2916+
if (sourceFileWithoutResolvedSignatureCaching && (isCallLikeOrFunctionLikeExpression(node) || tryGetRootParameterDeclaration(node)) && getSourceFileOfNode(node) === sourceFileWithoutResolvedSignatureCaching) {
2917+
nodeLinksWithoutResolvedSignatureCaching ??= [];
2918+
return nodeLinksWithoutResolvedSignatureCaching[nodeId] ??= new (NodeLinks as any)();
2919+
}
2920+
return nodeLinks[nodeId] ??= new (NodeLinks as any)();
29262921
}
29272922

29282923
function getSymbol(symbols: SymbolTable, name: __String, meaning: SymbolFlags): Symbol | undefined {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @strict: true
4+
// @target: esnext
5+
// @lib: esnext
6+
7+
//// type ObjectFromEntries<T> = T extends readonly [
8+
//// infer Key extends string | number | symbol,
9+
//// infer Value,
10+
//// ][]
11+
//// ? { [key in Key]: Value }
12+
//// : never;
13+
////
14+
//// type KeyValuePairs<T> = {
15+
//// [K in keyof T]: [K, T[K]];
16+
//// }[keyof T];
17+
////
18+
//// declare function mapObjectEntries<
19+
//// const T extends object,
20+
//// const TMapped extends [string | number | symbol, unknown],
21+
//// >(
22+
//// obj: T,
23+
//// mapper: ([a, b]: KeyValuePairs<T>) => TMapped,
24+
//// ): ObjectFromEntries<TMapped[]>;
25+
////
26+
//// mapObjectEntries({ a: 1, b: 2 }, ([x, y]) => ["a/*1*/", y]);
27+
28+
verify.completions({
29+
marker: "1",
30+
exact: ["a"],
31+
});
32+
verify.noErrors();
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @strict: true
4+
// @target: esnext
5+
// @lib: esnext
6+
7+
//// export interface Pipeable {
8+
//// pipe<A, B = never>(this: A, ab: (_: A) => B): B;
9+
//// }
10+
////
11+
//// type Covariant<A> = (_: never) => A;
12+
////
13+
//// interface VarianceStruct<out A, out E, out R> {
14+
//// readonly _V: string;
15+
//// readonly _A: Covariant<A>;
16+
//// readonly _E: Covariant<E>;
17+
//// readonly _R: Covariant<R>;
18+
//// }
19+
////
20+
//// declare const EffectTypeId: unique symbol;
21+
////
22+
//// interface Variance<out A, out E, out R> {
23+
//// readonly [EffectTypeId]: VarianceStruct<A, E, R>;
24+
//// }
25+
////
26+
//// interface Effect<out A, out E = never, out R = never>
27+
//// extends Variance<A, E, R>,
28+
//// Pipeable {}
29+
////
30+
//// interface Class<Fields> extends Pipeable {
31+
//// new (): Fields;
32+
//// }
33+
////
34+
//// interface TaggedErrorClass<Tag extends string, Fields> extends Class<Fields> {
35+
//// readonly _tag: Tag;
36+
//// }
37+
////
38+
//// declare const TaggedError: (identifier?: string) => <
39+
//// Tag extends string,
40+
//// Fields
41+
//// >(
42+
//// tag: Tag,
43+
//// fieldsOr: Fields
44+
//// ) => TaggedErrorClass<
45+
//// Tag,
46+
//// {
47+
//// readonly _tag: Tag;
48+
//// }
49+
//// >;
50+
////
51+
//// declare const log: (
52+
//// ...message: ReadonlyArray<any>
53+
//// ) => Effect<void, never, never>;
54+
////
55+
//// export const categoriesKey = "@effect/error/categories";
56+
////
57+
//// export declare const withCategory: <Categories extends Array<PropertyKey>>(
58+
//// ...categories: Categories
59+
//// ) => <Args extends Array<any>, Ret, C extends { new (...args: Args): Ret }>(
60+
//// C: C
61+
//// ) => C & {
62+
//// new (...args: Args): Ret & {
63+
//// [categoriesKey]: { [Cat in Categories[number]]: true };
64+
//// };
65+
//// };
66+
////
67+
//// export type AllKeys<E> = E extends { [categoriesKey]: infer Q }
68+
//// ? keyof Q
69+
//// : never;
70+
//// export type ExtractAll<E, Cats extends PropertyKey> = Cats extends any
71+
//// ? Extract<E, { [categoriesKey]: { [K in Cats]: any } }>
72+
//// : never;
73+
////
74+
//// export declare const catchCategory: <
75+
//// E,
76+
//// const Categories extends Array<AllKeys<E>>,
77+
//// A2,
78+
//// E2,
79+
//// R2
80+
//// >(
81+
//// ...args: [
82+
//// ...Categories,
83+
//// f: (err: ExtractAll<E, Categories[number]>) => Effect<A2, E2, R2>
84+
//// ]
85+
//// ) => <A, R>(
86+
//// effect: Effect<A, E, R>
87+
//// ) => Effect<A | A2, E2 | Exclude<E, ExtractAll<E, Categories[number]>>, R | R2>;
88+
////
89+
//// class FooError extends TaggedError()("FooError", {}).pipe(
90+
//// withCategory("domain")
91+
//// ) {}
92+
////
93+
//// class BarError extends TaggedError()("BarError", {}).pipe(
94+
//// withCategory("system", "domain")
95+
//// ) {}
96+
////
97+
//// class BazError extends TaggedError()("BazError", {}).pipe(
98+
//// withCategory("system")
99+
//// ) {}
100+
////
101+
//// declare const baz: (
102+
//// x: number
103+
//// ) => Effect<never, FooError | BarError | BazError, never>;
104+
////
105+
//// export const program = baz(1).pipe(catchCategory("domain",/*1*/ (_) => log(_._tag)));
106+
107+
verify.noErrors();
108+
goTo.marker("1");
109+
edit.insert(",");
110+
verify.signatureHelpPresentForTriggerReason({
111+
kind: "characterTyped",
112+
triggerCharacter: ",",
113+
});
114+
edit.backspace(1);
115+
verify.signatureHelpPresentForTriggerReason({
116+
kind: "retrigger",
117+
});
118+
verify.noErrors();

0 commit comments

Comments
 (0)