Просмотр исходного кода

Use an x-macro for special NameId values. (#5018)

Doing an in-file X-macro, though maybe we'll want to move it out to a
#include if we keep piling on more. I know there's `destroy` to add, and
possibly `copy` and `move`, but I don't know what threshold we'll want
for a separate file.

Note this does set up for an advantage where we can `switch` instead of
repeated `if` for special names, shifting to compile errors for new
values.

I also considered a simpler enum approach (with an implicit conversion
to `NameId`) but that runs into issues with things like
`Id::Kind::For<...>` as a consequence of calls like `name_id ==
special_name_id` (just requires another `operator==`) and
`context.node_stack().Push(node_id, SemIR::NameId::SelfType);` (a little
more complex how we'd want to handle it).
Jon Ross-Perkins 1 год назад
Родитель
Сommit
9d85b23b4b
3 измененных файлов с 90 добавлено и 65 удалено
  1. 13 19
      toolchain/sem_ir/ids.cpp
  2. 59 30
      toolchain/sem_ir/ids.h
  3. 18 16
      toolchain/sem_ir/name.cpp

+ 13 - 19
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 << ")";
 }

+ 59 - 30
toolchain/sem_ir/ids.h

@@ -481,6 +481,31 @@ struct FloatKind : public IdBase<FloatKind> {
   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<NameId> {
@@ -491,24 +516,19 @@ struct NameId : public IdBase<NameId> {
 
   // 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<NameId> {
     return index >= 0 ? IdentifierId(index) : IdentifierId::None;
   }
 
+  // Expose special names for `switch`.
+  constexpr auto AsSpecialNameId() const -> std::optional<SpecialNameId> {
+    if (index >= NoneIndex) {
+      return std::nullopt;
+    }
+    return static_cast<SpecialNameId>(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<int>(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<NameScopeId> {

+ 18 - 16
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 ? "" : "<none>";
-    case NameId::Base.index:
+  if (name_id == NameId::None) {
+    return for_ir ? "" : "<none>";
+  }
+
+  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:
+    case NameId::SpecialNameId::ChoiceDiscriminant:
+      return "discriminant";
+    case NameId::SpecialNameId::Core:
       return "Core";
-    case NameId::PeriodSelf.index:
+    case NameId::SpecialNameId::PackageNamespace:
+      return "package";
+    case NameId::SpecialNameId::PeriodSelf:
       return ".Self";
-    case NameId::ReturnSlot.index:
+    case NameId::SpecialNameId::ReturnSlot:
       return for_ir ? "return" : "<return slot>";
-    case NameId::PackageNamespace.index:
-      return "package";
-    case NameId::SelfType.index:
+    case NameId::SpecialNameId::SelfType:
       return "Self";
-    case NameId::SelfValue.index:
+    case NameId::SpecialNameId::SelfValue:
       return "self";
-    case NameId::Vptr.index:
+    case NameId::SpecialNameId::Vptr:
       return for_ir ? "vptr" : "<vptr>";
-    case NameId::ChoiceDiscriminant.index:
-      return "discriminant";
-    default:
-      CARBON_FATAL("Unknown special name");
   }
 }