Move None to IdBase (#5030)

Use CRTP to eliminate per-type declarations of `None`. Note this adds
`None` to a few that may not need it, but eliminates a lot off
boilerplate.

Note this leaves `GenericInstIndex::None` because it has a more complex
construction.

Also fix `InstId::InitTombstone` to be `NoneIndex - 1`
This commit is contained in:
Jon Ross-Perkins
2025-03-01 08:00:17 +00:00
committed by GitHub
parent 5574ad361d
commit f0403dadab
4 changed files with 11 additions and 138 deletions
+10
View File
@@ -48,6 +48,13 @@ template <typename IdT>
struct IdBase : public AnyIdBase, public Printable<IdT> {
using AnyIdBase::AnyIdBase;
// Provide a standard `None` mapping to `NoneIndex`.
//
// This uses a `&` to trigger slightly different instantiation behaviors in
// Clang. For context on why this is needed, see http://wg21.link/CWG2800.
// NOLINTNEXTLINE(readability-identifier-naming)
static const IdT& None;
auto Print(llvm::raw_ostream& out) const -> void {
out << IdT::Label;
if (has_value()) {
@@ -63,6 +70,9 @@ struct IdBase : public AnyIdBase, public Printable<IdT> {
}
};
template <typename IdT>
constexpr const IdT& IdBase<IdT>::None = IdT(NoneIndex);
// A lightweight handle to an item that behaves like an index.
//
// Unlike IdBase, classes derived from IndexBase are not completely opaque, and
-2
View File
@@ -20,13 +20,11 @@ namespace Carbon::Check {
struct ScopeIndex : public IndexBase<ScopeIndex> {
static constexpr llvm::StringLiteral Label = "scope";
static const ScopeIndex Package;
static const ScopeIndex None;
using IndexBase::IndexBase;
};
constexpr ScopeIndex ScopeIndex::Package = ScopeIndex(0);
constexpr ScopeIndex ScopeIndex::None = ScopeIndex(NoneIndex);
} // namespace Carbon::Check
-5
View File
@@ -29,14 +29,9 @@ struct DeferredDefinitionIndex : public IndexBase<DeferredDefinitionIndex> {
static constexpr llvm::StringLiteral Label = "deferred_def";
using ValueType = DeferredDefinition;
static const DeferredDefinitionIndex None;
using IndexBase::IndexBase;
};
constexpr DeferredDefinitionIndex DeferredDefinitionIndex::None =
DeferredDefinitionIndex(NoneIndex);
// A function whose definition is deferred because it is defined inline in a
// class or similar scope.
//
+1 -131
View File
@@ -40,9 +40,6 @@ struct InstId : public IdBase<InstId> {
static constexpr llvm::StringLiteral Label = "inst";
using ValueType = Inst;
// An ID with no value.
static const InstId None;
// Represents the result of a name lookup that is temporarily disallowed
// because the name is currently being initialized.
static const InstId InitTombstone;
@@ -52,8 +49,7 @@ struct InstId : public IdBase<InstId> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr InstId InstId::None = InstId(NoneIndex);
constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 2);
constexpr InstId InstId::InitTombstone = InstId(NoneIndex - 1);
// An ID of an instruction that is referenced absolutely by another instruction.
// This should only be used as the type of a field within a typed instruction
@@ -113,8 +109,6 @@ struct ConstantId : public IdBase<ConstantId> {
// An ID for an expression that is not constant.
static const ConstantId NotConstant;
// An ID with no value.
static const ConstantId None;
// Returns the constant ID corresponding to a concrete constant, which should
// either be in the `constants` block in the file or should be known to be
@@ -180,36 +174,24 @@ struct ConstantId : public IdBase<ConstantId> {
};
constexpr ConstantId ConstantId::NotConstant = ConstantId(NotConstantIndex);
constexpr ConstantId ConstantId::None = ConstantId(NoneIndex);
// The ID of a EntityName.
struct EntityNameId : public IdBase<EntityNameId> {
static constexpr llvm::StringLiteral Label = "entity_name";
using ValueType = EntityName;
// An ID with no value.
static const EntityNameId None;
using IdBase::IdBase;
};
constexpr EntityNameId EntityNameId::None = EntityNameId(NoneIndex);
// The index of a compile-time binding. This is the de Bruijn level for the
// binding -- that is, this is the number of other compile time bindings whose
// scope encloses this binding.
struct CompileTimeBindIndex : public IndexBase<CompileTimeBindIndex> {
static constexpr llvm::StringLiteral Label = "comp_time_bind";
// An index with no value.
static const CompileTimeBindIndex None;
using IndexBase::IndexBase;
};
constexpr CompileTimeBindIndex CompileTimeBindIndex::None =
CompileTimeBindIndex(NoneIndex);
// The index of a runtime parameter in a function. These are allocated
// sequentially, left-to-right, to the function parameters that will have
// arguments passed to them at runtime. In a `call` instruction, a runtime
@@ -220,9 +202,6 @@ constexpr CompileTimeBindIndex CompileTimeBindIndex::None =
struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
static constexpr llvm::StringLiteral Label = "runtime_param";
// An index with no value.
static const RuntimeParamIndex None;
// An placeholder for index whose value is not yet known.
static const RuntimeParamIndex Unknown;
@@ -231,9 +210,6 @@ struct RuntimeParamIndex : public IndexBase<RuntimeParamIndex> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr RuntimeParamIndex RuntimeParamIndex::None =
RuntimeParamIndex(NoneIndex);
constexpr RuntimeParamIndex RuntimeParamIndex::Unknown =
RuntimeParamIndex(NoneIndex - 1);
@@ -242,14 +218,9 @@ struct FunctionId : public IdBase<FunctionId> {
static constexpr llvm::StringLiteral Label = "function";
using ValueType = Function;
// An ID with no value.
static const FunctionId None;
using IdBase::IdBase;
};
constexpr FunctionId FunctionId::None = FunctionId(NoneIndex);
// The ID of an IR within the set of all IRs being evaluated in the current
// check execution.
struct CheckIRId : public IdBase<CheckIRId> {
@@ -262,109 +233,66 @@ struct ClassId : public IdBase<ClassId> {
static constexpr llvm::StringLiteral Label = "class";
using ValueType = Class;
// An ID with no value.
static const ClassId None;
using IdBase::IdBase;
};
constexpr ClassId ClassId::None = ClassId(NoneIndex);
// The ID of an interface.
struct InterfaceId : public IdBase<InterfaceId> {
static constexpr llvm::StringLiteral Label = "interface";
using ValueType = Interface;
// An ID with no value.
static const InterfaceId None;
using IdBase::IdBase;
};
constexpr InterfaceId InterfaceId::None = InterfaceId(NoneIndex);
// The ID of an associated constant.
struct AssociatedConstantId : public IdBase<AssociatedConstantId> {
static constexpr llvm::StringLiteral Label = "assoc_const";
using ValueType = AssociatedConstant;
// An ID with no value.
static const AssociatedConstantId None;
using IdBase::IdBase;
};
constexpr AssociatedConstantId AssociatedConstantId::None =
AssociatedConstantId(NoneIndex);
// The ID of an facet type value.
struct FacetTypeId : public IdBase<FacetTypeId> {
static constexpr llvm::StringLiteral Label = "facet_type";
using ValueType = FacetTypeInfo;
// An ID with no value.
static const FacetTypeId None;
using IdBase::IdBase;
};
constexpr FacetTypeId FacetTypeId::None = FacetTypeId(NoneIndex);
// The ID of an resolved facet type value.
struct CompleteFacetTypeId : public IdBase<CompleteFacetTypeId> {
static constexpr llvm::StringLiteral Label = "complete_facet_type";
using ValueType = CompleteFacetType;
// An ID with no value.
static const CompleteFacetTypeId None;
using IdBase::IdBase;
};
constexpr CompleteFacetTypeId CompleteFacetTypeId::None =
CompleteFacetTypeId(NoneIndex);
// The ID of an impl.
struct ImplId : public IdBase<ImplId> {
static constexpr llvm::StringLiteral Label = "impl";
using ValueType = Impl;
// An ID with no value.
static const ImplId None;
using IdBase::IdBase;
};
constexpr ImplId ImplId::None = ImplId(NoneIndex);
// The ID of a generic.
struct GenericId : public IdBase<GenericId> {
static constexpr llvm::StringLiteral Label = "generic";
using ValueType = Generic;
// An ID with no value.
static const GenericId None;
using IdBase::IdBase;
};
constexpr GenericId GenericId::None = GenericId(NoneIndex);
// The ID of a specific, which is the result of specifying the generic arguments
// for a generic.
struct SpecificId : public IdBase<SpecificId> {
static constexpr llvm::StringLiteral Label = "specific";
using ValueType = Specific;
// An ID with no value. This is typically used to represent a non-generic
// entity.
static const SpecificId None;
using IdBase::IdBase;
};
constexpr SpecificId SpecificId::None = SpecificId(NoneIndex);
// The index of an instruction that depends on generic parameters within a
// region of a generic. A corresponding specific version of the instruction can
// be found in each specific corresponding to that generic. This is a pair of a
@@ -419,22 +347,14 @@ struct ImportCppId : public IdBase<ImportCppId> {
static constexpr llvm::StringLiteral Label = "import_cpp";
using ValueType = ImportCpp;
// An ID with no value.
static const ImportCppId None;
using IdBase::IdBase;
};
constexpr ImportCppId ImportCppId::None = ImportCppId(NoneIndex);
// The ID of an IR within the set of imported IRs, both direct and indirect.
struct ImportIRId : public IdBase<ImportIRId> {
static constexpr llvm::StringLiteral Label = "ir";
using ValueType = ImportIR;
// An ID with no value.
static const ImportIRId None;
// The implicit `api` import, for an `impl` file. A null entry is added if
// there is none, as in an `api`, in which case this ID should not show up in
// instructions.
@@ -443,7 +363,6 @@ struct ImportIRId : public IdBase<ImportIRId> {
using IdBase::IdBase;
};
constexpr ImportIRId ImportIRId::None = ImportIRId(NoneIndex);
constexpr ImportIRId ImportIRId::ApiForImpl = ImportIRId(0);
// A boolean value.
@@ -536,9 +455,6 @@ struct NameId : public IdBase<NameId> {
// names().GetFormatted() is used for diagnostics.
using DiagnosticType = DiagnosticTypeInfo<std::string>;
// An ID with no value.
static const NameId None;
// An enum of special names.
enum class SpecialNameId : uint8_t {
#define CARBON_SPECIAL_NAME_ID_FOR_ENUM(Name) Name,
@@ -582,8 +498,6 @@ struct NameId : public IdBase<NameId> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr NameId NameId::None = NameId(NoneIndex);
// Define the special `static const NameId` values.
#define CARBON_SPECIAL_NAME_ID_FOR_DEF(Name) \
constexpr NameId NameId::Name = \
@@ -602,15 +516,12 @@ struct NameScopeId : public IdBase<NameScopeId> {
static constexpr llvm::StringLiteral Label = "name_scope";
using ValueType = NameScope;
// An ID with no value.
static const NameScopeId None;
// The package (or file) name scope, guaranteed to be the first added.
static const NameScopeId Package;
using IdBase::IdBase;
};
constexpr NameScopeId NameScopeId::None = NameScopeId(NoneIndex);
constexpr NameScopeId NameScopeId::Package = NameScopeId(0);
// The ID of an instruction block.
@@ -637,9 +548,6 @@ struct InstBlockId : public IdBase<InstBlockId> {
// be inserted into it.
static const InstBlockId GlobalInit;
// An ID with no value.
static const InstBlockId None;
// An ID for unreachable code.
static const InstBlockId Unreachable;
@@ -651,7 +559,6 @@ constexpr InstBlockId InstBlockId::Empty = InstBlockId(0);
constexpr InstBlockId InstBlockId::Exports = InstBlockId(1);
constexpr InstBlockId InstBlockId::ImportRefs = InstBlockId(2);
constexpr InstBlockId InstBlockId::GlobalInit = InstBlockId(3);
constexpr InstBlockId InstBlockId::None = InstBlockId(NoneIndex);
constexpr InstBlockId InstBlockId::Unreachable = InstBlockId(NoneIndex - 1);
// An ID of an instruction block that is referenced absolutely by an
@@ -704,14 +611,9 @@ struct ExprRegionId : public IdBase<ExprRegionId> {
static constexpr llvm::StringLiteral Label = "region";
using ValueType = ExprRegion;
// An ID with no value.
static const ExprRegionId None;
using IdBase::IdBase;
};
constexpr ExprRegionId ExprRegionId::None = ExprRegionId(NoneIndex);
// The ID of a struct type field block.
struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
static constexpr llvm::StringLiteral Label = "struct_type_fields";
@@ -719,9 +621,6 @@ struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
using ElementType = StructTypeField;
using ValueType = llvm::MutableArrayRef<StructTypeField>;
// An ID with no value.
static const StructTypeFieldsId None;
// The canonical empty block, reused to avoid allocating empty vectors. Always
// the 0-index block.
static const StructTypeFieldsId Empty;
@@ -729,8 +628,6 @@ struct StructTypeFieldsId : public IdBase<StructTypeFieldsId> {
using IdBase::IdBase;
};
constexpr StructTypeFieldsId StructTypeFieldsId::None =
StructTypeFieldsId(NoneIndex);
constexpr StructTypeFieldsId StructTypeFieldsId::Empty = StructTypeFieldsId(0);
// The ID of a type.
@@ -742,9 +639,6 @@ struct TypeId : public IdBase<TypeId> {
// `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
using DiagnosticType = DiagnosticTypeInfo<std::string>;
// An ID with no value.
static const TypeId None;
using IdBase::IdBase;
// Returns the ID of the type corresponding to the constant `const_id`, which
@@ -765,8 +659,6 @@ struct TypeId : public IdBase<TypeId> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr TypeId TypeId::None = TypeId(NoneIndex);
// The ID of a type block.
struct TypeBlockId : public IdBase<TypeBlockId> {
static constexpr llvm::StringLiteral Label = "type_block";
@@ -774,9 +666,6 @@ struct TypeBlockId : public IdBase<TypeBlockId> {
using ElementType = TypeId;
using ValueType = llvm::MutableArrayRef<ElementType>;
// An ID with no value.
static const TypeBlockId None;
// The canonical empty block, reused to avoid allocating empty vectors. Always
// the 0-index block.
static const TypeBlockId Empty;
@@ -784,27 +673,19 @@ struct TypeBlockId : public IdBase<TypeBlockId> {
using IdBase::IdBase;
};
constexpr TypeBlockId TypeBlockId::None = TypeBlockId(NoneIndex);
constexpr TypeBlockId TypeBlockId::Empty = TypeBlockId(0);
// An index for element access, for structs, tuples, and classes.
struct ElementIndex : public IndexBase<ElementIndex> {
static constexpr llvm::StringLiteral Label = "element";
using IndexBase::IndexBase;
// An ID with no value.
static const ElementIndex None;
};
constexpr ElementIndex ElementIndex::None = ElementIndex(NoneIndex);
// The ID of a library name. This is either a string literal or `default`.
struct LibraryNameId : public IdBase<LibraryNameId> {
static constexpr llvm::StringLiteral Label = "library_name";
using DiagnosticType = DiagnosticTypeInfo<std::string>;
// An ID with no value.
static const LibraryNameId None;
// The name of `default`.
static const LibraryNameId Default;
// Track cases where the library name was set, but has been diagnosed and
@@ -825,7 +706,6 @@ struct LibraryNameId : public IdBase<LibraryNameId> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr LibraryNameId LibraryNameId::None = LibraryNameId(NoneIndex);
constexpr LibraryNameId LibraryNameId::Default = LibraryNameId(NoneIndex - 1);
constexpr LibraryNameId LibraryNameId::Error = LibraryNameId(NoneIndex - 2);
@@ -834,14 +714,9 @@ struct ImportIRInstId : public IdBase<ImportIRInstId> {
static constexpr llvm::StringLiteral Label = "import_ir_inst";
using ValueType = ImportIRInst;
// An ID with no value.
static const ImportIRInstId None;
using IdBase::IdBase;
};
constexpr ImportIRInstId ImportIRInstId::None = ImportIRInstId(NoneIndex);
// A SemIR location used as the location of instructions.
//
// Contents:
@@ -855,9 +730,6 @@ struct LocId : public IdBase<LocId> {
// operations performed implicitly.
static const int32_t ImplicitBit = 1 << 30;
// An ID with no value.
static const LocId None;
using IdBase::IdBase;
// NOLINTNEXTLINE(google-explicit-constructor)
@@ -909,8 +781,6 @@ struct LocId : public IdBase<LocId> {
auto Print(llvm::raw_ostream& out) const -> void;
};
constexpr LocId LocId::None = LocId(Parse::NodeId::None);
// Polymorphic id for fields in `Any[...]` typed instruction category. Used for
// fields where the specific instruction structs have different field types in
// that position or do not have a field in that position at all. Allows