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.
This commit is contained in:
Jon Ross-Perkins
2024-06-04 23:12:12 +00:00
committed by GitHub
parent 8c64f0bfdd
commit a910eda020
17 changed files with 192 additions and 174 deletions
+32 -24
View File
@@ -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<int8_t>(ModifierOrder::Last); ++order_index) {
auto order = static_cast<ModifierOrder>(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<SemIR::Inst> 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<SemIR::Inst> 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<SemIR::Inst> 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<SemIR::Namespace>()) {
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<SemIR::Inst> parent_scope_inst) -> void {
if (parent_scope_inst && parent_scope_inst->Is<SemIR::InterfaceDecl>()) {
// 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