-
Notifications
You must be signed in to change notification settings - Fork 12.8k
TSServer hangs when using recursive types on tuples and pressing "," #26155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Reproduced in a fourslash test: /// <reference path='fourslash.ts'/>
////type Tail<T extends any[]> =
//// ((...args: T) => any) extends ((head: any, ...tail: infer R) => any) ? R : never;
////
////type Reverse<List extends any[]> = _Reverse<List, []>;
////
////type _Reverse<Source extends any[], Result extends any[] = []> = {
//// 1: Result,
//// 0: _Reverse<Tail<Source>, 0>,
////}[Source extends [] ? 1 : 0];
////
////type Foo = Reverse<[0,/**/]>;
verify.signatureHelp({
marker: "",
text: "?",
}); |
Potentially relevant: While the process hangs, its RAM usage continues to rise - as if its building some infinite signature help or something like that. |
afaik TS did do stuff on trailing comma for Intellisense purposes... not sure what's happening here though. |
I might have a clue whats going on behind the scenes. Using [email protected] and the following code: /**
* Returns the length of an array or tuple
*/
export type LengthOf<T extends any[]> = T["length"];
/**
* Returns the logarithm to the base 2 of the (L + 1)
*/
export type Magnitude<L> =
number extends L ? never : (
L extends 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 ?
L extends 0 | 1 | 2 | 3 ?
L extends 0 | 1 ?
L extends 0 ?
0 : 1 : 2 : 3 : 4
);
// Drop the first N items of T
type Drop1<T extends any[]> = ((...args: T) => void) extends ((a1: any, ...rest: infer R) => void) ? R : never;
type Drop2<T extends any[]> = ((...args: T) => void) extends ((a1: any, a2: any, ...rest: infer R) => void) ? R : never;
type Drop4<T extends any[]> = ((...args: T) => void) extends ((a1: any, a2: any, a3: any, a4: any, ...rest: infer R) => void) ? R : never;
type Drop8<T extends any[]> = ((...args: T) => void) extends ((a1: any, a2: any, a3: any, a4: any, a5: any, a6: any, a7: any, a8: any, ...rest: infer R) => void) ? R : never;
// Take the first N items of T1, reverse them and prepend them to T2
type ConcatReverse1<T1 extends any[], T2 extends any[]> = ((a1: T1[0], ...rest: T2) => void) extends ((...args: infer R) => void) ? R : never;
type ConcatReverse2<T1 extends any[], T2 extends any[]> = ((a2: T1[1], a1: T1[0], ...rest: T2) => void) extends ((...args: infer R) => void) ? R : never;
type ConcatReverse4<T1 extends any[], T2 extends any[]> = ((a4: T1[3], a3: T1[2], a2: T1[1], a1: T1[0], ...rest: T2) => void) extends ((...args: infer R) => void) ? R : never;
type ConcatReverse8<T1 extends any[], T2 extends any[]> = ((a8: T1[7], a7: T1[6], a6: T1[5], a5: T1[4], a4: T1[3], a3: T1[2], a2: T1[1], a1: T1[0], ...rest: T2) => void) extends ((...args: infer R) => void) ? R : never;
export type ConcatReverse<
T1 extends any[], T2 extends any[]=[]
> = {
0: T2,
// depending on the length of T1, take the first half of T1,
// and prepend it to T2 in a reversed order
1: ConcatReverse<Drop1<T1>, ConcatReverse1<T1, T2>>,
2: ConcatReverse<Drop2<T1>, ConcatReverse2<T1, T2>>,
3: ConcatReverse<Drop4<T1>, ConcatReverse4<T1, T2>>,
4: ConcatReverse<Drop8<T1>, ConcatReverse8<T1, T2>>,
}[Magnitude<T1["length"]>];
/**
* Reverses the given list
* WARNING: Use at your own risk, this might crash TypeScript
*/
export type Reverse<T extends any[]> = ConcatReverse<T>;
type DropLast<
T extends any[],
U extends any[] = Reverse<T>, // error here, but it works!
V extends any[] = Drop1<U>,
W extends any[] = Reverse<V>
> = W;
type Foo = DropLast<[1, 2, 3, 4, 5]>; Intellisense shows an error on the two lines using |
Update: Using [email protected], the original code no longer completely freezes the language server. It's still incredibly slow, but works. |
@sheetalkamat @RyanCavanaugh |
with typescript@next there is no huge type generated that I can repro with your example. |
Disclaimer: This is probably not intended use of the type system but it might show an underlying issue so I still report it.
TypeScript Version: 3.1.0-dev.20180802
Search Terms: recursive conditional type tuple freeze
Code
While experimenting with the examples found in #24897 (comment), I noticed some weird behavior when it comes to recursive types. Apparently tail recursion on type members seems to work, which means it can be used to create crazy types like
Reverse
:When opening a file where that type is used, VSCode's Intellisense shows the correct type after a minor delay:
After adding a comma after the 3 in the recursive type, TSServers comes to a halt (1 core with full CPU usage).
However, if I paste a comma and a number from somewhere else in a single operation, it works just fine:
The same thing happens when changing a type to this recursive type
but not doing it in this order:
Related Issues: #24897
The text was updated successfully, but these errors were encountered: