Skip to content

Commit ce6b623

Browse files
committed
Support for protected members in classes
1 parent 11b9118 commit ce6b623

File tree

68 files changed

+586
-245
lines changed

Some content is hidden

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

68 files changed

+586
-245
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ module ts {
226226
function bindConstructorDeclaration(node: ConstructorDeclaration) {
227227
bindDeclaration(node, SymbolFlags.Constructor, 0);
228228
forEach(node.parameters, p => {
229-
if (p.flags & (NodeFlags.Public | NodeFlags.Private)) {
229+
if (p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
230230
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
231231
}
232232
});

src/compiler/checker.ts

Lines changed: 109 additions & 75 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ module ts {
138138
Type_0_is_not_assignable_to_type_1_Colon: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}':" },
139139
Type_0_is_not_assignable_to_type_1: { code: 2323, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
140140
Property_0_is_missing_in_type_1: { code: 2324, category: DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." },
141-
Private_property_0_cannot_be_reimplemented: { code: 2325, category: DiagnosticCategory.Error, key: "Private property '{0}' cannot be reimplemented." },
141+
Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." },
142142
Types_of_property_0_are_incompatible_Colon: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible:" },
143-
Required_property_0_cannot_be_reimplemented_with_optional_property_in_1: { code: 2327, category: DiagnosticCategory.Error, key: "Required property '{0}' cannot be reimplemented with optional property in '{1}'." },
143+
Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." },
144144
Types_of_parameters_0_and_1_are_incompatible_Colon: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible:" },
145145
Index_signature_is_missing_in_type_0: { code: 2329, category: DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." },
146146
Index_signatures_are_incompatible_Colon: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible:" },
@@ -153,7 +153,7 @@ module ts {
153153
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" },
154154
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" },
155155
Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." },
156-
Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public methods of the base class are accessible via the 'super' keyword" },
156+
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" },
157157
Property_0_is_inaccessible: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is inaccessible." },
158158
An_index_expression_argument_must_be_of_type_string_number_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', or 'any'." },
159159
Type_0_does_not_satisfy_the_constraint_1_Colon: { code: 2343, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}':" },
@@ -198,7 +198,7 @@ module ts {
198198
Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: { code: 2382, category: DiagnosticCategory.Error, key: "Specialized overload signature is not assignable to any non-specialized signature." },
199199
Overload_signatures_must_all_be_exported_or_not_exported: { code: 2383, category: DiagnosticCategory.Error, key: "Overload signatures must all be exported or not exported." },
200200
Overload_signatures_must_all_be_ambient_or_non_ambient: { code: 2384, category: DiagnosticCategory.Error, key: "Overload signatures must all be ambient or non-ambient." },
201-
Overload_signatures_must_all_be_public_or_private: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public or private." },
201+
Overload_signatures_must_all_be_public_private_or_protected: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public, private or protected." },
202202
Overload_signatures_must_all_be_optional_or_required: { code: 2386, category: DiagnosticCategory.Error, key: "Overload signatures must all be optional or required." },
203203
Function_overload_must_be_static: { code: 2387, category: DiagnosticCategory.Error, key: "Function overload must be static." },
204204
Function_overload_must_not_be_static: { code: 2388, category: DiagnosticCategory.Error, key: "Function overload must not be static." },
@@ -255,6 +255,9 @@ module ts {
255255
Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2439, category: DiagnosticCategory.Error, key: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name." },
256256
Import_declaration_conflicts_with_local_declaration_of_0: { code: 2440, category: DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" },
257257
Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: { code: 2441, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module." },
258+
Types_have_separate_declarations_of_a_private_property_0: { code: 2442, category: DiagnosticCategory.Error, key: "Types have separate declarations of a private property '{0}'." },
259+
Property_0_is_protected_but_type_1_is_not_derived_from_type_2: { code: 2443, category: DiagnosticCategory.Error, key: "Property '{0}' is protected but type '{1}' is not derived from type '{2}'." },
260+
Property_0_is_protected_in_type_1_but_public_in_type_2: { code: 2444, category: DiagnosticCategory.Error, key: "Property '{0}' is protected in type '{1}' but public in type '{2}'." },
258261
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
259262
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
260263
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,15 @@
544544
"category": "Error",
545545
"code": 2324
546546
},
547-
"Private property '{0}' cannot be reimplemented.": {
547+
"Property '{0}' is private in type '{1}' but not in type '{2}'.": {
548548
"category": "Error",
549549
"code": 2325
550550
},
551551
"Types of property '{0}' are incompatible:": {
552552
"category": "Error",
553553
"code": 2326
554554
},
555-
"Required property '{0}' cannot be reimplemented with optional property in '{1}'.": {
555+
"Property '{0}' is optional in type '{1}' but required in type '{2}'.": {
556556
"category": "Error",
557557
"code": 2327
558558
},
@@ -604,7 +604,7 @@
604604
"category": "Error",
605605
"code": 2339
606606
},
607-
"Only public methods of the base class are accessible via the 'super' keyword": {
607+
"Only public and protected methods of the base class are accessible via the 'super' keyword": {
608608
"category": "Error",
609609
"code": 2340
610610
},
@@ -784,7 +784,7 @@
784784
"category": "Error",
785785
"code": 2384
786786
},
787-
"Overload signatures must all be public or private.": {
787+
"Overload signatures must all be public, private or protected.": {
788788
"category": "Error",
789789
"code": 2385
790790
},
@@ -1012,7 +1012,18 @@
10121012
"category": "Error",
10131013
"code": 2441
10141014
},
1015-
1015+
"Types have separate declarations of a private property '{0}'.": {
1016+
"category": "Error",
1017+
"code": 2442
1018+
},
1019+
"Property '{0}' is protected but type '{1}' is not derived from type '{2}'.": {
1020+
"category": "Error",
1021+
"code": 2443
1022+
},
1023+
"Property '{0}' is protected in type '{1}' but public in type '{2}'.": {
1024+
"category": "Error",
1025+
"code": 2444
1026+
},
10161027

10171028
"Import declaration '{0}' is using private name '{1}'.": {
10181029
"category": "Error",

src/compiler/emitter.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ module ts {
14311431

14321432
function emitParameterPropertyAssignments(node: ConstructorDeclaration) {
14331433
forEach(node.parameters, param => {
1434-
if (param.flags & (NodeFlags.Public | NodeFlags.Private)) {
1434+
if (param.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
14351435
writeLine();
14361436
emitStart(param);
14371437
emitStart(param.name);
@@ -2368,12 +2368,18 @@ module ts {
23682368
if (node.flags & NodeFlags.Private) {
23692369
write("private ");
23702370
}
2371+
else if (node.flags & NodeFlags.Protected) {
2372+
write("protected ");
2373+
}
23712374
write("static ");
23722375
}
23732376
else {
23742377
if (node.flags & NodeFlags.Private) {
23752378
write("private ");
23762379
}
2380+
else if (node.flags & NodeFlags.Protected) {
2381+
write("protected ");
2382+
}
23772383
// If the node is parented in the current source file we need to emit export declare or just export
23782384
else if (node.parent === currentSourceFile) {
23792385
// If the node is exported
@@ -2630,7 +2636,7 @@ module ts {
26302636
function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
26312637
if (constructorDeclaration) {
26322638
forEach(constructorDeclaration.parameters, param => {
2633-
if (param.flags & (NodeFlags.Public | NodeFlags.Private)) {
2639+
if (param.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
26342640
emitPropertyDeclaration(param);
26352641
}
26362642
});

src/compiler/parser.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ module ts {
597597
switch (token) {
598598
case SyntaxKind.PublicKeyword:
599599
case SyntaxKind.PrivateKeyword:
600+
case SyntaxKind.ProtectedKeyword:
600601
case SyntaxKind.StaticKeyword:
601602
case SyntaxKind.ExportKeyword:
602603
case SyntaxKind.DeclareKeyword:
@@ -2883,6 +2884,7 @@ module ts {
28832884
}
28842885
case SyntaxKind.PublicKeyword:
28852886
case SyntaxKind.PrivateKeyword:
2887+
case SyntaxKind.ProtectedKeyword:
28862888
case SyntaxKind.StaticKeyword:
28872889
// When followed by an identifier or keyword, these do not start a statement but
28882890
// might instead be following type members
@@ -3201,6 +3203,8 @@ module ts {
32013203
var lastDeclareModifierLength: number;
32023204
var lastPrivateModifierStart: number;
32033205
var lastPrivateModifierLength: number;
3206+
var lastProtectedModifierStart: number;
3207+
var lastProtectedModifierLength: number;
32043208

32053209
while (true) {
32063210
var modifierStart = scanner.getTokenPos();
@@ -3213,7 +3217,7 @@ module ts {
32133217

32143218
switch (modifierToken) {
32153219
case SyntaxKind.PublicKeyword:
3216-
if (flags & NodeFlags.Private || flags & NodeFlags.Public) {
3220+
if (flags & NodeFlags.Public || flags & NodeFlags.Private || flags & NodeFlags.Protected) {
32173221
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics.Accessibility_modifier_already_seen);
32183222
}
32193223
else if (flags & NodeFlags.Static) {
@@ -3226,7 +3230,7 @@ module ts {
32263230
break;
32273231

32283232
case SyntaxKind.PrivateKeyword:
3229-
if (flags & NodeFlags.Private || flags & NodeFlags.Public) {
3233+
if (flags & NodeFlags.Public || flags & NodeFlags.Private || flags & NodeFlags.Protected) {
32303234
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics.Accessibility_modifier_already_seen);
32313235
}
32323236
else if (flags & NodeFlags.Static) {
@@ -3240,6 +3244,21 @@ module ts {
32403244
flags |= NodeFlags.Private;
32413245
break;
32423246

3247+
case SyntaxKind.ProtectedKeyword:
3248+
if (flags & NodeFlags.Public || flags & NodeFlags.Private || flags & NodeFlags.Protected) {
3249+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics.Accessibility_modifier_already_seen);
3250+
}
3251+
else if (flags & NodeFlags.Static) {
3252+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_must_precede_1_modifier, "protected", "static");
3253+
}
3254+
else if (context === ModifierContext.ModuleElements || context === ModifierContext.SourceElements) {
3255+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_cannot_appear_on_a_module_element, "protected");
3256+
}
3257+
lastProtectedModifierStart = modifierStart;
3258+
lastProtectedModifierLength = modifierLength;
3259+
flags |= NodeFlags.Protected;
3260+
break;
3261+
32433262
case SyntaxKind.StaticKeyword:
32443263
if (flags & NodeFlags.Static) {
32453264
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_already_seen, "static");
@@ -3297,6 +3316,9 @@ module ts {
32973316
else if (token === SyntaxKind.ConstructorKeyword && flags & NodeFlags.Private) {
32983317
grammarErrorAtPos(lastPrivateModifierStart, lastPrivateModifierLength, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private");
32993318
}
3319+
else if (token === SyntaxKind.ConstructorKeyword && flags & NodeFlags.Protected) {
3320+
grammarErrorAtPos(lastProtectedModifierStart, lastProtectedModifierLength, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected");
3321+
}
33003322
else if (token === SyntaxKind.ImportKeyword) {
33013323
if (flags & NodeFlags.Ambient) {
33023324
grammarErrorAtPos(lastDeclareModifierStart, lastDeclareModifierLength, Diagnostics.A_declare_modifier_cannot_be_used_with_an_import_declaration, "declare");
@@ -3573,6 +3595,7 @@ module ts {
35733595
case SyntaxKind.DeclareKeyword:
35743596
case SyntaxKind.PublicKeyword:
35753597
case SyntaxKind.PrivateKeyword:
3598+
case SyntaxKind.ProtectedKeyword:
35763599
case SyntaxKind.StaticKeyword:
35773600
// Check for modifier on source element
35783601
return lookAhead(() => { nextToken(); return isDeclaration(); });

src/compiler/types.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,13 @@ module ts {
232232
Rest = 0x00000008, // Parameter
233233
Public = 0x00000010, // Property/Method
234234
Private = 0x00000020, // Property/Method
235-
Static = 0x00000040, // Property/Method
236-
MultiLine = 0x00000080, // Multi-line array or object literal
237-
Synthetic = 0x00000100, // Synthetic node (for full fidelity)
238-
DeclarationFile = 0x00000200, // Node is a .d.ts file
235+
Protected = 0x00000040, // Property/Method
236+
Static = 0x00000080, // Property/Method
237+
MultiLine = 0x00000100, // Multi-line array or object literal
238+
Synthetic = 0x00000200, // Synthetic node (for full fidelity)
239+
DeclarationFile = 0x00000400, // Node is a .d.ts file
239240

240-
Modifier = Export | Ambient | Public | Private | Static
241+
Modifier = Export | Ambient | Public | Private | Protected | Static
241242
}
242243

243244
export interface Node extends TextRange {

0 commit comments

Comments
 (0)