Skip to content

Commit f4bd6e4

Browse files
elkaltzygoloid
andauthored
Replace impl fn with override fn (#6008)
This proposal renames the syntax used to mark an overriding definition of a virtual method from `impl fn` to `override fn` to avoid ambiguity: besides indicating an overriding virtual function, it can be parsed as an "impl" declaration when the construct following "impl" begins with a lambda introduced by "fn". Closes #5711 --------- Co-authored-by: Richard Smith <[email protected]>
1 parent 973d721 commit f4bd6e4

File tree

17 files changed

+234
-162
lines changed

17 files changed

+234
-162
lines changed

docs/design/classes.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,21 +1237,20 @@ There are three virtual modifier keywords:
12371237
virtual" but is called
12381238
["pure virtual" in C++](https://en.wikipedia.org/wiki/Virtual_function#Abstract_classes_and_pure_virtual_functions).
12391239
Only abstract classes may have unimplemented abstract methods.
1240-
- `impl` - This marks a method that overrides a method marked `virtual` or
1240+
- `override` - This marks a method that overrides a method marked `virtual` or
12411241
`abstract` in the base class with an implementation specific to -- and
12421242
defined within -- this class. The method is still virtual and may be
12431243
overridden again in subsequent derived classes if this is a base class. See
12441244
[method overriding in Wikipedia](https://en.wikipedia.org/wiki/Method_overriding).
12451245
Requiring a keyword when overriding allows the compiler to diagnose when the
12461246
derived class accidentally uses the wrong signature or spelling and so
1247-
doesn't match the base class. We intentionally use the same keyword here as
1248-
for implementing interfaces, to emphasize that they are similar operations.
1247+
doesn't match the base class.
12491248

1250-
| Keyword on<br />method in `C` | Allowed in<br />`abstract class C` | Allowed in<br />`base class C` | Allowed in<br />final `class C` | in `B` where<br />`C` extends `B` | in `D` where<br />`D` extends `C` |
1251-
| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
1252-
| `virtual` |||| _not present_ | `abstract`<br />`impl`<br />_not mentioned_ |
1253-
| `abstract` |||| _not present_<br />`virtual`<br />`abstract`<br />`impl` | `abstract`<br />`impl`<br />_may not be<br />mentioned if<br />`D` is not final_ |
1254-
| `impl` |||| `virtual`<br />`abstract`<br />`impl` | `abstract`<br />`impl` |
1249+
| Keyword on<br />method in `C` | Allowed in<br />`abstract class C` | Allowed in<br />`base class C` | Allowed in<br />final `class C` | in `B` where<br />`C` extends `B` | in `D` where<br />`D` extends `C` |
1250+
| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
1251+
| `virtual` |||| _not present_ | `abstract`<br />`override`<br />_not mentioned_ |
1252+
| `abstract` |||| _not present_<br />`virtual`<br />`abstract`<br />`override` | `abstract`<br />`override`<br />_may not be<br />mentioned if<br />`D` is not final_ |
1253+
| `override` |||| `virtual`<br />`abstract`<br />`override` | `abstract`<br />`override` |
12551254

12561255
Since validating a method with a virtual modifier keyword involves looking for
12571256
methods with the same name in the base class, virtual methods must be declared
@@ -1315,15 +1314,15 @@ base class B1 {
13151314
class D1 {
13161315
extend base: B1;
13171316
// ❌ Illegal:
1318-
// impl fn F[self: Self](x: Self) -> Self;
1317+
// override fn F[self: Self](x: Self) -> Self;
13191318
// since that would mean the same thing as:
1320-
// impl fn F[self: Self](x: D1) -> D1;
1319+
// override fn F[self: Self](x: D1) -> D1;
13211320
// and `D1` is a different type than `B1`.
13221321
13231322
// ✅ Allowed: Parameter and return types
13241323
// of `F` match declaration in `B1`.
1325-
impl fn F[self: Self](x: B1) -> B1;
1326-
// Or: impl fn F[self: D1](x: B1) -> B1;
1324+
override fn F[self: Self](x: B1) -> B1;
1325+
// Or: override fn F[self: D1](x: B1) -> B1;
13271326
}
13281327
```
13291328

@@ -1341,9 +1340,9 @@ base class B2 {
13411340
class D2 {
13421341
extend base: B2;
13431342
// ✅ Allowed
1344-
impl fn Clone[self: Self]() -> Self*;
1343+
override fn Clone[self: Self]() -> Self*;
13451344
// Means the same thing as:
1346-
// impl fn Clone[self: D2]() -> D2*;
1345+
// override fn Clone[self: D2]() -> D2*;
13471346
// which is allowed since `D2*` is a
13481347
// subtype of `B2*`.
13491348
}
@@ -1615,7 +1614,7 @@ of its base classes unless it has a
16151614
[virtual destructor](https://en.wikipedia.org/wiki/Virtual_function#Virtual_destructors).
16161615
An abstract or base class' destructor may be declared virtual using the
16171616
`virtual` introducer, in which case any derived class destructor declaration
1618-
must be `impl`:
1617+
must be `override`:
16191618

16201619
```carbon
16211620
base class MyBaseClass {
@@ -1624,7 +1623,7 @@ base class MyBaseClass {
16241623
16251624
class MyDerivedClass {
16261625
extend base: MyBaseClass;
1627-
impl fn destroy[addr self: Self*]() { ... }
1626+
override fn destroy[addr self: Self*]() { ... }
16281627
}
16291628
```
16301629

@@ -2298,6 +2297,8 @@ the type of `U.x`."
22982297
- [Destructor syntax options](/proposals/p5017.md#destructor-syntax-options)
22992298
- [Destructor name options](/proposals/p5017.md#destructor-name-options)
23002299
2300+
- [#6008: Replace `impl fn` with `override fn`](https://github.com/carbon-language/carbon-lang/pull/6008)
2301+
23012302
## References
23022303
23032304
- [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)

proposals/p6008.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Replace `impl fn` with `override fn`
2+
3+
<!--
4+
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
5+
Exceptions. See /LICENSE for license information.
6+
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
-->
8+
9+
[Pull request](https://github.com/carbon-language/carbon-lang/pull/6008)
10+
11+
<!-- toc -->
12+
13+
## Table of contents
14+
15+
- [Abstract](#abstract)
16+
- [Problem](#problem)
17+
- [Background](#background)
18+
- [Proposal](#proposal)
19+
- [Rationale](#rationale)
20+
21+
<!-- tocstop -->
22+
23+
## Abstract
24+
25+
This proposal renames the syntax used to mark an overriding definition of a
26+
virtual method from `impl fn` to `override fn` to avoid ambiguity.
27+
28+
## Problem
29+
30+
The phrase `impl fn` was introduced to mark overriding virtual functions,
31+
however, it is now ambiguous: besides indicating an overriding virtual function,
32+
it can be parsed as an "impl" declaration when the construct following "impl"
33+
begins with a lambda introduced by "fn".
34+
35+
## Background
36+
37+
The original syntax was adopted in
38+
[proposal #777](https://github.com/carbon-language/carbon-lang/pull/777) to
39+
emphasize that implementing interfaces and overriding virtual functions are
40+
similar operations.
41+
42+
## Proposal
43+
44+
This proposal is to replace the `impl fn` syntax with `override fn` for method
45+
overriding in class inheritance.
46+
47+
Note that `impl` is still a modifier keyword for library and package
48+
declarations (`impl library ...` and `impl package ...` respectively). The
49+
former is unambiguous and the latter is easy to disambiguate, so no change is
50+
needed for these two cases.
51+
52+
## Rationale
53+
54+
This proposal is focused on the
55+
[That code is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
56+
Carbon goal. Changing the keyword from `impl` to `override` makes the intent
57+
clearer, resolves syntax ambiguity, and adheres to existing C++ conventions.

toolchain/check/class.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
199199
.GetAs<SemIR::FunctionDecl>(override_fn_decl_id)
200200
.function_id);
201201
return override_fn.virtual_modifier ==
202-
SemIR::FunctionFields::VirtualModifier::Impl &&
202+
SemIR::FunctionFields::VirtualModifier::Override &&
203203
override_fn.name_id == fn.name_id;
204204
});
205205
if (i != vtable_contents.end()) {
@@ -237,13 +237,15 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
237237
for (auto inst_id : vtable_contents) {
238238
auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
239239
auto& fn = context.functions().Get(fn_decl.function_id);
240-
if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
240+
if (fn.virtual_modifier !=
241+
SemIR::FunctionFields::VirtualModifier::Override) {
241242
fn.virtual_index = vtable.size();
242243
vtable.push_back(build_specific_function(inst_id));
243244
} else if (!implemented_impls.Lookup(fn_decl.function_id)) {
244-
CARBON_DIAGNOSTIC(ImplWithoutVirtualInBase, Error,
245-
"impl without compatible virtual in base class");
246-
context.emitter().Emit(SemIR::LocId(inst_id), ImplWithoutVirtualInBase);
245+
CARBON_DIAGNOSTIC(OverrideWithoutVirtualInBase, Error,
246+
"override without compatible virtual in base class");
247+
context.emitter().Emit(SemIR::LocId(inst_id),
248+
OverrideWithoutVirtualInBase);
247249
}
248250
}
249251

toolchain/check/handle_function.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ static auto GetVirtualModifier(const KeywordModifierSet& modifier_set)
128128
SemIR::Function::VirtualModifier::Virtual)
129129
.Case(KeywordModifierSet::Abstract,
130130
SemIR::Function::VirtualModifier::Abstract)
131-
.Case(KeywordModifierSet::Impl, SemIR::Function::VirtualModifier::Impl)
131+
.Case(KeywordModifierSet::Override,
132+
SemIR::Function::VirtualModifier::Override)
132133
.Default(SemIR::Function::VirtualModifier::None);
133134
}
134135

@@ -342,10 +343,11 @@ static auto RequestVtableIfVirtual(
342343
}
343344

344345
auto& class_info = context.classes().Get(class_decl->class_id);
345-
if (virtual_modifier == SemIR::Function::VirtualModifier::Impl &&
346+
if (virtual_modifier == SemIR::Function::VirtualModifier::Override &&
346347
!class_info.base_id.has_value()) {
347-
CARBON_DIAGNOSTIC(ImplWithoutBase, Error, "impl without base class");
348-
context.emitter().Emit(node_id, ImplWithoutBase);
348+
CARBON_DIAGNOSTIC(OverrideWithoutBase, Error,
349+
"override without base class");
350+
context.emitter().Emit(node_id, OverrideWithoutBase);
349351
virtual_modifier = SemIR::Function::VirtualModifier::None;
350352
return;
351353
}

toolchain/check/keyword_modifier_set.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Last = Decl };
3838
X(Export) \
3939
X(Final) \
4040
X(Impl) \
41+
X(Override) \
4142
X(Returned) \
4243
X(Virtual)
4344

@@ -113,11 +114,11 @@ CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE)
113114

114115
constexpr KeywordModifierSet KeywordModifierSet::Access(Private | Protected);
115116
constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base);
116-
constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Impl |
117+
constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Override |
117118
Virtual);
118119
constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend | Final);
119120
constexpr KeywordModifierSet KeywordModifierSet::Interface(Default | Final);
120-
constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method |
121+
constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method | Impl |
121122
Interface | Export |
122123
Returned);
123124

0 commit comments

Comments
 (0)