From a910eda020c4e8b06fdb9f0d8425f54eb1ee2fa0 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Tue, 4 Jun 2024 16:12:12 -0700 Subject: [PATCH] Switch decl_state to an arg for modifier functions (#4027) With private modifiers, we'll want to start checking modifiers later, e.g. after a name conflict is detected (and potentially merged). I think we've agreed to be more explicit about whether the modifier functions are manipulating state, versus trying to keep the state on the stack a little longer (moving Pop to the end of these functions). Removing FileScope from the stack and renaming it to DeclIntroducerStack to better reflect the usage and behavior. The FileScope mostly reflects an approach that wasn't ultimately adopted. --- toolchain/check/BUILD | 2 +- toolchain/check/context.h | 8 ++- .../{decl_state.h => decl_introducer_state.h} | 42 +++++++------- toolchain/check/handle_alias.cpp | 13 ++--- toolchain/check/handle_class.cpp | 50 +++++++++-------- toolchain/check/handle_export.cpp | 7 ++- toolchain/check/handle_function.cpp | 48 ++++++++-------- toolchain/check/handle_impl.cpp | 14 ++--- toolchain/check/handle_import_and_package.cpp | 25 +++++---- toolchain/check/handle_interface.cpp | 15 +++-- toolchain/check/handle_let.cpp | 24 ++++---- toolchain/check/handle_loop_statement.cpp | 2 +- toolchain/check/handle_modifier.cpp | 4 +- toolchain/check/handle_namespace.cpp | 11 ++-- toolchain/check/handle_variable.cpp | 17 +++--- toolchain/check/modifiers.cpp | 56 +++++++++++-------- toolchain/check/modifiers.h | 28 ++++++---- 17 files changed, 192 insertions(+), 174 deletions(-) rename toolchain/check/{decl_state.h => decl_introducer_state.h} (61%) diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index faff4877731a..6a780721d3d4 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -66,8 +66,8 @@ cc_library( hdrs = [ "context.h", "convert.h", + "decl_introducer_state.h", "decl_name_stack.h", - "decl_state.h", "diagnostic_helpers.h", "eval.h", "function.h", diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 95276d19a062..5847a72690a1 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -8,8 +8,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" +#include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/decl_name_stack.h" -#include "toolchain/check/decl_state.h" #include "toolchain/check/diagnostic_helpers.h" #include "toolchain/check/inst_block_stack.h" #include "toolchain/check/node_stack.h" @@ -335,7 +335,9 @@ class Context { auto decl_name_stack() -> DeclNameStack& { return decl_name_stack_; } - auto decl_state_stack() -> DeclStateStack& { return decl_state_stack_; } + auto decl_introducer_state_stack() -> DeclIntroducerStateStack& { + return decl_introducer_state_stack_; + } auto scope_stack() -> ScopeStack& { return scope_stack_; } @@ -447,7 +449,7 @@ class Context { DeclNameStack decl_name_stack_; // The stack of declarations that could have modifiers. - DeclStateStack decl_state_stack_; + DeclIntroducerStateStack decl_introducer_state_stack_; // The stack of scopes we are currently within. ScopeStack scope_stack_; diff --git a/toolchain/check/decl_state.h b/toolchain/check/decl_introducer_state.h similarity index 61% rename from toolchain/check/decl_state.h rename to toolchain/check/decl_introducer_state.h index ec64086b1ded..0816db2ca13d 100644 --- a/toolchain/check/decl_state.h +++ b/toolchain/check/decl_introducer_state.h @@ -2,20 +2,20 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_CHECK_DECL_STATE_H_ -#define CARBON_TOOLCHAIN_CHECK_DECL_STATE_H_ +#ifndef CARBON_TOOLCHAIN_CHECK_DECL_INTRODUCER_STATE_H_ +#define CARBON_TOOLCHAIN_CHECK_DECL_INTRODUCER_STATE_H_ #include "toolchain/check/keyword_modifier_set.h" #include "toolchain/parse/node_ids.h" namespace Carbon::Check { -// State stored for each declaration we are currently in: the kind of -// declaration and the keyword modifiers that apply to that declaration. -struct DeclState { +// State stored for each declaration we are introducing: the kind of +// declaration and the keyword modifiers that apply to that declaration +// introducer. +struct DeclIntroducerState { // The kind of declaration. enum DeclKind : int8_t { - FileScope, Adapt, Alias, Base, @@ -32,7 +32,7 @@ struct DeclState { Var }; - explicit DeclState(DeclKind decl_kind) : kind(decl_kind) {} + explicit DeclIntroducerState(DeclKind decl_kind) : kind(decl_kind) {} auto modifier_node_id(ModifierOrder order) -> Parse::NodeId { return ordered_modifier_node_ids[static_cast(order)]; @@ -55,32 +55,30 @@ struct DeclState { KeywordModifierSet modifier_set; }; -// Stack of `DeclState` values, representing all the declarations we are -// currently nested within. -// Invariant: Bottom of the stack always has a "DeclState::FileScope" entry. -class DeclStateStack { +// Stack of `DeclIntroducerState` values, representing all the declaration +// introducers we are currently nested within. Commonly size 0 or 1, as nested +// introducers are rare. +class DeclIntroducerStateStack { public: - DeclStateStack() { stack_.emplace_back(DeclState::FileScope); } - - // Enters a declaration of kind `k`. - auto Push(DeclState::DeclKind k) -> void { stack_.emplace_back(k); } + // Begins introducing a declaration of kind `k`. + auto Push(DeclIntroducerState::DeclKind k) -> void { stack_.emplace_back(k); } // Gets the state of declaration at the top of the stack -- the innermost // declaration currently being processed. - auto innermost() -> DeclState& { return stack_.back(); } + auto innermost() -> DeclIntroducerState& { return stack_.back(); } - // Exits a declaration of kind `k`. - auto Pop(DeclState::DeclKind k) -> void { + // Finishes introducing a declaration of kind `k` and returns the + // produced state. + auto Pop(DeclIntroducerState::DeclKind k) -> DeclIntroducerState { CARBON_CHECK(stack_.back().kind == k) << "Found: " << stack_.back().kind << " expected: " << k; - stack_.pop_back(); - CARBON_CHECK(!stack_.empty()); + return stack_.pop_back_val(); } private: - llvm::SmallVector stack_; + llvm::SmallVector stack_; }; } // namespace Carbon::Check -#endif // CARBON_TOOLCHAIN_CHECK_DECL_STATE_H_ +#endif // CARBON_TOOLCHAIN_CHECK_DECL_INTRODUCER_STATE_H_ diff --git a/toolchain/check/handle_alias.cpp b/toolchain/check/handle_alias.cpp index 66cb7642898c..32e27dae312b 100644 --- a/toolchain/check/handle_alias.cpp +++ b/toolchain/check/handle_alias.cpp @@ -14,7 +14,7 @@ namespace Carbon::Check { auto HandleAliasIntroducer(Context& context, Parse::AliasIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::Alias); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Alias); context.decl_name_stack().PushScopeAndStartName(); return true; } @@ -30,15 +30,14 @@ auto HandleAlias(Context& context, Parse::AliasId /*node_id*/) -> bool { auto name_context = context.decl_name_stack().FinishName( PopNameComponentWithoutParams(context, Lex::TokenKind::Alias)); - LimitModifiersOnDecl(context, KeywordModifierSet::Access, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Alias); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access, Lex::TokenKind::Alias); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - context.decl_state_stack().Pop(DeclState::Alias); auto bind_name_id = context.bind_names().Add( {.name_id = name_context.name_id_for_new_inst(), diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index ffe481438f8a..bd9c50c09977 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -36,7 +36,7 @@ auto HandleClassIntroducer(Context& context, Parse::ClassIntroducerId node_id) // Push the bracketing node. context.node_stack().Push(node_id); // Optional modifiers and the name follow. - context.decl_state_stack().Push(DeclState::Class); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Class); context.decl_name_stack().PushScopeAndStartName(); return true; } @@ -187,28 +187,30 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id, // Process modifiers. auto [_, parent_scope_inst] = context.name_scopes().GetInstIfValid(name_context.parent_scope_id); - CheckAccessModifiersOnDecl(context, Lex::TokenKind::Class, parent_scope_inst); - LimitModifiersOnDecl(context, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Class); + CheckAccessModifiersOnDecl(context, introducer, Lex::TokenKind::Class, + parent_scope_inst); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Class | KeywordModifierSet::Access | KeywordModifierSet::Extern, Lex::TokenKind::Class); - RestrictExternModifierOnDecl(context, Lex::TokenKind::Class, + RestrictExternModifierOnDecl(context, introducer, Lex::TokenKind::Class, parent_scope_inst, is_definition); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - bool is_extern = modifiers.HasAnyOf(KeywordModifierSet::Extern); + bool is_extern = introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extern); auto inheritance_kind = - modifiers.HasAnyOf(KeywordModifierSet::Abstract) ? SemIR::Class::Abstract - : modifiers.HasAnyOf(KeywordModifierSet::Base) ? SemIR::Class::Base - : SemIR::Class::Final; + introducer.modifier_set.HasAnyOf(KeywordModifierSet::Abstract) + ? SemIR::Class::Abstract + : introducer.modifier_set.HasAnyOf(KeywordModifierSet::Base) + ? SemIR::Class::Base + : SemIR::Class::Final; - context.decl_state_stack().Pop(DeclState::Class); auto decl_block_id = context.inst_block_stack().Pop(); // Add the class declaration. @@ -355,7 +357,7 @@ static auto DiagnoseClassSpecificDeclRepeated(Context& context, auto HandleAdaptIntroducer(Context& context, Parse::AdaptIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::Adapt); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Adapt); return true; } @@ -364,10 +366,10 @@ auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool { context.node_stack().PopExprWithNodeId(); // Process modifiers. `extend` is permitted, no others are allowed. - LimitModifiersOnDecl(context, KeywordModifierSet::Extend, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Adapt); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend, Lex::TokenKind::Adapt); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - context.decl_state_stack().Pop(DeclState::Adapt); auto parent_class_decl = GetCurrentScopeAsClassOrDiagnose(context, node_id, Lex::TokenKind::Adapt); @@ -396,7 +398,7 @@ auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool { node_id, {.adapted_type_id = adapted_type_id}); // Extend the class scope with the adapted type's scope if requested. - if (modifiers.HasAnyOf(KeywordModifierSet::Extend)) { + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { auto extended_scope_id = SemIR::NameScopeId::Invalid; if (adapted_type_id == SemIR::TypeId::Error) { // Recover by not extending any scope. We instead set has_error to true @@ -423,7 +425,7 @@ auto HandleAdaptDecl(Context& context, Parse::AdaptDeclId node_id) -> bool { auto HandleBaseIntroducer(Context& context, Parse::BaseIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::Base); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Base); return true; } @@ -495,15 +497,15 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool { context.node_stack().PopExprWithNodeId(); // Process modifiers. `extend` is required, no others are allowed. - LimitModifiersOnDecl(context, KeywordModifierSet::Extend, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Base); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Extend, Lex::TokenKind::Base); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (!modifiers.HasAnyOf(KeywordModifierSet::Extend)) { + if (!introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { CARBON_DIAGNOSTIC(BaseMissingExtend, Error, "Missing `extend` before `base` declaration in class."); context.emitter().Emit(node_id, BaseMissingExtend); } - context.decl_state_stack().Pop(DeclState::Base); auto parent_class_decl = GetCurrentScopeAsClassOrDiagnose(context, node_id, Lex::TokenKind::Base); @@ -546,7 +548,7 @@ auto HandleBaseDecl(Context& context, Parse::BaseDeclId node_id) -> bool { class_info.base_id); // Extend the class scope with the base class. - if (modifiers.HasAnyOf(KeywordModifierSet::Extend)) { + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { auto& class_scope = context.name_scopes().Get(class_info.scope_id); if (base_info.scope_id.is_valid()) { class_scope.extended_scopes.push_back(base_info.scope_id); diff --git a/toolchain/check/handle_export.cpp b/toolchain/check/handle_export.cpp index fff79f45f29c..0d79ab28b8ef 100644 --- a/toolchain/check/handle_export.cpp +++ b/toolchain/check/handle_export.cpp @@ -15,7 +15,7 @@ namespace Carbon::Check { auto HandleExportIntroducer(Context& context, Parse::ExportIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::Export); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Export); // TODO: Probably need to update DeclNameStack to restrict to only namespaces. context.decl_name_stack().PushScopeAndStartName(); return true; @@ -26,9 +26,10 @@ auto HandleExportDecl(Context& context, Parse::ExportDeclId node_id) -> bool { PopNameComponentWithoutParams(context, Lex::TokenKind::Export)); context.decl_name_stack().PopScope(); - LimitModifiersOnDecl(context, KeywordModifierSet::None, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Export); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::None, Lex::TokenKind::Export); - context.decl_state_stack().Pop(DeclState::Export); if (name_context.state == DeclNameStack::NameContext::State::Error) { // Should already be diagnosed. diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 02144ca85d1f..05437ffe86d2 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -5,8 +5,8 @@ #include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/convert.h" +#include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/decl_name_stack.h" -#include "toolchain/check/decl_state.h" #include "toolchain/check/function.h" #include "toolchain/check/handle.h" #include "toolchain/check/interface.h" @@ -30,7 +30,7 @@ auto HandleFunctionIntroducer(Context& context, // Push the bracketing node. context.node_stack().Push(node_id); // Optional modifiers and the name follow. - context.decl_state_stack().Push(DeclState::Fn); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Fn); context.decl_name_stack().PushScopeAndStartName(); return true; } @@ -45,24 +45,24 @@ auto HandleReturnType(Context& context, Parse::ReturnTypeId node_id) -> bool { return true; } -static auto DiagnoseModifiers(Context& context, bool is_definition, +static auto DiagnoseModifiers(Context& context, DeclIntroducerState& introducer, + bool is_definition, SemIR::InstId parent_scope_inst_id, std::optional parent_scope_inst) - -> KeywordModifierSet { - CheckAccessModifiersOnDecl(context, Lex::TokenKind::Fn, parent_scope_inst); - LimitModifiersOnDecl(context, + -> void { + CheckAccessModifiersOnDecl(context, introducer, Lex::TokenKind::Fn, + parent_scope_inst); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access | KeywordModifierSet::Extern | KeywordModifierSet::Method | KeywordModifierSet::Interface, Lex::TokenKind::Fn); - RestrictExternModifierOnDecl(context, Lex::TokenKind::Fn, parent_scope_inst, - is_definition); - CheckMethodModifiersOnFunction(context, parent_scope_inst_id, + RestrictExternModifierOnDecl(context, introducer, Lex::TokenKind::Fn, + parent_scope_inst, is_definition); + CheckMethodModifiersOnFunction(context, introducer, parent_scope_inst_id, parent_scope_inst); - RequireDefaultFinalOnlyInInterfaces(context, Lex::TokenKind::Fn, + RequireDefaultFinalOnlyInInterfaces(context, introducer, Lex::TokenKind::Fn, parent_scope_inst); - - return context.decl_state_stack().innermost().modifier_set; } // Returns the return slot usage for a function given the computed usage for two @@ -227,27 +227,25 @@ static auto BuildFunctionDecl(Context& context, // Process modifiers. auto [parent_scope_inst_id, parent_scope_inst] = context.name_scopes().GetInstIfValid(name_context.parent_scope_id); - auto modifiers = DiagnoseModifiers(context, is_definition, - parent_scope_inst_id, parent_scope_inst); - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Fn); + DiagnoseModifiers(context, introducer, is_definition, parent_scope_inst_id, + parent_scope_inst); + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - bool is_extern = modifiers.HasAnyOf(KeywordModifierSet::Extern); - if (modifiers.HasAnyOf(KeywordModifierSet::Method)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Decl), + bool is_extern = introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extern); + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Method)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Decl), "method modifier"); } - if (modifiers.HasAnyOf(KeywordModifierSet::Interface)) { + 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`. - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Decl), + context.TODO(introducer.modifier_node_id(ModifierOrder::Decl), "interface modifier"); } - context.decl_state_stack().Pop(DeclState::Fn); // Add the function declaration. auto function_decl = SemIR::FunctionDecl{ diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index 4cc02b251a8d..59d8cd9fe308 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -24,7 +24,7 @@ auto HandleImplIntroducer(Context& context, Parse::ImplIntroducerId node_id) context.node_stack().Push(node_id); // Optional modifiers follow. - context.decl_state_stack().Push(DeclState::Impl); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Impl); // An impl doesn't have a name per se, but it makes the processing more // consistent to imagine that it does. This also gives us a scope for implicit @@ -192,7 +192,9 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id) // Process modifiers. // TODO: Should we somehow permit access specifiers on `impl`s? // TODO: Handle `final` modifier. - LimitModifiersOnDecl(context, KeywordModifierSet::ImplDecl, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Impl); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::ImplDecl, Lex::TokenKind::Impl); // Finish processing the name, which should be empty, but might have @@ -214,16 +216,12 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id) auto impl_decl_id = context.AddInst(node_id, impl_decl); // For an `extend impl` declaration, mark the impl as extending this `impl`. - if (context.decl_state_stack().innermost().modifier_set.HasAnyOf( - KeywordModifierSet::Extend)) { - auto extend_node = context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Decl); + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { + auto extend_node = introducer.modifier_node_id(ModifierOrder::Decl); ExtendImpl(context, extend_node, node_id, self_type_node, self_type_id, params_node, constraint_type_id); } - context.decl_state_stack().Pop(DeclState::Impl); - return {impl_decl.impl_id, impl_decl_id}; } diff --git a/toolchain/check/handle_import_and_package.cpp b/toolchain/check/handle_import_and_package.cpp index 883c71a4cf74..bf3618d4722d 100644 --- a/toolchain/check/handle_import_and_package.cpp +++ b/toolchain/check/handle_import_and_package.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/check/context.h" -#include "toolchain/check/decl_state.h" +#include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/handle.h" #include "toolchain/check/modifiers.h" @@ -14,43 +14,48 @@ namespace Carbon::Check { auto HandleImportIntroducer(Context& context, Parse::ImportIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::Import); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Import); return true; } auto HandleImportDecl(Context& context, Parse::ImportDeclId /*node_id*/) -> bool { - LimitModifiersOnDecl(context, KeywordModifierSet::Export, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Import); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Export, Lex::TokenKind::Import); - context.decl_state_stack().Pop(DeclState::Import); return true; } auto HandleLibraryIntroducer(Context& context, Parse::LibraryIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::PackageOrLibrary); + context.decl_introducer_state_stack().Push( + DeclIntroducerState::PackageOrLibrary); return true; } auto HandleLibraryDecl(Context& context, Parse::LibraryDeclId /*node_id*/) -> bool { - LimitModifiersOnDecl(context, KeywordModifierSet::Impl, + auto introducer = context.decl_introducer_state_stack().Pop( + DeclIntroducerState::PackageOrLibrary); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Impl, Lex::TokenKind::Library); - context.decl_state_stack().Pop(DeclState::PackageOrLibrary); return true; } auto HandlePackageIntroducer(Context& context, Parse::PackageIntroducerId /*node_id*/) -> bool { - context.decl_state_stack().Push(DeclState::PackageOrLibrary); + context.decl_introducer_state_stack().Push( + DeclIntroducerState::PackageOrLibrary); return true; } auto HandlePackageDecl(Context& context, Parse::PackageDeclId /*node_id*/) -> bool { - LimitModifiersOnDecl(context, KeywordModifierSet::Impl, + auto introducer = context.decl_introducer_state_stack().Pop( + DeclIntroducerState::PackageOrLibrary); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Impl, Lex::TokenKind::Package); - context.decl_state_stack().Pop(DeclState::PackageOrLibrary); return true; } diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 139976c81180..e4dafdcbd9f0 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -19,7 +19,7 @@ auto HandleInterfaceIntroducer(Context& context, // Push the bracketing node. context.node_stack().Push(node_id); // Optional modifiers and the name follow. - context.decl_state_stack().Push(DeclState::Interface); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Interface); context.decl_name_stack().PushScopeAndStartName(); return true; } @@ -39,18 +39,17 @@ static auto BuildInterfaceDecl(Context& context, // Process modifiers. auto [_, parent_scope_inst] = context.name_scopes().GetInstIfValid(name_context.parent_scope_id); - CheckAccessModifiersOnDecl(context, Lex::TokenKind::Interface, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Interface); + CheckAccessModifiersOnDecl(context, introducer, Lex::TokenKind::Interface, parent_scope_inst); - LimitModifiersOnDecl(context, KeywordModifierSet::Access, + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access, Lex::TokenKind::Interface); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - context.decl_state_stack().Pop(DeclState::Interface); auto decl_block_id = context.inst_block_stack().Pop(); diff --git a/toolchain/check/handle_let.cpp b/toolchain/check/handle_let.cpp index 491ac968ac0d..54bca1a57dfa 100644 --- a/toolchain/check/handle_let.cpp +++ b/toolchain/check/handle_let.cpp @@ -15,7 +15,7 @@ namespace Carbon::Check { auto HandleLetIntroducer(Context& context, Parse::LetIntroducerId node_id) -> bool { - context.decl_state_stack().Push(DeclState::Let); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Let); // Push a bracketing node to establish the pattern context. context.node_stack().Push(node_id); return true; @@ -82,25 +82,25 @@ auto HandleLetDecl(Context& context, Parse::LetDeclId node_id) -> bool { auto [parent_scope_inst_id, parent_scope_inst] = context.name_scopes().GetInstIfValid( context.scope_stack().PeekNameScopeId()); - CheckAccessModifiersOnDecl(context, Lex::TokenKind::Let, parent_scope_inst); - RequireDefaultFinalOnlyInInterfaces(context, Lex::TokenKind::Let, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Let); + CheckAccessModifiersOnDecl(context, introducer, Lex::TokenKind::Let, + parent_scope_inst); + RequireDefaultFinalOnlyInInterfaces(context, introducer, Lex::TokenKind::Let, parent_scope_inst); LimitModifiersOnDecl( - context, KeywordModifierSet::Access | KeywordModifierSet::Interface, + context, introducer, + KeywordModifierSet::Access | KeywordModifierSet::Interface, Lex::TokenKind::Let); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - if (modifiers.HasAnyOf(KeywordModifierSet::Interface)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Decl), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Interface)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Decl), "interface modifier"); } - context.decl_state_stack().Pop(DeclState::Let); auto pattern = context.insts().GetWithLocId(pattern_id); auto interface_scope = context.GetCurrentScopeAs(); diff --git a/toolchain/check/handle_loop_statement.cpp b/toolchain/check/handle_loop_statement.cpp index 57de7dd004a6..afa0d93dadb1 100644 --- a/toolchain/check/handle_loop_statement.cpp +++ b/toolchain/check/handle_loop_statement.cpp @@ -77,7 +77,7 @@ auto HandleForHeaderStart(Context& context, Parse::ForHeaderStartId node_id) } auto HandleForIn(Context& context, Parse::ForInId node_id) -> bool { - context.decl_state_stack().Pop(DeclState::Var); + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Var); return context.TODO(node_id, "HandleForIn"); } diff --git a/toolchain/check/handle_modifier.cpp b/toolchain/check/handle_modifier.cpp index 9a0558d9ce35..8cd329018946 100644 --- a/toolchain/check/handle_modifier.cpp +++ b/toolchain/check/handle_modifier.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/check/context.h" -#include "toolchain/check/decl_state.h" +#include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/handle.h" #include "toolchain/lex/token_kind.h" @@ -36,7 +36,7 @@ static auto DiagnoseNotAllowedWith(Context& context, Parse::NodeId first_node, static auto HandleModifier(Context& context, Parse::NodeId node_id, KeywordModifierSet keyword) -> bool { - auto& s = context.decl_state_stack().innermost(); + auto& s = context.decl_introducer_state_stack().innermost(); ModifierOrder order; KeywordModifierSet later_modifiers; diff --git a/toolchain/check/handle_namespace.cpp b/toolchain/check/handle_namespace.cpp index 53fef7ff4b84..f86ce26fd534 100644 --- a/toolchain/check/handle_namespace.cpp +++ b/toolchain/check/handle_namespace.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "toolchain/check/context.h" -#include "toolchain/check/decl_state.h" +#include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/handle.h" #include "toolchain/check/modifiers.h" #include "toolchain/check/name_component.h" @@ -15,7 +15,7 @@ namespace Carbon::Check { auto HandleNamespaceStart(Context& context, Parse::NamespaceStartId /*node_id*/) -> bool { // Optional modifiers and the name follow. - context.decl_state_stack().Push(DeclState::Namespace); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Namespace); context.decl_name_stack().PushScopeAndStartName(); return true; } @@ -23,8 +23,12 @@ auto HandleNamespaceStart(Context& context, Parse::NamespaceStartId /*node_id*/) auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool { auto name_context = context.decl_name_stack().FinishName( PopNameComponentWithoutParams(context, Lex::TokenKind::Namespace)); - LimitModifiersOnDecl(context, KeywordModifierSet::None, + + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Namespace); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::None, Lex::TokenKind::Namespace); + auto namespace_inst = SemIR::Namespace{ context.GetBuiltinType(SemIR::BuiltinKind::NamespaceType), SemIR::NameScopeId::Invalid, SemIR::InstId::Invalid}; @@ -54,7 +58,6 @@ auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool { } context.decl_name_stack().PopScope(); - context.decl_state_stack().Pop(DeclState::Namespace); return true; } diff --git a/toolchain/check/handle_variable.cpp b/toolchain/check/handle_variable.cpp index c132008c3e91..ba47c93d1cae 100644 --- a/toolchain/check/handle_variable.cpp +++ b/toolchain/check/handle_variable.cpp @@ -13,7 +13,7 @@ auto HandleVariableIntroducer(Context& context, Parse::VariableIntroducerId node_id) -> bool { // No action, just a bracketing node. context.node_stack().Push(node_id); - context.decl_state_stack().Push(DeclState::Var); + context.decl_introducer_state_stack().Push(DeclIntroducerState::Var); return true; } @@ -101,18 +101,17 @@ auto HandleVariableDecl(Context& context, Parse::VariableDeclId node_id) // of the name introduced in the declaration. See #2590. auto [_, parent_scope_inst] = context.name_scopes().GetInstIfValid( context.scope_stack().PeekNameScopeId()); - CheckAccessModifiersOnDecl(context, Lex::TokenKind::Var, parent_scope_inst); - LimitModifiersOnDecl(context, KeywordModifierSet::Access, + auto introducer = + context.decl_introducer_state_stack().Pop(DeclIntroducerState::Var); + CheckAccessModifiersOnDecl(context, introducer, Lex::TokenKind::Var, + parent_scope_inst); + LimitModifiersOnDecl(context, introducer, KeywordModifierSet::Access, Lex::TokenKind::Var); - auto modifiers = context.decl_state_stack().innermost().modifier_set; - if (modifiers.HasAnyOf(KeywordModifierSet::Access)) { - context.TODO(context.decl_state_stack().innermost().modifier_node_id( - ModifierOrder::Access), + if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Access)) { + context.TODO(introducer.modifier_node_id(ModifierOrder::Access), "access modifier"); } - context.decl_state_stack().Pop(DeclState::Var); - return true; } diff --git a/toolchain/check/modifiers.cpp b/toolchain/check/modifiers.cpp index ca9c7dc35895..8d8d486508b7 100644 --- a/toolchain/check/modifiers.cpp +++ b/toolchain/check/modifiers.cpp @@ -4,7 +4,7 @@ #include "toolchain/check/modifiers.h" -#include "toolchain/check/decl_state.h" +#include "toolchain/check/decl_introducer_state.h" namespace Carbon::Check { @@ -38,12 +38,12 @@ static auto ModifierOrderAsSet(ModifierOrder order) -> KeywordModifierSet { } } -auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, +auto ForbidModifiersOnDecl(Context& context, DeclIntroducerState& introducer, + KeywordModifierSet forbidden, Lex::TokenKind decl_kind, llvm::StringRef context_string, SemIR::LocId context_loc_id) -> void { - auto& s = context.decl_state_stack().innermost(); - auto not_allowed = s.modifier_set & forbidden; + auto not_allowed = introducer.modifier_set & forbidden; if (not_allowed.empty()) { return; } @@ -52,16 +52,18 @@ auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, order_index <= static_cast(ModifierOrder::Last); ++order_index) { auto order = static_cast(order_index); if (not_allowed.HasAnyOf(ModifierOrderAsSet(order))) { - DiagnoseNotAllowed(context, s.modifier_node_id(order), decl_kind, + DiagnoseNotAllowed(context, introducer.modifier_node_id(order), decl_kind, context_string, context_loc_id); - s.set_modifier_node_id(order, Parse::NodeId::Invalid); + introducer.set_modifier_node_id(order, Parse::NodeId::Invalid); } } - s.modifier_set.Remove(forbidden); + introducer.modifier_set.Remove(forbidden); } -auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind, +auto CheckAccessModifiersOnDecl(Context& context, + DeclIntroducerState& introducer, + Lex::TokenKind decl_kind, std::optional parent_scope_inst) -> void { if (parent_scope_inst) { @@ -71,7 +73,7 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind, // the parents of the target scope to determine whether we're at file // scope. ForbidModifiersOnDecl( - context, KeywordModifierSet::Protected, decl_kind, + context, introducer, KeywordModifierSet::Protected, decl_kind, " at file scope, `protected` is only allowed on class members"); return; } @@ -83,15 +85,17 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind, } // Otherwise neither `private` nor `protected` allowed. - ForbidModifiersOnDecl(context, KeywordModifierSet::Protected, decl_kind, + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Protected, + decl_kind, ", `protected` is only allowed on class members"); ForbidModifiersOnDecl( - context, KeywordModifierSet::Private, decl_kind, + context, introducer, KeywordModifierSet::Private, decl_kind, ", `private` is only allowed on class members and at file scope"); } auto CheckMethodModifiersOnFunction( - Context& context, SemIR::InstId parent_scope_inst_id, + Context& context, DeclIntroducerState& introducer, + SemIR::InstId parent_scope_inst_id, std::optional parent_scope_inst) -> void { const Lex::TokenKind decl_kind = Lex::TokenKind::Fn; if (parent_scope_inst) { @@ -99,12 +103,14 @@ auto CheckMethodModifiersOnFunction( auto inheritance_kind = context.classes().Get(class_decl->class_id).inheritance_kind; if (inheritance_kind == SemIR::Class::Final) { - ForbidModifiersOnDecl(context, KeywordModifierSet::Virtual, decl_kind, + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Virtual, + decl_kind, " in a non-abstract non-base `class` definition", context.insts().GetLocId(parent_scope_inst_id)); } if (inheritance_kind != SemIR::Class::Abstract) { - ForbidModifiersOnDecl(context, KeywordModifierSet::Abstract, decl_kind, + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Abstract, + decl_kind, " in a non-abstract `class` definition", context.insts().GetLocId(parent_scope_inst_id)); } @@ -112,32 +118,34 @@ auto CheckMethodModifiersOnFunction( } } - ForbidModifiersOnDecl(context, KeywordModifierSet::Method, decl_kind, - " outside of a class"); + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Method, + decl_kind, " outside of a class"); } -auto RestrictExternModifierOnDecl(Context& context, Lex::TokenKind decl_kind, +auto RestrictExternModifierOnDecl(Context& context, + DeclIntroducerState& introducer, + Lex::TokenKind decl_kind, std::optional parent_scope_inst, bool is_definition) -> void { if (is_definition) { - ForbidModifiersOnDecl(context, KeywordModifierSet::Extern, decl_kind, - " that provides a definition"); + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern, + decl_kind, " that provides a definition"); } if (parent_scope_inst && !parent_scope_inst->Is()) { - ForbidModifiersOnDecl(context, KeywordModifierSet::Extern, decl_kind, - " that is a member"); + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Extern, + decl_kind, " that is a member"); } } auto RequireDefaultFinalOnlyInInterfaces( - Context& context, Lex::TokenKind decl_kind, + Context& context, DeclIntroducerState& introducer, Lex::TokenKind decl_kind, std::optional parent_scope_inst) -> void { if (parent_scope_inst && parent_scope_inst->Is()) { // Both `default` and `final` allowed in an interface definition. return; } - ForbidModifiersOnDecl(context, KeywordModifierSet::Interface, decl_kind, - " outside of an interface"); + ForbidModifiersOnDecl(context, introducer, KeywordModifierSet::Interface, + decl_kind, " outside of an interface"); } } // namespace Carbon::Check diff --git a/toolchain/check/modifiers.h b/toolchain/check/modifiers.h index 3625d2f3489a..6a99de9bfefc 100644 --- a/toolchain/check/modifiers.h +++ b/toolchain/check/modifiers.h @@ -10,11 +10,12 @@ namespace Carbon::Check { // Reports a diagnostic if access control modifiers on this are not allowed for -// a declaration in `parent_scope_inst`, and updates the declaration state in -// `context`. +// a declaration in `parent_scope_inst`, and updates `introducer`. // // `parent_scope_inst` may be nullopt for a declaration in a block scope. -auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind, +auto CheckAccessModifiersOnDecl(Context& context, + DeclIntroducerState& introducer, + Lex::TokenKind decl_kind, std::optional parent_scope_inst) -> void; @@ -24,25 +25,28 @@ auto CheckAccessModifiersOnDecl(Context& context, Lex::TokenKind decl_kind, // // `parent_scope_inst` may be nullopt for a declaration in a block scope. auto CheckMethodModifiersOnFunction( - Context& context, SemIR::InstId parent_scope_inst_id, + Context& context, DeclIntroducerState& introducer, + SemIR::InstId parent_scope_inst_id, std::optional parent_scope_inst) -> void; // Like `LimitModifiersOnDecl`, except says which modifiers are forbidden, and a // `context_string` (and optional `context_loc_id`) specifying the context in // which those modifiers are forbidden. // TODO: Take another look at diagnostic phrasing for callers. -auto ForbidModifiersOnDecl(Context& context, KeywordModifierSet forbidden, +auto ForbidModifiersOnDecl(Context& context, DeclIntroducerState& introducer, + KeywordModifierSet forbidden, Lex::TokenKind decl_kind, llvm::StringRef context_string, SemIR::LocId context_loc_id = SemIR::LocId::Invalid) -> void; // Reports a diagnostic (using `decl_kind`) if modifiers on this declaration are -// not in `allowed`. Updates the declaration state in -// `context.decl_state_stack()`. -inline auto LimitModifiersOnDecl(Context& context, KeywordModifierSet allowed, +// not in `allowed`. Updates `introducer`. +inline auto LimitModifiersOnDecl(Context& context, + DeclIntroducerState& introducer, + KeywordModifierSet allowed, Lex::TokenKind decl_kind) -> void { - ForbidModifiersOnDecl(context, ~allowed, decl_kind, ""); + ForbidModifiersOnDecl(context, introducer, ~allowed, decl_kind, ""); } // Restricts the `extern` modifier to only be used on namespace-scoped @@ -51,7 +55,9 @@ inline auto LimitModifiersOnDecl(Context& context, KeywordModifierSet allowed, // - `extern` on a scoped entity. // // `parent_scope_inst` may be nullopt for a declaration in a block scope. -auto RestrictExternModifierOnDecl(Context& context, Lex::TokenKind decl_kind, +auto RestrictExternModifierOnDecl(Context& context, + DeclIntroducerState& introducer, + Lex::TokenKind decl_kind, std::optional parent_scope_inst, bool is_definition) -> void; @@ -61,7 +67,7 @@ auto RestrictExternModifierOnDecl(Context& context, Lex::TokenKind decl_kind, // // `parent_scope_inst` may be nullopt for a declaration in a block scope. auto RequireDefaultFinalOnlyInInterfaces( - Context& context, Lex::TokenKind decl_kind, + Context& context, DeclIntroducerState& introducer, Lex::TokenKind decl_kind, std::optional parent_scope_inst) -> void; } // namespace Carbon::Check