diff --git a/toolchain/check/action.h b/toolchain/check/action.h index 3e40405933e0..aaef33d0afa1 100644 --- a/toolchain/check/action.h +++ b/toolchain/check/action.h @@ -9,53 +9,38 @@ #include "toolchain/check/inst.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" +#include "toolchain/sem_ir/inst_kind.h" #include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { -// Performs a member access action. Defined in member_access.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::AccessMemberAction action) -> SemIR::InstId; -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::AccessOptionalMemberAction action) -> SemIR::InstId; +namespace Internal { +// Computes the function type to use for PerformAction for InstT. +template +using FunctionTypeForPerformAction = std::conditional_t< + InstT::Kind.constant_kind() == SemIR::InstConstantKind::InstAction, + auto(Context& context, SemIR::LocId loc_id, InstT inst)->SemIR::InstId, + auto()->void>; +} // namespace Internal -// Performs a C++ template call action. Defined in cpp/call.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::CallCppTemplateAction action) -> SemIR::InstId; +// Explicitly delete the overload generated for non-action instructions. These +// all produce the same signature, so we only need to delete it once. +auto PerformAction() -> void = delete; -// Performs a conversion action. Defined in convert.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::ConvertAction action) -> SemIR::InstId; -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::ConvertToCategoryAction action) -> SemIR::InstId; -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::ConvertToValueAction action) -> SemIR::InstId; - -// Performs a form parameter pattern action. Defined in pattern.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::FormParamPatternAction action) -> SemIR::InstId; - -// Performs an output form parameter pattern action. Defined in pattern.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::OutFormParamPatternAction action) -> SemIR::InstId; - -// Performs a caller pattern match action. Defined in pattern_match.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::CallerPatternMatchAction action) -> SemIR::InstId; - -// Performs a callee pattern match action. Defined in pattern_match.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::CalleePatternMatchAction action) -> SemIR::InstId; - -// Performs a compound member access action. Defined in member_access.cpp. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::CompoundMemberAccessAction action) -> SemIR::InstId; - -// Performs a type refinement action, by creating a conversion from an -// instruction with a template-dependent symbolic type to the corresponding -// instantiated type. -auto PerformAction(Context& context, SemIR::LocId loc_id, - SemIR::RefineTypeAction action) -> SemIR::InstId; +// Performs an action. Each PerformAction implementation lives with the code +// that creates and defines the action. For an instruction whose constant kind +// is InstAction, an overload should be provided with the signature: +// +// auto PerformAction(Context& context, SemIR::LocId loc_id, InstT inst) +// -> SemIR::InstId; +// +// that returns the value that should be used as the result of evaluating the +// instructions produced by the action. Any instructions generated during +// `PerformAction` will be spliced into the code at the point where the action +// was created. +#define CARBON_SEM_IR_INST_KIND(Name) \ + Internal::FunctionTypeForPerformAction PerformAction; +#include "toolchain/sem_ir/inst_kind.def" // Determines whether the given action can be performed immediately (i.e. // whether it is non-template-dependent). diff --git a/toolchain/lower/function_context.h b/toolchain/lower/function_context.h index 75859e100fec..73017125c0c6 100644 --- a/toolchain/lower/function_context.h +++ b/toolchain/lower/function_context.h @@ -367,13 +367,42 @@ class FunctionContext { Map locals_; }; -// Provides handlers for instructions that occur in a FunctionContext. Although -// this is declared for all instructions, it should only be defined for -// instructions which are non-constant and not always typed. See -// `FunctionContext::LowerInst` for how this is used. -#define CARBON_SEM_IR_INST_KIND(Name) \ - auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, \ - SemIR::Name inst) -> void; +namespace Internal { +// Determines whether InstT should have a `HandleInst` function. +template +constexpr bool HasHandleInst = + // is_lowered() == false indicates lowering should never see this inst kind. + InstT::Kind.is_lowered() && + // Constant instructions never need to be explicitly lowered. + InstT::Kind.constant_kind() != SemIR::InstConstantKind::Always && + InstT::Kind.constant_kind() != SemIR::InstConstantKind::AlwaysUnique && + // Instructions that always produce types don't need a `HandleInst` even if + // they're not constant, because `type` has an empty runtime representation + // and we assume that `InstIsType::Always` implies a lack of side effects. + InstT::Kind.is_type() != SemIR::InstIsType::Always; + +// Computes the function type to use for HandleInst for InstT. +template +using FunctionTypeForHandleInst = std::conditional_t< + HasHandleInst, + auto(FunctionContext& context, SemIR::InstId inst_id, InstT inst)->void, + auto()->void>; +} // namespace Internal + +// Explicitly delete the overload generated for non-lowered instructions. +// These all produce the same signature, so we only need to delete it once. +auto HandleInst() -> void = delete; + +// Provides handlers for instructions that occur in a FunctionContext. This +// should be defined for instructions for which `Internal::HasHandleInst` +// is true. See `FunctionContext::LowerInst` for how this is used. +// +// The signature of an overload is: +// +// auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, +// InstT inst) -> void; +#define CARBON_SEM_IR_INST_KIND(Name) \ + Internal::FunctionTypeForHandleInst HandleInst; #include "toolchain/sem_ir/inst_kind.def" } // namespace Carbon::Lower diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index fadea586bc33..59921946fe9d 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -188,11 +188,6 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.pointer_id)); } -auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, - SemIR::FacetAccessType /*inst*/) -> void { - context.SetLocal(inst_id, context.GetTypeAsValue()); -} - auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, SemIR::FacetValue /*inst*/) -> void { context.SetLocal(inst_id, context.GetTypeAsValue());