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>
This commit is contained in:
Elliott Kalt
2025-09-12 23:27:02 +00:00
committed by GitHub
co-authored by Richard Smith
parent 973d721916
commit f4bd6e42f9
17 changed files with 234 additions and 162 deletions
+17 -16
View File
@@ -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<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
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)
+57
View File
@@ -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
View File
@@ -199,7 +199,7 @@ static auto BuildVtable(Context& context, Parse::ClassDefinitionId node_id,
.GetAs<SemIR::FunctionDecl>(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<SemIR::FunctionDecl>(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);
}
}
+6 -4
View File
@@ -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;
}
+3 -2
View File
@@ -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);
+109 -109
View File
@@ -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 `<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: 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 `<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: 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: <witness> = 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: <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: !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: 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: <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: !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: 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: }
@@ -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: ^~~~~~~
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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.
+1
View File
@@ -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")
+2 -2
View File
@@ -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() {
+1
View File
@@ -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)
+2 -2
View File
@@ -285,8 +285,8 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams)
// ^~~~~~
// final
// ^~~~~
// impl fn
// ^~~~
// override fn
// ^~~~~~~~
// private
// ^~~~~~~
// protected
+8 -1
View File
@@ -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: ]
+8 -8
View File
@@ -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: '('},
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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.