Skip to content

Commit 088fdf6

Browse files
authored
fix(51202): Circular instantiation expression crashing IDEs (#51214)
1 parent a3a4993 commit 088fdf6

14 files changed

+260
-21
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6677,6 +6677,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
66776677
}
66786678
}
66796679
else {
6680+
const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType);
6681+
if (isInstantiationExpressionType) {
6682+
const instantiationExpressionType = type as InstantiationExpressionType;
6683+
if (isTypeQueryNode(instantiationExpressionType.node)) {
6684+
const typeNode = serializeExistingTypeNode(context, instantiationExpressionType.node);
6685+
if (typeNode) {
6686+
return typeNode;
6687+
}
6688+
}
6689+
if (context.visitedTypes?.has(typeId)) {
6690+
return createElidedInformationPlaceholder(context);
6691+
}
6692+
return visitAndTransformType(type, createTypeNodeFromObjectType);
6693+
}
66806694
// Anonymous types without a symbol are never circular.
66816695
return createTypeNodeFromObjectType(type);
66826696
}

tests/baselines/reference/arrayTypeOfTypeOf.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ var xs2: typeof Array;
1414
>Array : ArrayConstructor
1515

1616
var xs3: typeof Array<number>;
17-
>xs3 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
17+
>xs3 : typeof Array<number>
1818
>Array : ArrayConstructor
1919

2020
var xs4: typeof Array<typeof x>;
21-
>xs4 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
21+
>xs4 : typeof Array<typeof x>
2222
>Array : ArrayConstructor
2323
>x : number
2424

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//// [circularInstantiationExpression.ts]
2+
declare function foo<T>(t: T): typeof foo<T>;
3+
foo("");
4+
5+
6+
//// [circularInstantiationExpression.js]
7+
foo("");
8+
9+
10+
//// [circularInstantiationExpression.d.ts]
11+
declare function foo<T>(t: T): typeof foo<T>;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/compiler/circularInstantiationExpression.ts ===
2+
declare function foo<T>(t: T): typeof foo<T>;
3+
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))
4+
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
5+
>t : Symbol(t, Decl(circularInstantiationExpression.ts, 0, 24))
6+
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
7+
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))
8+
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
9+
10+
foo("");
11+
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))
12+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/circularInstantiationExpression.ts ===
2+
declare function foo<T>(t: T): typeof foo<T>;
3+
>foo : <T>(t: T) => typeof foo<T>
4+
>t : T
5+
>foo : <T>(t: T) => typeof foo<T>
6+
7+
foo("");
8+
>foo("") : (t: string) => any
9+
>foo : <T>(t: T) => (t: T) => any
10+
>"" : ""
11+

tests/baselines/reference/expressionWithJSDocTypeArguments.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ const ComeOnFoo = foo<?string?>;
3333
>foo : <T>(x: T) => T
3434

3535
type TWhatFoo = typeof foo<?>;
36-
>TWhatFoo : (x: any) => any
36+
>TWhatFoo : typeof foo<unknown>
3737
>foo : <T>(x: T) => T
3838

3939
type THuhFoo = typeof foo<string?>;
40-
>THuhFoo : (x: string | null) => string | null
40+
>THuhFoo : typeof foo<string | null>
4141
>foo : <T>(x: T) => T
4242

4343
type TNopeFoo = typeof foo<?string>;
44-
>TNopeFoo : (x: string | null) => string | null
44+
>TNopeFoo : typeof foo<string | null>
4545
>foo : <T>(x: T) => T
4646

4747
type TComeOnFoo = typeof foo<?string?>;
48-
>TComeOnFoo : (x: string | null) => string | null
48+
>TComeOnFoo : typeof foo<(string | null) | null>
4949
>foo : <T>(x: T) => T
5050

5151
const WhatBar = Bar<?>;
@@ -69,18 +69,18 @@ const ComeOnBar = Bar<?string?>;
6969
>Bar : typeof Bar
7070

7171
type TWhatBar = typeof Bar<?>;
72-
>TWhatBar : { new (x: any): Bar<any>; prototype: Bar<any>; }
72+
>TWhatBar : typeof Bar<unknown>
7373
>Bar : typeof Bar
7474

7575
type THuhBar = typeof Bar<string?>;
76-
>THuhBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
76+
>THuhBar : typeof Bar<string | null>
7777
>Bar : typeof Bar
7878

7979
type TNopeBar = typeof Bar<?string>;
80-
>TNopeBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
80+
>TNopeBar : typeof Bar<string | null>
8181
>Bar : typeof Bar
8282

8383
type TComeOnBar = typeof Bar<?string?>;
84-
>TComeOnBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
84+
>TComeOnBar : typeof Bar<(string | null) | null>
8585
>Bar : typeof Bar
8686

tests/baselines/reference/instantiationExpressions.types

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ type T10 = typeof fx<>; // Error
4141
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
4242

4343
type T11 = typeof fx<string>; // { (x: string): string; (x: string, n: number): string; }
44-
>T11 : { (x: string): string; (x: string, n: number): string; }
44+
>T11 : typeof fx<string>
4545
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
4646

4747
type T12 = typeof fx<string, number>; // (t: [string, number]) => [string, number]
48-
>T12 : (t: [string, number]) => [string, number]
48+
>T12 : typeof fx<string, number>
4949
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
5050

5151
type T13 = typeof fx<string, number, boolean>; // Error
52-
>T13 : {}
52+
>T13 : typeof fx<string, number, boolean>
5353
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
5454

5555
function f2() {
@@ -76,11 +76,11 @@ type T20 = typeof Array<>; // Error
7676
>Array : ArrayConstructor
7777

7878
type T21 = typeof Array<string>; // new (...) => string[]
79-
>T21 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
79+
>T21 : typeof Array<string>
8080
>Array : ArrayConstructor
8181

8282
type T22 = typeof Array<string, number>; // Error
83-
>T22 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; }
83+
>T22 : typeof Array<string, number>
8484
>Array : ArrayConstructor
8585

8686
declare class C<T> {
@@ -439,7 +439,7 @@ function makeBox<T>(value: T) {
439439
}
440440

441441
type BoxFunc<T> = typeof makeBox<T>; // (value: T) => { value: T }
442-
>BoxFunc : (value: T) => { value: T; }
442+
>BoxFunc : typeof makeBox<T>
443443
>makeBox : <T>(value: T) => { value: T; }
444444

445445
type StringBoxFunc = BoxFunc<string>; // (value: string) => { value: string }
@@ -469,7 +469,7 @@ declare const g1: {
469469
}
470470

471471
type T30<V> = typeof g1<V>; // { (a: V) => { a: V }; new (b: V) => { b: V }; }
472-
>T30 : { (a: V): { a: V; }; new (b: V): { b: V; }; }
472+
>T30 : typeof g1<V>
473473
>g1 : { <T>(a: T): { a: T; }; new <U>(b: U): { b: U; }; }
474474

475475
type T31<A> = ReturnType<T30<A>>; // { a: A }
@@ -489,11 +489,11 @@ declare const g2: {
489489
}
490490

491491
type T40<U extends string> = typeof g2<U>; // Error
492-
>T40 : { (a: U): U; new <T extends number>(b: T): T; }
492+
>T40 : typeof g2<U>
493493
>g2 : { <T extends string>(a: T): T; new <T extends number>(b: T): T; }
494494

495495
type T41<U extends number> = typeof g2<U>; // Error
496-
>T41 : { <T extends string>(a: T): T; new (b: U): U; }
496+
>T41 : typeof g2<U>
497497
>g2 : { <T extends string>(a: T): T; new <T extends number>(b: T): T; }
498498

499499
declare const g3: {
@@ -507,10 +507,10 @@ declare const g3: {
507507
}
508508

509509
type T50<U extends string> = typeof g3<U>; // (a: U) => U
510-
>T50 : (a: U) => U
510+
>T50 : typeof g3<U>
511511
>g3 : { <T extends string>(a: T): T; new <T extends number, Q>(b: T): T; }
512512

513513
type T51<U extends number> = typeof g3<U, any>; // (b: U) => U
514-
>T51 : new (b: U) => U
514+
>T51 : typeof g3<U, any>
515515
>g3 : { <T extends string>(a: T): T; new <T extends number, Q>(b: T): T; }
516516

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
=== /tests/cases/fourslash/quickInfoCircularInstantiationExpression.ts ===
2+
// declare function foo<T>(t: T): typeof foo<T>;
3+
// foo("");
4+
// ^^^
5+
// | ----------------------------------------------------------------------
6+
// | function foo<string>(t: string): (t: string) => ...
7+
// | ----------------------------------------------------------------------
8+
9+
[
10+
{
11+
"marker": {
12+
"fileName": "/tests/cases/fourslash/quickInfoCircularInstantiationExpression.ts",
13+
"position": 46,
14+
"name": ""
15+
},
16+
"item": {
17+
"kind": "function",
18+
"kindModifiers": "declare",
19+
"textSpan": {
20+
"start": 46,
21+
"length": 3
22+
},
23+
"displayParts": [
24+
{
25+
"text": "function",
26+
"kind": "keyword"
27+
},
28+
{
29+
"text": " ",
30+
"kind": "space"
31+
},
32+
{
33+
"text": "foo",
34+
"kind": "functionName"
35+
},
36+
{
37+
"text": "<",
38+
"kind": "punctuation"
39+
},
40+
{
41+
"text": "string",
42+
"kind": "keyword"
43+
},
44+
{
45+
"text": ">",
46+
"kind": "punctuation"
47+
},
48+
{
49+
"text": "(",
50+
"kind": "punctuation"
51+
},
52+
{
53+
"text": "t",
54+
"kind": "parameterName"
55+
},
56+
{
57+
"text": ":",
58+
"kind": "punctuation"
59+
},
60+
{
61+
"text": " ",
62+
"kind": "space"
63+
},
64+
{
65+
"text": "string",
66+
"kind": "keyword"
67+
},
68+
{
69+
"text": ")",
70+
"kind": "punctuation"
71+
},
72+
{
73+
"text": ":",
74+
"kind": "punctuation"
75+
},
76+
{
77+
"text": " ",
78+
"kind": "space"
79+
},
80+
{
81+
"text": "(",
82+
"kind": "punctuation"
83+
},
84+
{
85+
"text": "t",
86+
"kind": "parameterName"
87+
},
88+
{
89+
"text": ":",
90+
"kind": "punctuation"
91+
},
92+
{
93+
"text": " ",
94+
"kind": "space"
95+
},
96+
{
97+
"text": "string",
98+
"kind": "keyword"
99+
},
100+
{
101+
"text": ")",
102+
"kind": "punctuation"
103+
},
104+
{
105+
"text": " ",
106+
"kind": "space"
107+
},
108+
{
109+
"text": "=>",
110+
"kind": "punctuation"
111+
},
112+
{
113+
"text": " ",
114+
"kind": "space"
115+
},
116+
{
117+
"text": "...",
118+
"kind": "text"
119+
}
120+
],
121+
"documentation": []
122+
}
123+
}
124+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [selfReferentialFunctionType.ts]
2+
declare function f<T>(args: typeof f<T>): T;
3+
declare function g<T = typeof g>(args: T): T;
4+
declare function h<T>(): typeof h<T>;
5+
6+
7+
//// [selfReferentialFunctionType.js]
8+
"use strict";
9+
10+
11+
//// [selfReferentialFunctionType.d.ts]
12+
declare function f<T>(args: typeof f<T>): T;
13+
declare function g<T = typeof g>(args: T): T;
14+
declare function h<T>(): typeof h<T>;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/selfReferentialFunctionType.ts ===
2+
declare function f<T>(args: typeof f<T>): T;
3+
>f : Symbol(f, Decl(selfReferentialFunctionType.ts, 0, 0))
4+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
5+
>args : Symbol(args, Decl(selfReferentialFunctionType.ts, 0, 22))
6+
>f : Symbol(f, Decl(selfReferentialFunctionType.ts, 0, 0))
7+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
8+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
9+
10+
declare function g<T = typeof g>(args: T): T;
11+
>g : Symbol(g, Decl(selfReferentialFunctionType.ts, 0, 44))
12+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
13+
>g : Symbol(g, Decl(selfReferentialFunctionType.ts, 0, 44))
14+
>args : Symbol(args, Decl(selfReferentialFunctionType.ts, 1, 33))
15+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
16+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
17+
18+
declare function h<T>(): typeof h<T>;
19+
>h : Symbol(h, Decl(selfReferentialFunctionType.ts, 1, 45))
20+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 2, 19))
21+
>h : Symbol(h, Decl(selfReferentialFunctionType.ts, 1, 45))
22+
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 2, 19))
23+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/selfReferentialFunctionType.ts ===
2+
declare function f<T>(args: typeof f<T>): T;
3+
>f : <T>(args: typeof f<T>) => T
4+
>args : typeof f<T>
5+
>f : <T>(args: typeof f<T>) => T
6+
7+
declare function g<T = typeof g>(args: T): T;
8+
>g : <T = typeof g>(args: T) => T
9+
>g : <T = typeof g>(args: T) => T
10+
>args : T
11+
12+
declare function h<T>(): typeof h<T>;
13+
>h : <T>() => typeof h<T>
14+
>h : <T>() => typeof h<T>
15+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @declaration: true
2+
declare function foo<T>(t: T): typeof foo<T>;
3+
foo("");
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @strict: true
2+
// @declaration: true
3+
4+
declare function f<T>(args: typeof f<T>): T;
5+
declare function g<T = typeof g>(args: T): T;
6+
declare function h<T>(): typeof h<T>;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////declare function foo<T>(t: T): typeof foo<T>;
4+
/////**/foo("");
5+
6+
verify.baselineQuickInfo();

0 commit comments

Comments
 (0)