Merge pull request #6036 from Microsoft/structural-enums

Compare enums semi-structurally.
This commit is contained in:
Nathan Shively-Sanders 2015-12-17 16:31:03 -08:00
commit 4d792f2014
4 changed files with 446 additions and 0 deletions

View file

@ -5066,6 +5066,11 @@ namespace ts {
if (source === undefinedType) return Ternary.True;
if (source === nullType && target !== undefinedType) return Ternary.True;
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
if (result = enumRelatedTo(source, target)) {
return result;
}
}
if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
if (relation === assignableRelation) {
if (isTypeAny(source)) return Ternary.True;
@ -5780,6 +5785,27 @@ namespace ts {
}
return Ternary.False;
}
function enumRelatedTo(source: Type, target: Type) {
if (source.symbol.name !== target.symbol.name ||
source.symbol.flags & SymbolFlags.ConstEnum ||
target.symbol.flags & SymbolFlags.ConstEnum) {
return Ternary.False;
}
const targetEnumType = getTypeOfSymbol(target.symbol);
for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
if (property.flags & SymbolFlags.EnumMember) {
const targetProperty = getPropertyOfType(targetEnumType, property.name);
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
reportError(Diagnostics.Property_0_is_missing_in_type_1,
property.name,
typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
return Ternary.False;
}
}
}
return Ternary.True;
}
}
// Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case

View file

@ -0,0 +1,129 @@
tests/cases/compiler/enumAssignmentCompat3.ts(68,1): error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'.
Property 'd' is missing in type 'First.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(70,1): error TS2322: Type 'Cd.E' is not assignable to type 'First.E'.
Property 'd' is missing in type 'First.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(71,1): error TS2322: Type 'Nope' is not assignable to type 'E'.
tests/cases/compiler/enumAssignmentCompat3.ts(75,1): error TS2322: Type 'First.E' is not assignable to type 'Ab.E'.
Property 'c' is missing in type 'Ab.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(76,1): error TS2322: Type 'First.E' is not assignable to type 'Cd.E'.
Property 'a' is missing in type 'Cd.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(77,1): error TS2322: Type 'E' is not assignable to type 'Nope'.
tests/cases/compiler/enumAssignmentCompat3.ts(82,1): error TS2322: Type 'Const.E' is not assignable to type 'First.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(83,1): error TS2322: Type 'First.E' is not assignable to type 'Const.E'.
tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2322: Type 'Merged.E' is not assignable to type 'First.E'.
Property 'd' is missing in type 'First.E'.
==== tests/cases/compiler/enumAssignmentCompat3.ts (9 errors) ====
namespace First {
export enum E {
a, b, c,
}
}
namespace Abc {
export enum E {
a, b, c,
}
export enum Nope {
a, b, c,
}
}
namespace Abcd {
export enum E {
a, b, c, d,
}
}
namespace Ab {
export enum E {
a, b,
}
}
namespace Cd {
export enum E {
c, d,
}
}
namespace Const {
export const enum E {
a, b, c,
}
}
namespace Decl {
export declare enum E {
a, b, c = 3,
}
}
namespace Merged {
export enum E {
a, b,
}
export enum E {
c = 3, d,
}
}
namespace Merged2 {
export enum E {
a, b, c
}
export module E {
export let d = 5;
}
}
var abc: First.E;
var secondAbc: Abc.E;
var secondAbcd: Abcd.E;
var secondAb: Ab.E;
var secondCd: Cd.E;
var nope: Abc.Nope;
var k: Const.E;
var decl: Decl.E;
var merged: Merged.E;
var merged2: Merged2.E;
abc = secondAbc; // ok
abc = secondAbcd; // missing 'd'
~~~
!!! error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'.
!!! error TS2322: Property 'd' is missing in type 'First.E'.
abc = secondAb; // ok
abc = secondCd; // missing 'd'
~~~
!!! error TS2322: Type 'Cd.E' is not assignable to type 'First.E'.
!!! error TS2322: Property 'd' is missing in type 'First.E'.
abc = nope; // nope!
~~~
!!! error TS2322: Type 'Nope' is not assignable to type 'E'.
abc = decl; // ok
secondAbc = abc; // ok
secondAbcd = abc; // ok
secondAb = abc; // missing 'c'
~~~~~~~~
!!! error TS2322: Type 'First.E' is not assignable to type 'Ab.E'.
!!! error TS2322: Property 'c' is missing in type 'Ab.E'.
secondCd = abc; // missing 'a' and 'b'
~~~~~~~~
!!! error TS2322: Type 'First.E' is not assignable to type 'Cd.E'.
!!! error TS2322: Property 'a' is missing in type 'Cd.E'.
nope = abc; // nope!
~~~~
!!! error TS2322: Type 'E' is not assignable to type 'Nope'.
decl = abc; // ok
// const is only assignable to itself
k = k;
abc = k; // error
~~~
!!! error TS2322: Type 'Const.E' is not assignable to type 'First.E'.
k = abc;
~
!!! error TS2322: Type 'First.E' is not assignable to type 'Const.E'.
// merged enums compare all their members
abc = merged; // missing 'd'
~~~
!!! error TS2322: Type 'Merged.E' is not assignable to type 'First.E'.
!!! error TS2322: Property 'd' is missing in type 'First.E'.
merged = abc; // ok
abc = merged2; // ok
merged2 = abc; // ok

View file

@ -0,0 +1,202 @@
//// [enumAssignmentCompat3.ts]
namespace First {
export enum E {
a, b, c,
}
}
namespace Abc {
export enum E {
a, b, c,
}
export enum Nope {
a, b, c,
}
}
namespace Abcd {
export enum E {
a, b, c, d,
}
}
namespace Ab {
export enum E {
a, b,
}
}
namespace Cd {
export enum E {
c, d,
}
}
namespace Const {
export const enum E {
a, b, c,
}
}
namespace Decl {
export declare enum E {
a, b, c = 3,
}
}
namespace Merged {
export enum E {
a, b,
}
export enum E {
c = 3, d,
}
}
namespace Merged2 {
export enum E {
a, b, c
}
export module E {
export let d = 5;
}
}
var abc: First.E;
var secondAbc: Abc.E;
var secondAbcd: Abcd.E;
var secondAb: Ab.E;
var secondCd: Cd.E;
var nope: Abc.Nope;
var k: Const.E;
var decl: Decl.E;
var merged: Merged.E;
var merged2: Merged2.E;
abc = secondAbc; // ok
abc = secondAbcd; // missing 'd'
abc = secondAb; // ok
abc = secondCd; // missing 'd'
abc = nope; // nope!
abc = decl; // ok
secondAbc = abc; // ok
secondAbcd = abc; // ok
secondAb = abc; // missing 'c'
secondCd = abc; // missing 'a' and 'b'
nope = abc; // nope!
decl = abc; // ok
// const is only assignable to itself
k = k;
abc = k; // error
k = abc;
// merged enums compare all their members
abc = merged; // missing 'd'
merged = abc; // ok
abc = merged2; // ok
merged2 = abc; // ok
//// [enumAssignmentCompat3.js]
var First;
(function (First) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
})(First.E || (First.E = {}));
var E = First.E;
})(First || (First = {}));
var Abc;
(function (Abc) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
})(Abc.E || (Abc.E = {}));
var E = Abc.E;
(function (Nope) {
Nope[Nope["a"] = 0] = "a";
Nope[Nope["b"] = 1] = "b";
Nope[Nope["c"] = 2] = "c";
})(Abc.Nope || (Abc.Nope = {}));
var Nope = Abc.Nope;
})(Abc || (Abc = {}));
var Abcd;
(function (Abcd) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
E[E["d"] = 3] = "d";
})(Abcd.E || (Abcd.E = {}));
var E = Abcd.E;
})(Abcd || (Abcd = {}));
var Ab;
(function (Ab) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
})(Ab.E || (Ab.E = {}));
var E = Ab.E;
})(Ab || (Ab = {}));
var Cd;
(function (Cd) {
(function (E) {
E[E["c"] = 0] = "c";
E[E["d"] = 1] = "d";
})(Cd.E || (Cd.E = {}));
var E = Cd.E;
})(Cd || (Cd = {}));
var Decl;
(function (Decl) {
})(Decl || (Decl = {}));
var Merged;
(function (Merged) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
})(Merged.E || (Merged.E = {}));
var E = Merged.E;
(function (E) {
E[E["c"] = 3] = "c";
E[E["d"] = 4] = "d";
})(Merged.E || (Merged.E = {}));
var E = Merged.E;
})(Merged || (Merged = {}));
var Merged2;
(function (Merged2) {
(function (E) {
E[E["a"] = 0] = "a";
E[E["b"] = 1] = "b";
E[E["c"] = 2] = "c";
})(Merged2.E || (Merged2.E = {}));
var E = Merged2.E;
var E;
(function (E) {
E.d = 5;
})(E = Merged2.E || (Merged2.E = {}));
})(Merged2 || (Merged2 = {}));
var abc;
var secondAbc;
var secondAbcd;
var secondAb;
var secondCd;
var nope;
var k;
var decl;
var merged;
var merged2;
abc = secondAbc; // ok
abc = secondAbcd; // missing 'd'
abc = secondAb; // ok
abc = secondCd; // missing 'd'
abc = nope; // nope!
abc = decl; // ok
secondAbc = abc; // ok
secondAbcd = abc; // ok
secondAb = abc; // missing 'c'
secondCd = abc; // missing 'a' and 'b'
nope = abc; // nope!
decl = abc; // ok
// const is only assignable to itself
k = k;
abc = k; // error
k = abc;
// merged enums compare all their members
abc = merged; // missing 'd'
merged = abc; // ok
abc = merged2; // ok
merged2 = abc; // ok

View file

@ -0,0 +1,89 @@
namespace First {
export enum E {
a, b, c,
}
}
namespace Abc {
export enum E {
a, b, c,
}
export enum Nope {
a, b, c,
}
}
namespace Abcd {
export enum E {
a, b, c, d,
}
}
namespace Ab {
export enum E {
a, b,
}
}
namespace Cd {
export enum E {
c, d,
}
}
namespace Const {
export const enum E {
a, b, c,
}
}
namespace Decl {
export declare enum E {
a, b, c = 3,
}
}
namespace Merged {
export enum E {
a, b,
}
export enum E {
c = 3, d,
}
}
namespace Merged2 {
export enum E {
a, b, c
}
export module E {
export let d = 5;
}
}
var abc: First.E;
var secondAbc: Abc.E;
var secondAbcd: Abcd.E;
var secondAb: Ab.E;
var secondCd: Cd.E;
var nope: Abc.Nope;
var k: Const.E;
var decl: Decl.E;
var merged: Merged.E;
var merged2: Merged2.E;
abc = secondAbc; // ok
abc = secondAbcd; // missing 'd'
abc = secondAb; // ok
abc = secondCd; // missing 'd'
abc = nope; // nope!
abc = decl; // ok
secondAbc = abc; // ok
secondAbcd = abc; // ok
secondAb = abc; // missing 'c'
secondCd = abc; // missing 'a' and 'b'
nope = abc; // nope!
decl = abc; // ok
// const is only assignable to itself
k = k;
abc = k; // error
k = abc;
// merged enums compare all their members
abc = merged; // missing 'd'
merged = abc; // ok
abc = merged2; // ok
merged2 = abc; // ok