Skip to content

Commit 82ea885

Browse files
authored
Merge pull request #31662 from microsoft/fixTypeAliasInference
Fix contravariant type alias inference
2 parents b8dcf27 + bb412ab commit 82ea885

File tree

5 files changed

+171
-17
lines changed

5 files changed

+171
-17
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15171,11 +15171,7 @@ namespace ts {
1517115171
if (source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
1517215172
// Source and target are types originating in the same generic type alias declaration.
1517315173
// Simply infer from source type arguments to target type arguments.
15174-
const sourceTypes = source.aliasTypeArguments;
15175-
const targetTypes = target.aliasTypeArguments!;
15176-
for (let i = 0; i < sourceTypes.length; i++) {
15177-
inferFromTypes(sourceTypes[i], targetTypes[i]);
15178-
}
15174+
inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol));
1517915175
return;
1518015176
}
1518115177
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && !(source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.EnumLiteral) ||
@@ -15281,18 +15277,7 @@ namespace ts {
1528115277
}
1528215278
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
1528315279
// If source and target are references to the same generic type, infer from type arguments
15284-
const sourceTypes = (<TypeReference>source).typeArguments || emptyArray;
15285-
const targetTypes = (<TypeReference>target).typeArguments || emptyArray;
15286-
const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length;
15287-
const variances = getVariances((<TypeReference>source).target);
15288-
for (let i = 0; i < count; i++) {
15289-
if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) {
15290-
inferFromContravariantTypes(sourceTypes[i], targetTypes[i]);
15291-
}
15292-
else {
15293-
inferFromTypes(sourceTypes[i], targetTypes[i]);
15294-
}
15295-
}
15280+
inferFromTypeArguments((<TypeReference>source).typeArguments || emptyArray, (<TypeReference>target).typeArguments || emptyArray, getVariances((<TypeReference>source).target));
1529615281
}
1529715282
else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) {
1529815283
contravariant = !contravariant;
@@ -15412,6 +15397,18 @@ namespace ts {
1541215397
}
1541315398
}
1541415399

15400+
function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) {
15401+
const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length;
15402+
for (let i = 0; i < count; i++) {
15403+
if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) {
15404+
inferFromContravariantTypes(sourceTypes[i], targetTypes[i]);
15405+
}
15406+
else {
15407+
inferFromTypes(sourceTypes[i], targetTypes[i]);
15408+
}
15409+
}
15410+
}
15411+
1541515412
function inferFromContravariantTypes(source: Type, target: Type) {
1541615413
if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) {
1541715414
contravariant = !contravariant;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [contravariantTypeAliasInference.ts]
2+
type Func1<T> = (x: T) => void;
3+
type Func2<T> = ((x: T) => void) | undefined;
4+
5+
declare let f1: Func1<string>;
6+
declare let f2: Func1<"a">;
7+
8+
declare function foo<T>(f1: Func1<T>, f2: Func1<T>): void;
9+
10+
foo(f1, f2);
11+
12+
declare let g1: Func2<string>;
13+
declare let g2: Func2<"a">;
14+
15+
declare function bar<T>(g1: Func2<T>, g2: Func2<T>): void;
16+
17+
bar(f1, f2);
18+
bar(g1, g2);
19+
20+
21+
//// [contravariantTypeAliasInference.js]
22+
"use strict";
23+
foo(f1, f2);
24+
bar(f1, f2);
25+
bar(g1, g2);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=== tests/cases/compiler/contravariantTypeAliasInference.ts ===
2+
type Func1<T> = (x: T) => void;
3+
>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0))
4+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 0, 11))
5+
>x : Symbol(x, Decl(contravariantTypeAliasInference.ts, 0, 17))
6+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 0, 11))
7+
8+
type Func2<T> = ((x: T) => void) | undefined;
9+
>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31))
10+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 1, 11))
11+
>x : Symbol(x, Decl(contravariantTypeAliasInference.ts, 1, 18))
12+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 1, 11))
13+
14+
declare let f1: Func1<string>;
15+
>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11))
16+
>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0))
17+
18+
declare let f2: Func1<"a">;
19+
>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11))
20+
>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0))
21+
22+
declare function foo<T>(f1: Func1<T>, f2: Func1<T>): void;
23+
>foo : Symbol(foo, Decl(contravariantTypeAliasInference.ts, 4, 27))
24+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21))
25+
>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 6, 24))
26+
>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0))
27+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21))
28+
>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 6, 37))
29+
>Func1 : Symbol(Func1, Decl(contravariantTypeAliasInference.ts, 0, 0))
30+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 6, 21))
31+
32+
foo(f1, f2);
33+
>foo : Symbol(foo, Decl(contravariantTypeAliasInference.ts, 4, 27))
34+
>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11))
35+
>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11))
36+
37+
declare let g1: Func2<string>;
38+
>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 10, 11))
39+
>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31))
40+
41+
declare let g2: Func2<"a">;
42+
>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 11, 11))
43+
>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31))
44+
45+
declare function bar<T>(g1: Func2<T>, g2: Func2<T>): void;
46+
>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27))
47+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21))
48+
>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 13, 24))
49+
>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31))
50+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21))
51+
>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 13, 37))
52+
>Func2 : Symbol(Func2, Decl(contravariantTypeAliasInference.ts, 0, 31))
53+
>T : Symbol(T, Decl(contravariantTypeAliasInference.ts, 13, 21))
54+
55+
bar(f1, f2);
56+
>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27))
57+
>f1 : Symbol(f1, Decl(contravariantTypeAliasInference.ts, 3, 11))
58+
>f2 : Symbol(f2, Decl(contravariantTypeAliasInference.ts, 4, 11))
59+
60+
bar(g1, g2);
61+
>bar : Symbol(bar, Decl(contravariantTypeAliasInference.ts, 11, 27))
62+
>g1 : Symbol(g1, Decl(contravariantTypeAliasInference.ts, 10, 11))
63+
>g2 : Symbol(g2, Decl(contravariantTypeAliasInference.ts, 11, 11))
64+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/contravariantTypeAliasInference.ts ===
2+
type Func1<T> = (x: T) => void;
3+
>Func1 : Func1<T>
4+
>x : T
5+
6+
type Func2<T> = ((x: T) => void) | undefined;
7+
>Func2 : Func2<T>
8+
>x : T
9+
10+
declare let f1: Func1<string>;
11+
>f1 : Func1<string>
12+
13+
declare let f2: Func1<"a">;
14+
>f2 : Func1<"a">
15+
16+
declare function foo<T>(f1: Func1<T>, f2: Func1<T>): void;
17+
>foo : <T>(f1: Func1<T>, f2: Func1<T>) => void
18+
>f1 : Func1<T>
19+
>f2 : Func1<T>
20+
21+
foo(f1, f2);
22+
>foo(f1, f2) : void
23+
>foo : <T>(f1: Func1<T>, f2: Func1<T>) => void
24+
>f1 : Func1<string>
25+
>f2 : Func1<"a">
26+
27+
declare let g1: Func2<string>;
28+
>g1 : Func2<string>
29+
30+
declare let g2: Func2<"a">;
31+
>g2 : Func2<"a">
32+
33+
declare function bar<T>(g1: Func2<T>, g2: Func2<T>): void;
34+
>bar : <T>(g1: Func2<T>, g2: Func2<T>) => void
35+
>g1 : Func2<T>
36+
>g2 : Func2<T>
37+
38+
bar(f1, f2);
39+
>bar(f1, f2) : void
40+
>bar : <T>(g1: Func2<T>, g2: Func2<T>) => void
41+
>f1 : Func1<string>
42+
>f2 : Func1<"a">
43+
44+
bar(g1, g2);
45+
>bar(g1, g2) : void
46+
>bar : <T>(g1: Func2<T>, g2: Func2<T>) => void
47+
>g1 : Func2<string>
48+
>g2 : Func2<"a">
49+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @strict: true
2+
3+
type Func1<T> = (x: T) => void;
4+
type Func2<T> = ((x: T) => void) | undefined;
5+
6+
declare let f1: Func1<string>;
7+
declare let f2: Func1<"a">;
8+
9+
declare function foo<T>(f1: Func1<T>, f2: Func1<T>): void;
10+
11+
foo(f1, f2);
12+
13+
declare let g1: Func2<string>;
14+
declare let g2: Func2<"a">;
15+
16+
declare function bar<T>(g1: Func2<T>, g2: Func2<T>): void;
17+
18+
bar(f1, f2);
19+
bar(g1, g2);

0 commit comments

Comments
 (0)