Merge pull request #19774 from Microsoft/fixInvariantGenericErrors

Fix invariant generic error elaboration logic
This commit is contained in:
Anders Hejlsberg 2017-11-06 10:42:32 -08:00 committed by GitHub
commit 7a4808a89e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 273 additions and 2 deletions

View file

@ -9451,6 +9451,7 @@ namespace ts {
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
let result: Ternary;
let originalErrorInfo: DiagnosticMessageChain;
const saveErrorInfo = errorInfo;
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].
@ -9530,6 +9531,7 @@ namespace ts {
// if we have indexed access types with identical index types, see if relationship holds for
// the two object types.
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
@ -9561,6 +9563,10 @@ namespace ts {
if (!(reportErrors && some(variances, v => v === Variance.Invariant))) {
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;
}
}
@ -9599,8 +9605,11 @@ namespace ts {
}
}
if (result) {
errorInfo = saveErrorInfo;
return result;
if (!originalErrorInfo) {
errorInfo = saveErrorInfo;
return result;
}
errorInfo = originalErrorInfo;
}
}
}

View file

@ -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,
}

View file

@ -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 });

View file

@ -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))
}

View file

@ -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
}

View 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,
}