diff --git a/toolchain/sem_ir/ids.cpp b/toolchain/sem_ir/ids.cpp index e809f512af47..555e6ef6b22a 100644 --- a/toolchain/sem_ir/ids.cpp +++ b/toolchain/sem_ir/ids.cpp @@ -77,6 +77,9 @@ auto IntKind::Print(llvm::raw_ostream& out) const -> void { } } +// Double-check the special value mapping and constexpr evaluation. +static_assert(NameId::SpecialNameId::Vptr == *NameId::Vptr.AsSpecialNameId()); + auto NameId::ForIdentifier(IdentifierId id) -> NameId { if (id.index >= 0) { return NameId(id.index); @@ -105,25 +108,16 @@ auto NameId::Print(llvm::raw_ostream& out) const -> void { return; } out << Label << "("; - if (*this == Base) { - out << "Base"; - } else if (*this == Core) { - out << "Core"; - } else if (*this == PackageNamespace) { - out << "PackageNamespace"; - } else if (*this == PeriodSelf) { - out << "PeriodSelf"; - } else if (*this == ReturnSlot) { - out << "ReturnSlot"; - } else if (*this == SelfType) { - out << "SelfType"; - } else if (*this == SelfValue) { - out << "SelfValue"; - } else if (*this == Vptr) { - out << "Vptr"; - } else { - CARBON_FATAL("Unknown index {0}", index); - IdBase::Print(out); + auto special_name_id = AsSpecialNameId(); + CARBON_CHECK(special_name_id, "Unknown index {0}", index); + + switch (*special_name_id) { +#define CARBON_SPECIAL_NAME_ID_FOR_PRINT(Name) \ + case SpecialNameId::Name: \ + out << #Name; \ + break; + CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_PRINT) +#undef CARBON_SPECIAL_NAME_ID_FOR_PRINT } out << ")"; } diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 3711937e0b39..b4e0a9b6667c 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -481,6 +481,31 @@ struct FloatKind : public IdBase { auto Print(llvm::raw_ostream& out) const -> void { out << "float"; } }; +// An X-macro for special names. Uses should look like: +// +// #define CARBON_SPECIAL_NAME_ID_FOR_XYZ(Name) ... +// CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_XYZ) +// #undef CARBON_SPECIAL_NAME_ID_FOR_XYZ +#define CARBON_SPECIAL_NAME_ID(X) \ + /* The name of `base`. */ \ + X(Base) \ + /* The name of the discriminant field (if any) in a choice. */ \ + X(ChoiceDiscriminant) \ + /* The name of the package `Core`. */ \ + X(Core) \ + /* The name of `package`. */ \ + X(PackageNamespace) \ + /* The name of `.Self`. */ \ + X(PeriodSelf) \ + /* The name of the return slot in a function. */ \ + X(ReturnSlot) \ + /* The name of `Self`. */ \ + X(SelfType) \ + /* The name of `self`. */ \ + X(SelfValue) \ + /* The name of `vptr`. */ \ + X(Vptr) + // The ID of a name. A name is either a string or a special name such as // `self`, `Self`, or `base`. struct NameId : public IdBase { @@ -491,24 +516,19 @@ struct NameId : public IdBase { // An ID with no value. static const NameId None; - // The name of `base`. - static const NameId Base; - // The name of the package `Core`. - static const NameId Core; - // The name of `package`. - static const NameId PackageNamespace; - // The name of `.Self`. - static const NameId PeriodSelf; - // The name of the return slot in a function. - static const NameId ReturnSlot; - // The name of `Self`. - static const NameId SelfType; - // The name of `self`. - static const NameId SelfValue; - // The name of `vptr`. - static const NameId Vptr; - // The name of the discriminant field (if any) in a choice. - static const NameId ChoiceDiscriminant; + + // An enum of special names. + enum class SpecialNameId : uint8_t { +#define CARBON_SPECIAL_NAME_ID_FOR_ENUM(Name) Name, + CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_ENUM) +#undef CARBON_SPECIAL_NAME_ID_FOR_ENUM + }; + + // For each SpecialNameId, provide a matching `NameId` instance for + // convenience. +#define CARBON_SPECIAL_NAME_ID_FOR_DECL(Name) static const NameId Name; + CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_DECL) +#undef CARBON_SPECIAL_NAME_ID_FOR_DECL // The number of non-index (<0) that exist, and will need storage in name // lookup. @@ -529,22 +549,31 @@ struct NameId : public IdBase { return index >= 0 ? IdentifierId(index) : IdentifierId::None; } + // Expose special names for `switch`. + constexpr auto AsSpecialNameId() const -> std::optional { + if (index >= NoneIndex) { + return std::nullopt; + } + return static_cast(NoneIndex - 1 - index); + } + auto Print(llvm::raw_ostream& out) const -> void; }; constexpr NameId NameId::None = NameId(NoneIndex); -constexpr NameId NameId::Base = NameId(NoneIndex - 1); -constexpr NameId NameId::Core = NameId(NoneIndex - 2); -constexpr NameId NameId::PackageNamespace = NameId(NoneIndex - 3); -constexpr NameId NameId::PeriodSelf = NameId(NoneIndex - 4); -constexpr NameId NameId::ReturnSlot = NameId(NoneIndex - 5); -constexpr NameId NameId::SelfType = NameId(NoneIndex - 6); -constexpr NameId NameId::SelfValue = NameId(NoneIndex - 7); -constexpr NameId NameId::Vptr = NameId(NoneIndex - 8); -constexpr NameId NameId::ChoiceDiscriminant = NameId(NoneIndex - 9); -constexpr int NameId::NonIndexValueCount = 10; -// Enforce the link between SpecialValueCount and the last special value. -static_assert(NameId::NonIndexValueCount == -NameId::ChoiceDiscriminant.index); + +// Define the special `static const NameId` values. +#define CARBON_SPECIAL_NAME_ID_FOR_DEF(Name) \ + constexpr NameId NameId::Name = \ + NameId(NoneIndex - 1 - static_cast(NameId::SpecialNameId::Name)); +CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_DEF) +#undef CARBON_SPECIAL_NAME_ID_FOR_DEF + +// Count non-index values, including `None` and special names. +#define CARBON_SPECIAL_NAME_ID_FOR_COUNT(...) +1 +constexpr int NameId::NonIndexValueCount = + 1 CARBON_SPECIAL_NAME_ID(CARBON_SPECIAL_NAME_ID_FOR_COUNT); +#undef CARBON_SPECIAL_NAME_ID_FOR_COUNT // The ID of a name scope. struct NameScopeId : public IdBase { diff --git a/toolchain/sem_ir/name.cpp b/toolchain/sem_ir/name.cpp index d51a224f6ee5..9484e7993798 100644 --- a/toolchain/sem_ir/name.cpp +++ b/toolchain/sem_ir/name.cpp @@ -10,29 +10,31 @@ namespace Carbon::SemIR { // Get the spelling to use for a special name. static auto GetSpecialName(NameId name_id, bool for_ir) -> llvm::StringRef { - switch (name_id.index) { - case NameId::None.index: - return for_ir ? "" : ""; - case NameId::Base.index: + if (name_id == NameId::None) { + return for_ir ? "" : ""; + } + + auto special_name_id = name_id.AsSpecialNameId(); + CARBON_CHECK(special_name_id, "Not a special name"); + switch (*special_name_id) { + case NameId::SpecialNameId::Base: return "base"; - case NameId::Core.index: - return "Core"; - case NameId::PeriodSelf.index: - return ".Self"; - case NameId::ReturnSlot.index: - return for_ir ? "return" : ""; - case NameId::PackageNamespace.index: - return "package"; - case NameId::SelfType.index: - return "Self"; - case NameId::SelfValue.index: - return "self"; - case NameId::Vptr.index: - return for_ir ? "vptr" : ""; - case NameId::ChoiceDiscriminant.index: + case NameId::SpecialNameId::ChoiceDiscriminant: return "discriminant"; - default: - CARBON_FATAL("Unknown special name"); + case NameId::SpecialNameId::Core: + return "Core"; + case NameId::SpecialNameId::PackageNamespace: + return "package"; + case NameId::SpecialNameId::PeriodSelf: + return ".Self"; + case NameId::SpecialNameId::ReturnSlot: + return for_ir ? "return" : ""; + case NameId::SpecialNameId::SelfType: + return "Self"; + case NameId::SpecialNameId::SelfValue: + return "self"; + case NameId::SpecialNameId::Vptr: + return for_ir ? "vptr" : ""; } }