Skip to content

Commit 3e90368

Browse files
[ScanDependency] Do not use public/private swiftinterface in the same package
When scanning finds a dependency in the same package, do not load public/private swiftinterface since they do not have the package level decl to compile the current module. Always prefer package module (if enabled), or use binary module, unless it is building a public/private swiftinterface file in which case the interface file is preferred. This also does some clean up to sync up the code path between implicit and explicit module finding path. rdar://122356964
1 parent 69ef3ad commit 3e90368

File tree

10 files changed

+101
-76
lines changed

10 files changed

+101
-76
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ namespace swift {
440440
/// The name of the package this module belongs to.
441441
std::string PackageName;
442442

443+
/// Allow importing a non-package interface from the same package.
444+
bool AllowNonPackageInterfaceImportFromSamePackage = false;
445+
443446
/// Diagnose implicit 'override'.
444447
bool WarnImplicitOverrides = false;
445448

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class FrontendInputsAndOutputs {
172172
bool shouldTreatAsLLVM() const;
173173
bool shouldTreatAsSIL() const;
174174
bool shouldTreatAsModuleInterface() const;
175+
bool shouldTreatAsNonPackageModuleInterface() const;
175176
bool shouldTreatAsObjCHeader() const;
176177

177178
bool areAllNonPrimariesSIB() const;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ struct SerializedModuleBaseName {
6868
std::optional<std::string> findInterfacePath(llvm::vfs::FileSystem &fs,
6969
ASTContext &ctx) const;
7070

71+
/// Returns the package-name of the interface file.
72+
std::optional<std::string>
73+
getPackageNameFromInterface(StringRef interfacePath,
74+
llvm::vfs::FileSystem &fs) const;
75+
7176
/// Returns the .package.swiftinterface path if its package-name also applies to
7277
/// the the importing module. Returns an empty optional otherwise.
7378
std::optional<std::string>

lib/Frontend/CompilerInvocation.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,8 +974,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
974974
auto pkgName = A->getValue();
975975
if (StringRef(pkgName).empty())
976976
Diags.diagnose(SourceLoc(), diag::error_empty_package_name);
977-
else
977+
else {
978978
Opts.PackageName = pkgName;
979+
// Unless the input type is public or private swift interface, do not
980+
// allow non package interface imports for dependencies in the same
981+
// package.
982+
Opts.AllowNonPackageInterfaceImportFromSamePackage =
983+
FrontendOpts.InputsAndOutputs
984+
.shouldTreatAsNonPackageModuleInterface();
985+
}
979986
}
980987

981988
if (const Arg *A = Args.getLastArg(OPT_require_explicit_availability_EQ)) {

lib/Frontend/FrontendInputsAndOutputs.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,16 @@ bool FrontendInputsAndOutputs::shouldTreatAsModuleInterface() const {
203203
return InputType == file_types::TY_SwiftModuleInterfaceFile;
204204
}
205205

206+
bool FrontendInputsAndOutputs::shouldTreatAsNonPackageModuleInterface() const {
207+
if (!hasSingleInput())
208+
return false;
209+
210+
file_types::ID InputType =
211+
file_types::lookupTypeFromFilename(getFilenameOfFirstInput());
212+
return InputType == file_types::TY_SwiftModuleInterfaceFile ||
213+
InputType == file_types::TY_PrivateSwiftModuleInterfaceFile;
214+
}
215+
206216
bool FrontendInputsAndOutputs::shouldTreatAsSIL() const {
207217
if (hasSingleInput()) {
208218
// If we have exactly one input filename, and its extension is "sil",

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,8 +1244,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12441244

12451245
// First check to see if the .swiftinterface exists at all. Bail if not.
12461246
auto &fs = *Ctx.SourceMgr.getFileSystem();
1247-
std::string InPath = BaseName.findInterfacePath(fs, Ctx).value_or("");
1248-
if (InPath.empty()) {
1247+
auto InPath = BaseName.findInterfacePath(fs, Ctx);
1248+
if (!InPath) {
12491249
if (fs.exists(ModPath)) {
12501250
LLVM_DEBUG(llvm::dbgs()
12511251
<< "No .swiftinterface file found adjacent to module file "
@@ -1256,22 +1256,22 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12561256
}
12571257

12581258
if (ModuleInterfaceSourcePath)
1259-
ModuleInterfaceSourcePath->assign(InPath.begin(), InPath.end());
1259+
ModuleInterfaceSourcePath->assign(InPath->begin(), InPath->end());
12601260

12611261
// If we've been told to skip building interfaces, we are done here and do
12621262
// not need to have the module actually built. For example, if we are
12631263
// currently answering a `canImport` query, it is enough to have found
12641264
// the interface.
12651265
if (skipBuildingInterface) {
12661266
if (ModuleInterfacePath)
1267-
ModuleInterfacePath->assign(InPath.begin(), InPath.end());
1267+
ModuleInterfacePath->assign(InPath->begin(), InPath->end());
12681268
return std::error_code();
12691269
}
12701270

12711271
// Create an instance of the Impl to do the heavy lifting.
12721272
auto ModuleName = ModuleID.Item.str();
12731273
ModuleInterfaceLoaderImpl Impl(
1274-
Ctx, ModPath, InPath, ModuleName, InterfaceChecker.CacheDir,
1274+
Ctx, ModPath, *InPath, ModuleName, InterfaceChecker.CacheDir,
12751275
InterfaceChecker.PrebuiltCacheDir, InterfaceChecker.BackupInterfaceDir,
12761276
ModuleID.Loc, InterfaceChecker.Opts,
12771277
InterfaceChecker.RequiresOSSAModules,
@@ -1290,7 +1290,7 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
12901290
if (ModuleBuffer) {
12911291
*ModuleBuffer = std::move(*ModuleBufferOrErr);
12921292
if (ModuleInterfacePath)
1293-
ModuleInterfacePath->assign(InPath.begin(), InPath.end());
1293+
ModuleInterfacePath->assign(InPath->begin(), InPath->end());
12941294
}
12951295

12961296
// Open .swiftsourceinfo file if it's present.

lib/Serialization/ScanningLoaders.cpp

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
5050
auto &fs = *Ctx.SourceMgr.getFileSystem();
5151

5252
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
53-
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
53+
auto InPath = BaseName.findInterfacePath(fs, Ctx);
5454

55-
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
55+
if (LoadMode == ModuleLoadingMode::OnlySerialized || !InPath) {
5656
if (fs.exists(ModPath)) {
5757
// The module file will be loaded directly.
5858
auto dependencies = scanModuleFile(ModPath, IsFramework);
@@ -61,26 +61,12 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
6161
return std::error_code();
6262
}
6363
return dependencies.getError();
64-
} else {
65-
return std::make_error_code(std::errc::no_such_file_or_directory);
6664
}
65+
return std::make_error_code(std::errc::no_such_file_or_directory);
6766
}
68-
assert(fs.exists(InPath));
67+
assert(InPath);
6968

70-
// Use package.swiftinterface if it exists and its package-name applies to
71-
// the importer module.
72-
auto PkgInPath = BaseName.getPackageInterfacePathIfInSamePackage(fs, Ctx).value_or("");
73-
if (!PkgInPath.empty() && fs.exists(PkgInPath)) {
74-
InPath = PkgInPath;
75-
} else {
76-
// If not in package, use the private interface file if exits.
77-
auto PrivateInPath =
78-
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
79-
if (fs.exists(PrivateInPath)) {
80-
InPath = PrivateInPath;
81-
}
82-
}
83-
auto dependencies = scanInterfaceFile(InPath, IsFramework);
69+
auto dependencies = scanInterfaceFile(*InPath, IsFramework);
8470
if (dependencies) {
8571
this->dependencies = std::move(dependencies.get());
8672
return std::error_code();

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -604,35 +604,43 @@ std::optional<std::string>
604604
SerializedModuleBaseName::getPackageInterfacePathIfInSamePackage(
605605
llvm::vfs::FileSystem &fs, ASTContext &ctx) const {
606606
if (!ctx.LangOpts.EnablePackageInterfaceLoad)
607-
return {};
607+
return std::nullopt;
608608

609609
std::string packagePath{
610-
getName(file_types::TY_PackageSwiftModuleInterfaceFile)};
610+
getName(file_types::TY_PackageSwiftModuleInterfaceFile)};
611611

612612
if (fs.exists(packagePath)) {
613613
// Read the interface file and extract its package-name argument value
614-
std::string result;
615-
if (auto packageFile = llvm::MemoryBuffer::getFile(packagePath)) {
616-
llvm::BumpPtrAllocator alloc;
617-
llvm::StringSaver argSaver(alloc);
618-
SmallVector<const char*, 8> args;
619-
(void)extractCompilerFlagsFromInterface(packagePath,
620-
(*packageFile)->getBuffer(), argSaver, args);
621-
for (unsigned I = 0, N = args.size(); I + 1 < N; I++) {
622-
StringRef current(args[I]), next(args[I + 1]);
623-
if (current == "-package-name") {
624-
// Instead of `break` here, continue to get the last value in case of dupes,
625-
// to be consistent with the default parsing logic.
626-
result = next;
627-
}
614+
if (auto packageName = getPackageNameFromInterface(packagePath, fs)) {
615+
// Return the .package.swiftinterface path if the package name applies to
616+
// the importer module.
617+
if (*packageName == ctx.LangOpts.PackageName)
618+
return packagePath;
619+
}
620+
}
621+
return std::nullopt;
622+
}
623+
624+
std::optional<std::string>
625+
SerializedModuleBaseName::getPackageNameFromInterface(
626+
StringRef interfacePath, llvm::vfs::FileSystem &fs) const {
627+
std::optional<std::string> result;
628+
if (auto interfaceFile = fs.getBufferForFile(interfacePath)) {
629+
llvm::BumpPtrAllocator alloc;
630+
llvm::StringSaver argSaver(alloc);
631+
SmallVector<const char *, 8> args;
632+
(void)extractCompilerFlagsFromInterface(
633+
interfacePath, (*interfaceFile)->getBuffer(), argSaver, args);
634+
for (unsigned I = 0, N = args.size(); I + 1 < N; I++) {
635+
StringRef current(args[I]), next(args[I + 1]);
636+
if (current == "-package-name") {
637+
// Instead of `break` here, continue to get the last value in case of
638+
// dupes, to be consistent with the default parsing logic.
639+
result = next;
628640
}
629641
}
630-
// Return the .package.swiftinterface path if the package name applies to
631-
// the importer module.
632-
if (!result.empty() && result == ctx.LangOpts.PackageName)
633-
return packagePath;
634642
}
635-
return {};
643+
return result;
636644
}
637645

638646
std::optional<std::string>
@@ -642,16 +650,18 @@ SerializedModuleBaseName::findInterfacePath(llvm::vfs::FileSystem &fs,
642650
// Ensure the public swiftinterface already exists, otherwise bail early
643651
// as it's considered the module doesn't exist.
644652
if (!fs.exists(interfacePath))
645-
return {};
646-
647-
// Check if a package interface exists and if the package name applies to
648-
// the importer module.
649-
auto pkgPath = getPackageInterfacePathIfInSamePackage(fs, ctx).value_or("");
650-
if (!pkgPath.empty() && fs.exists(pkgPath))
651-
return pkgPath;
653+
return std::nullopt;
654+
655+
// If in the same package, try return the package interface path if not
656+
// preferring the interface file.
657+
if (!ctx.LangOpts.AllowNonPackageInterfaceImportFromSamePackage) {
658+
if (auto packageName = getPackageNameFromInterface(interfacePath, fs)) {
659+
if (*packageName == ctx.LangOpts.PackageName)
660+
return getPackageInterfacePathIfInSamePackage(fs, ctx);
661+
}
662+
}
652663

653-
// If above fails, use the existing logic as fallback.
654-
// If present, use the private interface instead of the public one.
664+
// Otherwise, use the private interface instead of the public one.
655665
std::string privatePath{
656666
getName(file_types::TY_PrivateSwiftModuleInterfaceFile)};
657667
if (fs.exists(privatePath))
@@ -704,35 +714,33 @@ bool SerializedModuleLoaderBase::findModule(
704714
std::optional<SerializedModuleBaseName> firstAbsoluteBaseName;
705715

706716
for (const auto &targetSpecificBaseName : targetSpecificBaseNames) {
707-
SerializedModuleBaseName
708-
absoluteBaseName{currPath, targetSpecificBaseName};
717+
SerializedModuleBaseName absoluteBaseName{currPath,
718+
targetSpecificBaseName};
709719

710720
if (!firstAbsoluteBaseName.has_value())
711721
firstAbsoluteBaseName.emplace(absoluteBaseName);
712722

713723
auto result = findModuleFilesInDirectory(
714724
moduleID, absoluteBaseName, moduleInterfacePath,
715725
moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer,
716-
moduleSourceInfoBuffer, skipBuildingInterface,
717-
IsFramework, isTestableDependencyLookup);
718-
if (!result) {
726+
moduleSourceInfoBuffer, skipBuildingInterface, IsFramework,
727+
isTestableDependencyLookup);
728+
if (!result)
719729
return SearchResult::Found;
720-
} else if (result == std::errc::not_supported) {
730+
if (result == std::errc::not_supported)
721731
return SearchResult::Error;
722-
} else if (result != std::errc::no_such_file_or_directory) {
732+
if (result != std::errc::no_such_file_or_directory)
723733
return SearchResult::NotFound;
724-
}
725734
}
726735

727736
// We can only get here if all targetFileNamePairs failed with
728737
// 'std::errc::no_such_file_or_directory'.
729-
if (firstAbsoluteBaseName
730-
&& maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName,
731-
*firstAbsoluteBaseName)) {
738+
if (firstAbsoluteBaseName &&
739+
maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName,
740+
*firstAbsoluteBaseName))
732741
return SearchResult::Error;
733-
} else {
734-
return SearchResult::NotFound;
735-
}
742+
743+
return SearchResult::NotFound;
736744
};
737745

738746
SmallVector<std::string, 4> InterestingFilenames = {
@@ -788,13 +796,11 @@ bool SerializedModuleLoaderBase::findModule(
788796
moduleID, absoluteBaseName, moduleInterfacePath,
789797
moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer,
790798
moduleSourceInfoBuffer, skipBuildingInterface, isFramework);
791-
if (!result) {
799+
if (!result)
792800
return true;
793-
} else if (result == std::errc::not_supported) {
801+
if (result == std::errc::not_supported)
794802
return false;
795-
} else {
796-
continue;
797-
}
803+
continue;
798804
}
799805
case ModuleSearchPathKind::Framework:
800806
case ModuleSearchPathKind::DarwinImplicitFramework: {

test/ScanDependencies/package_interface.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// RUN: %target-swift-frontend -emit-module %t/Bar.swift -I %t \
55
// RUN: -module-name Bar -package-name barpkg \
66
// RUN: -enable-library-evolution -swift-version 5 \
7+
// RUN: -o %t/Bar.swiftmodule \
78
// RUN: -emit-module-interface-path %t/Bar.swiftinterface \
89
// RUN: -emit-private-module-interface-path %t/Bar.private.swiftinterface \
910
// RUN: -emit-package-module-interface-path %t/Bar.package.swiftinterface
@@ -21,10 +22,16 @@
2122
// RUN: %t/Client.swift -module-name Client -swift-version 5
2223
// RUN: %FileCheck %s --input-file=%t/deps3.json --check-prefix CHECK --check-prefix CHECK-PRIVATE
2324

25+
/// If -experimental-package-interface-load is not used but in the same package, it should find the binary module
26+
// RUN: %target-swift-frontend -scan-dependencies -I %t \
27+
// RUN: %t/Client.swift -module-name Client -package-name barpkg -swift-version 5 | \
28+
// RUN: %FileCheck %s --check-prefix CHECK-BINARY
29+
2430
// CHECK: "swift": "Bar"
2531
// CHECK: "modulePath": "{{.*}}{{/|\\}}Bar-{{.*}}.swiftmodule"
2632
// CHECK-PACKAGE: "moduleInterfacePath": "{{.*}}{{/|\\}}Bar.package.swiftinterface"
2733
// CHECK-PRIVATE: "moduleInterfacePath": "{{.*}}{{/|\\}}Bar.private.swiftinterface"
34+
// CHECK-BINARY: "swiftPrebuiltExternal": "Bar"
2835

2936
//--- Bar.swift
3037
public enum PubEnum {

test/Serialization/load_package_module.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
// RUN: not %target-swift-frontend -typecheck %t/ClientLoadInterface.swift -package-name libPkg -I %t 2> %t/resultY.output
3333
// RUN: %FileCheck %s -check-prefix CHECK-Y < %t/resultY.output
34-
// CHECK-Y: error: module 'LibInterface' is in package 'libPkg' but was built from a non-package interface; modules of the same package can only be loaded if built from source or package interface: {{.*}}LibInterface.private.swiftinterface
34+
// CHECK-Y: error: no such module 'LibInterface'
3535

3636

3737
//--- Lib.swift

0 commit comments

Comments
 (0)