diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8504074080ae5..d402f344d60eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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(target).type; } @@ -4267,6 +4268,10 @@ namespace ts { if (propertyName === TypeSystemPropertyName.ResolvedReturnType) { return (target).resolvedReturnType; } + if (propertyName === TypeSystemPropertyName.ResolvedBaseConstraint) { + const bc = (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; } diff --git a/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.errors.txt b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.errors.txt new file mode 100644 index 0000000000000..5300c97a576a6 --- /dev/null +++ b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.errors.txt @@ -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(n: number, v: T, k: K) { + ~ +!!! error TS2313: Type parameter 'P' has a circular constraint. + n += v[k]; + } + \ No newline at end of file diff --git a/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.js b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.js new file mode 100644 index 0000000000000..44954f5c7c272 --- /dev/null +++ b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.js @@ -0,0 +1,12 @@ +//// [incorrectRecursiveMappedTypeConstraint.ts] +// #17847 +function sum(n: number, v: T, k: K) { + n += v[k]; +} + + +//// [incorrectRecursiveMappedTypeConstraint.js] +// #17847 +function sum(n, v, k) { + n += v[k]; +} diff --git a/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.symbols b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.symbols new file mode 100644 index 0000000000000..42cc7b1f4fb71 --- /dev/null +++ b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.symbols @@ -0,0 +1,21 @@ +=== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts === +// #17847 +function sum(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)) +} + diff --git a/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.types b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.types new file mode 100644 index 0000000000000..b658995621655 --- /dev/null +++ b/tests/baselines/reference/incorrectRecursiveMappedTypeConstraint.types @@ -0,0 +1,23 @@ +=== tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts === +// #17847 +function sum(n: number, v: T, k: K) { +>sum : (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 +} + diff --git a/tests/baselines/reference/recursiveMappedTypes.errors.txt b/tests/baselines/reference/recursiveMappedTypes.errors.txt index 440825f531949..8279f4f60a65a 100644 --- a/tests/baselines/reference/recursiveMappedTypes.errors.txt +++ b/tests/baselines/reference/recursiveMappedTypes.errors.txt @@ -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. } \ No newline at end of file diff --git a/tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts b/tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts new file mode 100644 index 0000000000000..67e996c975b28 --- /dev/null +++ b/tests/cases/compiler/incorrectRecursiveMappedTypeConstraint.ts @@ -0,0 +1,4 @@ +// #17847 +function sum(n: number, v: T, k: K) { + n += v[k]; +} diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index 40bdb4eadabc9..ed149eb0c787b 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 +Subproject commit ed149eb0c787b1195a95b44105822c64bb6eb636