Skip to content

Commit 6775d88

Browse files
author
Arthur Ozga
committed
Merge pull request #3333 from aozgaa/mergedDeclarationClassInterface
Merged Declarations for Classes and Interfaces
2 parents 77d9362 + 3af3177 commit 6775d88

File tree

47 files changed

+1163
-138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1163
-138
lines changed

src/compiler/binder.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ namespace ts {
173173
return node.name ? declarationNameToString(node.name) : getDeclarationName(node);
174174
}
175175

176+
/**
177+
* Declares a Symbol for the node and adds it to symbols. Reports errors for conflicting identifier names.
178+
* @param symbolTable - The symbol table which node will be added to.
179+
* @param parent - node's parent declaration.
180+
* @param node - The declaration to be added to the symbol table
181+
* @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
182+
* @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
183+
*/
176184
function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
177185
Debug.assert(!hasDynamicName(node));
178186

@@ -181,10 +189,11 @@ namespace ts {
181189

182190
let symbol: Symbol;
183191
if (name !== undefined) {
192+
184193
// Check and see if the symbol table already has a symbol with this name. If not,
185194
// create a new symbol with this name and add it to the table. Note that we don't
186195
// give the new symbol any flags *yet*. This ensures that it will not conflict
187-
// witht he 'excludes' flags we pass in.
196+
// with the 'excludes' flags we pass in.
188197
//
189198
// If we do get an existing symbol, see if it conflicts with the new symbol we're
190199
// creating. For example, a 'var' symbol and a 'class' symbol will conflict within
@@ -202,10 +211,10 @@ namespace ts {
202211
symbol = hasProperty(symbolTable, name)
203212
? symbolTable[name]
204213
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
205-
214+
206215
if (name && (includes & SymbolFlags.Classifiable)) {
207-
classifiableNames[name] = name;
208-
}
216+
classifiableNames[name] = name;
217+
}
209218

210219
if (symbol.flags & excludes) {
211220
if (node.name) {
@@ -314,6 +323,7 @@ namespace ts {
314323

315324
addToContainerChain(container);
316325
}
326+
317327
else if (containerFlags & ContainerFlags.IsBlockScopedContainer) {
318328
blockScopeContainer = node;
319329
blockScopeContainer.locals = undefined;

src/compiler/checker.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12034,6 +12034,12 @@ namespace ts {
1203412034
grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name);
1203512035
}
1203612036
checkClassLikeDeclaration(node);
12037+
12038+
// Interfaces cannot be merged with non-ambient classes.
12039+
if (getSymbolOfNode(node).flags & SymbolFlags.Interface && !isInAmbientContext(node)) {
12040+
error(node, Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface)
12041+
}
12042+
1203712043
forEach(node.members, checkSourceElement);
1203812044
}
1203912045

@@ -12306,13 +12312,24 @@ namespace ts {
1230612312
checkIndexConstraints(type);
1230712313
}
1230812314
}
12315+
12316+
// Interfaces cannot merge with non-ambient classes.
12317+
if (symbol && symbol.declarations) {
12318+
for (let declaration of symbol.declarations) {
12319+
if (declaration.kind === SyntaxKind.ClassDeclaration && !isInAmbientContext(declaration)) {
12320+
error(node, Diagnostics.Only_an_ambient_class_can_be_merged_with_an_interface);
12321+
break;
12322+
}
12323+
}
12324+
}
1230912325
}
1231012326
forEach(getInterfaceBaseTypeNodes(node), heritageElement => {
1231112327
if (!isSupportedExpressionWithTypeArguments(heritageElement)) {
1231212328
error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments);
1231312329
}
1231412330
checkTypeReferenceNode(heritageElement);
1231512331
});
12332+
1231612333
forEach(node.members, checkSourceElement);
1231712334

1231812335
if (produceDiagnostics) {

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ namespace ts {
408408
Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." },
409409
All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." },
410410
Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type: { code: 2517, category: DiagnosticCategory.Error, key: "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type" },
411+
Only_an_ambient_class_can_be_merged_with_an_interface: { code: 2518, category: DiagnosticCategory.Error, key: "Only an ambient class can be merged with an interface." },
411412
Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." },
412413
Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." },
413414
The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." },

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,10 @@
16211621
"category": "Error",
16221622
"code":2517
16231623
},
1624+
"Only an ambient class can be merged with an interface.": {
1625+
"category": "Error",
1626+
"code": 2518
1627+
},
16241628
"Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": {
16251629
"category": "Error",
16261630
"code": 2520

src/compiler/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,8 +1597,8 @@ namespace ts {
15971597
PropertyExcludes = Value,
15981598
EnumMemberExcludes = Value,
15991599
FunctionExcludes = Value & ~(Function | ValueModule),
1600-
ClassExcludes = (Value | Type) & ~ValueModule,
1601-
InterfaceExcludes = Type & ~Interface,
1600+
ClassExcludes = (Value | Type) & ~(ValueModule | Interface), // class-interface mergability done in checker.ts
1601+
InterfaceExcludes = Type & ~(Interface | Class),
16021602
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
16031603
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
16041604
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),

tests/baselines/reference/augmentedTypesClass2.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/compiler/augmentedTypesClass2.ts(4,7): error TS2300: Duplicate identifier 'c11'.
2-
tests/cases/compiler/augmentedTypesClass2.ts(10,11): error TS2300: Duplicate identifier 'c11'.
1+
tests/cases/compiler/augmentedTypesClass2.ts(4,7): error TS2518: Only an ambient class can be merged with an interface.
2+
tests/cases/compiler/augmentedTypesClass2.ts(10,11): error TS2518: Only an ambient class can be merged with an interface.
33
tests/cases/compiler/augmentedTypesClass2.ts(16,7): error TS2300: Duplicate identifier 'c33'.
44
tests/cases/compiler/augmentedTypesClass2.ts(21,6): error TS2300: Duplicate identifier 'c33'.
55

@@ -10,15 +10,15 @@ tests/cases/compiler/augmentedTypesClass2.ts(21,6): error TS2300: Duplicate iden
1010
// class then interface
1111
class c11 { // error
1212
~~~
13-
!!! error TS2300: Duplicate identifier 'c11'.
13+
!!! error TS2518: Only an ambient class can be merged with an interface.
1414
foo() {
1515
return 1;
1616
}
1717
}
1818

1919
interface c11 { // error
2020
~~~
21-
!!! error TS2300: Duplicate identifier 'c11'.
21+
!!! error TS2518: Only an ambient class can be merged with an interface.
2222
bar(): void;
2323
}
2424

tests/baselines/reference/augmentedTypesInterface.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/compiler/augmentedTypesInterface.ts(12,11): error TS2300: Duplicate identifier 'i2'.
2-
tests/cases/compiler/augmentedTypesInterface.ts(16,7): error TS2300: Duplicate identifier 'i2'.
1+
tests/cases/compiler/augmentedTypesInterface.ts(12,11): error TS2518: Only an ambient class can be merged with an interface.
2+
tests/cases/compiler/augmentedTypesInterface.ts(16,7): error TS2518: Only an ambient class can be merged with an interface.
33
tests/cases/compiler/augmentedTypesInterface.ts(23,11): error TS2300: Duplicate identifier 'i3'.
44
tests/cases/compiler/augmentedTypesInterface.ts(26,6): error TS2300: Duplicate identifier 'i3'.
55

@@ -18,13 +18,13 @@ tests/cases/compiler/augmentedTypesInterface.ts(26,6): error TS2300: Duplicate i
1818
// interface then class
1919
interface i2 { // error
2020
~~
21-
!!! error TS2300: Duplicate identifier 'i2'.
21+
!!! error TS2518: Only an ambient class can be merged with an interface.
2222
foo(): void;
2323
}
2424

2525
class i2 { // error
2626
~~
27-
!!! error TS2300: Duplicate identifier 'i2'.
27+
!!! error TS2518: Only an ambient class can be merged with an interface.
2828
bar() {
2929
return 1;
3030
}

tests/baselines/reference/class1.errors.txt

Lines changed: 0 additions & 11 deletions
This file was deleted.

tests/baselines/reference/class1.js

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(7,16): error TS2300: Duplicate identifier 'CI'.
2-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(8,11): error TS2300: Duplicate identifier 'CI'.
3-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(10,11): error TS2300: Duplicate identifier 'IC'.
4-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(11,16): error TS2300: Duplicate identifier 'IC'.
1+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(7,16): error TS2518: Only an ambient class can be merged with an interface.
2+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(8,11): error TS2518: Only an ambient class can be merged with an interface.
3+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(10,11): error TS2518: Only an ambient class can be merged with an interface.
4+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(11,16): error TS2518: Only an ambient class can be merged with an interface.
55
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(13,16): error TS2300: Duplicate identifier 'CC1'.
66
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(14,7): error TS2300: Duplicate identifier 'CC1'.
77
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(16,7): error TS2300: Duplicate identifier 'CC2'.
88
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(17,16): error TS2300: Duplicate identifier 'CC2'.
9-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(19,1): error TS2511: Cannot create an instance of the abstract class 'CM'.
10-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(20,1): error TS2511: Cannot create an instance of the abstract class 'MC'.
11-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(21,1): error TS2511: Cannot create an instance of the abstract class 'CI'.
12-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(22,5): error TS2304: Cannot find name 'IC'.
13-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(23,1): error TS2511: Cannot create an instance of the abstract class 'CC1'.
9+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(25,24): error TS2300: Duplicate identifier 'DCC1'.
10+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(26,15): error TS2300: Duplicate identifier 'DCC1'.
11+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(28,15): error TS2300: Duplicate identifier 'DCC2'.
12+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(29,24): error TS2300: Duplicate identifier 'DCC2'.
13+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(31,1): error TS2511: Cannot create an instance of the abstract class 'CM'.
14+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(32,1): error TS2511: Cannot create an instance of the abstract class 'MC'.
15+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(33,1): error TS2511: Cannot create an instance of the abstract class 'CI'.
16+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(34,1): error TS2511: Cannot create an instance of the abstract class 'IC'.
17+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(35,1): error TS2511: Cannot create an instance of the abstract class 'CC1'.
18+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(37,1): error TS2511: Cannot create an instance of the abstract class 'DCI'.
19+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(38,1): error TS2511: Cannot create an instance of the abstract class 'DIC'.
20+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts(39,1): error TS2511: Cannot create an instance of the abstract class 'DCC1'.
1421

1522

16-
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts (13 errors) ====
23+
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractMergedDeclaration.ts (20 errors) ====
1724
abstract class CM {}
1825
module CM {}
1926

@@ -22,17 +29,17 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
2229

2330
abstract class CI {}
2431
~~
25-
!!! error TS2300: Duplicate identifier 'CI'.
32+
!!! error TS2518: Only an ambient class can be merged with an interface.
2633
interface CI {}
2734
~~
28-
!!! error TS2300: Duplicate identifier 'CI'.
35+
!!! error TS2518: Only an ambient class can be merged with an interface.
2936

3037
interface IC {}
3138
~~
32-
!!! error TS2300: Duplicate identifier 'IC'.
39+
!!! error TS2518: Only an ambient class can be merged with an interface.
3340
abstract class IC {}
3441
~~
35-
!!! error TS2300: Duplicate identifier 'IC'.
42+
!!! error TS2518: Only an ambient class can be merged with an interface.
3643

3744
abstract class CC1 {}
3845
~~~
@@ -48,6 +55,26 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
4855
~~~
4956
!!! error TS2300: Duplicate identifier 'CC2'.
5057

58+
declare abstract class DCI {}
59+
interface DCI {}
60+
61+
interface DIC {}
62+
declare abstract class DIC {}
63+
64+
declare abstract class DCC1 {}
65+
~~~~
66+
!!! error TS2300: Duplicate identifier 'DCC1'.
67+
declare class DCC1 {}
68+
~~~~
69+
!!! error TS2300: Duplicate identifier 'DCC1'.
70+
71+
declare class DCC2 {}
72+
~~~~
73+
!!! error TS2300: Duplicate identifier 'DCC2'.
74+
declare abstract class DCC2 {}
75+
~~~~
76+
!!! error TS2300: Duplicate identifier 'DCC2'.
77+
5178
new CM;
5279
~~~~~~
5380
!!! error TS2511: Cannot create an instance of the abstract class 'CM'.
@@ -58,9 +85,19 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
5885
~~~~~~
5986
!!! error TS2511: Cannot create an instance of the abstract class 'CI'.
6087
new IC;
61-
~~
62-
!!! error TS2304: Cannot find name 'IC'.
88+
~~~~~~
89+
!!! error TS2511: Cannot create an instance of the abstract class 'IC'.
6390
new CC1;
6491
~~~~~~~
6592
!!! error TS2511: Cannot create an instance of the abstract class 'CC1'.
66-
new CC2;
93+
new CC2;
94+
new DCI;
95+
~~~~~~~
96+
!!! error TS2511: Cannot create an instance of the abstract class 'DCI'.
97+
new DIC;
98+
~~~~~~~
99+
!!! error TS2511: Cannot create an instance of the abstract class 'DIC'.
100+
new DCC1;
101+
~~~~~~~~
102+
!!! error TS2511: Cannot create an instance of the abstract class 'DCC1'.
103+
new DCC2;

tests/baselines/reference/classAbstractMergedDeclaration.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,28 @@ class CC1 {}
1717
class CC2 {}
1818
abstract class CC2 {}
1919

20+
declare abstract class DCI {}
21+
interface DCI {}
22+
23+
interface DIC {}
24+
declare abstract class DIC {}
25+
26+
declare abstract class DCC1 {}
27+
declare class DCC1 {}
28+
29+
declare class DCC2 {}
30+
declare abstract class DCC2 {}
31+
2032
new CM;
2133
new MC;
2234
new CI;
2335
new IC;
2436
new CC1;
25-
new CC2;
37+
new CC2;
38+
new DCI;
39+
new DIC;
40+
new DCC1;
41+
new DCC2;
2642

2743
//// [classAbstractMergedDeclaration.js]
2844
var CM = (function () {
@@ -71,3 +87,7 @@ new CI;
7187
new IC;
7288
new CC1;
7389
new CC2;
90+
new DCI;
91+
new DIC;
92+
new DCC1;
93+
new DCC2;

tests/baselines/reference/classAndInterface1.errors.txt

Lines changed: 0 additions & 11 deletions
This file was deleted.

tests/baselines/reference/classAndInterface1.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)