Remove ArgKinds to encourage safer coding patterns (#5212)

#5171 ran into an issue where the wrong kind was associated with an arg
(`auto arg1 = RefineOperand(context, loc_id, arg0_kind,
action.arg1());`). This PR is trying to reduce risk of similar errors by
replaced `ArgKinds()` with instead an `ArgAndKind` structure and
corresponding accessors.

A couple things I considered and discarded were:

- Adding `CARBON_KIND_SWITCH` support (in this PR -- see #5216).
- The particular way that `ForCase` works would need to change, and I
was hesitant to do that here.
- But this is why I did add `As` to `ArgAndKind`, because it had me
thinking in that direction.
- Trying to make wrapper functions like `MutateArgs(callback_fn);`. This
kind of approach gets a little messy due to some of the conditional
passes, and in particular the reverse-iteration done for `PopOperand` in
subst.cpp
- Making something like `args_and_kinds() -> std::array<ArgAndKind, 2>`.
There's one spot where iteration is already set up as a loop, but for
others it felt a little convoluted with less gain than
`MutateArgs`-style things.

I'm not sure if there's a better way to set up the table generators, I
might keep tinkering with those for ideas.
This commit is contained in:
Jon Ross-Perkins
2025-03-28 23:24:36 +00:00
committed by GitHub
parent 2973cafd60
commit 4cb61ae4e1
8 changed files with 204 additions and 161 deletions
+12 -13
View File
@@ -138,37 +138,37 @@ class DeductionWorklist {
}
// Adds a (param, arg) pair for an instruction argument, given its kind.
auto AddInstArg(SemIR::IdKind kind, int32_t param, int32_t arg,
auto AddInstArg(SemIR::Inst::ArgAndKind param, int32_t arg,
bool needs_substitution) -> void {
switch (kind) {
switch (param.kind) {
case SemIR::IdKind::None:
case SemIR::IdKind::For<SemIR::ClassId>:
case SemIR::IdKind::For<SemIR::IntKind>:
break;
case SemIR::IdKind::For<SemIR::InstId>:
Add(SemIR::InstId(param), SemIR::InstId(arg), needs_substitution);
Add(param.As<SemIR::InstId>(), SemIR::InstId(arg), needs_substitution);
break;
case SemIR::IdKind::For<SemIR::TypeId>:
Add(SemIR::TypeId(param), SemIR::TypeId(arg), needs_substitution);
Add(param.As<SemIR::TypeId>(), SemIR::TypeId(arg), needs_substitution);
break;
case SemIR::IdKind::For<SemIR::StructTypeFieldsId>:
AddAll(SemIR::StructTypeFieldsId(param), SemIR::StructTypeFieldsId(arg),
needs_substitution);
AddAll(param.As<SemIR::StructTypeFieldsId>(),
SemIR::StructTypeFieldsId(arg), needs_substitution);
break;
case SemIR::IdKind::For<SemIR::InstBlockId>:
AddAll(SemIR::InstBlockId(param), SemIR::InstBlockId(arg),
AddAll(param.As<SemIR::InstBlockId>(), SemIR::InstBlockId(arg),
needs_substitution);
break;
case SemIR::IdKind::For<SemIR::TypeBlockId>:
AddAll(SemIR::TypeBlockId(param), SemIR::TypeBlockId(arg),
AddAll(param.As<SemIR::TypeBlockId>(), SemIR::TypeBlockId(arg),
needs_substitution);
break;
case SemIR::IdKind::For<SemIR::SpecificId>:
Add(SemIR::SpecificId(param), SemIR::SpecificId(arg),
Add(param.As<SemIR::SpecificId>(), SemIR::SpecificId(arg),
needs_substitution);
break;
case SemIR::IdKind::For<SemIR::FacetTypeId>:
AddAll(SemIR::FacetTypeId(param), SemIR::FacetTypeId(arg),
AddAll(param.As<SemIR::FacetTypeId>(), SemIR::FacetTypeId(arg),
needs_substitution);
break;
default:
@@ -469,10 +469,9 @@ auto DeductionContext::Deduce() -> bool {
if (arg_inst.kind() != param_inst.kind()) {
break;
}
auto [kind0, kind1] = param_inst.ArgKinds();
worklist_.AddInstArg(kind0, param_inst.arg0(), arg_inst.arg0(),
worklist_.AddInstArg(param_inst.arg0_and_kind(), arg_inst.arg0(),
needs_substitution);
worklist_.AddInstArg(kind1, param_inst.arg1(), arg_inst.arg1(),
worklist_.AddInstArg(param_inst.arg1_and_kind(), arg_inst.arg1(),
needs_substitution);
continue;
}