From 65790d16637a7a83146b5b07ea95672dc77052e6 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 14 Apr 2015 17:48:56 -0700 Subject: [PATCH 1/4] Check assignability recursively when source is type parameter with union constraint --- src/compiler/checker.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e9430a058f..1b5bf8a654 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4067,10 +4067,17 @@ module ts { let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; // identity relation does not use apparent type let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); - if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType && - (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors))) { - errorInfo = saveErrorInfo; - return result; + if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { + if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { + if (result = isRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } } } if (reportErrors) { From 1d8fb49f4c3dee7b7d46f47a9e57a958eca830a7 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 15 Apr 2015 11:41:02 -0700 Subject: [PATCH 2/4] Source type parameter extending union works even when target is a type parameter --- src/compiler/checker.ts | 48 +++++++++---------- .../reference/typeParameterDiamond1.js | 28 +++++++++++ .../reference/typeParameterDiamond1.types | 48 +++++++++++++++++++ .../typeParameterDiamond2.errors.txt | 28 +++++++++++ .../reference/typeParameterDiamond2.js | 28 +++++++++++ .../typeParameterDiamond3.errors.txt | 37 ++++++++++++++ .../reference/typeParameterDiamond3.js | 28 +++++++++++ .../typeParameterDiamond4.errors.txt | 28 +++++++++++ .../reference/typeParameterDiamond4.js | 28 +++++++++++ .../reference/typeParameterExtendingUnion1.js | 48 +++++++++++++++++++ .../typeParameterExtendingUnion1.types | 46 ++++++++++++++++++ .../reference/typeParameterExtendingUnion2.js | 48 +++++++++++++++++++ .../typeParameterExtendingUnion2.types | 47 ++++++++++++++++++ tests/cases/compiler/typeParameterDiamond1.ts | 13 +++++ tests/cases/compiler/typeParameterDiamond2.ts | 13 +++++ tests/cases/compiler/typeParameterDiamond3.ts | 13 +++++ tests/cases/compiler/typeParameterDiamond4.ts | 13 +++++ .../compiler/typeParameterExtendingUnion1.ts | 12 +++++ .../compiler/typeParameterExtendingUnion2.ts | 12 +++++ 19 files changed, 542 insertions(+), 24 deletions(-) create mode 100644 tests/baselines/reference/typeParameterDiamond1.js create mode 100644 tests/baselines/reference/typeParameterDiamond1.types create mode 100644 tests/baselines/reference/typeParameterDiamond2.errors.txt create mode 100644 tests/baselines/reference/typeParameterDiamond2.js create mode 100644 tests/baselines/reference/typeParameterDiamond3.errors.txt create mode 100644 tests/baselines/reference/typeParameterDiamond3.js create mode 100644 tests/baselines/reference/typeParameterDiamond4.errors.txt create mode 100644 tests/baselines/reference/typeParameterDiamond4.js create mode 100644 tests/baselines/reference/typeParameterExtendingUnion1.js create mode 100644 tests/baselines/reference/typeParameterExtendingUnion1.types create mode 100644 tests/baselines/reference/typeParameterExtendingUnion2.js create mode 100644 tests/baselines/reference/typeParameterExtendingUnion2.types create mode 100644 tests/cases/compiler/typeParameterDiamond1.ts create mode 100644 tests/cases/compiler/typeParameterDiamond2.ts create mode 100644 tests/cases/compiler/typeParameterDiamond3.ts create mode 100644 tests/cases/compiler/typeParameterDiamond4.ts create mode 100644 tests/cases/compiler/typeParameterExtendingUnion1.ts create mode 100644 tests/cases/compiler/typeParameterExtendingUnion2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b5bf8a654..57603c461e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4016,6 +4016,7 @@ module ts { if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True; } } + let saveErrorInfo = errorInfo; if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) { if (relation === identityRelation) { if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) { @@ -4054,32 +4055,31 @@ module ts { return result; } } - else { - let saveErrorInfo = errorInfo; - if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { - // We have type references to same target type, see if relationship holds for all type arguments - if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) { - return result; - } - } - // Even if relationship doesn't hold for type arguments, it may hold in a structural comparison - // Report structural errors only if we haven't reported any errors yet - let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; - // identity relation does not use apparent type - let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); - if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { - if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { - errorInfo = saveErrorInfo; - return result; - } - } - else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { - if (result = isRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { - errorInfo = saveErrorInfo; - return result; - } + else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { + // We have type references to same target type, see if relationship holds for all type arguments + if (result = typesRelatedTo((source).typeArguments, (target).typeArguments, reportErrors)) { + return result; } } + + // Even if relationship doesn't hold for type arguments, it may hold in a structural comparison + // Report structural errors only if we haven't reported any errors yet + let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; + // identity relation does not use apparent type + let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source); + if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { + if (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { + if (result = isRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + if (reportErrors) { headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1; let sourceType = typeToString(source); diff --git a/tests/baselines/reference/typeParameterDiamond1.js b/tests/baselines/reference/typeParameterDiamond1.js new file mode 100644 index 0000000000..08954c1305 --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond1.js @@ -0,0 +1,28 @@ +//// [typeParameterDiamond1.ts] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} + +//// [typeParameterDiamond1.js] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top; + var middle; + var bottom; + top = middle; + middle = bottom; + top = bottom; + } + } +} diff --git a/tests/baselines/reference/typeParameterDiamond1.types b/tests/baselines/reference/typeParameterDiamond1.types new file mode 100644 index 0000000000..73d5f41b7c --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond1.types @@ -0,0 +1,48 @@ +=== tests/cases/compiler/typeParameterDiamond1.ts === +function diamondTop() { +>diamondTop : () => void, Symbol(diamondTop, Decl(typeParameterDiamond1.ts, 0, 0)) +>Top : Top, Symbol(Top, Decl(typeParameterDiamond1.ts, 0, 20)) + + function diamondMiddle() { +>diamondMiddle : () => void, Symbol(diamondMiddle, Decl(typeParameterDiamond1.ts, 0, 28)) +>T : T, Symbol(T, Decl(typeParameterDiamond1.ts, 1, 27)) +>Top : Top, Symbol(Top, Decl(typeParameterDiamond1.ts, 0, 20)) +>U : U, Symbol(U, Decl(typeParameterDiamond1.ts, 1, 41)) +>Top : Top, Symbol(Top, Decl(typeParameterDiamond1.ts, 0, 20)) + + function diamondBottom() { +>diamondBottom : () => void, Symbol(diamondBottom, Decl(typeParameterDiamond1.ts, 1, 60)) +>Bottom : Bottom, Symbol(Bottom, Decl(typeParameterDiamond1.ts, 2, 31)) +>T : T, Symbol(T, Decl(typeParameterDiamond1.ts, 1, 27)) +>U : U, Symbol(U, Decl(typeParameterDiamond1.ts, 1, 41)) + + var top: Top; +>top : Top, Symbol(top, Decl(typeParameterDiamond1.ts, 3, 15)) +>Top : Top, Symbol(Top, Decl(typeParameterDiamond1.ts, 0, 20)) + + var middle: T | U; +>middle : T | U, Symbol(middle, Decl(typeParameterDiamond1.ts, 4, 15)) +>T : T, Symbol(T, Decl(typeParameterDiamond1.ts, 1, 27)) +>U : U, Symbol(U, Decl(typeParameterDiamond1.ts, 1, 41)) + + var bottom: Bottom; +>bottom : Bottom, Symbol(bottom, Decl(typeParameterDiamond1.ts, 5, 15)) +>Bottom : Bottom, Symbol(Bottom, Decl(typeParameterDiamond1.ts, 2, 31)) + + top = middle; +>top = middle : T | U +>top : Top, Symbol(top, Decl(typeParameterDiamond1.ts, 3, 15)) +>middle : T | U, Symbol(middle, Decl(typeParameterDiamond1.ts, 4, 15)) + + middle = bottom; +>middle = bottom : Bottom +>middle : T | U, Symbol(middle, Decl(typeParameterDiamond1.ts, 4, 15)) +>bottom : Bottom, Symbol(bottom, Decl(typeParameterDiamond1.ts, 5, 15)) + + top = bottom; +>top = bottom : Bottom +>top : Top, Symbol(top, Decl(typeParameterDiamond1.ts, 3, 15)) +>bottom : Bottom, Symbol(bottom, Decl(typeParameterDiamond1.ts, 5, 15)) + } + } +} diff --git a/tests/baselines/reference/typeParameterDiamond2.errors.txt b/tests/baselines/reference/typeParameterDiamond2.errors.txt new file mode 100644 index 0000000000..f268724c6e --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond2.errors.txt @@ -0,0 +1,28 @@ +tests/cases/compiler/typeParameterDiamond2.ts(8,13): error TS2322: Type 'T | U' is not assignable to type 'Top'. + Type 'U' is not assignable to type 'Top'. +tests/cases/compiler/typeParameterDiamond2.ts(10,13): error TS2322: Type 'Bottom' is not assignable to type 'Top'. + Type 'T | U' is not assignable to type 'Top'. + Type 'U' is not assignable to type 'Top'. + + +==== tests/cases/compiler/typeParameterDiamond2.ts (2 errors) ==== + function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + ~~~ +!!! error TS2322: Type 'T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'U' is not assignable to type 'Top'. + middle = bottom; + top = bottom; + ~~~ +!!! error TS2322: Type 'Bottom' is not assignable to type 'Top'. +!!! error TS2322: Type 'T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'U' is not assignable to type 'Top'. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterDiamond2.js b/tests/baselines/reference/typeParameterDiamond2.js new file mode 100644 index 0000000000..06b47b10bb --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond2.js @@ -0,0 +1,28 @@ +//// [typeParameterDiamond2.ts] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} + +//// [typeParameterDiamond2.js] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top; + var middle; + var bottom; + top = middle; + middle = bottom; + top = bottom; + } + } +} diff --git a/tests/baselines/reference/typeParameterDiamond3.errors.txt b/tests/baselines/reference/typeParameterDiamond3.errors.txt new file mode 100644 index 0000000000..2ef46ec2f8 --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond3.errors.txt @@ -0,0 +1,37 @@ +tests/cases/compiler/typeParameterDiamond3.ts(8,13): error TS2322: Type 'T | U' is not assignable to type 'Top'. + Type 'T' is not assignable to type 'Top'. +tests/cases/compiler/typeParameterDiamond3.ts(9,13): error TS2322: Type 'Bottom' is not assignable to type 'T | U'. + Type 'Bottom' is not assignable to type 'U'. + Type 'Top | T | U' is not assignable to type 'U'. + Type 'Top' is not assignable to type 'U'. +tests/cases/compiler/typeParameterDiamond3.ts(10,13): error TS2322: Type 'Bottom' is not assignable to type 'Top'. + Type 'Top | T | U' is not assignable to type 'Top'. + Type 'T' is not assignable to type 'Top'. + + +==== tests/cases/compiler/typeParameterDiamond3.ts (3 errors) ==== + function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + ~~~ +!!! error TS2322: Type 'T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'T' is not assignable to type 'Top'. + middle = bottom; + ~~~~~~ +!!! error TS2322: Type 'Bottom' is not assignable to type 'T | U'. +!!! error TS2322: Type 'Bottom' is not assignable to type 'U'. +!!! error TS2322: Type 'Top | T | U' is not assignable to type 'U'. +!!! error TS2322: Type 'Top' is not assignable to type 'U'. + top = bottom; + ~~~ +!!! error TS2322: Type 'Bottom' is not assignable to type 'Top'. +!!! error TS2322: Type 'Top | T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'T' is not assignable to type 'Top'. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterDiamond3.js b/tests/baselines/reference/typeParameterDiamond3.js new file mode 100644 index 0000000000..cd8b69f275 --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond3.js @@ -0,0 +1,28 @@ +//// [typeParameterDiamond3.ts] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} + +//// [typeParameterDiamond3.js] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top; + var middle; + var bottom; + top = middle; + middle = bottom; + top = bottom; + } + } +} diff --git a/tests/baselines/reference/typeParameterDiamond4.errors.txt b/tests/baselines/reference/typeParameterDiamond4.errors.txt new file mode 100644 index 0000000000..2a7fbdaf15 --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond4.errors.txt @@ -0,0 +1,28 @@ +tests/cases/compiler/typeParameterDiamond4.ts(8,13): error TS2322: Type 'Top | T | U' is not assignable to type 'Top'. + Type 'T' is not assignable to type 'Top'. +tests/cases/compiler/typeParameterDiamond4.ts(10,13): error TS2322: Type 'Bottom' is not assignable to type 'Top'. + Type 'Top | T | U' is not assignable to type 'Top'. + Type 'T' is not assignable to type 'Top'. + + +==== tests/cases/compiler/typeParameterDiamond4.ts (2 errors) ==== + function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: Top | T | U; + var bottom: Bottom; + + top = middle; + ~~~ +!!! error TS2322: Type 'Top | T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'T' is not assignable to type 'Top'. + middle = bottom; + top = bottom; + ~~~ +!!! error TS2322: Type 'Bottom' is not assignable to type 'Top'. +!!! error TS2322: Type 'Top | T | U' is not assignable to type 'Top'. +!!! error TS2322: Type 'T' is not assignable to type 'Top'. + } + } + } \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterDiamond4.js b/tests/baselines/reference/typeParameterDiamond4.js new file mode 100644 index 0000000000..3a94f9d80d --- /dev/null +++ b/tests/baselines/reference/typeParameterDiamond4.js @@ -0,0 +1,28 @@ +//// [typeParameterDiamond4.ts] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: Top | T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} + +//// [typeParameterDiamond4.js] +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top; + var middle; + var bottom; + top = middle; + middle = bottom; + top = bottom; + } + } +} diff --git a/tests/baselines/reference/typeParameterExtendingUnion1.js b/tests/baselines/reference/typeParameterExtendingUnion1.js new file mode 100644 index 0000000000..2cfbe7b07b --- /dev/null +++ b/tests/baselines/reference/typeParameterExtendingUnion1.js @@ -0,0 +1,48 @@ +//// [typeParameterExtendingUnion1.ts] +class Animal { run() { } } +class Cat extends Animal { meow } +class Dog extends Animal { woof } + +function run(a: Animal) { + a.run(); +} + +function f(a: T) { + a.run(); + run(a); +} + +//// [typeParameterExtendingUnion1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Animal = (function () { + function Animal() { + } + Animal.prototype.run = function () { }; + return Animal; +})(); +var Cat = (function (_super) { + __extends(Cat, _super); + function Cat() { + _super.apply(this, arguments); + } + return Cat; +})(Animal); +var Dog = (function (_super) { + __extends(Dog, _super); + function Dog() { + _super.apply(this, arguments); + } + return Dog; +})(Animal); +function run(a) { + a.run(); +} +function f(a) { + a.run(); + run(a); +} diff --git a/tests/baselines/reference/typeParameterExtendingUnion1.types b/tests/baselines/reference/typeParameterExtendingUnion1.types new file mode 100644 index 0000000000..5294afb8cf --- /dev/null +++ b/tests/baselines/reference/typeParameterExtendingUnion1.types @@ -0,0 +1,46 @@ +=== tests/cases/compiler/typeParameterExtendingUnion1.ts === +class Animal { run() { } } +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion1.ts, 0, 0)) +>run : () => void, Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14)) + +class Cat extends Animal { meow } +>Cat : Cat, Symbol(Cat, Decl(typeParameterExtendingUnion1.ts, 0, 26)) +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion1.ts, 0, 0)) +>meow : any, Symbol(meow, Decl(typeParameterExtendingUnion1.ts, 1, 26)) + +class Dog extends Animal { woof } +>Dog : Dog, Symbol(Dog, Decl(typeParameterExtendingUnion1.ts, 1, 33)) +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion1.ts, 0, 0)) +>woof : any, Symbol(woof, Decl(typeParameterExtendingUnion1.ts, 2, 26)) + +function run(a: Animal) { +>run : (a: Animal) => void, Symbol(run, Decl(typeParameterExtendingUnion1.ts, 2, 33)) +>a : Animal, Symbol(a, Decl(typeParameterExtendingUnion1.ts, 4, 13)) +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion1.ts, 0, 0)) + + a.run(); +>a.run() : void +>a.run : () => void, Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14)) +>a : Animal, Symbol(a, Decl(typeParameterExtendingUnion1.ts, 4, 13)) +>run : () => void, Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14)) +} + +function f(a: T) { +>f : (a: T) => void, Symbol(f, Decl(typeParameterExtendingUnion1.ts, 6, 1)) +>T : T, Symbol(T, Decl(typeParameterExtendingUnion1.ts, 8, 11)) +>Cat : Cat, Symbol(Cat, Decl(typeParameterExtendingUnion1.ts, 0, 26)) +>Dog : Dog, Symbol(Dog, Decl(typeParameterExtendingUnion1.ts, 1, 33)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion1.ts, 8, 32)) +>T : T, Symbol(T, Decl(typeParameterExtendingUnion1.ts, 8, 11)) + + a.run(); +>a.run() : void +>a.run : () => void, Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion1.ts, 8, 32)) +>run : () => void, Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14)) + + run(a); +>run(a) : void +>run : (a: Animal) => void, Symbol(run, Decl(typeParameterExtendingUnion1.ts, 2, 33)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion1.ts, 8, 32)) +} diff --git a/tests/baselines/reference/typeParameterExtendingUnion2.js b/tests/baselines/reference/typeParameterExtendingUnion2.js new file mode 100644 index 0000000000..c5e462bb96 --- /dev/null +++ b/tests/baselines/reference/typeParameterExtendingUnion2.js @@ -0,0 +1,48 @@ +//// [typeParameterExtendingUnion2.ts] +class Animal { run() { } } +class Cat extends Animal { meow } +class Dog extends Animal { woof } + +function run(a: Cat | Dog) { + a.run(); +} + +function f(a: T) { + a.run(); + run(a); +} + +//// [typeParameterExtendingUnion2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Animal = (function () { + function Animal() { + } + Animal.prototype.run = function () { }; + return Animal; +})(); +var Cat = (function (_super) { + __extends(Cat, _super); + function Cat() { + _super.apply(this, arguments); + } + return Cat; +})(Animal); +var Dog = (function (_super) { + __extends(Dog, _super); + function Dog() { + _super.apply(this, arguments); + } + return Dog; +})(Animal); +function run(a) { + a.run(); +} +function f(a) { + a.run(); + run(a); +} diff --git a/tests/baselines/reference/typeParameterExtendingUnion2.types b/tests/baselines/reference/typeParameterExtendingUnion2.types new file mode 100644 index 0000000000..edbf220a7b --- /dev/null +++ b/tests/baselines/reference/typeParameterExtendingUnion2.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/typeParameterExtendingUnion2.ts === +class Animal { run() { } } +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion2.ts, 0, 0)) +>run : () => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14)) + +class Cat extends Animal { meow } +>Cat : Cat, Symbol(Cat, Decl(typeParameterExtendingUnion2.ts, 0, 26)) +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion2.ts, 0, 0)) +>meow : any, Symbol(meow, Decl(typeParameterExtendingUnion2.ts, 1, 26)) + +class Dog extends Animal { woof } +>Dog : Dog, Symbol(Dog, Decl(typeParameterExtendingUnion2.ts, 1, 33)) +>Animal : Animal, Symbol(Animal, Decl(typeParameterExtendingUnion2.ts, 0, 0)) +>woof : any, Symbol(woof, Decl(typeParameterExtendingUnion2.ts, 2, 26)) + +function run(a: Cat | Dog) { +>run : (a: Cat | Dog) => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 2, 33)) +>a : Cat | Dog, Symbol(a, Decl(typeParameterExtendingUnion2.ts, 4, 13)) +>Cat : Cat, Symbol(Cat, Decl(typeParameterExtendingUnion2.ts, 0, 26)) +>Dog : Dog, Symbol(Dog, Decl(typeParameterExtendingUnion2.ts, 1, 33)) + + a.run(); +>a.run() : void +>a.run : () => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>a : Cat | Dog, Symbol(a, Decl(typeParameterExtendingUnion2.ts, 4, 13)) +>run : () => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +} + +function f(a: T) { +>f : (a: T) => void, Symbol(f, Decl(typeParameterExtendingUnion2.ts, 6, 1)) +>T : T, Symbol(T, Decl(typeParameterExtendingUnion2.ts, 8, 11)) +>Cat : Cat, Symbol(Cat, Decl(typeParameterExtendingUnion2.ts, 0, 26)) +>Dog : Dog, Symbol(Dog, Decl(typeParameterExtendingUnion2.ts, 1, 33)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion2.ts, 8, 32)) +>T : T, Symbol(T, Decl(typeParameterExtendingUnion2.ts, 8, 11)) + + a.run(); +>a.run() : void +>a.run : () => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion2.ts, 8, 32)) +>run : () => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14)) + + run(a); +>run(a) : void +>run : (a: Cat | Dog) => void, Symbol(run, Decl(typeParameterExtendingUnion2.ts, 2, 33)) +>a : T, Symbol(a, Decl(typeParameterExtendingUnion2.ts, 8, 32)) +} diff --git a/tests/cases/compiler/typeParameterDiamond1.ts b/tests/cases/compiler/typeParameterDiamond1.ts new file mode 100644 index 0000000000..6bd53ba4e7 --- /dev/null +++ b/tests/cases/compiler/typeParameterDiamond1.ts @@ -0,0 +1,13 @@ +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterDiamond2.ts b/tests/cases/compiler/typeParameterDiamond2.ts new file mode 100644 index 0000000000..e099e79626 --- /dev/null +++ b/tests/cases/compiler/typeParameterDiamond2.ts @@ -0,0 +1,13 @@ +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterDiamond3.ts b/tests/cases/compiler/typeParameterDiamond3.ts new file mode 100644 index 0000000000..df434d829f --- /dev/null +++ b/tests/cases/compiler/typeParameterDiamond3.ts @@ -0,0 +1,13 @@ +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterDiamond4.ts b/tests/cases/compiler/typeParameterDiamond4.ts new file mode 100644 index 0000000000..d962122edc --- /dev/null +++ b/tests/cases/compiler/typeParameterDiamond4.ts @@ -0,0 +1,13 @@ +function diamondTop() { + function diamondMiddle() { + function diamondBottom() { + var top: Top; + var middle: Top | T | U; + var bottom: Bottom; + + top = middle; + middle = bottom; + top = bottom; + } + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterExtendingUnion1.ts b/tests/cases/compiler/typeParameterExtendingUnion1.ts new file mode 100644 index 0000000000..019e722f1e --- /dev/null +++ b/tests/cases/compiler/typeParameterExtendingUnion1.ts @@ -0,0 +1,12 @@ +class Animal { run() { } } +class Cat extends Animal { meow } +class Dog extends Animal { woof } + +function run(a: Animal) { + a.run(); +} + +function f(a: T) { + a.run(); + run(a); +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParameterExtendingUnion2.ts b/tests/cases/compiler/typeParameterExtendingUnion2.ts new file mode 100644 index 0000000000..347999fa8e --- /dev/null +++ b/tests/cases/compiler/typeParameterExtendingUnion2.ts @@ -0,0 +1,12 @@ +class Animal { run() { } } +class Cat extends Animal { meow } +class Dog extends Animal { woof } + +function run(a: Cat | Dog) { + a.run(); +} + +function f(a: T) { + a.run(); + run(a); +} \ No newline at end of file From 628a5baf4a4291e8238311b229e7e09147461ca0 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 15 Apr 2015 11:46:21 -0700 Subject: [PATCH 3/4] Improve error message for type parameter extending union --- src/compiler/checker.ts | 4 ++-- .../baselines/reference/typeParameterDiamond3.errors.txt | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 57603c461e..df5356e733 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4074,8 +4074,8 @@ module ts { } } else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { - if (result = isRelatedTo(sourceOrApparentType, target, reportStructuralErrors)) { - errorInfo = saveErrorInfo; + errorInfo = saveErrorInfo; + if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) { return result; } } diff --git a/tests/baselines/reference/typeParameterDiamond3.errors.txt b/tests/baselines/reference/typeParameterDiamond3.errors.txt index 2ef46ec2f8..abefeb2a2d 100644 --- a/tests/baselines/reference/typeParameterDiamond3.errors.txt +++ b/tests/baselines/reference/typeParameterDiamond3.errors.txt @@ -1,8 +1,8 @@ tests/cases/compiler/typeParameterDiamond3.ts(8,13): error TS2322: Type 'T | U' is not assignable to type 'Top'. Type 'T' is not assignable to type 'Top'. tests/cases/compiler/typeParameterDiamond3.ts(9,13): error TS2322: Type 'Bottom' is not assignable to type 'T | U'. - Type 'Bottom' is not assignable to type 'U'. - Type 'Top | T | U' is not assignable to type 'U'. + Type 'Top | T | U' is not assignable to type 'T | U'. + Type 'Top' is not assignable to type 'T | U'. Type 'Top' is not assignable to type 'U'. tests/cases/compiler/typeParameterDiamond3.ts(10,13): error TS2322: Type 'Bottom' is not assignable to type 'Top'. Type 'Top | T | U' is not assignable to type 'Top'. @@ -24,8 +24,8 @@ tests/cases/compiler/typeParameterDiamond3.ts(10,13): error TS2322: Type 'Bottom middle = bottom; ~~~~~~ !!! error TS2322: Type 'Bottom' is not assignable to type 'T | U'. -!!! error TS2322: Type 'Bottom' is not assignable to type 'U'. -!!! error TS2322: Type 'Top | T | U' is not assignable to type 'U'. +!!! error TS2322: Type 'Top | T | U' is not assignable to type 'T | U'. +!!! error TS2322: Type 'Top' is not assignable to type 'T | U'. !!! error TS2322: Type 'Top' is not assignable to type 'U'. top = bottom; ~~~ From e05a94457ed172fd37fd7852cddee0399d245001 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Wed, 15 Apr 2015 11:48:26 -0700 Subject: [PATCH 4/4] Fix up comment --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index df5356e733..c5151c8d43 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4062,7 +4062,8 @@ module ts { } } - // Even if relationship doesn't hold for type arguments, it may hold in a structural comparison + // Even if relationship doesn't hold for unions, type parameters, or generic type references, + // it may hold in a structural comparison. // Report structural errors only if we haven't reported any errors yet let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo; // identity relation does not use apparent type @@ -4074,6 +4075,8 @@ module ts { } } else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) { + // We clear the errors first because the following check often gives a better error than + // the union comparison above if it is applicable. errorInfo = saveErrorInfo; if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) { return result;