diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65807b5347b86..1524eafcd382a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11603,6 +11603,13 @@ namespace ts { return undefined; } + function typesDefinitelyUnrelated(source: Type, target: Type) { + // Two tuple types with different arity are definitely unrelated. + // Two object types that each have a property that is unmatched in the other are definitely unrelated. + return isTupleType(source) && isTupleType(target) && getTypeReferenceArity(source) !== getTypeReferenceArity(target) || + !!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) && !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false); + } + function getTypeFromInference(inference: InferenceInfo) { return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : inference.contraCandidates ? getIntersectionType(inference.contraCandidates) : @@ -11873,9 +11880,8 @@ namespace ts { return; } } - // Infer from the members of source and target only if the two types are possibly related. We check - // in both directions because we may be inferring for a co-variant or a contra-variant position. - if (!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false) || !getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false)) { + // Infer from the members of source and target only if the two types are possibly related + if (!typesDefinitelyUnrelated(source, target)) { inferFromProperties(source, target); inferFromSignatures(source, target, SignatureKind.Call); inferFromSignatures(source, target, SignatureKind.Construct); diff --git a/tests/baselines/reference/tupleTypeInference2.js b/tests/baselines/reference/tupleTypeInference2.js new file mode 100644 index 0000000000000..7032bdbe4f2ed --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference2.js @@ -0,0 +1,35 @@ +//// [tupleTypeInference2.ts] +// Repro from #22564 + +type A = [R] | [R, string]; +declare function f(x: A): T; +f([undefined, ''] as [never, string]); // T: never +f([undefined, ''] as [void, string]); // T: void + +// Repro from #22563 + +type B = [R] | [R, S]; +declare function g(f: B): U; +g([[]] as [void[]]); // U: {} + +type C = [R[]] | [R[], S]; +declare function h(f: C): U; +h([[]] as [void[]]); // U: {} + +// Repro from #22562 + +type C2 = [R[]] | [R[], void]; +declare function h2(f: C2): T; +h2([[]] as [never[]]); // T: never +h2([[]] as [void[]]); // T: void + + +//// [tupleTypeInference2.js] +"use strict"; +// Repro from #22564 +f([undefined, '']); // T: never +f([undefined, '']); // T: void +g([[]]); // U: {} +h([[]]); // U: {} +h2([[]]); // T: never +h2([[]]); // T: void diff --git a/tests/baselines/reference/tupleTypeInference2.symbols b/tests/baselines/reference/tupleTypeInference2.symbols new file mode 100644 index 0000000000000..02e8c10139feb --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference2.symbols @@ -0,0 +1,91 @@ +=== tests/cases/compiler/tupleTypeInference2.ts === +// Repro from #22564 + +type A = [R] | [R, string]; +>A : Symbol(A, Decl(tupleTypeInference2.ts, 0, 0)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 2, 7)) + +declare function f(x: A): T; +>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19)) +>x : Symbol(x, Decl(tupleTypeInference2.ts, 3, 22)) +>A : Symbol(A, Decl(tupleTypeInference2.ts, 0, 0)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 3, 19)) + +f([undefined, ''] as [never, string]); // T: never +>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30)) +>undefined : Symbol(undefined) + +f([undefined, ''] as [void, string]); // T: void +>f : Symbol(f, Decl(tupleTypeInference2.ts, 2, 30)) +>undefined : Symbol(undefined) + +// Repro from #22563 + +type B = [R] | [R, S]; +>B : Symbol(B, Decl(tupleTypeInference2.ts, 5, 37)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7)) +>S : Symbol(S, Decl(tupleTypeInference2.ts, 9, 9)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 9, 7)) +>S : Symbol(S, Decl(tupleTypeInference2.ts, 9, 9)) + +declare function g(f: B): U; +>g : Symbol(g, Decl(tupleTypeInference2.ts, 9, 28)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 10, 19)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21)) +>f : Symbol(f, Decl(tupleTypeInference2.ts, 10, 25)) +>B : Symbol(B, Decl(tupleTypeInference2.ts, 5, 37)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 10, 19)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 10, 21)) + +g([[]] as [void[]]); // U: {} +>g : Symbol(g, Decl(tupleTypeInference2.ts, 9, 28)) + +type C = [R[]] | [R[], S]; +>C : Symbol(C, Decl(tupleTypeInference2.ts, 11, 20)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7)) +>S : Symbol(S, Decl(tupleTypeInference2.ts, 13, 9)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 13, 7)) +>S : Symbol(S, Decl(tupleTypeInference2.ts, 13, 9)) + +declare function h(f: C): U; +>h : Symbol(h, Decl(tupleTypeInference2.ts, 13, 32)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 14, 19)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21)) +>f : Symbol(f, Decl(tupleTypeInference2.ts, 14, 25)) +>C : Symbol(C, Decl(tupleTypeInference2.ts, 11, 20)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 14, 19)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21)) +>U : Symbol(U, Decl(tupleTypeInference2.ts, 14, 21)) + +h([[]] as [void[]]); // U: {} +>h : Symbol(h, Decl(tupleTypeInference2.ts, 13, 32)) + +// Repro from #22562 + +type C2 = [R[]] | [R[], void]; +>C2 : Symbol(C2, Decl(tupleTypeInference2.ts, 15, 20)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8)) +>R : Symbol(R, Decl(tupleTypeInference2.ts, 19, 8)) + +declare function h2(f: C2): T; +>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20)) +>f : Symbol(f, Decl(tupleTypeInference2.ts, 20, 23)) +>C2 : Symbol(C2, Decl(tupleTypeInference2.ts, 15, 20)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20)) +>T : Symbol(T, Decl(tupleTypeInference2.ts, 20, 20)) + +h2([[]] as [never[]]); // T: never +>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33)) + +h2([[]] as [void[]]); // T: void +>h2 : Symbol(h2, Decl(tupleTypeInference2.ts, 19, 33)) + diff --git a/tests/baselines/reference/tupleTypeInference2.types b/tests/baselines/reference/tupleTypeInference2.types new file mode 100644 index 0000000000000..acdf1fb64221e --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference2.types @@ -0,0 +1,115 @@ +=== tests/cases/compiler/tupleTypeInference2.ts === +// Repro from #22564 + +type A = [R] | [R, string]; +>A : A +>R : R +>R : R +>R : R + +declare function f(x: A): T; +>f : (x: A) => T +>T : T +>x : A +>A : A +>T : T +>T : T + +f([undefined, ''] as [never, string]); // T: never +>f([undefined, ''] as [never, string]) : never +>f : (x: A) => T +>[undefined, ''] as [never, string] : [never, string] +>[undefined, ''] : [undefined, string] +>undefined : undefined +>'' : "" + +f([undefined, ''] as [void, string]); // T: void +>f([undefined, ''] as [void, string]) : void +>f : (x: A) => T +>[undefined, ''] as [void, string] : [void, string] +>[undefined, ''] : [undefined, string] +>undefined : undefined +>'' : "" + +// Repro from #22563 + +type B = [R] | [R, S]; +>B : B +>R : R +>S : S +>R : R +>R : R +>S : S + +declare function g(f: B): U; +>g : (f: B) => U +>T : T +>U : U +>f : B +>B : B +>T : T +>U : U +>U : U + +g([[]] as [void[]]); // U: {} +>g([[]] as [void[]]) : {} +>g : (f: B) => U +>[[]] as [void[]] : [void[]] +>[[]] : [never[]] +>[] : never[] + +type C = [R[]] | [R[], S]; +>C : C +>R : R +>S : S +>R : R +>R : R +>S : S + +declare function h(f: C): U; +>h : (f: C) => U +>T : T +>U : U +>f : C +>C : C +>T : T +>U : U +>U : U + +h([[]] as [void[]]); // U: {} +>h([[]] as [void[]]) : {} +>h : (f: C) => U +>[[]] as [void[]] : [void[]] +>[[]] : [never[]] +>[] : never[] + +// Repro from #22562 + +type C2 = [R[]] | [R[], void]; +>C2 : C2 +>R : R +>R : R +>R : R + +declare function h2(f: C2): T; +>h2 : (f: C2) => T +>T : T +>f : C2 +>C2 : C2 +>T : T +>T : T + +h2([[]] as [never[]]); // T: never +>h2([[]] as [never[]]) : never +>h2 : (f: C2) => T +>[[]] as [never[]] : [never[]] +>[[]] : [never[]] +>[] : never[] + +h2([[]] as [void[]]); // T: void +>h2([[]] as [void[]]) : void +>h2 : (f: C2) => T +>[[]] as [void[]] : [void[]] +>[[]] : [never[]] +>[] : never[] + diff --git a/tests/cases/compiler/tupleTypeInference2.ts b/tests/cases/compiler/tupleTypeInference2.ts new file mode 100644 index 0000000000000..080d8fc853295 --- /dev/null +++ b/tests/cases/compiler/tupleTypeInference2.ts @@ -0,0 +1,25 @@ +// @strict: true + +// Repro from #22564 + +type A = [R] | [R, string]; +declare function f(x: A): T; +f([undefined, ''] as [never, string]); // T: never +f([undefined, ''] as [void, string]); // T: void + +// Repro from #22563 + +type B = [R] | [R, S]; +declare function g(f: B): U; +g([[]] as [void[]]); // U: {} + +type C = [R[]] | [R[], S]; +declare function h(f: C): U; +h([[]] as [void[]]); // U: {} + +// Repro from #22562 + +type C2 = [R[]] | [R[], void]; +declare function h2(f: C2): T; +h2([[]] as [never[]]); // T: never +h2([[]] as [void[]]); // T: void