Skip to content

Commit 84d8429

Browse files
authored
Add depth limiter to isConstTypeVariable function (#54624)
1 parent e1a9290 commit 84d8429

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13538,14 +13538,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1353813538
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
1353913539
}
1354013540

13541-
function isConstTypeVariable(type: Type | undefined): boolean {
13542-
return !!(type && (
13541+
function isConstTypeVariable(type: Type | undefined, depth = 0): boolean {
13542+
return depth < 5 && !!(type && (
1354313543
type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) ||
13544-
type.flags & TypeFlags.Union && some((type as UnionType).types, isConstTypeVariable) ||
13545-
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType) ||
13546-
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType)) ||
13547-
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType) ||
13548-
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
13544+
type.flags & TypeFlags.Union && some((type as UnionType).types, t => isConstTypeVariable(t, depth)) ||
13545+
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) ||
13546+
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) ||
13547+
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) ||
13548+
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0));
1354913549
}
1355013550

1355113551
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
circularBaseConstraint.ts(14,8): error TS2304: Cannot find name 'a'.
2+
3+
4+
==== circularBaseConstraint.ts (1 errors) ====
5+
// Repro from #54610
6+
7+
type A<T> = T;
8+
9+
type B<T> = T extends any[]
10+
? never
11+
: A<T> extends infer key
12+
? key extends keyof T
13+
? B<T[key]>
14+
: never
15+
: never;
16+
17+
function foo<T>() {
18+
`${a}` as B<T>;
19+
~
20+
!!! error TS2304: Cannot find name 'a'.
21+
}
22+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [tests/cases/compiler/circularBaseConstraint.ts] ////
2+
3+
=== circularBaseConstraint.ts ===
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
>A : Symbol(A, Decl(circularBaseConstraint.ts, 0, 0))
8+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 2, 7))
9+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 2, 7))
10+
11+
type B<T> = T extends any[]
12+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
13+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
14+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
15+
16+
? never
17+
: A<T> extends infer key
18+
>A : Symbol(A, Decl(circularBaseConstraint.ts, 0, 0))
19+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
20+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
21+
22+
? key extends keyof T
23+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
24+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
25+
26+
? B<T[key]>
27+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
28+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
29+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
30+
31+
: never
32+
: never;
33+
34+
function foo<T>() {
35+
>foo : Symbol(foo, Decl(circularBaseConstraint.ts, 10, 12))
36+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 12, 13))
37+
38+
`${a}` as B<T>;
39+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
40+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 12, 13))
41+
}
42+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [tests/cases/compiler/circularBaseConstraint.ts] ////
2+
3+
=== circularBaseConstraint.ts ===
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
>A : T
8+
9+
type B<T> = T extends any[]
10+
>B : B<T>
11+
12+
? never
13+
: A<T> extends infer key
14+
? key extends keyof T
15+
? B<T[key]>
16+
: never
17+
: never;
18+
19+
function foo<T>() {
20+
>foo : <T>() => void
21+
22+
`${a}` as B<T>;
23+
>`${a}` as B<T> : B<T>
24+
>`${a}` : string
25+
>a : any
26+
}
27+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
8+
type B<T> = T extends any[]
9+
? never
10+
: A<T> extends infer key
11+
? key extends keyof T
12+
? B<T[key]>
13+
: never
14+
: never;
15+
16+
function foo<T>() {
17+
`${a}` as B<T>;
18+
}

0 commit comments

Comments
 (0)