Files
swift-mirror/test/embedded/linkage/implementation_only_hiding.swift
Doug Gregor ae8e95d5d9 [Embedded] Introduce a test for @_implementationOnly + @_neverEmitIntoClient
In Desktop Swift, @_implementationOnly imports allow one to hide the
implementation so long as you're careful to only reference entities
from the imported modules in code that gets compiled into the object
file and *not* referenced by the corresponding Swift module file.

Until very recently, there was no such affordance for Embedded Swift,
because all functions would have their SIL serialized to the Swift
module file. Using them from a client module would then attempt to
deserialize the SIL, loading the @_implementationOnly-imported module
and causing the compiler to abort. With the introduction of
@_neverEmitIntoClient, we now have a way to say "only in the object
file, never in the module file" for the definition of functions.

Introduce a test that makes sure @_implementationOnly +
@_neverEmitIntoClient has the desired effect of hiding the imported
modules from clients. It's still brittle and hard to use, just like
the existing @_implementationOnly, but this shows that it's at least
possible to do this implementation hiding in Embedded Swift.
2025-08-19 16:03:18 -07:00

74 lines
2.7 KiB
Swift

// This elaborate test ensures that @_implementationOnly with Embedded Swift
// can hide some dependencies if you are very, very careful.
// RUN: %empty-directory(%t)
// RUN: mkdir -p %t/Dependencies
// RUN: mkdir -p %t/Files
// RUN: mkdir -p %t/Modules
// Copy Swift file + C header + module map into a separate directory we'll use
// when building the module whose implementation we want to hide.
// RUN: cp %S/Inputs/SwiftDependency.swift %t/Dependencies/
// RUN: cp %S/Inputs/CHeader.h %t/Dependencies/
// RUN: cp %S/Inputs/module.modulemap %t/Dependencies/
// RUN: split-file %s %t/Files
// Compile the Swift dependencies into that same location.
// RUN: %target-swift-frontend -parse-as-library -emit-module %t/Dependencies/SwiftDependency.swift -enable-experimental-feature Embedded -o %t/Dependencies/SwiftDependency.swiftmodule
// Build the library (which is supposed to encapsulate those dependencies)
// against the dependencies.
// RUN: %target-swift-frontend -parse-as-library -emit-module %t/Files/Library.swift -enable-experimental-feature Embedded -I %t/Dependencies/ -o %t/Modules/Library.swiftmodule
// Remove the dependencies so there is no way we can find them later.
// RUN: rm -rf %t/Dependencies
// Build the application against the library. This is expected to work because
// @_neverEmitIntoClient hides the body of test().
// RUN: %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir
// Build the application against the library, but intentionally trigger
// deserialization of some serialized SIL that refers to an implementation-only
// dependency. Right now, these fail spectacularly. Over time, we want them to
// become compile-time errors or start working.
// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_C_USAGE
// RUN: not --crash %target-swift-frontend -emit-ir -parse-as-library %t/Files/Application.swift -enable-experimental-feature Embedded -I %t/Modules -o %t/Application.ir -DBAD_SWIFT_USAGE
// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Embedded
//--- Library.swift
@_implementationOnly import CDependency
@_implementationOnly import SwiftDependency
@_neverEmitIntoClient
public func test() {
_ = getPoint(3.14159, 2.71828)
A().doSomething()
}
public func badCLibraryUsage() {
_ = getPoint(3.14159, 2.71828)
}
public func badSwiftLibraryUsage() {
A().doSomething()
}
//--- Application.swift
import Library
public func useTest() {
test()
#if BAD_C_USAGE
badCLibraryUsage()
#endif
#if BAD_SWIFT_USAGE
badSwiftLibraryUsage()
#endif
}