Skip to content

Commit 9cbb728

Browse files
authored
feat: add override keyword (#2366)
1 parent 1d05e8d commit 9cbb728

File tree

10 files changed

+78
-18
lines changed

10 files changed

+78
-18
lines changed

src/common.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,52 @@ export enum CommonFlags {
3636
GET = 1 << 11,
3737
/** Has a `set` modifier. */
3838
SET = 1 << 12,
39+
/** Has a `override` modifier. */
40+
OVERRIDE = 1 << 13,
41+
3942
/** Has a definite assignment assertion `!` as in `x!: i32;`. */
40-
DEFINITELY_ASSIGNED = 1 << 13,
43+
DEFINITELY_ASSIGNED = 1 << 14,
4144

4245
// Extended modifiers usually derived from basic modifiers
4346

4447
/** Is ambient, that is either declared or nested in a declared element. */
45-
AMBIENT = 1 << 14,
48+
AMBIENT = 1 << 15,
4649
/** Is generic. */
47-
GENERIC = 1 << 15,
50+
GENERIC = 1 << 16,
4851
/** Is part of a generic context. */
49-
GENERIC_CONTEXT = 1 << 16,
52+
GENERIC_CONTEXT = 1 << 17,
5053
/** Is an instance member. */
51-
INSTANCE = 1 << 17,
54+
INSTANCE = 1 << 18,
5255
/** Is a constructor. */
53-
CONSTRUCTOR = 1 << 18,
56+
CONSTRUCTOR = 1 << 19,
5457
/** Is a module export. */
55-
MODULE_EXPORT = 1 << 19,
58+
MODULE_EXPORT = 1 << 20,
5659
/** Is a module import. */
57-
MODULE_IMPORT = 1 << 20,
60+
MODULE_IMPORT = 1 << 21,
5861

5962
// Compilation states
6063

6164
/** Is resolved. */
62-
RESOLVED = 1 << 21,
65+
RESOLVED = 1 << 22,
6366
/** Is compiled. */
64-
COMPILED = 1 << 22,
67+
COMPILED = 1 << 23,
6568
/** Did error. */
66-
ERRORED = 1 << 23,
69+
ERRORED = 1 << 24,
6770
/** Has a constant value and is therefore inlined. */
68-
INLINED = 1 << 24,
71+
INLINED = 1 << 25,
6972
/** Is scoped. */
70-
SCOPED = 1 << 25,
73+
SCOPED = 1 << 26,
7174
/** Is a stub. */
72-
STUB = 1 << 26,
75+
STUB = 1 << 27,
7376
/** Is a virtual method. */
74-
VIRTUAL = 1 << 27,
77+
VIRTUAL = 1 << 28,
7578
/** Is (part of) a closure. */
76-
CLOSURE = 1 << 28,
79+
CLOSURE = 1 << 29,
7780

7881
// Other
7982

8083
/** Is quoted. */
81-
QUOTED = 1 << 29
84+
QUOTED = 1 << 30
8285
}
8386

8487
/** Path delimiter inserted between file system levels. */

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
"Duplicate property '{0}'.": 2718,
186186
"Property '{0}' is missing in type '{1}' but required in type '{2}'.": 2741,
187187
"Type '{0}' has no call signatures.": 2757,
188+
"This member cannot have an 'override' modifier because it is not declared in the base class '{0}'.": 4117,
188189

189190
"File '{0}' not found.": 6054,
190191
"Numeric separators are not allowed here.": 6188,

src/parser.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,7 @@ export class Parser extends DiagnosticEmitter {
18621862
// 'declare'?
18631863
// ('public' | 'private' | 'protected')?
18641864
// ('static' | 'abstract')?
1865+
// 'override'?
18651866
// 'readonly'?
18661867
// ('get' | 'set')?
18671868
// Identifier ...
@@ -1991,6 +1992,22 @@ export class Parser extends DiagnosticEmitter {
19911992
if (parent.flags & CommonFlags.GENERIC) flags |= CommonFlags.GENERIC_CONTEXT;
19921993
}
19931994

1995+
var overrideStart = 0;
1996+
var overrideEnd = 0;
1997+
if (tn.skip(Token.OVERRIDE)) {
1998+
if (isInterface || parent.extendsType == null) {
1999+
this.error(
2000+
DiagnosticCode._0_modifier_cannot_be_used_here,
2001+
tn.range(), "override"
2002+
);
2003+
} else {
2004+
flags |= CommonFlags.OVERRIDE;
2005+
overrideStart = tn.tokenPos;
2006+
overrideEnd = tn.pos;
2007+
}
2008+
if (!startPos) startPos = tn.tokenPos;
2009+
}
2010+
19942011
var readonlyStart = 0;
19952012
var readonlyEnd = 0;
19962013
if (tn.peek() == Token.READONLY) {
@@ -2104,6 +2121,12 @@ export class Parser extends DiagnosticEmitter {
21042121
tn.range(staticStart, staticEnd), "static"
21052122
); // recoverable
21062123
}
2124+
if (flags & CommonFlags.OVERRIDE) {
2125+
this.error(
2126+
DiagnosticCode._0_modifier_cannot_be_used_here,
2127+
tn.range(overrideStart, overrideEnd), "override"
2128+
);
2129+
}
21072130
if (flags & CommonFlags.ABSTRACT) {
21082131
this.error(
21092132
DiagnosticCode._0_modifier_cannot_be_used_here,

src/program.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,12 @@ export class Program extends DiagnosticEmitter {
15241524
}
15251525
}
15261526
}
1527+
if (thisMember.is(CommonFlags.OVERRIDE) && !baseInstanceMembers.has(thisMember.name)) {
1528+
this.error(
1529+
DiagnosticCode.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0,
1530+
thisMember.identifierNode.range, basePrototype.name
1531+
);
1532+
}
15271533
}
15281534
}
15291535
let nextPrototype = basePrototype.basePrototype;

src/tokenizer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export enum Token {
8080
NEW, // ES2017
8181
NULL, // ES
8282
OF,
83+
OVERRIDE,
8384
PACKAGE, // ES2017 non-lexical
8485
PRIVATE, // ES2017 non-lexical
8586
PROTECTED, // ES2017 non-lexical
@@ -291,6 +292,7 @@ export function tokenFromKeyword(text: string): Token {
291292
}
292293
case CharCode.o: {
293294
if (text == "of") return Token.OF;
295+
if (text == "override") return Token.OVERRIDE;
294296
break;
295297
}
296298
case CharCode.p: {

tests/compiler/class-overloading-cast.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class A<T> {
44
}
55
}
66
class B<T, V> extends A<T> {
7-
foo(a: T): string {
7+
override foo(a: T): string {
88
return "B";
99
}
1010
}

tests/compiler/override-error.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"asc_flags": [],
3+
"stderr": [
4+
"TS4117: This member cannot have an 'override' modifier because it is not declared in the base class 'A'."
5+
]
6+
}

tests/compiler/override-error.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class A {
2+
method(): void {}
3+
}
4+
5+
class B extends A {
6+
override method(): void {}
7+
// TS4117: This member cannot have an 'override' modifier because it is not declared in the base class 'A'.
8+
override method_error(): void {}
9+
}
10+
11+
export function test(): void {
12+
new A();
13+
new B();
14+
}

tests/parser/class.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ export class Invalid<T> {
3737
// 1031: 'declare' modifier cannot appear on class elements of this kind.
3838
// 1183: An implementation cannot be declared in ambient contexts.
3939
declare declareMethod(): i32 {}
40+
41+
// ERROR 1042: "'override' modifier cannot be used here."
42+
override overrideMethod(): void {}
4043
}

tests/parser/class.ts.fixture.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class Invalid<T> {
1717
declare declareField: i32;
1818
declare declareInitializer: i32 = 0;
1919
declare declareMethod(): i32 {}
20+
overrideMethod(): void {}
2021
}
2122
// ERROR 1092: "Type parameters cannot appear on a constructor declaration." in class.ts(15,14+3)
2223
// ERROR 1110: "Type expected." in class.ts(18,21+0)
@@ -31,3 +32,4 @@ export class Invalid<T> {
3132
// ERROR 1039: "Initializers are not allowed in ambient contexts." in class.ts(35,35+1)
3233
// ERROR 1031: "'declare' modifier cannot appear on class elements of this kind." in class.ts(39,3+7)
3334
// ERROR 1183: "An implementation cannot be declared in ambient contexts." in class.ts(39,32+1)
35+
// ERROR 1042: "'override' modifier cannot be used here." in class.ts(42,3+8)

0 commit comments

Comments
 (0)