Skip to content

Commit 3143818

Browse files
committed
Improves modifier checks and diagnostic messages.
* Rename check{Implicit -> Augmented}PropertyMemberOverrides. * Disable augment checks in ambients contexts. * Allow override on static methods. * Add override keyword to spec.md. * Use chained diagnostics when possible. * Remove hardcoded diagnotic-related strings in checker.ts. * Split tests into separate files overrideKeyword{es5 + es6}.ts.
1 parent fb705a6 commit 3143818

18 files changed

+2520
-2122
lines changed

doc/spec.md

+1,540-1,540
Large diffs are not rendered by default.

src/compiler/checker.ts

+70-31
Original file line numberDiff line numberDiff line change
@@ -18334,7 +18334,7 @@ namespace ts {
1833418334
for (const prop of getPropertiesOfObjectType(type)) {
1833518335
properties[prop.name] = prop;
1833618336
}
18337-
checkImplicitPropertyMemberOverrides(type, properties);
18337+
checkAugmentedPropertyMemberOverrides(type, properties);
1833818338
}
1833918339

1834018340
const implementedTypeNodes = getClassImplementsHeritageClauseElements(node);
@@ -18388,40 +18388,53 @@ namespace ts {
1838818388
return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined);
1838918389
}
1839018390

18391-
function checkImplicitPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map<Symbol>): void {
18391+
function checkAugmentedPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map<Symbol>): void {
1839218392
// If the class does not explicitly declare 'extends Object',
1839318393
// declarations that mask 'Object' members ('toString()', 'hasOwnProperty()', etc...)
1839418394
// are considered here.
18395+
18396+
// check is disabled in ambient contexts
18397+
if (isInAmbientContext(type.symbol.valueDeclaration)) {
18398+
return;
18399+
}
18400+
1839518401
const objectType = getSymbol(globals, "Object", SymbolFlags.Type);
1839618402
if (!objectType) {
1839718403
return;
1839818404
}
18405+
1839918406
for (const name in propertiesToCheck) {
1840018407
const derived = getTargetSymbol(propertiesToCheck[name]);
1840118408
const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived);
1840218409
const found = objectType.members[name];
1840318410
if (found) {
1840418411
if (compilerOptions.noImplicitOverride) {
1840518412
const foundSymbol = getTargetSymbol(found);
18406-
let detail = "masks Object." + symbolToString(found);
18407-
// assert that the type of the derived
18408-
// property matches that of the base property.
18413+
let errorInfo = chainDiagnosticMessages(
18414+
undefined,
18415+
Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1,
18416+
symbolToString(derived),
18417+
symbolToString(found)
18418+
);
1840918419
if (!isPropertyIdenticalTo(derived, foundSymbol)) {
18410-
detail += "). The override declaration ("
18411-
+ typeToString(getTypeOfSymbol(derived))
18412-
+ ") also has a different type signature than the original ("
18413-
+ typeToString(getTypeOfSymbol(foundSymbol));
18420+
errorInfo = chainDiagnosticMessages(
18421+
errorInfo,
18422+
Diagnostics.Type_0_is_not_assignable_to_type_1,
18423+
typeToString(getTypeOfSymbol(derived)),
18424+
typeToString(getTypeOfSymbol(foundSymbol))
18425+
);
1841418426
}
18415-
error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1,
18416-
symbolToString(derived), detail);
18427+
diagnostics.add(createDiagnosticForNodeFromMessageChain(derived.valueDeclaration.name, errorInfo));
1841718428
}
1841818429
}
1841918430
// No matching property found on the object type. It
1842018431
// is an error for the derived property to falsely
1842118432
// claim 'override'.
1842218433
else if (derivedDeclarationFlags & ModifierFlags.Override) {
18423-
error(derived.valueDeclaration.name, Diagnostics.Class_member_0_was_marked_override_but_no_matching_definition_was_found_in_any_supertype_of_1,
18424-
symbolToString(derived), typeToString(type));
18434+
error(derived.valueDeclaration.name,
18435+
Diagnostics.Class_member_0_was_marked_override_but_no_matching_declaration_was_found_in_any_supertype_of_1,
18436+
symbolToString(derived),
18437+
typeToString(type));
1842518438
}
1842618439
}
1842718440
}
@@ -18450,6 +18463,8 @@ namespace ts {
1845018463
onlyInDerived[prop.name] = prop;
1845118464
}
1845218465

18466+
const ambient = isInAmbientContext(type.symbol.valueDeclaration);
18467+
1845318468
const baseProperties = getPropertiesOfObjectType(baseType);
1845418469
for (const baseProperty of baseProperties) {
1845518470
const base = getTargetSymbol(baseProperty);
@@ -18507,10 +18522,13 @@ namespace ts {
1850718522
// Before accepting the correct case, ensure 'override' is marked if --noImplicitOverride is true.
1850818523
// Abstract members are an exception as override checks are suspended until the implementation solidifies.
1850918524
if (compilerOptions.noImplicitOverride
18525+
&& !ambient
1851018526
&& !(derivedDeclarationFlags & ModifierFlags.Abstract)
1851118527
&& !(derivedDeclarationFlags & ModifierFlags.Override)) {
18512-
error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1,
18513-
symbolToString(derived), "inherited from " + typeToString(baseType));
18528+
error(derived.valueDeclaration.name,
18529+
Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1,
18530+
symbolToString(derived),
18531+
typeToString(baseType));
1851418532
}
1851518533

1851618534
continue;
@@ -18541,7 +18559,7 @@ namespace ts {
1854118559
}
1854218560
}
1854318561

18544-
checkImplicitPropertyMemberOverrides(type, onlyInDerived);
18562+
checkAugmentedPropertyMemberOverrides(type, onlyInDerived);
1854518563
}
1854618564

1854718565
function isAccessor(kind: SyntaxKind): boolean {
@@ -21030,9 +21048,6 @@ namespace ts {
2103021048
else if (flags & ModifierFlags.Async) {
2103121049
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async");
2103221050
}
21033-
else if (flags & ModifierFlags.Override) {
21034-
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override");
21035-
}
2103621051
else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
2103721052
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text);
2103821053
}
@@ -21044,6 +21059,14 @@ namespace ts {
2104421059
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract");
2104521060
}
2104621061
}
21062+
else if (flags & ModifierFlags.Override) {
21063+
if (modifier.kind === SyntaxKind.PrivateKeyword) {
21064+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "override");
21065+
}
21066+
else {
21067+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override");
21068+
}
21069+
}
2104721070
flags |= modifierToFlag(modifier.kind);
2104821071
break;
2104921072

@@ -21066,9 +21089,6 @@ namespace ts {
2106621089
else if (flags & ModifierFlags.Abstract) {
2106721090
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract");
2106821091
}
21069-
else if (flags & ModifierFlags.Override) {
21070-
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override");
21071-
}
2107221092
flags |= ModifierFlags.Static;
2107321093
lastStatic = modifier;
2107421094
break;
@@ -21131,20 +21151,23 @@ namespace ts {
2113121151
if (flags & ModifierFlags.Abstract) {
2113221152
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract");
2113321153
}
21134-
if (node.kind !== SyntaxKind.ClassDeclaration) {
21154+
else if (node.kind !== SyntaxKind.ClassDeclaration) {
2113521155
if (node.kind !== SyntaxKind.MethodDeclaration &&
2113621156
node.kind !== SyntaxKind.PropertyDeclaration &&
2113721157
node.kind !== SyntaxKind.GetAccessor &&
2113821158
node.kind !== SyntaxKind.SetAccessor) {
21139-
return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration);
21159+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "abstract");
2114021160
}
21141-
if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) {
21161+
else if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) {
2114221162
return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class);
2114321163
}
21144-
if (flags & ModifierFlags.Static) {
21164+
else if (flags & ModifierFlags.Override) {
21165+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "abstract");
21166+
}
21167+
else if (flags & ModifierFlags.Static) {
2114521168
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract");
2114621169
}
21147-
if (flags & ModifierFlags.Private) {
21170+
else if (flags & ModifierFlags.Private) {
2114821171
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract");
2114921172
}
2115021173
}
@@ -21157,17 +21180,33 @@ namespace ts {
2115721180
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override");
2115821181
}
2115921182
else if (flags & ModifierFlags.Static) {
21160-
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override");
21183+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "static");
2116121184
}
21162-
else if (flags & ModifierFlags.Private) {
21163-
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override");
21185+
else if (flags & ModifierFlags.Async) {
21186+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async");
21187+
}
21188+
else if (flags & ModifierFlags.Readonly) {
21189+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly");
2116421190
}
2116521191
else if (flags & ModifierFlags.Abstract) {
2116621192
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override");
2116721193
}
21194+
else if (flags & ModifierFlags.Private) {
21195+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override");
21196+
}
21197+
else if (node.kind === SyntaxKind.Parameter) {
21198+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "override");
21199+
}
2116821200
else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
2116921201
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override");
2117021202
}
21203+
else if (node.kind !== SyntaxKind.MethodDeclaration &&
21204+
node.kind !== SyntaxKind.PropertyDeclaration &&
21205+
node.kind !== SyntaxKind.GetAccessor &&
21206+
node.kind !== SyntaxKind.SetAccessor) {
21207+
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "override");
21208+
}
21209+
2117121210
flags |= ModifierFlags.Override;
2117221211
break;
2117321212

@@ -21191,7 +21230,7 @@ namespace ts {
2119121230
if (flags & ModifierFlags.Static) {
2119221231
return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static");
2119321232
}
21194-
if (flags & ModifierFlags.Abstract) {
21233+
else if (flags & ModifierFlags.Abstract) {
2119521234
return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract");
2119621235
}
2119721236
else if (flags & ModifierFlags.Async) {

src/compiler/declarationEmitter.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,6 @@ namespace ts {
717717
}
718718

719719
function emitClassMemberDeclarationFlags(flags: ModifierFlags) {
720-
if (flags & ModifierFlags.Override) {
721-
write("override ");
722-
}
723720
if (flags & ModifierFlags.Private) {
724721
write("private ");
725722
}
@@ -730,6 +727,9 @@ namespace ts {
730727
if (flags & ModifierFlags.Static) {
731728
write("static ");
732729
}
730+
if (flags & ModifierFlags.Override) {
731+
write("override ");
732+
}
733733
if (flags & ModifierFlags.Readonly) {
734734
write("readonly ");
735735
}

src/compiler/diagnosticMessages.json

+9-5
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@
767767
"category": "Error",
768768
"code": 1241
769769
},
770-
"'abstract' modifier can only appear on a class, method, or property declaration.": {
770+
"'{0}' modifier can only appear on a class, method, or property declaration.": {
771771
"category": "Error",
772772
"code": 1242
773773
},
@@ -3291,21 +3291,25 @@
32913291
"category": "Error",
32923292
"code": 90030
32933293
},
3294-
"Class member '{0}' was marked 'override', but no matching definition was found in any supertype of '{1}'": {
3294+
"Class member '{0}' was marked 'override', but no matching declaration was found in any supertype of '{1}'": {
32953295
"category": "Error",
32963296
"code": 90032
32973297
},
3298-
"Class member '{0}' must be marked 'override' when noImplicitOverride is enabled ({1})": {
3298+
"Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (inherited from {1})": {
32993299
"category": "Error",
33003300
"code": 90033
33013301
},
3302+
"Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.{1})": {
3303+
"category": "Error",
3304+
"code": 90034
3305+
},
33023306
"override modifier cannot be used with an optional property declaration": {
33033307
"category": "Error",
3304-
"code": 90034
3308+
"code": 90035
33053309
},
33063310
"All declarations of an override method must be consecutive.": {
33073311
"category": "Error",
3308-
"code": 90035
3312+
"code": 90036
33093313
},
33103314
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
33113315
"category": "Error",

0 commit comments

Comments
 (0)