mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
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:
+28
-28
@@ -44,21 +44,24 @@ auto OperandIsDependent(Context& context, SemIR::MetaInstId inst_id) -> bool {
|
||||
OperandIsDependent(context, context.constant_values().Get(inst_id));
|
||||
}
|
||||
|
||||
static auto OperandIsDependent(Context& context, SemIR::IdKind kind,
|
||||
int32_t arg) -> bool {
|
||||
if (kind == SemIR::IdKind::For<SemIR::MetaInstId>) {
|
||||
return OperandIsDependent(context, SemIR::MetaInstId(arg));
|
||||
static auto OperandIsDependent(Context& context, SemIR::Inst::ArgAndKind arg)
|
||||
-> bool {
|
||||
switch (arg.kind) {
|
||||
case SemIR::IdKind::For<SemIR::MetaInstId>:
|
||||
return OperandIsDependent(context, arg.As<SemIR::MetaInstId>());
|
||||
|
||||
case SemIR::IdKind::For<SemIR::TypeId>:
|
||||
return OperandIsDependent(context, arg.As<SemIR::TypeId>());
|
||||
|
||||
case SemIR::IdKind::None:
|
||||
case SemIR::IdKind::For<SemIR::AbsoluteInstId>:
|
||||
case SemIR::IdKind::For<SemIR::NameId>:
|
||||
return false;
|
||||
|
||||
default:
|
||||
// TODO: Properly handle different argument kinds.
|
||||
CARBON_FATAL("Unexpected argument kind for action");
|
||||
}
|
||||
if (kind == SemIR::IdKind::For<SemIR::TypeId>) {
|
||||
return OperandIsDependent(context, SemIR::TypeId(arg));
|
||||
}
|
||||
if (kind == SemIR::IdKind::None ||
|
||||
kind == SemIR::IdKind::For<SemIR::AbsoluteInstId> ||
|
||||
kind == SemIR::IdKind::For<SemIR::NameId>) {
|
||||
return false;
|
||||
}
|
||||
// TODO: Properly handle different argument kinds.
|
||||
CARBON_FATAL("Unexpected argument kind for action");
|
||||
}
|
||||
|
||||
auto ActionIsDependent(Context& context, SemIR::Inst action_inst) -> bool {
|
||||
@@ -71,9 +74,8 @@ auto ActionIsDependent(Context& context, SemIR::Inst action_inst) -> bool {
|
||||
if (OperandIsDependent(context, action_inst.type_id())) {
|
||||
return true;
|
||||
}
|
||||
auto [arg0_kind, arg1_kind] = action_inst.ArgKinds();
|
||||
return OperandIsDependent(context, arg0_kind, action_inst.arg0()) ||
|
||||
OperandIsDependent(context, arg1_kind, action_inst.arg1());
|
||||
return OperandIsDependent(context, action_inst.arg0_and_kind()) ||
|
||||
OperandIsDependent(context, action_inst.arg1_and_kind());
|
||||
}
|
||||
|
||||
static auto AddDependentActionSpliceImpl(Context& context,
|
||||
@@ -98,14 +100,13 @@ 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::IdKind kind, int32_t arg) -> int32_t {
|
||||
if (kind == SemIR::IdKind::For<SemIR::MetaInstId>) {
|
||||
auto inst_id = SemIR::MetaInstId(arg);
|
||||
auto inst = context.insts().Get(inst_id);
|
||||
SemIR::Inst::ArgAndKind arg) -> int32_t {
|
||||
if (auto inst_id = arg.TryAs<SemIR::MetaInstId>()) {
|
||||
auto inst = context.insts().Get(*inst_id);
|
||||
if (inst.Is<SemIR::SpliceInst>()) {
|
||||
// The argument will evaluate to the spliced instruction, which is already
|
||||
// refined.
|
||||
return arg;
|
||||
return arg.value;
|
||||
}
|
||||
|
||||
// If the type of the action argument is dependent, refine to an instruction
|
||||
@@ -116,7 +117,7 @@ static auto RefineOperand(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::LocIdAndInst(loc_id,
|
||||
SemIR::RefineTypeAction{
|
||||
.type_id = SemIR::InstType::SingletonTypeId,
|
||||
.inst_id = inst_id,
|
||||
.inst_id = *inst_id,
|
||||
.inst_type_id = inst.type_id()}),
|
||||
inst.type_id());
|
||||
}
|
||||
@@ -124,19 +125,18 @@ static auto RefineOperand(Context& context, SemIR::LocId loc_id,
|
||||
// TODO: Handle the case where the constant value of the instruction is
|
||||
// template-dependent.
|
||||
|
||||
return inst_id.index;
|
||||
return inst_id->index;
|
||||
}
|
||||
|
||||
return arg;
|
||||
return arg.value;
|
||||
}
|
||||
|
||||
// Refine the operands of an action, ensuring that they will refer to concrete
|
||||
// instructions that don't have template-dependent types.
|
||||
static auto RefineOperands(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::Inst action) -> SemIR::Inst {
|
||||
auto [arg0_kind, arg1_kind] = action.ArgKinds();
|
||||
auto arg0 = RefineOperand(context, loc_id, arg0_kind, action.arg0());
|
||||
auto arg1 = RefineOperand(context, loc_id, arg1_kind, action.arg1());
|
||||
auto arg0 = RefineOperand(context, loc_id, action.arg0_and_kind());
|
||||
auto arg1 = RefineOperand(context, loc_id, action.arg1_and_kind());
|
||||
action.SetArgs(arg0, arg1);
|
||||
return action;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user