Skip to content

[6.0][ScanDependencies] Make sure canImport resolution agrees with import #74519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@ class ASTContext final {
///
/// Note that even if this check succeeds, errors may still occur if the
/// module is loaded in full.
bool canImportModuleImpl(ImportPath::Module ModulePath,
bool canImportModuleImpl(ImportPath::Module ModulePath, SourceLoc loc,
llvm::VersionTuple version, bool underlyingVersion,
bool updateFailingList,
llvm::VersionTuple &foundVersion) const;
Expand Down Expand Up @@ -1146,7 +1146,7 @@ class ASTContext final {
///
/// Note that even if this check succeeds, errors may still occur if the
/// module is loaded in full.
bool canImportModule(ImportPath::Module ModulePath,
bool canImportModule(ImportPath::Module ModulePath, SourceLoc loc,
llvm::VersionTuple version = llvm::VersionTuple(),
bool underlyingVersion = false);

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,9 @@ ERROR(serialization_failed,none,
"serialization of module %0 failed due to the errors above",
(const ModuleDecl *))

WARNING(can_import_invalid_swiftmodule,none,
"canImport() evaluated to false due to invalid swiftmodule: %0", (StringRef))

ERROR(serialization_load_failed,Fatal,
"failed to load module '%0'", (StringRef))
ERROR(module_interface_build_failed,Fatal,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/ModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ class ModuleLoader {
///
/// If a non-null \p versionInfo is provided, the module version will be
/// parsed and populated.
virtual bool canImportModule(ImportPath::Module named,
virtual bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableImport = false) = 0;

Expand Down
2 changes: 1 addition & 1 deletion include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class ClangImporter final : public ClangModuleLoader {
///
/// If a non-null \p versionInfo is provided, the module version will be
/// parsed and populated.
virtual bool canImportModule(ImportPath::Module named,
virtual bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableImport = false) override;

Expand Down
4 changes: 2 additions & 2 deletions include/swift/Frontend/ModuleInterfaceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase {
bool SkipBuildingInterface, bool IsFramework,
bool IsTestableDependencyLookup = false) override;

bool canImportModule(ImportPath::Module named,
bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;

Expand Down Expand Up @@ -212,7 +212,7 @@ class ExplicitCASModuleLoader : public SerializedModuleLoaderBase {
bool SkipBuildingInterface, bool IsFramework,
bool IsTestableDependencyLookup = false) override;

bool canImportModule(ImportPath::Module named,
bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;

Expand Down
7 changes: 4 additions & 3 deletions include/swift/Sema/SourceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ class SourceLoader : public ModuleLoader {
///
/// If a non-null \p versionInfo is provided, the module version will be
/// parsed and populated.
virtual bool canImportModule(ImportPath::Module named,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;
virtual bool
canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;

/// Import a module with the given module path.
///
Expand Down
9 changes: 5 additions & 4 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,10 @@ class SerializedModuleLoaderBase : public ModuleLoader {
///
/// If a non-null \p versionInfo is provided, the module version will be
/// parsed and populated.
virtual bool canImportModule(ImportPath::Module named,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;
virtual bool
canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;

/// Import a module with the given module path.
///
Expand Down Expand Up @@ -339,7 +340,7 @@ class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase {
public:
virtual ~MemoryBufferSerializedModuleLoader();

bool canImportModule(ImportPath::Module named,
bool canImportModule(ImportPath::Module named, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup = false) override;

Expand Down
21 changes: 11 additions & 10 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2403,10 +2403,11 @@ void ASTContext::addSucceededCanImportModule(
}
}

bool ASTContext::canImportModuleImpl(
ImportPath::Module ModuleName, llvm::VersionTuple version,
bool underlyingVersion, bool updateFailingList,
llvm::VersionTuple &foundVersion) const {
bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName,
SourceLoc loc, llvm::VersionTuple version,
bool underlyingVersion,
bool updateFailingList,
llvm::VersionTuple &foundVersion) const {
SmallString<64> FullModuleName;
ModuleName.getString(FullModuleName);
auto ModuleNameStr = FullModuleName.str().str();
Expand Down Expand Up @@ -2447,7 +2448,7 @@ bool ASTContext::canImportModuleImpl(

// Otherwise, ask whether any module loader can load the module.
for (auto &importer : getImpl().ModuleLoaders) {
if (importer->canImportModule(ModuleName, nullptr))
if (importer->canImportModule(ModuleName, loc, nullptr))
return true;
}

Expand All @@ -2464,7 +2465,7 @@ bool ASTContext::canImportModuleImpl(
for (auto &importer : getImpl().ModuleLoaders) {
ModuleLoader::ModuleVersionInfo versionInfo;

if (!importer->canImportModule(ModuleName, &versionInfo))
if (!importer->canImportModule(ModuleName, loc, &versionInfo))
continue; // The loader can't find the module.

if (!versionInfo.isValid())
Expand Down Expand Up @@ -2504,11 +2505,11 @@ void ASTContext::forEachCanImportVersionCheck(
Callback(entry.first, entry.second.Version, entry.second.UnderlyingVersion);
}

bool ASTContext::canImportModule(ImportPath::Module moduleName,
bool ASTContext::canImportModule(ImportPath::Module moduleName, SourceLoc loc,
llvm::VersionTuple version,
bool underlyingVersion) {
llvm::VersionTuple versionInfo;
if (!canImportModuleImpl(moduleName, version, underlyingVersion, true,
if (!canImportModuleImpl(moduleName, loc, version, underlyingVersion, true,
versionInfo))
return false;

Expand All @@ -2522,8 +2523,8 @@ bool ASTContext::testImportModule(ImportPath::Module ModuleName,
llvm::VersionTuple version,
bool underlyingVersion) const {
llvm::VersionTuple versionInfo;
return canImportModuleImpl(ModuleName, version, underlyingVersion, false,
versionInfo);
return canImportModuleImpl(ModuleName, SourceLoc(), version,
underlyingVersion, false, versionInfo);
}

ModuleDecl *
Expand Down
1 change: 1 addition & 0 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,7 @@ static llvm::VersionTuple getCurrentVersionFromTBD(llvm::vfs::FileSystem &FS,
}

bool ClangImporter::canImportModule(ImportPath::Module modulePath,
SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// Look up the top-level module to see if it exists.
Expand Down
2 changes: 1 addition & 1 deletion lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3510,7 +3510,7 @@ ModuleDecl *ClangImporter::Implementation::tryLoadFoundationModule() {
bool ClangImporter::Implementation::canImportFoundationModule() {
ImportPath::Module::Builder builder(SwiftContext.Id_Foundation);
auto modulePath = builder.get();
return SwiftContext.canImportModule(modulePath);
return SwiftContext.canImportModule(modulePath, SourceLoc());
}

Type ClangImporter::Implementation::getNamedSwiftType(ModuleDecl *module,
Expand Down
14 changes: 6 additions & 8 deletions lib/Frontend/ModuleInterfaceLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2383,7 +2383,7 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory(
}

bool ExplicitSwiftModuleLoader::canImportModule(
ImportPath::Module path, ModuleVersionInfo *versionInfo,
ImportPath::Module path, SourceLoc loc, ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// FIXME: Swift submodules?
if (path.hasSubmodule())
Expand All @@ -2409,7 +2409,7 @@ bool ExplicitSwiftModuleLoader::canImportModule(
auto &fs = *Ctx.SourceMgr.getFileSystem();
auto moduleBuf = fs.getBufferForFile(it->second.modulePath);
if (!moduleBuf) {
Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file,
Ctx.Diags.diagnose(loc, diag::error_opening_explicit_module_file,
it->second.modulePath);
return false;
}
Expand All @@ -2420,8 +2420,7 @@ bool ExplicitSwiftModuleLoader::canImportModule(
if (auto forwardingModule = ForwardingModule::load(**moduleBuf)) {
moduleBuf = fs.getBufferForFile(forwardingModule->underlyingModulePath);
if (!moduleBuf) {
Ctx.Diags.diagnose(SourceLoc(),
diag::error_opening_explicit_module_file,
Ctx.Diags.diagnose(loc, diag::error_opening_explicit_module_file,
forwardingModule->underlyingModulePath);
return false;
}
Expand Down Expand Up @@ -2734,7 +2733,7 @@ std::error_code ExplicitCASModuleLoader::findModuleFilesInDirectory(
}

bool ExplicitCASModuleLoader::canImportModule(
ImportPath::Module path, ModuleVersionInfo *versionInfo,
ImportPath::Module path, SourceLoc loc, ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// FIXME: Swift submodules?
if (path.hasSubmodule())
Expand Down Expand Up @@ -2763,12 +2762,11 @@ bool ExplicitCASModuleLoader::canImportModule(
: it->second.modulePath;
auto moduleBuf = Impl.loadFileBuffer(moduleCASID, it->second.modulePath);
if (!moduleBuf) {
Ctx.Diags.diagnose(SourceLoc(), diag::error_cas,
toString(moduleBuf.takeError()));
Ctx.Diags.diagnose(loc, diag::error_cas, toString(moduleBuf.takeError()));
return false;
}
if (!*moduleBuf) {
Ctx.Diags.diagnose(SourceLoc(), diag::error_opening_explicit_module_file,
Ctx.Diags.diagnose(loc, diag::error_opening_explicit_module_file,
it->second.modulePath);
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Parse/ParseIfConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,8 @@ class EvaluateIfConfigCondition :
}
ImportPath::Module::Builder builder(Ctx, Str, /*separator=*/'.',
Arg->getStartLoc());
return Ctx.canImportModule(builder.get(), version, underlyingModule);
return Ctx.canImportModule(builder.get(), E->getLoc(), version,
underlyingModule);
} else if (KindName == "hasFeature") {
auto featureName = getDeclRefStr(Arg);
return Ctx.LangOpts.hasFeature(featureName);
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/SourceLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void SourceLoader::collectVisibleTopLevelModuleNames(
// TODO: Implement?
}

bool SourceLoader::canImportModule(ImportPath::Module path,
bool SourceLoader::canImportModule(ImportPath::Module path, SourceLoc loc,
ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// FIXME: Swift submodules?
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/ScanningLoaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ ModuleDependencyVector SerializedModuleLoaderBase::getModuleDependencies(
"Expected PlaceholderSwiftModuleScanner as the first dependency "
"scanner loader.");
for (auto &scanner : scanners) {
if (scanner->canImportModule(modulePath, nullptr,
if (scanner->canImportModule(modulePath, SourceLoc(), nullptr,
isTestableDependencyLookup)) {

ModuleDependencyVector moduleDependnecies;
Expand Down
56 changes: 38 additions & 18 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -1373,7 +1374,7 @@ swift::extractUserModuleVersionFromInterface(StringRef moduleInterfacePath) {
}

bool SerializedModuleLoaderBase::canImportModule(
ImportPath::Module path, ModuleVersionInfo *versionInfo,
ImportPath::Module path, SourceLoc loc, ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// FIXME: Swift submodules?
if (path.hasSubmodule())
Expand All @@ -1396,36 +1397,55 @@ bool SerializedModuleLoaderBase::canImportModule(
if (!found)
return false;

// If the caller doesn't want version info we're done.
if (!versionInfo)
return true;

assert(found);
llvm::VersionTuple swiftInterfaceVersion;
if (!moduleInterfaceSourcePath.empty()) {
swiftInterfaceVersion =
// If we found interface and version is not requested, we're done.
if (!versionInfo)
return true;

auto moduleVersion =
extractUserModuleVersionFromInterface(moduleInterfaceSourcePath);

// If version is requested and found in interface, return the version.
// Otherwise fallback to binary module handling.
if (!moduleVersion.empty()) {
versionInfo->setVersion(moduleVersion,
ModuleVersionSourceKind::SwiftInterface);
return true;
}
}

// If failing to extract the user version from the interface file, try the
// binary module format, if present.
if (swiftInterfaceVersion.empty() && moduleInputBuffer) {
if (moduleInputBuffer) {
auto metaData = serialization::validateSerializedAST(
moduleInputBuffer->getBuffer(),
Ctx.SILOpts.EnableOSSAModules,
moduleInputBuffer->getBuffer(), Ctx.SILOpts.EnableOSSAModules,
Ctx.LangOpts.SDKName);
versionInfo->setVersion(metaData.userModuleVersion,

// If we only found binary module, make sure that is valid.
if (metaData.status != serialization::Status::Valid &&
moduleInterfaceSourcePath.empty()) {
// Emit warning if the canImport check location is known.
if (loc.isValid())
Ctx.Diags.diagnose(loc, diag::can_import_invalid_swiftmodule,
moduleInputBuffer->getBufferIdentifier());

return false;
}

if (versionInfo)
versionInfo->setVersion(metaData.userModuleVersion,
ModuleVersionSourceKind::SwiftBinaryModule);
}

if (versionInfo && !versionInfo->isValid()) {
// If no version is found, set it to empty version.
versionInfo->setVersion(llvm::VersionTuple(),
ModuleVersionSourceKind::SwiftBinaryModule);
} else {
versionInfo->setVersion(swiftInterfaceVersion,
ModuleVersionSourceKind::SwiftInterface);
}

return true;
}

bool MemoryBufferSerializedModuleLoader::canImportModule(
ImportPath::Module path, ModuleVersionInfo *versionInfo,
ImportPath::Module path, SourceLoc loc, ModuleVersionInfo *versionInfo,
bool isTestableDependencyLookup) {
// FIXME: Swift submodules?
if (path.hasSubmodule())
Expand Down
30 changes: 30 additions & 0 deletions test/ScanDependencies/can_import_version_mismatch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: cp %S/../Serialization/Inputs/too-old/Library.swiftmodule %t/include/Library.swiftmodule

/// No warning when there is a swiftinterface file even the binary module is invalid.
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test.swift -module-cache-path %t/clang-module-cache \
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
// RUN: -o %t/deps.json -I %t/include 2>&1 | %FileCheck %s --check-prefix=NOWARN --allow-empty

// NOWARN-NOT: warning:

/// Issue a warning when only found invalid binary module.
// RUN: rm %t/include/Library.swiftinterface
// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test.swift -module-cache-path %t/clang-module-cache \
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \
// RUN: -o %t/deps.json -I %t/include 2>&1 | %FileCheck %s --check-prefix=WARN
// WARN: warning: canImport() evaluated to false due to invalid swiftmodule

// RUN: %FileCheck %s --check-prefix=DEP --input-file=%t/deps.json
// DEP-NOT: Library

//--- test.swift
#if canImport(Library)
import Library
#endif

//--- include/Library.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Library -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 1.0
public func foo() {}