mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 19:41:05 +01:00
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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user