فهرست منبع

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 <richard@metafoo.co.uk>
Elliott Kalt 7 ماه پیش
والد
کامیت
f4bd6e42f9

+ 17 - 16
docs/design/classes.md

@@ -1237,21 +1237,20 @@ There are three virtual modifier keywords:
     virtual" but is called
     virtual" but is called
     ["pure virtual" in C++](https://en.wikipedia.org/wiki/Virtual_function#Abstract_classes_and_pure_virtual_functions).
     ["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.
     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
     `abstract` in the base class with an implementation specific to -- and
     defined within -- this class. The method is still virtual and may be
     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
     overridden again in subsequent derived classes if this is a base class. See
     [method overriding in Wikipedia](https://en.wikipedia.org/wiki/Method_overriding).
     [method overriding in Wikipedia](https://en.wikipedia.org/wiki/Method_overriding).
     Requiring a keyword when overriding allows the compiler to diagnose when the
     Requiring a keyword when overriding allows the compiler to diagnose when the
     derived class accidentally uses the wrong signature or spelling and so
     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<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`                                                |
-| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
-| `virtual`                     | ✅                                 | ✅                             | ❌                              | _not present_                                            | `abstract`<br />`impl`<br />_not mentioned_                                      |
-| `abstract`                    | ✅                                 | ❌                             | ❌                              | _not present_<br />`virtual`<br />`abstract`<br />`impl` | `abstract`<br />`impl`<br />_may not be<br />mentioned if<br />`D` is not final_ |
-| `impl`                        | ✅                                 | ✅                             | ✅                              | `virtual`<br />`abstract`<br />`impl`                    | `abstract`<br />`impl`                                                           |
+| 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`                                                    |
+| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
+| `virtual`                     | ✅                                 | ✅                             | ❌                              | _not present_                                                | `abstract`<br />`override`<br />_not mentioned_                                      |
+| `abstract`                    | ✅                                 | ❌                             | ❌                              | _not present_<br />`virtual`<br />`abstract`<br />`override` | `abstract`<br />`override`<br />_may not be<br />mentioned if<br />`D` is not final_ |
+| `override`                    | ✅                                 | ✅                             | ✅                              | `virtual`<br />`abstract`<br />`override`                    | `abstract`<br />`override`                                                           |
 
 
 Since validating a method with a virtual modifier keyword involves looking for
 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
 methods with the same name in the base class, virtual methods must be declared
@@ -1315,15 +1314,15 @@ base class B1 {
 class D1 {
 class D1 {
   extend base: B1;
   extend base: B1;
   // ❌ Illegal:
   // ❌ 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:
   // 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`.
   // and `D1` is a different type than `B1`.
 
 
   // ✅ Allowed: Parameter and return types
   // ✅ Allowed: Parameter and return types
   //  of `F` match declaration in `B1`.
   //  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 {
 class D2 {
   extend base: B2;
   extend base: B2;
   // ✅ Allowed
   // ✅ Allowed
-  impl fn Clone[self: Self]() -> Self*;
+  override fn Clone[self: Self]() -> Self*;
   // Means the same thing as:
   // Means the same thing as:
-  //   impl fn Clone[self: D2]() -> D2*;
+  //   override fn Clone[self: D2]() -> D2*;
   // which is allowed since `D2*` is a
   // which is allowed since `D2*` is a
   // subtype of `B2*`.
   // 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).
 [virtual destructor](https://en.wikipedia.org/wiki/Virtual_function#Virtual_destructors).
 An abstract or base class' destructor may be declared virtual using the
 An abstract or base class' destructor may be declared virtual using the
 `virtual` introducer, in which case any derived class destructor declaration
 `virtual` introducer, in which case any derived class destructor declaration
-must be `impl`:
+must be `override`:
 
 
 ```carbon
 ```carbon
 base class MyBaseClass {
 base class MyBaseClass {
@@ -1624,7 +1623,7 @@ base class MyBaseClass {
 
 
 class MyDerivedClass {
 class MyDerivedClass {
   extend base: MyBaseClass;
   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 syntax options](/proposals/p5017.md#destructor-syntax-options)
     -   [Destructor name options](/proposals/p5017.md#destructor-name-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
 ## References
 
 
 -   [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)
 -   [#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257)

+ 57 - 0
proposals/p6008.md

@@ -0,0 +1,57 @@
+# Replace `impl fn` with `override fn`
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/6008)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Abstract](#abstract)
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Rationale](#rationale)
+
+<!-- tocstop -->
+
+## 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.

+ 7 - 5
toolchain/check/class.cpp

@@ -199,7 +199,7 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
                     .GetAs<SemIR::FunctionDecl>(override_fn_decl_id)
                     .GetAs<SemIR::FunctionDecl>(override_fn_decl_id)
                     .function_id);
                     .function_id);
             return override_fn.virtual_modifier ==
             return override_fn.virtual_modifier ==
-                       SemIR::FunctionFields::VirtualModifier::Impl &&
+                       SemIR::FunctionFields::VirtualModifier::Override &&
                    override_fn.name_id == fn.name_id;
                    override_fn.name_id == fn.name_id;
           });
           });
       if (i != vtable_contents.end()) {
       if (i != vtable_contents.end()) {
@@ -237,13 +237,15 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
   for (auto inst_id : vtable_contents) {
   for (auto inst_id : vtable_contents) {
     auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
     auto fn_decl = context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
     auto& fn = context.functions().Get(fn_decl.function_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();
       fn.virtual_index = vtable.size();
       vtable.push_back(build_specific_function(inst_id));
       vtable.push_back(build_specific_function(inst_id));
     } else if (!implemented_impls.Lookup(fn_decl.function_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);
     }
     }
   }
   }
 
 

+ 6 - 4
toolchain/check/handle_function.cpp

@@ -128,7 +128,8 @@ static auto GetVirtualModifier(const KeywordModifierSet& modifier_set)
             SemIR::Function::VirtualModifier::Virtual)
             SemIR::Function::VirtualModifier::Virtual)
       .Case(KeywordModifierSet::Abstract,
       .Case(KeywordModifierSet::Abstract,
             SemIR::Function::VirtualModifier::Abstract)
             SemIR::Function::VirtualModifier::Abstract)
-      .Case(KeywordModifierSet::Impl, SemIR::Function::VirtualModifier::Impl)
+      .Case(KeywordModifierSet::Override,
+            SemIR::Function::VirtualModifier::Override)
       .Default(SemIR::Function::VirtualModifier::None);
       .Default(SemIR::Function::VirtualModifier::None);
 }
 }
 
 
@@ -342,10 +343,11 @@ static auto RequestVtableIfVirtual(
   }
   }
 
 
   auto& class_info = context.classes().Get(class_decl->class_id);
   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()) {
       !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;
     virtual_modifier = SemIR::Function::VirtualModifier::None;
     return;
     return;
   }
   }

+ 3 - 2
toolchain/check/keyword_modifier_set.h

@@ -38,6 +38,7 @@ enum class ModifierOrder : int8_t { Access, Extern, Extend, Decl, Last = Decl };
   X(Export)                                                                  \
   X(Export)                                                                  \
   X(Final)                                                                   \
   X(Final)                                                                   \
   X(Impl)                                                                    \
   X(Impl)                                                                    \
+  X(Override)                                                                \
   X(Returned)                                                                \
   X(Returned)                                                                \
   X(Virtual)
   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::Access(Private | Protected);
 constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base);
 constexpr KeywordModifierSet KeywordModifierSet::Class(Abstract | Base);
-constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Impl |
+constexpr KeywordModifierSet KeywordModifierSet::Method(Abstract | Override |
                                                         Virtual);
                                                         Virtual);
 constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend | Final);
 constexpr KeywordModifierSet KeywordModifierSet::ImplDecl(Extend | Final);
 constexpr KeywordModifierSet KeywordModifierSet::Interface(Default | Final);
 constexpr KeywordModifierSet KeywordModifierSet::Interface(Default | Final);
-constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method |
+constexpr KeywordModifierSet KeywordModifierSet::Decl(Class | Method | Impl |
                                                       Interface | Export |
                                                       Interface | Export |
                                                       Returned);
                                                       Returned);
 
 

+ 109 - 109
toolchain/check/testdata/class/virtual_modifiers.carbon

@@ -34,7 +34,7 @@ import Modifiers;
 
 
 class Derived {
 class Derived {
   extend base: Modifiers.Base;
   extend base: Modifiers.Base;
-  impl fn H[self: Self]();
+  override fn H[self: Self]();
 }
 }
 
 
 fn Use() {
 fn Use() {
@@ -72,7 +72,7 @@ abstract class A1 {
 
 
 abstract class A2 {
 abstract class A2 {
   extend base: A1;
   extend base: A1;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 // --- impl_base.carbon
 // --- impl_base.carbon
@@ -85,12 +85,12 @@ base class B1 {
 
 
 base class B2 {
 base class B2 {
   extend base: B1;
   extend base: B1;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 class C {
 class C {
   extend base: B2;
   extend base: B2;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 fn Use() {
 fn Use() {
@@ -104,11 +104,11 @@ fn Use() {
 library "[[@TEST_NAME]]";
 library "[[@TEST_NAME]]";
 
 
 class C {
 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:
   // CHECK:STDERR:
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 // --- init_members.carbon
 // --- init_members.carbon
@@ -139,11 +139,11 @@ base class Base {
 
 
 class Derived {
 class Derived {
   extend base: Base;
   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:
   // CHECK:STDERR:
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 // --- abstract_impl.carbon
 // --- abstract_impl.carbon
@@ -160,7 +160,7 @@ abstract class AbstractIntermediate {
 
 
 class Derived {
 class Derived {
   extend base: AbstractIntermediate;
   extend base: AbstractIntermediate;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 // --- virtual_impl.carbon
 // --- virtual_impl.carbon
@@ -177,7 +177,7 @@ base class VirtualIntermediate {
 
 
 class Derived {
 class Derived {
   extend base: VirtualIntermediate;
   extend base: VirtualIntermediate;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 // --- fail_impl_mismatch.carbon
 // --- fail_impl_mismatch.carbon
@@ -191,13 +191,13 @@ base class Base {
 class Derived {
 class Derived {
   extend base: Base;
   extend base: Base;
   // CHECK:STDERR: fail_impl_mismatch.carbon:[[@LINE+7]]:3: error: redeclaration differs because of parameter count of 1 [RedeclParamCountDiffers]
   // 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: 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:   virtual fn F[self: Self]();
   // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
-  impl fn F[self: Self](v: i32);
+  override fn F[self: Self](v: i32);
 }
 }
 
 
 // --- fail_todo_impl_conversion.carbon
 // --- fail_todo_impl_conversion.carbon
@@ -223,13 +223,13 @@ base class Base {
 class Derived {
 class Derived {
   extend base: Base;
   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: 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: 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:   virtual fn F[self: Self]() -> T1;
   // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
-  impl fn F[self: Self]() -> T2;
+  override fn F[self: Self]() -> T2;
 }
 }
 
 
 // --- fail_generic_virtual_decl.carbon
 // --- fail_generic_virtual_decl.carbon
@@ -261,7 +261,7 @@ base class Base(T:! type) {
 
 
 class Derived {
 class Derived {
   extend base: Base(T1);
   extend base: Base(T1);
-  impl fn F[self: Self](t: T1) { }
+  override fn F[self: Self](t: T1) { }
 }
 }
 
 
 // --- fail_virtual_without_self.carbon
 // --- fail_virtual_without_self.carbon
@@ -284,10 +284,10 @@ abstract class T1 {
 class T2 {
 class T2 {
   extend base: T1;
   extend base: T1;
   // CHECK:STDERR: fail_virtual_without_self.carbon:[[@LINE+4]]:3: error: virtual class function [VirtualWithoutSelf]
   // 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:
   // CHECK:STDERR:
-  impl fn F();
+  override fn F();
 }
 }
 
 
 // --- fail_addr_self_mismatch.carbon
 // --- fail_addr_self_mismatch.carbon
@@ -300,14 +300,14 @@ base class T1 {
 
 
 class T2 {
 class T2 {
   extend base: T1;
   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: 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:   virtual fn F1[self: Self*]();
   // CHECK:STDERR:                 ^~~~~~~~~~~
   // CHECK:STDERR:                 ^~~~~~~~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
-  impl fn F1[addr self: Self*]();
+  override fn F1[addr self: Self*]();
 }
 }
 
 
 // --- fail_generic_virtual.carbon
 // --- fail_generic_virtual.carbon
@@ -369,7 +369,7 @@ base class NonGenericBase {
 
 
 base class GenericDerived(T:! type) {
 base class GenericDerived(T:! type) {
   extend base: NonGenericBase;
   extend base: NonGenericBase;
-  impl fn F2[self: Self]() { }
+  override fn F2[self: Self]() { }
   virtual fn F3[self: Self]() { }
   virtual fn F3[self: Self]() { }
 }
 }
 
 
@@ -386,7 +386,7 @@ class T1;
 
 
 base class NonGenericDerived {
 base class NonGenericDerived {
   extend base: GenericBase(T1);
   extend base: GenericBase(T1);
-  impl fn F2[self: Self]() { }
+  override fn F2[self: Self]() { }
   virtual fn F3[self: Self]() { }
   virtual fn F3[self: Self]() { }
 }
 }
 
 
@@ -400,7 +400,7 @@ base class Base(T:! type) {
 class T1;
 class T1;
 class D1 {
 class D1 {
   extend base: Base(T1);
   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
 // --- fail_impl_generic_specifically_mismatch.carbon
@@ -416,14 +416,14 @@ base class Base(T:! type) {
 
 
 class D1 {
 class D1 {
   extend base: Base(T1);
   extend base: Base(T1);
-  // CHECK:STDERR: fail_impl_generic_specifically_mismatch.carbon:[[@LINE+7]]:25: error: type `<pattern for T2*>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for T1*>` [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 `<pattern for T2*>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for T1*>` [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: 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:   virtual fn F[self: Self](t: T1*) { }
   // CHECK:STDERR:                            ^~~~~~
   // CHECK:STDERR:                            ^~~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
-  impl fn F[self: Self](t: T2*) { }
+  override fn F[self: Self](t: T2*) { }
 }
 }
 
 
 // --- fail_impl_generic_generic_mismatch.carbon
 // --- fail_impl_generic_generic_mismatch.carbon
@@ -435,14 +435,14 @@ abstract class Base(T:! type) {
 }
 }
 class Derived(T:! type) {
 class Derived(T:! type) {
   extend base: Base(T);
   extend base: Base(T);
-  // CHECK:STDERR: fail_impl_generic_generic_mismatch.carbon:[[@LINE+7]]:25: error: type `<pattern for T>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for T*>` [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 `<pattern for T>` of parameter 1 in redeclaration differs from previous parameter type `<pattern for T*>` [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: 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:   virtual fn F[self: Self](t: T*) { }
   // CHECK:STDERR:                            ^~~~~
   // CHECK:STDERR:                            ^~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
-  impl fn F[self: Self](t: T) { }
+  override fn F[self: Self](t: T) { }
 }
 }
 
 
 // --- impl_generic_generic.carbon
 // --- impl_generic_generic.carbon
@@ -454,7 +454,7 @@ abstract class Base(T:! type) {
 }
 }
 class Derived(T:! type) {
 class Derived(T:! type) {
   extend base: Base(T*);
   extend base: Base(T*);
-  impl fn F[self: Self](t: T*) { }
+  override fn F[self: Self](t: T*) { }
 }
 }
 
 
 // --- abstract_generic_undefined.carbon
 // --- abstract_generic_undefined.carbon
@@ -469,7 +469,7 @@ class T1;
 
 
 class Derived {
 class Derived {
   extend base: Base(T1);
   extend base: Base(T1);
-  impl fn F[self: Self]() { }
+  override fn F[self: Self]() { }
 }
 }
 
 
 // --- generic_lib.carbon
 // --- generic_lib.carbon
@@ -802,7 +802,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:   @Derived.%Derived.H.decl
 // CHECK:STDOUT:   @Derived.%Derived.H.decl
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -1236,7 +1236,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @A1.as.Destroy.impl.Op(%self.param: %ptr.678) = "no_op";
 // CHECK:STDOUT: fn @A1.as.Destroy.impl.Op(%self.param: %ptr.678) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @A2.F(%self.param: %A2);
+// CHECK:STDOUT: override fn @A2.F(%self.param: %A2);
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @A2.as.Destroy.impl.Op(%self.param: %ptr.590) = "no_op";
 // CHECK:STDOUT: fn @A2.as.Destroy.impl.Op(%self.param: %ptr.590) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -1468,11 +1468,11 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @B1.as.Destroy.impl.Op(%self.param: %ptr.890) = "no_op";
 // CHECK:STDOUT: fn @B1.as.Destroy.impl.Op(%self.param: %ptr.890) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
-// CHECK:STDOUT: impl fn @B2.F(%self.param: %B2);
+// CHECK:STDOUT: override fn @B2.F(%self.param: %B2);
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @B2.as.Destroy.impl.Op(%self.param: %ptr.afe) = "no_op";
 // CHECK:STDOUT: fn @B2.as.Destroy.impl.Op(%self.param: %ptr.afe) = "no_op";
 // 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:
 // CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
 // CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -1617,7 +1617,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:   .F = %C.F.decl
 // CHECK:STDOUT:   .F = %C.F.decl
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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:
 // CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
 // CHECK:STDOUT: fn @C.as.Destroy.impl.Op(%self.param: %ptr.019) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -2013,7 +2013,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "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:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -2218,7 +2218,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @AbstractIntermediate.as.Destroy.impl.Op(%self.param: %ptr.fd8) = "no_op";
 // CHECK:STDOUT: fn @AbstractIntermediate.as.Destroy.impl.Op(%self.param: %ptr.fd8) = "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:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -2423,7 +2423,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @VirtualIntermediate.as.Destroy.impl.Op(%self.param: %ptr.7dc) = "no_op";
 // CHECK:STDOUT: fn @VirtualIntermediate.as.Destroy.impl.Op(%self.param: %ptr.7dc) = "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:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -2590,7 +2590,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
 // CHECK:STDOUT:
 // 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:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // CHECK:STDOUT:
@@ -2882,7 +2882,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
 // CHECK:STDOUT: fn @Base.as.Destroy.impl.Op(%self.param: %ptr.11f) = "no_op";
 // CHECK:STDOUT:
 // 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:
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT: fn @Derived.as.Destroy.impl.Op(%self.param: %ptr.404) = "no_op";
 // CHECK:STDOUT:
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // 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:   %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.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:     %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:   } {
 // CHECK:STDOUT:     %self.param: %ptr.63e = value_param call_param0
 // 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:       %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:       %ptr: type = ptr_type %Self.ref [concrete = constants.%ptr.63e]
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     }
@@ -3660,7 +3660,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @T1.as.Destroy.impl.Op(%self.param: %ptr.87b) = "no_op";
 // CHECK:STDOUT: fn @T1.as.Destroy.impl.Op(%self.param: %ptr.87b) = "no_op";
 // CHECK:STDOUT:
 // 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:
 // CHECK:STDOUT: fn @T2.as.Destroy.impl.Op(%self.param: %ptr.63e) = "no_op";
 // CHECK:STDOUT: fn @T2.as.Destroy.impl.Op(%self.param: %ptr.63e) = "no_op";
 // CHECK:STDOUT:
 // 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:       %self.param_patt: @GenericDerived.F2.%pattern_type (%pattern_type.061) = value_param_pattern %self.patt, call_param0 [concrete]
 // CHECK:STDOUT:     } {
 // CHECK:STDOUT:     } {
 // CHECK:STDOUT:       %self.param: @GenericDerived.F2.%GenericDerived (%GenericDerived) = value_param call_param0
 // 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:       }
 // CHECK:STDOUT:       %self: @GenericDerived.F2.%GenericDerived (%GenericDerived) = bind_name self, %self.param
 // CHECK:STDOUT:       %self: @GenericDerived.F2.%GenericDerived (%GenericDerived) = bind_name self, %self.param
 // CHECK:STDOUT:     }
 // CHECK:STDOUT:     }
@@ -4566,7 +4566,7 @@ class T2(G2:! type) {
 // CHECK:STDOUT:
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @NonGenericBase.as.Destroy.impl.Op(%self.param: %ptr.806) = "no_op";
 // CHECK:STDOUT: fn @NonGenericBase.as.Destroy.impl.Op(%self.param: %ptr.806) = "no_op";
 // CHECK:STDOUT:
 // 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:   %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:   %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)]
 // 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: !definition:
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %GenericDerived [symbolic = %require_complete (constants.%require_complete)]
 // CHECK:STDOUT:   %require_complete: <witness> = require_complete_type %GenericDerived [symbolic = %require_complete (constants.%require_complete)]
 // CHECK:STDOUT:
 // 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:   !entry:
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:   }
 // 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:   fn(%self.param: @GenericBase.as.Destroy.impl.Op.%ptr (%ptr.b68)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // 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:     %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:     %.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:     %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:     } {
 // CHECK:STDOUT:       %self.param: @Derived.F.%Derived (%Derived) = value_param call_param0
 // 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:       }
 // CHECK:STDOUT:       %self: @Derived.F.%Derived (%Derived) = bind_name self, %self.param
 // CHECK:STDOUT:       %self: @Derived.F.%Derived (%Derived) = bind_name self, %self.param
 // CHECK:STDOUT:       %t.param: @Derived.F.%T (%T) = value_param call_param1
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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:   %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:   %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:   %Base: type = class_type @Base, @Base(%T) [symbolic = %Base (constants.%Base)]
-// CHECK:STDOUT:   %require_complete.loc16_28: <witness> = 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: <witness> = 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:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %require_complete.loc16_17: <witness> = require_complete_type %Derived [symbolic = %require_complete.loc16_17 (constants.%require_complete.5f4)]
-// CHECK:STDOUT:   %require_complete.loc16_26: <witness> = require_complete_type %T [symbolic = %require_complete.loc16_26 (constants.%require_complete.4ae)]
+// CHECK:STDOUT:   %require_complete.loc16_21: <witness> = require_complete_type %Derived [symbolic = %require_complete.loc16_21 (constants.%require_complete.5f4)]
+// CHECK:STDOUT:   %require_complete.loc16_30: <witness> = require_complete_type %T [symbolic = %require_complete.loc16_30 (constants.%require_complete.4ae)]
 // CHECK:STDOUT:
 // 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:   !entry:
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
@@ -5979,14 +5979,14 @@ class T2(G2:! type) {
 // CHECK:STDOUT: specific @Derived.F(constants.%T) {
 // CHECK:STDOUT: specific @Derived.F(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:   %Derived => constants.%Derived
 // 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:   %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:
 // CHECK:STDOUT: !definition:
 // 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:
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Derived.as.Destroy.impl(constants.%T) {
 // 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:     %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:     %.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:     %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:     } {
 // CHECK:STDOUT:       %self.param: @Derived.F.%Derived (%Derived) = value_param call_param0
 // 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:       }
 // CHECK:STDOUT:       %self: @Derived.F.%Derived (%Derived) = bind_name self, %self.param
 // 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:         %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:       }
-// 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:     }
 // CHECK:STDOUT:     %Self.ref: type = name_ref Self, constants.%Derived [symbolic = @Derived.as.Destroy.impl.%Derived (constants.%Derived)]
 // 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] {} {}
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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:   %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:   %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: <witness> = 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: <witness> = 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:
 // CHECK:STDOUT: !definition:
 // CHECK:STDOUT: !definition:
-// CHECK:STDOUT:   %require_complete.loc9_17: <witness> = require_complete_type %Derived [symbolic = %require_complete.loc9_17 (constants.%require_complete.5f4)]
-// CHECK:STDOUT:   %require_complete.loc9_26: <witness> = require_complete_type %ptr.loc9_28 [symbolic = %require_complete.loc9_26 (constants.%require_complete.6e5)]
+// CHECK:STDOUT:   %require_complete.loc9_21: <witness> = require_complete_type %Derived [symbolic = %require_complete.loc9_21 (constants.%require_complete.5f4)]
+// CHECK:STDOUT:   %require_complete.loc9_30: <witness> = require_complete_type %ptr.loc9_32 [symbolic = %require_complete.loc9_30 (constants.%require_complete.6e5)]
 // CHECK:STDOUT:
 // 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:   !entry:
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:     return
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   }
@@ -6385,15 +6385,15 @@ class T2(G2:! type) {
 // CHECK:STDOUT: specific @Derived.F(constants.%T) {
 // CHECK:STDOUT: specific @Derived.F(constants.%T) {
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:   %T => constants.%T
 // CHECK:STDOUT:   %Derived => constants.%Derived
 // 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:   %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:
 // CHECK:STDOUT: !definition:
 // 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:
 // CHECK:STDOUT:
 // CHECK:STDOUT: specific @Derived.as.Destroy.impl(constants.%T) {
 // 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:   fn(%self.param: @Base.as.Destroy.impl.Op.%ptr (%ptr.b7c)) = "no_op";
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 // 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: !entry:
 // CHECK:STDOUT:   return
 // CHECK:STDOUT:   return
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }

+ 4 - 4
toolchain/check/testdata/function/definition/fail_local_decl.carbon

@@ -22,11 +22,11 @@ fn F() {
   // CHECK:STDERR:   ^~~~~~~
   // CHECK:STDERR:   ^~~~~~~
   // CHECK:STDERR:
   // CHECK:STDERR:
   default fn F();
   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:
   // 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: fail_virtual.carbon:[[@LINE+4]]:3: error: `virtual` not allowed; requires class scope [ModifierRequiresClass]
   // CHECK:STDERR:   virtual fn H();
   // CHECK:STDERR:   virtual fn H();
   // CHECK:STDERR:   ^~~~~~~
   // CHECK:STDERR:   ^~~~~~~

+ 4 - 4
toolchain/check/testdata/interop/cpp/class/abstract.carbon

@@ -46,11 +46,11 @@ import Cpp library "abstract.h";
 
 
 class C {
 class C {
   extend base: Cpp.A;
   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:
   // CHECK:STDERR:
-  impl fn f[addr self: Self*]() {}
+  override fn f[addr self: Self*]() {}
 }
 }
 
 
 // --- abstract_final.h
 // --- abstract_final.h

+ 2 - 2
toolchain/diagnostics/diagnostic_kind.def

@@ -289,8 +289,8 @@ CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass)
 CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious)
 CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclPrevious)
 CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)
 CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)
 CARBON_DIAGNOSTIC_KIND(GenericVirtual)
 CARBON_DIAGNOSTIC_KIND(GenericVirtual)
-CARBON_DIAGNOSTIC_KIND(ImplWithoutBase)
-CARBON_DIAGNOSTIC_KIND(ImplWithoutVirtualInBase)
+CARBON_DIAGNOSTIC_KIND(OverrideWithoutBase)
+CARBON_DIAGNOSTIC_KIND(OverrideWithoutVirtualInBase)
 CARBON_DIAGNOSTIC_KIND(VirtualWithoutSelf)
 CARBON_DIAGNOSTIC_KIND(VirtualWithoutSelf)
 
 
 // Deduction.
 // Deduction.

+ 1 - 0
toolchain/lex/token_kind.def

@@ -199,6 +199,7 @@ CARBON_KEYWORD_TOKEN(Not,                 "not")
 CARBON_KEYWORD_TOKEN(Observe,             "observe")
 CARBON_KEYWORD_TOKEN(Observe,             "observe")
 CARBON_TOKEN_WITH_VIRTUAL_NODE(
 CARBON_TOKEN_WITH_VIRTUAL_NODE(
   CARBON_KEYWORD_TOKEN(Or,                "or"))
   CARBON_KEYWORD_TOKEN(Or,                "or"))
+CARBON_KEYWORD_TOKEN(Override,            "override")
 CARBON_KEYWORD_TOKEN(Partial,             "partial")
 CARBON_KEYWORD_TOKEN(Partial,             "partial")
 CARBON_KEYWORD_TOKEN(Private,             "private")
 CARBON_KEYWORD_TOKEN(Private,             "private")
 CARBON_KEYWORD_TOKEN(Protected,           "protected")
 CARBON_KEYWORD_TOKEN(Protected,           "protected")

+ 2 - 2
toolchain/lower/testdata/class/virtual.carbon

@@ -24,7 +24,7 @@ base class Intermediate {
 
 
 class Derived {
 class Derived {
   extend base: Intermediate;
   extend base: Intermediate;
-  impl fn Fn[self: Self]() { }
+  override fn Fn[self: Self]() { }
 }
 }
 
 
 // --- create.carbon
 // --- create.carbon
@@ -100,7 +100,7 @@ base class Base {
 
 
 class Derived {
 class Derived {
   extend base: Base;
   extend base: Base;
-  impl fn F[self: Self]();
+  override fn F[self: Self]();
 }
 }
 
 
 fn Use() {
 fn Use() {

+ 1 - 0
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(Extend)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Final)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Final)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Impl)
 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(Private)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Protected)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Protected)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Virtual)
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Virtual)

+ 2 - 2
toolchain/parse/state.def

@@ -285,8 +285,8 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams)
 // ^~~~~~
 // ^~~~~~
 // final
 // final
 // ^~~~~
 // ^~~~~
-// impl fn
-// ^~~~
+// override fn
+// ^~~~~~~~
 // private
 // private
 // ^~~~~~~
 // ^~~~~~~
 // protected
 // protected

+ 8 - 1
toolchain/parse/testdata/function/decl_statement.carbon

@@ -37,6 +37,7 @@ fn F() {
   namespace N;
   namespace N;
   default fn F();
   default fn F();
   impl fn G();
   impl fn G();
+  override fn H();
   virtual fn H();
   virtual fn H();
   private var v: i32;
   private var v: i32;
   protected var v: i32;
   protected var v: i32;
@@ -157,6 +158,12 @@ fn F() {
 // CHECK:STDOUT:         {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:         {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:       {kind: 'FunctionDecl', text: ';', subtree_size: 6},
 // CHECK:STDOUT:       {kind: 'FunctionDecl', text: ';', subtree_size: 6},
 // CHECK:STDOUT:         {kind: 'FunctionIntroducer', text: 'fn'},
 // 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: 'VirtualModifier', text: 'virtual'},
 // CHECK:STDOUT:         {kind: 'IdentifierNameBeforeParams', text: 'H'},
 // CHECK:STDOUT:         {kind: 'IdentifierNameBeforeParams', text: 'H'},
 // CHECK:STDOUT:           {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:           {kind: 'ExplicitParamListStart', text: '('},
@@ -176,6 +183,6 @@ fn F() {
 // CHECK:STDOUT:           {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
 // CHECK:STDOUT:           {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
 // CHECK:STDOUT:         {kind: 'VariablePattern', text: 'var', subtree_size: 4},
 // CHECK:STDOUT:         {kind: 'VariablePattern', text: 'var', subtree_size: 4},
 // CHECK:STDOUT:       {kind: 'VariableDecl', text: ';', subtree_size: 7},
 // 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:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]
 // CHECK:STDOUT:   ]

+ 8 - 8
toolchain/parse/testdata/function/declaration.carbon

@@ -58,10 +58,10 @@ fn destroy[self: Self]().Foo() {}
 
 
 // --- impl_fn.carbon
 // --- 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
 // --- 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:   parse_tree: [
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // 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: 'IdentifierNameBeforeParams', text: 'F'},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:       {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:       {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'FunctionDecl', text: ';', subtree_size: 6},
 // CHECK:STDOUT:     {kind: 'FunctionDecl', text: ';', subtree_size: 6},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'AbstractModifier', text: 'abstract'},
 // 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: 'IdentifierNameBeforeParams', text: 'G'},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:       {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:       {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'FunctionDecl', text: ';', subtree_size: 7},
 // CHECK:STDOUT:     {kind: 'FunctionDecl', text: ';', subtree_size: 7},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // 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: 'AbstractModifier', text: 'abstract'},
 // CHECK:STDOUT:       {kind: 'IdentifierNameBeforeParams', text: 'H'},
 // CHECK:STDOUT:       {kind: 'IdentifierNameBeforeParams', text: 'H'},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // 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: 'FunctionDecl', text: ';', subtree_size: 7},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'FunctionIntroducer', text: 'fn'},
 // CHECK:STDOUT:       {kind: 'PrivateModifier', text: 'private'},
 // 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: 'DefaultModifier', text: 'default'},
 // CHECK:STDOUT:       {kind: 'IdentifierNameBeforeParams', text: 'I'},
 // CHECK:STDOUT:       {kind: 'IdentifierNameBeforeParams', text: 'I'},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},
 // CHECK:STDOUT:         {kind: 'ExplicitParamListStart', text: '('},

+ 2 - 2
toolchain/sem_ir/formatter.cpp

@@ -496,8 +496,8 @@ auto Formatter::FormatFunction(FunctionId id, const Function& fn) -> void {
     case FunctionFields::VirtualModifier::Abstract:
     case FunctionFields::VirtualModifier::Abstract:
       function_start += "abstract ";
       function_start += "abstract ";
       break;
       break;
-    case FunctionFields::VirtualModifier::Impl:
-      function_start += "impl ";
+    case FunctionFields::VirtualModifier::Override:
+      function_start += "override ";
       break;
       break;
     case FunctionFields::VirtualModifier::None:
     case FunctionFields::VirtualModifier::None:
       break;
       break;

+ 1 - 1
toolchain/sem_ir/function.h

@@ -27,7 +27,7 @@ struct FunctionFields {
   };
   };
 
 
   // Kinds of virtual modifiers that can apply to functions.
   // 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
   // The following members always have values, and do not change throughout the
   // lifetime of the function.
   // lifetime of the function.