diff --git a/toolchain/base/value_store.h b/toolchain/base/value_store.h index c6520a2f399a..29bd9131bb8a 100644 --- a/toolchain/base/value_store.h +++ b/toolchain/base/value_store.h @@ -172,7 +172,9 @@ class ValueStore auto size() const -> int { return values_.size(); } private: - llvm::SmallVector> values_; + // Set inline size to 0 because these will typically be too large for the + // stack, while this does make File smaller. + llvm::SmallVector, 0> values_; }; // Storage for StringRefs. The caller is responsible for ensuring storage is @@ -207,7 +209,9 @@ class ValueStore : public Yaml::Printable> { private: llvm::DenseMap map_; - llvm::SmallVector values_; + // Set inline size to 0 because these will typically be too large for the + // stack, while this does make File smaller. + llvm::SmallVector values_; }; // A thin wrapper around a `ValueStore` that provides a different IdT, diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 31ef1188c48e..4be14e9f825c 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -69,8 +69,73 @@ struct UnitInfo { }; // Add imports to the root block. -static auto AddImports(Context& context, UnitInfo& unit_info) -> void { +static auto InitPackageScopeAndImports(Context& context, UnitInfo& unit_info) + -> void { + // Define the package scope, with an instruction for `package` expressions to + // reference. + auto package_scope_id = context.name_scopes().Add(); + CARBON_CHECK(package_scope_id == SemIR::NameScopeId::Package); + + auto package_inst = context.AddInst(SemIR::Namespace{ + Parse::NodeId::Invalid, + context.GetBuiltinType(SemIR::BuiltinKind::NamespaceType), + SemIR::NameScopeId::Package}); + CARBON_CHECK(package_inst == SemIR::InstId::PackageNamespace); + + // Add imports from the current package. + auto self_import = unit_info.package_imports_map.find(IdentifierId::Invalid); + if (self_import != unit_info.package_imports_map.end()) { + auto& package_scope = + context.name_scopes().Get(SemIR::NameScopeId::Package); + package_scope.has_load_error = self_import->second.has_load_error; + + for (const auto& import : self_import->second.imports) { + const auto& import_sem_ir = **import.unit_info->unit->sem_ir; + const auto& import_scope = + import_sem_ir.name_scopes().Get(SemIR::NameScopeId::Package); + + // If an import of the current package caused an error for the imported + // file, it transitively affects the current file too. + package_scope.has_load_error |= import_scope.has_load_error; + + auto ir_id = context.sem_ir().cross_ref_irs().Add(&import_sem_ir); + + for (const auto& [import_name_id, import_inst_id] : import_scope.names) { + // Translate the name to the current IR. + auto name_id = SemIR::NameId::Invalid; + if (auto import_identifier_id = import_name_id.AsIdentifierId(); + import_identifier_id.is_valid()) { + auto name = import_sem_ir.identifiers().Get(import_identifier_id); + name_id = + SemIR::NameId::ForIdentifier(context.identifiers().Add(name)); + } else { + // A builtin name ID which is equivalent cross-IR. + name_id = import_name_id; + } + + // Leave a placeholder that the inst comes from the other IR. + auto target_id = context.AddInst( + SemIR::LazyImportRef{.ir_id = ir_id, .inst_id = import_inst_id}); + // TODO: The scope's names should be changed to allow for ambiguous + // names. + package_scope.names.insert({name_id, target_id}); + } + } + + // Push the scope. + context.PushScope(package_inst, SemIR::NameScopeId::Package, + package_scope.has_load_error); + } else { + // Push the scope; there are no names to add. + context.PushScope(package_inst, SemIR::NameScopeId::Package); + } + for (auto& [package_id, package_imports] : unit_info.package_imports_map) { + if (!package_id.is_valid()) { + // Current package is handled above. + continue; + } + llvm::SmallVector sem_irs; for (auto import : package_imports.imports) { sem_irs.push_back(&**import.unit_info->unit->sem_ir); @@ -105,8 +170,6 @@ static auto ProcessParseNodes(Context& context, } // Produces and checks the IR for the provided Parse::Tree. -// TODO: Both valid and invalid imports should be recorded on the SemIR. Invalid -// imports should suppress errors where it makes sense. static auto CheckParseTree(const SemIR::File& builtin_ir, UnitInfo& unit_info, llvm::raw_ostream* vlog_stream) -> void { unit_info.unit->sem_ir->emplace( @@ -124,17 +187,7 @@ static auto CheckParseTree(const SemIR::File& builtin_ir, UnitInfo& unit_info, // Add a block for the file. context.inst_block_stack().Push(); - // Define the package scope, with an instruction for `package` expressions to - // reference. - auto package_scope = context.name_scopes().Add(); - auto package_inst = context.AddInst(SemIR::Namespace{ - Parse::NodeId::Invalid, - context.GetBuiltinType(SemIR::BuiltinKind::NamespaceType), - package_scope}); - CARBON_CHECK(package_inst == SemIR::InstId::PackageNamespace); - context.PushScope(SemIR::InstId::Invalid, package_scope); - - AddImports(context, unit_info); + InitPackageScopeAndImports(context, unit_info); if (!ProcessParseNodes(context, unit_info.err_tracker)) { context.sem_ir().set_has_errors(true); @@ -338,7 +391,7 @@ static auto BuildApiMapAndDiagnosePackaging( packaging && packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl; // Add to the `api` map and diagnose duplicates. This occurs before the - // file extension check because we might emit both diagnostics in situation + // file extension check because we might emit both diagnostics in situations // where the user forgets (or has syntax errors with) a package line // multiple times. if (!is_impl) { @@ -418,7 +471,9 @@ auto CheckParseTrees(const SemIR::File& builtin_ir, unit_info.unit->parse_tree->packaging_directive()) { if (packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl) { // An `impl` has an implicit import of its `api`. - TrackImport(api_map, nullptr, unit_info, packaging->names); + auto implicit_names = packaging->names; + implicit_names.package_id = IdentifierId::Invalid; + TrackImport(api_map, nullptr, unit_info, implicit_names); } } diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index 4a59c19847e7..3994f47d3e24 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -137,20 +137,17 @@ auto Context::AddPackageImports(Parse::NodeId import_node, .type_id = type_id, .first_cross_ref_ir_id = first_id, .last_cross_ref_ir_id = last_id}); - if (name_id.is_valid()) { - // Add the import to lookup. Should always succeed because imports will be - // uniquely named. - AddNameToLookup(import_node, name_id, inst_id); - // Add a name for formatted output. This isn't used in name lookup in order - // to reduce indirection, but it's separate from the Import because it - // otherwise fits in an Inst. - AddInst(SemIR::BindName{.parse_node = import_node, - .type_id = type_id, - .name_id = name_id, - .value_id = inst_id}); - } else { - // TODO: All names from the current package should be added. - } + + // Add the import to lookup. Should always succeed because imports will be + // uniquely named. + AddNameToLookup(import_node, name_id, inst_id); + // Add a name for formatted output. This isn't used in name lookup in order + // to reduce indirection, but it's separate from the Import because it + // otherwise fits in an Inst. + AddInst(SemIR::BindName{.parse_node = import_node, + .type_id = type_id, + .name_id = name_id, + .value_id = inst_id}); } auto Context::AddNameToLookup(Parse::NodeId name_node, SemIR::NameId name_id, @@ -169,6 +166,45 @@ auto Context::AddNameToLookup(Parse::NodeId name_node, SemIR::NameId name_id, } } +auto Context::ResolveIfLazyImportRef(SemIR::InstId inst_id) -> void { + auto inst = insts().Get(inst_id); + auto lazy_inst = inst.TryAs(); + if (!lazy_inst) { + return; + } + const SemIR::File& import_ir = *cross_ref_irs().Get(lazy_inst->ir_id); + auto import_inst = import_ir.insts().Get(lazy_inst->inst_id); + switch (import_inst.kind()) { + case SemIR::InstKind::FunctionDecl: { + // TODO: Fill this in better. + auto function_id = + functions().Add({.name_id = SemIR::NameId::Invalid, + .decl_id = inst_id, + .implicit_param_refs_id = SemIR::InstBlockId::Empty, + .param_refs_id = SemIR::InstBlockId::Empty, + .return_type_id = SemIR::TypeId::Invalid, + .return_slot_id = SemIR::InstId::Invalid}); + insts().Set(inst_id, SemIR::FunctionDecl{ + Parse::NodeId::Invalid, + GetBuiltinType(SemIR::BuiltinKind::FunctionType), + function_id}); + break; + } + + default: + // TODO: We need more type support. For now we inject an arbitrary + // invalid node that's unrelated to the underlying value. The TODO + // diagnostic is used since this section shouldn't typically be able to + // error. + TODO(Parse::NodeId::Invalid, + (llvm::Twine("TODO: support ") + import_inst.kind().name()).str()); + insts().Set(inst_id, SemIR::VarStorage{Parse::NodeId::Invalid, + SemIR::TypeId::Error, + SemIR::NameId::PackageNamespace}); + break; + } +} + auto Context::LookupNameInDecl(Parse::NodeId parse_node, SemIR::NameId name_id, SemIR::NameScopeId scope_id) -> SemIR::InstId { if (scope_id == SemIR::NameScopeId::Invalid) { @@ -201,6 +237,7 @@ auto Context::LookupNameInDecl(Parse::NodeId parse_node, SemIR::NameId name_id, << "Should have been erased: " << names().GetFormatted(name_id); auto result = name_it->second.back(); if (result.scope_index == current_scope_index()) { + ResolveIfLazyImportRef(result.inst_id); return result.inst_id; } } @@ -233,23 +270,29 @@ auto Context::LookupUnqualifiedName(Parse::NodeId parse_node, // it shadows all further non-lexical results and we're done. if (!lexical_results.empty() && lexical_results.back().scope_index > index) { - return lexical_results.back().inst_id; + auto inst_id = lexical_results.back().inst_id; + ResolveIfLazyImportRef(inst_id); + return inst_id; } - auto non_lexical_result = - LookupQualifiedName(parse_node, name_id, name_scope_id, - /*required=*/false); - if (non_lexical_result.is_valid()) { + if (auto non_lexical_result = + LookupQualifiedName(parse_node, name_id, name_scope_id, + /*required=*/false); + non_lexical_result.is_valid()) { return non_lexical_result; } } if (!lexical_results.empty()) { - return lexical_results.back().inst_id; + auto inst_id = lexical_results.back().inst_id; + ResolveIfLazyImportRef(inst_id); + return inst_id; } // We didn't find anything at all. - DiagnoseNameNotFound(parse_node, name_id); + if (!name_lookup_has_load_error_) { + DiagnoseNameNotFound(parse_node, name_id); + } return SemIR::InstId::BuiltinError; } @@ -259,28 +302,36 @@ auto Context::LookupQualifiedName(Parse::NodeId parse_node, -> SemIR::InstId { CARBON_CHECK(scope_id.is_valid()) << "No scope to perform lookup into"; const auto& scope = name_scopes().Get(scope_id); - auto it = scope.find(name_id); - if (it == scope.end()) { - // TODO: Also perform lookups into `extend`ed scopes. - if (required) { - DiagnoseNameNotFound(parse_node, name_id); - return SemIR::InstId::BuiltinError; - } - return SemIR::InstId::Invalid; + if (auto it = scope.names.find(name_id); it != scope.names.end()) { + ResolveIfLazyImportRef(it->second); + return it->second; } - return it->second; + // TODO: Also perform lookups into `extend`ed scopes. + + if (!required) { + return SemIR::InstId::Invalid; + } + if (!scope.has_load_error) { + DiagnoseNameNotFound(parse_node, name_id); + } + return SemIR::InstId::BuiltinError; } auto Context::PushScope(SemIR::InstId scope_inst_id, - SemIR::NameScopeId scope_id) -> void { - scope_stack_.push_back({.index = next_scope_index_, - .scope_inst_id = scope_inst_id, - .scope_id = scope_id}); + SemIR::NameScopeId scope_id, + bool name_lookup_has_load_error) -> void { + scope_stack_.push_back( + {.index = next_scope_index_, + .scope_inst_id = scope_inst_id, + .scope_id = scope_id, + .prev_name_lookup_has_load_error = name_lookup_has_load_error_}); if (scope_id.is_valid()) { non_lexical_scope_stack_.push_back({next_scope_index_, scope_id}); } + name_lookup_has_load_error_ |= name_lookup_has_load_error; + // TODO: Handle this case more gracefully. CARBON_CHECK(next_scope_index_.index != std::numeric_limits::max()) << "Ran out of scopes"; @@ -289,6 +340,9 @@ auto Context::PushScope(SemIR::InstId scope_inst_id, auto Context::PopScope() -> void { auto scope = scope_stack_.pop_back_val(); + + name_lookup_has_load_error_ = scope.prev_name_lookup_has_load_error; + for (const auto& str_id : scope.names) { auto it = name_lookup_.find(str_id); CARBON_CHECK(it->second.back().scope_index == scope.index) @@ -848,6 +902,7 @@ class TypeCompleter { case SemIR::InitializeFrom::Kind: case SemIR::InterfaceDecl::Kind: case SemIR::IntLiteral::Kind: + case SemIR::LazyImportRef::Kind: case SemIR::NameRef::Kind: case SemIR::Namespace::Kind: case SemIR::NoOp::Kind: diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 53a4de070274..d3e2e43d13ce 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -102,10 +102,13 @@ class Context { auto NoteIncompleteClass(SemIR::ClassId class_id, DiagnosticBuilder& builder) -> void; - // Pushes a new scope onto scope_stack_. + // Pushes a scope onto scope_stack_. NameScopeId::Invalid is used for new + // scopes. name_lookup_has_load_error is used to limit diagnostics when a + // given namespace may contain a mix of both successful and failed name + // imports. auto PushScope(SemIR::InstId scope_inst_id = SemIR::InstId::Invalid, - SemIR::NameScopeId scope_id = SemIR::NameScopeId::Invalid) - -> void; + SemIR::NameScopeId scope_id = SemIR::NameScopeId::Invalid, + bool name_lookup_has_load_error = false) -> void; // Pops the top scope from scope_stack_, cleaning up names from name_lookup_. auto PopScope() -> void; @@ -387,6 +390,9 @@ class Context { // The name scope associated with this entry, if any. SemIR::NameScopeId scope_id; + // The previous state of name_lookup_has_load_error_, restored on pop. + bool prev_name_lookup_has_load_error; + // Names which are registered with name_lookup_, and will need to be // unregistered when the scope ends. llvm::DenseSet names; @@ -427,6 +433,10 @@ class Context { // instruction to the current block. auto CanonicalizeTypeAndAddInstIfNew(SemIR::Inst inst) -> SemIR::TypeId; + // If the passed in instruction ID is a LazyImportRef, resolves it for use. + // Called when name lookup intends to return an inst_id. + auto ResolveIfLazyImportRef(SemIR::InstId inst_id) -> void; + auto current_scope() -> ScopeStackEntry& { return scope_stack_.back(); } auto current_scope() const -> const ScopeStackEntry& { return scope_stack_.back(); @@ -499,6 +509,10 @@ class Context { llvm::DenseMap> name_lookup_; + // Whether name_lookup_ has load errors, updated whenever scope_stack_ is + // pushed or popped. + bool name_lookup_has_load_error_ = false; + // Cache of the mapping from instructions to types, to avoid recomputing the // folding set ID. llvm::DenseMap canonical_types_; diff --git a/toolchain/check/decl_name_stack.cpp b/toolchain/check/decl_name_stack.cpp index 4b318f129057..d8a1a664ad7d 100644 --- a/toolchain/check/decl_name_stack.cpp +++ b/toolchain/check/decl_name_stack.cpp @@ -145,7 +145,8 @@ auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context) -> void { auto scope_id = resolved_inst.As().name_scope_id; name_context.state = NameContext::State::Resolved; name_context.target_scope_id = scope_id; - context_->PushScope(name_context.resolved_inst_id, scope_id); + context_->PushScope(name_context.resolved_inst_id, scope_id, + context_->name_scopes().Get(scope_id).has_load_error); break; } default: diff --git a/toolchain/check/testdata/packages/explicit_imports.carbon b/toolchain/check/testdata/packages/explicit_imports.carbon index ec7e26089d29..856fd72eb4ce 100644 --- a/toolchain/check/testdata/packages/explicit_imports.carbon +++ b/toolchain/check/testdata/packages/explicit_imports.carbon @@ -50,7 +50,6 @@ import library "lib"; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- different_package.carbon @@ -71,6 +70,5 @@ import library "lib"; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_api_not_found.carbon b/toolchain/check/testdata/packages/fail_api_not_found.carbon index 9d472c282ba1..45f5a301ba5c 100644 --- a/toolchain/check/testdata/packages/fail_api_not_found.carbon +++ b/toolchain/check/testdata/packages/fail_api_not_found.carbon @@ -28,23 +28,18 @@ library "Bar" impl; // CHECK:STDOUT: --- no_api.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Foo: = bind_name Foo, %import +// CHECK:STDOUT: package: = namespace {has_load_error} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- no_api_lib.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Foo: = bind_name Foo, %import +// CHECK:STDOUT: package: = namespace {has_load_error} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- no_api_main_lib.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 +// CHECK:STDOUT: package: = namespace {has_load_error} // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_cycle.carbon b/toolchain/check/testdata/packages/fail_cycle.carbon index f83d6b1342a3..e0d0d70f99b6 100644 --- a/toolchain/check/testdata/packages/fail_cycle.carbon +++ b/toolchain/check/testdata/packages/fail_cycle.carbon @@ -74,9 +74,7 @@ import B; // CHECK:STDOUT: --- c.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %C: = bind_name C, %import +// CHECK:STDOUT: package: = namespace {has_load_error} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- cycle_child.carbon diff --git a/toolchain/check/testdata/packages/fail_extension.carbon b/toolchain/check/testdata/packages/fail_extension.carbon index 054cfdafd147..565c9c9678c1 100644 --- a/toolchain/check/testdata/packages/fail_extension.carbon +++ b/toolchain/check/testdata/packages/fail_extension.carbon @@ -92,7 +92,6 @@ package SwappedExt impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- package.incorrect @@ -105,8 +104,6 @@ package SwappedExt impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Package: = bind_name Package, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- package_lib.incorrect @@ -119,8 +116,6 @@ package SwappedExt impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Package: = bind_name Package, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- swapped_ext.impl.carbon @@ -133,7 +128,5 @@ package SwappedExt impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %SwappedExt: = bind_name SwappedExt, %import // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_import_default.carbon b/toolchain/check/testdata/packages/fail_import_default.carbon index 8e09f82699e0..498c45d75849 100644 --- a/toolchain/check/testdata/packages/fail_import_default.carbon +++ b/toolchain/check/testdata/packages/fail_import_default.carbon @@ -48,8 +48,6 @@ import library default; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %A: = bind_name A, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- main_import_default.carbon diff --git a/toolchain/check/testdata/packages/fail_import_invalid.carbon b/toolchain/check/testdata/packages/fail_import_invalid.carbon index 6eda8ee14635..5c52004917d5 100644 --- a/toolchain/check/testdata/packages/fail_import_invalid.carbon +++ b/toolchain/check/testdata/packages/fail_import_invalid.carbon @@ -116,8 +116,6 @@ import ImportNotFound; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Implicit: = bind_name Implicit, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- implicit_lib_api.carbon @@ -130,8 +128,6 @@ import ImportNotFound; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %Implicit: = bind_name Implicit, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- not_found.carbon diff --git a/toolchain/check/testdata/packages/fail_import_repeat.carbon b/toolchain/check/testdata/packages/fail_import_repeat.carbon index 42ab73e596e3..abefefb502fa 100644 --- a/toolchain/check/testdata/packages/fail_import_repeat.carbon +++ b/toolchain/check/testdata/packages/fail_import_repeat.carbon @@ -80,15 +80,13 @@ import library default; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import.loc2: = import ir1, ir2 -// CHECK:STDOUT: %Api: = bind_name Api, %import.loc2 -// CHECK:STDOUT: %import.loc20: = import ir3, ir3 +// CHECK:STDOUT: %import: = import ir2, ir3 +// CHECK:STDOUT: %Api: = bind_name Api, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- default_import.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_name_with_import_failure.carbon b/toolchain/check/testdata/packages/fail_name_with_import_failure.carbon new file mode 100644 index 000000000000..86daf27c7e3b --- /dev/null +++ b/toolchain/check/testdata/packages/fail_name_with_import_failure.carbon @@ -0,0 +1,31 @@ +// 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 +// +// AUTOUPDATE + +// --- implicit.impl.carbon + +// CHECK:STDERR: implicit.impl.carbon:[[@LINE+3]]:1: ERROR: Corresponding API not found. +// CHECK:STDERR: package Implicit impl; +// CHECK:STDERR: ^~~~~~~ +package Implicit impl; + +var a: () = A(); + +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.loc7: type = tuple_type () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a = %a, has_load_error} +// CHECK:STDOUT: %.loc7_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc7_9.2: type = converted %.loc7_9.1, constants.%.loc7 +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %A.ref: = name_ref A, +// CHECK:STDOUT: assign %a.var, +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon b/toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon new file mode 100644 index 000000000000..a80be9867a79 --- /dev/null +++ b/toolchain/check/testdata/packages/fail_todo_lazy_import_ref.carbon @@ -0,0 +1,49 @@ +// 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 +// +// When there are no more cases that can hit a TODO, remove this test. Until +// then, update it whenever its target is implemented. +// +// AUTOUPDATE +// CHECK:STDERR: implicit.impl.carbon: ERROR: Semantics TODO: `TODO: support BindName`. + +// --- implicit.carbon + +package Implicit api; + +var a_ref: i32 = 0; + +// --- implicit.impl.carbon + +package Implicit impl; + +var a: () = a_ref; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %a_ref} +// CHECK:STDOUT: %a_ref.var: ref i32 = var a_ref +// CHECK:STDOUT: %a_ref: ref i32 = bind_name a_ref, %a_ref.var +// CHECK:STDOUT: %.loc4: i32 = int_literal 0 +// CHECK:STDOUT: assign %a_ref.var, %.loc4 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.loc4: type = tuple_type () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.a_ref = %package.var, .a = %a} +// CHECK:STDOUT: %package.var: ref = var package +// CHECK:STDOUT: %.loc4_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc4_9.2: type = converted %.loc4_9.1, constants.%.loc4 +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %a_ref.ref: ref = name_ref a_ref, %package.var +// CHECK:STDOUT: assign %a.var, +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/implicit_imports.carbon b/toolchain/check/testdata/packages/implicit_imports.carbon index 19a95dcd48ee..6a2be7140fa0 100644 --- a/toolchain/check/testdata/packages/implicit_imports.carbon +++ b/toolchain/check/testdata/packages/implicit_imports.carbon @@ -65,16 +65,12 @@ library "lib" impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- with_impl_extra.impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- with_impl_lib.carbon @@ -87,8 +83,6 @@ library "lib" impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 -// CHECK:STDOUT: %WithImpl: = bind_name WithImpl, %import // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- main.carbon @@ -107,6 +101,5 @@ library "lib" impl; // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: package: = namespace {} -// CHECK:STDOUT: %import: = import ir1, ir1 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/loaded_global.carbon b/toolchain/check/testdata/packages/loaded_global.carbon new file mode 100644 index 000000000000..b27039dd360a --- /dev/null +++ b/toolchain/check/testdata/packages/loaded_global.carbon @@ -0,0 +1,110 @@ +// 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 +// +// AUTOUPDATE + +// --- implicit.carbon + +package Implicit api; + +fn A(); + +// --- implicit.impl.carbon + +package Implicit impl; + +var a: () = A(); + +var package_a: () = package.A(); + +// --- same_package.carbon + +package SamePackage api; + +fn B(); + +// --- same_package_importer.carbon + +package SamePackage library "importer" api; + +import library default; + +var b: () = B(); + +var package_b: () = package.B(); + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.A = %A} +// CHECK:STDOUT: %A: = fn_decl @A +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.loc4: type = tuple_type () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.A = %.2, .a = %a, .package_a = %package_a} +// CHECK:STDOUT: %.2: = fn_decl @.1 +// CHECK:STDOUT: %.loc4_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc4_9.2: type = converted %.loc4_9.1, constants.%.loc4 +// CHECK:STDOUT: %a.var: ref () = var a +// CHECK:STDOUT: %a: ref () = bind_name a, %a.var +// CHECK:STDOUT: %A.ref.loc4: = name_ref A, %.2 +// CHECK:STDOUT: %.loc4_14: init () = call %A.ref.loc4() +// CHECK:STDOUT: assign %a.var, %.loc4_14 +// CHECK:STDOUT: %.loc6_17: () = tuple_literal () +// CHECK:STDOUT: %.loc4_9.3: type = converted %.loc6_17, constants.%.loc4 +// CHECK:STDOUT: %package_a.var: ref () = var package_a +// CHECK:STDOUT: %package_a: ref () = bind_name package_a, %package_a.var +// CHECK:STDOUT: %package.ref: = name_ref package, package +// CHECK:STDOUT: %A.ref.loc6: = name_ref A, %.2 +// CHECK:STDOUT: %.loc6_30: init () = call %A.ref.loc6() +// CHECK:STDOUT: assign %package_a.var, %.loc6_30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- same_package.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.B = %B} +// CHECK:STDOUT: %B: = fn_decl @B +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @B(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- same_package_importer.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.loc6: type = tuple_type () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.B = %.2, .b = %b, .package_b = %package_b} +// CHECK:STDOUT: %.2: = fn_decl @.1 +// CHECK:STDOUT: %.loc6_9.1: () = tuple_literal () +// CHECK:STDOUT: %.loc6_9.2: type = converted %.loc6_9.1, constants.%.loc6 +// CHECK:STDOUT: %b.var: ref () = var b +// CHECK:STDOUT: %b: ref () = bind_name b, %b.var +// CHECK:STDOUT: %B.ref.loc6: = name_ref B, %.2 +// CHECK:STDOUT: %.loc6_14: init () = call %B.ref.loc6() +// CHECK:STDOUT: assign %b.var, %.loc6_14 +// CHECK:STDOUT: %.loc8_17: () = tuple_literal () +// CHECK:STDOUT: %.loc6_9.3: type = converted %.loc8_17, constants.%.loc6 +// CHECK:STDOUT: %package_b.var: ref () = var package_b +// CHECK:STDOUT: %package_b: ref () = bind_name package_b, %package_b.var +// CHECK:STDOUT: %package.ref: = name_ref package, package +// CHECK:STDOUT: %B.ref.loc8: = name_ref B, %.2 +// CHECK:STDOUT: %.loc8_30: init () = call %B.ref.loc8() +// CHECK:STDOUT: assign %package_b.var, %.loc8_30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1(); +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/unused_lazy_import.carbon b/toolchain/check/testdata/packages/unused_lazy_import.carbon new file mode 100644 index 000000000000..e8d09c6621bd --- /dev/null +++ b/toolchain/check/testdata/packages/unused_lazy_import.carbon @@ -0,0 +1,32 @@ +// 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 +// +// AUTOUPDATE + +// --- implicit.carbon + +package Implicit api; + +fn A(); + +// --- implicit.impl.carbon + +package Implicit impl; + +// CHECK:STDOUT: --- implicit.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.A = %A} +// CHECK:STDOUT: %A: = fn_decl @A +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- implicit.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace {.A = %lazy_import_ref} +// CHECK:STDOUT: %lazy_import_ref = lazy_import_ref ir1, inst+1 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index 3a63d7f41a34..7fdad7f9c5d0 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -12,13 +12,17 @@ #include "llvm/Support/Casting.h" #include "toolchain/lower/function_context.h" #include "toolchain/sem_ir/inst.h" -#include "toolchain/sem_ir/inst_kind.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Lower { -auto HandleCrossRef(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, - SemIR::CrossRef inst) -> void { - CARBON_FATAL() << "TODO: Add support: " << inst; +template +static auto FatalErrorIfEncountered(InstT inst) -> void { + CARBON_FATAL() + << "Encountered an instruction that isn't expected to lower. It's " + "possible that logic needs to be changed in order to stop " + "showing this instruction in lowered contexts. Instruction: " + << inst; } auto HandleAddressOf(FunctionContext& context, SemIR::InstId inst_id, @@ -166,6 +170,11 @@ auto HandleConverted(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, context.GetValue(inst.result_id)); } +auto HandleCrossRef(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, + SemIR::CrossRef inst) -> void { + FatalErrorIfEncountered(inst); +} + auto HandleDeref(FunctionContext& context, SemIR::InstId inst_id, SemIR::Deref inst) -> void { context.SetLocal(inst_id, context.GetValue(inst.pointer_id)); @@ -173,18 +182,12 @@ auto HandleDeref(FunctionContext& context, SemIR::InstId inst_id, auto HandleFunctionDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::FunctionDecl inst) -> void { - CARBON_FATAL() - << "Should not be encountered. If that changes, we may want to change " - "higher-level logic to skip them rather than calling this. " - << inst; + FatalErrorIfEncountered(inst); } auto HandleImport(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::Import inst) -> void { - CARBON_FATAL() - << "Should not be encountered. If that changes, we may want to change " - "higher-level logic to skip them rather than calling this. " - << inst; + FatalErrorIfEncountered(inst); } auto HandleInitializeFrom(FunctionContext& context, SemIR::InstId /*inst_id*/, @@ -208,6 +211,12 @@ auto HandleIntLiteral(FunctionContext& context, SemIR::InstId inst_id, context.SetLocal(inst_id, v); } +auto HandleLazyImportRef(FunctionContext& /*context*/, + SemIR::InstId /*inst_id*/, SemIR::LazyImportRef inst) + -> void { + FatalErrorIfEncountered(inst); +} + auto HandleNameRef(FunctionContext& context, SemIR::InstId inst_id, SemIR::NameRef inst) -> void { auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id); @@ -220,10 +229,7 @@ auto HandleNameRef(FunctionContext& context, SemIR::InstId inst_id, auto HandleNamespace(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, SemIR::Namespace inst) -> void { - CARBON_FATAL() - << "Should not be encountered. If that changes, we may want to change " - "higher-level logic to skip them rather than calling this. " - << inst; + FatalErrorIfEncountered(inst); } auto HandleNoOp(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/, diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index b513a3bca2c5..e5d6ab6266f7 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -208,6 +208,7 @@ static auto GetTypePrecedence(InstKind kind) -> int { case InitializeFrom::Kind: case InterfaceDecl::Kind: case IntLiteral::Kind: + case LazyImportRef::Kind: case Namespace::Kind: case NoOp::Kind: case Param::Kind: @@ -409,6 +410,7 @@ auto File::StringifyTypeExpr(InstId outer_inst_id) const -> std::string { case InitializeFrom::Kind: case InterfaceDecl::Kind: case IntLiteral::Kind: + case LazyImportRef::Kind: case Namespace::Kind: case NoOp::Kind: case Param::Kind: @@ -466,6 +468,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case FunctionDecl::Kind: case Import::Kind: case InterfaceDecl::Kind: + case LazyImportRef::Kind: case Namespace::Kind: case NoOp::Kind: case Return::Kind: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 696e8b7b829f..fbb9bed99889 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -12,6 +12,7 @@ #include "toolchain/lex/tokenized_buffer.h" #include "toolchain/parse/tree.h" #include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::SemIR { @@ -494,6 +495,10 @@ class InstNamer { ".decl"); continue; } + case LazyImportRef::Kind: { + add_inst_name("lazy_import_ref"); + continue; + } case NameRef::Kind: { add_inst_name_id(inst.As().name_id, ".ref"); continue; @@ -703,10 +708,12 @@ class Formatter { auto FormatNameScope(NameScopeId id, llvm::StringRef separator, llvm::StringRef prefix) -> void { + const auto& scope = sem_ir_.name_scopes().Get(id); + // Name scopes aren't kept in any particular order. Sort the entries before // we print them for stability and consistency. llvm::SmallVector> entries; - for (auto [name_id, inst_id] : sem_ir_.name_scopes().Get(id)) { + for (auto [name_id, inst_id] : scope.names) { entries.push_back({inst_id, name_id}); } llvm::sort(entries, @@ -719,6 +726,10 @@ class Formatter { out_ << " = "; FormatInstName(inst_id); } + + if (scope.has_load_error) { + out_ << sep << "has_load_error"; + } } auto FormatInstruction(InstId inst_id) -> void { @@ -794,6 +805,13 @@ class Formatter { out_ << " = "; } + // Print LazyImportRef with type-like semantics even though it lacks a + // type_id. + auto FormatInstructionLHS(InstId inst_id, LazyImportRef /*inst*/) -> void { + FormatInstName(inst_id); + out_ << " = "; + } + template auto FormatInstructionRHS(InstT inst) -> void { // By default, an instruction has a comma-separated argument list. @@ -900,7 +918,13 @@ class Formatter { auto FormatInstructionRHS(CrossRef inst) -> void { // TODO: Figure out a way to make this meaningful. We'll need some way to // name cross-reference IRs, perhaps by the instruction ID of the import? - out_ << " " << inst.ir_id << "." << inst.inst_id; + out_ << " " << inst.ir_id << ", " << inst.inst_id; + } + + auto FormatInstructionRHS(LazyImportRef inst) -> void { + // Don't format the inst_id because it refers to a different IR. + // TODO: Consider a better way to format the InstID from other IRs. + out_ << " " << inst.ir_id << ", " << inst.inst_id; } auto FormatInstructionRHS(SpliceBlock inst) -> void { diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 6aa2b3051b6d..c658c309fa25 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -19,6 +19,7 @@ class Inst; struct Class; struct Function; struct Interface; +struct NameScope; struct TypeInfo; // The ID of an instruction. @@ -181,7 +182,7 @@ struct NameId : public IdBase, public Printable { // Returns the IdentifierId corresponding to this NameId, or an invalid // IdentifierId if this is a special name. - auto AsIdentifierId() -> IdentifierId { + auto AsIdentifierId() const -> IdentifierId { return index >= 0 ? IdentifierId(index) : IdentifierId::Invalid; } @@ -213,10 +214,12 @@ constexpr NameId NameId::Base = NameId(NameId::InvalidIndex - 5); // The ID of a name scope. struct NameScopeId : public IdBase, public Printable { - using ValueType = llvm::DenseMap; + using ValueType = NameScope; // An explicitly invalid ID. static const NameScopeId Invalid; + // The package (or file) name scope, guaranteed to be the first added. + static const NameScopeId Package; using IdBase::IdBase; auto Print(llvm::raw_ostream& out) const -> void { @@ -227,6 +230,7 @@ struct NameScopeId : public IdBase, public Printable { constexpr NameScopeId NameScopeId::Invalid = NameScopeId(NameScopeId::InvalidIndex); +constexpr NameScopeId NameScopeId::Package = NameScopeId(0); // The ID of an instruction block. struct InstBlockId : public IdBase, public Printable { diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index 2815cb9a0c5b..53e28e669597 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -47,6 +47,7 @@ CARBON_SEM_IR_INST_KIND(Import) CARBON_SEM_IR_INST_KIND(InitializeFrom) CARBON_SEM_IR_INST_KIND(InterfaceDecl) CARBON_SEM_IR_INST_KIND(IntLiteral) +CARBON_SEM_IR_INST_KIND(LazyImportRef) CARBON_SEM_IR_INST_KIND(NameRef) CARBON_SEM_IR_INST_KIND(Namespace) CARBON_SEM_IR_INST_KIND(NoOp) diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index 8d207ed5a212..89d4783ecee4 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -341,6 +341,20 @@ struct IntLiteral { IntId int_id; }; +// This instruction is not intended for direct use. Instead, it should be loaded +// if it's referenced through name resolution. +struct LazyImportRef { + static constexpr auto Kind = + InstKind::LazyImportRef.Define("lazy_import_ref"); + + // No parse node: an instruction's parse tree node must refer to a node in the + // current parse tree. This cannot use the cross-referenced instruction's + // parse tree node because it will be in a different parse tree. + + CrossRefIRId ir_id; + InstId inst_id; +}; + struct NameRef { static constexpr auto Kind = InstKind::NameRef.Define("name_ref"); diff --git a/toolchain/sem_ir/value_stores.h b/toolchain/sem_ir/value_stores.h index 9b502ab56db4..f0c6ed2b40bb 100644 --- a/toolchain/sem_ir/value_stores.h +++ b/toolchain/sem_ir/value_stores.h @@ -164,6 +164,15 @@ class NameStoreWrapper { const StringStoreWrapper* identifiers_; }; +struct NameScope { + // Names in the scope. + llvm::DenseMap names; + + // Whether the scope corresponds to an import that failed. There may still be + // names from successful imports, or the current file. + bool has_load_error = false; +}; + // Provides a ValueStore wrapper for an API specific to name scopes. class NameScopeStore { public: @@ -174,12 +183,14 @@ class NameScopeStore { // duplicates. auto AddEntry(NameScopeId scope_id, NameId name_id, InstId target_id) -> bool { - return values_.Get(scope_id).insert({name_id, target_id}).second; + return values_.Get(scope_id).names.insert({name_id, target_id}).second; } // Returns the requested name scope. - auto Get(NameScopeId scope_id) const - -> const llvm::DenseMap& { + auto Get(NameScopeId scope_id) -> NameScope& { return values_.Get(scope_id); } + + // Returns the requested name scope. + auto Get(NameScopeId scope_id) const -> const NameScope& { return values_.Get(scope_id); }