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