From b8f61a712ec963ffe0b810f9338707baedc7e2d5 Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Tue, 10 Sep 2024 15:01:21 -0700 Subject: [PATCH] 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 --- toolchain/check/handle_class.cpp | 9 +++--- toolchain/check/handle_function.cpp | 21 ++++++-------- toolchain/check/keyword_modifier_set.h | 39 +++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index a1322474fc94..e6e6f505c8dd 100644 --- a/toolchain/check/handle_class.cpp +++ b/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() + .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(); diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 0064b9edf684..593f18efcb99 100644 --- a/toolchain/check/handle_function.cpp +++ b/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() + .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`. diff --git a/toolchain/check/keyword_modifier_set.h b/toolchain/check/keyword_modifier_set.h index 8a77c7784c95..1db89c3ec4f4 100644 --- a/toolchain/check/keyword_modifier_set.h +++ b/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 + #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() + // .Case(KeywordModifierSet::A, SomeEnum::A) + // .Case(KeywordModifierSet::B, SomeEnum::B) + // .Default(SomeEnum::DefaultValue); + // ``` + template + 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 result_; + }; + return Converter(*this); + } + // Returns the access kind from modifiers. auto GetAccessKind() -> SemIR::AccessKind { if (HasAnyOf(KeywordModifierSet::Protected)) {