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

Add KeywordModifierSet helper for conversion to (likely SemIR) enums (#4290)

(based on
https://github.com/carbon-language/carbon-lang/pull/4272#discussion_r1751001345)

Could haggle over the name "ToEnum" probably avoids the debate over
"enumeration" (the type being returned) v "enumerator" (the value being
returned)

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
David Blaikie 1 год назад
Родитель
Сommit
b8f61a712e

+ 4 - 5
toolchain/check/handle_class.cpp

@@ -201,11 +201,10 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
     context.TODO(node_id, "extern library");
   }
   auto inheritance_kind =
-      introducer.modifier_set.HasAnyOf(KeywordModifierSet::Abstract)
-          ? SemIR::Class::Abstract
-      : introducer.modifier_set.HasAnyOf(KeywordModifierSet::Base)
-          ? SemIR::Class::Base
-          : SemIR::Class::Final;
+      introducer.modifier_set.ToEnum<SemIR::Class::InheritanceKind>()
+          .Case(KeywordModifierSet::Abstract, SemIR::Class::Abstract)
+          .Case(KeywordModifierSet::Base, SemIR::Class::Base)
+          .Default(SemIR::Class::Final);
 
   auto decl_block_id = context.inst_block_stack().Pop();
 

+ 9 - 12
toolchain/check/handle_function.cpp

@@ -194,18 +194,15 @@ static auto BuildFunctionDecl(Context& context,
   DiagnoseModifiers(context, introducer, is_definition, parent_scope_inst_id,
                     parent_scope_inst);
   bool is_extern = introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extern);
-  SemIR::FunctionFields::VirtualModifier virtual_modifier =
-      SemIR::FunctionFields::VirtualModifier::None;
-
-  if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Virtual)) {
-    virtual_modifier = SemIR::FunctionFields::VirtualModifier::Virtual;
-  }
-  if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Abstract)) {
-    virtual_modifier = SemIR::FunctionFields::VirtualModifier::Abstract;
-  }
-  if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Impl)) {
-    virtual_modifier = SemIR::FunctionFields::VirtualModifier::Impl;
-  }
+  auto virtual_modifier =
+      introducer.modifier_set.ToEnum<SemIR::Function::VirtualModifier>()
+          .Case(KeywordModifierSet::Virtual,
+                SemIR::Function::VirtualModifier::Virtual)
+          .Case(KeywordModifierSet::Abstract,
+                SemIR::Function::VirtualModifier::Abstract)
+          .Case(KeywordModifierSet::Impl,
+                SemIR::Function::VirtualModifier::Impl)
+          .Default(SemIR::Function::VirtualModifier::None);
   if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Interface)) {
     // TODO: Once we are saving the modifiers for a function, add check that
     // the function may only be defined if it is marked `default` or `final`.

+ 38 - 1
toolchain/check/keyword_modifier_set.h

@@ -5,6 +5,8 @@
 #ifndef CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
 #define CARBON_TOOLCHAIN_CHECK_KEYWORD_MODIFIER_SET_H_
 
+#include <optional>
+
 #include "llvm/ADT/BitmaskEnum.h"
 #include "toolchain/sem_ir/name_scope.h"
 
@@ -70,10 +72,45 @@ class KeywordModifierSet {
   auto Remove(KeywordModifierSet set) -> void { set_ &= ~set.set_; }
 
   // Returns true if there's a non-empty set intersection.
-  constexpr auto HasAnyOf(KeywordModifierSet other) -> bool {
+  constexpr auto HasAnyOf(KeywordModifierSet other) const -> bool {
     return set_ & other.set_;
   }
 
+  // Return a builder that returns the new enumeration type once a series of
+  // mapping `Case`s and a final `Default` are provided. For example:
+  //   ```
+  //   auto e = set.ToEnum<SomeEnum>()
+  //                .Case(KeywordModifierSet::A, SomeEnum::A)
+  //                .Case(KeywordModifierSet::B, SomeEnum::B)
+  //                .Default(SomeEnum::DefaultValue);
+  //   ```
+  template <typename T>
+  auto ToEnum() -> auto {
+    class Converter {
+     public:
+      Converter(const KeywordModifierSet& set) : set_(set) {}
+
+      auto Case(RawEnumType raw_enumerator, T result) -> Converter& {
+        if (set_.HasAnyOf(raw_enumerator)) {
+          result_ = result;
+        }
+        return *this;
+      }
+
+      auto Default(T default_value) -> T {
+        if (result_) {
+          return *result_;
+        }
+        return default_value;
+      }
+
+     private:
+      const KeywordModifierSet& set_;
+      std::optional<T> result_;
+    };
+    return Converter(*this);
+  }
+
   // Returns the access kind from modifiers.
   auto GetAccessKind() -> SemIR::AccessKind {
     if (HasAnyOf(KeywordModifierSet::Protected)) {