From cc3a48fc7fe1e6c7a1169ed67125a59652b06ff8 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 5 Aug 2015 09:05:06 -0700 Subject: [PATCH 1/2] Use different relation for `instanceof` type guards --- src/compiler/checker.ts | 18 ++- .../reference/instanceOfAssignability.js | 105 +++++++++++++++ .../reference/instanceOfAssignability.symbols | 119 +++++++++++++++++ .../reference/instanceOfAssignability.types | 124 ++++++++++++++++++ ...nstanceOfByConstructorSignature.errors.txt | 16 +-- .../cases/compiler/instanceOfAssignability.ts | 54 ++++++++ 6 files changed, 419 insertions(+), 17 deletions(-) create mode 100644 tests/baselines/reference/instanceOfAssignability.js create mode 100644 tests/baselines/reference/instanceOfAssignability.symbols create mode 100644 tests/baselines/reference/instanceOfAssignability.types create mode 100644 tests/cases/compiler/instanceOfAssignability.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c37189488b..ba899c7b29 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6207,14 +6207,20 @@ namespace ts { } function getNarrowedType(originalType: Type, narrowedTypeCandidate: Type) { - // Narrow to the target type if it's a subtype of the current type - if (isTypeSubtypeOf(narrowedTypeCandidate, originalType)) { + // If the current type is a union type, remove all constituents that aren't assignable to target. If that produces + // 0 candidates, fall back to the assignability check + if (originalType.flags & TypeFlags.Union) { + let assignableConsituents = filter((originalType).types, t => isTypeAssignableTo(t, narrowedTypeCandidate)); + if (assignableConsituents.length) { + return getUnionType(assignableConsituents); + } + } + + if (isTypeAssignableTo(narrowedTypeCandidate, originalType)) { + // Narrow to the target type if it's assignable to the current type return narrowedTypeCandidate; } - // If the current type is a union type, remove all constituents that aren't subtypes of the target. - if (originalType.flags & TypeFlags.Union) { - return getUnionType(filter((originalType).types, t => isTypeSubtypeOf(t, narrowedTypeCandidate))); - } + return originalType; } diff --git a/tests/baselines/reference/instanceOfAssignability.js b/tests/baselines/reference/instanceOfAssignability.js new file mode 100644 index 0000000000..8e868f06d8 --- /dev/null +++ b/tests/baselines/reference/instanceOfAssignability.js @@ -0,0 +1,105 @@ +//// [instanceOfAssignability.ts] +interface Base { + foo: string|number; + optional?: number; +} + +// Derived1 is assignable to, but not a subtype of, Base +class Derived1 implements Base { + foo: string; +} +// Derived2 is a subtype of Base that is not assignable to Derived1 +class Derived2 implements Base { + foo: number; + optional: number; +} + +function fn1(x: Array|Array|boolean) { + if(x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; + } +} + +function fn2(x: Base) { + if(x instanceof Derived1) { + // 1.5: y: Base + // Want: y: Derived1 + let y = x; + } +} + +function fn3(x: Base|Derived1) { + if(x instanceof Derived2) { + // 1.5: y: Derived2 + // Want: Derived2 + let y = x; + } +} + +function fn4(x: Base|Derived2) { + if(x instanceof Derived1) { + // 1.5: y: {} + // Want: Derived1 + let y = x; + } +} + +function fn5(x: Derived1) { + if(x instanceof Derived2) { + // 1.5: y: Derived1 + // Want: ??? + let y = x; + } +} + + +//// [instanceOfAssignability.js] +// Derived1 is assignable to, but not a subtype of, Base +var Derived1 = (function () { + function Derived1() { + } + return Derived1; +})(); +// Derived2 is a subtype of Base that is not assignable to Derived1 +var Derived2 = (function () { + function Derived2() { + } + return Derived2; +})(); +function fn1(x) { + if (x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + var y = x; + } +} +function fn2(x) { + if (x instanceof Derived1) { + // 1.5: y: Base + // Want: y: Derived1 + var y = x; + } +} +function fn3(x) { + if (x instanceof Derived2) { + // 1.5: y: Derived2 + // Want: Derived2 + var y = x; + } +} +function fn4(x) { + if (x instanceof Derived1) { + // 1.5: y: {} + // Want: Derived1 + var y = x; + } +} +function fn5(x) { + if (x instanceof Derived2) { + // 1.5: y: Derived1 + // Want: ??? + var y = x; + } +} diff --git a/tests/baselines/reference/instanceOfAssignability.symbols b/tests/baselines/reference/instanceOfAssignability.symbols new file mode 100644 index 0000000000..f7f7560a18 --- /dev/null +++ b/tests/baselines/reference/instanceOfAssignability.symbols @@ -0,0 +1,119 @@ +=== tests/cases/compiler/instanceOfAssignability.ts === +interface Base { +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) + + foo: string|number; +>foo : Symbol(foo, Decl(instanceOfAssignability.ts, 0, 16)) + + optional?: number; +>optional : Symbol(optional, Decl(instanceOfAssignability.ts, 1, 20)) +} + +// Derived1 is assignable to, but not a subtype of, Base +class Derived1 implements Base { +>Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) + + foo: string; +>foo : Symbol(foo, Decl(instanceOfAssignability.ts, 6, 32)) +} +// Derived2 is a subtype of Base that is not assignable to Derived1 +class Derived2 implements Base { +>Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) + + foo: number; +>foo : Symbol(foo, Decl(instanceOfAssignability.ts, 10, 32)) + + optional: number; +>optional : Symbol(optional, Decl(instanceOfAssignability.ts, 11, 13)) +} + +function fn1(x: Array|Array|boolean) { +>fn1 : Symbol(fn1, Decl(instanceOfAssignability.ts, 13, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) + + if(x instanceof Array) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) + + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 19, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) + } +} + +function fn2(x: Base) { +>fn2 : Symbol(fn2, Decl(instanceOfAssignability.ts, 21, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) + + if(x instanceof Derived1) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) +>Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) + + // 1.5: y: Base + // Want: y: Derived1 + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 27, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) + } +} + +function fn3(x: Base|Derived1) { +>fn3 : Symbol(fn3, Decl(instanceOfAssignability.ts, 29, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) +>Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) + + if(x instanceof Derived2) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) +>Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) + + // 1.5: y: Derived2 + // Want: Derived2 + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 35, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) + } +} + +function fn4(x: Base|Derived2) { +>fn4 : Symbol(fn4, Decl(instanceOfAssignability.ts, 37, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) +>Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) +>Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) + + if(x instanceof Derived1) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) +>Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) + + // 1.5: y: {} + // Want: Derived1 + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 43, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) + } +} + +function fn5(x: Derived1) { +>fn5 : Symbol(fn5, Decl(instanceOfAssignability.ts, 45, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) +>Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) + + if(x instanceof Derived2) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) +>Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) + + // 1.5: y: Derived1 + // Want: ??? + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 51, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) + } +} + diff --git a/tests/baselines/reference/instanceOfAssignability.types b/tests/baselines/reference/instanceOfAssignability.types new file mode 100644 index 0000000000..8e537c4baf --- /dev/null +++ b/tests/baselines/reference/instanceOfAssignability.types @@ -0,0 +1,124 @@ +=== tests/cases/compiler/instanceOfAssignability.ts === +interface Base { +>Base : Base + + foo: string|number; +>foo : string | number + + optional?: number; +>optional : number +} + +// Derived1 is assignable to, but not a subtype of, Base +class Derived1 implements Base { +>Derived1 : Derived1 +>Base : Base + + foo: string; +>foo : string +} +// Derived2 is a subtype of Base that is not assignable to Derived1 +class Derived2 implements Base { +>Derived2 : Derived2 +>Base : Base + + foo: number; +>foo : number + + optional: number; +>optional : number +} + +function fn1(x: Array|Array|boolean) { +>fn1 : (x: number[] | string[] | boolean) => void +>x : number[] | string[] | boolean +>Array : T[] +>Array : T[] + + if(x instanceof Array) { +>x instanceof Array : boolean +>x : number[] | string[] | boolean +>Array : ArrayConstructor + + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; +>y : number[] | string[] +>x : number[] | string[] + } +} + +function fn2(x: Base) { +>fn2 : (x: Base) => void +>x : Base +>Base : Base + + if(x instanceof Derived1) { +>x instanceof Derived1 : boolean +>x : Base +>Derived1 : typeof Derived1 + + // 1.5: y: Base + // Want: y: Derived1 + let y = x; +>y : Derived1 +>x : Derived1 + } +} + +function fn3(x: Base|Derived1) { +>fn3 : (x: Base | Derived1) => void +>x : Base | Derived1 +>Base : Base +>Derived1 : Derived1 + + if(x instanceof Derived2) { +>x instanceof Derived2 : boolean +>x : Base | Derived1 +>Derived2 : typeof Derived2 + + // 1.5: y: Derived2 + // Want: Derived2 + let y = x; +>y : Derived2 +>x : Derived2 + } +} + +function fn4(x: Base|Derived2) { +>fn4 : (x: Base | Derived2) => void +>x : Base | Derived2 +>Base : Base +>Derived2 : Derived2 + + if(x instanceof Derived1) { +>x instanceof Derived1 : boolean +>x : Base | Derived2 +>Derived1 : typeof Derived1 + + // 1.5: y: {} + // Want: Derived1 + let y = x; +>y : Derived1 +>x : Derived1 + } +} + +function fn5(x: Derived1) { +>fn5 : (x: Derived1) => void +>x : Derived1 +>Derived1 : Derived1 + + if(x instanceof Derived2) { +>x instanceof Derived2 : boolean +>x : Derived1 +>Derived2 : typeof Derived2 + + // 1.5: y: Derived1 + // Want: ??? + let y = x; +>y : Derived1 +>x : Derived1 + } +} + diff --git a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt index 2f86b6797d..63b9de2aed 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOfByConstructorSignature.errors.txt @@ -1,18 +1,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(12,10): error TS2339: Property 'bar' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(33,5): error TS2322: Type 'string' is not assignable to type 'number'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(34,10): error TS2339: Property 'bar' does not exist on type 'B'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(65,10): error TS2339: Property 'bar1' does not exist on type 'C1 | C2'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(66,10): error TS2339: Property 'bar2' does not exist on type 'C1 | C2'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(66,10): error TS2339: Property 'bar2' does not exist on type 'C1'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(85,10): error TS2339: Property 'bar' does not exist on type 'D'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(111,10): error TS2339: Property 'bar1' does not exist on type 'E1 | E2'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(112,10): error TS2339: Property 'bar2' does not exist on type 'E1 | E2'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(112,10): error TS2339: Property 'bar2' does not exist on type 'E1'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(134,11): error TS2339: Property 'foo' does not exist on type 'F | string'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(135,11): error TS2339: Property 'bar' does not exist on type 'F | string'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(160,11): error TS2339: Property 'foo2' does not exist on type 'G1'. tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts(182,11): error TS2339: Property 'bar' does not exist on type 'H'. -==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (12 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstructorSignature.ts (10 errors) ==== interface AConstructor { new (): A; } @@ -84,11 +82,9 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru obj5.foo; obj5.c; obj5.bar1; - ~~~~ -!!! error TS2339: Property 'bar1' does not exist on type 'C1 | C2'. obj5.bar2; ~~~~ -!!! error TS2339: Property 'bar2' does not exist on type 'C1 | C2'. +!!! error TS2339: Property 'bar2' does not exist on type 'C1'. } var obj6: any; @@ -136,11 +132,9 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOfByConstru if (obj9 instanceof E) { // narrowed to E1 | E2 obj9.foo; obj9.bar1; - ~~~~ -!!! error TS2339: Property 'bar1' does not exist on type 'E1 | E2'. obj9.bar2; ~~~~ -!!! error TS2339: Property 'bar2' does not exist on type 'E1 | E2'. +!!! error TS2339: Property 'bar2' does not exist on type 'E1'. } var obj10: any; diff --git a/tests/cases/compiler/instanceOfAssignability.ts b/tests/cases/compiler/instanceOfAssignability.ts new file mode 100644 index 0000000000..9f8934b526 --- /dev/null +++ b/tests/cases/compiler/instanceOfAssignability.ts @@ -0,0 +1,54 @@ +interface Base { + foo: string|number; + optional?: number; +} + +// Derived1 is assignable to, but not a subtype of, Base +class Derived1 implements Base { + foo: string; +} +// Derived2 is a subtype of Base that is not assignable to Derived1 +class Derived2 implements Base { + foo: number; + optional: number; +} + +function fn1(x: Array|Array|boolean) { + if(x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; + } +} + +function fn2(x: Base) { + if(x instanceof Derived1) { + // 1.5: y: Base + // Want: y: Derived1 + let y = x; + } +} + +function fn3(x: Base|Derived1) { + if(x instanceof Derived2) { + // 1.5: y: Derived2 + // Want: Derived2 + let y = x; + } +} + +function fn4(x: Base|Derived2) { + if(x instanceof Derived1) { + // 1.5: y: {} + // Want: Derived1 + let y = x; + } +} + +function fn5(x: Derived1) { + if(x instanceof Derived2) { + // 1.5: y: Derived1 + // Want: ??? + let y = x; + } +} From 748d7564a6806b610fe8cce07f7c91f5d4c1af3b Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 5 Aug 2015 13:30:45 -0700 Subject: [PATCH 2/2] Add tests and fix spelling --- src/compiler/checker.ts | 6 +- .../reference/instanceOfAssignability.js | 82 +++++++++++ .../reference/instanceOfAssignability.symbols | 139 ++++++++++++++---- .../reference/instanceOfAssignability.types | 92 ++++++++++++ .../cases/compiler/instanceOfAssignability.ts | 34 +++++ 5 files changed, 325 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba899c7b29..9ff121f5c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6210,9 +6210,9 @@ namespace ts { // If the current type is a union type, remove all constituents that aren't assignable to target. If that produces // 0 candidates, fall back to the assignability check if (originalType.flags & TypeFlags.Union) { - let assignableConsituents = filter((originalType).types, t => isTypeAssignableTo(t, narrowedTypeCandidate)); - if (assignableConsituents.length) { - return getUnionType(assignableConsituents); + let assignableConstituents = filter((originalType).types, t => isTypeAssignableTo(t, narrowedTypeCandidate)); + if (assignableConstituents.length) { + return getUnionType(assignableConstituents); } } diff --git a/tests/baselines/reference/instanceOfAssignability.js b/tests/baselines/reference/instanceOfAssignability.js index 8e868f06d8..4a1e8b9e9d 100644 --- a/tests/baselines/reference/instanceOfAssignability.js +++ b/tests/baselines/reference/instanceOfAssignability.js @@ -14,6 +14,12 @@ class Derived2 implements Base { optional: number; } +class Animal { + move; +} +class Mammal extends Animal { milk; } +class Giraffe extends Mammal { neck; } + function fn1(x: Array|Array|boolean) { if(x instanceof Array) { // 1.5: y: Array|Array @@ -53,9 +59,42 @@ function fn5(x: Derived1) { let y = x; } } + +function fn6(x: Animal|Mammal) { + if(x instanceof Giraffe) { + // 1.5: y: Derived1 + // Want: ??? + let y = x; + } +} + +function fn7(x: Array|Array) { + if(x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; + } +} + +interface Alpha { a } +interface Beta { b } +interface Gamma { c } +class ABC { a; b; c; } +function fn8(x: Alpha|Beta|Gamma) { + if(x instanceof ABC) { + let y = x; + } +} + + //// [instanceOfAssignability.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; // Derived1 is assignable to, but not a subtype of, Base var Derived1 = (function () { function Derived1() { @@ -68,6 +107,25 @@ var Derived2 = (function () { } return Derived2; })(); +var Animal = (function () { + function Animal() { + } + return Animal; +})(); +var Mammal = (function (_super) { + __extends(Mammal, _super); + function Mammal() { + _super.apply(this, arguments); + } + return Mammal; +})(Animal); +var Giraffe = (function (_super) { + __extends(Giraffe, _super); + function Giraffe() { + _super.apply(this, arguments); + } + return Giraffe; +})(Mammal); function fn1(x) { if (x instanceof Array) { // 1.5: y: Array|Array @@ -103,3 +161,27 @@ function fn5(x) { var y = x; } } +function fn6(x) { + if (x instanceof Giraffe) { + // 1.5: y: Derived1 + // Want: ??? + var y = x; + } +} +function fn7(x) { + if (x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + var y = x; + } +} +var ABC = (function () { + function ABC() { + } + return ABC; +})(); +function fn8(x) { + if (x instanceof ABC) { + var y = x; + } +} diff --git a/tests/baselines/reference/instanceOfAssignability.symbols b/tests/baselines/reference/instanceOfAssignability.symbols index f7f7560a18..b01f29a5fa 100644 --- a/tests/baselines/reference/instanceOfAssignability.symbols +++ b/tests/baselines/reference/instanceOfAssignability.symbols @@ -29,91 +29,180 @@ class Derived2 implements Base { >optional : Symbol(optional, Decl(instanceOfAssignability.ts, 11, 13)) } +class Animal { +>Animal : Symbol(Animal, Decl(instanceOfAssignability.ts, 13, 1)) + + move; +>move : Symbol(move, Decl(instanceOfAssignability.ts, 15, 14)) +} +class Mammal extends Animal { milk; } +>Mammal : Symbol(Mammal, Decl(instanceOfAssignability.ts, 17, 1)) +>Animal : Symbol(Animal, Decl(instanceOfAssignability.ts, 13, 1)) +>milk : Symbol(milk, Decl(instanceOfAssignability.ts, 18, 29)) + +class Giraffe extends Mammal { neck; } +>Giraffe : Symbol(Giraffe, Decl(instanceOfAssignability.ts, 18, 37)) +>Mammal : Symbol(Mammal, Decl(instanceOfAssignability.ts, 17, 1)) +>neck : Symbol(neck, Decl(instanceOfAssignability.ts, 19, 30)) + function fn1(x: Array|Array|boolean) { ->fn1 : Symbol(fn1, Decl(instanceOfAssignability.ts, 13, 1)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) +>fn1 : Symbol(fn1, Decl(instanceOfAssignability.ts, 19, 38)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 21, 13)) >Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) >Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) if(x instanceof Array) { ->x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 21, 13)) >Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) // 1.5: y: Array|Array // Want: y: Array|Array let y = x; ->y : Symbol(y, Decl(instanceOfAssignability.ts, 19, 5)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 15, 13)) +>y : Symbol(y, Decl(instanceOfAssignability.ts, 25, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 21, 13)) } } function fn2(x: Base) { ->fn2 : Symbol(fn2, Decl(instanceOfAssignability.ts, 21, 1)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) +>fn2 : Symbol(fn2, Decl(instanceOfAssignability.ts, 27, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 29, 13)) >Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) if(x instanceof Derived1) { ->x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 29, 13)) >Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) // 1.5: y: Base // Want: y: Derived1 let y = x; ->y : Symbol(y, Decl(instanceOfAssignability.ts, 27, 5)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 23, 13)) +>y : Symbol(y, Decl(instanceOfAssignability.ts, 33, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 29, 13)) } } function fn3(x: Base|Derived1) { ->fn3 : Symbol(fn3, Decl(instanceOfAssignability.ts, 29, 1)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) +>fn3 : Symbol(fn3, Decl(instanceOfAssignability.ts, 35, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 37, 13)) >Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) >Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) if(x instanceof Derived2) { ->x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 37, 13)) >Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) // 1.5: y: Derived2 // Want: Derived2 let y = x; ->y : Symbol(y, Decl(instanceOfAssignability.ts, 35, 5)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 31, 13)) +>y : Symbol(y, Decl(instanceOfAssignability.ts, 41, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 37, 13)) } } function fn4(x: Base|Derived2) { ->fn4 : Symbol(fn4, Decl(instanceOfAssignability.ts, 37, 1)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) +>fn4 : Symbol(fn4, Decl(instanceOfAssignability.ts, 43, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 45, 13)) >Base : Symbol(Base, Decl(instanceOfAssignability.ts, 0, 0)) >Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) if(x instanceof Derived1) { ->x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 45, 13)) >Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) // 1.5: y: {} // Want: Derived1 let y = x; ->y : Symbol(y, Decl(instanceOfAssignability.ts, 43, 5)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 39, 13)) +>y : Symbol(y, Decl(instanceOfAssignability.ts, 49, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 45, 13)) } } function fn5(x: Derived1) { ->fn5 : Symbol(fn5, Decl(instanceOfAssignability.ts, 45, 1)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) +>fn5 : Symbol(fn5, Decl(instanceOfAssignability.ts, 51, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 53, 13)) >Derived1 : Symbol(Derived1, Decl(instanceOfAssignability.ts, 3, 1)) if(x instanceof Derived2) { ->x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 53, 13)) >Derived2 : Symbol(Derived2, Decl(instanceOfAssignability.ts, 8, 1)) // 1.5: y: Derived1 // Want: ??? let y = x; ->y : Symbol(y, Decl(instanceOfAssignability.ts, 51, 5)) ->x : Symbol(x, Decl(instanceOfAssignability.ts, 47, 13)) +>y : Symbol(y, Decl(instanceOfAssignability.ts, 57, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 53, 13)) } } +function fn6(x: Animal|Mammal) { +>fn6 : Symbol(fn6, Decl(instanceOfAssignability.ts, 59, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 61, 13)) +>Animal : Symbol(Animal, Decl(instanceOfAssignability.ts, 13, 1)) +>Mammal : Symbol(Mammal, Decl(instanceOfAssignability.ts, 17, 1)) + + if(x instanceof Giraffe) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 61, 13)) +>Giraffe : Symbol(Giraffe, Decl(instanceOfAssignability.ts, 18, 37)) + + // 1.5: y: Derived1 + // Want: ??? + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 65, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 61, 13)) + } +} + +function fn7(x: Array|Array) { +>fn7 : Symbol(fn7, Decl(instanceOfAssignability.ts, 67, 1)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 69, 13)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) + + if(x instanceof Array) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 69, 13)) +>Array : Symbol(Array, Decl(lib.d.ts, 1000, 23), Decl(lib.d.ts, 1171, 11)) + + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 73, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 69, 13)) + } +} + +interface Alpha { a } +>Alpha : Symbol(Alpha, Decl(instanceOfAssignability.ts, 75, 1)) +>a : Symbol(a, Decl(instanceOfAssignability.ts, 77, 17)) + +interface Beta { b } +>Beta : Symbol(Beta, Decl(instanceOfAssignability.ts, 77, 21)) +>b : Symbol(b, Decl(instanceOfAssignability.ts, 78, 16)) + +interface Gamma { c } +>Gamma : Symbol(Gamma, Decl(instanceOfAssignability.ts, 78, 20)) +>c : Symbol(c, Decl(instanceOfAssignability.ts, 79, 17)) + +class ABC { a; b; c; } +>ABC : Symbol(ABC, Decl(instanceOfAssignability.ts, 79, 21)) +>a : Symbol(a, Decl(instanceOfAssignability.ts, 80, 11)) +>b : Symbol(b, Decl(instanceOfAssignability.ts, 80, 14)) +>c : Symbol(c, Decl(instanceOfAssignability.ts, 80, 17)) + +function fn8(x: Alpha|Beta|Gamma) { +>fn8 : Symbol(fn8, Decl(instanceOfAssignability.ts, 80, 22)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 81, 13)) +>Alpha : Symbol(Alpha, Decl(instanceOfAssignability.ts, 75, 1)) +>Beta : Symbol(Beta, Decl(instanceOfAssignability.ts, 77, 21)) +>Gamma : Symbol(Gamma, Decl(instanceOfAssignability.ts, 78, 20)) + + if(x instanceof ABC) { +>x : Symbol(x, Decl(instanceOfAssignability.ts, 81, 13)) +>ABC : Symbol(ABC, Decl(instanceOfAssignability.ts, 79, 21)) + + let y = x; +>y : Symbol(y, Decl(instanceOfAssignability.ts, 83, 5)) +>x : Symbol(x, Decl(instanceOfAssignability.ts, 81, 13)) + } +} + + + diff --git a/tests/baselines/reference/instanceOfAssignability.types b/tests/baselines/reference/instanceOfAssignability.types index 8e537c4baf..12b2d32606 100644 --- a/tests/baselines/reference/instanceOfAssignability.types +++ b/tests/baselines/reference/instanceOfAssignability.types @@ -29,6 +29,22 @@ class Derived2 implements Base { >optional : number } +class Animal { +>Animal : Animal + + move; +>move : any +} +class Mammal extends Animal { milk; } +>Mammal : Mammal +>Animal : Animal +>milk : any + +class Giraffe extends Mammal { neck; } +>Giraffe : Giraffe +>Mammal : Mammal +>neck : any + function fn1(x: Array|Array|boolean) { >fn1 : (x: number[] | string[] | boolean) => void >x : number[] | string[] | boolean @@ -122,3 +138,79 @@ function fn5(x: Derived1) { } } +function fn6(x: Animal|Mammal) { +>fn6 : (x: Animal | Mammal) => void +>x : Animal | Mammal +>Animal : Animal +>Mammal : Mammal + + if(x instanceof Giraffe) { +>x instanceof Giraffe : boolean +>x : Animal | Mammal +>Giraffe : typeof Giraffe + + // 1.5: y: Derived1 + // Want: ??? + let y = x; +>y : Giraffe +>x : Giraffe + } +} + +function fn7(x: Array|Array) { +>fn7 : (x: number[] | string[]) => void +>x : number[] | string[] +>Array : T[] +>Array : T[] + + if(x instanceof Array) { +>x instanceof Array : boolean +>x : number[] | string[] +>Array : ArrayConstructor + + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; +>y : number[] | string[] +>x : number[] | string[] + } +} + +interface Alpha { a } +>Alpha : Alpha +>a : any + +interface Beta { b } +>Beta : Beta +>b : any + +interface Gamma { c } +>Gamma : Gamma +>c : any + +class ABC { a; b; c; } +>ABC : ABC +>a : any +>b : any +>c : any + +function fn8(x: Alpha|Beta|Gamma) { +>fn8 : (x: Alpha | Beta | Gamma) => void +>x : Alpha | Beta | Gamma +>Alpha : Alpha +>Beta : Beta +>Gamma : Gamma + + if(x instanceof ABC) { +>x instanceof ABC : boolean +>x : Alpha | Beta | Gamma +>ABC : typeof ABC + + let y = x; +>y : ABC +>x : ABC + } +} + + + diff --git a/tests/cases/compiler/instanceOfAssignability.ts b/tests/cases/compiler/instanceOfAssignability.ts index 9f8934b526..909de1ff2a 100644 --- a/tests/cases/compiler/instanceOfAssignability.ts +++ b/tests/cases/compiler/instanceOfAssignability.ts @@ -13,6 +13,12 @@ class Derived2 implements Base { optional: number; } +class Animal { + move; +} +class Mammal extends Animal { milk; } +class Giraffe extends Mammal { neck; } + function fn1(x: Array|Array|boolean) { if(x instanceof Array) { // 1.5: y: Array|Array @@ -52,3 +58,31 @@ function fn5(x: Derived1) { let y = x; } } + +function fn6(x: Animal|Mammal) { + if(x instanceof Giraffe) { + // 1.5: y: Derived1 + // Want: ??? + let y = x; + } +} + +function fn7(x: Array|Array) { + if(x instanceof Array) { + // 1.5: y: Array|Array + // Want: y: Array|Array + let y = x; + } +} + +interface Alpha { a } +interface Beta { b } +interface Gamma { c } +class ABC { a; b; c; } +function fn8(x: Alpha|Beta|Gamma) { + if(x instanceof ABC) { + let y = x; + } +} + +