diff --git a/docs/design/classes.md b/docs/design/classes.md
index da0a61e1f49a..736fb961eb39 100644
--- a/docs/design/classes.md
+++ b/docs/design/classes.md
@@ -1237,21 +1237,20 @@ There are three virtual modifier keywords:
virtual" but is called
["pure virtual" in C++](https://en.wikipedia.org/wiki/Virtual_function#Abstract_classes_and_pure_virtual_functions).
Only abstract classes may have unimplemented abstract methods.
-- `impl` - This marks a method that overrides a method marked `virtual` or
+- `override` - This marks a method that overrides a method marked `virtual` or
`abstract` in the base class with an implementation specific to -- and
defined within -- this class. The method is still virtual and may be
overridden again in subsequent derived classes if this is a base class. See
[method overriding in Wikipedia](https://en.wikipedia.org/wiki/Method_overriding).
Requiring a keyword when overriding allows the compiler to diagnose when the
derived class accidentally uses the wrong signature or spelling and so
- doesn't match the base class. We intentionally use the same keyword here as
- for implementing interfaces, to emphasize that they are similar operations.
+ doesn't match the base class.
-| Keyword on
method in `C` | Allowed in
`abstract class C` | Allowed in
`base class C` | Allowed in
final `class C` | in `B` where
`C` extends `B` | in `D` where
`D` extends `C` |
-| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
-| `virtual` | ✅ | ✅ | ❌ | _not present_ | `abstract`
`impl`
_not mentioned_ |
-| `abstract` | ✅ | ❌ | ❌ | _not present_
`virtual`
`abstract`
`impl` | `abstract`
`impl`
_may not be
mentioned if
`D` is not final_ |
-| `impl` | ✅ | ✅ | ✅ | `virtual`
`abstract`
`impl` | `abstract`
`impl` |
+| Keyword on
method in `C` | Allowed in
`abstract class C` | Allowed in
`base class C` | Allowed in
final `class C` | in `B` where
`C` extends `B` | in `D` where
`D` extends `C` |
+| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
+| `virtual` | ✅ | ✅ | ❌ | _not present_ | `abstract`
`override`
_not mentioned_ |
+| `abstract` | ✅ | ❌ | ❌ | _not present_
`virtual`
`abstract`
`override` | `abstract`
`override`
_may not be
mentioned if
`D` is not final_ |
+| `override` | ✅ | ✅ | ✅ | `virtual`
`abstract`
`override` | `abstract`
`override` |
Since validating a method with a virtual modifier keyword involves looking for
methods with the same name in the base class, virtual methods must be declared
@@ -1315,15 +1314,15 @@ base class B1 {
class D1 {
extend base: B1;
// ❌ Illegal:
- // impl fn F[self: Self](x: Self) -> Self;
+ // override fn F[self: Self](x: Self) -> Self;
// since that would mean the same thing as:
- // impl fn F[self: Self](x: D1) -> D1;
+ // override fn F[self: Self](x: D1) -> D1;
// and `D1` is a different type than `B1`.
// ✅ Allowed: Parameter and return types
// of `F` match declaration in `B1`.
- impl fn F[self: Self](x: B1) -> B1;
- // Or: impl fn F[self: D1](x: B1) -> B1;
+ override fn F[self: Self](x: B1) -> B1;
+ // Or: override fn F[self: D1](x: B1) -> B1;
}
```
@@ -1341,9 +1340,9 @@ base class B2 {
class D2 {
extend base: B2;
// ✅ Allowed
- impl fn Clone[self: Self]() -> Self*;
+ override fn Clone[self: Self]() -> Self*;
// Means the same thing as:
- // impl fn Clone[self: D2]() -> D2*;
+ // override fn Clone[self: D2]() -> D2*;
// which is allowed since `D2*` is a
// subtype of `B2*`.
}
@@ -1615,7 +1614,7 @@ of its base classes unless it has a
[virtual destructor](https://en.wikipedia.org/wiki/Virtual_function#Virtual_destructors).
An abstract or base class' destructor may be declared virtual using the
`virtual` introducer, in which case any derived class destructor declaration
-must be `impl`:
+must be `override`:
```carbon
base class MyBaseClass {
@@ -1624,7 +1623,7 @@ base class MyBaseClass {
class MyDerivedClass {
extend base: MyBaseClass;
- impl fn destroy[addr self: Self*]() { ... }
+ override fn destroy[addr self: Self*]() { ... }
}
```
@@ -2298,6 +2297,8 @@ the type of `U.x`."
- [Destructor syntax options](/proposals/p5017.md#destructor-syntax-options)
- [Destructor name options](/proposals/p5017.md#destructor-name-options)
+- [#6008: Replace `impl fn` with `override fn`](https://github.com/carbon-language/carbon-lang/pull/6008)
+
## References
- [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)
diff --git a/proposals/p6008.md b/proposals/p6008.md
new file mode 100644
index 000000000000..575801e1a204
--- /dev/null
+++ b/proposals/p6008.md
@@ -0,0 +1,57 @@
+# Replace `impl fn` with `override fn`
+
+
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/6008)
+
+
+
+## Table of contents
+
+- [Abstract](#abstract)
+- [Problem](#problem)
+- [Background](#background)
+- [Proposal](#proposal)
+- [Rationale](#rationale)
+
+
+
+## Abstract
+
+This proposal renames the syntax used to mark an overriding definition of a
+virtual method from `impl fn` to `override fn` to avoid ambiguity.
+
+## Problem
+
+The phrase `impl fn` was introduced to mark overriding virtual functions,
+however, it is now ambiguous: 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".
+
+## Background
+
+The original syntax was adopted in
+[proposal #777](https://github.com/carbon-language/carbon-lang/pull/777) to
+emphasize that implementing interfaces and overriding virtual functions are
+similar operations.
+
+## Proposal
+
+This proposal is to replace the `impl fn` syntax with `override fn` for method
+overriding in class inheritance.
+
+Note that `impl` is still a modifier keyword for library and package
+declarations (`impl library ...` and `impl package ...` respectively). The
+former is unambiguous and the latter is easy to disambiguate, so no change is
+needed for these two cases.
+
+## Rationale
+
+This proposal is focused on the
+[That code is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
+Carbon goal. Changing the keyword from `impl` to `override` makes the intent
+clearer, resolves syntax ambiguity, and adheres to existing C++ conventions.
diff --git a/toolchain/check/class.cpp b/toolchain/check/class.cpp
index 7a03c925e51a..3d07f6c461e2 100644
--- a/toolchain/check/class.cpp
+++ b/toolchain/check/class.cpp
@@ -199,7 +199,7 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
.GetAs(override_fn_decl_id)
.function_id);
return override_fn.virtual_modifier ==
- SemIR::FunctionFields::VirtualModifier::Impl &&
+ SemIR::FunctionFields::VirtualModifier::Override &&
override_fn.name_id == fn.name_id;
});
if (i != vtable_contents.end()) {
@@ -237,13 +237,15 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
for (auto inst_id : vtable_contents) {
auto fn_decl = context.insts().GetAs(inst_id);
auto& fn = context.functions().Get(fn_decl.function_id);
- if (fn.virtual_modifier != SemIR::FunctionFields::VirtualModifier::Impl) {
+ if (fn.virtual_modifier !=
+ SemIR::FunctionFields::VirtualModifier::Override) {
fn.virtual_index = vtable.size();
vtable.push_back(build_specific_function(inst_id));
} else if (!implemented_impls.Lookup(fn_decl.function_id)) {
- CARBON_DIAGNOSTIC(ImplWithoutVirtualInBase, Error,
- "impl without compatible virtual in base class");
- context.emitter().Emit(SemIR::LocId(inst_id), ImplWithoutVirtualInBase);
+ CARBON_DIAGNOSTIC(OverrideWithoutVirtualInBase, Error,
+ "override without compatible virtual in base class");
+ context.emitter().Emit(SemIR::LocId(inst_id),
+ OverrideWithoutVirtualInBase);
}
}
diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp
index a2b4bd912961..57f847545634 100644
--- a/toolchain/check/handle_function.cpp
+++ b/toolchain/check/handle_function.cpp
@@ -128,7 +128,8 @@ static auto GetVirtualModifier(const KeywordModifierSet& modifier_set)
SemIR::Function::VirtualModifier::Virtual)
.Case(KeywordModifierSet::Abstract,
SemIR::Function::VirtualModifier::Abstract)
- .Case(KeywordModifierSet::Impl, SemIR::Function::VirtualModifier::Impl)
+ .Case(KeywordModifierSet::Override,
+ SemIR::Function::VirtualModifier::Override)
.Default(SemIR::Function::VirtualModifier::None);
}
@@ -342,10 +343,11 @@ static auto RequestVtableIfVirtual(
}
auto& class_info = context.classes().Get(class_decl->class_id);
- if (virtual_modifier == SemIR::Function::VirtualModifier::Impl &&
+ if (virtual_modifier == SemIR::Function::VirtualModifier::Override &&
!class_info.base_id.has_value()) {
- CARBON_DIAGNOSTIC(ImplWithoutBase, Error, "impl without base class");
- context.emitter().Emit(node_id, ImplWithoutBase);
+ CARBON_DIAGNOSTIC(OverrideWithoutBase, Error,
+ "override without base class");
+ context.emitter().Emit(node_id, OverrideWithoutBase);
virtual_modifier = SemIR::Function::VirtualModifier::None;
return;
}
diff --git a/toolchain/check/keyword_modifier_set.h b/toolchain/check/keyword_modifier_set.h
index bfabe5625f79..a8c4f39196ae 100644
--- a/toolchain/check/keyword_modifier_set.h
+++ b/toolchain/check/keyword_modifier_set.h
@@ -38,6 +38,7 @@ enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Last = Decl };
X(Export) \
X(Final) \
X(Impl) \
+ X(Override) \
X(Returned) \
X(Virtual)
@@ -113,11 +114,11 @@ CARBON_KEYWORD_MODIFIER_SET(CARBON_KEYWORD_MODIFIER_SET_WITH_TYPE)
constexpr KeywordModifierSet KeywordModifierSet::Access(Private | Protected);
constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base);
-constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Impl |
+constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Override |
Virtual);
constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend | Final);
constexpr KeywordModifierSet KeywordModifierSet::Interface(Default | Final);
-constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method |
+constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method | Impl |
Interface | Export |
Returned);
diff --git a/toolchain/check/testdata/class/virtual_modifiers.carbon b/toolchain/check/testdata/class/virtual_modifiers.carbon
index 54cc4b098547..287778cd291b 100644
--- a/toolchain/check/testdata/class/virtual_modifiers.carbon
+++ b/toolchain/check/testdata/class/virtual_modifiers.carbon
@@ -34,7 +34,7 @@ import Modifiers;
class Derived {
extend base: Modifiers.Base;
- impl fn H[self: Self]();
+ override fn H[self: Self]();
}
fn Use() {
@@ -72,7 +72,7 @@ abstract class A1 {
abstract class A2 {
extend base: A1;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
// --- impl_base.carbon
@@ -85,12 +85,12 @@ base class B1 {
base class B2 {
extend base: B1;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
class C {
extend base: B2;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
fn Use() {
@@ -104,11 +104,11 @@ fn Use() {
library "[[@TEST_NAME]]";
class C {
- // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:3: error: impl without base class [ImplWithoutBase]
- // CHECK:STDERR: impl fn F[self: Self]();
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
+ // CHECK:STDERR: fail_modifiers.carbon:[[@LINE+4]]:3: error: override without base class [OverrideWithoutBase]
+ // CHECK:STDERR: override fn F[self: Self]();
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
// --- init_members.carbon
@@ -139,11 +139,11 @@ base class Base {
class Derived {
extend base: Base;
- // CHECK:STDERR: fail_impl_without_base_declaration.carbon:[[@LINE+4]]:3: error: impl without compatible virtual in base class [ImplWithoutVirtualInBase]
- // CHECK:STDERR: impl fn F[self: Self]();
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
+ // CHECK:STDERR: fail_impl_without_base_declaration.carbon:[[@LINE+4]]:3: error: override without compatible virtual in base class [OverrideWithoutVirtualInBase]
+ // CHECK:STDERR: override fn F[self: Self]();
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
// --- abstract_impl.carbon
@@ -160,7 +160,7 @@ abstract class AbstractIntermediate {
class Derived {
extend base: AbstractIntermediate;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
// --- virtual_impl.carbon
@@ -177,7 +177,7 @@ base class VirtualIntermediate {
class Derived {
extend base: VirtualIntermediate;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
// --- fail_impl_mismatch.carbon
@@ -191,13 +191,13 @@ base class Base {
class Derived {
extend base: Base;
// CHECK:STDERR: fail_impl_mismatch.carbon:[[@LINE+7]]:3: error: redeclaration differs because of parameter count of 1 [RedeclParamCountDiffers]
- // CHECK:STDERR: impl fn F[self: Self](v: i32);
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // CHECK:STDERR: override fn F[self: Self](v: i32);
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_impl_mismatch.carbon:[[@LINE-8]]:3: note: previously declared with parameter count of 0 [RedeclParamCountPrevious]
// CHECK:STDERR: virtual fn F[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn F[self: Self](v: i32);
+ override fn F[self: Self](v: i32);
}
// --- fail_todo_impl_conversion.carbon
@@ -223,13 +223,13 @@ base class Base {
class Derived {
extend base: Base;
// CHECK:STDERR: fail_todo_impl_conversion.carbon:[[@LINE+7]]:3: error: function redeclaration differs because return type is `T2` [FunctionRedeclReturnTypeDiffers]
- // CHECK:STDERR: impl fn F[self: Self]() -> T2;
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // CHECK:STDERR: override fn F[self: Self]() -> T2;
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_impl_conversion.carbon:[[@LINE-8]]:3: note: previously declared with return type `T1` [FunctionRedeclReturnTypePrevious]
// CHECK:STDERR: virtual fn F[self: Self]() -> T1;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn F[self: Self]() -> T2;
+ override fn F[self: Self]() -> T2;
}
// --- fail_generic_virtual_decl.carbon
@@ -261,7 +261,7 @@ base class Base(T:! type) {
class Derived {
extend base: Base(T1);
- impl fn F[self: Self](t: T1) { }
+ override fn F[self: Self](t: T1) { }
}
// --- fail_virtual_without_self.carbon
@@ -284,10 +284,10 @@ abstract class T1 {
class T2 {
extend base: T1;
// CHECK:STDERR: fail_virtual_without_self.carbon:[[@LINE+4]]:3: error: virtual class function [VirtualWithoutSelf]
- // CHECK:STDERR: impl fn F();
- // CHECK:STDERR: ^~~~~~~~~~~~
+ // CHECK:STDERR: override fn F();
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn F();
+ override fn F();
}
// --- fail_addr_self_mismatch.carbon
@@ -300,14 +300,14 @@ base class T1 {
class T2 {
extend base: T1;
- // CHECK:STDERR: fail_addr_self_mismatch.carbon:[[@LINE+7]]:14: error: redeclaration differs at implicit parameter 1 [RedeclParamDiffers]
- // CHECK:STDERR: impl fn F1[addr self: Self*]();
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~
+ // CHECK:STDERR: fail_addr_self_mismatch.carbon:[[@LINE+7]]:18: error: redeclaration differs at implicit parameter 1 [RedeclParamDiffers]
+ // CHECK:STDERR: override fn F1[addr self: Self*]();
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_addr_self_mismatch.carbon:[[@LINE-8]]:17: note: previous declaration's corresponding implicit parameter here [RedeclParamPrevious]
// CHECK:STDERR: virtual fn F1[self: Self*]();
// CHECK:STDERR: ^~~~~~~~~~~
// CHECK:STDERR:
- impl fn F1[addr self: Self*]();
+ override fn F1[addr self: Self*]();
}
// --- fail_generic_virtual.carbon
@@ -369,7 +369,7 @@ base class NonGenericBase {
base class GenericDerived(T:! type) {
extend base: NonGenericBase;
- impl fn F2[self: Self]() { }
+ override fn F2[self: Self]() { }
virtual fn F3[self: Self]() { }
}
@@ -386,7 +386,7 @@ class T1;
base class NonGenericDerived {
extend base: GenericBase(T1);
- impl fn F2[self: Self]() { }
+ override fn F2[self: Self]() { }
virtual fn F3[self: Self]() { }
}
@@ -400,7 +400,7 @@ base class Base(T:! type) {
class T1;
class D1 {
extend base: Base(T1);
- impl fn F[self: Self](t: Base(T1)*) { }
+ override fn F[self: Self](t: Base(T1)*) { }
}
// --- fail_impl_generic_specifically_mismatch.carbon
@@ -416,14 +416,14 @@ base class Base(T:! type) {
class D1 {
extend base: Base(T1);
- // CHECK:STDERR: fail_impl_generic_specifically_mismatch.carbon:[[@LINE+7]]:25: error: type `` of parameter 1 in redeclaration differs from previous parameter type `` [RedeclParamDiffersType]
- // CHECK:STDERR: impl fn F[self: Self](t: T2*) { }
- // CHECK:STDERR: ^~~~~~
+ // CHECK:STDERR: fail_impl_generic_specifically_mismatch.carbon:[[@LINE+7]]:29: error: type `` of parameter 1 in redeclaration differs from previous parameter type `` [RedeclParamDiffersType]
+ // CHECK:STDERR: override fn F[self: Self](t: T2*) { }
+ // CHECK:STDERR: ^~~~~~
// CHECK:STDERR: fail_impl_generic_specifically_mismatch.carbon:[[@LINE-8]]:28: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
// CHECK:STDERR: virtual fn F[self: Self](t: T1*) { }
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR:
- impl fn F[self: Self](t: T2*) { }
+ override fn F[self: Self](t: T2*) { }
}
// --- fail_impl_generic_generic_mismatch.carbon
@@ -435,14 +435,14 @@ abstract class Base(T:! type) {
}
class Derived(T:! type) {
extend base: Base(T);
- // CHECK:STDERR: fail_impl_generic_generic_mismatch.carbon:[[@LINE+7]]:25: error: type `` of parameter 1 in redeclaration differs from previous parameter type `` [RedeclParamDiffersType]
- // CHECK:STDERR: impl fn F[self: Self](t: T) { }
- // CHECK:STDERR: ^~~~
+ // CHECK:STDERR: fail_impl_generic_generic_mismatch.carbon:[[@LINE+7]]:29: error: type `` of parameter 1 in redeclaration differs from previous parameter type `` [RedeclParamDiffersType]
+ // CHECK:STDERR: override fn F[self: Self](t: T) { }
+ // CHECK:STDERR: ^~~~
// CHECK:STDERR: fail_impl_generic_generic_mismatch.carbon:[[@LINE-7]]:28: note: previous declaration's corresponding parameter here [RedeclParamPrevious]
// CHECK:STDERR: virtual fn F[self: Self](t: T*) { }
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
- impl fn F[self: Self](t: T) { }
+ override fn F[self: Self](t: T) { }
}
// --- impl_generic_generic.carbon
@@ -454,7 +454,7 @@ abstract class Base(T:! type) {
}
class Derived(T:! type) {
extend base: Base(T*);
- impl fn F[self: Self](t: T*) { }
+ override fn F[self: Self](t: T*) { }
}
// --- abstract_generic_undefined.carbon
@@ -469,7 +469,7 @@ class T1;
class Derived {
extend base: Base(T1);
- impl fn F[self: Self]() { }
+ override fn F[self: Self]() { }
}
// --- generic_lib.carbon
@@ -802,7 +802,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: @Derived.%Derived.H.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.H(%self.param: %Derived);
+// CHECK:STDOUT: override fn @Derived.H(%self.param: %Derived);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -1236,7 +1236,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @A1.as.Destroy.impl.Op(%self.param: %ptr.678) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @A2.F(%self.param: %A2);
+// CHECK:STDOUT: override fn @A2.F(%self.param: %A2);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @A2.as.Destroy.impl.Op(%self.param: %ptr.590) = "no_op";
// CHECK:STDOUT:
@@ -1468,11 +1468,11 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @B1.as.Destroy.impl.Op(%self.param: %ptr.890) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @B2.F(%self.param: %B2);
+// CHECK:STDOUT: override fn @B2.F(%self.param: %B2);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @B2.as.Destroy.impl.Op(%self.param: %ptr.afe) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @C.F(%self.param: %C);
+// CHECK:STDOUT: override fn @C.F(%self.param: %C);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
// CHECK:STDOUT:
@@ -1617,7 +1617,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: .F = %C.F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @C.F(%self.param: %C);
+// CHECK:STDOUT: override fn @C.F(%self.param: %C);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
// CHECK:STDOUT:
@@ -2013,7 +2013,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived);
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -2218,7 +2218,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AbstractIntermediate.as.Destroy.impl.Op(%self.param: %ptr.fd8) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived);
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -2423,7 +2423,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @VirtualIntermediate.as.Destroy.impl.Op(%self.param: %ptr.7dc) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived);
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -2590,7 +2590,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived, %v.param: %i32);
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived, %v.param: %i32);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -2882,7 +2882,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived) -> %return.param: %T2;
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived) -> %return.param: %T2;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
// CHECK:STDOUT:
@@ -3320,7 +3320,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived, %t.param: %T1) {
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived, %t.param: %T1) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -3622,10 +3622,10 @@ class T2(G2:! type) {
// CHECK:STDOUT: %T2.F1.decl: %T2.F1.type = fn_decl @T2.F1 [concrete = constants.%T2.F1] {
// CHECK:STDOUT: %self.patt: %pattern_type.fb8 = binding_pattern self [concrete]
// CHECK:STDOUT: %self.param_patt: %pattern_type.fb8 = value_param_pattern %self.patt, call_param0 [concrete]
-// CHECK:STDOUT: %.loc17_14: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
+// CHECK:STDOUT: %.loc17_18: %pattern_type.f6d = addr_pattern %self.param_patt [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %ptr.63e = value_param call_param0
-// CHECK:STDOUT: %.loc17_29: type = splice_block %ptr [concrete = constants.%ptr.63e] {
+// CHECK:STDOUT: %.loc17_33: type = splice_block %ptr [concrete = constants.%ptr.63e] {
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%T2 [concrete = constants.%T2]
// CHECK:STDOUT: %ptr: type = ptr_type %Self.ref [concrete = constants.%ptr.63e]
// CHECK:STDOUT: }
@@ -3660,7 +3660,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @T1.as.Destroy.impl.Op(%self.param: %ptr.87b) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @T2.F1(%self.param: %ptr.63e);
+// CHECK:STDOUT: override fn @T2.F1(%self.param: %ptr.63e);
// CHECK:STDOUT:
// CHECK:STDOUT: fn @T2.as.Destroy.impl.Op(%self.param: %ptr.63e) = "no_op";
// CHECK:STDOUT:
@@ -4505,9 +4505,9 @@ class T2(G2:! type) {
// CHECK:STDOUT: %self.param_patt: @GenericDerived.F2.%pattern_type (%pattern_type.061) = value_param_pattern %self.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: @GenericDerived.F2.%GenericDerived (%GenericDerived) = value_param call_param0
-// CHECK:STDOUT: %.loc11_20.1: type = splice_block %Self.ref [symbolic = %GenericDerived (constants.%GenericDerived)] {
-// CHECK:STDOUT: %.loc11_20.2: type = specific_constant constants.%GenericDerived, @GenericDerived(constants.%T) [symbolic = %GenericDerived (constants.%GenericDerived)]
-// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc11_20.2 [symbolic = %GenericDerived (constants.%GenericDerived)]
+// CHECK:STDOUT: %.loc11_24.1: type = splice_block %Self.ref [symbolic = %GenericDerived (constants.%GenericDerived)] {
+// CHECK:STDOUT: %.loc11_24.2: type = specific_constant constants.%GenericDerived, @GenericDerived(constants.%T) [symbolic = %GenericDerived (constants.%GenericDerived)]
+// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc11_24.2 [symbolic = %GenericDerived (constants.%GenericDerived)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %self: @GenericDerived.F2.%GenericDerived (%GenericDerived) = bind_name self, %self.param
// CHECK:STDOUT: }
@@ -4566,7 +4566,7 @@ class T2(G2:! type) {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @NonGenericBase.as.Destroy.impl.Op(%self.param: %ptr.806) = "no_op";
// CHECK:STDOUT:
-// CHECK:STDOUT: generic impl fn @GenericDerived.F2(@GenericDerived.%T.loc9_27.2: type) {
+// CHECK:STDOUT: generic override fn @GenericDerived.F2(@GenericDerived.%T.loc9_27.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %GenericDerived: type = class_type @GenericDerived, @GenericDerived(%T) [symbolic = %GenericDerived (constants.%GenericDerived)]
// CHECK:STDOUT: %pattern_type: type = pattern_type %GenericDerived [symbolic = %pattern_type (constants.%pattern_type.061)]
@@ -4574,7 +4574,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: !definition:
// CHECK:STDOUT: %require_complete: = require_complete_type %GenericDerived [symbolic = %require_complete (constants.%require_complete)]
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn(%self.param: @GenericDerived.F2.%GenericDerived (%GenericDerived)) {
+// CHECK:STDOUT: override fn(%self.param: @GenericDerived.F2.%GenericDerived (%GenericDerived)) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -4921,7 +4921,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @GenericBase.as.Destroy.impl.Op.%ptr (%ptr.b68)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @NonGenericDerived.F2(%self.param: %NonGenericDerived) {
+// CHECK:STDOUT: override fn @NonGenericDerived.F2(%self.param: %NonGenericDerived) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -5257,7 +5257,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @D1.F(%self.param: %D1, %t.param: %ptr.184) {
+// CHECK:STDOUT: override fn @D1.F(%self.param: %D1, %t.param: %ptr.184) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -5568,7 +5568,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @D1.F(%self.param: %D1, %t.param: %ptr.63e) {
+// CHECK:STDOUT: override fn @D1.F(%self.param: %D1, %t.param: %ptr.63e) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -5827,15 +5827,15 @@ class T2(G2:! type) {
// CHECK:STDOUT: %Base.loc8_22.1: type = class_type @Base, @Base(constants.%T) [symbolic = %Base.loc8_22.2 (constants.%Base)]
// CHECK:STDOUT: %.loc8: @Derived.%Derived.elem (%Derived.elem) = base_decl %Base.loc8_22.1, element0 [concrete]
// CHECK:STDOUT: %Derived.F.decl: @Derived.%Derived.F.type (%Derived.F.type) = fn_decl @Derived.F [symbolic = @Derived.%Derived.F (constants.%Derived.F)] {
-// CHECK:STDOUT: %self.patt: @Derived.F.%pattern_type.loc16_13 (%pattern_type.423) = binding_pattern self [concrete]
-// CHECK:STDOUT: %self.param_patt: @Derived.F.%pattern_type.loc16_13 (%pattern_type.423) = value_param_pattern %self.patt, call_param0 [concrete]
-// CHECK:STDOUT: %t.patt: @Derived.F.%pattern_type.loc16_25 (%pattern_type.7dc) = binding_pattern t [concrete]
-// CHECK:STDOUT: %t.param_patt: @Derived.F.%pattern_type.loc16_25 (%pattern_type.7dc) = value_param_pattern %t.patt, call_param1 [concrete]
+// CHECK:STDOUT: %self.patt: @Derived.F.%pattern_type.loc16_17 (%pattern_type.423) = binding_pattern self [concrete]
+// CHECK:STDOUT: %self.param_patt: @Derived.F.%pattern_type.loc16_17 (%pattern_type.423) = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT: %t.patt: @Derived.F.%pattern_type.loc16_29 (%pattern_type.7dc) = binding_pattern t [concrete]
+// CHECK:STDOUT: %t.param_patt: @Derived.F.%pattern_type.loc16_29 (%pattern_type.7dc) = value_param_pattern %t.patt, call_param1 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: @Derived.F.%Derived (%Derived) = value_param call_param0
-// CHECK:STDOUT: %.loc16_19.1: type = splice_block %Self.ref [symbolic = %Derived (constants.%Derived)] {
-// CHECK:STDOUT: %.loc16_19.2: type = specific_constant constants.%Derived, @Derived(constants.%T) [symbolic = %Derived (constants.%Derived)]
-// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc16_19.2 [symbolic = %Derived (constants.%Derived)]
+// CHECK:STDOUT: %.loc16_23.1: type = splice_block %Self.ref [symbolic = %Derived (constants.%Derived)] {
+// CHECK:STDOUT: %.loc16_23.2: type = specific_constant constants.%Derived, @Derived(constants.%T) [symbolic = %Derived (constants.%Derived)]
+// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc16_23.2 [symbolic = %Derived (constants.%Derived)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %self: @Derived.F.%Derived (%Derived) = bind_name self, %self.param
// CHECK:STDOUT: %t.param: @Derived.F.%T (%T) = value_param call_param1
@@ -5898,19 +5898,19 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: generic impl fn @Derived.F(@Derived.%T.loc7_15.2: type) {
+// CHECK:STDOUT: generic override fn @Derived.F(@Derived.%T.loc7_15.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %Derived: type = class_type @Derived, @Derived(%T) [symbolic = %Derived (constants.%Derived)]
-// CHECK:STDOUT: %pattern_type.loc16_13: type = pattern_type %Derived [symbolic = %pattern_type.loc16_13 (constants.%pattern_type.423)]
+// CHECK:STDOUT: %pattern_type.loc16_17: type = pattern_type %Derived [symbolic = %pattern_type.loc16_17 (constants.%pattern_type.423)]
// CHECK:STDOUT: %Base: type = class_type @Base, @Base(%T) [symbolic = %Base (constants.%Base)]
-// CHECK:STDOUT: %require_complete.loc16_28: = require_complete_type %Base [symbolic = %require_complete.loc16_28 (constants.%require_complete.97d)]
-// CHECK:STDOUT: %pattern_type.loc16_25: type = pattern_type %T [symbolic = %pattern_type.loc16_25 (constants.%pattern_type.7dc)]
+// CHECK:STDOUT: %require_complete.loc16_32: = require_complete_type %Base [symbolic = %require_complete.loc16_32 (constants.%require_complete.97d)]
+// CHECK:STDOUT: %pattern_type.loc16_29: type = pattern_type %T [symbolic = %pattern_type.loc16_29 (constants.%pattern_type.7dc)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
-// CHECK:STDOUT: %require_complete.loc16_17: = require_complete_type %Derived [symbolic = %require_complete.loc16_17 (constants.%require_complete.5f4)]
-// CHECK:STDOUT: %require_complete.loc16_26: = require_complete_type %T [symbolic = %require_complete.loc16_26 (constants.%require_complete.4ae)]
+// CHECK:STDOUT: %require_complete.loc16_21: = require_complete_type %Derived [symbolic = %require_complete.loc16_21 (constants.%require_complete.5f4)]
+// CHECK:STDOUT: %require_complete.loc16_30: = require_complete_type %T [symbolic = %require_complete.loc16_30 (constants.%require_complete.4ae)]
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn(%self.param: @Derived.F.%Derived (%Derived), %t.param: @Derived.F.%T (%T)) {
+// CHECK:STDOUT: override fn(%self.param: @Derived.F.%Derived (%Derived), %t.param: @Derived.F.%T (%T)) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -5979,14 +5979,14 @@ class T2(G2:! type) {
// CHECK:STDOUT: specific @Derived.F(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %Derived => constants.%Derived
-// CHECK:STDOUT: %pattern_type.loc16_13 => constants.%pattern_type.423
+// CHECK:STDOUT: %pattern_type.loc16_17 => constants.%pattern_type.423
// CHECK:STDOUT: %Base => constants.%Base
-// CHECK:STDOUT: %require_complete.loc16_28 => constants.%require_complete.97d
-// CHECK:STDOUT: %pattern_type.loc16_25 => constants.%pattern_type.7dc
+// CHECK:STDOUT: %require_complete.loc16_32 => constants.%require_complete.97d
+// CHECK:STDOUT: %pattern_type.loc16_29 => constants.%pattern_type.7dc
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
-// CHECK:STDOUT: %require_complete.loc16_17 => constants.%require_complete.5f4
-// CHECK:STDOUT: %require_complete.loc16_26 => constants.%require_complete.4ae
+// CHECK:STDOUT: %require_complete.loc16_21 => constants.%require_complete.5f4
+// CHECK:STDOUT: %require_complete.loc16_30 => constants.%require_complete.4ae
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Derived.as.Destroy.impl(constants.%T) {
@@ -6210,23 +6210,23 @@ class T2(G2:! type) {
// CHECK:STDOUT: %Base.loc8_23.1: type = class_type @Base, @Base(constants.%ptr.79f) [symbolic = %Base.loc8_23.2 (constants.%Base.16b)]
// CHECK:STDOUT: %.loc8: @Derived.%Derived.elem (%Derived.elem) = base_decl %Base.loc8_23.1, element0 [concrete]
// CHECK:STDOUT: %Derived.F.decl: @Derived.%Derived.F.type (%Derived.F.type) = fn_decl @Derived.F [symbolic = @Derived.%Derived.F (constants.%Derived.F)] {
-// CHECK:STDOUT: %self.patt: @Derived.F.%pattern_type.loc9_13 (%pattern_type.423) = binding_pattern self [concrete]
-// CHECK:STDOUT: %self.param_patt: @Derived.F.%pattern_type.loc9_13 (%pattern_type.423) = value_param_pattern %self.patt, call_param0 [concrete]
-// CHECK:STDOUT: %t.patt: @Derived.F.%pattern_type.loc9_25 (%pattern_type.afe) = binding_pattern t [concrete]
-// CHECK:STDOUT: %t.param_patt: @Derived.F.%pattern_type.loc9_25 (%pattern_type.afe) = value_param_pattern %t.patt, call_param1 [concrete]
+// CHECK:STDOUT: %self.patt: @Derived.F.%pattern_type.loc9_17 (%pattern_type.423) = binding_pattern self [concrete]
+// CHECK:STDOUT: %self.param_patt: @Derived.F.%pattern_type.loc9_17 (%pattern_type.423) = value_param_pattern %self.patt, call_param0 [concrete]
+// CHECK:STDOUT: %t.patt: @Derived.F.%pattern_type.loc9_29 (%pattern_type.afe) = binding_pattern t [concrete]
+// CHECK:STDOUT: %t.param_patt: @Derived.F.%pattern_type.loc9_29 (%pattern_type.afe) = value_param_pattern %t.patt, call_param1 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: @Derived.F.%Derived (%Derived) = value_param call_param0
-// CHECK:STDOUT: %.loc9_19.1: type = splice_block %Self.ref [symbolic = %Derived (constants.%Derived)] {
-// CHECK:STDOUT: %.loc9_19.2: type = specific_constant constants.%Derived, @Derived(constants.%T) [symbolic = %Derived (constants.%Derived)]
-// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc9_19.2 [symbolic = %Derived (constants.%Derived)]
+// CHECK:STDOUT: %.loc9_23.1: type = splice_block %Self.ref [symbolic = %Derived (constants.%Derived)] {
+// CHECK:STDOUT: %.loc9_23.2: type = specific_constant constants.%Derived, @Derived(constants.%T) [symbolic = %Derived (constants.%Derived)]
+// CHECK:STDOUT: %Self.ref: type = name_ref Self, %.loc9_23.2 [symbolic = %Derived (constants.%Derived)]
// CHECK:STDOUT: }
// CHECK:STDOUT: %self: @Derived.F.%Derived (%Derived) = bind_name self, %self.param
-// CHECK:STDOUT: %t.param: @Derived.F.%ptr.loc9_28 (%ptr.79f) = value_param call_param1
-// CHECK:STDOUT: %.loc9_29: type = splice_block %ptr.loc9_29 [symbolic = %ptr.loc9_28 (constants.%ptr.79f)] {
+// CHECK:STDOUT: %t.param: @Derived.F.%ptr.loc9_32 (%ptr.79f) = value_param call_param1
+// CHECK:STDOUT: %.loc9_33: type = splice_block %ptr.loc9_33 [symbolic = %ptr.loc9_32 (constants.%ptr.79f)] {
// CHECK:STDOUT: %T.ref: type = name_ref T, @Derived.%T.loc7_15.2 [symbolic = %T (constants.%T)]
-// CHECK:STDOUT: %ptr.loc9_29: type = ptr_type %T.ref [symbolic = %ptr.loc9_28 (constants.%ptr.79f)]
+// CHECK:STDOUT: %ptr.loc9_33: type = ptr_type %T.ref [symbolic = %ptr.loc9_32 (constants.%ptr.79f)]
// CHECK:STDOUT: }
-// CHECK:STDOUT: %t: @Derived.F.%ptr.loc9_28 (%ptr.79f) = bind_name t, %t.param
+// CHECK:STDOUT: %t: @Derived.F.%ptr.loc9_32 (%ptr.79f) = bind_name t, %t.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Derived [symbolic = @Derived.as.Destroy.impl.%Derived (constants.%Derived)]
// CHECK:STDOUT: impl_decl @Derived.as.Destroy.impl [concrete] {} {}
@@ -6283,20 +6283,20 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: generic impl fn @Derived.F(@Derived.%T.loc7_15.2: type) {
+// CHECK:STDOUT: generic override fn @Derived.F(@Derived.%T.loc7_15.2: type) {
// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)]
// CHECK:STDOUT: %Derived: type = class_type @Derived, @Derived(%T) [symbolic = %Derived (constants.%Derived)]
-// CHECK:STDOUT: %pattern_type.loc9_13: type = pattern_type %Derived [symbolic = %pattern_type.loc9_13 (constants.%pattern_type.423)]
-// CHECK:STDOUT: %ptr.loc9_28: type = ptr_type %T [symbolic = %ptr.loc9_28 (constants.%ptr.79f)]
-// CHECK:STDOUT: %Base: type = class_type @Base, @Base(%ptr.loc9_28) [symbolic = %Base (constants.%Base.16b)]
-// CHECK:STDOUT: %require_complete.loc9_28: = require_complete_type %Base [symbolic = %require_complete.loc9_28 (constants.%require_complete.fce)]
-// CHECK:STDOUT: %pattern_type.loc9_25: type = pattern_type %ptr.loc9_28 [symbolic = %pattern_type.loc9_25 (constants.%pattern_type.afe)]
+// CHECK:STDOUT: %pattern_type.loc9_17: type = pattern_type %Derived [symbolic = %pattern_type.loc9_17 (constants.%pattern_type.423)]
+// CHECK:STDOUT: %ptr.loc9_32: type = ptr_type %T [symbolic = %ptr.loc9_32 (constants.%ptr.79f)]
+// CHECK:STDOUT: %Base: type = class_type @Base, @Base(%ptr.loc9_32) [symbolic = %Base (constants.%Base.16b)]
+// CHECK:STDOUT: %require_complete.loc9_32: = require_complete_type %Base [symbolic = %require_complete.loc9_32 (constants.%require_complete.fce)]
+// CHECK:STDOUT: %pattern_type.loc9_29: type = pattern_type %ptr.loc9_32 [symbolic = %pattern_type.loc9_29 (constants.%pattern_type.afe)]
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
-// CHECK:STDOUT: %require_complete.loc9_17: = require_complete_type %Derived [symbolic = %require_complete.loc9_17 (constants.%require_complete.5f4)]
-// CHECK:STDOUT: %require_complete.loc9_26: = require_complete_type %ptr.loc9_28 [symbolic = %require_complete.loc9_26 (constants.%require_complete.6e5)]
+// CHECK:STDOUT: %require_complete.loc9_21: = require_complete_type %Derived [symbolic = %require_complete.loc9_21 (constants.%require_complete.5f4)]
+// CHECK:STDOUT: %require_complete.loc9_30: = require_complete_type %ptr.loc9_32 [symbolic = %require_complete.loc9_30 (constants.%require_complete.6e5)]
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn(%self.param: @Derived.F.%Derived (%Derived), %t.param: @Derived.F.%ptr.loc9_28 (%ptr.79f)) {
+// CHECK:STDOUT: override fn(%self.param: @Derived.F.%Derived (%Derived), %t.param: @Derived.F.%ptr.loc9_32 (%ptr.79f)) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
@@ -6385,15 +6385,15 @@ class T2(G2:! type) {
// CHECK:STDOUT: specific @Derived.F(constants.%T) {
// CHECK:STDOUT: %T => constants.%T
// CHECK:STDOUT: %Derived => constants.%Derived
-// CHECK:STDOUT: %pattern_type.loc9_13 => constants.%pattern_type.423
-// CHECK:STDOUT: %ptr.loc9_28 => constants.%ptr.79f
+// CHECK:STDOUT: %pattern_type.loc9_17 => constants.%pattern_type.423
+// CHECK:STDOUT: %ptr.loc9_32 => constants.%ptr.79f
// CHECK:STDOUT: %Base => constants.%Base.16b
-// CHECK:STDOUT: %require_complete.loc9_28 => constants.%require_complete.fce
-// CHECK:STDOUT: %pattern_type.loc9_25 => constants.%pattern_type.afe
+// CHECK:STDOUT: %require_complete.loc9_32 => constants.%require_complete.fce
+// CHECK:STDOUT: %pattern_type.loc9_29 => constants.%pattern_type.afe
// CHECK:STDOUT:
// CHECK:STDOUT: !definition:
-// CHECK:STDOUT: %require_complete.loc9_17 => constants.%require_complete.5f4
-// CHECK:STDOUT: %require_complete.loc9_26 => constants.%require_complete.6e5
+// CHECK:STDOUT: %require_complete.loc9_21 => constants.%require_complete.5f4
+// CHECK:STDOUT: %require_complete.loc9_30 => constants.%require_complete.6e5
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: specific @Derived.as.Destroy.impl(constants.%T) {
@@ -6623,7 +6623,7 @@ class T2(G2:! type) {
// CHECK:STDOUT: fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
// CHECK:STDOUT: }
// CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @Derived.F(%self.param: %Derived) {
+// CHECK:STDOUT: override fn @Derived.F(%self.param: %Derived) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: return
// CHECK:STDOUT: }
diff --git a/toolchain/check/testdata/function/definition/fail_local_decl.carbon b/toolchain/check/testdata/function/definition/fail_local_decl.carbon
index dffce768ac0e..a10c1d79e46f 100644
--- a/toolchain/check/testdata/function/definition/fail_local_decl.carbon
+++ b/toolchain/check/testdata/function/definition/fail_local_decl.carbon
@@ -22,11 +22,11 @@ fn F() {
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
default fn F();
- // CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `impl` not allowed; requires class scope [ModifierRequiresClass]
- // CHECK:STDERR: impl fn G();
- // CHECK:STDERR: ^~~~
+ // CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `override` not allowed; requires class scope [ModifierRequiresClass]
+ // CHECK:STDERR: override fn G();
+ // CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
- impl fn G();
+ override fn G();
// CHECK:STDERR: fail_virtual.carbon:[[@LINE+4]]:3: error: `virtual` not allowed; requires class scope [ModifierRequiresClass]
// CHECK:STDERR: virtual fn H();
// CHECK:STDERR: ^~~~~~~
diff --git a/toolchain/check/testdata/interop/cpp/class/abstract.carbon b/toolchain/check/testdata/interop/cpp/class/abstract.carbon
index 688f5dd19cde..c676be1a3613 100644
--- a/toolchain/check/testdata/interop/cpp/class/abstract.carbon
+++ b/toolchain/check/testdata/interop/cpp/class/abstract.carbon
@@ -46,11 +46,11 @@ import Cpp library "abstract.h";
class C {
extend base: Cpp.A;
- // CHECK:STDERR: fail_todo_impl_abstract_member.carbon:[[@LINE+4]]:3: error: impl without compatible virtual in base class [ImplWithoutVirtualInBase]
- // CHECK:STDERR: impl fn f[addr self: Self*]() {}
- // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // CHECK:STDERR: fail_todo_impl_abstract_member.carbon:[[@LINE+4]]:3: error: override without compatible virtual in base class [OverrideWithoutVirtualInBase]
+ // CHECK:STDERR: override fn f[addr self: Self*]() {}
+ // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
- impl fn f[addr self: Self*]() {}
+ override fn f[addr self: Self*]() {}
}
// --- abstract_final.h
diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def
index 3e81a0f6c3b4..f2ad06b77227 100644
--- a/toolchain/diagnostics/diagnostic_kind.def
+++ b/toolchain/diagnostics/diagnostic_kind.def
@@ -289,8 +289,8 @@ CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass)
CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious)
CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)
CARBON_DIAGNOSTIC_KIND(GenericVirtual)
-CARBON_DIAGNOSTIC_KIND(ImplWithoutBase)
-CARBON_DIAGNOSTIC_KIND(ImplWithoutVirtualInBase)
+CARBON_DIAGNOSTIC_KIND(OverrideWithoutBase)
+CARBON_DIAGNOSTIC_KIND(OverrideWithoutVirtualInBase)
CARBON_DIAGNOSTIC_KIND(VirtualWithoutSelf)
// Deduction.
diff --git a/toolchain/lex/token_kind.def b/toolchain/lex/token_kind.def
index 8f99e5d1b3a7..5cd423e39900 100644
--- a/toolchain/lex/token_kind.def
+++ b/toolchain/lex/token_kind.def
@@ -199,6 +199,7 @@ CARBON_KEYWORD_TOKEN(Not, "not")
CARBON_KEYWORD_TOKEN(Observe, "observe")
CARBON_TOKEN_WITH_VIRTUAL_NODE(
CARBON_KEYWORD_TOKEN(Or, "or"))
+CARBON_KEYWORD_TOKEN(Override, "override")
CARBON_KEYWORD_TOKEN(Partial, "partial")
CARBON_KEYWORD_TOKEN(Private, "private")
CARBON_KEYWORD_TOKEN(Protected, "protected")
diff --git a/toolchain/lower/testdata/class/virtual.carbon b/toolchain/lower/testdata/class/virtual.carbon
index 41495b6d6dd2..c29d841f8f6c 100644
--- a/toolchain/lower/testdata/class/virtual.carbon
+++ b/toolchain/lower/testdata/class/virtual.carbon
@@ -24,7 +24,7 @@ base class Intermediate {
class Derived {
extend base: Intermediate;
- impl fn Fn[self: Self]() { }
+ override fn Fn[self: Self]() { }
}
// --- create.carbon
@@ -100,7 +100,7 @@ base class Base {
class Derived {
extend base: Base;
- impl fn F[self: Self]();
+ override fn F[self: Self]();
}
fn Use() {
diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def
index 55dfecbfeec4..de29180ac512 100644
--- a/toolchain/parse/node_kind.def
+++ b/toolchain/parse/node_kind.def
@@ -344,6 +344,7 @@ CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Export)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Extend)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Final)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Impl)
+CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Override)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Private)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Protected)
CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Virtual)
diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def
index 283ff96b4441..d39b1d6ebb03 100644
--- a/toolchain/parse/state.def
+++ b/toolchain/parse/state.def
@@ -285,8 +285,8 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams)
// ^~~~~~
// final
// ^~~~~
-// impl fn
-// ^~~~
+// override fn
+// ^~~~~~~~
// private
// ^~~~~~~
// protected
diff --git a/toolchain/parse/testdata/function/decl_statement.carbon b/toolchain/parse/testdata/function/decl_statement.carbon
index f188ae5e2c5e..a623e27b1cd6 100644
--- a/toolchain/parse/testdata/function/decl_statement.carbon
+++ b/toolchain/parse/testdata/function/decl_statement.carbon
@@ -37,6 +37,7 @@ fn F() {
namespace N;
default fn F();
impl fn G();
+ override fn H();
virtual fn H();
private var v: i32;
protected var v: i32;
@@ -157,6 +158,12 @@ fn F() {
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
+// CHECK:STDOUT: {kind: 'OverrideModifier', text: 'override'},
+// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'H'},
+// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
+// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
+// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6},
+// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'VirtualModifier', text: 'virtual'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'H'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
@@ -176,6 +183,6 @@ fn F() {
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 4},
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 7},
-// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 58},
+// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 64},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
diff --git a/toolchain/parse/testdata/function/declaration.carbon b/toolchain/parse/testdata/function/declaration.carbon
index 0b1438ea4a00..b6f4a41b7276 100644
--- a/toolchain/parse/testdata/function/declaration.carbon
+++ b/toolchain/parse/testdata/function/declaration.carbon
@@ -58,10 +58,10 @@ fn destroy[self: Self]().Foo() {}
// --- impl_fn.carbon
-impl fn F();
-abstract impl fn G();
-impl abstract fn H();
-private impl default fn I();
+override fn F();
+abstract override fn G();
+override abstract fn H();
+private override default fn I();
// --- fail_identifier_instead_of_sig.carbon
@@ -346,20 +346,20 @@ fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z);
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
-// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'},
+// CHECK:STDOUT: {kind: 'OverrideModifier', text: 'override'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'F'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'AbstractModifier', text: 'abstract'},
-// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'},
+// CHECK:STDOUT: {kind: 'OverrideModifier', text: 'override'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'G'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
-// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'},
+// CHECK:STDOUT: {kind: 'OverrideModifier', text: 'override'},
// CHECK:STDOUT: {kind: 'AbstractModifier', text: 'abstract'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'H'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
@@ -367,7 +367,7 @@ fn (a tokens c d e f g h i j k l m n o p q r s t u v w x y z);
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'PrivateModifier', text: 'private'},
-// CHECK:STDOUT: {kind: 'ImplModifier', text: 'impl'},
+// CHECK:STDOUT: {kind: 'OverrideModifier', text: 'override'},
// CHECK:STDOUT: {kind: 'DefaultModifier', text: 'default'},
// CHECK:STDOUT: {kind: 'IdentifierNameBeforeParams', text: 'I'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp
index e88b6e031ba9..b9ebfa4d028e 100644
--- a/toolchain/sem_ir/formatter.cpp
+++ b/toolchain/sem_ir/formatter.cpp
@@ -496,8 +496,8 @@ auto Formatter::FormatFunction(FunctionId id, const Function& fn) -> void {
case FunctionFields::VirtualModifier::Abstract:
function_start += "abstract ";
break;
- case FunctionFields::VirtualModifier::Impl:
- function_start += "impl ";
+ case FunctionFields::VirtualModifier::Override:
+ function_start += "override ";
break;
case FunctionFields::VirtualModifier::None:
break;
diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h
index 109e0ca2ed4b..20cf84e23f29 100644
--- a/toolchain/sem_ir/function.h
+++ b/toolchain/sem_ir/function.h
@@ -27,7 +27,7 @@ struct FunctionFields {
};
// Kinds of virtual modifiers that can apply to functions.
- enum class VirtualModifier : uint8_t { None, Virtual, Abstract, Impl };
+ enum class VirtualModifier : uint8_t { None, Virtual, Abstract, Override };
// The following members always have values, and do not change throughout the
// lifetime of the function.