Add circularity checking during deferred type argument creation (#34791)

This commit is contained in:
Wesley Wigham 2019-10-30 13:36:43 -07:00 committed by GitHub
parent 8b7664ae15
commit 5e0fbc677a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 1 deletions

View File

@ -163,6 +163,7 @@ namespace ts {
ImmediateBaseConstraint,
EnumTagType,
JSDocTypeReference,
ResolvedTypeArguments,
}
const enum CheckMode {
@ -6560,6 +6561,8 @@ namespace ts {
return !!(<Type>target).immediateBaseConstraint;
case TypeSystemPropertyName.JSDocTypeReference:
return !!getSymbolLinks(target as Symbol).resolvedJSDocType;
case TypeSystemPropertyName.ResolvedTypeArguments:
return !!(target as TypeReference).resolvedTypeArguments;
}
return Debug.assertNever(propertyName);
}
@ -10650,12 +10653,28 @@ namespace ts {
function getTypeArguments(type: TypeReference): readonly Type[] {
if (!type.resolvedTypeArguments) {
if (!pushTypeResolution(type, TypeSystemPropertyName.ResolvedTypeArguments)) {
return type.target.localTypeParameters?.map(() => errorType) || emptyArray;
}
const node = type.node;
const typeArguments = !node ? emptyArray :
node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) :
node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] :
map(node.elementTypes, getTypeFromTypeNode);
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
if (popTypeResolution()) {
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
}
else {
type.resolvedTypeArguments = type.target.localTypeParameters?.map(() => errorType) || emptyArray;
error(
type.node || currentNode,
type.target.symbol
? Diagnostics.Type_arguments_for_0_circularly_reference_themselves
: Diagnostics.Tuple_type_arguments_circularly_reference_themselves
,
type.target.symbol && symbolToString(type.target.symbol)
);
}
}
return type.resolvedTypeArguments;
}

View File

@ -3136,6 +3136,14 @@
"category": "Error",
"code": 4108
},
"Type arguments for '{0}' circularly reference themselves.": {
"category": "Error",
"code": 4109
},
"Tuple type arguments circularly reference themselves.": {
"category": "Error",
"code": 4110
},
"The current host does not support the '{0}' option.": {
"category": "Error",

View File

@ -0,0 +1,23 @@
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(1,12): error TS4109: Type arguments for 'Mx' circularly reference themselves.
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(8,16): error TS4109: Type arguments for 'Array' circularly reference themselves.
tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts(10,18): error TS4110: Tuple type arguments circularly reference themselves.
==== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts (3 errors) ====
type Mxs = Mx<'list', Mxs['p1']>;
~~~~~~~~~~~~~~~~~~~~~
!!! error TS4109: Type arguments for 'Mx' circularly reference themselves.
interface Mx<T, K> {
p1: T;
p2: K;
}
type ArrElem = ['list', ArrElem[number][0]][];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4109: Type arguments for 'Array' circularly reference themselves.
type TupleElem = [['list', TupleElem[0][0]]];
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4110: Tuple type arguments circularly reference themselves.

View File

@ -0,0 +1,14 @@
//// [circularlyReferentialInterfaceAccessNoCrash.ts]
type Mxs = Mx<'list', Mxs['p1']>;
interface Mx<T, K> {
p1: T;
p2: K;
}
type ArrElem = ['list', ArrElem[number][0]][];
type TupleElem = [['list', TupleElem[0][0]]];
//// [circularlyReferentialInterfaceAccessNoCrash.js]

View File

@ -0,0 +1,28 @@
=== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts ===
type Mxs = Mx<'list', Mxs['p1']>;
>Mxs : Symbol(Mxs, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 0))
>Mx : Symbol(Mx, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 33))
>Mxs : Symbol(Mxs, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 0))
interface Mx<T, K> {
>Mx : Symbol(Mx, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 0, 33))
>T : Symbol(T, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 13))
>K : Symbol(K, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 15))
p1: T;
>p1 : Symbol(Mx.p1, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 20))
>T : Symbol(T, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 13))
p2: K;
>p2 : Symbol(Mx.p2, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 3, 8))
>K : Symbol(K, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 2, 15))
}
type ArrElem = ['list', ArrElem[number][0]][];
>ArrElem : Symbol(ArrElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 5, 1))
>ArrElem : Symbol(ArrElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 5, 1))
type TupleElem = [['list', TupleElem[0][0]]];
>TupleElem : Symbol(TupleElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 7, 46))
>TupleElem : Symbol(TupleElem, Decl(circularlyReferentialInterfaceAccessNoCrash.ts, 7, 46))

View File

@ -0,0 +1,18 @@
=== tests/cases/compiler/circularlyReferentialInterfaceAccessNoCrash.ts ===
type Mxs = Mx<'list', Mxs['p1']>;
>Mxs : Mxs
interface Mx<T, K> {
p1: T;
>p1 : T
p2: K;
>p2 : K
}
type ArrElem = ['list', ArrElem[number][0]][];
>ArrElem : ArrElem
type TupleElem = [['list', TupleElem[0][0]]];
>TupleElem : TupleElem

View File

@ -0,0 +1,10 @@
type Mxs = Mx<'list', Mxs['p1']>;
interface Mx<T, K> {
p1: T;
p2: K;
}
type ArrElem = ['list', ArrElem[number][0]][];
type TupleElem = [['list', TupleElem[0][0]]];