|
|
@@ -14,6 +14,7 @@
|
|
|
#include "toolchain/check/context.h"
|
|
|
#include "toolchain/check/diagnostic_helpers.h"
|
|
|
#include "toolchain/check/impl_lookup.h"
|
|
|
+#include "toolchain/check/inst.h"
|
|
|
#include "toolchain/check/operator.h"
|
|
|
#include "toolchain/check/pattern_match.h"
|
|
|
#include "toolchain/check/type.h"
|
|
|
@@ -114,10 +115,10 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id,
|
|
|
"initialized multiple times? Have {0}",
|
|
|
sem_ir.insts().Get(return_slot_arg_id));
|
|
|
auto init = sem_ir.insts().Get(init_id);
|
|
|
- return context.AddInst<SemIR::Temporary>(sem_ir.insts().GetLocId(init_id),
|
|
|
- {.type_id = init.type_id(),
|
|
|
- .storage_id = return_slot_arg_id,
|
|
|
- .init_id = init_id});
|
|
|
+ return AddInst<SemIR::Temporary>(context, sem_ir.insts().GetLocId(init_id),
|
|
|
+ {.type_id = init.type_id(),
|
|
|
+ .storage_id = return_slot_arg_id,
|
|
|
+ .init_id = init_id});
|
|
|
}
|
|
|
|
|
|
if (discarded) {
|
|
|
@@ -131,11 +132,12 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id,
|
|
|
// initialize a temporary, rather than two separate instructions.
|
|
|
auto init = sem_ir.insts().Get(init_id);
|
|
|
auto loc_id = sem_ir.insts().GetLocId(init_id);
|
|
|
- auto temporary_id = context.AddInst<SemIR::TemporaryStorage>(
|
|
|
- loc_id, {.type_id = init.type_id()});
|
|
|
- return context.AddInst<SemIR::Temporary>(loc_id, {.type_id = init.type_id(),
|
|
|
- .storage_id = temporary_id,
|
|
|
- .init_id = init_id});
|
|
|
+ auto temporary_id = AddInst<SemIR::TemporaryStorage>(
|
|
|
+ context, loc_id, {.type_id = init.type_id()});
|
|
|
+ return AddInst<SemIR::Temporary>(context, loc_id,
|
|
|
+ {.type_id = init.type_id(),
|
|
|
+ .storage_id = temporary_id,
|
|
|
+ .init_id = init_id});
|
|
|
}
|
|
|
|
|
|
// Materialize a temporary to hold the result of the given expression if it is
|
|
|
@@ -149,12 +151,20 @@ static auto MaterializeIfInitializing(Context& context, SemIR::InstId expr_id)
|
|
|
return expr_id;
|
|
|
}
|
|
|
|
|
|
+// Helper to allow `MakeElementAccessInst` to call `AddInst` with either a
|
|
|
+// `PendingBlock` or `Context` (defined in `inst.h`).
|
|
|
+template <typename AccessInstT>
|
|
|
+static auto AddInst(PendingBlock& block, SemIR::LocId loc_id, AccessInstT inst)
|
|
|
+ -> SemIR::InstId {
|
|
|
+ return block.AddInst<AccessInstT>(loc_id, inst);
|
|
|
+}
|
|
|
+
|
|
|
// Creates and adds an instruction to perform element access into an aggregate.
|
|
|
template <typename AccessInstT, typename InstBlockT>
|
|
|
static auto MakeElementAccessInst(Context& context, SemIR::LocId loc_id,
|
|
|
SemIR::InstId aggregate_id,
|
|
|
SemIR::TypeId elem_type_id, InstBlockT& block,
|
|
|
- size_t i) {
|
|
|
+ size_t i) -> SemIR::InstId {
|
|
|
if constexpr (std::is_same_v<AccessInstT, SemIR::ArrayIndex>) {
|
|
|
// TODO: Add a new instruction kind for indexing an array at a constant
|
|
|
// index so that we don't need an integer literal instruction here, and
|
|
|
@@ -163,11 +173,11 @@ static auto MakeElementAccessInst(Context& context, SemIR::LocId loc_id,
|
|
|
loc_id, {.type_id = GetSingletonType(
|
|
|
context, SemIR::IntLiteralType::SingletonInstId),
|
|
|
.int_id = context.ints().Add(static_cast<int64_t>(i))});
|
|
|
- return block.template AddInst<AccessInstT>(
|
|
|
- loc_id, {elem_type_id, aggregate_id, index_id});
|
|
|
+ return AddInst<AccessInstT>(block, loc_id,
|
|
|
+ {elem_type_id, aggregate_id, index_id});
|
|
|
} else {
|
|
|
- return block.template AddInst<AccessInstT>(
|
|
|
- loc_id, {elem_type_id, aggregate_id, SemIR::ElementIndex(i)});
|
|
|
+ return AddInst<AccessInstT>(
|
|
|
+ block, loc_id, {elem_type_id, aggregate_id, SemIR::ElementIndex(i)});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -191,7 +201,7 @@ static auto ConvertAggregateElement(
|
|
|
llvm::ArrayRef<SemIR::InstId> src_literal_elems,
|
|
|
ConversionTarget::Kind kind, SemIR::InstId target_id,
|
|
|
SemIR::TypeId target_elem_type, PendingBlock* target_block,
|
|
|
- size_t src_field_index, size_t target_field_index) {
|
|
|
+ size_t src_field_index, size_t target_field_index) -> SemIR::InstId {
|
|
|
// 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.
|
|
|
@@ -303,10 +313,10 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type,
|
|
|
// Flush the temporary here if we didn't insert it earlier, so we can add a
|
|
|
// reference to the return slot.
|
|
|
target_block->InsertHere();
|
|
|
- return context.AddInst<SemIR::ArrayInit>(
|
|
|
- value_loc_id, {.type_id = target.type_id,
|
|
|
- .inits_id = sem_ir.inst_blocks().Add(inits),
|
|
|
- .dest_id = return_slot_arg_id});
|
|
|
+ return AddInst<SemIR::ArrayInit>(context, value_loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .inits_id = sem_ir.inst_blocks().Add(inits),
|
|
|
+ .dest_id = return_slot_arg_id});
|
|
|
}
|
|
|
|
|
|
// Performs a conversion from a tuple to a tuple type. This function only
|
|
|
@@ -383,13 +393,13 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
|
|
|
|
|
|
if (is_init) {
|
|
|
target.init_block->InsertHere();
|
|
|
- return context.AddInst<SemIR::TupleInit>(value_loc_id,
|
|
|
- {.type_id = target.type_id,
|
|
|
- .elements_id = new_block.id(),
|
|
|
- .dest_id = target.init_id});
|
|
|
+ return AddInst<SemIR::TupleInit>(context, value_loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .elements_id = new_block.id(),
|
|
|
+ .dest_id = target.init_id});
|
|
|
} else {
|
|
|
- return context.AddInst<SemIR::TupleValue>(
|
|
|
- value_loc_id,
|
|
|
+ return AddInst<SemIR::TupleValue>(
|
|
|
+ context, value_loc_id,
|
|
|
{.type_id = target.type_id, .elements_id = new_block.id()});
|
|
|
}
|
|
|
}
|
|
|
@@ -478,16 +488,18 @@ static auto ConvertStructToStructOrClass(Context& context,
|
|
|
for (auto [i, dest_field] : llvm::enumerate(dest_elem_fields)) {
|
|
|
if (dest_field.name_id == SemIR::NameId::Vptr) {
|
|
|
// CARBON_CHECK(ToClass, "Only classes should have vptrs.");
|
|
|
- auto dest_id = context.AddInst<SemIR::ClassElementAccess>(
|
|
|
- value_loc_id, {.type_id = dest_field.type_id,
|
|
|
- .base_id = target.init_id,
|
|
|
- .index = SemIR::ElementIndex(i)});
|
|
|
- auto vtable_ptr_id = context.AddInst<SemIR::VtablePtr>(
|
|
|
- value_loc_id, {.type_id = dest_field.type_id});
|
|
|
- auto init_id = context.AddInst<SemIR::InitializeFrom>(
|
|
|
- value_loc_id, {.type_id = dest_field.type_id,
|
|
|
- .src_id = vtable_ptr_id,
|
|
|
- .dest_id = dest_id});
|
|
|
+ auto dest_id =
|
|
|
+ AddInst<SemIR::ClassElementAccess>(context, value_loc_id,
|
|
|
+ {.type_id = dest_field.type_id,
|
|
|
+ .base_id = target.init_id,
|
|
|
+ .index = SemIR::ElementIndex(i)});
|
|
|
+ auto vtable_ptr_id = AddInst<SemIR::VtablePtr>(
|
|
|
+ context, value_loc_id, {.type_id = dest_field.type_id});
|
|
|
+ auto init_id =
|
|
|
+ AddInst<SemIR::InitializeFrom>(context, value_loc_id,
|
|
|
+ {.type_id = dest_field.type_id,
|
|
|
+ .src_id = vtable_ptr_id,
|
|
|
+ .dest_id = dest_id});
|
|
|
new_block.Set(i, init_id);
|
|
|
continue;
|
|
|
}
|
|
|
@@ -536,19 +548,19 @@ static auto ConvertStructToStructOrClass(Context& context,
|
|
|
target.init_block->InsertHere();
|
|
|
CARBON_CHECK(is_init,
|
|
|
"Converting directly to a class value is not supported");
|
|
|
- return context.AddInst<SemIR::ClassInit>(value_loc_id,
|
|
|
- {.type_id = target.type_id,
|
|
|
- .elements_id = new_block.id(),
|
|
|
- .dest_id = target.init_id});
|
|
|
+ return AddInst<SemIR::ClassInit>(context, value_loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .elements_id = new_block.id(),
|
|
|
+ .dest_id = target.init_id});
|
|
|
} else if (is_init) {
|
|
|
target.init_block->InsertHere();
|
|
|
- return context.AddInst<SemIR::StructInit>(value_loc_id,
|
|
|
- {.type_id = target.type_id,
|
|
|
- .elements_id = new_block.id(),
|
|
|
- .dest_id = target.init_id});
|
|
|
+ return AddInst<SemIR::StructInit>(context, value_loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .elements_id = new_block.id(),
|
|
|
+ .dest_id = target.init_id});
|
|
|
} else {
|
|
|
- return context.AddInst<SemIR::StructValue>(
|
|
|
- value_loc_id,
|
|
|
+ return AddInst<SemIR::StructValue>(
|
|
|
+ context, value_loc_id,
|
|
|
{.type_id = target.type_id, .elements_id = new_block.id()});
|
|
|
}
|
|
|
}
|
|
|
@@ -597,10 +609,11 @@ static auto ConvertStructToClass(Context& context, SemIR::StructType src_type,
|
|
|
|
|
|
if (need_temporary) {
|
|
|
target_block.InsertHere();
|
|
|
- result_id = context.AddInst<SemIR::Temporary>(
|
|
|
- context.insts().GetLocId(value_id), {.type_id = target.type_id,
|
|
|
- .storage_id = target.init_id,
|
|
|
- .init_id = result_id});
|
|
|
+ result_id =
|
|
|
+ AddInst<SemIR::Temporary>(context, context.insts().GetLocId(value_id),
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .storage_id = target.init_id,
|
|
|
+ .init_id = result_id});
|
|
|
}
|
|
|
return result_id;
|
|
|
}
|
|
|
@@ -657,10 +670,10 @@ static auto ConvertDerivedToBase(Context& context, SemIR::LocId loc_id,
|
|
|
// Add a series of `.base` accesses.
|
|
|
for (auto [base_id, base_type_id] : path) {
|
|
|
auto base_decl = context.insts().GetAs<SemIR::BaseDecl>(base_id);
|
|
|
- value_id = context.AddInst<SemIR::ClassElementAccess>(
|
|
|
- loc_id, {.type_id = base_type_id,
|
|
|
- .base_id = value_id,
|
|
|
- .index = base_decl.index});
|
|
|
+ value_id = AddInst<SemIR::ClassElementAccess>(context, loc_id,
|
|
|
+ {.type_id = base_type_id,
|
|
|
+ .base_id = value_id,
|
|
|
+ .index = base_decl.index});
|
|
|
}
|
|
|
return value_id;
|
|
|
}
|
|
|
@@ -672,15 +685,16 @@ static auto ConvertDerivedPointerToBasePointer(
|
|
|
const InheritancePath& path) -> SemIR::InstId {
|
|
|
// Form `*p`.
|
|
|
ptr_id = ConvertToValueExpr(context, ptr_id);
|
|
|
- auto ref_id = context.AddInst<SemIR::Deref>(
|
|
|
- loc_id, {.type_id = src_ptr_type.pointee_id, .pointer_id = ptr_id});
|
|
|
+ auto ref_id = AddInst<SemIR::Deref>(
|
|
|
+ context, loc_id,
|
|
|
+ {.type_id = src_ptr_type.pointee_id, .pointer_id = ptr_id});
|
|
|
|
|
|
// Convert as a reference expression.
|
|
|
ref_id = ConvertDerivedToBase(context, loc_id, ref_id, path);
|
|
|
|
|
|
// Take the address.
|
|
|
- return context.AddInst<SemIR::AddrOf>(
|
|
|
- loc_id, {.type_id = dest_ptr_type_id, .lvalue_id = ref_id});
|
|
|
+ return AddInst<SemIR::AddrOf>(
|
|
|
+ context, loc_id, {.type_id = dest_ptr_type_id, .lvalue_id = ref_id});
|
|
|
}
|
|
|
|
|
|
// Returns whether `category` is a valid expression category to produce as a
|
|
|
@@ -801,8 +815,8 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
// value right out of it.
|
|
|
if (value_cat == SemIR::ExprCategory::Initializing &&
|
|
|
CanUseValueOfInitializer(sem_ir, value_type_id, target.kind)) {
|
|
|
- return context.AddInst<SemIR::ValueOfInitializer>(
|
|
|
- loc_id, {.type_id = value_type_id, .init_id = value_id});
|
|
|
+ return AddInst<SemIR::ValueOfInitializer>(
|
|
|
+ context, loc_id, {.type_id = value_type_id, .init_id = value_id});
|
|
|
}
|
|
|
|
|
|
// PerformBuiltinConversion converts each part of a tuple or struct, even
|
|
|
@@ -825,8 +839,9 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
foundation_type_id != value_type_id &&
|
|
|
(context.types().Is<SemIR::TupleType>(foundation_type_id) ||
|
|
|
context.types().Is<SemIR::StructType>(foundation_type_id))) {
|
|
|
- auto foundation_value_id = context.AddInst<SemIR::AsCompatible>(
|
|
|
- loc_id, {.type_id = foundation_type_id, .source_id = value_id});
|
|
|
+ auto foundation_value_id = AddInst<SemIR::AsCompatible>(
|
|
|
+ context, loc_id,
|
|
|
+ {.type_id = foundation_type_id, .source_id = value_id});
|
|
|
|
|
|
auto foundation_init_id = target.init_id;
|
|
|
if (foundation_init_id != SemIR::InstId::None) {
|
|
|
@@ -858,8 +873,8 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return context.AddInst<SemIR::AsCompatible>(
|
|
|
- loc_id,
|
|
|
+ return AddInst<SemIR::AsCompatible>(
|
|
|
+ context, loc_id,
|
|
|
{.type_id = target.type_id, .source_id = foundation_value_id});
|
|
|
}
|
|
|
}
|
|
|
@@ -880,8 +895,8 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
ConversionTarget{.kind = ConversionTarget::Value,
|
|
|
.type_id = value_type_id});
|
|
|
}
|
|
|
- return context.AddInst<SemIR::AsCompatible>(
|
|
|
- loc_id, {.type_id = target.type_id, .source_id = value_id});
|
|
|
+ return AddInst<SemIR::AsCompatible>(
|
|
|
+ context, loc_id, {.type_id = target.type_id, .source_id = value_id});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -986,8 +1001,9 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
// TODO: Support converting tuple and struct values to facet types,
|
|
|
// combining the above conversions and this one in a single conversion.
|
|
|
if (sem_ir.types().Is<SemIR::FacetType>(value_type_id)) {
|
|
|
- return context.AddInst<SemIR::FacetAccessType>(
|
|
|
- loc_id, {.type_id = target.type_id, .facet_value_inst_id = value_id});
|
|
|
+ return AddInst<SemIR::FacetAccessType>(
|
|
|
+ context, loc_id,
|
|
|
+ {.type_id = target.type_id, .facet_value_inst_id = value_id});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1040,12 +1056,13 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
|
|
context.constant_values().Get(lookup_inst_id),
|
|
|
context.types().GetConstantId(target.type_id));
|
|
|
if (witness_inst_id != SemIR::InstId::None) {
|
|
|
- return context.AddInst<SemIR::FacetValue>(
|
|
|
- loc_id, {
|
|
|
- .type_id = target.type_id,
|
|
|
- .type_inst_id = lookup_inst_id,
|
|
|
- .witness_inst_id = witness_inst_id,
|
|
|
- });
|
|
|
+ return AddInst<SemIR::FacetValue>(
|
|
|
+ context, loc_id,
|
|
|
+ {
|
|
|
+ .type_id = target.type_id,
|
|
|
+ .type_inst_id = lookup_inst_id,
|
|
|
+ .witness_inst_id = witness_inst_id,
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1168,17 +1185,17 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
|
|
// Pull a value directly out of the initializer if possible and wanted.
|
|
|
if (expr_id != SemIR::ErrorInst::SingletonInstId &&
|
|
|
CanUseValueOfInitializer(sem_ir, target.type_id, target.kind)) {
|
|
|
- expr_id = context.AddInst<SemIR::ValueOfInitializer>(
|
|
|
- loc_id, {.type_id = target.type_id, .init_id = expr_id});
|
|
|
+ expr_id = AddInst<SemIR::ValueOfInitializer>(
|
|
|
+ context, loc_id, {.type_id = target.type_id, .init_id = expr_id});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Track that we performed a type conversion, if we did so.
|
|
|
if (orig_expr_id != expr_id) {
|
|
|
- expr_id =
|
|
|
- context.AddInst<SemIR::Converted>(loc_id, {.type_id = target.type_id,
|
|
|
- .original_id = orig_expr_id,
|
|
|
- .result_id = expr_id});
|
|
|
+ expr_id = AddInst<SemIR::Converted>(context, loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .original_id = orig_expr_id,
|
|
|
+ .result_id = expr_id});
|
|
|
}
|
|
|
|
|
|
// For `as`, don't perform any value category conversions. In particular, an
|
|
|
@@ -1228,8 +1245,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
|
|
|
|
|
// If we have a reference and don't want one, form a value binding.
|
|
|
// TODO: Support types with custom value representations.
|
|
|
- expr_id = context.AddInst<SemIR::BindValue>(
|
|
|
- context.insts().GetLocId(expr_id),
|
|
|
+ expr_id = AddInst<SemIR::BindValue>(
|
|
|
+ context, context.insts().GetLocId(expr_id),
|
|
|
{.type_id = target.type_id, .value_id = expr_id});
|
|
|
// We now have a value expression.
|
|
|
[[fallthrough]];
|
|
|
@@ -1247,10 +1264,10 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
|
|
if (auto init_rep = SemIR::InitRepr::ForType(sem_ir, target.type_id);
|
|
|
init_rep.kind == SemIR::InitRepr::ByCopy) {
|
|
|
target.init_block->InsertHere();
|
|
|
- expr_id = context.AddInst<SemIR::InitializeFrom>(
|
|
|
- loc_id, {.type_id = target.type_id,
|
|
|
- .src_id = expr_id,
|
|
|
- .dest_id = target.init_id});
|
|
|
+ expr_id = AddInst<SemIR::InitializeFrom>(context, loc_id,
|
|
|
+ {.type_id = target.type_id,
|
|
|
+ .src_id = expr_id,
|
|
|
+ .dest_id = target.init_id});
|
|
|
}
|
|
|
}
|
|
|
|