Merge pull request #21134 from Microsoft/fix-recursive-mapped-type-infinite-recursion

Fix recursive mapped type infinite recursion
This commit is contained in:
Nathan Shively-Sanders
2018-01-11 10:24:23 -08:00
committed by GitHub
8 changed files with 93 additions and 8 deletions
+11 -6
View File
@@ -530,6 +530,7 @@ namespace ts {
ResolvedBaseConstructorType,
DeclaredType,
ResolvedReturnType,
ResolvedBaseConstraint,
}
const enum CheckMode {
@@ -4254,7 +4255,7 @@ namespace ts {
return -1;
}
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type {
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): Type | boolean {
if (propertyName === TypeSystemPropertyName.Type) {
return getSymbolLinks(<Symbol>target).type;
}
@@ -4267,6 +4268,10 @@ namespace ts {
if (propertyName === TypeSystemPropertyName.ResolvedReturnType) {
return (<Signature>target).resolvedReturnType;
}
if (propertyName === TypeSystemPropertyName.ResolvedBaseConstraint) {
const bc = (<TypeParameter | UnionOrIntersectionType>target).resolvedBaseConstraint;
return bc && bc !== circularConstraintType;
}
Debug.fail("Unhandled TypeSystemPropertyName " + propertyName);
}
@@ -6500,23 +6505,23 @@ namespace ts {
* circularly references the type variable.
*/
function getResolvedBaseConstraint(type: TypeVariable | UnionOrIntersectionType): Type {
let typeStack: Type[];
let circular: boolean;
if (!type.resolvedBaseConstraint) {
typeStack = [];
const constraint = getBaseConstraint(type);
type.resolvedBaseConstraint = circular ? circularConstraintType : getTypeWithThisArgument(constraint || noConstraintType, type);
}
return type.resolvedBaseConstraint;
function getBaseConstraint(t: Type): Type {
if (contains(typeStack, t)) {
if (!pushTypeResolution(t, TypeSystemPropertyName.ResolvedBaseConstraint)) {
circular = true;
return undefined;
}
typeStack.push(t);
const result = computeBaseConstraint(t);
typeStack.pop();
if (!popTypeResolution()) {
circular = true;
return undefined;
}
return result;
}
@@ -0,0 +1,11 @@
tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts(2,32): error TS2313: Type parameter 'P' has a circular constraint.
==== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts (1 errors) ====
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
~
!!! error TS2313: Type parameter 'P' has a circular constraint.
n += v[k];
}
@@ -0,0 +1,12 @@
//// [incorrectRecursiveMappedTypeConstraint.ts]
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
n += v[k];
}
//// [incorrectRecursiveMappedTypeConstraint.js]
// #17847
function sum(n, v, k) {
n += v[k];
}
@@ -0,0 +1,21 @@
=== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts ===
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
>sum : Symbol(sum, Decl(incorrectRecursiveMappedTypeConstraint.ts, 0, 0))
>T : Symbol(T, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 13))
>P : Symbol(P, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 26))
>T : Symbol(T, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 13))
>K : Symbol(K, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 44))
>T : Symbol(T, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 13))
>n : Symbol(n, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 64))
>v : Symbol(v, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 74))
>T : Symbol(T, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 13))
>k : Symbol(k, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 80))
>K : Symbol(K, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 44))
n += v[k];
>n : Symbol(n, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 64))
>v : Symbol(v, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 74))
>k : Symbol(k, Decl(incorrectRecursiveMappedTypeConstraint.ts, 1, 80))
}
@@ -0,0 +1,23 @@
=== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts ===
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
>sum : <T extends { [x: string]: number; }, K extends keyof T>(n: number, v: T, k: K) => void
>T : T
>P : P
>T : T
>K : K
>T : T
>n : number
>v : T
>T : T
>k : K
>K : K
n += v[k];
>n += v[k] : number
>n : number
>v[k] : T[K]
>v : T
>k : K
}
@@ -1,25 +1,34 @@
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(3,6): error TS2456: Type alias 'Recurse' circularly references itself.
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(4,11): error TS2313: Type parameter 'K' has a circular constraint.
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(7,6): error TS2456: Type alias 'Recurse1' circularly references itself.
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(8,11): error TS2313: Type parameter 'K' has a circular constraint.
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(11,6): error TS2456: Type alias 'Recurse2' circularly references itself.
tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,11): error TS2313: Type parameter 'K' has a circular constraint.
==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (3 errors) ====
==== tests/cases/conformance/types/mapped/recursiveMappedTypes.ts (6 errors) ====
// Recursive mapped types simply appear empty
type Recurse = {
~~~~~~~
!!! error TS2456: Type alias 'Recurse' circularly references itself.
[K in keyof Recurse]: Recurse[K]
~~~~~~~~~~~~~
!!! error TS2313: Type parameter 'K' has a circular constraint.
}
type Recurse1 = {
~~~~~~~~
!!! error TS2456: Type alias 'Recurse1' circularly references itself.
[K in keyof Recurse2]: Recurse2[K]
~~~~~~~~~~~~~~
!!! error TS2313: Type parameter 'K' has a circular constraint.
}
type Recurse2 = {
~~~~~~~~
!!! error TS2456: Type alias 'Recurse2' circularly references itself.
[K in keyof Recurse1]: Recurse1[K]
~~~~~~~~~~~~~~
!!! error TS2313: Type parameter 'K' has a circular constraint.
}
@@ -0,0 +1,4 @@
// #17847
function sum<T extends { [P in T]: number }, K extends keyof T>(n: number, v: T, k: K) {
n += v[k];
}