Handle out-of-line declarations. (#3536)

By adding an InstId to the NameScope, we can determine whether the
declaration is being added to a scoped entity (versus a namespace).

The choice of InstId on NameScope is chosen versus other solutions
because, for imports, we want to just have a list of InstIds to import
and, from those, get the containing namespaces for addition. Similar may
also be desirable for printing fully qualified names given a singular
InstId. That means an InstId must have a path to find enclosing name
scopes.

What we're looking at here is:

- NameScopeId knows its InstId. (done here)
- Inst knows the enclosing NameScopeId. (future work)
- To walk up enclosing scopes for an Inst:
  1. Fetch the Inst.
2. Find its enclosing NameScopeId (which will be per-declaration due to
Function etc complexity).
  3. Fetch the NameScope if not Package scope. (if Package scope, done)
  4. Use the InstId on the NameScope to go back to step 1.
This commit is contained in:
Jon Ross-Perkins
2023-12-21 18:36:33 +00:00
committed by GitHub
parent 0a06fceb5f
commit 3d661c96f3
10 changed files with 85 additions and 17 deletions
+22 -7
View File
@@ -69,11 +69,22 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context,
context_->AddNameToLookup(name_context.parse_node,
name_context.unresolved_name_id, target_id);
} else {
// TODO: Reject unless the scope is a namespace scope or the name is
// unqualified.
bool success = context_->name_scopes().AddEntry(
name_context.target_scope_id, name_context.unresolved_name_id,
target_id);
auto& name_scope =
context_->name_scopes().Get(name_context.target_scope_id);
if (name_context.has_qualifiers) {
auto inst = context_->insts().Get(name_scope.inst_id);
if (!inst.Is<SemIR::Namespace>()) {
// TODO: Point at the declaration for the scoped entity.
CARBON_DIAGNOSTIC(
QualifiedDeclOutsideScopeEntity, Error,
"Out-of-line declaration requires a declaration in "
"scoped entity.");
context_->emitter().Emit(name_context.parse_node,
QualifiedDeclOutsideScopeEntity);
}
}
auto [_, success] = name_scope.names.insert(
{name_context.unresolved_name_id, target_id});
CARBON_CHECK(success)
<< "Duplicate names should have been resolved previously: "
<< name_context.unresolved_name_id << " in "
@@ -102,7 +113,7 @@ auto DeclNameStack::ApplyNameQualifier(Parse::NodeId parse_node,
auto DeclNameStack::ApplyNameQualifierTo(NameContext& name_context,
Parse::NodeId parse_node,
SemIR::NameId name_id) -> void {
if (CanResolveQualifier(name_context, parse_node)) {
if (TryResolveQualifier(name_context, parse_node)) {
// For identifier nodes, we need to perform a lookup on the identifier.
auto resolved_inst_id = context_->LookupNameInDecl(
name_context.parse_node, name_id, name_context.target_scope_id);
@@ -152,8 +163,12 @@ auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context) -> void {
}
}
auto DeclNameStack::CanResolveQualifier(NameContext& name_context,
auto DeclNameStack::TryResolveQualifier(NameContext& name_context,
Parse::NodeId parse_node) -> bool {
// Update has_qualifiers based on the state before any possible changes. If
// this is the first qualifier, it may just be the name.
name_context.has_qualifiers = name_context.state != NameContext::State::Empty;
switch (name_context.state) {
case NameContext::State::Error:
// Already in an error state, so return without examining.