Skip to content

Commit

Permalink
Merge pull request #25115 from Microsoft/matchingTypeRefs
Browse files Browse the repository at this point in the history
Improved errors using type reference targets
  • Loading branch information
DanielRosenwasser authored Jun 21, 2018
2 parents 51e7ae0 + 6d755aa commit 72068e2
Show file tree
Hide file tree
Showing 7 changed files with 543 additions and 6 deletions.
24 changes: 22 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10823,12 +10823,32 @@ namespace ts {
}
}
if (reportErrors) {
const discriminantType = findMatchingDiscriminantType(source, target);
isRelatedTo(source, discriminantType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true);
const bestMatchingType =
findMatchingDiscriminantType(source, target) ||
findMatchingTypeReferenceOrTypeAliasReference(source, target);

isRelatedTo(source, bestMatchingType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true);
}
return Ternary.False;
}

function findMatchingTypeReferenceOrTypeAliasReference(source: Type, unionTarget: UnionOrIntersectionType) {
if (source.flags & TypeFlags.Object && (source as ObjectType).objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union) {
return find(unionTarget.types, target => {
if (target.flags & TypeFlags.Object) {
if ((source as ObjectType).objectFlags & (target as ObjectType).objectFlags & ObjectFlags.Reference) {
return (source as TypeReference).target === (target as TypeReference).target;
}
if ((source as ObjectType).objectFlags & (target as ObjectType).objectFlags & ObjectFlags.Anonymous) {
return !!(source as AnonymousType).aliasSymbol && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol;
}
}
return false;
});
}
}


// Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
let match: Type | undefined;
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/for-of39.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,19): error TS2345: Ar
Types of parameters 'items' and 'items' are incompatible.
Type 'ConcatArray<[string, boolean]>' is not assignable to type 'ConcatArray<[string, number] | [string, true]>'.
Type '[string, boolean]' is not assignable to type '[string, number] | [string, true]'.
Type '[string, boolean]' is not assignable to type '[string, true]'.
Type 'boolean' is not assignable to type 'true'.
Type '[string, boolean]' is not assignable to type '[string, number]'.
Type 'boolean' is not assignable to type 'number'.


==== tests/cases/conformance/es6/for-ofStatements/for-of39.ts (1 errors) ====
Expand All @@ -17,8 +17,8 @@ tests/cases/conformance/es6/for-ofStatements/for-of39.ts(1,19): error TS2345: Ar
!!! error TS2345: Types of parameters 'items' and 'items' are incompatible.
!!! error TS2345: Type 'ConcatArray<[string, boolean]>' is not assignable to type 'ConcatArray<[string, number] | [string, true]>'.
!!! error TS2345: Type '[string, boolean]' is not assignable to type '[string, number] | [string, true]'.
!!! error TS2345: Type '[string, boolean]' is not assignable to type '[string, true]'.
!!! error TS2345: Type 'boolean' is not assignable to type 'true'.
!!! error TS2345: Type '[string, boolean]' is not assignable to type '[string, number]'.
!!! error TS2345: Type 'boolean' is not assignable to type 'number'.
for (var [k, v] of map) {
k;
v;
Expand Down
107 changes: 107 additions & 0 deletions tests/baselines/reference/unionTypeErrorMessageTypeRefs01.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(25,1): error TS2322: Type 'A<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
Type 'A<Foo>' is not assignable to type 'A<Bar>'.
Type 'Foo' is not assignable to type 'Bar'.
Property 'bar' is missing in type 'Foo'.
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(26,1): error TS2322: Type 'B<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
Type 'B<Foo>' is not assignable to type 'B<Baz>'.
Type 'Foo' is not assignable to type 'Baz'.
Property 'baz' is missing in type 'Foo'.
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(27,1): error TS2322: Type 'C<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
Type 'C<Foo>' is not assignable to type 'C<Kwah>'.
Type 'Foo' is not assignable to type 'Kwah'.
Property 'kwah' is missing in type 'Foo'.
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(48,1): error TS2322: Type 'X<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
Type 'X<Foo>' is not assignable to type 'X<Bar>'.
Types of property 'xProp' are incompatible.
Type 'Foo' is not assignable to type 'Bar'.
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(49,1): error TS2322: Type 'Y<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
Type 'Y<Foo>' is not assignable to type 'Y<Baz>'.
Types of property 'yProp' are incompatible.
Type 'Foo' is not assignable to type 'Baz'.
tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts(50,1): error TS2322: Type 'Z<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
Type 'Z<Foo>' is not assignable to type 'Z<Kwah>'.
Types of property 'zProp' are incompatible.
Type 'Foo' is not assignable to type 'Kwah'.


==== tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts (6 errors) ====
interface Foo { foo: any }
interface Bar { bar: any }
interface Baz { baz: any }
interface Kwah { kwah: any }

////////

interface A<T> {
aProp: T;
}

interface B<T> {
bProp: T;
}

interface C<T> {
cProp: T;
}

declare const a: A<Foo>;
declare const b: B<Foo>;
declare const c: C<Foo>;
declare let thingOfInterfaces: A<Bar> | B<Baz> | C<Kwah>;

thingOfInterfaces = a;
~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'A<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
!!! error TS2322: Type 'A<Foo>' is not assignable to type 'A<Bar>'.
!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'.
!!! error TS2322: Property 'bar' is missing in type 'Foo'.
thingOfInterfaces = b;
~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'B<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
!!! error TS2322: Type 'B<Foo>' is not assignable to type 'B<Baz>'.
!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'.
!!! error TS2322: Property 'baz' is missing in type 'Foo'.
thingOfInterfaces = c;
~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'C<Foo>' is not assignable to type 'A<Bar> | B<Baz> | C<Kwah>'.
!!! error TS2322: Type 'C<Foo>' is not assignable to type 'C<Kwah>'.
!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'.
!!! error TS2322: Property 'kwah' is missing in type 'Foo'.

////////

type X<T> = {
xProp: T;
}

type Y<T> = {
yProp: T;
}

type Z<T> = {
zProp: T;
}

declare const x: X<Foo>;
declare const y: Y<Foo>;
declare const z: Z<Foo>;
declare let thingOfTypeAliases: X<Bar> | Y<Baz> | Z<Kwah>;

thingOfTypeAliases = x;
~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'X<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
!!! error TS2322: Type 'X<Foo>' is not assignable to type 'X<Bar>'.
!!! error TS2322: Types of property 'xProp' are incompatible.
!!! error TS2322: Type 'Foo' is not assignable to type 'Bar'.
thingOfTypeAliases = y;
~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'Y<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
!!! error TS2322: Type 'Y<Foo>' is not assignable to type 'Y<Baz>'.
!!! error TS2322: Types of property 'yProp' are incompatible.
!!! error TS2322: Type 'Foo' is not assignable to type 'Baz'.
thingOfTypeAliases = z;
~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'Z<Foo>' is not assignable to type 'X<Bar> | Y<Baz> | Z<Kwah>'.
!!! error TS2322: Type 'Z<Foo>' is not assignable to type 'Z<Kwah>'.
!!! error TS2322: Types of property 'zProp' are incompatible.
!!! error TS2322: Type 'Foo' is not assignable to type 'Kwah'.
59 changes: 59 additions & 0 deletions tests/baselines/reference/unionTypeErrorMessageTypeRefs01.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//// [unionTypeErrorMessageTypeRefs01.ts]
interface Foo { foo: any }
interface Bar { bar: any }
interface Baz { baz: any }
interface Kwah { kwah: any }

////////

interface A<T> {
aProp: T;
}

interface B<T> {
bProp: T;
}

interface C<T> {
cProp: T;
}

declare const a: A<Foo>;
declare const b: B<Foo>;
declare const c: C<Foo>;
declare let thingOfInterfaces: A<Bar> | B<Baz> | C<Kwah>;

thingOfInterfaces = a;
thingOfInterfaces = b;
thingOfInterfaces = c;

////////

type X<T> = {
xProp: T;
}

type Y<T> = {
yProp: T;
}

type Z<T> = {
zProp: T;
}

declare const x: X<Foo>;
declare const y: Y<Foo>;
declare const z: Z<Foo>;
declare let thingOfTypeAliases: X<Bar> | Y<Baz> | Z<Kwah>;

thingOfTypeAliases = x;
thingOfTypeAliases = y;
thingOfTypeAliases = z;

//// [unionTypeErrorMessageTypeRefs01.js]
thingOfInterfaces = a;
thingOfInterfaces = b;
thingOfInterfaces = c;
thingOfTypeAliases = x;
thingOfTypeAliases = y;
thingOfTypeAliases = z;
147 changes: 147 additions & 0 deletions tests/baselines/reference/unionTypeErrorMessageTypeRefs01.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
=== tests/cases/compiler/unionTypeErrorMessageTypeRefs01.ts ===
interface Foo { foo: any }
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))
>foo : Symbol(Foo.foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 15))

interface Bar { bar: any }
>Bar : Symbol(Bar, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 26))
>bar : Symbol(Bar.bar, Decl(unionTypeErrorMessageTypeRefs01.ts, 1, 15))

interface Baz { baz: any }
>Baz : Symbol(Baz, Decl(unionTypeErrorMessageTypeRefs01.ts, 1, 26))
>baz : Symbol(Baz.baz, Decl(unionTypeErrorMessageTypeRefs01.ts, 2, 15))

interface Kwah { kwah: any }
>Kwah : Symbol(Kwah, Decl(unionTypeErrorMessageTypeRefs01.ts, 2, 26))
>kwah : Symbol(Kwah.kwah, Decl(unionTypeErrorMessageTypeRefs01.ts, 3, 16))

////////

interface A<T> {
>A : Symbol(A, Decl(unionTypeErrorMessageTypeRefs01.ts, 3, 28))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 7, 12))

aProp: T;
>aProp : Symbol(A.aProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 7, 16))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 7, 12))
}

interface B<T> {
>B : Symbol(B, Decl(unionTypeErrorMessageTypeRefs01.ts, 9, 1))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 11, 12))

bProp: T;
>bProp : Symbol(B.bProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 11, 16))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 11, 12))
}

interface C<T> {
>C : Symbol(C, Decl(unionTypeErrorMessageTypeRefs01.ts, 13, 1))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 15, 12))

cProp: T;
>cProp : Symbol(C.cProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 15, 16))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 15, 12))
}

declare const a: A<Foo>;
>a : Symbol(a, Decl(unionTypeErrorMessageTypeRefs01.ts, 19, 13))
>A : Symbol(A, Decl(unionTypeErrorMessageTypeRefs01.ts, 3, 28))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare const b: B<Foo>;
>b : Symbol(b, Decl(unionTypeErrorMessageTypeRefs01.ts, 20, 13))
>B : Symbol(B, Decl(unionTypeErrorMessageTypeRefs01.ts, 9, 1))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare const c: C<Foo>;
>c : Symbol(c, Decl(unionTypeErrorMessageTypeRefs01.ts, 21, 13))
>C : Symbol(C, Decl(unionTypeErrorMessageTypeRefs01.ts, 13, 1))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare let thingOfInterfaces: A<Bar> | B<Baz> | C<Kwah>;
>thingOfInterfaces : Symbol(thingOfInterfaces, Decl(unionTypeErrorMessageTypeRefs01.ts, 22, 11))
>A : Symbol(A, Decl(unionTypeErrorMessageTypeRefs01.ts, 3, 28))
>Bar : Symbol(Bar, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 26))
>B : Symbol(B, Decl(unionTypeErrorMessageTypeRefs01.ts, 9, 1))
>Baz : Symbol(Baz, Decl(unionTypeErrorMessageTypeRefs01.ts, 1, 26))
>C : Symbol(C, Decl(unionTypeErrorMessageTypeRefs01.ts, 13, 1))
>Kwah : Symbol(Kwah, Decl(unionTypeErrorMessageTypeRefs01.ts, 2, 26))

thingOfInterfaces = a;
>thingOfInterfaces : Symbol(thingOfInterfaces, Decl(unionTypeErrorMessageTypeRefs01.ts, 22, 11))
>a : Symbol(a, Decl(unionTypeErrorMessageTypeRefs01.ts, 19, 13))

thingOfInterfaces = b;
>thingOfInterfaces : Symbol(thingOfInterfaces, Decl(unionTypeErrorMessageTypeRefs01.ts, 22, 11))
>b : Symbol(b, Decl(unionTypeErrorMessageTypeRefs01.ts, 20, 13))

thingOfInterfaces = c;
>thingOfInterfaces : Symbol(thingOfInterfaces, Decl(unionTypeErrorMessageTypeRefs01.ts, 22, 11))
>c : Symbol(c, Decl(unionTypeErrorMessageTypeRefs01.ts, 21, 13))

////////

type X<T> = {
>X : Symbol(X, Decl(unionTypeErrorMessageTypeRefs01.ts, 26, 22))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 30, 7))

xProp: T;
>xProp : Symbol(xProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 30, 13))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 30, 7))
}

type Y<T> = {
>Y : Symbol(Y, Decl(unionTypeErrorMessageTypeRefs01.ts, 32, 1))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 34, 7))

yProp: T;
>yProp : Symbol(yProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 34, 13))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 34, 7))
}

type Z<T> = {
>Z : Symbol(Z, Decl(unionTypeErrorMessageTypeRefs01.ts, 36, 1))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 38, 7))

zProp: T;
>zProp : Symbol(zProp, Decl(unionTypeErrorMessageTypeRefs01.ts, 38, 13))
>T : Symbol(T, Decl(unionTypeErrorMessageTypeRefs01.ts, 38, 7))
}

declare const x: X<Foo>;
>x : Symbol(x, Decl(unionTypeErrorMessageTypeRefs01.ts, 42, 13))
>X : Symbol(X, Decl(unionTypeErrorMessageTypeRefs01.ts, 26, 22))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare const y: Y<Foo>;
>y : Symbol(y, Decl(unionTypeErrorMessageTypeRefs01.ts, 43, 13))
>Y : Symbol(Y, Decl(unionTypeErrorMessageTypeRefs01.ts, 32, 1))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare const z: Z<Foo>;
>z : Symbol(z, Decl(unionTypeErrorMessageTypeRefs01.ts, 44, 13))
>Z : Symbol(Z, Decl(unionTypeErrorMessageTypeRefs01.ts, 36, 1))
>Foo : Symbol(Foo, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 0))

declare let thingOfTypeAliases: X<Bar> | Y<Baz> | Z<Kwah>;
>thingOfTypeAliases : Symbol(thingOfTypeAliases, Decl(unionTypeErrorMessageTypeRefs01.ts, 45, 11))
>X : Symbol(X, Decl(unionTypeErrorMessageTypeRefs01.ts, 26, 22))
>Bar : Symbol(Bar, Decl(unionTypeErrorMessageTypeRefs01.ts, 0, 26))
>Y : Symbol(Y, Decl(unionTypeErrorMessageTypeRefs01.ts, 32, 1))
>Baz : Symbol(Baz, Decl(unionTypeErrorMessageTypeRefs01.ts, 1, 26))
>Z : Symbol(Z, Decl(unionTypeErrorMessageTypeRefs01.ts, 36, 1))
>Kwah : Symbol(Kwah, Decl(unionTypeErrorMessageTypeRefs01.ts, 2, 26))

thingOfTypeAliases = x;
>thingOfTypeAliases : Symbol(thingOfTypeAliases, Decl(unionTypeErrorMessageTypeRefs01.ts, 45, 11))
>x : Symbol(x, Decl(unionTypeErrorMessageTypeRefs01.ts, 42, 13))

thingOfTypeAliases = y;
>thingOfTypeAliases : Symbol(thingOfTypeAliases, Decl(unionTypeErrorMessageTypeRefs01.ts, 45, 11))
>y : Symbol(y, Decl(unionTypeErrorMessageTypeRefs01.ts, 43, 13))

thingOfTypeAliases = z;
>thingOfTypeAliases : Symbol(thingOfTypeAliases, Decl(unionTypeErrorMessageTypeRefs01.ts, 45, 11))
>z : Symbol(z, Decl(unionTypeErrorMessageTypeRefs01.ts, 44, 13))

Loading

0 comments on commit 72068e2

Please sign in to comment.