Restructure ArgAndKind as a type-safe generic ID. (#7172)

The key changes here are:
- Relocating and renaming it to align with `IdKind` (and relocating
`ToRaw` and `FromRaw` to follow it).
- Adding a `Dispatch` method that provides a generic overload-based API
for expressing per-ID-kind dispatch, and rewriting existing code to use
it.

Note in particular that using overloads instead of switch cases makes it
possible to generically handle all specializations of a templated ID
type, e.g. `SomeIdType<T>` for all `T`. We have no such templated ID
types yet, but I'm introducing one in a follow-up PR that needs this
capability.
This commit is contained in:
Geoff Romer
2026-05-07 00:13:52 +00:00
committed by GitHub
parent db24042fe5
commit daebbf32fa
10 changed files with 236 additions and 218 deletions
+26 -22
View File
@@ -90,6 +90,13 @@ auto OperandDependence(Context& context, SemIR::InstId inst_id)
OperandDependence(context, context.constant_values().Get(inst_id)));
}
static auto OperandDependence(Context& context, SemIR::MetaInstId inst_id)
-> SemIR::ConstantDependence {
// A meta-instruction operand makes the instruction dependent if its type or
// constant value is dependent.
return OperandDependence(context, SemIR::InstId{inst_id});
}
auto OperandDependence(Context& context, SemIR::TypeInstId inst_id)
-> SemIR::ConstantDependence {
// An instruction operand makes the instruction dependent if its type or
@@ -98,30 +105,27 @@ auto OperandDependence(Context& context, SemIR::TypeInstId inst_id)
return OperandDependence(context, context.constant_values().Get(inst_id));
}
static auto OperandDependence(Context& context, SemIR::Inst::ArgAndKind arg)
template <typename IdT>
requires SemIR::Internal::IsIdKindType<IdT> &&
SameAsOneOf<IdT, SemIR::IdAndKind::NoneType, SemIR::AbsoluteInstId,
SemIR::CallParamIndex, SemIR::NameId>
static auto OperandDependence(Context& /*context*/, IdT /*id*/)
-> SemIR::ConstantDependence {
CARBON_KIND_SWITCH(arg) {
case CARBON_KIND(SemIR::InstId inst_id): {
return OperandDependence(context, inst_id);
}
return SemIR::ConstantDependence::None;
}
case CARBON_KIND(SemIR::MetaInstId inst_id): {
return OperandDependence(context, inst_id);
}
template <typename IdT>
requires SemIR::Internal::IsIdKindType<IdT>
static auto OperandDependence(Context& /*context*/, IdT /*id*/)
-> SemIR::ConstantDependence {
// TODO: Properly handle different argument kinds.
CARBON_FATAL("Unexpected argument kind for action: {}", IdT::Label);
}
case CARBON_KIND(SemIR::TypeInstId inst_id): {
return OperandDependence(context, inst_id);
}
case SemIR::IdKind::None:
case SemIR::IdKind::For<SemIR::AbsoluteInstId>:
case SemIR::IdKind::For<SemIR::NameId>:
return SemIR::ConstantDependence::None;
default:
// TODO: Properly handle different argument kinds.
CARBON_FATAL("Unexpected argument kind for action");
}
static auto OperandDependence(Context& context, SemIR::IdAndKind arg)
-> SemIR::ConstantDependence {
return arg.Dispatch<SemIR::ConstantDependence>(
[&](auto id) { return OperandDependence(context, id); });
}
auto ActionIsPerformable(Context& context, SemIR::Inst action_inst) -> bool {
@@ -208,7 +212,7 @@ static auto AddDependentActionSpliceImpl(Context& context,
// their concrete values, so that the action doesn't need to know which specific
// it is operating on.
static auto RefineOperand(Context& context, SemIR::LocId loc_id,
SemIR::Inst::ArgAndKind arg) -> int32_t {
SemIR::IdAndKind arg) -> int32_t {
if (auto inst_id = arg.TryAs<SemIR::MetaInstId>()) {
auto inst = context.insts().Get(*inst_id);
if (inst.Is<SemIR::SpliceInst>()) {