Use the DeclNameStack for impl declarations. (#3691)

They don't have names, but using the DeclNameStack anyway keeps our
behavior more consistent, and keeps track of the enclosing name scope
and the prior state of the scope stack for us.

Depends on #3683.
This commit is contained in:
Richard Smith
2024-02-06 22:28:31 +00:00
committed by GitHub
parent da34f61ef9
commit 5ab26072fd
4 changed files with 57 additions and 37 deletions
+25 -30
View File
@@ -4,6 +4,7 @@
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/decl_name_stack.h"
#include "toolchain/check/modifiers.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/typed_insts.h"
@@ -17,15 +18,15 @@ auto HandleImplIntroducer(Context& context, Parse::ImplIntroducerId parse_node)
context.inst_block_stack().Push();
// Push the bracketing node.
context.node_stack().Push(parse_node,
context.scope_stack().PeekNameScopeId());
context.node_stack().Push(parse_node);
// Optional modifiers follow.
context.decl_state_stack().Push(DeclState::Impl);
// Create a scope for implicit parameters. We may not use it, but it's simpler
// to create it unconditionally than to track whether it exists.
context.scope_stack().Push();
// 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
// parameters.
context.decl_name_stack().PushScopeAndStartName();
return true;
}
@@ -68,8 +69,7 @@ auto HandleDefaultSelfImplAs(Context& context,
// TODO: Do this without modifying the node stack.
auto implicit_param_list =
context.node_stack().PopWithParseNodeIf<Parse::NodeKind::ImplForall>();
auto enclosing_scope_id =
context.node_stack().Peek<Parse::NodeKind::ImplIntroducer>();
auto enclosing_scope_id = context.decl_name_stack().PeekTargetScope();
if (implicit_param_list) {
context.node_stack().Push(implicit_param_list->first,
implicit_param_list->second);
@@ -90,8 +90,9 @@ auto HandleDefaultSelfImplAs(Context& context,
// Process an `extend impl` declaration by extending the impl scope with the
// `impl`'s scope.
static auto ExtendImpl(Context& context, Parse::AnyImplDeclId parse_node,
SemIR::TypeId constraint_id,
SemIR::NameScopeId enclosing_scope_id) -> void {
SemIR::TypeId constraint_id) -> void {
auto enclosing_scope_id = context.decl_name_stack().PeekTargetScope();
// TODO: This is also valid in a mixin.
if (!TryAsClassScope(context, enclosing_scope_id)) {
CARBON_DIAGNOSTIC(ExtendImplOutsideClass, Error,
@@ -120,26 +121,17 @@ static auto ExtendImpl(Context& context, Parse::AnyImplDeclId parse_node,
enclosing_scope.extended_scopes.push_back(interface.scope_id);
}
namespace {
struct BuildImplDeclResult {
SemIR::ImplId impl_id;
SemIR::InstId impl_decl_id;
SemIR::NameScopeId enclosing_scope_id;
};
} // namespace
// Build an ImplDecl describing the signature of an impl. This handles the
// common logic shared by impl forward declarations and impl definitions.
static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId parse_node)
-> BuildImplDeclResult {
-> std::pair<SemIR::ImplId, SemIR::InstId> {
auto [constraint_node, constraint_id] =
context.node_stack().PopExprWithParseNode();
auto self_type_id = context.node_stack().Pop<Parse::NodeCategory::ImplAs>();
auto params_id = context.node_stack().PopIf<Parse::NodeKind::ImplForall>();
auto decl_block_id = context.inst_block_stack().Pop();
auto enclosing_scope_id =
context.node_stack().Pop<Parse::NodeKind::ImplIntroducer>();
context.node_stack().PopForSoloParseNode<Parse::NodeKind::ImplIntroducer>();
// Convert the constraint expression to a type.
// TODO: Check that its constant value is a constraint.
@@ -151,6 +143,11 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId parse_node)
LimitModifiersOnDecl(context, KeywordModifierSet::ImplDecl,
Lex::TokenKind::Impl);
// Finish processing the name, which should be empty, but might have
// parameters.
auto name_context = context.decl_name_stack().FinishImplName();
CARBON_CHECK(name_context.state == DeclNameStack::NameContext::State::Empty);
// Add the impl declaration.
auto impl_decl = SemIR::ImplDecl{SemIR::ImplId::Invalid, decl_block_id};
auto impl_decl_id = context.AddPlaceholderInst({parse_node, impl_decl});
@@ -172,25 +169,24 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId parse_node)
KeywordModifierSet::Extend)) {
// TODO: Diagnose combining `extend` with `forall`.
// TODO: Diagnose combining `extend` with an explicit self type.
ExtendImpl(context, parse_node, constraint_type_id, enclosing_scope_id);
ExtendImpl(context, parse_node, constraint_type_id);
}
context.decl_state_stack().Pop(DeclState::Impl);
return {impl_decl.impl_id, impl_decl_id, enclosing_scope_id};
return {impl_decl.impl_id, impl_decl_id};
}
auto HandleImplDecl(Context& context, Parse::ImplDeclId parse_node) -> bool {
BuildImplDecl(context, parse_node);
context.scope_stack().Pop();
context.decl_name_stack().PopScope();
return true;
}
auto HandleImplDefinitionStart(Context& context,
Parse::ImplDefinitionStartId parse_node)
-> bool {
auto [impl_id, impl_decl_id, enclosing_scope_id] =
BuildImplDecl(context, parse_node);
auto [impl_id, impl_decl_id] = BuildImplDecl(context, parse_node);
auto& impl_info = context.impls().Get(impl_id);
if (impl_info.definition_id.is_valid()) {
@@ -207,8 +203,9 @@ auto HandleImplDefinitionStart(Context& context,
.Emit();
} else {
impl_info.definition_id = impl_decl_id;
impl_info.scope_id = context.name_scopes().Add(
impl_decl_id, SemIR::NameId::Invalid, enclosing_scope_id);
impl_info.scope_id =
context.name_scopes().Add(impl_decl_id, SemIR::NameId::Invalid,
context.decl_name_stack().PeekTargetScope());
}
context.scope_stack().Push(impl_decl_id, impl_info.scope_id);
@@ -234,9 +231,7 @@ auto HandleImplDefinition(Context& context,
auto impl_id =
context.node_stack().Pop<Parse::NodeKind::ImplDefinitionStart>();
context.inst_block_stack().Pop();
// Pop the impl body scope and the parameter scope.
context.scope_stack().Pop();
context.scope_stack().Pop();
context.decl_name_stack().PopScope();
// The impl is now fully defined.
context.impls().Get(impl_id).defined = true;