Skip to content

Commit da0c1f8

Browse files
TypeScript Botweswigham
authored andcommitted
Cherry-pick PR #34791 into release-3.7 (#34834)
Component commits: 3904be1 Add circularity checking during deferred type argument creation
1 parent 068ae69 commit da0c1f8

7 files changed

+121
-1
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ namespace ts {
163163
ImmediateBaseConstraint,
164164
EnumTagType,
165165
JSDocTypeReference,
166+
ResolvedTypeArguments,
166167
}
167168

168169
const enum CheckMode {
@@ -6539,6 +6540,8 @@ namespace ts {
65396540
return !!(<Type>target).immediateBaseConstraint;
65406541
case TypeSystemPropertyName.JSDocTypeReference:
65416542
return !!getSymbolLinks(target as Symbol).resolvedJSDocType;
6543+
case TypeSystemPropertyName.ResolvedTypeArguments:
6544+
return !!(target as TypeReference).resolvedTypeArguments;
65426545
}
65436546
return Debug.assertNever(propertyName);
65446547
}
@@ -10629,12 +10632,28 @@ namespace ts {
1062910632

1063010633
function getTypeArguments(type: TypeReference): readonly Type[] {
1063110634
if (!type.resolvedTypeArguments) {
10635+
if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedTypeArguments)) {
10636+
return type.target.localTypeParameters?.map(() => errorType) || emptyArray;
10637+
}
1063210638
const node = type.node;
1063310639
const typeArguments = !node ? emptyArray :
1063410640
node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) :
1063510641
node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] :
1063610642
map(node.elementTypes, getTypeFromTypeNode);
10637-
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
10643+
if (popTypeResolution()) {
10644+
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
10645+
}
10646+
else {
10647+
type.resolvedTypeArguments = type.target.localTypeParameters?.map(() => errorType) || emptyArray;
10648+
error(
10649+
type.node || currentNode,
10650+
type.target.symbol
10651+
? Diagnostics.Type_arguments_for_0_circularly_reference_themselves
10652+
: Diagnostics.Tuple_type_arguments_circularly_reference_themselves
10653+
,
10654+
type.target.symbol && symbolToString(type.target.symbol)
10655+
);
10656+
}
1063810657
}
1063910658
return type.resolvedTypeArguments;
1064010659
}

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,6 +3136,14 @@
31363136
"category": "Error",
31373137
"code": 4108
31383138
},
3139+
"Type arguments for '{0}' circularly reference themselves.": {
3140+
"category": "Error",
3141+
"code": 4109
3142+
},
3143+
"Tuple type arguments circularly reference themselves.": {
3144+
"category": "Error",
3145+
"code": 4110
3146+
},
31393147

31403148
"The current host does not support the '{0}' option.": {
31413149
"category": "Error",
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(1,12): error TS4109: Type arguments for 'Mx' circularly reference themselves.
2+
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(8,16): error TS4109: Type arguments for 'Array' circularly reference themselves.
3+
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(10,18): error TS4110: Tuple type arguments circularly reference themselves.
4+
5+
6+
==== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts (3 errors) ====
7+
type Mxs = Mx<'list', Mxs['p1']>;
8+
~~~~~~~~~~~~~~~~~~~~~
9+
!!! error TS4109: Type arguments for 'Mx' circularly reference themselves.
10+
11+
interface Mx<T, K> {
12+
p1: T;
13+
p2: K;
14+
}
15+
16+
type ArrElem = ['list', ArrElem[number][0]][];
17+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18+
!!! error TS4109: Type arguments for 'Array' circularly reference themselves.
19+
20+
type TupleElem = [['list', TupleElem[0][0]]];
21+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
22+
!!! error TS4110: Tuple type arguments circularly reference themselves.
23+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//// [circularlyReferentialInterfaceAccessNoCrash.ts]
2+
type Mxs = Mx<'list', Mxs['p1']>;
3+
4+
interface Mx<T, K> {
5+
p1: T;
6+
p2: K;
7+
}
8+
9+
type ArrElem = ['list', ArrElem[number][0]][];
10+
11+
type TupleElem = [['list', TupleElem[0][0]]];
12+
13+
14+
//// [circularlyReferentialInterfaceAccessNoCrash.js]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts ===
2+
type Mxs = Mx<'list', Mxs['p1']>;
3+
>Mxs : Symbol(Mxs, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 0))
4+
>Mx : Symbol(Mx, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 33))
5+
>Mxs : Symbol(Mxs, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 0))
6+
7+
interface Mx<T, K> {
8+
>Mx : Symbol(Mx, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 33))
9+
>T : Symbol(T, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 13))
10+
>K : Symbol(K, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 15))
11+
12+
p1: T;
13+
>p1 : Symbol(Mx.p1, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 20))
14+
>T : Symbol(T, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 13))
15+
16+
p2: K;
17+
>p2 : Symbol(Mx.p2, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 3, 8))
18+
>K : Symbol(K, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 15))
19+
}
20+
21+
type ArrElem = ['list', ArrElem[number][0]][];
22+
>ArrElem : Symbol(ArrElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 5, 1))
23+
>ArrElem : Symbol(ArrElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 5, 1))
24+
25+
type TupleElem = [['list', TupleElem[0][0]]];
26+
>TupleElem : Symbol(TupleElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 7, 46))
27+
>TupleElem : Symbol(TupleElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 7, 46))
28+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts ===
2+
type Mxs = Mx<'list', Mxs['p1']>;
3+
>Mxs : Mxs
4+
5+
interface Mx<T, K> {
6+
p1: T;
7+
>p1 : T
8+
9+
p2: K;
10+
>p2 : K
11+
}
12+
13+
type ArrElem = ['list', ArrElem[number][0]][];
14+
>ArrElem : ArrElem
15+
16+
type TupleElem = [['list', TupleElem[0][0]]];
17+
>TupleElem : TupleElem
18+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
type Mxs = Mx<'list', Mxs['p1']>;
2+
3+
interface Mx<T, K> {
4+
p1: T;
5+
p2: K;
6+
}
7+
8+
type ArrElem = ['list', ArrElem[number][0]][];
9+
10+
type TupleElem = [['list', TupleElem[0][0]]];

0 commit comments

Comments
 (0)