Skip to content

Limit loading error when importing a module built from interface with package-name #65481

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
merged 1 commit into from
Apr 28, 2023
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
25 changes: 24 additions & 1 deletion lib/Sema/ImportResolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ struct UnboundImport {
void validateResilience(NullablePtr<ModuleDecl> topLevelModule,
SourceFile &SF);
void validateAllowableClient(ModuleDecl *topLevelModule, SourceFile &SF);
void validateInterfaceWithPackageName(ModuleDecl *topLevelModule, SourceFile &SF);

/// Diagnoses an inability to import \p modulePath in this situation and, if
/// \p attrs is provided and has an \p attrKind, invalidates the attribute and
Expand Down Expand Up @@ -652,8 +653,8 @@ void UnboundImport::validateOptions(NullablePtr<ModuleDecl> topLevelModule,
validateTestable(top);
validatePrivate(top);
validateAllowableClient(top, SF);
validateInterfaceWithPackageName(top, SF);
}

validateResilience(topLevelModule, SF);
}

Expand Down Expand Up @@ -756,6 +757,28 @@ void UnboundImport::validateAllowableClient(ModuleDecl *importee,
}
}

void UnboundImport::validateInterfaceWithPackageName(ModuleDecl *topLevelModule,
SourceFile &SF) {
assert(topLevelModule);

// If current source file is interface, don't throw an error
if (SF.Kind == SourceFileKind::Interface)
return;

// If source file is .swift or non-interface, show diags when importing an interface file
ASTContext &ctx = topLevelModule->getASTContext();
if (!topLevelModule->getPackageName().empty() &&
topLevelModule->getPackageName().str() == ctx.LangOpts.PackageName &&
topLevelModule->isBuiltFromInterface()) {
ctx.Diags.diagnose(SourceLoc(),
diag::in_package_module_not_compiled_from_source,
topLevelModule->getBaseIdentifier(),
ctx.LangOpts.PackageName,
topLevelModule->getModuleSourceFilename()
);
}
}

void UnboundImport::validateResilience(NullablePtr<ModuleDecl> topLevelModule,
SourceFile &SF) {
if (import.options.contains(ImportFlags::ImplementationOnly) ||
Expand Down
9 changes: 0 additions & 9 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,15 +804,6 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
if (loadedModuleFile->isConcurrencyChecked())
M.setIsConcurrencyChecked();
if (!loadedModuleFile->getModulePackageName().empty()) {
if (loadedModuleFile->isBuiltFromInterface() &&
loadedModuleFile->getModulePackageName().str() == Ctx.LangOpts.PackageName) {
Ctx.Diags.diagnose(SourceLoc(),
diag::in_package_module_not_compiled_from_source,
M.getBaseIdentifier(),
Ctx.LangOpts.PackageName,
loadedModuleFile->getModuleSourceFilename()
);
}
M.setPackageName(Ctx.getIdentifier(loadedModuleFile->getModulePackageName()));
}
M.setUserModuleVersion(loadedModuleFile->getUserModuleVersion());
Expand Down
149 changes: 149 additions & 0 deletions test/Sema/accessibility_package_import_interface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// RUN: %empty-directory(%t)
// RUN: split-file %s %t

// TEST Build Dep with package symbols
// RUN: %target-swift-frontend -emit-module %t/Dep.swift \
// RUN: -module-name Dep -swift-version 5 -I %t \
// RUN: -package-name myPkg \
// RUN: -enable-library-evolution \
// RUN: -emit-module-path %t/Dep.swiftmodule \
// RUN: -emit-module-interface-path %t/Dep.swiftinterface \
// RUN: -emit-private-module-interface-path %t/Dep.private.swiftinterface

// TEST Dep private interface should contain the package name
// RUN: %target-swift-typecheck-module-from-interface(%t/Dep.private.swiftinterface) -module-name Dep -I %t
// RUN: %FileCheck %s --check-prefix=CHECK-DEP-PRIVATE < %t/Dep.private.swiftinterface
// CHECK-DEP-PRIVATE: -package-name myPkg

// TEST Dep.swiftmodule should contain package name and package symbols
// RUN: llvm-bcanalyzer --dump %t/Dep.swiftmodule | %FileCheck %s --check-prefix=CHECK-DEP-BC
// CHECK-DEP-BC: <MODULE_PACKAGE_NAME abbrevid=6/> blob data = 'myPkg'

// TEST Lib should load Dep.swiftmodule and access package decls if in the same package and error if not

// RUN: %target-swift-frontend -typecheck %t/Lib.swift -package-name myPkg -I %t -verify

// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -package-name otherPkg -I %t -Rmodule-loading 2> %t/result-binary-other-pkg.output
// RUN: %FileCheck %s --check-prefix=CHECK-DIFF-PKG < %t/result-binary-other-pkg.output

// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -I %t -Rmodule-loading 2> %t/result-binary-no-pkg.output
// RUN: %FileCheck %s --check-prefix=CHECK-DIFF-PKG < %t/result-binary-no-pkg.output

// CHECK-DIFF-PKG: remark: loaded module 'Dep'
// CHECK-DIFF-PKG: error: cannot find 'packageFuncInlinable' in scope
// CHECK-DIFF-PKG: error: cannot find 'packageFunc' in scope
// CHECK-DIFF-PKG: error: cannot find 'PackageKlassUFI' in scope

// TEST Remove Dep binary and build it from interface
// RUN: rm %t/Dep.swiftmodule
// RUN: %target-swift-frontend -compile-module-from-interface %t/Dep.private.swiftinterface \
// RUN: -module-name Dep -I %t \
// RUN: -o %t/Dep.swiftmodule

// TEST Dep binary built from interface should contain package name but no package symbols
// RUN: llvm-bcanalyzer --dump %t/Dep.swiftmodule | %FileCheck %s --check-prefix=CHECK-DEP-INTER-BC
// CHECK-DEP-INTER-BC: <MODULE_PACKAGE_NAME abbrevid=7/> blob data = 'myPkg'

// TEST Lib should error on loading Dep built from interface and accessing package symbols (unless usableFromInline or inlinable)
// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -package-name myPkg -I %t 2> %t/result-access.output
// RUN: %FileCheck %s --check-prefix CHECK-LIB < %t/result-access.output
// CHECK-LIB: error: module 'Dep' is in package 'myPkg' but was built from interface; modules of the same package can only be loaded if built from source
// CHECK-LIB: error: cannot find 'packageFunc' in scope
// CHECK-LIB: error: value of type 'PackageKlassUFI' has no member 'packageVar'

// TEST Remove and rebuild Dep from source
// RUN: rm %t/Dep.swiftmodule
// RUN: %target-swift-frontend -emit-module %t/Dep.swift \
// RUN: -module-name Dep -swift-version 5 -I %t \
// RUN: -package-name myPkg \
// RUN: -enable-library-evolution \
// RUN: -emit-module-path %t/Dep.swiftmodule

// TEST Build LibPass with package name
// RUN: %target-swift-frontend -emit-module %t/LibPass.swift \
// RUN: -module-name LibPass -swift-version 5 -I %t \
// RUN: -package-name myPkg \
// RUN: -enable-library-evolution \
// RUN: -emit-module-path %t/LibPass.swiftmodule \
// RUN: -emit-module-interface-path %t/LibPass.swiftinterface \
// RUN: -emit-private-module-interface-path %t/LibPass.private.swiftinterface

// TEST Loading LibPass and accessing lib func should pass
// RUN: %target-swift-frontend -typecheck %t/Client.swift -package-name myPkg -I %t -verify

// TEST Building LibPass from interface with Dep (built from interface) should succeed with or without package name
// Without package name
// RUN: rm %t/Dep.swiftmodule
// RUN: rm %t/LibPass.swiftmodule
// RUN: %target-swift-frontend -compile-module-from-interface %t/LibPass.private.swiftinterface \
// RUN: -module-name LibPass -I %t \
// RUN: -o %t/LibPass.swiftmodule

// With package name
// RUN: rm %t/LibPass.swiftmodule
// RUN: %target-swift-frontend -compile-module-from-interface %t/LibPass.private.swiftinterface \
// RUN: -module-name LibPass -I %t \
// RUN: -package-name myPkg \
// RUN: -o %t/LibPass.swiftmodule


//--- Dep.swift
@usableFromInline
package class PackageKlassUFI {
@usableFromInline package init() {}
@usableFromInline package var packageVarUFI: String = "pkgUFI"
package var packageVar: String = "pkg"
}

package func packageFunc() {
print("package func")
}

@inlinable
package func packageFuncInlinable() {
print("inlinable package func")
}

public func publicFunc() {
print("public func")
}

@inlinable
public func publicFuncInlinable() {
print("inlinable public func")
}

//--- Lib.swift
import Dep

public func libFunc() {
publicFuncInlinable()
publicFunc()
packageFuncInlinable()
packageFunc()
let x = PackageKlassUFI()
let y = x.packageVarUFI
let z = x.packageVar
print(x, y, z)
}


//--- LibPass.swift
import Dep

public func libFunc() {
publicFuncInlinable()
publicFunc()
packageFuncInlinable()
let x = PackageKlassUFI()
let y = x.packageVarUFI
print(x, y)
}


//--- Client.swift
import LibPass

public func clientFunc() {
libFunc()
}