mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Track tuple type recursion in inferFromObjectTypes (#37479)
* Track recursive tuple types in inferFromObjectTypes * Add regression test
This commit is contained in:
@@ -18131,7 +18131,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) {
|
||||
let symbolStack: Symbol[];
|
||||
let symbolOrTypeStack: (Symbol | Type)[];
|
||||
let visited: Map<number>;
|
||||
let bivariant = false;
|
||||
let propagationType: Type;
|
||||
@@ -18570,15 +18570,15 @@ namespace ts {
|
||||
// its symbol with the instance side which would lead to false positives.
|
||||
const isNonConstructorObject = target.flags & TypeFlags.Object &&
|
||||
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
|
||||
const symbol = isNonConstructorObject ? target.symbol : undefined;
|
||||
if (symbol) {
|
||||
if (contains(symbolStack, symbol)) {
|
||||
const symbolOrType = isNonConstructorObject ? isTupleType(target) ? target.target : target.symbol : undefined;
|
||||
if (symbolOrType) {
|
||||
if (contains(symbolOrTypeStack, symbolOrType)) {
|
||||
inferencePriority = InferencePriority.Circularity;
|
||||
return;
|
||||
}
|
||||
(symbolStack || (symbolStack = [])).push(symbol);
|
||||
(symbolOrTypeStack || (symbolOrTypeStack = [])).push(symbolOrType);
|
||||
inferFromObjectTypesWorker(source, target);
|
||||
symbolStack.pop();
|
||||
symbolOrTypeStack.pop();
|
||||
}
|
||||
else {
|
||||
inferFromObjectTypesWorker(source, target);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
tests/cases/compiler/recursiveTupleTypeInference.ts(23,5): error TS2345: Argument of type '{ b: A; }' is not assignable to parameter of type 'G<{ b: unknown; }>'.
|
||||
Types of property 'b' are incompatible.
|
||||
Type 'A' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'.
|
||||
Type '"number"' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/recursiveTupleTypeInference.ts (1 errors) ====
|
||||
// Repro from #37475
|
||||
|
||||
export type A = "number" | "null" | A[];
|
||||
|
||||
export type F<T> = null extends T
|
||||
? [F<NonNullable<T>>, "null"]
|
||||
: T extends number
|
||||
? "number"
|
||||
: never;
|
||||
|
||||
export type G<T> = { [k in keyof T]: F<T[k]> };
|
||||
|
||||
interface K {
|
||||
b: number | null;
|
||||
}
|
||||
|
||||
const gK: { [key in keyof K]: A } = { b: ["number", "null"] };
|
||||
|
||||
function foo<T>(g: G<T>): T {
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
foo(gK);
|
||||
~~
|
||||
!!! error TS2345: Argument of type '{ b: A; }' is not assignable to parameter of type 'G<{ b: unknown; }>'.
|
||||
!!! error TS2345: Types of property 'b' are incompatible.
|
||||
!!! error TS2345: Type 'A' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'.
|
||||
!!! error TS2345: Type '"number"' is not assignable to type '[[[[[[[[[[[[any, "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"], "null"]'.
|
||||
|
||||
35
tests/baselines/reference/recursiveTupleTypeInference.js
Normal file
35
tests/baselines/reference/recursiveTupleTypeInference.js
Normal file
@@ -0,0 +1,35 @@
|
||||
//// [recursiveTupleTypeInference.ts]
|
||||
// Repro from #37475
|
||||
|
||||
export type A = "number" | "null" | A[];
|
||||
|
||||
export type F<T> = null extends T
|
||||
? [F<NonNullable<T>>, "null"]
|
||||
: T extends number
|
||||
? "number"
|
||||
: never;
|
||||
|
||||
export type G<T> = { [k in keyof T]: F<T[k]> };
|
||||
|
||||
interface K {
|
||||
b: number | null;
|
||||
}
|
||||
|
||||
const gK: { [key in keyof K]: A } = { b: ["number", "null"] };
|
||||
|
||||
function foo<T>(g: G<T>): T {
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
foo(gK);
|
||||
|
||||
|
||||
//// [recursiveTupleTypeInference.js]
|
||||
"use strict";
|
||||
// Repro from #37475
|
||||
exports.__esModule = true;
|
||||
var gK = { b: ["number", "null"] };
|
||||
function foo(g) {
|
||||
return {};
|
||||
}
|
||||
foo(gK);
|
||||
@@ -0,0 +1,61 @@
|
||||
=== tests/cases/compiler/recursiveTupleTypeInference.ts ===
|
||||
// Repro from #37475
|
||||
|
||||
export type A = "number" | "null" | A[];
|
||||
>A : Symbol(A, Decl(recursiveTupleTypeInference.ts, 0, 0))
|
||||
>A : Symbol(A, Decl(recursiveTupleTypeInference.ts, 0, 0))
|
||||
|
||||
export type F<T> = null extends T
|
||||
>F : Symbol(F, Decl(recursiveTupleTypeInference.ts, 2, 40))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 4, 14))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 4, 14))
|
||||
|
||||
? [F<NonNullable<T>>, "null"]
|
||||
>F : Symbol(F, Decl(recursiveTupleTypeInference.ts, 2, 40))
|
||||
>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 4, 14))
|
||||
|
||||
: T extends number
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 4, 14))
|
||||
|
||||
? "number"
|
||||
: never;
|
||||
|
||||
export type G<T> = { [k in keyof T]: F<T[k]> };
|
||||
>G : Symbol(G, Decl(recursiveTupleTypeInference.ts, 8, 12))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 10, 14))
|
||||
>k : Symbol(k, Decl(recursiveTupleTypeInference.ts, 10, 22))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 10, 14))
|
||||
>F : Symbol(F, Decl(recursiveTupleTypeInference.ts, 2, 40))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 10, 14))
|
||||
>k : Symbol(k, Decl(recursiveTupleTypeInference.ts, 10, 22))
|
||||
|
||||
interface K {
|
||||
>K : Symbol(K, Decl(recursiveTupleTypeInference.ts, 10, 47))
|
||||
|
||||
b: number | null;
|
||||
>b : Symbol(K.b, Decl(recursiveTupleTypeInference.ts, 12, 13))
|
||||
}
|
||||
|
||||
const gK: { [key in keyof K]: A } = { b: ["number", "null"] };
|
||||
>gK : Symbol(gK, Decl(recursiveTupleTypeInference.ts, 16, 5))
|
||||
>key : Symbol(key, Decl(recursiveTupleTypeInference.ts, 16, 13))
|
||||
>K : Symbol(K, Decl(recursiveTupleTypeInference.ts, 10, 47))
|
||||
>A : Symbol(A, Decl(recursiveTupleTypeInference.ts, 0, 0))
|
||||
>b : Symbol(b, Decl(recursiveTupleTypeInference.ts, 16, 37))
|
||||
|
||||
function foo<T>(g: G<T>): T {
|
||||
>foo : Symbol(foo, Decl(recursiveTupleTypeInference.ts, 16, 62))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 18, 13))
|
||||
>g : Symbol(g, Decl(recursiveTupleTypeInference.ts, 18, 16))
|
||||
>G : Symbol(G, Decl(recursiveTupleTypeInference.ts, 8, 12))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 18, 13))
|
||||
>T : Symbol(T, Decl(recursiveTupleTypeInference.ts, 18, 13))
|
||||
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
foo(gK);
|
||||
>foo : Symbol(foo, Decl(recursiveTupleTypeInference.ts, 16, 62))
|
||||
>gK : Symbol(gK, Decl(recursiveTupleTypeInference.ts, 16, 5))
|
||||
|
||||
46
tests/baselines/reference/recursiveTupleTypeInference.types
Normal file
46
tests/baselines/reference/recursiveTupleTypeInference.types
Normal file
@@ -0,0 +1,46 @@
|
||||
=== tests/cases/compiler/recursiveTupleTypeInference.ts ===
|
||||
// Repro from #37475
|
||||
|
||||
export type A = "number" | "null" | A[];
|
||||
>A : A
|
||||
|
||||
export type F<T> = null extends T
|
||||
>F : F<T>
|
||||
>null : null
|
||||
|
||||
? [F<NonNullable<T>>, "null"]
|
||||
: T extends number
|
||||
? "number"
|
||||
: never;
|
||||
|
||||
export type G<T> = { [k in keyof T]: F<T[k]> };
|
||||
>G : G<T>
|
||||
|
||||
interface K {
|
||||
b: number | null;
|
||||
>b : number | null
|
||||
>null : null
|
||||
}
|
||||
|
||||
const gK: { [key in keyof K]: A } = { b: ["number", "null"] };
|
||||
>gK : { b: A; }
|
||||
>{ b: ["number", "null"] } : { b: ("number" | "null")[]; }
|
||||
>b : ("number" | "null")[]
|
||||
>["number", "null"] : ("number" | "null")[]
|
||||
>"number" : "number"
|
||||
>"null" : "null"
|
||||
|
||||
function foo<T>(g: G<T>): T {
|
||||
>foo : <T>(g: G<T>) => T
|
||||
>g : G<T>
|
||||
|
||||
return {} as any;
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
}
|
||||
|
||||
foo(gK);
|
||||
>foo(gK) : { b: unknown; }
|
||||
>foo : <T>(g: G<T>) => T
|
||||
>gK : { b: A; }
|
||||
|
||||
25
tests/cases/compiler/recursiveTupleTypeInference.ts
Normal file
25
tests/cases/compiler/recursiveTupleTypeInference.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// @strict: true
|
||||
|
||||
// Repro from #37475
|
||||
|
||||
export type A = "number" | "null" | A[];
|
||||
|
||||
export type F<T> = null extends T
|
||||
? [F<NonNullable<T>>, "null"]
|
||||
: T extends number
|
||||
? "number"
|
||||
: never;
|
||||
|
||||
export type G<T> = { [k in keyof T]: F<T[k]> };
|
||||
|
||||
interface K {
|
||||
b: number | null;
|
||||
}
|
||||
|
||||
const gK: { [key in keyof K]: A } = { b: ["number", "null"] };
|
||||
|
||||
function foo<T>(g: G<T>): T {
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
foo(gK);
|
||||
Reference in New Issue
Block a user