Skip to content

Commit e037023

Browse files
authored
Make Attachment always conform to CustomStringConvertible. (#1367)
This PR ensures that `Attachment` conforms to `CustomStringConvertible` even if the value it wraps is non-copyable. We accomplish this by creating a new helper function that is able to box an arbitrary `~Copyable` value in `Any` if its type is actually `Copyable`. (This requires a newer runtime on Apple platforms, so we fall back to a generic (`~Copyable`) implementation on older macOS/iOS/etc.) We then call this helper function in `Attachment.description` and if it returns a value, we can stringify it. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 5ac9500 commit e037023

File tree

5 files changed

+56
-10
lines changed

5 files changed

+56
-10
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ extension Array where Element == PackageDescription.SwiftSetting {
406406
.enableExperimentalFeature("AvailabilityMacro=_regexAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0"),
407407
.enableExperimentalFeature("AvailabilityMacro=_swiftVersionAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0"),
408408
.enableExperimentalFeature("AvailabilityMacro=_typedThrowsAPI:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0"),
409+
.enableExperimentalFeature("AvailabilityMacro=_castingWithNonCopyableGenerics:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0"),
409410

410411
.enableExperimentalFeature("AvailabilityMacro=_distantFuture:macOS 99.0, iOS 99.0, watchOS 99.0, tvOS 99.0, visionOS 99.0"),
411412
]

Sources/Testing/Attachments/Attachment.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,17 @@ public struct AnyAttachable: AttachableWrapper, Sendable, Copyable {
193193

194194
// MARK: - Describing an attachment
195195

196-
extension Attachment where AttachableValue: ~Copyable {
197-
@_documentation(visibility: private)
198-
public var description: String {
199-
let typeInfo = TypeInfo(describing: AttachableValue.self)
200-
return #""\#(preferredName)": instance of '\#(typeInfo.unqualifiedName)'"#
201-
}
202-
}
203-
204-
extension Attachment: CustomStringConvertible {
196+
extension Attachment: CustomStringConvertible where AttachableValue: ~Copyable {
205197
/// @Metadata {
206198
/// @Available(Swift, introduced: 6.2)
207199
/// @Available(Xcode, introduced: 26.0)
208200
/// }
209201
public var description: String {
210-
#""\#(preferredName)": \#(String(describingForTest: attachableValue))"#
202+
if #available(_castingWithNonCopyableGenerics, *), let attachableValue = boxCopyableValue(attachableValue) {
203+
return #""\#(preferredName)": \#(String(describingForTest: attachableValue))"#
204+
}
205+
let typeInfo = TypeInfo(describing: AttachableValue.self)
206+
return #""\#(preferredName)": instance of '\#(typeInfo.unqualifiedName)'"#
211207
}
212208
}
213209

Sources/Testing/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ add_library(Testing
7676
Support/Additions/ArrayAdditions.swift
7777
Support/Additions/CollectionDifferenceAdditions.swift
7878
Support/Additions/CommandLineAdditions.swift
79+
Support/Additions/CopyableAdditions.swift
7980
Support/Additions/NumericAdditions.swift
8081
Support/Additions/ResultAdditions.swift
8182
Support/Additions/TaskAdditions.swift
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// This source file is part of the Swift.org open source project
3+
//
4+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See https://swift.org/LICENSE.txt for license information
8+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
//
10+
11+
#if !hasFeature(Embedded)
12+
/// A helper protocol for ``boxCopyableValue(_:)``.
13+
private protocol _CopyablePointer {
14+
/// Load the value at this address into an existential box.
15+
///
16+
/// - Returns: The value at this address.
17+
func load() -> Any
18+
}
19+
20+
extension UnsafePointer: _CopyablePointer where Pointee: Copyable {
21+
func load() -> Any {
22+
pointee
23+
}
24+
}
25+
#endif
26+
27+
/// Copy a value to an existential box if its type conforms to `Copyable`.
28+
///
29+
/// - Parameters:
30+
/// - value: The value to copy.
31+
///
32+
/// - Returns: A copy of `value` in an existential box, or `nil` if the type of
33+
/// `value` does not conform to `Copyable`.
34+
///
35+
/// When using Embedded Swift, this function always returns `nil`.
36+
#if !hasFeature(Embedded)
37+
@available(_castingWithNonCopyableGenerics, *)
38+
func boxCopyableValue(_ value: borrowing some ~Copyable) -> Any? {
39+
withUnsafePointer(to: value) { address in
40+
return (address as? any _CopyablePointer)?.load()
41+
}
42+
}
43+
#else
44+
func boxCopyableValue(_ value: borrowing some ~Copyable) -> Void? {
45+
nil
46+
}
47+
#endif

cmake/modules/shared/AvailabilityDefinitions.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ add_compile_options(
1717
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -define-availability -Xfrontend \"_regexAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0\">"
1818
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -define-availability -Xfrontend \"_swiftVersionAPI:macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0\">"
1919
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -define-availability -Xfrontend \"_typedThrowsAPI:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0\">"
20+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -define-availability -Xfrontend \"_castingWithNonCopyableGenerics:macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0\">"
2021
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -define-availability -Xfrontend \"_distantFuture:macOS 99.0, iOS 99.0, watchOS 99.0, tvOS 99.0, visionOS 99.0\">")

0 commit comments

Comments
 (0)