fix(51202): Circular instantiation expression crashing IDEs (#51214)

This commit is contained in:
Oleksandr T
2023-02-17 21:31:45 +02:00
committed by GitHub
parent a3a4993937
commit 088fdf6efe
14 changed files with 260 additions and 21 deletions

View File

@@ -6677,6 +6677,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
else {
const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType);
if (isInstantiationExpressionType) {
const instantiationExpressionType = type as InstantiationExpressionType;
if (isTypeQueryNode(instantiationExpressionType.node)) {
const typeNode = serializeExistingTypeNode(context, instantiationExpressionType.node);
if (typeNode) {
return typeNode;
}
}
if (context.visitedTypes?.has(typeId)) {
return createElidedInformationPlaceholder(context);
}
return visitAndTransformType(type, createTypeNodeFromObjectType);
}
// Anonymous types without a symbol are never circular.
return createTypeNodeFromObjectType(type);
}

View File

@@ -14,11 +14,11 @@ var xs2: typeof Array;
>Array : ArrayConstructor
var xs3: typeof Array<number>;
>xs3 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>xs3 : typeof Array<number>
>Array : ArrayConstructor
var xs4: typeof Array<typeof x>;
>xs4 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>xs4 : typeof Array<typeof x>
>Array : ArrayConstructor
>x : number

View File

@@ -0,0 +1,11 @@
//// [circularInstantiationExpression.ts]
declare function foo<T>(t: T): typeof foo<T>;
foo("");
//// [circularInstantiationExpression.js]
foo("");
//// [circularInstantiationExpression.d.ts]
declare function foo<T>(t: T): typeof foo<T>;

View File

@@ -0,0 +1,12 @@
=== tests/cases/compiler/circularInstantiationExpression.ts ===
declare function foo<T>(t: T): typeof foo<T>;
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
>t : Symbol(t, Decl(circularInstantiationExpression.ts, 0, 24))
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))
>T : Symbol(T, Decl(circularInstantiationExpression.ts, 0, 21))
foo("");
>foo : Symbol(foo, Decl(circularInstantiationExpression.ts, 0, 0))

View File

@@ -0,0 +1,11 @@
=== tests/cases/compiler/circularInstantiationExpression.ts ===
declare function foo<T>(t: T): typeof foo<T>;
>foo : <T>(t: T) => typeof foo<T>
>t : T
>foo : <T>(t: T) => typeof foo<T>
foo("");
>foo("") : (t: string) => any
>foo : <T>(t: T) => (t: T) => any
>"" : ""

View File

@@ -33,19 +33,19 @@ const ComeOnFoo = foo<?string?>;
>foo : <T>(x: T) => T
type TWhatFoo = typeof foo<?>;
>TWhatFoo : (x: any) => any
>TWhatFoo : typeof foo<unknown>
>foo : <T>(x: T) => T
type THuhFoo = typeof foo<string?>;
>THuhFoo : (x: string | null) => string | null
>THuhFoo : typeof foo<string | null>
>foo : <T>(x: T) => T
type TNopeFoo = typeof foo<?string>;
>TNopeFoo : (x: string | null) => string | null
>TNopeFoo : typeof foo<string | null>
>foo : <T>(x: T) => T
type TComeOnFoo = typeof foo<?string?>;
>TComeOnFoo : (x: string | null) => string | null
>TComeOnFoo : typeof foo<(string | null) | null>
>foo : <T>(x: T) => T
const WhatBar = Bar<?>;
@@ -69,18 +69,18 @@ const ComeOnBar = Bar<?string?>;
>Bar : typeof Bar
type TWhatBar = typeof Bar<?>;
>TWhatBar : { new (x: any): Bar<any>; prototype: Bar<any>; }
>TWhatBar : typeof Bar<unknown>
>Bar : typeof Bar
type THuhBar = typeof Bar<string?>;
>THuhBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
>THuhBar : typeof Bar<string | null>
>Bar : typeof Bar
type TNopeBar = typeof Bar<?string>;
>TNopeBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
>TNopeBar : typeof Bar<string | null>
>Bar : typeof Bar
type TComeOnBar = typeof Bar<?string?>;
>TComeOnBar : { new (x: string | null): Bar<string | null>; prototype: Bar<any>; }
>TComeOnBar : typeof Bar<(string | null) | null>
>Bar : typeof Bar

View File

@@ -41,15 +41,15 @@ type T10 = typeof fx<>; // Error
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
type T11 = typeof fx<string>; // { (x: string): string; (x: string, n: number): string; }
>T11 : { (x: string): string; (x: string, n: number): string; }
>T11 : typeof fx<string>
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
type T12 = typeof fx<string, number>; // (t: [string, number]) => [string, number]
>T12 : (t: [string, number]) => [string, number]
>T12 : typeof fx<string, number>
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
type T13 = typeof fx<string, number, boolean>; // Error
>T13 : {}
>T13 : typeof fx<string, number, boolean>
>fx : { <T>(x: T): T; <T>(x: T, n: number): T; <T, U>(t: [T, U]): [T, U]; }
function f2() {
@@ -76,11 +76,11 @@ type T20 = typeof Array<>; // Error
>Array : ArrayConstructor
type T21 = typeof Array<string>; // new (...) => string[]
>T21 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>T21 : typeof Array<string>
>Array : ArrayConstructor
type T22 = typeof Array<string, number>; // Error
>T22 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>T22 : typeof Array<string, number>
>Array : ArrayConstructor
declare class C<T> {
@@ -439,7 +439,7 @@ function makeBox<T>(value: T) {
}
type BoxFunc<T> = typeof makeBox<T>; // (value: T) => { value: T }
>BoxFunc : (value: T) => { value: T; }
>BoxFunc : typeof makeBox<T>
>makeBox : <T>(value: T) => { value: T; }
type StringBoxFunc = BoxFunc<string>; // (value: string) => { value: string }
@@ -469,7 +469,7 @@ declare const g1: {
}
type T30<V> = typeof g1<V>; // { (a: V) => { a: V }; new (b: V) => { b: V }; }
>T30 : { (a: V): { a: V; }; new (b: V): { b: V; }; }
>T30 : typeof g1<V>
>g1 : { <T>(a: T): { a: T; }; new <U>(b: U): { b: U; }; }
type T31<A> = ReturnType<T30<A>>; // { a: A }
@@ -489,11 +489,11 @@ declare const g2: {
}
type T40<U extends string> = typeof g2<U>; // Error
>T40 : { (a: U): U; new <T extends number>(b: T): T; }
>T40 : typeof g2<U>
>g2 : { <T extends string>(a: T): T; new <T extends number>(b: T): T; }
type T41<U extends number> = typeof g2<U>; // Error
>T41 : { <T extends string>(a: T): T; new (b: U): U; }
>T41 : typeof g2<U>
>g2 : { <T extends string>(a: T): T; new <T extends number>(b: T): T; }
declare const g3: {
@@ -507,10 +507,10 @@ declare const g3: {
}
type T50<U extends string> = typeof g3<U>; // (a: U) => U
>T50 : (a: U) => U
>T50 : typeof g3<U>
>g3 : { <T extends string>(a: T): T; new <T extends number, Q>(b: T): T; }
type T51<U extends number> = typeof g3<U, any>; // (b: U) => U
>T51 : new (b: U) => U
>T51 : typeof g3<U, any>
>g3 : { <T extends string>(a: T): T; new <T extends number, Q>(b: T): T; }

View File

@@ -0,0 +1,124 @@
=== /tests/cases/fourslash/quickInfoCircularInstantiationExpression.ts ===
// declare function foo<T>(t: T): typeof foo<T>;
// foo("");
// ^^^
// | ----------------------------------------------------------------------
// | function foo<string>(t: string): (t: string) => ...
// | ----------------------------------------------------------------------
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoCircularInstantiationExpression.ts",
"position": 46,
"name": ""
},
"item": {
"kind": "function",
"kindModifiers": "declare",
"textSpan": {
"start": 46,
"length": 3
},
"displayParts": [
{
"text": "function",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo",
"kind": "functionName"
},
{
"text": "<",
"kind": "punctuation"
},
{
"text": "string",
"kind": "keyword"
},
{
"text": ">",
"kind": "punctuation"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "t",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "t",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "=>",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "...",
"kind": "text"
}
],
"documentation": []
}
}
]

View File

@@ -0,0 +1,14 @@
//// [selfReferentialFunctionType.ts]
declare function f<T>(args: typeof f<T>): T;
declare function g<T = typeof g>(args: T): T;
declare function h<T>(): typeof h<T>;
//// [selfReferentialFunctionType.js]
"use strict";
//// [selfReferentialFunctionType.d.ts]
declare function f<T>(args: typeof f<T>): T;
declare function g<T = typeof g>(args: T): T;
declare function h<T>(): typeof h<T>;

View File

@@ -0,0 +1,23 @@
=== tests/cases/compiler/selfReferentialFunctionType.ts ===
declare function f<T>(args: typeof f<T>): T;
>f : Symbol(f, Decl(selfReferentialFunctionType.ts, 0, 0))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
>args : Symbol(args, Decl(selfReferentialFunctionType.ts, 0, 22))
>f : Symbol(f, Decl(selfReferentialFunctionType.ts, 0, 0))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 0, 19))
declare function g<T = typeof g>(args: T): T;
>g : Symbol(g, Decl(selfReferentialFunctionType.ts, 0, 44))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
>g : Symbol(g, Decl(selfReferentialFunctionType.ts, 0, 44))
>args : Symbol(args, Decl(selfReferentialFunctionType.ts, 1, 33))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 1, 19))
declare function h<T>(): typeof h<T>;
>h : Symbol(h, Decl(selfReferentialFunctionType.ts, 1, 45))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 2, 19))
>h : Symbol(h, Decl(selfReferentialFunctionType.ts, 1, 45))
>T : Symbol(T, Decl(selfReferentialFunctionType.ts, 2, 19))

View File

@@ -0,0 +1,15 @@
=== tests/cases/compiler/selfReferentialFunctionType.ts ===
declare function f<T>(args: typeof f<T>): T;
>f : <T>(args: typeof f<T>) => T
>args : typeof f<T>
>f : <T>(args: typeof f<T>) => T
declare function g<T = typeof g>(args: T): T;
>g : <T = typeof g>(args: T) => T
>g : <T = typeof g>(args: T) => T
>args : T
declare function h<T>(): typeof h<T>;
>h : <T>() => typeof h<T>
>h : <T>() => typeof h<T>

View File

@@ -0,0 +1,3 @@
// @declaration: true
declare function foo<T>(t: T): typeof foo<T>;
foo("");

View File

@@ -0,0 +1,6 @@
// @strict: true
// @declaration: true
declare function f<T>(args: typeof f<T>): T;
declare function g<T = typeof g>(args: T): T;
declare function h<T>(): typeof h<T>;

View File

@@ -0,0 +1,6 @@
/// <reference path="fourslash.ts" />
////declare function foo<T>(t: T): typeof foo<T>;
/////**/foo("");
verify.baselineQuickInfo();