From 087dcb2d288f8ab9281f27ed6c5eee01223e7596 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 23 Jan 2021 08:58:28 -1000 Subject: [PATCH 1/3] Exclude old number/enum literal compatibility rule from comparable relation --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 49c45384e6df5..8ac9aecfd13af 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16750,7 +16750,7 @@ namespace ts { // numeric enum literal type. This rule exists for backwards compatibility reasons because // bit-flag enum types sometimes look like literal enum types with numeric literal values. if (s & (TypeFlags.Number | TypeFlags.NumberLiteral) && !(s & TypeFlags.EnumLiteral) && ( - t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; + t & TypeFlags.Enum || relation === assignableRelation && t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; } return false; } From 635a24b16ed483714cfb691c8edc40df389400b2 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 24 Jan 2021 07:03:31 -1000 Subject: [PATCH 2/3] Add tests --- .../comparable/equalityWithEnumTypes.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts diff --git a/tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts b/tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts new file mode 100644 index 0000000000000..31a902049e202 --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts @@ -0,0 +1,43 @@ +// @strict: true + +// Literal enum type +enum E1 { + a = 1, + b = 2, +} + +// Numeric enum type +enum E2 { + a = 1 << 0, + b = 1 << 1 +} + +function f1(v: E1) { + if (v !== 0) { // Error + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { // Error + v; + } +} + +function f2(v: E2) { + if (v !== 0) { + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { + v; + } +} From fd1a4cbd0e5c06248ce65a38410b6b1680760b28 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 24 Jan 2021 07:03:39 -1000 Subject: [PATCH 3/3] Accept new baselines --- .../equalityWithEnumTypes.errors.txt | 51 +++++++++ .../reference/equalityWithEnumTypes.js | 86 ++++++++++++++ .../reference/equalityWithEnumTypes.symbols | 85 ++++++++++++++ .../reference/equalityWithEnumTypes.types | 107 ++++++++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 tests/baselines/reference/equalityWithEnumTypes.errors.txt create mode 100644 tests/baselines/reference/equalityWithEnumTypes.js create mode 100644 tests/baselines/reference/equalityWithEnumTypes.symbols create mode 100644 tests/baselines/reference/equalityWithEnumTypes.types diff --git a/tests/baselines/reference/equalityWithEnumTypes.errors.txt b/tests/baselines/reference/equalityWithEnumTypes.errors.txt new file mode 100644 index 0000000000000..ebe0b71982717 --- /dev/null +++ b/tests/baselines/reference/equalityWithEnumTypes.errors.txt @@ -0,0 +1,51 @@ +tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts(14,9): error TS2367: This condition will always return 'true' since the types 'E1' and '0' have no overlap. +tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts(23,9): error TS2367: This condition will always return 'true' since the types 'E1' and '3' have no overlap. + + +==== tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts (2 errors) ==== + // Literal enum type + enum E1 { + a = 1, + b = 2, + } + + // Numeric enum type + enum E2 { + a = 1 << 0, + b = 1 << 1 + } + + function f1(v: E1) { + if (v !== 0) { // Error + ~~~~~~~ +!!! error TS2367: This condition will always return 'true' since the types 'E1' and '0' have no overlap. + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { // Error + ~~~~~~~ +!!! error TS2367: This condition will always return 'true' since the types 'E1' and '3' have no overlap. + v; + } + } + + function f2(v: E2) { + if (v !== 0) { + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { + v; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/equalityWithEnumTypes.js b/tests/baselines/reference/equalityWithEnumTypes.js new file mode 100644 index 0000000000000..31e33c5bddad5 --- /dev/null +++ b/tests/baselines/reference/equalityWithEnumTypes.js @@ -0,0 +1,86 @@ +//// [equalityWithEnumTypes.ts] +// Literal enum type +enum E1 { + a = 1, + b = 2, +} + +// Numeric enum type +enum E2 { + a = 1 << 0, + b = 1 << 1 +} + +function f1(v: E1) { + if (v !== 0) { // Error + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { // Error + v; + } +} + +function f2(v: E2) { + if (v !== 0) { + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { + v; + } +} + + +//// [equalityWithEnumTypes.js] +"use strict"; +// Literal enum type +var E1; +(function (E1) { + E1[E1["a"] = 1] = "a"; + E1[E1["b"] = 2] = "b"; +})(E1 || (E1 = {})); +// Numeric enum type +var E2; +(function (E2) { + E2[E2["a"] = 1] = "a"; + E2[E2["b"] = 2] = "b"; +})(E2 || (E2 = {})); +function f1(v) { + if (v !== 0) { // Error + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { // Error + v; + } +} +function f2(v) { + if (v !== 0) { + v; + } + if (v !== 1) { + v; + } + if (v !== 2) { + v; + } + if (v !== 3) { + v; + } +} diff --git a/tests/baselines/reference/equalityWithEnumTypes.symbols b/tests/baselines/reference/equalityWithEnumTypes.symbols new file mode 100644 index 0000000000000..e3fe037eb2bcd --- /dev/null +++ b/tests/baselines/reference/equalityWithEnumTypes.symbols @@ -0,0 +1,85 @@ +=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts === +// Literal enum type +enum E1 { +>E1 : Symbol(E1, Decl(equalityWithEnumTypes.ts, 0, 0)) + + a = 1, +>a : Symbol(E1.a, Decl(equalityWithEnumTypes.ts, 1, 9)) + + b = 2, +>b : Symbol(E1.b, Decl(equalityWithEnumTypes.ts, 2, 10)) +} + +// Numeric enum type +enum E2 { +>E2 : Symbol(E2, Decl(equalityWithEnumTypes.ts, 4, 1)) + + a = 1 << 0, +>a : Symbol(E2.a, Decl(equalityWithEnumTypes.ts, 7, 9)) + + b = 1 << 1 +>b : Symbol(E2.b, Decl(equalityWithEnumTypes.ts, 8, 15)) +} + +function f1(v: E1) { +>f1 : Symbol(f1, Decl(equalityWithEnumTypes.ts, 10, 1)) +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) +>E1 : Symbol(E1, Decl(equalityWithEnumTypes.ts, 0, 0)) + + if (v !== 0) { // Error +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + } + if (v !== 1) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + } + if (v !== 2) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + } + if (v !== 3) { // Error +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 12, 12)) + } +} + +function f2(v: E2) { +>f2 : Symbol(f2, Decl(equalityWithEnumTypes.ts, 25, 1)) +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) +>E2 : Symbol(E2, Decl(equalityWithEnumTypes.ts, 4, 1)) + + if (v !== 0) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + } + if (v !== 1) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + } + if (v !== 2) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + } + if (v !== 3) { +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + + v; +>v : Symbol(v, Decl(equalityWithEnumTypes.ts, 27, 12)) + } +} + diff --git a/tests/baselines/reference/equalityWithEnumTypes.types b/tests/baselines/reference/equalityWithEnumTypes.types new file mode 100644 index 0000000000000..935989418df22 --- /dev/null +++ b/tests/baselines/reference/equalityWithEnumTypes.types @@ -0,0 +1,107 @@ +=== tests/cases/conformance/types/typeRelationships/comparable/equalityWithEnumTypes.ts === +// Literal enum type +enum E1 { +>E1 : E1 + + a = 1, +>a : E1.a +>1 : 1 + + b = 2, +>b : E1.b +>2 : 2 +} + +// Numeric enum type +enum E2 { +>E2 : E2 + + a = 1 << 0, +>a : E2 +>1 << 0 : number +>1 : 1 +>0 : 0 + + b = 1 << 1 +>b : E2 +>1 << 1 : number +>1 : 1 +>1 : 1 +} + +function f1(v: E1) { +>f1 : (v: E1) => void +>v : E1 + + if (v !== 0) { // Error +>v !== 0 : boolean +>v : E1 +>0 : 0 + + v; +>v : E1 + } + if (v !== 1) { +>v !== 1 : boolean +>v : E1 +>1 : 1 + + v; +>v : E1.b + } + if (v !== 2) { +>v !== 2 : boolean +>v : E1 +>2 : 2 + + v; +>v : E1.a + } + if (v !== 3) { // Error +>v !== 3 : boolean +>v : E1 +>3 : 3 + + v; +>v : E1 + } +} + +function f2(v: E2) { +>f2 : (v: E2) => void +>v : E2 + + if (v !== 0) { +>v !== 0 : boolean +>v : E2 +>0 : 0 + + v; +>v : E2 + } + if (v !== 1) { +>v !== 1 : boolean +>v : E2 +>1 : 1 + + v; +>v : E2 + } + if (v !== 2) { +>v !== 2 : boolean +>v : E2 +>2 : 2 + + v; +>v : E2 + } + if (v !== 3) { +>v !== 3 : boolean +>v : E2 +>3 : 3 + + v; +>v : E2 + } +} +