From 7c966c2d59b462550706457cfb5c1f7c5503f920 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Sep 2026 17:06:22 +0000 Subject: [PATCH] Initialize specifics in-place. (#7717) Don't wait until we reach the end of the eval block to set the value block on the specific. This is a prerequisite for allowing template actions to read from the specific. --- toolchain/check/eval.cpp | 96 ++++--------------- toolchain/check/eval.h | 7 +- toolchain/check/generic.cpp | 14 +-- .../testdata/basics/dump_sem_ir_ranges.carbon | 8 +- .../one_file_with_textual_ir.carbon | 9 +- ...uction_uses_runtime_type_conversion.carbon | 8 +- toolchain/check/testdata/for/basic.carbon | 4 +- toolchain/check/testdata/impl/compound.carbon | 4 +- .../testdata/impl/import_compound.carbon | 4 +- .../overloaded/index_with_prelude.carbon | 8 +- .../check/testdata/patterns/tuple.carbon | 16 ++-- .../check/testdata/var/var_pattern.carbon | 12 +-- toolchain/sem_ir/generic.cpp | 11 ++- toolchain/sem_ir/generic.h | 17 ++++ toolchain/sem_ir/inst.h | 3 +- 15 files changed, 89 insertions(+), 132 deletions(-) diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index a2fa201a0986..a2fde9b0eb1b 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -76,14 +76,11 @@ struct LocalEvalInfo { // `context` must not be null. class EvalContext { public: - explicit EvalContext( - Context* context, SemIR::LocId fallback_loc_id, - SemIR::SpecificId specific_id = SemIR::SpecificId::None, - std::optional specific_eval_info = std::nullopt) + explicit EvalContext(Context* context, SemIR::LocId fallback_loc_id, + SemIR::SpecificId specific_id = SemIR::SpecificId::None) : context_(context), fallback_loc_id_(fallback_loc_id), - specific_id_(specific_id), - specific_eval_info_(specific_eval_info) {} + specific_id_(specific_id) {} EvalContext(const EvalContext&) = delete; auto operator=(const EvalContext&) -> EvalContext& = delete; @@ -156,29 +153,6 @@ class EvalContext { return constant_values().Get(args[binding_index]); } - // Given information about a symbolic constant, determine its value in the - // currently-being-evaluated eval block, if it refers to that eval block. If - // we can't find a value in this way, returns `None`. - auto GetInEvaluatedSpecific(const SemIR::SymbolicConstant& symbolic_info) - -> SemIR::ConstantId { - if (!specific_eval_info_ || !symbolic_info.index.has_value()) { - return SemIR::ConstantId::None; - } - - CARBON_CHECK( - symbolic_info.generic_id == specifics().Get(specific_id_).generic_id, - "Instruction has constant operand in wrong generic"); - if (symbolic_info.index.region() != specific_eval_info_->region) { - return SemIR::ConstantId::None; - } - - auto inst_id = specific_eval_info_->values[symbolic_info.index.index()]; - if (!inst_id.has_value()) { - return SemIR::ConstantId::NotConstant; - } - return constant_values().Get(inst_id); - } - // Gets the constant value of the specified instruction in this context. auto GetConstantValue(SemIR::InstId inst_id) -> SemIR::ConstantId { auto const_id = constant_values().GetAttached(inst_id); @@ -194,41 +168,11 @@ class EvalContext { return const_id; } - if (!const_id.is_symbolic()) { - return const_id; - } - - // While resolving a specific, map from previous instructions in the eval - // block into their evaluated values. These values won't be present on the - // specific itself yet, so `GetConstantValueInSpecific` won't be able to - // find them. - const auto& symbolic_info = constant_values().GetSymbolicConstant(const_id); - if (auto eval_block_const_id = GetInEvaluatedSpecific(symbolic_info); - eval_block_const_id.has_value()) { - return eval_block_const_id; - } - return GetConstantValueInSpecific(sem_ir(), specific_id_, inst_id); } // Gets the type of the specified instruction in this context. auto GetTypeOfInst(SemIR::InstId inst_id) -> SemIR::TypeId { - auto type_id = insts().GetAttachedType(inst_id); - if (!type_id.is_symbolic()) { - return type_id; - } - - // While resolving a specific, map from previous instructions in the eval - // block into their evaluated values. These values won't be present on the - // specific itself yet, so `GetTypeOfInstInSpecific` won't be able to - // find them. - const auto& symbolic_info = - constant_values().GetSymbolicConstant(types().GetConstantId(type_id)); - if (auto eval_block_const_id = GetInEvaluatedSpecific(symbolic_info); - eval_block_const_id.has_value()) { - return types().GetTypeIdForTypeConstantId(eval_block_const_id); - } - return GetTypeOfInstInSpecific(sem_ir(), specific_id_, inst_id); } @@ -298,9 +242,6 @@ class EvalContext { SemIR::LocId fallback_loc_id_; // The specific that we are evaluating within. SemIR::SpecificId specific_id_; - // If we are currently evaluating an eval block for `specific_id_`, - // information about that evaluation. - std::optional specific_eval_info_; // If we are currently evaluating within a local scope, values of local // instructions that have already been evaluated. This is here rather than in // `FunctionEvalContext` so we can reference it from `GetConstantValue`. @@ -3511,20 +3452,23 @@ auto TryEvalInstUnsafe(Context& context, SemIR::InstId inst_id, auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, SemIR::SpecificId specific_id, - SemIR::GenericInstIndex::Region region) - -> std::pair { + SemIR::GenericInstIndex::Region region) -> void { auto generic_id = context.specifics().Get(specific_id).generic_id; auto eval_block_id = context.generics().Get(generic_id).GetEvalBlock(region); auto eval_block = context.inst_blocks().Get(eval_block_id); - llvm::SmallVector result; - result.resize(eval_block.size(), SemIR::InstId::None); + // Allocate the value block and store it back onto the specific, so that our + // in-progress results are visible. + auto& specific = context.specifics().Get(specific_id); + auto value_block_id = + context.inst_blocks().AddUninitialized(eval_block.size()); + auto value_block = context.inst_blocks().GetMutable(value_block_id); + for (auto& inst_id : value_block) { + inst_id = SemIR::InstId::None; + } + specific.SetValueBlock(region, value_block_id); - EvalContext eval_context(&context, loc_id, specific_id, - SpecificEvalInfo{ - .region = region, - .values = result, - }); + EvalContext eval_context(&context, loc_id, specific_id); Diagnostics::ContextScope diagnostic_context( &context.emitter(), [&](auto& builder) { @@ -3534,19 +3478,17 @@ auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, builder.Context(loc_id, ResolvingSpecificHere, specific_id); }); - bool has_error = false; - for (auto [i, inst_id] : llvm::enumerate(eval_block)) { + for (auto [i, inst_id, result_id] : + llvm::enumerate(eval_block, value_block)) { auto const_id = TryEvalInstInContext(eval_context, inst_id, context.insts().Get(inst_id)); CARBON_CHECK(const_id.has_value(), "Failed to evaluate {0} in eval block", context.insts().Get(inst_id)); if (const_id == SemIR::ErrorInst::ConstantId) { - has_error = true; + specific.SetHasError(region); } - result[i] = context.constant_values().GetInstId(const_id); + result_id = context.constant_values().GetInstId(const_id); } - - return {context.inst_blocks().Add(result), has_error}; } // Information about the function call we are currently executing. Unlike diff --git a/toolchain/check/eval.h b/toolchain/check/eval.h index 67430c184298..50c37ea7510e 100644 --- a/toolchain/check/eval.h +++ b/toolchain/check/eval.h @@ -50,13 +50,12 @@ auto TryEvalInst(Context& context, InstT inst) -> SemIR::ConstantId { return TryEvalInstUnsafe(context, SemIR::InstId::None, inst); } -// Evaluates the eval block for a region of a specific. Produces a block +// Evaluates the eval block for a region of a specific. Writes a block // containing the evaluated constant values of the instructions in the eval -// block. The returned bool indicates whether the region has an error. +// block to the specific. auto TryEvalBlockForSpecific(Context& context, SemIR::LocId loc_id, SemIR::SpecificId specific_id, - SemIR::GenericInstIndex::Region region) - -> std::pair; + SemIR::GenericInstIndex::Region region) -> void; } // namespace Carbon::Check diff --git a/toolchain/check/generic.cpp b/toolchain/check/generic.cpp index d951e0ee5fe1..63f013f36b73 100644 --- a/toolchain/check/generic.cpp +++ b/toolchain/check/generic.cpp @@ -681,12 +681,8 @@ auto ResolveSpecificDecl(Context& context, SemIR::LocId loc_id, // block to form information about the specific. auto& specific = context.specifics().Get(specific_id); if (!specific.decl_block_id.has_value()) { - // Set a placeholder value as the decl block ID so we won't attempt to - // recursively resolve the same specific. - specific.decl_block_id = SemIR::InstBlockId::Empty; - std::tie(specific.decl_block_id, specific.decl_block_has_error) = - TryEvalBlockForSpecific(context, loc_id, specific_id, - SemIR::GenericInstIndex::Region::Declaration); + TryEvalBlockForSpecific(context, loc_id, specific_id, + SemIR::GenericInstIndex::Region::Declaration); } } @@ -750,10 +746,8 @@ auto ResolveSpecificDefinition(Context& context, SemIR::LocId loc_id, // The generic is not defined yet. return false; } - std::tie(specific.definition_block_id, - specific.definition_block_has_error) = - TryEvalBlockForSpecific(context, loc_id, specific_id, - SemIR::GenericInstIndex::Definition); + TryEvalBlockForSpecific(context, loc_id, specific_id, + SemIR::GenericInstIndex::Definition); } return true; } diff --git a/toolchain/check/testdata/basics/dump_sem_ir_ranges.carbon b/toolchain/check/testdata/basics/dump_sem_ir_ranges.carbon index 7b2de78c9459..2bbfd7087087 100644 --- a/toolchain/check/testdata/basics/dump_sem_ir_ranges.carbon +++ b/toolchain/check/testdata/basics/dump_sem_ir_ranges.carbon @@ -234,13 +234,13 @@ library "[[@TEST_NAME]]"; // CHECK:STDOUT: %C.call: init %empty_tuple.type = call %C.ref() // CHECK:STDOUT: %.loc13_7.1: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc13_7.2: ref %empty_tuple.type = temporary %.loc13_7.1, %A.call -// CHECK:STDOUT: %tuple.loc13: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc13_7.3: %empty_tuple.type = converted %A.call, %tuple.loc13 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc13: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc13_7.3: %empty_tuple.type = converted %A.call, %empty_tuple.loc13 [concrete = constants.%empty_tuple] // CHECK:STDOUT: // CHECK:STDOUT: %.loc17_7.1: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc17_7.2: ref %empty_tuple.type = temporary %.loc17_7.1, %C.call -// CHECK:STDOUT: %tuple.loc17: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc17_7.3: %empty_tuple.type = converted %C.call, %tuple.loc17 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc17: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc17_7.3: %empty_tuple.type = converted %C.call, %empty_tuple.loc17 [concrete = constants.%empty_tuple] // CHECK:STDOUT: // CHECK:STDOUT: %Destroy.Op.bound.loc17: = bound_method %.loc17_7.2, constants.%Destroy.Op // CHECK:STDOUT: %Destroy.Op.call.loc17: init %empty_tuple.type = call %Destroy.Op.bound.loc17(%.loc17_7.2) diff --git a/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon b/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon index 1910e47dff3a..ed33ce22ed36 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon @@ -130,14 +130,14 @@ fn Foo(n: ()) -> ((), ()) { // CHECK:STDOUT: inst50000032: {kind: TupleLiteral, arg0: inst_block_empty, type: type(inst50000010)} // CHECK:STDOUT: inst50000033: {kind: TupleLiteral, arg0: inst_block50000010, type: type(inst5000001C)} // CHECK:STDOUT: inst50000034: {kind: TupleAccess, arg0: inst5000002C, arg1: element0, type: type(inst50000010)} -// CHECK:STDOUT: inst50000035: {kind: TupleInit, arg0: inst_block50000011, arg1: inst50000034, type: type(inst50000010)} +// CHECK:STDOUT: inst50000035: {kind: TupleInit, arg0: inst_block_empty, arg1: inst50000034, type: type(inst50000010)} // CHECK:STDOUT: inst50000036: {kind: Converted, arg0: inst50000031, arg1: inst50000035, type: type(inst50000010)} // CHECK:STDOUT: inst50000037: {kind: InPlaceInit, arg0: inst50000036, arg1: inst50000034, type: type(inst50000010)} // CHECK:STDOUT: inst50000038: {kind: TupleAccess, arg0: inst5000002C, arg1: element1, type: type(inst50000010)} // CHECK:STDOUT: inst50000039: {kind: TupleInit, arg0: inst_block_empty, arg1: inst50000038, type: type(inst50000010)} // CHECK:STDOUT: inst5000003A: {kind: Converted, arg0: inst50000032, arg1: inst50000039, type: type(inst50000010)} // CHECK:STDOUT: inst5000003B: {kind: InPlaceInit, arg0: inst5000003A, arg1: inst50000038, type: type(inst50000010)} -// CHECK:STDOUT: inst5000003C: {kind: TupleInit, arg0: inst_block50000012, arg1: inst5000002C, type: type(inst5000001C)} +// CHECK:STDOUT: inst5000003C: {kind: TupleInit, arg0: inst_block50000011, arg1: inst5000002C, type: type(inst5000001C)} // CHECK:STDOUT: inst5000003D: {kind: Converted, arg0: inst50000033, arg1: inst5000003C, type: type(inst5000001C)} // CHECK:STDOUT: inst5000003E: {kind: ReturnExpr, arg0: inst5000003D, arg1: inst5000002C} // CHECK:STDOUT: bundles: {} @@ -249,11 +249,10 @@ fn Foo(n: ()) -> ((), ()) { // CHECK:STDOUT: inst_block50000010: // CHECK:STDOUT: 0: inst50000031 // CHECK:STDOUT: 1: inst50000032 -// CHECK:STDOUT: inst_block50000011: {} -// CHECK:STDOUT: inst_block50000012: +// CHECK:STDOUT: inst_block50000011: // CHECK:STDOUT: 0: inst50000037 // CHECK:STDOUT: 1: inst5000003B -// CHECK:STDOUT: inst_block50000013: +// CHECK:STDOUT: inst_block50000012: // CHECK:STDOUT: 0: instF // CHECK:STDOUT: 1: inst5000002E // CHECK:STDOUT: value_stores: diff --git a/toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon b/toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon index e72451e3899f..a76cc1737400 100644 --- a/toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon +++ b/toolchain/check/testdata/facet/fail_deduction_uses_runtime_type_conversion.carbon @@ -188,8 +188,8 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, )), generic from: RuntimeConvertFrom // CHECK:STDOUT: %HoldsType.ref: %HoldsType.type = name_ref HoldsType, file.%HoldsType.decl [concrete = constants.%HoldsType.generic] // CHECK:STDOUT: %RuntimeConvertTo.ref: type = name_ref RuntimeConvertTo, file.%RuntimeConvertTo.decl [concrete = constants.%RuntimeConvertTo] // CHECK:STDOUT: %.loc29_45: %tuple.type = tuple_literal (%RuntimeConvertTo.ref) [concrete = constants.%tuple.162] -// CHECK:STDOUT: %tuple.loc29: %tuple.type = tuple_value (%RuntimeConvertTo.ref) [concrete = constants.%tuple.162] -// CHECK:STDOUT: %.loc29_46.2: %tuple.type = converted %.loc29_45, %tuple.loc29 [concrete = constants.%tuple.162] +// CHECK:STDOUT: %tuple: %tuple.type = tuple_value (%RuntimeConvertTo.ref) [concrete = constants.%tuple.162] +// CHECK:STDOUT: %.loc29_46.2: %tuple.type = converted %.loc29_45, %tuple [concrete = constants.%tuple.162] // CHECK:STDOUT: %HoldsType: type = class_type @HoldsType, @HoldsType(constants.%tuple.162) [concrete = constants.%HoldsType.9f2] // CHECK:STDOUT: } // CHECK:STDOUT: %holds_to: %HoldsType.9f2 = wrapper_binding holds_to, %holds_to.param @@ -307,8 +307,8 @@ fn G(holds_to: HoldsType((RuntimeConvertTo, )), generic from: RuntimeConvertFrom // CHECK:STDOUT: %.loc40_19.4: %RuntimeConvertTo = acquire_value %.loc40_19.3 // CHECK:STDOUT: %F.specific_fn: = specific_function %F.ref, @F(constants.%tuple.162, ) [concrete = ] // CHECK:STDOUT: %.loc40_19.5: %empty_tuple.type = call %F.specific_fn(%holds_to.ref) -// CHECK:STDOUT: %tuple.loc40: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc40_19.6: %empty_tuple.type = converted %.loc40_19.5, %tuple.loc40 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc40_19.6: %empty_tuple.type = converted %.loc40_19.5, %empty_tuple [concrete = constants.%empty_tuple] // CHECK:STDOUT: %Destroy.Op.bound: = bound_method %.loc40_19.3, constants.%Destroy.Op.1a2547.2 // CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %Destroy.Op.bound(%.loc40_19.3) // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/for/basic.carbon b/toolchain/check/testdata/for/basic.carbon index 0f61780cb57e..b294da1f83b9 100644 --- a/toolchain/check/testdata/for/basic.carbon +++ b/toolchain/check/testdata/for/basic.carbon @@ -167,8 +167,8 @@ fn Run() { // CHECK:STDOUT: %Optional.Get.call: init %empty_tuple.type = call %bound_method.loc18_35.4(%.loc18_35.8) // CHECK:STDOUT: %.loc18_35.9: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc18_35.10: ref %empty_tuple.type = temporary %.loc18_35.9, %Optional.Get.call -// CHECK:STDOUT: %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc18_35.11: %empty_tuple.type = converted %Optional.Get.call, %tuple [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc18_35.11: %empty_tuple.type = converted %Optional.Get.call, %empty_tuple [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc18_12.1: type = splice_block %.loc18_12.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc18_12.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc18_12.3: type = converted %.loc18_12.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] diff --git a/toolchain/check/testdata/impl/compound.carbon b/toolchain/check/testdata/impl/compound.carbon index c08a852b9eb8..ddcb75b6a82c 100644 --- a/toolchain/check/testdata/impl/compound.carbon +++ b/toolchain/check/testdata/impl/compound.carbon @@ -984,8 +984,8 @@ fn InstanceCallFail() { // CHECK:STDOUT: %impl.elem0: %.df4 = impl_witness_access constants.%Instance1.impl_witness, element0 [concrete = constants.%struct_type.d.as.Instance1.impl.G1] // CHECK:STDOUT: %bound_method: = bound_method %.loc16_4.1, %impl.elem0 // CHECK:STDOUT: %.loc16_4.2: ref %empty_tuple.type = struct_access %.loc16_4.1, element0 -// CHECK:STDOUT: %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc16_4.3: %empty_tuple.type = converted %.loc16_4.2, %tuple [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc16_4.3: %empty_tuple.type = converted %.loc16_4.2, %empty_tuple [concrete = constants.%empty_tuple] // CHECK:STDOUT: %struct: %struct_type.d = struct_value (%.loc16_4.3) [concrete = constants.%struct] // CHECK:STDOUT: %.loc16_4.4: %struct_type.d = converted %.loc16_4.1, %struct [concrete = constants.%struct] // CHECK:STDOUT: %struct_type.d.as.Instance1.impl.G1.call: init %empty_tuple.type = call %bound_method(%.loc16_4.4) diff --git a/toolchain/check/testdata/impl/import_compound.carbon b/toolchain/check/testdata/impl/import_compound.carbon index 83401112f0df..8513e7ef45d7 100644 --- a/toolchain/check/testdata/impl/import_compound.carbon +++ b/toolchain/check/testdata/impl/import_compound.carbon @@ -744,8 +744,8 @@ fn InstanceCallImportFail() { // CHECK:STDOUT: %impl.elem0: %.760 = impl_witness_access constants.%Instance.impl_witness, element0 [concrete = constants.%struct_type.i.as.Instance.impl.G] // CHECK:STDOUT: %bound_method: = bound_method %.loc10_4.1, %impl.elem0 // CHECK:STDOUT: %.loc10_4.2: ref %empty_tuple.type = struct_access %.loc10_4.1, element0 -// CHECK:STDOUT: %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc10_4.3: %empty_tuple.type = converted %.loc10_4.2, %tuple [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc10_4.3: %empty_tuple.type = converted %.loc10_4.2, %empty_tuple [concrete = constants.%empty_tuple] // CHECK:STDOUT: %struct: %struct_type.i = struct_value (%.loc10_4.3) [concrete = constants.%struct] // CHECK:STDOUT: %.loc10_4.4: %struct_type.i = converted %.loc10_4.1, %struct [concrete = constants.%struct] // CHECK:STDOUT: %struct_type.i.as.Instance.impl.G.call: init %empty_tuple.type = call %bound_method(%.loc10_4.4) diff --git a/toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon b/toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon index 19d3d5a57f6c..bfc7413f9dba 100644 --- a/toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon +++ b/toolchain/check/testdata/operators/overloaded/index_with_prelude.carbon @@ -397,8 +397,8 @@ let x: i32 = c[0]; // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: %.loc8: = impl_self_witness @tuple.type.as.IndexWith.impl.%.loc8_11.2, @IndexWith, @IndexWith(Core.IntLiteral) [concrete = constants.%.291] -// CHECK:STDOUT: %tuple.loc14: %tuple.type.748 = tuple_value (@__global_init.%.loc14_21.2, @__global_init.%.loc14_30.2) [concrete = constants.%tuple.adf] -// CHECK:STDOUT: %.loc14_34: %tuple.type.748 = converted @__global_init.%.loc14_34, %tuple.loc14 [concrete = constants.%tuple.adf] +// CHECK:STDOUT: %tuple: %tuple.type.748 = tuple_value (@__global_init.%.loc14_21.2, @__global_init.%.loc14_30.2) [concrete = constants.%tuple.adf] +// CHECK:STDOUT: %.loc14_34: %tuple.type.748 = converted @__global_init.%.loc14_34, %tuple [concrete = constants.%tuple.adf] // CHECK:STDOUT: %.loc14_13.1: type = splice_block %.loc14_13.3 [concrete = constants.%tuple.type.748] { // CHECK:STDOUT: %C.ref.loc14_9: type = name_ref C, %C.decl [concrete = constants.%C] // CHECK:STDOUT: %C.ref.loc14_12: type = name_ref C, %C.decl [concrete = constants.%C] @@ -412,8 +412,8 @@ let x: i32 = c[0]; // CHECK:STDOUT: %.loc15_15.1: init %empty_tuple.type = as_compatible @__global_init.%tuple.type.as.IndexWith.impl.At.call // CHECK:STDOUT: %.loc15_15.2: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc15_15.3: ref %empty_tuple.type = temporary %.loc15_15.2, %.loc15_15.1 -// CHECK:STDOUT: %tuple.loc15: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4] -// CHECK:STDOUT: %.loc15_15.4: %C = as_compatible %tuple.loc15 [concrete = constants.%empty_tuple.4db] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple.af4] +// CHECK:STDOUT: %.loc15_15.4: %C = as_compatible %empty_tuple [concrete = constants.%empty_tuple.4db] // CHECK:STDOUT: %.loc15_15.5: %C = converted @__global_init.%tuple.type.as.IndexWith.impl.At.call, %.loc15_15.4 [concrete = constants.%empty_tuple.4db] // CHECK:STDOUT: %C.ref.loc15: type = name_ref C, %C.decl [concrete = constants.%C] // CHECK:STDOUT: %e: %C = wrapper_binding e, %.loc15_15.5 diff --git a/toolchain/check/testdata/patterns/tuple.carbon b/toolchain/check/testdata/patterns/tuple.carbon index c4632ed1843d..851ac220285a 100644 --- a/toolchain/check/testdata/patterns/tuple.carbon +++ b/toolchain/check/testdata/patterns/tuple.carbon @@ -121,15 +121,15 @@ let (((b: ()),)) = ((),); // CHECK:STDOUT: %.loc7_24.1: ref %tuple.type = temporary @__global_init.%.loc7, @__global_init.%F.call // CHECK:STDOUT: %tuple.elem0: ref %empty_tuple.type = tuple_access %.loc7_24.1, element0 // CHECK:STDOUT: %tuple.elem1: ref %empty_tuple.type = tuple_access %.loc7_24.1, element1 -// CHECK:STDOUT: %tuple.loc7_24.1: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc7_24.2: %empty_tuple.type = converted %tuple.elem0, %tuple.loc7_24.1 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc7_24.1: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc7_24.2: %empty_tuple.type = converted %tuple.elem0, %empty_tuple.loc7_24.1 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc7_10.1: type = splice_block %.loc7_10.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc7_10.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc7_10.3: type = converted %.loc7_10.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] // CHECK:STDOUT: } // CHECK:STDOUT: %a: %empty_tuple.type = wrapper_binding a, %.loc7_24.2 -// CHECK:STDOUT: %tuple.loc7_24.2: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc7_24.3: %empty_tuple.type = converted %tuple.elem1, %tuple.loc7_24.2 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc7_24.2: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc7_24.3: %empty_tuple.type = converted %tuple.elem1, %empty_tuple.loc7_24.2 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc7_17.1: type = splice_block %.loc7_17.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc7_17.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc7_17.3: type = converted %.loc7_17.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] @@ -168,15 +168,15 @@ let (((b: ()),)) = ((),); // CHECK:STDOUT: file { // CHECK:STDOUT: %tuple.elem0: ref %empty_tuple.type = tuple_access @__global_init.%t.ref, element0 [concrete = constants.%tuple.elem0] // CHECK:STDOUT: %tuple.elem1: ref %empty_tuple.type = tuple_access @__global_init.%t.ref, element1 [concrete = constants.%tuple.elem1] -// CHECK:STDOUT: %tuple.loc6_22.1: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc6_22.1: %empty_tuple.type = converted %tuple.elem0, %tuple.loc6_22.1 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc6_22.1: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc6_22.1: %empty_tuple.type = converted %tuple.elem0, %empty_tuple.loc6_22.1 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc6_10.1: type = splice_block %.loc6_10.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc6_10.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc6_10.3: type = converted %.loc6_10.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] // CHECK:STDOUT: } // CHECK:STDOUT: %a: %empty_tuple.type = wrapper_binding a, %.loc6_22.1 -// CHECK:STDOUT: %tuple.loc6_22.2: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc6_22.2: %empty_tuple.type = converted %tuple.elem1, %tuple.loc6_22.2 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc6_22.2: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc6_22.2: %empty_tuple.type = converted %tuple.elem1, %empty_tuple.loc6_22.2 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc6_17.1: type = splice_block %.loc6_17.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc6_17.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc6_17.3: type = converted %.loc6_17.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] diff --git a/toolchain/check/testdata/var/var_pattern.carbon b/toolchain/check/testdata/var/var_pattern.carbon index 5568f71e36f5..b59fab70449b 100644 --- a/toolchain/check/testdata/var/var_pattern.carbon +++ b/toolchain/check/testdata/var/var_pattern.carbon @@ -555,8 +555,8 @@ fn Call() { // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F] // CHECK:STDOUT: %v.ref: ref %empty_tuple.type = name_ref v, %v // CHECK:STDOUT: %.loc8_9.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc8_5: %empty_tuple.type = converted %v.ref, %tuple [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc8_5: %empty_tuple.type = converted %v.ref, %empty_tuple [concrete = constants.%empty_tuple] // CHECK:STDOUT: %y.var: ref %empty_tuple.type = var_storage @F.%y.param_patt // CHECK:STDOUT: %.loc8_9.2: init %empty_tuple.type = tuple_init () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc4: init %empty_tuple.type = converted %.loc8_9.1, %.loc8_9.2 [concrete = constants.%empty_tuple] @@ -911,8 +911,8 @@ fn Call() { // CHECK:STDOUT: %.loc8_70: %tuple.type = tuple_literal (%F.call.loc8_59, %F.call.loc8_64, %F.call.loc8_69) // CHECK:STDOUT: %.loc8_59.1: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc8_59.2: ref %empty_tuple.type = temporary %.loc8_59.1, %F.call.loc8_59 -// CHECK:STDOUT: %tuple.loc8_59: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc8_59.3: %empty_tuple.type = converted %F.call.loc8_59, %tuple.loc8_59 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc8_59: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc8_59.3: %empty_tuple.type = converted %F.call.loc8_59, %empty_tuple.loc8_59 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc8_19.1: type = splice_block %.loc8_19.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc8_19.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc8_19.3: type = converted %.loc8_19.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] @@ -926,8 +926,8 @@ fn Call() { // CHECK:STDOUT: %y: ref %empty_tuple.type = wrapper_binding y, %y.var // CHECK:STDOUT: %.loc8_69.1: ref %empty_tuple.type = temporary_storage // CHECK:STDOUT: %.loc8_69.2: ref %empty_tuple.type = temporary %.loc8_69.1, %F.call.loc8_69 -// CHECK:STDOUT: %tuple.loc8_69: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] -// CHECK:STDOUT: %.loc8_69.3: %empty_tuple.type = converted %F.call.loc8_69, %tuple.loc8_69 [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %empty_tuple.loc8_69: %empty_tuple.type = tuple_value () [concrete = constants.%empty_tuple] +// CHECK:STDOUT: %.loc8_69.3: %empty_tuple.type = converted %F.call.loc8_69, %empty_tuple.loc8_69 [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc8_51.1: type = splice_block %.loc8_51.3 [concrete = constants.%empty_tuple.type] { // CHECK:STDOUT: %.loc8_51.2: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple] // CHECK:STDOUT: %.loc8_51.3: type = converted %.loc8_51.2, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] diff --git a/toolchain/sem_ir/generic.cpp b/toolchain/sem_ir/generic.cpp index c1a882fe5334..39916801e18e 100644 --- a/toolchain/sem_ir/generic.cpp +++ b/toolchain/sem_ir/generic.cpp @@ -99,9 +99,14 @@ static auto GetConstantInSpecific(const File& specific_ir, // specific. return {&const_ir, const_ir.constant_values().Get(symbolic.inst_id)}; } - return {&specific_ir, - specific_ir.constant_values().Get(specific_ir.inst_blocks().Get( - value_block_id)[symbolic.index.index()])}; + // TODO: Distinguish between parts of the instruction block that we've not + // reached yet during eval and values that evaluated successfully to + // ConstantId::NotConstant. + auto value_id = + specific_ir.inst_blocks().Get(value_block_id)[symbolic.index.index()]; + return {&specific_ir, value_id.has_value() + ? specific_ir.constant_values().Get(value_id) + : SemIR::ConstantId::NotConstant}; } auto GetConstantValueInSpecific(const File& sem_ir, SpecificId specific_id, diff --git a/toolchain/sem_ir/generic.h b/toolchain/sem_ir/generic.h index 803623490f7c..cf5aa9cf6c87 100644 --- a/toolchain/sem_ir/generic.h +++ b/toolchain/sem_ir/generic.h @@ -100,11 +100,28 @@ struct Specific : Printable { ? decl_block_id : definition_block_id; } + // Sets the specified value block of this specific. + auto SetValueBlock(GenericInstIndex::Region region, InstBlockId inst_block_id) + -> void { + auto& value_block_id = region == GenericInstIndex::Region::Declaration + ? decl_block_id + : definition_block_id; + CARBON_CHECK(!value_block_id.has_value(), "Value block set twice"); + value_block_id = inst_block_id; + } // Returns whether either block has an error. auto HasError() const -> bool { return decl_block_has_error || definition_block_has_error; } + // Sets that one of the blocks has an error. + auto SetHasError(GenericInstIndex::Region region) -> void { + if (region == SemIR::GenericInstIndex::Declaration) { + decl_block_has_error = true; + } else { + definition_block_has_error = true; + } + } // The generic that this is a specific version of. GenericId generic_id; diff --git a/toolchain/sem_ir/inst.h b/toolchain/sem_ir/inst.h index dfb03f475399..8166c59e5dd5 100644 --- a/toolchain/sem_ir/inst.h +++ b/toolchain/sem_ir/inst.h @@ -678,7 +678,8 @@ class InstBlockStore // Adds an uninitialized block of the given size. The caller is expected to // modify values. auto AddUninitialized(size_t size) -> InstBlockId { - return values().Add(AllocateUninitialized(size)); + return size ? values().Add(AllocateUninitialized(size)) + : InstBlockId::Empty; } // Reserves and returns a block ID. The contents of the block should be