Skip to content

Commit 9e8eaa1

Browse files
🤖 Pick PR #62604 (Propagate variance reliability) into tsgo-port (#62701)
Co-authored-by: Anders Hejlsberg <[email protected]>
1 parent 39a1607 commit 9e8eaa1

File tree

5 files changed

+141
-21
lines changed

5 files changed

+141
-21
lines changed

‎src/compiler/checker.ts‎

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23235,29 +23235,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2323523235
// the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be)
2323623236
related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t);
2323723237
}
23238-
else if (variance === VarianceFlags.Covariant) {
23239-
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23240-
}
23241-
else if (variance === VarianceFlags.Contravariant) {
23242-
related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23243-
}
23244-
else if (variance === VarianceFlags.Bivariant) {
23245-
// In the bivariant case we first compare contravariantly without reporting
23246-
// errors. Then, if that doesn't succeed, we compare covariantly with error
23247-
// reporting. Thus, error elaboration will be based on the the covariant check,
23248-
// which is generally easier to reason about.
23249-
related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false);
23250-
if (!related) {
23238+
else {
23239+
// Propagate unreliable variance flag
23240+
if (inVarianceComputation && varianceFlags & VarianceFlags.Unreliable) {
23241+
instantiateType(s, reportUnreliableMapper);
23242+
}
23243+
if (variance === VarianceFlags.Covariant) {
2325123244
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
2325223245
}
23253-
}
23254-
else {
23255-
// In the invariant case we first compare covariantly, and only when that
23256-
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
23257-
// will typically be based on the covariant check.
23258-
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23259-
if (related) {
23260-
related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23246+
else if (variance === VarianceFlags.Contravariant) {
23247+
related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23248+
}
23249+
else if (variance === VarianceFlags.Bivariant) {
23250+
// In the bivariant case we first compare contravariantly without reporting
23251+
// errors. Then, if that doesn't succeed, we compare covariantly with error
23252+
// reporting. Thus, error elaboration will be based on the the covariant check,
23253+
// which is generally easier to reason about.
23254+
related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false);
23255+
if (!related) {
23256+
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23257+
}
23258+
}
23259+
else {
23260+
// In the invariant case we first compare covariantly, and only when that
23261+
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
23262+
// will typically be based on the covariant check.
23263+
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23264+
if (related) {
23265+
related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
23266+
}
2326123267
}
2326223268
}
2326323269
if (!related) {

‎tests/baselines/reference/circularlySimplifyingConditionalTypesNoCrash.types‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//// [tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts] ////
22

3+
=== Performance Stats ===
4+
Instantiation count: 1,000
5+
36
=== circularlySimplifyingConditionalTypesNoCrash.ts ===
47
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
58
>Omit : Omit<T, K>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//// [tests/cases/compiler/variancePropagation.ts] ////
2+
3+
=== variancePropagation.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/62606
5+
6+
interface DerivedTable<S extends { base: any; new: any }> {
7+
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
8+
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
9+
>base : Symbol(base, Decl(variancePropagation.ts, 2, 34))
10+
>new : Symbol(new, Decl(variancePropagation.ts, 2, 45))
11+
12+
// Error disappears when these property declarations are reversed
13+
schema: S["base"] & S["new"]
14+
>schema : Symbol(DerivedTable.schema, Decl(variancePropagation.ts, 2, 59))
15+
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
16+
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
17+
18+
readonlySchema: Readonly<S["base"] & S["new"]>
19+
>readonlySchema : Symbol(DerivedTable.readonlySchema, Decl(variancePropagation.ts, 4, 32))
20+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
21+
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
22+
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
23+
}
24+
25+
interface Base { baseProp: number; }
26+
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
27+
>baseProp : Symbol(Base.baseProp, Decl(variancePropagation.ts, 8, 16))
28+
29+
interface New { newProp: boolean; }
30+
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
31+
>newProp : Symbol(New.newProp, Decl(variancePropagation.ts, 9, 16))
32+
33+
declare const source: DerivedTable<{ base: Base, new: New }>
34+
>source : Symbol(source, Decl(variancePropagation.ts, 11, 13))
35+
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
36+
>base : Symbol(base, Decl(variancePropagation.ts, 11, 36))
37+
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
38+
>new : Symbol(new, Decl(variancePropagation.ts, 11, 48))
39+
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
40+
41+
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error
42+
>destination : Symbol(destination, Decl(variancePropagation.ts, 12, 5))
43+
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
44+
>base : Symbol(base, Decl(variancePropagation.ts, 12, 33))
45+
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
46+
>new : Symbol(new, Decl(variancePropagation.ts, 12, 45))
47+
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
48+
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
49+
>source : Symbol(source, Decl(variancePropagation.ts, 11, 13))
50+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [tests/cases/compiler/variancePropagation.ts] ////
2+
3+
=== variancePropagation.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/62606
5+
6+
interface DerivedTable<S extends { base: any; new: any }> {
7+
>base : any
8+
>new : any
9+
10+
// Error disappears when these property declarations are reversed
11+
schema: S["base"] & S["new"]
12+
>schema : S["base"] & S["new"]
13+
> : ^^^^^^^^^^^^^^^^^^^^
14+
15+
readonlySchema: Readonly<S["base"] & S["new"]>
16+
>readonlySchema : Readonly<S["base"] & S["new"]>
17+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
}
19+
20+
interface Base { baseProp: number; }
21+
>baseProp : number
22+
> : ^^^^^^
23+
24+
interface New { newProp: boolean; }
25+
>newProp : boolean
26+
> : ^^^^^^^
27+
28+
declare const source: DerivedTable<{ base: Base, new: New }>
29+
>source : DerivedTable<{ base: Base; new: New; }>
30+
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
31+
>base : Base
32+
> : ^^^^
33+
>new : New
34+
> : ^^^
35+
36+
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error
37+
>destination : DerivedTable<{ base: Base; new: New & Base; }>
38+
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
39+
>base : Base
40+
> : ^^^^
41+
>new : New & Base
42+
> : ^^^^^^^^^^
43+
>source : DerivedTable<{ base: Base; new: New; }>
44+
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
45+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/62606
5+
6+
interface DerivedTable<S extends { base: any; new: any }> {
7+
// Error disappears when these property declarations are reversed
8+
schema: S["base"] & S["new"]
9+
readonlySchema: Readonly<S["base"] & S["new"]>
10+
}
11+
12+
interface Base { baseProp: number; }
13+
interface New { newProp: boolean; }
14+
15+
declare const source: DerivedTable<{ base: Base, new: New }>
16+
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error

0 commit comments

Comments
 (0)