mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 13:50:10 +01:00
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.
This commit is contained in:
+19
-77
@@ -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<SpecificEvalInfo> 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<SpecificEvalInfo> 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::InstBlockId, bool> {
|
||||
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<SemIR::InstId> 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
|
||||
|
||||
@@ -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::InstBlockId, bool>;
|
||||
SemIR::GenericInstIndex::Region region) -> void;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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: <elided>
|
||||
// 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: <elided>
|
||||
// CHECK:STDOUT: %Destroy.Op.bound.loc17: <bound method> = 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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
+4
-4
@@ -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> = specific_function %F.ref, @F(constants.%tuple.162, <error>) [concrete = <error>]
|
||||
// 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> = 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
|
||||
|
||||
+2
-2
@@ -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]
|
||||
|
||||
+2
-2
@@ -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> = 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)
|
||||
|
||||
+2
-2
@@ -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> = 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)
|
||||
|
||||
@@ -397,8 +397,8 @@ let x: i32 = c[0];
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %.loc8: <witness> = 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
|
||||
|
||||
+8
-8
@@ -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]
|
||||
|
||||
+6
-6
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -100,11 +100,28 @@ struct Specific : Printable<Specific> {
|
||||
? 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user