Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add override keyword #13217

Closed
wants to merge 10 commits into from
3,080 changes: 1,540 additions & 1,540 deletions doc/spec.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3104,6 +3104,7 @@ namespace ts {
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.ReadonlyKeyword:
// These nodes are TypeScript syntax.
transformFlags |= TransformFlags.AssertTypeScript;
Expand Down
197 changes: 178 additions & 19 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ namespace ts {
type: "boolean",
description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type,
},
{
name: "noImplicitOverride",
type: "boolean",
description: Diagnostics.Raise_an_error_when_inherited_Slashoverridden_class_members_are_not_explicitly_marked_override,
},
{
name: "noImplicitThis",
type: "boolean",
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,9 @@ namespace ts {
if (flags & ModifierFlags.Static) {
write("static ");
}
if (flags & ModifierFlags.Override) {
write("override ");
}
if (flags & ModifierFlags.Readonly) {
write("readonly ");
}
Expand Down
34 changes: 33 additions & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@
"category": "Error",
"code": 1241
},
"'abstract' modifier can only appear on a class, method, or property declaration.": {
"'{0}' modifier can only appear on a class, method, or property declaration.": {
"category": "Error",
"code": 1242
},
Expand Down Expand Up @@ -1683,6 +1683,10 @@
"category": "Error",
"code": 2518
},
"Overload signatures must all be override or non-override.": {
"category": "Error",
"code": 2519
},
"Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": {
"category": "Error",
"code": 2520
Expand Down Expand Up @@ -2015,6 +2019,10 @@
"category": "Error",
"code": 2698
},
"Accessors must both be override or non-override.": {
"category": "Error",
"code": 2699
},
"Rest types may only be created from object types.": {
"category": "Error",
"code": 2700
Expand Down Expand Up @@ -3279,6 +3287,30 @@
"category": "Message",
"code": 90015
},
"Raise an error when inherited/overridden class members are not explicitly marked 'override'": {
"category": "Error",
"code": 90030
},
"Class member '{0}' was marked 'override', but no matching declaration was found in any supertype of '{1}'": {
"category": "Error",
"code": 90032
},
"Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (inherited from {1})": {
"category": "Error",
"code": 90033
},
"Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.{1})": {
"category": "Error",
"code": 90034
},
"override modifier cannot be used with an optional property declaration": {
"category": "Error",
"code": 90035
},
"All declarations of an override method must be consecutive.": {
"category": "Error",
"code": 90036
},
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
"category": "Error",
"code": 8017
Expand Down
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ namespace ts {
case SyntaxKind.ModuleKeyword:
case SyntaxKind.NamespaceKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.RequireKeyword:
case SyntaxKind.NumberKeyword:
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4692,6 +4692,7 @@ namespace ts {
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.PublicKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.ReadonlyKeyword:
nextToken();
// ASI takes effect for this modifier.
Expand Down Expand Up @@ -4776,6 +4777,7 @@ namespace ts {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.ReadonlyKeyword:
// When these don't start a declaration, they may be the start of a class member if an identifier
Expand Down Expand Up @@ -4857,6 +4859,7 @@ namespace ts {
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.PublicKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.AbstractKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.ReadonlyKeyword:
Expand Down Expand Up @@ -5154,6 +5157,7 @@ namespace ts {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.ReadonlyKeyword:
return true;
Expand Down
1 change: 1 addition & 0 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@ namespace ts {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.AbstractKeyword:
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ namespace ts {
"null": SyntaxKind.NullKeyword,
"number": SyntaxKind.NumberKeyword,
"object": SyntaxKind.ObjectKeyword,
"override": SyntaxKind.OverrideKeyword,
"package": SyntaxKind.PackageKeyword,
"private": SyntaxKind.PrivateKeyword,
"protected": SyntaxKind.ProtectedKeyword,
Expand Down
1 change: 1 addition & 0 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ namespace ts {
case SyntaxKind.ConstKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.OverrideKeyword:
// TypeScript accessibility and readonly modifiers are elided.

case SyntaxKind.ArrayType:
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ namespace ts {
UndefinedKeyword,
FromKeyword,
GlobalKeyword,
OverrideKeyword,
OfKeyword, // LastKeyword and LastToken

// Parse tree nodes
Expand Down Expand Up @@ -453,6 +454,7 @@ namespace ts {
Abstract = 1 << 7, // Class/Method/ConstructSignature
Async = 1 << 8, // Property/Method/Function
Default = 1 << 9, // Function/Class (export default declaration)
Override = 1 << 10, // Property/Method
Const = 1 << 11, // Variable declaration
HasComputedFlags = 1 << 29, // Modifier flags have been computed

Expand All @@ -461,7 +463,7 @@ namespace ts {
ParameterPropertyModifier = AccessibilityModifier | Readonly,
NonPublicAccessibilityModifier = Private | Protected,

TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const,
TypeScriptModifier = Ambient | Public | Private | Protected | Override | Readonly | Abstract | Const,
ExportDefault = Export | Default,
}

Expand Down Expand Up @@ -532,6 +534,7 @@ namespace ts {
| Token<SyntaxKind.PublicKeyword>
| Token<SyntaxKind.PrivateKeyword>
| Token<SyntaxKind.ProtectedKeyword>
| Token<SyntaxKind.OverrideKeyword>
| Token<SyntaxKind.ReadonlyKeyword>
| Token<SyntaxKind.StaticKeyword>
;
Expand Down Expand Up @@ -3192,6 +3195,7 @@ namespace ts {
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
noImplicitOverride?: boolean;
noImplicitReturns?: boolean;
noImplicitThis?: boolean;
noUnusedLocals?: boolean;
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1964,6 +1964,7 @@ namespace ts {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.StaticKeyword:
return true;
Expand Down Expand Up @@ -3123,6 +3124,7 @@ namespace ts {
case SyntaxKind.DefaultKeyword: return ModifierFlags.Default;
case SyntaxKind.AsyncKeyword: return ModifierFlags.Async;
case SyntaxKind.ReadonlyKeyword: return ModifierFlags.Readonly;
case SyntaxKind.OverrideKeyword: return ModifierFlags.Override;
}
return ModifierFlags.None;
}
Expand Down
4 changes: 4 additions & 0 deletions src/harness/unittests/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ var x = 0;`, {
options: { compilerOptions: { noImplicitAny: true }, fileName: "input.js", reportDiagnostics: true }
});

transpilesCorrectly("Supports setting 'noImplicitOverride'", "x;", {
options: { compilerOptions: { noImplicitOverride: true }, fileName: "input.js", reportDiagnostics: true }
});

transpilesCorrectly("Supports setting 'noImplicitReturns'", "x;", {
options: { compilerOptions: { noImplicitReturns: true }, fileName: "input.js", reportDiagnostics: true }
});
Expand Down
7 changes: 4 additions & 3 deletions src/server/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ namespace ts.server.protocol {
startOffset: number;

/**
* Position (can be specified instead of line/offset pair)
* Position (can be specified instead of line/offset pair)
*/
/* @internal */
startPosition?: number;
Expand All @@ -433,7 +433,7 @@ namespace ts.server.protocol {
endOffset: number;

/**
* Position (can be specified instead of line/offset pair)
* Position (can be specified instead of line/offset pair)
*/
/* @internal */
endPosition?: number;
Expand All @@ -445,7 +445,7 @@ namespace ts.server.protocol {
}

/**
* Response for GetCodeFixes request.
* Response for GetCodeFixes request.
*/
export interface GetCodeFixesResponse extends Response {
body?: CodeAction[];
Expand Down Expand Up @@ -2237,6 +2237,7 @@ namespace ts.server.protocol {
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
noImplicitOverride?: boolean;
noImplicitReturns?: boolean;
noImplicitThis?: boolean;
noUnusedLocals?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/services/jsDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace ts.JsDoc {
"private",
"property",
"public",
"override",
"requires",
"returns",
"see",
Expand Down
86 changes: 86 additions & 0 deletions tests/baselines/reference/noImplicitOverride.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
tests/cases/compiler/noImplicitOverride.ts(11,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something's wrong with the way this is being rendered. We shouldn't have Object. in front of all of these. (Except e.g. Object.toString which is actually a property of Object.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

tests/cases/compiler/noImplicitOverride.ts(12,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object)
tests/cases/compiler/noImplicitOverride.ts(18,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString)
tests/cases/compiler/noImplicitOverride.ts(19,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty)
tests/cases/compiler/noImplicitOverride.ts(25,5): error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'.
Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty)
tests/cases/compiler/noImplicitOverride.ts(31,12): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)
tests/cases/compiler/noImplicitOverride.ts(35,9): error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)
tests/cases/compiler/noImplicitOverride.ts(43,5): error TS1070: 'override' modifier cannot appear on a type member.
tests/cases/compiler/noImplicitOverride.ts(52,29): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)


==== tests/cases/compiler/noImplicitOverride.ts (9 errors) ====

class Base {
get name(): string {
return 'Base';
}
getMeaningOfLife(): number { return 42; }
public userId: number = 1;
}

class RejectWhenOverrideMissingOnInheritedMethod extends Object {
toString(): string { return 'foo'; };
~~~~~~~~
!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object)
hasOwnProperty(prop: string): boolean {
~~~~~~~~~~~~~~
!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object)
return super.hasOwnProperty(prop);
}
}

class RejectWhenOverrideMissingOnAugmentedProperty {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include a positive version of this test. class A { override toString() { return ""; } } should succeed with no errors.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

toString(): string { return 'foo'; };
~~~~~~~~
!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString)
hasOwnProperty(prop: string): boolean {
~~~~~~~~~~~~~~
!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty)
return false;
}
}

class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember {
hasOwnProperty(prop: string): number {
~~~~~~~~~~~~~~
!!! error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'.
!!! error TS2322: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty)
return -1;
}
}

class RejectWhenOverrideMissingOnInheritedProperty extends Base {
public userId = 2;
~~~~~~
!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)
}

class RejectWhenOverrideMissingOnInheritedAccessor extends Base {
get name(): string { return 'foo'; };
~~~~
!!! error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)
}

interface Shape {
getWidth(): number;
}

interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape {
override getWidth(): number;
~~~~~~~~
!!! error TS1070: 'override' modifier cannot appear on a type member.
}

interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape {
// abstract members don't need to be declared override
getWidth(): number;
}

class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base {
/** @override */ public userId: number = 2;
~~~~~~
!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base)
}

Loading