Merge pull request #19774 from Microsoft/fixInvariantGenericErrors
Fix invariant generic error elaboration logic
This commit is contained in:
commit
7a4808a89e
6 changed files with 273 additions and 2 deletions
|
@ -9451,6 +9451,7 @@ namespace ts {
|
||||||
|
|
||||||
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||||
let result: Ternary;
|
let result: Ternary;
|
||||||
|
let originalErrorInfo: DiagnosticMessageChain;
|
||||||
const saveErrorInfo = errorInfo;
|
const saveErrorInfo = errorInfo;
|
||||||
if (target.flags & TypeFlags.TypeParameter) {
|
if (target.flags & TypeFlags.TypeParameter) {
|
||||||
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
|
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
|
||||||
|
@ -9530,6 +9531,7 @@ namespace ts {
|
||||||
// if we have indexed access types with identical index types, see if relationship holds for
|
// if we have indexed access types with identical index types, see if relationship holds for
|
||||||
// the two object types.
|
// the two object types.
|
||||||
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
|
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
|
||||||
|
errorInfo = saveErrorInfo;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9561,6 +9563,10 @@ namespace ts {
|
||||||
if (!(reportErrors && some(variances, v => v === Variance.Invariant))) {
|
if (!(reportErrors && some(variances, v => v === Variance.Invariant))) {
|
||||||
return Ternary.False;
|
return Ternary.False;
|
||||||
}
|
}
|
||||||
|
// We remember the original error information so we can restore it in case the structural
|
||||||
|
// comparison unexpectedly succeeds. This can happen when the structural comparison result
|
||||||
|
// is a Ternary.Maybe for example caused by the recursion depth limiter.
|
||||||
|
originalErrorInfo = errorInfo;
|
||||||
errorInfo = saveErrorInfo;
|
errorInfo = saveErrorInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9599,8 +9605,11 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
errorInfo = saveErrorInfo;
|
if (!originalErrorInfo) {
|
||||||
return result;
|
errorInfo = saveErrorInfo;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
errorInfo = originalErrorInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||||
|
Types of property 'constraint' are incompatible.
|
||||||
|
Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
|
||||||
|
Types of property 'constraint' are incompatible.
|
||||||
|
Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
|
||||||
|
Types of property 'constraint' are incompatible.
|
||||||
|
Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
|
||||||
|
Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
|
||||||
|
Types of property 'underlying' are incompatible.
|
||||||
|
Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
|
||||||
|
tests/cases/compiler/invariantGenericErrorElaboration.ts(4,17): error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype<any>; }'.
|
||||||
|
Property 'foo' is incompatible with index signature.
|
||||||
|
Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ====
|
||||||
|
// Repro from #19746
|
||||||
|
|
||||||
|
const wat: Runtype<any> = Num;
|
||||||
|
~~~
|
||||||
|
!!! error TS2322: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||||
|
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||||
|
!!! error TS2322: Type 'Constraint<Num>' is not assignable to type 'Constraint<Runtype<any>>'.
|
||||||
|
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||||
|
!!! error TS2322: Type 'Constraint<Constraint<Num>>' is not assignable to type 'Constraint<Constraint<Runtype<any>>>'.
|
||||||
|
!!! error TS2322: Types of property 'constraint' are incompatible.
|
||||||
|
!!! error TS2322: Type 'Constraint<Constraint<Constraint<Num>>>' is not assignable to type 'Constraint<Constraint<Constraint<Runtype<any>>>>'.
|
||||||
|
!!! error TS2322: Type 'Constraint<Constraint<Runtype<any>>>' is not assignable to type 'Constraint<Constraint<Num>>'.
|
||||||
|
!!! error TS2322: Types of property 'underlying' are incompatible.
|
||||||
|
!!! error TS2322: Type 'Constraint<Runtype<any>>' is not assignable to type 'Constraint<Num>'.
|
||||||
|
const Foo = Obj({ foo: Num })
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
!!! error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype<any>; }'.
|
||||||
|
!!! error TS2345: Property 'foo' is incompatible with index signature.
|
||||||
|
!!! error TS2345: Type 'Num' is not assignable to type 'Runtype<any>'.
|
||||||
|
|
||||||
|
interface Runtype<A> {
|
||||||
|
constraint: Constraint<this>
|
||||||
|
witness: A
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Num extends Runtype<number> {
|
||||||
|
tag: 'number'
|
||||||
|
}
|
||||||
|
declare const Num: Num
|
||||||
|
|
||||||
|
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||||
|
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||||
|
|
||||||
|
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||||
|
underlying: A,
|
||||||
|
check: (x: A['witness']) => void,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
//// [invariantGenericErrorElaboration.ts]
|
||||||
|
// Repro from #19746
|
||||||
|
|
||||||
|
const wat: Runtype<any> = Num;
|
||||||
|
const Foo = Obj({ foo: Num })
|
||||||
|
|
||||||
|
interface Runtype<A> {
|
||||||
|
constraint: Constraint<this>
|
||||||
|
witness: A
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Num extends Runtype<number> {
|
||||||
|
tag: 'number'
|
||||||
|
}
|
||||||
|
declare const Num: Num
|
||||||
|
|
||||||
|
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||||
|
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||||
|
|
||||||
|
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||||
|
underlying: A,
|
||||||
|
check: (x: A['witness']) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// [invariantGenericErrorElaboration.js]
|
||||||
|
"use strict";
|
||||||
|
// Repro from #19746
|
||||||
|
var wat = Num;
|
||||||
|
var Foo = Obj({ foo: Num });
|
|
@ -0,0 +1,76 @@
|
||||||
|
=== tests/cases/compiler/invariantGenericErrorElaboration.ts ===
|
||||||
|
// Repro from #19746
|
||||||
|
|
||||||
|
const wat: Runtype<any> = Num;
|
||||||
|
>wat : Symbol(wat, Decl(invariantGenericErrorElaboration.ts, 2, 5))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
|
||||||
|
|
||||||
|
const Foo = Obj({ foo: Num })
|
||||||
|
>Foo : Symbol(Foo, Decl(invariantGenericErrorElaboration.ts, 3, 5))
|
||||||
|
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
|
||||||
|
>foo : Symbol(foo, Decl(invariantGenericErrorElaboration.ts, 3, 17))
|
||||||
|
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
|
||||||
|
|
||||||
|
interface Runtype<A> {
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18))
|
||||||
|
|
||||||
|
constraint: Constraint<this>
|
||||||
|
>constraint : Symbol(Runtype.constraint, Decl(invariantGenericErrorElaboration.ts, 5, 22))
|
||||||
|
>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81))
|
||||||
|
|
||||||
|
witness: A
|
||||||
|
>witness : Symbol(Runtype.witness, Decl(invariantGenericErrorElaboration.ts, 6, 30))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Num extends Runtype<number> {
|
||||||
|
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
|
||||||
|
tag: 'number'
|
||||||
|
>tag : Symbol(Num.tag, Decl(invariantGenericErrorElaboration.ts, 10, 39))
|
||||||
|
}
|
||||||
|
declare const Num: Num
|
||||||
|
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
|
||||||
|
>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13))
|
||||||
|
|
||||||
|
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||||
|
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
|
||||||
|
>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 15, 27))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14))
|
||||||
|
>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75))
|
||||||
|
|
||||||
|
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||||
|
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
|
||||||
|
>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 16, 34))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>fields : Symbol(fields, Decl(invariantGenericErrorElaboration.ts, 16, 62))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
|
||||||
|
>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111))
|
||||||
|
>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21))
|
||||||
|
|
||||||
|
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||||
|
>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
|
||||||
|
|
||||||
|
underlying: A,
|
||||||
|
>underlying : Symbol(Constraint.underlying, Decl(invariantGenericErrorElaboration.ts, 18, 76))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
|
||||||
|
|
||||||
|
check: (x: A['witness']) => void,
|
||||||
|
>check : Symbol(Constraint.check, Decl(invariantGenericErrorElaboration.ts, 19, 16))
|
||||||
|
>x : Symbol(x, Decl(invariantGenericErrorElaboration.ts, 20, 10))
|
||||||
|
>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
=== tests/cases/compiler/invariantGenericErrorElaboration.ts ===
|
||||||
|
// Repro from #19746
|
||||||
|
|
||||||
|
const wat: Runtype<any> = Num;
|
||||||
|
>wat : Runtype<any>
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>Num : Num
|
||||||
|
|
||||||
|
const Foo = Obj({ foo: Num })
|
||||||
|
>Foo : any
|
||||||
|
>Obj({ foo: Num }) : any
|
||||||
|
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
|
||||||
|
>{ foo: Num } : { foo: Num; }
|
||||||
|
>foo : Num
|
||||||
|
>Num : Num
|
||||||
|
|
||||||
|
interface Runtype<A> {
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>A : A
|
||||||
|
|
||||||
|
constraint: Constraint<this>
|
||||||
|
>constraint : Constraint<this>
|
||||||
|
>Constraint : Constraint<A>
|
||||||
|
|
||||||
|
witness: A
|
||||||
|
>witness : A
|
||||||
|
>A : A
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Num extends Runtype<number> {
|
||||||
|
>Num : Num
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
|
||||||
|
tag: 'number'
|
||||||
|
>tag : "number"
|
||||||
|
}
|
||||||
|
declare const Num: Num
|
||||||
|
>Num : Num
|
||||||
|
>Num : Num
|
||||||
|
|
||||||
|
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||||
|
>Obj : Obj<O>
|
||||||
|
>O : O
|
||||||
|
>_ : _
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>K : K
|
||||||
|
>O : O
|
||||||
|
>O : O
|
||||||
|
>K : K
|
||||||
|
|
||||||
|
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||||
|
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
|
||||||
|
>O : O
|
||||||
|
>_ : string
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>fields : O
|
||||||
|
>O : O
|
||||||
|
>Obj : Obj<O>
|
||||||
|
>O : O
|
||||||
|
|
||||||
|
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||||
|
>Constraint : Constraint<A>
|
||||||
|
>A : A
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>Runtype : Runtype<A>
|
||||||
|
>A : A
|
||||||
|
|
||||||
|
underlying: A,
|
||||||
|
>underlying : A
|
||||||
|
>A : A
|
||||||
|
|
||||||
|
check: (x: A['witness']) => void,
|
||||||
|
>check : (x: A["witness"]) => void
|
||||||
|
>x : A["witness"]
|
||||||
|
>A : A
|
||||||
|
}
|
||||||
|
|
24
tests/cases/compiler/invariantGenericErrorElaboration.ts
Normal file
24
tests/cases/compiler/invariantGenericErrorElaboration.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// @strict: true
|
||||||
|
|
||||||
|
// Repro from #19746
|
||||||
|
|
||||||
|
const wat: Runtype<any> = Num;
|
||||||
|
const Foo = Obj({ foo: Num })
|
||||||
|
|
||||||
|
interface Runtype<A> {
|
||||||
|
constraint: Constraint<this>
|
||||||
|
witness: A
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Num extends Runtype<number> {
|
||||||
|
tag: 'number'
|
||||||
|
}
|
||||||
|
declare const Num: Num
|
||||||
|
|
||||||
|
interface Obj<O extends { [_ in string]: Runtype<any> }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {}
|
||||||
|
declare function Obj<O extends { [_: string]: Runtype<any> }>(fields: O): Obj<O>;
|
||||||
|
|
||||||
|
interface Constraint<A extends Runtype<any>> extends Runtype<A['witness']> {
|
||||||
|
underlying: A,
|
||||||
|
check: (x: A['witness']) => void,
|
||||||
|
}
|
Loading…
Reference in a new issue