diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp index 5d2dbfebe8e7..c63dc3d49433 100644 --- a/toolchain/check/call.cpp +++ b/toolchain/check/call.cpp @@ -12,12 +12,35 @@ namespace Carbon::Check { +// Performs a call where the callee is the name of a generic class, such as +// `Vector(i32)`. +static auto PerformCallToGenericClass(Context& context, Parse::NodeId node_id, + SemIR::ClassId class_id, + llvm::ArrayRef arg_ids) + -> SemIR::InstId { + auto& class_info = context.classes().Get(class_id); + + // Convert the arguments to match the parameters. + auto converted_args_id = ConvertCallArgs( + context, node_id, /*self_id=*/SemIR::InstId::Invalid, arg_ids, + /*return_storage_id=*/SemIR::InstId::Invalid, class_info.decl_id, + class_info.implicit_param_refs_id, class_info.param_refs_id); + return context.AddInst( + {node_id, + SemIR::ClassType{SemIR::TypeId::TypeType, class_id, converted_args_id}}); +} + auto PerformCall(Context& context, Parse::NodeId node_id, SemIR::InstId callee_id, llvm::ArrayRef arg_ids) -> SemIR::InstId { // Identify the function we're calling. auto callee_function = GetCalleeFunction(context.sem_ir(), callee_id); if (!callee_function.function_id.is_valid()) { + if (auto generic_class = context.types().TryGetAs( + context.insts().Get(callee_id).type_id())) { + return PerformCallToGenericClass(context, node_id, + generic_class->class_id, arg_ids); + } if (!callee_function.is_error) { CARBON_DIAGNOSTIC(CallToNonCallable, Error, "Value of type `{0}` is not callable.", SemIR::TypeId); diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index fc0c334c339b..4c588e7e1edc 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -1158,8 +1158,9 @@ auto ConvertCallArgs(Context& context, SemIR::LocId call_loc_id, SemIR::InstId return_storage_id, SemIR::InstId callee_id, SemIR::InstBlockId implicit_param_refs_id, SemIR::InstBlockId param_refs_id) -> SemIR::InstBlockId { - auto implicit_param_refs = context.inst_blocks().Get(implicit_param_refs_id); - auto param_refs = context.inst_blocks().Get(param_refs_id); + auto implicit_param_refs = + context.inst_blocks().GetOrEmpty(implicit_param_refs_id); + auto param_refs = context.inst_blocks().GetOrEmpty(param_refs_id); // If sizes mismatch, fail early. if (arg_refs.size() != param_refs.size()) { diff --git a/toolchain/check/testdata/class/generic/call.carbon b/toolchain/check/testdata/class/generic/call.carbon new file mode 100644 index 000000000000..4d3cd46eea3a --- /dev/null +++ b/toolchain/check/testdata/class/generic/call.carbon @@ -0,0 +1,236 @@ +// 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 + +// --- call.carbon + +library "call" api; + +class Class(T:! type, N:! i32) {} + +var a: Class(i32*, 5); + +// Requires an implicit conversion to type `type`. +var b: Class((), 0); + +// --- fail_too_few.carbon + +library "too_few" api; + +class Class(T:! type, N:! i32) {} + +// CHECK:STDERR: fail_too_few.carbon:[[@LINE+7]]:8: ERROR: 1 argument(s) passed to function expecting 2 argument(s). +// CHECK:STDERR: var a: Class(i32*); +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: fail_too_few.carbon:[[@LINE-5]]:1: Calling function declared here. +// CHECK:STDERR: class Class(T:! type, N:! i32) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +var a: Class(i32*); + +// --- fail_too_many.carbon + +library "too_many" api; + +class Class(T:! type, N:! i32) {} + +// CHECK:STDERR: fail_too_many.carbon:[[@LINE+7]]:8: ERROR: 3 argument(s) passed to function expecting 2 argument(s). +// CHECK:STDERR: var a: Class(i32*, 1, 2); +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: fail_too_many.carbon:[[@LINE-5]]:1: Calling function declared here. +// CHECK:STDERR: class Class(T:! type, N:! i32) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +var a: Class(i32*, 1, 2); + +// --- fail_no_conversion.carbon + +library "no_conversion" api; + +class Class(T:! type, N:! i32) {} + +// CHECK:STDERR: fail_no_conversion.carbon:[[@LINE+6]]:8: ERROR: Cannot implicitly convert from `i32` to `type`. +// CHECK:STDERR: var a: Class(5, i32*); +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: fail_no_conversion.carbon:[[@LINE-5]]:1: Initializing parameter 1 of function declared here. +// CHECK:STDERR: class Class(T:! type, N:! i32) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a: Class(5, i32*); + +// CHECK:STDOUT: --- call.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: type = ptr_type i32 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 5 [template] +// CHECK:STDOUT: %Class.3: type = class_type @Class, (file.%.loc6_17, file.%.loc6_20) [template] +// CHECK:STDOUT: %.5: type = ptr_type {} [template] +// CHECK:STDOUT: %.6: i32 = int_literal 0 [template] +// CHECK:STDOUT: %Class.4: type = class_type @Class, (file.%.loc9_13, file.%.loc9_18) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: .b = %b +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct] { +// CHECK:STDOUT: %T.loc4_13.1: type = param T +// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc4_23.1: i32 = param N +// CHECK:STDOUT: %N.loc4_23.2: i32 = bind_symbolic_name N 1, %N.loc4_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Class.ref.loc6: Class = name_ref Class, %Class.decl [template = constants.%struct] +// CHECK:STDOUT: %.loc6_17: type = ptr_type i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc6_20: i32 = int_literal 5 [template = constants.%.4] +// CHECK:STDOUT: %Class.loc6: type = class_type @Class, (%.loc6_17, %.loc6_20) [template = constants.%Class.3] +// CHECK:STDOUT: %a.var: ref Class = var a +// CHECK:STDOUT: %a: ref Class = bind_name a, %a.var +// CHECK:STDOUT: %Class.ref.loc9: Class = name_ref Class, %Class.decl [template = constants.%struct] +// CHECK:STDOUT: %.loc9_15: () = tuple_literal () +// CHECK:STDOUT: %.loc9_18: i32 = int_literal 0 [template = constants.%.6] +// CHECK:STDOUT: %.loc9_13: type = converted %.loc9_15, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %Class.loc9: type = class_type @Class, (%.loc9_13, %.loc9_18) [template = constants.%Class.4] +// CHECK:STDOUT: %b.var: ref Class = var b +// CHECK:STDOUT: %b: ref Class = bind_name b, %b.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_too_few.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: type = ptr_type i32 [template] +// CHECK:STDOUT: %.4: type = ptr_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct] { +// CHECK:STDOUT: %T.loc4_13.1: type = param T +// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc4_23.1: i32 = param N +// CHECK:STDOUT: %N.loc4_23.2: i32 = bind_symbolic_name N 1, %N.loc4_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Class.ref: Class = name_ref Class, %Class.decl [template = constants.%struct] +// CHECK:STDOUT: %.loc13: type = ptr_type i32 [template = constants.%.3] +// CHECK:STDOUT: %Class: type = class_type @Class [template = constants.%Class.2] +// CHECK:STDOUT: %a.var: ref Class = var a +// CHECK:STDOUT: %a: ref Class = bind_name a, %a.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_too_many.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: type = ptr_type i32 [template] +// CHECK:STDOUT: %.4: i32 = int_literal 1 [template] +// CHECK:STDOUT: %.5: i32 = int_literal 2 [template] +// CHECK:STDOUT: %.6: type = ptr_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct] { +// CHECK:STDOUT: %T.loc4_13.1: type = param T +// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc4_23.1: i32 = param N +// CHECK:STDOUT: %N.loc4_23.2: i32 = bind_symbolic_name N 1, %N.loc4_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Class.ref: Class = name_ref Class, %Class.decl [template = constants.%struct] +// CHECK:STDOUT: %.loc13_17: type = ptr_type i32 [template = constants.%.3] +// CHECK:STDOUT: %.loc13_20: i32 = int_literal 1 [template = constants.%.4] +// CHECK:STDOUT: %.loc13_23: i32 = int_literal 2 [template = constants.%.5] +// CHECK:STDOUT: %Class: type = class_type @Class [template = constants.%Class.2] +// CHECK:STDOUT: %a.var: ref Class = var a +// CHECK:STDOUT: %a: ref Class = bind_name a, %a.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_no_conversion.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: i32 = int_literal 5 [template] +// CHECK:STDOUT: %.4: type = ptr_type i32 [template] +// CHECK:STDOUT: %.5: type = ptr_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: .a = %a +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct] { +// CHECK:STDOUT: %T.loc4_13.1: type = param T +// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc4_23.1: i32 = param N +// CHECK:STDOUT: %N.loc4_23.2: i32 = bind_symbolic_name N 1, %N.loc4_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Class.ref: Class = name_ref Class, %Class.decl [template = constants.%struct] +// CHECK:STDOUT: %.loc12_14: i32 = int_literal 5 [template = constants.%.3] +// CHECK:STDOUT: %.loc12_20: type = ptr_type i32 [template = constants.%.4] +// CHECK:STDOUT: %Class: type = class_type @Class [template = constants.%Class.2] +// CHECK:STDOUT: %a.var: ref Class = var a +// CHECK:STDOUT: %a: ref Class = bind_name a, %a.var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/fail_todo_use.carbon b/toolchain/check/testdata/class/generic/fail_todo_use.carbon index ad39ef7668b8..11d608997829 100644 --- a/toolchain/check/testdata/class/generic/fail_todo_use.carbon +++ b/toolchain/check/testdata/class/generic/fail_todo_use.carbon @@ -14,10 +14,21 @@ class Class(T:! type) { // TODO: The following should work. fn Run() -> i32 { - // CHECK:STDERR: fail_todo_use.carbon:[[@LINE+3]]:10: ERROR: Value of type `Class` is not callable. + // CHECK:STDERR: fail_todo_use.carbon:[[@LINE+4]]:23: ERROR: Cannot implicitly convert from `i32` to `T`. // CHECK:STDERR: var v: Class(i32) = {.k = 0}; - // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: var v: Class(i32) = {.k = 0}; + // CHECK:STDERR: fail_todo_use.carbon:[[@LINE+10]]:3: ERROR: Cannot implicitly convert from `T*` to `i32`. + // CHECK:STDERR: return v.Get(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_use.carbon:[[@LINE+6]]:10: ERROR: Cannot implicitly convert from `Class*` to `Class*`. + // CHECK:STDERR: return v.Get(); + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_todo_use.carbon:[[@LINE-21]]:15: Initializing `addr self` parameter of method declared here. + // CHECK:STDERR: fn Get[addr self: Self*]() -> T* { + // CHECK:STDERR: ^~~~ return v.Get(); } @@ -38,8 +49,10 @@ fn Run() -> i32 { // CHECK:STDOUT: %.6: type = ptr_type {.k: T} [symbolic] // CHECK:STDOUT: %Run: type = fn_type @Run [template] // CHECK:STDOUT: %struct.3: Run = struct_value () [template] +// CHECK:STDOUT: %Class.3: type = class_type @Class, (i32) [template] // CHECK:STDOUT: %.7: i32 = int_literal 0 [template] // CHECK:STDOUT: %.8: type = struct_type {.k: i32} [template] +// CHECK:STDOUT: %.9: type = ptr_type Class [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -91,12 +104,17 @@ fn Run() -> i32 { // CHECK:STDOUT: fn @Run() -> i32 { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Class.ref: Class = name_ref Class, file.%Class.decl [template = constants.%struct.1] -// CHECK:STDOUT: %v.var: ref = var v -// CHECK:STDOUT: %v: ref = bind_name v, %v.var -// CHECK:STDOUT: %.loc20_29: i32 = int_literal 0 [template = constants.%.7] -// CHECK:STDOUT: %.loc20_30: {.k: i32} = struct_literal (%.loc20_29) +// CHECK:STDOUT: %Class: type = class_type @Class, (i32) [template = constants.%Class.3] +// CHECK:STDOUT: %v.var: ref Class = var v +// CHECK:STDOUT: %v: ref Class = bind_name v, %v.var +// CHECK:STDOUT: %.loc21_29: i32 = int_literal 0 [template = constants.%.7] +// CHECK:STDOUT: %.loc21_30: {.k: i32} = struct_literal (%.loc21_29) // CHECK:STDOUT: assign %v.var, -// CHECK:STDOUT: %v.ref: ref = name_ref v, %v +// CHECK:STDOUT: %v.ref: ref Class = name_ref v, %v +// CHECK:STDOUT: %Get.ref: Get = name_ref Get, @Class.%Get.decl [template = constants.%struct.2] +// CHECK:STDOUT: %.loc32_11: = bound_method %v.ref, %Get.ref +// CHECK:STDOUT: %.loc32_10: Class* = addr_of %v.ref +// CHECK:STDOUT: %Get.call: init T* = call %.loc32_11() [template = ] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 16029d593431..f5edafa7e5d1 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -604,6 +604,14 @@ class Formatter { FormatTrailingBlock(inst.decl_block_id); } + auto FormatInstructionRHS(ClassType inst) -> void { + if (inst.args_id.is_valid()) { + FormatArgs(inst.class_id, inst.args_id); + } else { + FormatArgs(inst.class_id); + } + } + auto FormatInstructionRHS(ImplDecl inst) -> void { FormatArgs(inst.impl_id); FormatTrailingBlock(inst.decl_block_id); diff --git a/toolchain/sem_ir/inst.h b/toolchain/sem_ir/inst.h index 28bb3a5dc4c4..7cdcf78391b0 100644 --- a/toolchain/sem_ir/inst.h +++ b/toolchain/sem_ir/inst.h @@ -437,6 +437,12 @@ class InstBlockStore : public BlockValueStore { CARBON_CHECK(block_id != InstBlockId::Unreachable); BlockValueStore::Set(block_id, content); } + + // Returns the contents of the specified block, or an empty array if the block + // is empty. + auto GetOrEmpty(InstBlockId block_id) -> llvm::ArrayRef { + return block_id.is_valid() ? Get(block_id) : llvm::ArrayRef(); + } }; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/inst_profile.cpp b/toolchain/sem_ir/inst_profile.cpp index 4e2e34f73c35..86006c2b51ec 100644 --- a/toolchain/sem_ir/inst_profile.cpp +++ b/toolchain/sem_ir/inst_profile.cpp @@ -35,7 +35,15 @@ static auto DefaultProfileArgFunction(llvm::FoldingSetNodeID& id, static auto InstBlockProfileArgFunction(llvm::FoldingSetNodeID& id, const File& sem_ir, int32_t arg) -> void { - for (auto inst_id : sem_ir.inst_blocks().Get(InstBlockId(arg))) { + auto inst_block_id = InstBlockId(arg); + if (!inst_block_id.is_valid()) { + id.AddInteger(-1); + return; + } + + auto inst_block = sem_ir.inst_blocks().Get(inst_block_id); + id.AddInteger(inst_block.size()); + for (auto inst_id : inst_block) { id.AddInteger(inst_id.index); } } @@ -45,7 +53,15 @@ static auto InstBlockProfileArgFunction(llvm::FoldingSetNodeID& id, static auto TypeBlockProfileArgFunction(llvm::FoldingSetNodeID& id, const File& sem_ir, int32_t arg) -> void { - for (auto type_id : sem_ir.type_blocks().Get(TypeBlockId(arg))) { + auto type_block_id = TypeBlockId(arg); + if (!type_block_id.is_valid()) { + id.AddInteger(-1); + return; + } + + auto type_block = sem_ir.type_blocks().Get(type_block_id); + id.AddInteger(type_block.size()); + for (auto type_id : type_block) { id.AddInteger(type_id.index); } } diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index a6817d183e4e..d36f0ec24b27 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -402,11 +402,11 @@ struct ClassInit { struct ClassType { static constexpr auto Kind = - InstKind::ClassType.Define("class_type"); + InstKind::ClassType.Define("class_type"); TypeId type_id; ClassId class_id; - // TODO: Once we support generic classes, include the class's arguments here. + InstBlockId args_id = InstBlockId::Invalid; }; struct ConstType {