Merge pull request #6036 from Microsoft/structural-enums
Compare enums semi-structurally.
This commit is contained in:
commit
4d792f2014
4 changed files with 446 additions and 0 deletions
|
@ -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
|
||||
|
|
129
tests/baselines/reference/enumAssignmentCompat3.errors.txt
Normal file
129
tests/baselines/reference/enumAssignmentCompat3.errors.txt
Normal 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
|
202
tests/baselines/reference/enumAssignmentCompat3.js
Normal file
202
tests/baselines/reference/enumAssignmentCompat3.js
Normal 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
|
89
tests/cases/compiler/enumAssignmentCompat3.ts
Normal file
89
tests/cases/compiler/enumAssignmentCompat3.ts
Normal 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
|
Loading…
Reference in a new issue