mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-10 00:20:22 -06:00
Propagate variance reliability (#62604)
This commit is contained in:
parent
9222837872
commit
cc05d940a2
@ -23190,29 +23190,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be)
|
||||
related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t);
|
||||
}
|
||||
else if (variance === VarianceFlags.Covariant) {
|
||||
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
else if (variance === VarianceFlags.Contravariant) {
|
||||
related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
else if (variance === VarianceFlags.Bivariant) {
|
||||
// In the bivariant case we first compare contravariantly without reporting
|
||||
// errors. Then, if that doesn't succeed, we compare covariantly with error
|
||||
// reporting. Thus, error elaboration will be based on the the covariant check,
|
||||
// which is generally easier to reason about.
|
||||
related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false);
|
||||
if (!related) {
|
||||
else {
|
||||
// Propagate unreliable variance flag
|
||||
if (inVarianceComputation && varianceFlags & VarianceFlags.Unreliable) {
|
||||
instantiateType(s, reportUnreliableMapper);
|
||||
}
|
||||
if (variance === VarianceFlags.Covariant) {
|
||||
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// In the invariant case we first compare covariantly, and only when that
|
||||
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
|
||||
// will typically be based on the covariant check.
|
||||
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
if (related) {
|
||||
related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
else if (variance === VarianceFlags.Contravariant) {
|
||||
related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
else if (variance === VarianceFlags.Bivariant) {
|
||||
// In the bivariant case we first compare contravariantly without reporting
|
||||
// errors. Then, if that doesn't succeed, we compare covariantly with error
|
||||
// reporting. Thus, error elaboration will be based on the the covariant check,
|
||||
// which is generally easier to reason about.
|
||||
related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false);
|
||||
if (!related) {
|
||||
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// In the invariant case we first compare covariantly, and only when that
|
||||
// succeeds do we proceed to compare contravariantly. Thus, error elaboration
|
||||
// will typically be based on the covariant check.
|
||||
related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
if (related) {
|
||||
related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!related) {
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
//// [tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts] ////
|
||||
|
||||
=== Performance Stats ===
|
||||
Instantiation count: 1,000
|
||||
|
||||
=== circularlySimplifyingConditionalTypesNoCrash.ts ===
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
>Omit : Omit<T, K>
|
||||
|
||||
50
tests/baselines/reference/variancePropagation.symbols
Normal file
50
tests/baselines/reference/variancePropagation.symbols
Normal file
@ -0,0 +1,50 @@
|
||||
//// [tests/cases/compiler/variancePropagation.ts] ////
|
||||
|
||||
=== variancePropagation.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/62606
|
||||
|
||||
interface DerivedTable<S extends { base: any; new: any }> {
|
||||
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
|
||||
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
|
||||
>base : Symbol(base, Decl(variancePropagation.ts, 2, 34))
|
||||
>new : Symbol(new, Decl(variancePropagation.ts, 2, 45))
|
||||
|
||||
// Error disappears when these property declarations are reversed
|
||||
schema: S["base"] & S["new"]
|
||||
>schema : Symbol(DerivedTable.schema, Decl(variancePropagation.ts, 2, 59))
|
||||
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
|
||||
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
|
||||
|
||||
readonlySchema: Readonly<S["base"] & S["new"]>
|
||||
>readonlySchema : Symbol(DerivedTable.readonlySchema, Decl(variancePropagation.ts, 4, 32))
|
||||
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
|
||||
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
|
||||
>S : Symbol(S, Decl(variancePropagation.ts, 2, 23))
|
||||
}
|
||||
|
||||
interface Base { baseProp: number; }
|
||||
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
|
||||
>baseProp : Symbol(Base.baseProp, Decl(variancePropagation.ts, 8, 16))
|
||||
|
||||
interface New { newProp: boolean; }
|
||||
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
|
||||
>newProp : Symbol(New.newProp, Decl(variancePropagation.ts, 9, 16))
|
||||
|
||||
declare const source: DerivedTable<{ base: Base, new: New }>
|
||||
>source : Symbol(source, Decl(variancePropagation.ts, 11, 13))
|
||||
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
|
||||
>base : Symbol(base, Decl(variancePropagation.ts, 11, 36))
|
||||
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
|
||||
>new : Symbol(new, Decl(variancePropagation.ts, 11, 48))
|
||||
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
|
||||
|
||||
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error
|
||||
>destination : Symbol(destination, Decl(variancePropagation.ts, 12, 5))
|
||||
>DerivedTable : Symbol(DerivedTable, Decl(variancePropagation.ts, 0, 0))
|
||||
>base : Symbol(base, Decl(variancePropagation.ts, 12, 33))
|
||||
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
|
||||
>new : Symbol(new, Decl(variancePropagation.ts, 12, 45))
|
||||
>New : Symbol(New, Decl(variancePropagation.ts, 8, 36))
|
||||
>Base : Symbol(Base, Decl(variancePropagation.ts, 6, 1))
|
||||
>source : Symbol(source, Decl(variancePropagation.ts, 11, 13))
|
||||
|
||||
45
tests/baselines/reference/variancePropagation.types
Normal file
45
tests/baselines/reference/variancePropagation.types
Normal file
@ -0,0 +1,45 @@
|
||||
//// [tests/cases/compiler/variancePropagation.ts] ////
|
||||
|
||||
=== variancePropagation.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/62606
|
||||
|
||||
interface DerivedTable<S extends { base: any; new: any }> {
|
||||
>base : any
|
||||
>new : any
|
||||
|
||||
// Error disappears when these property declarations are reversed
|
||||
schema: S["base"] & S["new"]
|
||||
>schema : S["base"] & S["new"]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
readonlySchema: Readonly<S["base"] & S["new"]>
|
||||
>readonlySchema : Readonly<S["base"] & S["new"]>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
|
||||
interface Base { baseProp: number; }
|
||||
>baseProp : number
|
||||
> : ^^^^^^
|
||||
|
||||
interface New { newProp: boolean; }
|
||||
>newProp : boolean
|
||||
> : ^^^^^^^
|
||||
|
||||
declare const source: DerivedTable<{ base: Base, new: New }>
|
||||
>source : DerivedTable<{ base: Base; new: New; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
|
||||
>base : Base
|
||||
> : ^^^^
|
||||
>new : New
|
||||
> : ^^^
|
||||
|
||||
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error
|
||||
>destination : DerivedTable<{ base: Base; new: New & Base; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
|
||||
>base : Base
|
||||
> : ^^^^
|
||||
>new : New & Base
|
||||
> : ^^^^^^^^^^
|
||||
>source : DerivedTable<{ base: Base; new: New; }>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^
|
||||
|
||||
16
tests/cases/compiler/variancePropagation.ts
Normal file
16
tests/cases/compiler/variancePropagation.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/62606
|
||||
|
||||
interface DerivedTable<S extends { base: any; new: any }> {
|
||||
// Error disappears when these property declarations are reversed
|
||||
schema: S["base"] & S["new"]
|
||||
readonlySchema: Readonly<S["base"] & S["new"]>
|
||||
}
|
||||
|
||||
interface Base { baseProp: number; }
|
||||
interface New { newProp: boolean; }
|
||||
|
||||
declare const source: DerivedTable<{ base: Base, new: New }>
|
||||
const destination: DerivedTable<{ base: Base; new: New & Base }> = source; // Error
|
||||
Loading…
x
Reference in New Issue
Block a user