diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index 51392d65458c..47ff599b0790 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -8,6 +8,7 @@ #include "toolchain/base/pretty_stack_trace_function.h" #include "toolchain/base/value_store.h" #include "toolchain/check/context.h" +#include "toolchain/parse/tree.h" #include "toolchain/parse/tree_node_location_translator.h" #include "toolchain/sem_ir/file.h" @@ -100,42 +101,48 @@ static auto CheckParseTree(const SemIR::File& builtin_ir, UnitInfo& unit_info, // The package and library names, used as map keys. using ImportKey = std::pair; -// Returns a key form of the package object. -static auto GetImportKey(UnitInfo& unit_info, - Parse::Tree::PackagingNames package) -> ImportKey { +// Returns a key form of the package object. file_package_id is only used for +// imports, not the main package directive; as a consequence, it will be invalid +// for the main package directive. +static auto GetImportKey(UnitInfo& unit_info, IdentifierId file_package_id, + Parse::Tree::PackagingNames names) -> ImportKey { auto* stores = unit_info.unit->value_stores; - return {package.package_id.is_valid() - ? stores->identifiers().Get(package.package_id) - : "", - package.library_id.is_valid() - ? stores->string_literals().Get(package.library_id) - : ""}; + llvm::StringRef package_name = + names.package_id.is_valid() ? stores->identifiers().Get(names.package_id) + : file_package_id.is_valid() ? stores->identifiers().Get(file_package_id) + : ""; + llvm::StringRef library_name = + names.library_id.is_valid() + ? stores->string_literals().Get(names.library_id) + : ""; + return {package_name, library_name}; } static constexpr llvm::StringLiteral ExplicitMainName = "Main"; // Marks an import as required on both the source and target file. -// TODO: When importing without a package name is supported, check that it's -// used correctly. +// +// The ID comparisons between the import and unit are okay because they both +// come from the same file. static auto TrackImport( llvm::DenseMap& api_map, llvm::DenseMap* explicit_import_map, UnitInfo& unit_info, Parse::Tree::PackagingNames import) -> void { - auto import_key = GetImportKey(unit_info, import); + const auto& packaging = unit_info.unit->parse_tree->packaging_directive(); - // Specialize the error for imports from `Main`. - if (import_key.first == ExplicitMainName) { - // Implicit imports will have already warned. - if (explicit_import_map) { - CARBON_DIAGNOSTIC(ImportMainPackage, Error, - "Cannot import `Main` from other packages."); - unit_info.emitter.Emit(import.node, ImportMainPackage); - } - return; - } + IdentifierId file_package_id = + packaging ? packaging->names.package_id : IdentifierId::Invalid; + auto import_key = GetImportKey(unit_info, file_package_id, import); + // True if the import has `Main` as the package name, even if it comes from + // the file's packaging (diagnostics may differentiate). + bool is_explicit_main = import_key.first == ExplicitMainName; + + // Explicit imports need more validation than implicit ones. We try to do + // these in an order of imports that should be removed, followed by imports + // that might be valid with syntax fixes. if (explicit_import_map) { - // Check for redundant imports. + // Diagnose redundant imports. if (auto [insert_it, success] = explicit_import_map->insert({import_key, import.node}); !success) { @@ -148,21 +155,74 @@ static auto TrackImport( return; } - // Check for explicit imports of the same library. The ID comparison is okay - // in this case because both come from the same file. - auto packaging = unit_info.unit->parse_tree->packaging_directive(); - if (packaging && import.package_id == packaging->names.package_id && - import.library_id == packaging->names.library_id) { + // True if the file's package is implicitly `Main` (by omitting an explicit + // package name). + bool is_file_implicit_main = + !packaging || !packaging->names.package_id.is_valid(); + // True if the import is using implicit "current package" syntax (by + // omitting an explicit package name). + bool is_import_implicit_current_package = !import.package_id.is_valid(); + // True if the import is using `default` library syntax. + bool is_import_default_library = !import.library_id.is_valid(); + // True if the import and file point at the same package, even by + // incorrectly specifying the current package name to `import`. + bool is_same_package = is_import_implicit_current_package || + import.package_id == file_package_id; + // True if the import points at the same library as the file's library. + bool is_same_library = + is_same_package && + (packaging ? import.library_id == packaging->names.library_id + : is_import_default_library); + + // Diagnose explicit imports of the same library, whether from `api` or + // `impl`. + if (is_same_library) { CARBON_DIAGNOSTIC(ExplicitImportApi, Error, "Explicit import of `api` from `impl` file is " "redundant with implicit import."); CARBON_DIAGNOSTIC(ImportSelf, Error, "File cannot import itself."); - unit_info.emitter.Emit( - import.node, packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl - ? ExplicitImportApi - : ImportSelf); + bool is_impl = + !packaging || packaging->api_or_impl == Parse::Tree::ApiOrImpl::Impl; + unit_info.emitter.Emit(import.node, + is_impl ? ExplicitImportApi : ImportSelf); return; } + + // Diagnose explicit imports of `Main//default`. There is no `api` for it. + // This lets other diagnostics handle explicit `Main` package naming. + if (is_file_implicit_main && is_import_implicit_current_package && + is_import_default_library) { + CARBON_DIAGNOSTIC(ImportMainDefaultLibrary, Error, + "Cannot import `Main//default`."); + unit_info.emitter.Emit(import.node, ImportMainDefaultLibrary); + + return; + } + + if (!is_import_implicit_current_package) { + // Diagnose explicit imports of the same package that use the package + // name. + if (is_same_package || (is_file_implicit_main && is_explicit_main)) { + CARBON_DIAGNOSTIC( + ImportCurrentPackageByName, Error, + "Imports from the current package must omit the package name."); + unit_info.emitter.Emit(import.node, ImportCurrentPackageByName); + return; + } + + // Diagnose explicit imports from `Main`. + if (is_explicit_main) { + CARBON_DIAGNOSTIC(ImportMainPackage, Error, + "Cannot import `Main` from other packages."); + unit_info.emitter.Emit(import.node, ImportMainPackage); + return; + } + } + } else if (is_explicit_main) { + // An implicit import with an explicit `Main` occurs when a `package` rule + // has bad syntax, which will have been diagnosed when building the API map. + // As a consequence, we return silently. + return; } if (auto api = api_map.find(import_key); api != api_map.end()) { @@ -194,15 +254,18 @@ auto CheckParseTrees(const SemIR::File& builtin_ir, // Create a map of APIs which might be imported. llvm::DenseMap api_map; for (auto& unit_info : unit_infos) { + // TODO: It may be good to validate filenames here, but that would have use + // put .impl.carbon on almost all tests (which are in `Main//default`). We + // should probably get leads direction on filenames before enforcing. const auto& packaging = unit_info.unit->parse_tree->packaging_directive(); if (packaging) { - auto import_key = GetImportKey(unit_info, packaging->names); - // Catch explicit `Main` errors before they become marked as possible + auto import_key = + GetImportKey(unit_info, IdentifierId::Invalid, packaging->names); + // Diagnose explicit `Main` uses before they become marked as possible // APIs. if (import_key.first == ExplicitMainName) { - CARBON_DIAGNOSTIC( - ExplicitMainPackage, Error, - "Default `Main` library must omit `package` directive."); + CARBON_DIAGNOSTIC(ExplicitMainPackage, Error, + "`Main//default` must omit `package` directive."); CARBON_DIAGNOSTIC( ExplicitMainLibrary, Error, "Use `library` directive in `Main` package libraries."); @@ -230,10 +293,12 @@ auto CheckParseTrees(const SemIR::File& builtin_ir, llvm::SmallVector ready_to_check; ready_to_check.reserve(units.size()); for (auto& unit_info : unit_infos) { - const auto& packaging = unit_info.unit->parse_tree->packaging_directive(); - if (packaging && 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); + if (const auto& packaging = + 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); + } } llvm::DenseMap explicit_import_map; diff --git a/toolchain/check/handle_import_and_package.cpp b/toolchain/check/handle_import_and_package.cpp index ded009468445..40a7ef01281d 100644 --- a/toolchain/check/handle_import_and_package.cpp +++ b/toolchain/check/handle_import_and_package.cpp @@ -14,14 +14,48 @@ auto HandleImportIntroducer(Context& /*context*/, Parse::Node /*parse_node*/) return true; } +auto HandleImportDirective(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandleLibraryIntroducer(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandleLibraryDirective(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + auto HandlePackageIntroducer(Context& /*context*/, Parse::Node /*parse_node*/) -> bool { return true; } -auto HandleLibrary(Context& context, Parse::Node /*parse_node*/) -> bool { - // Pop and discard the library name from the node stack. - context.node_stack().Pop(); +auto HandlePackageDirective(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandleLibrarySpecifier(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandlePackageName(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandleLibraryName(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { + return true; +} + +auto HandleDefaultLibrary(Context& /*context*/, Parse::Node /*parse_node*/) + -> bool { return true; } @@ -35,18 +69,4 @@ auto HandlePackageImpl(Context& /*context*/, Parse::Node /*parse_node*/) return true; } -auto HandleImportDirective(Context& context, Parse::Node /*parse_node*/) - -> bool { - // Pop and discard the identifier from the node stack. - context.node_stack().Pop(); - return true; -} - -auto HandlePackageDirective(Context& context, Parse::Node /*parse_node*/) - -> bool { - // Pop and discard the identifier from the node stack. - context.node_stack().Pop(); - return true; -} - } // namespace Carbon::Check diff --git a/toolchain/check/testdata/packages/explicit_imports.carbon b/toolchain/check/testdata/packages/explicit_imports.carbon index b1077e470e80..fcd5b188b6bb 100644 --- a/toolchain/check/testdata/packages/explicit_imports.carbon +++ b/toolchain/check/testdata/packages/explicit_imports.carbon @@ -12,24 +12,37 @@ package Api api; package Api library "lib" api; -// --- import_api.carbon +// --- same_package.carbon + +package Api library "other" api; + +import library default; +import library "lib"; + +// --- different_package.carbon + +package ApiOther api; import Api; import Api library "lib"; +// --- main_lib_api.carbon + +library "lib" api; + +// --- main_import.carbon + +import library "lib"; + // CHECK:STDOUT: file "api.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "api_lib.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String +// CHECK:STDOUT: file "same_package.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file "import_api.carbon" { -// CHECK:STDOUT: %.loc3: String = string_literal "lib" +// CHECK:STDOUT: file "different_package.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_lib_api.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_import.carbon" { // 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 72b0dba05926..11c9d66841de 100644 --- a/toolchain/check/testdata/packages/fail_api_not_found.carbon +++ b/toolchain/check/testdata/packages/fail_api_not_found.carbon @@ -18,12 +18,16 @@ package Foo impl; // CHECK:STDERR: ^ package Foo library "Bar" impl; +// --- no_api_main_lib.carbon + +// CHECK:STDERR: no_api_main_lib.carbon:[[@LINE+3]]:1: ERROR: Corresponding API not found. +// CHECK:STDERR: library "Bar" impl; +// CHECK:STDERR: ^ +library "Bar" impl; + // CHECK:STDOUT: file "no_api.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "no_api_lib.carbon" { -// CHECK:STDOUT: %.loc5: String = string_literal "Bar" +// CHECK:STDOUT: } +// CHECK:STDOUT: file "no_api_main_lib.carbon" { // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_default.carbon b/toolchain/check/testdata/packages/fail_import_default.carbon new file mode 100644 index 000000000000..805c75e1080d --- /dev/null +++ b/toolchain/check/testdata/packages/fail_import_default.carbon @@ -0,0 +1,48 @@ +// 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 + +// --- default_api.carbon + +package A api; + +// CHECK:STDERR: default_api.carbon:[[@LINE+3]]:1: ERROR: File cannot import itself. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +import library default; + +// --- default_impl.carbon + +package A impl; + +// CHECK:STDERR: default_impl.carbon:[[@LINE+3]]:1: ERROR: Explicit import of `api` from `impl` file is redundant with implicit import. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +import library default; + +// --- main_import_default.carbon + +// CHECK:STDERR: main_import_default.carbon:[[@LINE+3]]:1: ERROR: Explicit import of `api` from `impl` file is redundant with implicit import. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +import library default; + +// --- main_lib_import_default.carbon + +library "lib" api; + +// CHECK:STDERR: main_lib_import_default.carbon:[[@LINE+3]]:1: ERROR: Cannot import `Main//default`. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +import library default; + +// CHECK:STDOUT: file "default_api.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "default_impl.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_import_default.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_lib_import_default.carbon" { +// CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_invalid.carbon b/toolchain/check/testdata/packages/fail_import_invalid.carbon index c8e847933f9c..58ebbaacbb2f 100644 --- a/toolchain/check/testdata/packages/fail_import_invalid.carbon +++ b/toolchain/check/testdata/packages/fail_import_invalid.carbon @@ -6,14 +6,28 @@ // --- main.carbon -// CHECK:STDERR: main.carbon:[[@LINE+3]]:1: ERROR: Cannot import `Main` from other packages. +// CHECK:STDERR: main.carbon:[[@LINE+3]]:1: ERROR: Imports from the current package must omit the package name. // CHECK:STDERR: import Main; // CHECK:STDERR: ^ import Main; // --- main_lib.carbon -// CHECK:STDERR: main_lib.carbon:[[@LINE+3]]:1: ERROR: Cannot import `Main` from other packages. +// CHECK:STDERR: main_lib.carbon:[[@LINE+3]]:1: ERROR: Imports from the current package must omit the package name. +// CHECK:STDERR: import Main library "lib"; +// CHECK:STDERR: ^ +import Main library "lib"; + +// --- not_main.carbon + +package NotMain api; + +// CHECK:STDERR: not_main.carbon:[[@LINE+3]]:1: ERROR: Cannot import `Main` from other packages. +// CHECK:STDERR: import Main; +// CHECK:STDERR: ^ +import Main; + +// CHECK:STDERR: not_main.carbon:[[@LINE+3]]:1: ERROR: Cannot import `Main` from other packages. // CHECK:STDERR: import Main library "lib"; // CHECK:STDERR: ^ import Main library "lib"; @@ -32,9 +46,9 @@ import This; package This library "lib" api; // CHECK:STDERR: this_lib.carbon:[[@LINE+3]]:1: ERROR: File cannot import itself. -// CHECK:STDERR: import This library "lib"; +// CHECK:STDERR: import library "lib"; // CHECK:STDERR: ^ -import This library "lib"; +import library "lib"; // --- implicit_api.carbon @@ -62,50 +76,30 @@ package Implicit library "lib" impl; // CHECK:STDERR: ^ import Implicit library "lib"; -// --- unknown.carbon +// --- not_found.carbon -// CHECK:STDERR: unknown.carbon:[[@LINE+3]]:1: ERROR: Imported API not found. -// CHECK:STDERR: import Unknown; +// CHECK:STDERR: not_found.carbon:[[@LINE+3]]:1: ERROR: Imported API not found. +// CHECK:STDERR: import NotFound; // CHECK:STDERR: ^ -import Unknown; +import NotFound; // CHECK:STDOUT: file "main.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "main_lib.carbon" { -// CHECK:STDOUT: %.loc5: String = string_literal "lib" +// CHECK:STDOUT: } +// CHECK:STDOUT: file "not_main.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "this.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "this_lib.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" -// CHECK:STDOUT: %.loc7: String = string_literal "lib" // CHECK:STDOUT: } // CHECK:STDOUT: file "implicit_api.carbon" { // CHECK:STDOUT: } // CHECK:STDOUT: file "implicit_impl.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "implicit_lib_api.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "implicit_lib_impl.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" -// CHECK:STDOUT: %.loc7: String = string_literal "lib" // CHECK:STDOUT: } -// CHECK:STDOUT: file "unknown.carbon" { +// CHECK:STDOUT: file "not_found.carbon" { // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_import_repeat.carbon b/toolchain/check/testdata/packages/fail_import_repeat.carbon index 473a28206361..712b2abcd683 100644 --- a/toolchain/check/testdata/packages/fail_import_repeat.carbon +++ b/toolchain/check/testdata/packages/fail_import_repeat.carbon @@ -12,39 +12,59 @@ package Api api; package Api library "lib" api; -// --- import_api.carbon +// --- main_lib.carbon + +library "lib" api; + +// --- import.carbon import Api; -// CHECK:STDERR: import_api.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. +// CHECK:STDERR: import.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. // CHECK:STDERR: import Api; // CHECK:STDERR: ^ -// CHECK:STDERR: import_api.carbon:[[@LINE-4]]:1: First import here. +// CHECK:STDERR: import.carbon:[[@LINE-4]]:1: First import here. // CHECK:STDERR: import Api; // CHECK:STDERR: ^ import Api; + import Api library "lib"; -// CHECK:STDERR: import_api.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. +// CHECK:STDERR: import.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. // CHECK:STDERR: import Api library "lib"; // CHECK:STDERR: ^ -// CHECK:STDERR: import_api.carbon:[[@LINE-4]]:1: First import here. +// CHECK:STDERR: import.carbon:[[@LINE-4]]:1: First import here. // CHECK:STDERR: import Api library "lib"; // CHECK:STDERR: ^ import Api library "lib"; +import library "lib"; +// CHECK:STDERR: import.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. +// CHECK:STDERR: import library "lib"; +// CHECK:STDERR: ^ +// CHECK:STDERR: import.carbon:[[@LINE-4]]:1: First import here. +// CHECK:STDERR: import library "lib"; +// CHECK:STDERR: ^ +import library "lib"; + +// --- default_import.carbon + +package Api library "not_default" api; + +import library default; +// CHECK:STDERR: default_import.carbon:[[@LINE+6]]:1: ERROR: Library imported more than once. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +// CHECK:STDERR: default_import.carbon:[[@LINE-4]]:1: First import here. +// CHECK:STDERR: import library default; +// CHECK:STDERR: ^ +import library default; + // CHECK:STDOUT: file "api.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "api_lib.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String +// CHECK:STDOUT: file "main_lib.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file "import_api.carbon" { -// CHECK:STDOUT: %.loc10: String = string_literal "lib" -// CHECK:STDOUT: %.loc17: String = string_literal "lib" +// CHECK:STDOUT: file "import.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "default_import.carbon" { // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/fail_package_main.carbon b/toolchain/check/testdata/packages/fail_package_main.carbon index ee572cbe578f..afb49f7a5b04 100644 --- a/toolchain/check/testdata/packages/fail_package_main.carbon +++ b/toolchain/check/testdata/packages/fail_package_main.carbon @@ -6,14 +6,14 @@ // --- main.carbon -// CHECK:STDERR: main.carbon:[[@LINE+3]]:1: ERROR: Default `Main` library must omit `package` directive. +// CHECK:STDERR: main.carbon:[[@LINE+3]]:1: ERROR: `Main//default` must omit `package` directive. // CHECK:STDERR: package Main api; // CHECK:STDERR: ^ package Main api; // --- main_impl.carbon -// CHECK:STDERR: main_impl.carbon:[[@LINE+3]]:1: ERROR: Default `Main` library must omit `package` directive. +// CHECK:STDERR: main_impl.carbon:[[@LINE+3]]:1: ERROR: `Main//default` must omit `package` directive. // CHECK:STDERR: package Main impl; // CHECK:STDERR: ^ package Main impl; @@ -21,7 +21,7 @@ package Main impl; // --- raw_main.carbon // `Main` isn't a keyword, so this fails the same way. -// CHECK:STDERR: raw_main.carbon:[[@LINE+3]]:1: ERROR: Default `Main` library must omit `package` directive. +// CHECK:STDERR: raw_main.carbon:[[@LINE+3]]:1: ERROR: `Main//default` must omit `package` directive. // CHECK:STDERR: package r#Main api; // CHECK:STDERR: ^ package r#Main api; @@ -39,10 +39,5 @@ package Main library "lib" api; // CHECK:STDOUT: } // CHECK:STDOUT: file "raw_main.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "main_lib.carbon" { -// CHECK:STDOUT: %.loc5: String = string_literal "lib" // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/packages/implicit_imports.carbon b/toolchain/check/testdata/packages/implicit_imports.carbon index 79c96e56e9ef..be20ccb938cc 100644 --- a/toolchain/check/testdata/packages/implicit_imports.carbon +++ b/toolchain/check/testdata/packages/implicit_imports.carbon @@ -33,14 +33,19 @@ package WithImpl library "lib" api; package WithImpl library "lib" impl; +// --- main.carbon + +// --- main_lib.carbon + +library "lib" api; + +// --- main_lib_impl.carbon + +library "lib" impl; + // CHECK:STDOUT: file "api_only.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "api_only_lib.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl_api.carbon" { // CHECK:STDOUT: } @@ -48,17 +53,13 @@ package WithImpl library "lib" impl; // CHECK:STDOUT: } // CHECK:STDOUT: file "with_impl_impl_extra.carbon" { // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "with_impl_lib_api.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" // CHECK:STDOUT: } -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %.1: type = ptr_type String -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: file "with_impl_lib_impl.carbon" { -// CHECK:STDOUT: %.loc2: String = string_literal "lib" +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_lib.carbon" { +// CHECK:STDOUT: } +// CHECK:STDOUT: file "main_lib_impl.carbon" { // CHECK:STDOUT: } diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 760df86293bd..280712c32344 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -86,8 +86,10 @@ CARBON_DIAGNOSTIC_KIND(FirstDecl) CARBON_DIAGNOSTIC_KIND(FirstNonCommentLine) CARBON_DIAGNOSTIC_KIND(PackageTooLate) CARBON_DIAGNOSTIC_KIND(ImportTooLate) -CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterKeyword) +CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterPackage) +CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterImport) CARBON_DIAGNOSTIC_KIND(ExpectedLibraryName) +CARBON_DIAGNOSTIC_KIND(ExpectedLibraryNameOrDefault) CARBON_DIAGNOSTIC_KIND(MissingLibraryKeyword) CARBON_DIAGNOSTIC_KIND(ExpectedApiOrImpl) @@ -122,6 +124,8 @@ CARBON_DIAGNOSTIC_KIND(ImportCycleDetected) CARBON_DIAGNOSTIC_KIND(ExplicitMainPackage) CARBON_DIAGNOSTIC_KIND(ExplicitMainLibrary) CARBON_DIAGNOSTIC_KIND(ImportMainPackage) +CARBON_DIAGNOSTIC_KIND(ImportMainDefaultLibrary) +CARBON_DIAGNOSTIC_KIND(ImportCurrentPackageByName) CARBON_DIAGNOSTIC_KIND(ImportSelf) CARBON_DIAGNOSTIC_KIND(ExplicitImportApi) CARBON_DIAGNOSTIC_KIND(RepeatedImport) diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index c9ecca9df885..5bcf02087395 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -30,11 +30,15 @@ auto HandleDeclScopeLoop(Context& context) -> void { context.PopAndDiscardState(); return; } - // `import` and `package` manage their packaging state. + // `import`, `library`, and `package` manage their packaging state. case Lex::TokenKind::Import: { context.PushState(State::Import); return; } + case Lex::TokenKind::Library: { + context.PushState(State::Library); + return; + } case Lex::TokenKind::Package: { context.PushState(State::Package); return; diff --git a/toolchain/parse/handle_import_and_package.cpp b/toolchain/parse/handle_import_and_package.cpp index 1345a8c9c28f..506739d22dc3 100644 --- a/toolchain/parse/handle_import_and_package.cpp +++ b/toolchain/parse/handle_import_and_package.cpp @@ -5,113 +5,165 @@ #include "toolchain/base/value_store.h" #include "toolchain/lex/tokenized_buffer.h" #include "toolchain/parse/context.h" +#include "toolchain/parse/node_kind.h" namespace Carbon::Parse { -// Provides error exiting logic for `import`/`package`, skipping to the semi. -static auto ExitOnParseError(Context& context, Context::StateStackEntry state, - NodeKind directive) { +// Provides common error exiting logic that skips to the semi, if present. +static auto OnParseError(Context& context, Context::StateStackEntry state, + NodeKind directive) -> void { auto semi_token = context.SkipPastLikelyEnd(state.token); return context.AddNode(directive, semi_token ? *semi_token : state.token, state.subtree_start, /*has_error=*/true); } -// Handles the main parsing of `import`/`package`. It's expected that the -// introducer is already added. -static auto HandleImportAndPackage(Context& context, +// Handles parsing of the library name. Returns the name's ID on success, which +// may be invalid for `default`. +static auto HandleLibraryName(Context& context, bool accept_default) + -> std::optional { + if (auto library_name_token = + context.ConsumeIf(Lex::TokenKind::StringLiteral)) { + context.AddLeafNode(NodeKind::LibraryName, *library_name_token); + return context.tokens().GetStringLiteral(*library_name_token); + } + + if (accept_default) { + if (auto default_token = context.ConsumeIf(Lex::TokenKind::Default)) { + context.AddLeafNode(NodeKind::DefaultLibrary, *default_token); + return StringLiteralId::Invalid; + } + } + + CARBON_DIAGNOSTIC( + ExpectedLibraryNameOrDefault, Error, + "Expected `default` or a string literal to specify the library name."); + CARBON_DIAGNOSTIC(ExpectedLibraryName, Error, + "Expected a string literal to specify the library name."); + context.emitter().Emit(*context.position(), accept_default + ? ExpectedLibraryNameOrDefault + : ExpectedLibraryName); + return std::nullopt; +} + +// Returns whether `api` or `impl` is provided, or prints an error and returns +// nullopt. +static auto HandleApiOrImpl(Context& context) + -> std::optional { + switch (context.PositionKind()) { + case Lex::TokenKind::Api: { + context.AddLeafNode(NodeKind::PackageApi, + context.ConsumeChecked(Lex::TokenKind::Api)); + return Tree::ApiOrImpl::Api; + break; + } + case Lex::TokenKind::Impl: { + context.AddLeafNode(NodeKind::PackageImpl, + context.ConsumeChecked(Lex::TokenKind::Impl)); + return Tree::ApiOrImpl::Impl; + break; + } + default: { + CARBON_DIAGNOSTIC(ExpectedApiOrImpl, Error, "Expected `api` or `impl`."); + context.emitter().Emit(*context.position(), ExpectedApiOrImpl); + return std::nullopt; + } + } +} + +// Handles everything after the directive's introducer. +static auto HandleDirectiveContent(Context& context, Context::StateStackEntry state, - NodeKind directive, bool is_package) + NodeKind directive, + llvm::function_ref on_parse_error) -> void { Tree::PackagingNames names{.node = Node(state.subtree_start)}; - if (auto package_name_token = context.ConsumeIf(Lex::TokenKind::Identifier)) { - names.package_id = context.tokens().GetIdentifier(*package_name_token); - context.AddLeafNode(NodeKind::Name, *package_name_token); - } else { - CARBON_DIAGNOSTIC(ExpectedIdentifierAfterKeyword, Error, - "Expected identifier after `{0}`.", Lex::TokenKind); - context.emitter().Emit(*context.position(), ExpectedIdentifierAfterKeyword, - context.tokens().GetKind(state.token)); - ExitOnParseError(context, state, directive); - return; - } - - if (auto library_token = context.ConsumeIf(Lex::TokenKind::Library)) { - auto library_start = context.tree().size(); - - if (auto library_name_token = - context.ConsumeIf(Lex::TokenKind::StringLiteral)) { - names.library_id = context.tokens().GetStringLiteral(*library_name_token); - context.AddLeafNode(NodeKind::Literal, *library_name_token); - } else { - CARBON_DIAGNOSTIC( - ExpectedLibraryName, Error, - "Expected a string literal to specify the library name."); - context.emitter().Emit(*context.position(), ExpectedLibraryName); - ExitOnParseError(context, state, directive); + if (directive != NodeKind::LibraryDirective) { + if (auto package_name_token = + context.ConsumeIf(Lex::TokenKind::Identifier)) { + names.package_id = context.tokens().GetIdentifier(*package_name_token); + context.AddLeafNode(NodeKind::PackageName, *package_name_token); + } else if (directive == NodeKind::PackageDirective || + !context.PositionIs(Lex::TokenKind::Library)) { + CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error, + "Expected identifier after `package`."); + CARBON_DIAGNOSTIC(ExpectedIdentifierAfterImport, Error, + "Expected identifier or `library` after `import`."); + context.emitter().Emit(*context.position(), + directive == NodeKind::PackageDirective + ? ExpectedIdentifierAfterPackage + : ExpectedIdentifierAfterImport); + on_parse_error(); return; } - - context.AddNode(NodeKind::Library, *library_token, library_start, - /*has_error=*/false); } - auto next_kind = context.PositionKind(); - if (!names.library_id.is_valid() && - next_kind == Lex::TokenKind::StringLiteral) { - // If we come acroess a string literal and we didn't parse `library - // "..."` yet, then most probably the user forgot to add `library` - // before the library name. - CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error, - "Missing `library` keyword."); - context.emitter().Emit(*context.position(), MissingLibraryKeyword); - ExitOnParseError(context, state, directive); - return; - } - - Tree::ApiOrImpl api_or_impl; - if (is_package) { - switch (next_kind) { - case Lex::TokenKind::Api: { - context.AddLeafNode(NodeKind::PackageApi, context.Consume()); - api_or_impl = Tree::ApiOrImpl::Api; - break; - } - case Lex::TokenKind::Impl: { - context.AddLeafNode(NodeKind::PackageImpl, context.Consume()); - api_or_impl = Tree::ApiOrImpl::Impl; - break; - } - default: { - CARBON_DIAGNOSTIC(ExpectedApiOrImpl, Error, - "Expected `api` or `impl`."); - context.emitter().Emit(*context.position(), ExpectedApiOrImpl); - ExitOnParseError(context, state, directive); + // Parse the optional library keyword. + bool accept_default = !names.package_id.is_valid(); + if (directive == NodeKind::LibraryDirective) { + auto library_id = HandleLibraryName(context, accept_default); + if (!library_id) { + on_parse_error(); + return; + } + names.library_id = *library_id; + } else { + auto next_kind = context.PositionKind(); + if (next_kind == Lex::TokenKind::Library) { + auto library_token = context.ConsumeChecked(Lex::TokenKind::Library); + auto library_subtree_start = context.tree().size(); + auto library_id = HandleLibraryName(context, accept_default); + if (!library_id) { + on_parse_error(); return; } + names.library_id = *library_id; + context.AddNode(NodeKind::LibrarySpecifier, library_token, + library_subtree_start, + /*has_error=*/false); + } else if (next_kind == Lex::TokenKind::StringLiteral || + (accept_default && next_kind == Lex::TokenKind::Default)) { + // If we come across a string literal and we didn't parse `library + // "..."` yet, then most probably the user forgot to add `library` + // before the library name. + CARBON_DIAGNOSTIC(MissingLibraryKeyword, Error, + "Missing `library` keyword."); + context.emitter().Emit(*context.position(), MissingLibraryKeyword); + on_parse_error(); + return; } } - if (!context.PositionIs(Lex::TokenKind::Semi)) { - context.EmitExpectedDeclSemi(context.tokens().GetKind(state.token)); - ExitOnParseError(context, state, directive); - return; + std::optional api_or_impl; + if (directive != NodeKind::ImportDirective) { + api_or_impl = HandleApiOrImpl(context); + if (!api_or_impl) { + on_parse_error(); + return; + } } - if (is_package) { - context.set_packaging_directive(names, api_or_impl); + if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) { + if (directive == NodeKind::ImportDirective) { + context.AddImport(names); + } else { + context.set_packaging_directive(names, *api_or_impl); + } + + context.AddNode(directive, *semi, state.subtree_start, state.has_error); } else { - context.AddImport(names); + context.EmitExpectedDeclSemi(context.tokens().GetKind(state.token)); + on_parse_error(); } - - context.AddNode(directive, context.Consume(), state.subtree_start, - state.has_error); } auto HandleImport(Context& context) -> void { auto state = context.PopState(); - auto intro_token = context.Consume(); + auto directive = NodeKind::ImportDirective; + auto on_parse_error = [&] { OnParseError(context, state, directive); }; + + auto intro_token = context.ConsumeChecked(Lex::TokenKind::Import); context.AddLeafNode(NodeKind::ImportIntroducer, intro_token); switch (context.packaging_state()) { @@ -121,8 +173,7 @@ auto HandleImport(Context& context) -> void { [[clang::fallthrough]]; case Context::PackagingState::InImports: - HandleImportAndPackage(context, state, NodeKind::ImportDirective, - /*is_package=*/false); + HandleDirectiveContent(context, state, directive, on_parse_error); break; case Context::PackagingState::AfterNonPackagingDecl: { @@ -137,42 +188,60 @@ auto HandleImport(Context& context) -> void { .Build(intro_token, ImportTooLate) .Note(context.first_non_packaging_token(), FirstDecl) .Emit(); - ExitOnParseError(context, state, NodeKind::ImportDirective); + on_parse_error(); break; } case Context::PackagingState::InImportsAfterNonPackagingDecl: // There is a sequential block of misplaced `import` statements, which can // occur if a declaration is added above `import`s. Avoid duplicate // warnings. - ExitOnParseError(context, state, NodeKind::ImportDirective); + on_parse_error(); break; } } -auto HandlePackage(Context& context) -> void { +// Handles common logic for `package` and `library`. +static auto HandlePackageAndLibraryDirectives(Context& context, + Lex::TokenKind intro_token_kind, + NodeKind intro, + NodeKind directive) -> void { auto state = context.PopState(); - auto intro_token = context.Consume(); - context.AddLeafNode(NodeKind::PackageIntroducer, intro_token); + auto on_parse_error = [&] { OnParseError(context, state, directive); }; + + auto intro_token = context.ConsumeChecked(intro_token_kind); + context.AddLeafNode(intro, intro_token); if (intro_token != Lex::Token::FirstNonCommentToken) { - CARBON_DIAGNOSTIC( - PackageTooLate, Error, - "The `package` directive must be the first non-comment line."); + CARBON_DIAGNOSTIC(PackageTooLate, Error, + "The `{0}` directive must be the first non-comment line.", + Lex::TokenKind); CARBON_DIAGNOSTIC(FirstNonCommentLine, Note, "First non-comment line is here."); context.emitter() - .Build(intro_token, PackageTooLate) + .Build(intro_token, PackageTooLate, intro_token_kind) .Note(Lex::Token::FirstNonCommentToken, FirstNonCommentLine) .Emit(); - ExitOnParseError(context, state, NodeKind::PackageDirective); + on_parse_error(); return; } - // `package` is no longer allowed, but `import` may repeat. + // `package`/`library` is no longer allowed, but `import` may repeat. context.set_packaging_state(Context::PackagingState::InImports); - HandleImportAndPackage(context, state, NodeKind::PackageDirective, - /*is_package=*/true); + + HandleDirectiveContent(context, state, directive, on_parse_error); +} + +auto HandlePackage(Context& context) -> void { + HandlePackageAndLibraryDirectives(context, Lex::TokenKind::Package, + NodeKind::PackageIntroducer, + NodeKind::PackageDirective); +} + +auto HandleLibrary(Context& context) -> void { + HandlePackageAndLibraryDirectives(context, Lex::TokenKind::Library, + NodeKind::LibraryIntroducer, + NodeKind::LibraryDirective); } } // namespace Carbon::Parse diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index 0a8a543b21d4..19157ac014bd 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -95,15 +95,14 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(NameExpr, 0, CARBON_TOKEN(Identifier)) // ---------------------------------------------------------------------------- -// `library`: -// _external_: Literal -// Library -CARBON_PARSE_NODE_KIND_CHILD_COUNT(Library, 1, CARBON_TOKEN(Library)) +// The name of a package or library for `package`, `import`, and `library`. +CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageName, 0, CARBON_TOKEN(Identifier)) +CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryName, 0, CARBON_TOKEN(StringLiteral)) // `package`: // PackageIntroducer -// _external_: Name -// _optional_ _external_: Library +// _optional_ _external_: PackageName +// _optional_ _external_: LibrarySpecifier // PackageApi or PackageImpl // PackageDirective CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageIntroducer, 0, CARBON_TOKEN(Package)) @@ -115,13 +114,27 @@ CARBON_PARSE_NODE_KIND_BRACKET(PackageDirective, PackageIntroducer, // `import`: // ImportIntroducer -// _external_: Name -// _optional_ _external_: Library +// _optional_ _external_: PackageName +// _optional_ _external_: LibrarySpecifier // ImportDirective CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportIntroducer, 0, CARBON_TOKEN(Import)) CARBON_PARSE_NODE_KIND_BRACKET(ImportDirective, ImportIntroducer, CARBON_TOKEN(Semi) CARBON_IF_ERROR(CARBON_TOKEN(Import))) +// `library` as directive: +// LibraryIntroducer +// DefaultLibrary or _external_: LibraryName +// LibraryDirective +CARBON_PARSE_NODE_KIND_CHILD_COUNT(DefaultLibrary, 0, CARBON_TOKEN(Default)) +CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryIntroducer, 0, CARBON_TOKEN(Library)) +CARBON_PARSE_NODE_KIND_BRACKET(LibraryDirective, LibraryIntroducer, + CARBON_TOKEN(Semi) + CARBON_IF_ERROR(CARBON_TOKEN(Library))) + +// `library` in `package` or `import`: +// _external_: LibraryName +// LibrarySpecifier +CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, CARBON_TOKEN(Library)) // `namespace`: // NamespaceStart diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index a8737ac4913d..d99f6e46acc4 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -591,6 +591,12 @@ CARBON_PARSE_STATE(FunctionDefinitionFinish) // (state done) CARBON_PARSE_STATE(Import) +// Handles `library` in directive form. +// +// Always: +// (state done) +CARBON_PARSE_STATE(Library) + // Handles `namespace`. // // namespace ... diff --git a/toolchain/parse/testdata/packages/import/after_import.carbon b/toolchain/parse/testdata/packages/import/after_import.carbon index 7f14322681e6..8a16817cf602 100644 --- a/toolchain/parse/testdata/packages/import/after_import.carbon +++ b/toolchain/parse/testdata/packages/import/after_import.carbon @@ -11,10 +11,10 @@ import B; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'A'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'B'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'B'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/after_package.carbon b/toolchain/parse/testdata/packages/import/after_package.carbon index 7f859725ae1e..fe482c558a9f 100644 --- a/toolchain/parse/testdata/packages/import/after_package.carbon +++ b/toolchain/parse/testdata/packages/import/after_package.carbon @@ -12,11 +12,11 @@ import B; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'A'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, // CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'B'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'B'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/basic.carbon b/toolchain/parse/testdata/packages/import/basic.carbon index 4cfb8a73dbb5..b37335dc3c7f 100644 --- a/toolchain/parse/testdata/packages/import/basic.carbon +++ b/toolchain/parse/testdata/packages/import/basic.carbon @@ -10,7 +10,7 @@ import Geometry; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/current_package_library.carbon b/toolchain/parse/testdata/packages/import/current_package_library.carbon new file mode 100644 index 000000000000..ab955a7e046c --- /dev/null +++ b/toolchain/parse/testdata/packages/import/current_package_library.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 + +// --- default.carbon + +import library default; + +// --- named.carbon + +import library "Shapes"; + +// CHECK:STDOUT: - filename: default.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'DefaultLibrary', text: 'default'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: named.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"Shapes"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_extra_string.carbon b/toolchain/parse/testdata/packages/import/fail_extra_string.carbon index 6d523bad9a56..b58173ac77d4 100644 --- a/toolchain/parse/testdata/packages/import/fail_extra_string.carbon +++ b/toolchain/parse/testdata/packages/import/fail_extra_string.carbon @@ -13,9 +13,9 @@ import Foo library "bar" "baz"; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'Literal', text: '"bar"'}, -// CHECK:STDOUT: {kind: 'Library', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"bar"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_library_is_identifier.carbon b/toolchain/parse/testdata/packages/import/fail_library_is_identifier.carbon index e2a745738e28..911a3a43a50c 100644 --- a/toolchain/parse/testdata/packages/import/fail_library_is_identifier.carbon +++ b/toolchain/parse/testdata/packages/import/fail_library_is_identifier.carbon @@ -13,7 +13,7 @@ import Geometry library Shapes; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_library_skips_name.carbon b/toolchain/parse/testdata/packages/import/fail_library_skips_name.carbon deleted file mode 100644 index 0bad8f5bcce7..000000000000 --- a/toolchain/parse/testdata/packages/import/fail_library_skips_name.carbon +++ /dev/null @@ -1,18 +0,0 @@ -// 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 - -// CHECK:STDERR: fail_library_skips_name.carbon:[[@LINE+3]]:8: ERROR: Expected identifier after `import`. -// CHECK:STDERR: import library "Shapes"; -// CHECK:STDERR: ^ -import library "Shapes"; - -// CHECK:STDOUT: - filename: fail_library_skips_name.carbon -// CHECK:STDOUT: parse_tree: [ -// CHECK:STDOUT: {kind: 'FileStart', text: ''}, -// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, -// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_name_is_keyword.carbon b/toolchain/parse/testdata/packages/import/fail_name_is_keyword.carbon index 27d3b2950004..bc17d80201a6 100644 --- a/toolchain/parse/testdata/packages/import/fail_name_is_keyword.carbon +++ b/toolchain/parse/testdata/packages/import/fail_name_is_keyword.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_name_is_keyword.carbon:[[@LINE+3]]:8: ERROR: Expected identifier after `import`. +// CHECK:STDERR: fail_name_is_keyword.carbon:[[@LINE+3]]:8: ERROR: Expected identifier or `library` after `import`. // CHECK:STDERR: import fn; // CHECK:STDERR: ^ import fn; diff --git a/toolchain/parse/testdata/packages/import/fail_no_name.carbon b/toolchain/parse/testdata/packages/import/fail_no_name.carbon index 1b867b767483..4d52842078a3 100644 --- a/toolchain/parse/testdata/packages/import/fail_no_name.carbon +++ b/toolchain/parse/testdata/packages/import/fail_no_name.carbon @@ -4,7 +4,7 @@ // // AUTOUPDATE -// CHECK:STDERR: fail_no_name.carbon:[[@LINE+3]]:7: ERROR: Expected identifier after `import`. +// CHECK:STDERR: fail_no_name.carbon:[[@LINE+3]]:7: ERROR: Expected identifier or `library` after `import`. // CHECK:STDERR: import; // CHECK:STDERR: ^ import; diff --git a/toolchain/parse/testdata/packages/import/fail_no_semi.carbon b/toolchain/parse/testdata/packages/import/fail_no_semi.carbon index 93580a7f2720..fca391a5aa48 100644 --- a/toolchain/parse/testdata/packages/import/fail_no_semi.carbon +++ b/toolchain/parse/testdata/packages/import/fail_no_semi.carbon @@ -13,7 +13,7 @@ import Geometry // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: 'import', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_omit_library_keyword.carbon b/toolchain/parse/testdata/packages/import/fail_omit_library_keyword.carbon index 815fb103cd4f..1fea016b2f3a 100644 --- a/toolchain/parse/testdata/packages/import/fail_omit_library_keyword.carbon +++ b/toolchain/parse/testdata/packages/import/fail_omit_library_keyword.carbon @@ -13,7 +13,7 @@ import Geometry "Shapes"; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/fail_type.carbon b/toolchain/parse/testdata/packages/import/fail_type.carbon index 6fa8f8d5c475..4b9f180cd299 100644 --- a/toolchain/parse/testdata/packages/import/fail_type.carbon +++ b/toolchain/parse/testdata/packages/import/fail_type.carbon @@ -13,7 +13,7 @@ import Geometry api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/library.carbon b/toolchain/parse/testdata/packages/import/library.carbon index 3d5b756ce3a8..c43f73b11f60 100644 --- a/toolchain/parse/testdata/packages/import/library.carbon +++ b/toolchain/parse/testdata/packages/import/library.carbon @@ -10,9 +10,9 @@ import Geometry library "Shapes"; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, -// CHECK:STDOUT: {kind: 'Literal', text: '"Shapes"'}, -// CHECK:STDOUT: {kind: 'Library', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"Shapes"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/import/ordering.carbon b/toolchain/parse/testdata/packages/import/ordering.carbon new file mode 100644 index 000000000000..284efbf995a0 --- /dev/null +++ b/toolchain/parse/testdata/packages/import/ordering.carbon @@ -0,0 +1,58 @@ +// 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 + +// --- after_import.carbon + +import A; +import B; + +// --- after_library.carbon + +library "A" api; + +import B; + +// --- after_package.carbon + +package A api; + +import B; + +// CHECK:STDOUT: - filename: after_import.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'B'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: after_library.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"A"'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'B'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: after_package.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'B'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/library/basic.carbon b/toolchain/parse/testdata/packages/library/basic.carbon new file mode 100644 index 000000000000..9c24f1b67797 --- /dev/null +++ b/toolchain/parse/testdata/packages/library/basic.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 + +// --- default.carbon + +library default api; + +// --- named.carbon + +library "Shapes" impl; + +// CHECK:STDOUT: - filename: default.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'DefaultLibrary', text: 'default'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: named.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"Shapes"'}, +// CHECK:STDOUT: {kind: 'PackageImpl', text: 'impl'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/library/fail_invalid_name.carbon b/toolchain/parse/testdata/packages/library/fail_invalid_name.carbon new file mode 100644 index 000000000000..6739686812f1 --- /dev/null +++ b/toolchain/parse/testdata/packages/library/fail_invalid_name.carbon @@ -0,0 +1,78 @@ +// 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 + +// --- identifier.carbon + +// CHECK:STDERR: identifier.carbon:[[@LINE+3]]:9: ERROR: Expected `default` or a string literal to specify the library name. +// CHECK:STDERR: library Shapes api; +// CHECK:STDERR: ^ +library Shapes api; + +// --- raw_identifier.carbon + +// CHECK:STDERR: raw_identifier.carbon:[[@LINE+3]]:9: ERROR: Expected `default` or a string literal to specify the library name. +// CHECK:STDERR: library r#default api; +// CHECK:STDERR: ^ +library r#default api; + +// --- missing.carbon + +// CHECK:STDERR: missing.carbon:[[@LINE+3]]:8: ERROR: Expected `default` or a string literal to specify the library name. +// CHECK:STDERR: library; +// CHECK:STDERR: ^ +library; + +// --- missing_with_api.carbon + +// CHECK:STDERR: missing_with_api.carbon:[[@LINE+3]]:9: ERROR: Expected `default` or a string literal to specify the library name. +// CHECK:STDERR: library api; +// CHECK:STDERR: ^ +library api; + +// --- no_semi.carbon + +library "NoSemi" api + +// CHECK:STDERR: no_semi.carbon:[[@LINE+39]]:21: ERROR: `library` declarations must end with a `;`. +// CHECK:STDERR: // CHECK:STDOUT: ] +// CHECK:STDERR: ^ +// CHECK:STDOUT: - filename: identifier.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: raw_identifier.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: missing.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: missing_with_api.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: - filename: no_semi.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"NoSemi"'}, +// CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: 'library', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/library/fail_too_late.carbon b/toolchain/parse/testdata/packages/library/fail_too_late.carbon new file mode 100644 index 000000000000..54ea670b4f97 --- /dev/null +++ b/toolchain/parse/testdata/packages/library/fail_too_late.carbon @@ -0,0 +1,26 @@ +// 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 + +import Geometry; + +// CHECK:STDERR: fail_too_late.carbon:[[@LINE+6]]:1: ERROR: The `library` directive must be the first non-comment line. +// CHECK:STDERR: library "Shapes" api; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_too_late.carbon:[[@LINE-5]]:1: First non-comment line is here. +// CHECK:STDERR: import Geometry; +// CHECK:STDERR: ^ +library "Shapes" api; + +// CHECK:STDOUT: - filename: fail_too_late.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'LibraryIntroducer', text: 'library'}, +// CHECK:STDOUT: {kind: 'LibraryDirective', text: ';', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/api.carbon b/toolchain/parse/testdata/packages/package/api.carbon index 3ac51c66dbdc..420ff101e435 100644 --- a/toolchain/parse/testdata/packages/package/api.carbon +++ b/toolchain/parse/testdata/packages/package/api.carbon @@ -10,7 +10,7 @@ package Geometry api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/package/api_library.carbon b/toolchain/parse/testdata/packages/package/api_library.carbon index 4ab898ef3034..b20bbb981a2a 100644 --- a/toolchain/parse/testdata/packages/package/api_library.carbon +++ b/toolchain/parse/testdata/packages/package/api_library.carbon @@ -10,9 +10,9 @@ package Geometry library "Shapes" api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, -// CHECK:STDOUT: {kind: 'Literal', text: '"Shapes"'}, -// CHECK:STDOUT: {kind: 'Library', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"Shapes"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, // CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 6}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/package/fail_after_import.carbon b/toolchain/parse/testdata/packages/package/fail_after_import.carbon index 843dfa929f67..bb3b1e20407d 100644 --- a/toolchain/parse/testdata/packages/package/fail_after_import.carbon +++ b/toolchain/parse/testdata/packages/package/fail_after_import.carbon @@ -18,7 +18,7 @@ package B api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'ImportIntroducer', text: 'import'}, -// CHECK:STDOUT: {kind: 'Name', text: 'A'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, // CHECK:STDOUT: {kind: 'ImportDirective', text: ';', subtree_size: 3}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 2}, diff --git a/toolchain/parse/testdata/packages/package/fail_after_package.carbon b/toolchain/parse/testdata/packages/package/fail_after_package.carbon index 341c0b2a1315..a9e4fdecd434 100644 --- a/toolchain/parse/testdata/packages/package/fail_after_package.carbon +++ b/toolchain/parse/testdata/packages/package/fail_after_package.carbon @@ -17,7 +17,7 @@ package B api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'A'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'A'}, // CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, diff --git a/toolchain/parse/testdata/packages/package/fail_extra_string.carbon b/toolchain/parse/testdata/packages/package/fail_extra_string.carbon index 9432f4c7ee34..0de4de74db94 100644 --- a/toolchain/parse/testdata/packages/package/fail_extra_string.carbon +++ b/toolchain/parse/testdata/packages/package/fail_extra_string.carbon @@ -13,9 +13,9 @@ package Foo library "bar" "baz"; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Foo'}, -// CHECK:STDOUT: {kind: 'Literal', text: '"bar"'}, -// CHECK:STDOUT: {kind: 'Library', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Foo'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"bar"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 5}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/fail_library_is_identifier.carbon b/toolchain/parse/testdata/packages/package/fail_library_is_identifier.carbon index 03f76bb14973..501c5c532b82 100644 --- a/toolchain/parse/testdata/packages/package/fail_library_is_identifier.carbon +++ b/toolchain/parse/testdata/packages/package/fail_library_is_identifier.carbon @@ -13,7 +13,7 @@ package Geometry library Shapes api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/fail_no_semi.carbon b/toolchain/parse/testdata/packages/package/fail_no_semi.carbon index b9aee3f1bf26..fc3f1d0c3a20 100644 --- a/toolchain/parse/testdata/packages/package/fail_no_semi.carbon +++ b/toolchain/parse/testdata/packages/package/fail_no_semi.carbon @@ -13,7 +13,7 @@ package Geometry api // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageApi', text: 'api'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: 'package', has_error: yes, subtree_size: 4}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/package/fail_no_type.carbon b/toolchain/parse/testdata/packages/package/fail_no_type.carbon index e574d90e24e8..ad70261b4d29 100644 --- a/toolchain/parse/testdata/packages/package/fail_no_type.carbon +++ b/toolchain/parse/testdata/packages/package/fail_no_type.carbon @@ -13,7 +13,7 @@ package Geometry; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/fail_omit_library_keyword.carbon b/toolchain/parse/testdata/packages/package/fail_omit_library_keyword.carbon index 744b5da749f8..a2035a7befa4 100644 --- a/toolchain/parse/testdata/packages/package/fail_omit_library_keyword.carbon +++ b/toolchain/parse/testdata/packages/package/fail_omit_library_keyword.carbon @@ -13,7 +13,7 @@ package Geometry "Shapes" api; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', has_error: yes, subtree_size: 3}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, // CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/packages/package/impl.carbon b/toolchain/parse/testdata/packages/package/impl.carbon index d840b5fadc05..a8414405e701 100644 --- a/toolchain/parse/testdata/packages/package/impl.carbon +++ b/toolchain/parse/testdata/packages/package/impl.carbon @@ -10,7 +10,7 @@ package Geometry impl; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, // CHECK:STDOUT: {kind: 'PackageImpl', text: 'impl'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 4}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''}, diff --git a/toolchain/parse/testdata/packages/package/impl_library.carbon b/toolchain/parse/testdata/packages/package/impl_library.carbon index 878b96811005..f1dfc524cf3d 100644 --- a/toolchain/parse/testdata/packages/package/impl_library.carbon +++ b/toolchain/parse/testdata/packages/package/impl_library.carbon @@ -10,9 +10,9 @@ package Geometry library "Shapes" impl; // CHECK:STDOUT: parse_tree: [ // CHECK:STDOUT: {kind: 'FileStart', text: ''}, // CHECK:STDOUT: {kind: 'PackageIntroducer', text: 'package'}, -// CHECK:STDOUT: {kind: 'Name', text: 'Geometry'}, -// CHECK:STDOUT: {kind: 'Literal', text: '"Shapes"'}, -// CHECK:STDOUT: {kind: 'Library', text: 'library', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PackageName', text: 'Geometry'}, +// CHECK:STDOUT: {kind: 'LibraryName', text: '"Shapes"'}, +// CHECK:STDOUT: {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2}, // CHECK:STDOUT: {kind: 'PackageImpl', text: 'impl'}, // CHECK:STDOUT: {kind: 'PackageDirective', text: ';', subtree_size: 6}, // CHECK:STDOUT: {kind: 'FileEnd', text: ''},