Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

element index init with vptr #4565

Open
wants to merge 2 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions toolchain/check/convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,16 @@ static auto ConvertAggregateElement(
SemIR::TypeId src_elem_type,
llvm::ArrayRef<SemIR::InstId> src_literal_elems,
ConversionTarget::Kind kind, SemIR::InstId target_id,
SemIR::TypeId target_elem_type, PendingBlock* target_block, size_t i) {
SemIR::TypeId target_elem_type, PendingBlock* target_block,
size_t src_field_index, size_t dest_field_index) {
// Compute the location of the source element. This goes into the current code
// block, not into the target block.
// TODO: Ideally we would discard this instruction if it's unused.
auto src_elem_id =
!src_literal_elems.empty()
? src_literal_elems[i]
: MakeElementAccessInst<SourceAccessInstT>(context, loc_id, src_id,
src_elem_type, context, i);
auto src_elem_id = !src_literal_elems.empty()
? src_literal_elems[src_field_index]
: MakeElementAccessInst<SourceAccessInstT>(
context, loc_id, src_id, src_elem_type, context,
src_field_index);

// If we're performing a conversion rather than an initialization, we won't
// have or need a target.
Expand All @@ -204,7 +205,8 @@ static auto ConvertAggregateElement(
PendingBlock::DiscardUnusedInstsScope scope(target_block);
target.init_block = target_block;
target.init_id = MakeElementAccessInst<TargetAccessInstT>(
context, loc_id, target_id, target_elem_type, *target_block, i);
context, loc_id, target_id, target_elem_type, *target_block,
dest_field_index);
return Convert(context, loc_id, src_elem_id, target);
}

Expand Down Expand Up @@ -275,7 +277,7 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type,
ConvertAggregateElement<SemIR::TupleAccess, SemIR::ArrayIndex>(
context, value_loc_id, value_id, src_type_id, literal_elems,
ConversionTarget::FullInitializer, return_slot_id,
array_type.element_type_id, target_block, i);
array_type.element_type_id, target_block, i, i);
if (init_id == SemIR::InstId::BuiltinErrorInst) {
return SemIR::InstId::BuiltinErrorInst;
}
Expand Down Expand Up @@ -356,7 +358,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
auto init_id =
ConvertAggregateElement<SemIR::TupleAccess, SemIR::TupleAccess>(
context, value_loc_id, value_id, src_type_id, literal_elems,
inner_kind, target.init_id, dest_type_id, target.init_block, i);
inner_kind, target.init_id, dest_type_id, target.init_block, i, i);
if (init_id == SemIR::InstId::BuiltinErrorInst) {
return SemIR::InstId::BuiltinErrorInst;
}
Expand Down Expand Up @@ -496,7 +498,7 @@ static auto ConvertStructToStructOrClass(Context& context,
ConvertAggregateElement<SemIR::StructAccess, TargetAccessInstT>(
context, value_loc_id, value_id, src_field.type_id, literal_elems,
inner_kind, target.init_id, dest_field.type_id, target.init_block,
src_field_index);
src_field_index, src_field_index + dest_has_vptr);
if (init_id == SemIR::InstId::BuiltinErrorInst) {
return SemIR::InstId::BuiltinErrorInst;
}
Expand Down
116 changes: 116 additions & 0 deletions toolchain/check/testdata/class/virtual_modifiers.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ fn F() {
var v: Modifiers.Base = {};
}

// --- init_members.carbon

package InitMembers;

base class Base {
virtual fn F();
var m1: i32;
var m2: i32;
}

fn F() {
var v: Base = {.m2 = 3, .m1 = 5};
}

// CHECK:STDOUT: --- modifiers.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
Expand Down Expand Up @@ -235,3 +249,105 @@ fn F() {
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- init_members.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Base: type = class_type @Base [template]
// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template]
// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template]
// CHECK:STDOUT: %.1: Core.IntLiteral = int_value 32 [template]
// CHECK:STDOUT: %Int.type: type = fn_type @Int [template]
// CHECK:STDOUT: %Int: %Int.type = struct_value () [template]
// CHECK:STDOUT: %i32: type = int_type signed, %.1 [template]
// CHECK:STDOUT: %.2: type = unbound_element_type %Base, %i32 [template]
// CHECK:STDOUT: %.3: type = ptr_type <vtable> [template]
// CHECK:STDOUT: %.4: type = struct_type {.<vptr>: %.3, .m1: %i32, .m2: %i32} [template]
// CHECK:STDOUT: %.5: <witness> = complete_type_witness %.4 [template]
// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template]
// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template]
// CHECK:STDOUT: %.7: Core.IntLiteral = int_value 3 [template]
// CHECK:STDOUT: %.8: Core.IntLiteral = int_value 5 [template]
// CHECK:STDOUT: %.9: type = struct_type {.m2: Core.IntLiteral, .m1: Core.IntLiteral} [template]
// CHECK:STDOUT: %Convert.type.2: type = fn_type @Convert.1, @ImplicitAs(%i32) [template]
// CHECK:STDOUT: %Convert.type.14: type = fn_type @Convert.2, @impl.1(%.1) [template]
// CHECK:STDOUT: %Convert.14: %Convert.type.14 = struct_value () [template]
// CHECK:STDOUT: %.29: <witness> = interface_witness (%Convert.14) [template]
// CHECK:STDOUT: %.30: <bound method> = bound_method %.8, %Convert.14 [template]
// CHECK:STDOUT: %.31: <specific function> = specific_function %.30, @Convert.2(%.1) [template]
// CHECK:STDOUT: %.32: %i32 = int_value 5 [template]
// CHECK:STDOUT: %.33: <bound method> = bound_method %.7, %Convert.14 [template]
// CHECK:STDOUT: %.34: <specific function> = specific_function %.33, @Convert.2(%.1) [template]
// CHECK:STDOUT: %.35: %i32 = int_value 3 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Core: <namespace> = namespace file.%Core.import, [template] {
// CHECK:STDOUT: .Int = %import_ref.1
// CHECK:STDOUT: .ImplicitAs = %import_ref.2
// 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: .Base = %Base.decl
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core.import = import Core
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [template = constants.%Base] {} {}
// CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Base {
// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {}
// CHECK:STDOUT: %.loc6_11.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
// CHECK:STDOUT: %int.make_type_signed.loc6: init type = call constants.%Int(%.loc6_11.1) [template = constants.%i32]
// CHECK:STDOUT: %.loc6_11.2: type = value_of_initializer %int.make_type_signed.loc6 [template = constants.%i32]
// CHECK:STDOUT: %.loc6_11.3: type = converted %int.make_type_signed.loc6, %.loc6_11.2 [template = constants.%i32]
// CHECK:STDOUT: %.loc6_9: %.2 = field_decl m1, element0 [template]
// CHECK:STDOUT: %.loc7_11.1: Core.IntLiteral = int_value 32 [template = constants.%.1]
// CHECK:STDOUT: %int.make_type_signed.loc7: init type = call constants.%Int(%.loc7_11.1) [template = constants.%i32]
// CHECK:STDOUT: %.loc7_11.2: type = value_of_initializer %int.make_type_signed.loc7 [template = constants.%i32]
// CHECK:STDOUT: %.loc7_11.3: type = converted %int.make_type_signed.loc7, %.loc7_11.2 [template = constants.%i32]
// CHECK:STDOUT: %.loc7_9: %.2 = field_decl m2, element1 [template]
// CHECK:STDOUT: %.loc8: <witness> = complete_type_witness %.4 [template = constants.%.5]
// CHECK:STDOUT:
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%Base
// CHECK:STDOUT: .F = %F.decl
// CHECK:STDOUT: .m1 = %.loc6_9
// CHECK:STDOUT: .m2 = %.loc7_9
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: virtual fn @F.1();
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F.2() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Base.ref: type = name_ref Base, file.%Base.decl [template = constants.%Base]
// CHECK:STDOUT: %v.var: ref %Base = var v
// CHECK:STDOUT: %v: ref %Base = bind_name v, %v.var
// CHECK:STDOUT: %.loc11_24: Core.IntLiteral = int_value 3 [template = constants.%.7]
// CHECK:STDOUT: %.loc11_33: Core.IntLiteral = int_value 5 [template = constants.%.8]
// CHECK:STDOUT: %.loc11_34.1: %.9 = struct_literal (%.loc11_24, %.loc11_33)
// CHECK:STDOUT: %.loc11_34.2: %Convert.type.2 = interface_witness_access constants.%.29, element0 [template = constants.%Convert.14]
// CHECK:STDOUT: %.loc11_34.3: <bound method> = bound_method %.loc11_33, %.loc11_34.2 [template = constants.%.30]
// CHECK:STDOUT: %.loc11_34.4: <specific function> = specific_function %.loc11_34.3, @Convert.2(constants.%.1) [template = constants.%.31]
// CHECK:STDOUT: %int.convert_checked.loc11_34.1: init %i32 = call %.loc11_34.4(%.loc11_33) [template = constants.%.32]
// CHECK:STDOUT: %.loc11_34.5: init %i32 = converted %.loc11_33, %int.convert_checked.loc11_34.1 [template = constants.%.32]
// CHECK:STDOUT: %.loc11_34.6: ref %i32 = class_element_access %v.var, element2
// CHECK:STDOUT: %.loc11_34.7: init %i32 = initialize_from %.loc11_34.5 to %.loc11_34.6 [template = constants.%.32]
// CHECK:STDOUT: %.loc11_34.8: %Convert.type.2 = interface_witness_access constants.%.29, element0 [template = constants.%Convert.14]
// CHECK:STDOUT: %.loc11_34.9: <bound method> = bound_method %.loc11_24, %.loc11_34.8 [template = constants.%.33]
// CHECK:STDOUT: %.loc11_34.10: <specific function> = specific_function %.loc11_34.9, @Convert.2(constants.%.1) [template = constants.%.34]
// CHECK:STDOUT: %int.convert_checked.loc11_34.2: init %i32 = call %.loc11_34.10(%.loc11_24) [template = constants.%.35]
// CHECK:STDOUT: %.loc11_34.11: init %i32 = converted %.loc11_24, %int.convert_checked.loc11_34.2 [template = constants.%.35]
// CHECK:STDOUT: %.loc11_34.12: ref %i32 = class_element_access %v.var, element1
// CHECK:STDOUT: %.loc11_34.13: init %i32 = initialize_from %.loc11_34.11 to %.loc11_34.12 [template = constants.%.35]
// CHECK:STDOUT: %.loc11_34.14: init %Base = class_init (<error>, %.loc11_34.7, %.loc11_34.13), %v.var [template = <error>]
// CHECK:STDOUT: %.loc11_35: init %Base = converted %.loc11_34.1, %.loc11_34.14 [template = <error>]
// CHECK:STDOUT: assign %v.var, %.loc11_35
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT: