Merge pull request #27357 from Microsoft/fixBivariantInferences
Make contravariant inferences only from pure contravariant positions
This commit is contained in:
commit
d7219b21c2
|
@ -13462,6 +13462,7 @@ namespace ts {
|
|||
let symbolStack: Symbol[];
|
||||
let visited: Map<boolean>;
|
||||
let contravariant = false;
|
||||
let bivariant = false;
|
||||
let propagationType: Type;
|
||||
let allowComplexConstraintInference = true;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
@ -13548,11 +13549,13 @@ namespace ts {
|
|||
}
|
||||
if (priority === inference.priority) {
|
||||
const candidate = propagationType || source;
|
||||
if (contravariant) {
|
||||
inference.contraCandidates = append(inference.contraCandidates, candidate);
|
||||
// We make contravariant inferences only if we are in a pure contravariant position,
|
||||
// i.e. only if we have not descended into a bivariant position.
|
||||
if (contravariant && !bivariant) {
|
||||
inference.contraCandidates = appendIfUnique(inference.contraCandidates, candidate);
|
||||
}
|
||||
else {
|
||||
inference.candidates = append(inference.candidates, candidate);
|
||||
inference.candidates = appendIfUnique(inference.candidates, candidate);
|
||||
}
|
||||
}
|
||||
if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
|
||||
|
@ -13800,7 +13803,12 @@ namespace ts {
|
|||
|
||||
function inferFromSignature(source: Signature, target: Signature, skipParameters: boolean) {
|
||||
if (!skipParameters) {
|
||||
const saveBivariant = bivariant;
|
||||
const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown;
|
||||
// Once we descend into a bivariant signature we remain bivariant for all nested inferences
|
||||
bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor;
|
||||
forEachMatchingParameterType(source, target, inferFromContravariantTypes);
|
||||
bivariant = saveBivariant;
|
||||
}
|
||||
const sourceTypePredicate = getTypePredicateOfSignature(source);
|
||||
const targetTypePredicate = getTypePredicateOfSignature(target);
|
||||
|
|
17
tests/baselines/reference/bivariantInferences.js
Normal file
17
tests/baselines/reference/bivariantInferences.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
//// [bivariantInferences.ts]
|
||||
// Repro from #27337
|
||||
|
||||
interface Array<T> {
|
||||
equalsShallow<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>): boolean;
|
||||
}
|
||||
|
||||
declare const a: (string | number)[] | null[] | undefined[] | {}[];
|
||||
declare const b: (string | number)[] | null[] | undefined[] | {}[];
|
||||
|
||||
let x = a.equalsShallow(b);
|
||||
|
||||
|
||||
//// [bivariantInferences.js]
|
||||
"use strict";
|
||||
// Repro from #27337
|
||||
var x = a.equalsShallow(b);
|
31
tests/baselines/reference/bivariantInferences.symbols
Normal file
31
tests/baselines/reference/bivariantInferences.symbols
Normal file
|
@ -0,0 +1,31 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/typeInference/bivariantInferences.ts ===
|
||||
// Repro from #27337
|
||||
|
||||
interface Array<T> {
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(bivariantInferences.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(lib.es5.d.ts, --, --), Decl(bivariantInferences.ts, 2, 16))
|
||||
|
||||
equalsShallow<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>): boolean;
|
||||
>equalsShallow : Symbol(Array.equalsShallow, Decl(bivariantInferences.ts, 2, 20))
|
||||
>T : Symbol(T, Decl(bivariantInferences.ts, 3, 18))
|
||||
>this : Symbol(this, Decl(bivariantInferences.ts, 3, 21))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(bivariantInferences.ts, 3, 18))
|
||||
>other : Symbol(other, Decl(bivariantInferences.ts, 3, 44))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(bivariantInferences.ts, 3, 18))
|
||||
}
|
||||
|
||||
declare const a: (string | number)[] | null[] | undefined[] | {}[];
|
||||
>a : Symbol(a, Decl(bivariantInferences.ts, 6, 13))
|
||||
|
||||
declare const b: (string | number)[] | null[] | undefined[] | {}[];
|
||||
>b : Symbol(b, Decl(bivariantInferences.ts, 7, 13))
|
||||
|
||||
let x = a.equalsShallow(b);
|
||||
>x : Symbol(x, Decl(bivariantInferences.ts, 9, 3))
|
||||
>a.equalsShallow : Symbol(equalsShallow, Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20))
|
||||
>a : Symbol(a, Decl(bivariantInferences.ts, 6, 13))
|
||||
>equalsShallow : Symbol(equalsShallow, Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20), Decl(bivariantInferences.ts, 2, 20))
|
||||
>b : Symbol(b, Decl(bivariantInferences.ts, 7, 13))
|
||||
|
26
tests/baselines/reference/bivariantInferences.types
Normal file
26
tests/baselines/reference/bivariantInferences.types
Normal file
|
@ -0,0 +1,26 @@
|
|||
=== tests/cases/conformance/types/typeRelationships/typeInference/bivariantInferences.ts ===
|
||||
// Repro from #27337
|
||||
|
||||
interface Array<T> {
|
||||
equalsShallow<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>): boolean;
|
||||
>equalsShallow : <T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean
|
||||
>this : ReadonlyArray<T>
|
||||
>other : ReadonlyArray<T>
|
||||
}
|
||||
|
||||
declare const a: (string | number)[] | null[] | undefined[] | {}[];
|
||||
>a : (string | number)[] | null[] | undefined[] | {}[]
|
||||
>null : null
|
||||
|
||||
declare const b: (string | number)[] | null[] | undefined[] | {}[];
|
||||
>b : (string | number)[] | null[] | undefined[] | {}[]
|
||||
>null : null
|
||||
|
||||
let x = a.equalsShallow(b);
|
||||
>x : boolean
|
||||
>a.equalsShallow(b) : boolean
|
||||
>a.equalsShallow : (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean)
|
||||
>a : (string | number)[] | null[] | undefined[] | {}[]
|
||||
>equalsShallow : (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean) | (<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>) => boolean)
|
||||
>b : (string | number)[] | null[] | undefined[] | {}[]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// @strict: true
|
||||
|
||||
// Repro from #27337
|
||||
|
||||
interface Array<T> {
|
||||
equalsShallow<T>(this: ReadonlyArray<T>, other: ReadonlyArray<T>): boolean;
|
||||
}
|
||||
|
||||
declare const a: (string | number)[] | null[] | undefined[] | {}[];
|
||||
declare const b: (string | number)[] | null[] | undefined[] | {}[];
|
||||
|
||||
let x = a.equalsShallow(b);
|
Loading…
Reference in a new issue