mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 15:10:12 +01:00
Use consistent pattern to generate constrained overload sets. (#7679)
Follow the pattern used by eval_inst.h's `EvalConstantInst` to generate declarations of an overload set that handles some but not all typed inst classes. The pattern is: * A template computes the signature to use for a particular overload, producing a fallback `() -> void` signature for overloads that should not exist. * The `.def` file is used to generate a declaration per instruction kind, whose signature is generated by the template. * The `() -> void` signature that all the "should not exist" cases generate is explicitly deleted. This avoids the redundancy of manually declaring all the overloads, as we did for `PerformAction`, and is less error-prone as it both catches signature errors and definitions of overloads that are dead code and should not exist, as it did for the `FacetAccessType` overload of `LowerInst`.
This commit is contained in:
+26
-41
@@ -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 <typename InstT>
|
||||
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<SemIR::Name> 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).
|
||||
|
||||
@@ -367,13 +367,42 @@ class FunctionContext {
|
||||
Map<SemIR::InstId, llvm::Value*> 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 <typename InstT>
|
||||
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 <typename InstT>
|
||||
using FunctionTypeForHandleInst = std::conditional_t<
|
||||
HasHandleInst<InstT>,
|
||||
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<InstT>`
|
||||
// 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<SemIR::Name> HandleInst;
|
||||
#include "toolchain/sem_ir/inst_kind.def"
|
||||
|
||||
} // namespace Carbon::Lower
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user