Skip to content

Commit 3fe794d

Browse files
committed
Fix perf issue in recursiveTypeReferences2 by broadening recursion guards and introducing better deep nesting heuristic for unions and intersections
1 parent db9529d commit 3fe794d

10 files changed

+43
-57
lines changed

src/compiler/checker.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -17320,6 +17320,10 @@ namespace ts {
1732017320
}
1732117321

1732217322
function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
17323+
return recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, typeRelatedToEachTypeWorker);
17324+
}
17325+
17326+
function typeRelatedToEachTypeWorker(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
1732317327
let result = Ternary.True;
1732417328
const targetTypes = target.types;
1732517329
for (const targetType of targetTypes) {
@@ -17357,7 +17361,6 @@ namespace ts {
1735717361
return target;
1735817362
}
1735917363

17360-
1736117364
function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
1736217365
// By piping the union comparison through `recursiveTypeRelatedTo`, we can prevent recursively normalizing types like those
1736317366
// in `recursivelyExpandingUnionNoStackoverflow` from blowing the stack during comparison checking when their variance is requested.
@@ -19040,6 +19043,11 @@ namespace ts {
1904019043
// The root object represents the origin of the conditional type
1904119044
return (type as ConditionalType).root;
1904219045
}
19046+
if (type.flags & TypeFlags.UnionOrIntersection && type.aliasSymbol && type.aliasTypeArguments) {
19047+
// Unions and intersections are difficult to make recusive, but they can be, if they have an associated alias
19048+
// (which is then later used to make a recursive type reference). In such cases, use the alias symbol as the identity.
19049+
return type.aliasSymbol;
19050+
}
1904319051
return undefined;
1904419052
}
1904519053

tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt

+20-36
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,18 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t
22
Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>, "type">'.
33
Types of property 'type' are incompatible.
44
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
5-
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
6-
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
5+
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
6+
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
77
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
88
Type '"text"' is not assignable to type 'T & "text"'.
9-
Type '"text"' is not assignable to type 'T'.
10-
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
11-
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
12-
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
13-
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
14-
Type '"text"' is not assignable to type 'T & "text"'.
15-
Type '"text"' is not assignable to type 'T'.
16-
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
17-
Type 'T' is not assignable to type 'T & "text"'.
18-
Type '"text" | "email"' is not assignable to type 'T & "text"'.
19-
Type '"text"' is not assignable to type 'T & "text"'.
20-
Type '"text"' is not assignable to type 'T'.
21-
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
22-
Type 'T' is not assignable to type '"text"'.
23-
Type '"text" | "email"' is not assignable to type '"text"'.
24-
Type '"email"' is not assignable to type '"text"'.
9+
Type 'T' is not assignable to type 'T & "text"'.
10+
Type '"text" | "email"' is not assignable to type 'T & "text"'.
11+
Type '"text"' is not assignable to type 'T & "text"'.
12+
Type '"text"' is not assignable to type 'T'.
13+
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
14+
Type 'T' is not assignable to type '"text"'.
15+
Type '"text" | "email"' is not assignable to type '"text"'.
16+
Type '"email"' is not assignable to type '"text"'.
2517

2618

2719
==== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts (1 errors) ====
@@ -63,26 +55,18 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t
6355
!!! error TS2322: Type '{ type: T; localChannelId: string; }' is not assignable to type 'Pick<ChannelOfType<T, TextChannel> | ChannelOfType<T, EmailChannel>, "type">'.
6456
!!! error TS2322: Types of property 'type' are incompatible.
6557
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
66-
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
67-
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
58+
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
59+
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
6860
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
6961
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
70-
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
71-
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
72-
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
73-
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
74-
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
75-
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
76-
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
77-
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
78-
!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'.
79-
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'.
80-
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
81-
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
82-
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
83-
!!! error TS2322: Type 'T' is not assignable to type '"text"'.
84-
!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'.
85-
!!! error TS2322: Type '"email"' is not assignable to type '"text"'.
62+
!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'.
63+
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'.
64+
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
65+
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
66+
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
67+
!!! error TS2322: Type 'T' is not assignable to type '"text"'.
68+
!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'.
69+
!!! error TS2322: Type '"email"' is not assignable to type '"text"'.
8670
}
8771

8872
const newTextChannel = makeNewChannel('text');

tests/baselines/reference/instantiateContextualTypes.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ createReducer(
149149

150150
handler(NON_VOID_ACTION, (state, _payload) => state),
151151
>handler(NON_VOID_ACTION, (state, _payload) => state) : ActionHandler<AppState, number>
152-
>handler : <S, P>(actionType: ActionType<P>, handler: Handler<S, P>) => ActionHandler<S, P>
152+
>handler : <S, P>(actionType: ActionType<unknown>, handler: Handler<S, P>) => ActionHandler<S, P>
153153
>NON_VOID_ACTION : ActionType<number>
154154
>(state, _payload) => state : (state: AppState, _payload: number) => AppState
155155
>state : AppState
@@ -158,7 +158,7 @@ createReducer(
158158

159159
handler(VOID_ACTION, state => state)
160160
>handler(VOID_ACTION, state => state) : ActionHandler<AppState, void>
161-
>handler : <S, P>(actionType: ActionType<P>, handler: Handler<S, P>) => ActionHandler<S, P>
161+
>handler : <S, P>(actionType: ActionType<unknown>, handler: Handler<S, P>) => ActionHandler<S, P>
162162
>VOID_ACTION : ActionType<void>
163163
>state => state : (state: AppState) => AppState
164164
>state : AppState

tests/baselines/reference/intersectionAndUnionTypes.errors.txt

-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(20,1): e
55
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(23,1): error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'.
66
Type 'A' is not assignable to type '(A & B) | (C & D)'.
77
Type 'A' is not assignable to type 'A & B'.
8-
Type 'A' is not assignable to type 'B'.
98
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(25,1): error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'.
109
Type 'C' is not assignable to type '(A & B) | (C & D)'.
1110
Type 'C' is not assignable to type 'C & D'.
@@ -80,7 +79,6 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): e
8079
!!! error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'.
8180
!!! error TS2322: Type 'A' is not assignable to type '(A & B) | (C & D)'.
8281
!!! error TS2322: Type 'A' is not assignable to type 'A & B'.
83-
!!! error TS2322: Type 'A' is not assignable to type 'B'.
8482
x = cnd; // Ok
8583
x = cod;
8684
~

tests/baselines/reference/jsxNamespaceGlobalReexport.types

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import { JSXInternal } from '..';
9090
>JSXInternal : any
9191

9292
export function jsx(
93-
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
93+
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
9494

9595
type: string,
9696
>type : string
@@ -125,7 +125,7 @@ export function jsx<P>(
125125
): VNode<any>;
126126

127127
export function jsxs(
128-
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
128+
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
129129

130130
type: string,
131131
>type : string
@@ -160,7 +160,7 @@ export function jsxs<P>(
160160
): VNode<any>;
161161

162162
export function jsxDEV(
163-
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
163+
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
164164

165165
type: string,
166166
>type : string

tests/baselines/reference/jsxNamespaceGlobalReexportMissingAliasTarget.types

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import { JSXInternal } from '..';
9090
>JSXInternal : any
9191

9292
export function jsx(
93-
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
93+
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
9494

9595
type: string,
9696
>type : string
@@ -125,7 +125,7 @@ export function jsx<P>(
125125
): VNode<any>;
126126

127127
export function jsxs(
128-
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
128+
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
129129

130130
type: string,
131131
>type : string
@@ -160,7 +160,7 @@ export function jsxs<P>(
160160
): VNode<any>;
161161

162162
export function jsxDEV(
163-
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
163+
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
164164

165165
type: string,
166166
>type : string

tests/baselines/reference/jsxNamespaceImplicitImportJSXNamespace.types

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ import { JSXInternal } from '..';
9090
>JSXInternal : any
9191

9292
export function jsx(
93-
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
93+
>jsx : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild | undefined; }, key?: string | undefined): VNode<any>; }
9494

9595
type: string,
9696
>type : string
@@ -126,7 +126,7 @@ export function jsx<P>(
126126

127127

128128
export function jsxs(
129-
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
129+
>jsxs : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChild[];}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChild[] | undefined; }, key?: string | undefined): VNode<any>; }
130130

131131
type: string,
132132
>type : string
@@ -162,7 +162,7 @@ export function jsxs<P>(
162162

163163

164164
export function jsxDEV(
165-
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<P>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
165+
>jsxDEV : { (type: string, props: JSXInternal.HTMLAttributes & JSXInternal.SVGAttributes & Record<string, any> & { children?: ComponentChildren;}, key?: string | undefined): VNode<any>; <P>(type: ComponentType<unknown>, props: P & { children?: ComponentChildren | undefined; }, key?: string | undefined): VNode<any>; }
166166

167167
type: string,
168168
>type : string

tests/baselines/reference/mutuallyRecursiveCallbacks.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ declare var bar: Bar<{}>;
1616
>bar : Bar<{}>
1717

1818
bar = foo;
19-
>bar = foo : <T>(bar: Bar<T>) => void
19+
>bar = foo : <T>(bar: Bar<unknown>) => void
2020
>bar : Bar<{}>
21-
>foo : <T>(bar: Bar<T>) => void
21+
>foo : <T>(bar: Bar<unknown>) => void
2222

tests/baselines/reference/specedNoStackBlown.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,5 @@ export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<I
6060
>true : true
6161

6262
export default spected;
63-
>spected : <ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT) => Result<ROOTINPUT, SPEC>
63+
>spected : <ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT) => Result<ROOTINPUT, unknown>
6464

0 commit comments

Comments
 (0)