mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:50:13 +01:00
Per discussion with zygoloid, namespace declarations will merge both when repeated in a given file, and across files. This echoes how forward declarations of other entities are allowed to repeat. When merging with an imported namespace, fill in the parse node so that future diagnostics point at the declaration in the same file rather than a declaration in a different file, just for locality. Although it might be desirable to issue a diagnostic when a namespace declaration is repeated within a given file, that's similarly true in other cases, but may be more desirable as a tidy-style issue rather than preventing code from compiling. Allowing the repetition also makes the import versus non-import cases more consistent: the namespace declarations merge regardless of the source.
58 lines
2.3 KiB
C++
58 lines
2.3 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/check/context.h"
|
|
#include "toolchain/check/decl_state.h"
|
|
#include "toolchain/check/modifiers.h"
|
|
#include "toolchain/sem_ir/ids.h"
|
|
|
|
namespace Carbon::Check {
|
|
|
|
auto HandleNamespaceStart(Context& context,
|
|
Parse::NamespaceStartId /*parse_node*/) -> bool {
|
|
// Optional modifiers and the name follow.
|
|
context.decl_state_stack().Push(DeclState::Namespace);
|
|
context.decl_name_stack().PushScopeAndStartName();
|
|
return true;
|
|
}
|
|
|
|
auto HandleNamespace(Context& context, Parse::NamespaceId parse_node) -> bool {
|
|
auto name_context = context.decl_name_stack().FinishName();
|
|
LimitModifiersOnDecl(context, KeywordModifierSet::None,
|
|
Lex::TokenKind::Namespace);
|
|
auto namespace_inst = SemIR::Namespace{
|
|
context.GetBuiltinType(SemIR::BuiltinKind::NamespaceType),
|
|
SemIR::NameScopeId::Invalid, SemIR::InstId::Invalid};
|
|
auto namespace_id = context.AddPlaceholderInst({parse_node, namespace_inst});
|
|
namespace_inst.name_scope_id = context.name_scopes().Add(
|
|
namespace_id, name_context.name_id_for_new_inst(),
|
|
name_context.enclosing_scope_id_for_new_inst());
|
|
context.ReplaceInstBeforeConstantUse(namespace_id,
|
|
{parse_node, namespace_inst});
|
|
|
|
auto existing_inst_id =
|
|
context.decl_name_stack().LookupOrAddName(name_context, namespace_id);
|
|
if (existing_inst_id.is_valid()) {
|
|
// If there's a name conflict with a namespace, "merge" by using the
|
|
// previous declaration. Otherwise, diagnose the issue.
|
|
if (auto existing =
|
|
context.insts().TryGetAs<SemIR::Namespace>(existing_inst_id)) {
|
|
// When the name conflict is an imported namespace, fill the parse node
|
|
// so that future diagnostics point at this declaration.
|
|
if (existing->import_id.is_valid() &&
|
|
!context.insts().GetParseNode(existing_inst_id).is_valid()) {
|
|
context.SetNamespaceParseNode(existing_inst_id, parse_node);
|
|
}
|
|
} else {
|
|
context.DiagnoseDuplicateName(namespace_id, existing_inst_id);
|
|
}
|
|
}
|
|
|
|
context.decl_name_stack().PopScope();
|
|
context.decl_state_stack().Pop(DeclState::Namespace);
|
|
return true;
|
|
}
|
|
|
|
} // namespace Carbon::Check
|