Files
carbon-lang/toolchain/check/testdata/class/import_base.carbon
T
Jon Ross-Perkins be56ff87c6 Convert StructTypeField to a specific type. (#4492)
This converts `StructTypeField` from an instruction to a dedicated type,
with its own store. This had originated from discussing how
`.GetAs<SemIR::StructTypeField>` was more prevalent than for other
instructions, but is probably more interesting for the storage savings
(16 bytes StructTypeField + 4 byte LocId + 4 byte InstId -> 8 byte
StructTypeField).

Due to the different structure, these now have their own stack during
construction, reducing (but not eliminating) `args_type_info_stack_`
use-cases.

The test changes of different InstIds is expected because structs and
classes generate fewer instructions now. Other than that, results should
remain the same.

I'm generally trying to avoid unrelated cleanup here due to the PR size,
though I did scrutinize the `VerifyOnFinish` calls, adding one and
commenting others (putting them in member order because that's how I was
checking what was verified and what wasn't).
2024-11-06 21:38:27 +00:00

241 lines
12 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/import_base.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/import_base.carbon
// --- a.carbon
library "[[@TEST_NAME]]";
base class Base {
fn F[self: Self]();
fn Unused[self: Self]();
var x: i32;
var unused: i32;
}
class Child {
extend base: Base;
}
// --- b.carbon
library "[[@TEST_NAME]]";
import library "a";
fn Run() {
var a: Child = {.base = {.x = 0, .unused = 1}};
a.x = 2;
a.F();
}
// CHECK:STDOUT: --- a.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Base: type = class_type @Base [template]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
// CHECK:STDOUT: %Unused.type: type = fn_type @Unused [template]
// CHECK:STDOUT: %Unused: %Unused.type = struct_value () [template]
// CHECK:STDOUT: %Int32.type: type = fn_type @Int32 [template]
// CHECK:STDOUT: %Int32: %Int32.type = struct_value () [template]
// CHECK:STDOUT: %.2: type = unbound_element_type %Base, i32 [template]
// CHECK:STDOUT: %.3: type = struct_type {.x: i32, .unused: i32} [template]
// CHECK:STDOUT: %.4: <witness> = complete_type_witness %.3 [template]
// CHECK:STDOUT: %Child: type = class_type @Child [template]
// CHECK:STDOUT: %.5: type = ptr_type %.3 [template]
// CHECK:STDOUT: %.6: type = unbound_element_type %Child, %Base [template]
// CHECK:STDOUT: %.7: type = struct_type {.base: %Base} [template]
// CHECK:STDOUT: %.8: <witness> = complete_type_witness %.7 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: .Int32 = %import_ref
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref: %Int32.type = import_ref Core//prelude/types, inst+15, loaded [template = constants.%Int32]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: .Child = %Child.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [template = constants.%Base] {} {}
// CHECK:STDOUT: %Child.decl: type = class_decl @Child [template = constants.%Child] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Base {
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {
// CHECK:STDOUT: %self.patt: %Base = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %Base = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Base [template = constants.%Base]
// CHECK:STDOUT: %self.param: %Base = value_param runtime_param0
// CHECK:STDOUT: %self: %Base = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %Unused.decl: %Unused.type = fn_decl @Unused [template = constants.%Unused] {
// CHECK:STDOUT: %self.patt: %Base = binding_pattern self
// CHECK:STDOUT: %self.param_patt: %Base = value_param_pattern %self.patt, runtime_param0
// CHECK:STDOUT: } {
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Base [template = constants.%Base]
// CHECK:STDOUT: %self.param: %Base = value_param runtime_param0
// CHECK:STDOUT: %self: %Base = bind_name self, %self.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %int.make_type_32.loc8: init type = call constants.%Int32() [template = i32]
// CHECK:STDOUT: %.loc8_10.1: type = value_of_initializer %int.make_type_32.loc8 [template = i32]
// CHECK:STDOUT: %.loc8_10.2: type = converted %int.make_type_32.loc8, %.loc8_10.1 [template = i32]
// CHECK:STDOUT: %.loc8_8: %.2 = field_decl x, element0 [template]
// CHECK:STDOUT: %int.make_type_32.loc9: init type = call constants.%Int32() [template = i32]
// CHECK:STDOUT: %.loc9_15.1: type = value_of_initializer %int.make_type_32.loc9 [template = i32]
// CHECK:STDOUT: %.loc9_15.2: type = converted %int.make_type_32.loc9, %.loc9_15.1 [template = i32]
// CHECK:STDOUT: %.loc9_13: %.2 = field_decl unused, element1 [template]
// CHECK:STDOUT: %.loc10: <witness> = complete_type_witness %.3 [template = constants.%.4]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Base
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .Unused = %Unused.decl
// CHECK:STDOUT: .x = %.loc8_8
// CHECK:STDOUT: .unused = %.loc9_13
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Child {
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
// CHECK:STDOUT: %.loc13: %.6 = base_decl %Base, element0 [template]
// CHECK:STDOUT: %.loc14: <witness> = complete_type_witness %.7 [template = constants.%.8]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Child
// CHECK:STDOUT: .base = %.loc13
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F[%self.param_patt: %Base]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Unused[%self.param_patt: %Base]();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32";
// CHECK:STDOUT:
// CHECK:STDOUT: --- b.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Run.type: type = fn_type @Run [template]
// CHECK:STDOUT: %.1: type = tuple_type () [template]
// CHECK:STDOUT: %Run: %Run.type = struct_value () [template]
// CHECK:STDOUT: %Child: type = class_type @Child [template]
// CHECK:STDOUT: %Base: type = class_type @Base [template]
// CHECK:STDOUT: %.2: type = struct_type {.x: i32, .unused: i32} [template]
// CHECK:STDOUT: %.3: <witness> = complete_type_witness %.2 [template]
// CHECK:STDOUT: %.4: type = unbound_element_type %Child, %Base [template]
// CHECK:STDOUT: %.5: type = struct_type {.base: %Base} [template]
// CHECK:STDOUT: %.6: <witness> = complete_type_witness %.5 [template]
// CHECK:STDOUT: %.7: type = ptr_type %.2 [template]
// CHECK:STDOUT: %.8: type = struct_type {.base: %.7} [template]
// CHECK:STDOUT: %.9: type = ptr_type %.5 [template]
// CHECK:STDOUT: %.10: i32 = int_value 0 [template]
// CHECK:STDOUT: %.11: i32 = int_value 1 [template]
// CHECK:STDOUT: %.12: type = struct_type {.base: %.2} [template]
// CHECK:STDOUT: %struct.1: %Base = struct_value (%.10, %.11) [template]
// CHECK:STDOUT: %struct.2: %Child = struct_value (%struct.1) [template]
// CHECK:STDOUT: %.13: type = unbound_element_type %Base, i32 [template]
// CHECK:STDOUT: %.14: i32 = int_value 2 [template]
// CHECK:STDOUT: %F.type: type = fn_type @F [template]
// CHECK:STDOUT: %F: %F.type = struct_value () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %import_ref.1 = import_ref Main//a, inst+3, unloaded
// CHECK:STDOUT: %import_ref.2: type = import_ref Main//a, inst+41, loaded [template = constants.%Child]
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: import Core//prelude
// CHECK:STDOUT: import Core//prelude/...
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.3 = import_ref Main//a, inst+4, unloaded
// CHECK:STDOUT: %import_ref.4: %F.type = import_ref Main//a, inst+10, loaded [template = constants.%F]
// CHECK:STDOUT: %import_ref.5 = import_ref Main//a, inst+19, unloaded
// CHECK:STDOUT: %import_ref.6: %.13 = import_ref Main//a, inst+33, loaded [template = %.1]
// CHECK:STDOUT: %import_ref.7 = import_ref Main//a, inst+37, unloaded
// CHECK:STDOUT: %import_ref.8 = import_ref Main//a, inst+42, unloaded
// CHECK:STDOUT: %import_ref.9 = import_ref Main//a, inst+46, unloaded
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Base = imports.%import_ref.1
// CHECK:STDOUT: .Child = imports.%import_ref.2
// CHECK:STDOUT: .Core = imports.%Core
// CHECK:STDOUT: .Run = %Run.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %default.import = import <invalid>
// CHECK:STDOUT: %Run.decl: %Run.type = fn_decl @Run [template = constants.%Run] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Child {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = imports.%import_ref.8
// CHECK:STDOUT: .base = imports.%import_ref.9
// CHECK:STDOUT: extend name_scope2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Base {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = imports.%import_ref.3
// CHECK:STDOUT: .F = imports.%import_ref.4
// CHECK:STDOUT: .Unused = imports.%import_ref.5
// CHECK:STDOUT: .x = imports.%import_ref.6
// CHECK:STDOUT: .unused = imports.%import_ref.7
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @Run() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Child.ref: type = name_ref Child, imports.%import_ref.2 [template = constants.%Child]
// CHECK:STDOUT: %a.var: ref %Child = var a
// CHECK:STDOUT: %a: ref %Child = bind_name a, %a.var
// CHECK:STDOUT: %.loc7_33: i32 = int_value 0 [template = constants.%.10]
// CHECK:STDOUT: %.loc7_46: i32 = int_value 1 [template = constants.%.11]
// CHECK:STDOUT: %.loc7_47.1: %.2 = struct_literal (%.loc7_33, %.loc7_46)
// CHECK:STDOUT: %.loc7_48.1: %.12 = struct_literal (%.loc7_47.1)
// CHECK:STDOUT: %.loc7_48.2: ref %Base = class_element_access %a.var, element0
// CHECK:STDOUT: %.loc7_47.2: ref i32 = class_element_access %.loc7_48.2, element0
// CHECK:STDOUT: %.loc7_47.3: init i32 = initialize_from %.loc7_33 to %.loc7_47.2 [template = constants.%.10]
// CHECK:STDOUT: %.loc7_47.4: ref i32 = class_element_access %.loc7_48.2, element1
// CHECK:STDOUT: %.loc7_47.5: init i32 = initialize_from %.loc7_46 to %.loc7_47.4 [template = constants.%.11]
// CHECK:STDOUT: %.loc7_47.6: init %Base = class_init (%.loc7_47.3, %.loc7_47.5), %.loc7_48.2 [template = constants.%struct.1]
// CHECK:STDOUT: %.loc7_48.3: init %Base = converted %.loc7_47.1, %.loc7_47.6 [template = constants.%struct.1]
// CHECK:STDOUT: %.loc7_48.4: init %Child = class_init (%.loc7_48.3), %a.var [template = constants.%struct.2]
// CHECK:STDOUT: %.loc7_49: init %Child = converted %.loc7_48.1, %.loc7_48.4 [template = constants.%struct.2]
// CHECK:STDOUT: assign %a.var, %.loc7_49
// CHECK:STDOUT: %a.ref.loc8: ref %Child = name_ref a, %a
// CHECK:STDOUT: %x.ref: %.13 = name_ref x, imports.%import_ref.6 [template = imports.%.1]
// CHECK:STDOUT: %.loc8_4.1: ref %Base = class_element_access %a.ref.loc8, element0
// CHECK:STDOUT: %.loc8_4.2: ref %Base = converted %a.ref.loc8, %.loc8_4.1
// CHECK:STDOUT: %.loc8_4.3: ref i32 = class_element_access %.loc8_4.2, element0
// CHECK:STDOUT: %.loc8_9: i32 = int_value 2 [template = constants.%.14]
// CHECK:STDOUT: assign %.loc8_4.3, %.loc8_9
// CHECK:STDOUT: %a.ref.loc9: ref %Child = name_ref a, %a
// CHECK:STDOUT: %F.ref: %F.type = name_ref F, imports.%import_ref.4 [template = constants.%F]
// CHECK:STDOUT: %.loc9_4: <bound method> = bound_method %a.ref.loc9, %F.ref
// CHECK:STDOUT: %.loc9_3.1: ref %Base = class_element_access %a.ref.loc9, element0
// CHECK:STDOUT: %.loc9_3.2: ref %Base = converted %a.ref.loc9, %.loc9_3.1
// CHECK:STDOUT: %.loc9_3.3: %Base = bind_value %.loc9_3.2
// CHECK:STDOUT: %F.call: init %.1 = call %.loc9_4(%.loc9_3.3)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F[%self.param_patt: %Base]();
// CHECK:STDOUT: