Files
carbon-lang/toolchain/check/testdata/class/fail_method_modifiers.carbon
T
a8b46cf561 Add SemIR Vtable instruction and usage (#4732)
Add a Vtable typed inst with a type_id (of the type this vtable applies
to) and list of virtual function decls (or import refs to function
object constants).

This doesn't add lowering/emission of the vtable, or usage when
initializing objects of the type.

Some questions in case they're interesting to discuss:
* is it right/worth having the type_id in the vtable? (probably makes it
easier to emit - using the type to get the class name to figure out the
mangled name for the vtable) perhaps it should be a ClassId?
* I'm thinking the logic in CheckCompleteClassType could be the place we
handle diagnostics for mismatched keywords (virtual/abstract for a
function that's already virtual/abstract, maybe checking for non-virtual
functions with the same name in a base class, or derived class functions
without `impl`, etc) - but we could move some of that to the moment we
walk the function decl, and record our findings in the function decl
(record the base function it overrides, or the index of the vtable to
slot to use when building the vtable at the end of the class)
* the Vtable typed inst has `constant_kind = InstConstantKind::Always`
and `is_lowered = false`, I think I added that in to workaround/address
some failures in lowering. And seems correct for this intermediate step
- I'll add lowering in a follow-up patch. But the constant_kind - what
should this be? We can just say all vtables are of VtableType (in which
case the `Always` constant kind sounds right to me) or we could have
them introduce a type with each virtual function as a named member,
even?

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
2025-01-16 20:19:22 +00:00

163 lines
8.8 KiB
Plaintext

// 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
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_method_modifiers.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_method_modifiers.carbon
class FinalClass {
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE+7]]:3: error: `abstract` not allowed; requires `abstract` class scope [ModifierAbstractNotAllowed]
// CHECK:STDERR: abstract fn Abstract[self: Self]();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE-5]]:1: note: containing definition here [ModifierNotInContext]
// CHECK:STDERR: class FinalClass {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
abstract fn Abstract[self: Self]();
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE+7]]:3: error: `virtual` not allowed; requires `abstract` or `base` class scope [ModifierVirtualNotAllowed]
// CHECK:STDERR: virtual fn Virtual[self: Self]();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE-14]]:1: note: containing definition here [ModifierNotInContext]
// CHECK:STDERR: class FinalClass {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
virtual fn Virtual[self: Self]();
}
abstract class AbstractClass {
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE+4]]:3: error: `default` not allowed; requires interface scope [ModifierRequiresInterface]
// CHECK:STDERR: default fn Default[self: Self]();
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
default fn Default[self: Self]();
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE+4]]:3: error: `final` not allowed; requires interface scope [ModifierRequiresInterface]
// CHECK:STDERR: final fn Final[self: Self]();
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
final fn Final[self: Self]();
}
base class BaseClass {
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE+6]]:3: error: `abstract` not allowed; requires `abstract` class scope [ModifierAbstractNotAllowed]
// CHECK:STDERR: abstract fn Abstract[self: Self]();
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_method_modifiers.carbon:[[@LINE-5]]:1: note: containing definition here [ModifierNotInContext]
// CHECK:STDERR: base class BaseClass {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
abstract fn Abstract[self: Self]();
}
// CHECK:STDOUT: --- fail_method_modifiers.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %FinalClass: type = class_type @FinalClass [template]
// CHECK:STDOUT: %Abstract.type.c3e: type = fn_type @Abstract.1 [template]
// CHECK:STDOUT: %Abstract.d21: %Abstract.type.c3e = struct_value () [template]
// CHECK:STDOUT: %Virtual.type: type = fn_type @Virtual [template]
// CHECK:STDOUT: %Virtual: %Virtual.type = struct_value () [template]
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template]
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template]
// CHECK:STDOUT: %AbstractClass: type = class_type @AbstractClass [template]
// CHECK:STDOUT: %Default.type: type = fn_type @Default [template]
// CHECK:STDOUT: %Default: %Default.type = struct_value () [template]
// CHECK:STDOUT: %Final.type: type = fn_type @Final [template]
// CHECK:STDOUT: %Final: %Final.type = struct_value () [template]
// CHECK:STDOUT: %BaseClass: type = class_type @BaseClass [template]
// CHECK:STDOUT: %Abstract.type.de1: type = fn_type @Abstract.2 [template]
// CHECK:STDOUT: %Abstract.af0: %Abstract.type.de1 = struct_value () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .FinalClass = %FinalClass.decl
// CHECK:STDOUT: .AbstractClass = %AbstractClass.decl
// CHECK:STDOUT: .BaseClass = %BaseClass.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %FinalClass.decl: type = class_decl @FinalClass [template = constants.%FinalClass] {} {}
// CHECK:STDOUT: %AbstractClass.decl: type = class_decl @AbstractClass [template = constants.%AbstractClass] {} {}
// CHECK:STDOUT: %BaseClass.decl: type = class_decl @BaseClass [template = constants.%BaseClass] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @FinalClass {
// CHECK:STDOUT: %Abstract.decl: %Abstract.type.c3e = fn_decl @Abstract.1 [template = constants.%Abstract.d21] {
// CHECK:STDOUT: %self.patt: %FinalClass = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %FinalClass = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %FinalClass = value_param runtime_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%FinalClass [template = constants.%FinalClass]
// CHECK:STDOUT: %self: %FinalClass = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Virtual.decl: %Virtual.type = fn_decl @Virtual [template = constants.%Virtual] {
// CHECK:STDOUT: %self.patt: %FinalClass = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %FinalClass = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %FinalClass = value_param runtime_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%FinalClass [template = constants.%FinalClass]
// CHECK:STDOUT: %self: %FinalClass = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @AbstractClass {
// CHECK:STDOUT: %Default.decl: %Default.type = fn_decl @Default [template = constants.%Default] {
// CHECK:STDOUT: %self.patt: %AbstractClass = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %AbstractClass = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %AbstractClass = value_param runtime_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%AbstractClass [template = constants.%AbstractClass]
// CHECK:STDOUT: %self: %AbstractClass = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Final.decl: %Final.type = fn_decl @Final [template = constants.%Final] {
// CHECK:STDOUT: %self.patt: %AbstractClass = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %AbstractClass = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %AbstractClass = value_param runtime_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%AbstractClass [template = constants.%AbstractClass]
// CHECK:STDOUT: %self: %AbstractClass = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @BaseClass {
// CHECK:STDOUT: %Abstract.decl: %Abstract.type.de1 = fn_decl @Abstract.2 [template = constants.%Abstract.af0] {
// CHECK:STDOUT: %self.patt: %BaseClass = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %BaseClass = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: %BaseClass = value_param runtime_param0
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%BaseClass [template = constants.%BaseClass]
// CHECK:STDOUT: %self: %BaseClass = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [template = constants.%complete_type]
// CHECK:STDOUT: complete_type_witness = %complete_type
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Abstract.1[%self.param_patt: %FinalClass]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Virtual[%self.param_patt: %FinalClass]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Default[%self.param_patt: %AbstractClass]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Final[%self.param_patt: %AbstractClass]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Abstract.2[%self.param_patt: %BaseClass]();
// CHECK:STDOUT: