Skip to content

Commit cbafbcd

Browse files
authored
Use generics to declare suite types in macro expansions. (#1338)
This PR adopts generics instead of existentials when declaring suite types in the expansions of `@Suite` and `@Test` and in the interface of the internal `TypeInfo` helper type. ### 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 ee0ba8c commit cbafbcd

File tree

6 files changed

+45
-25
lines changed

6 files changed

+45
-25
lines changed

Sources/Testing/Parameterization/TypeInfo.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public struct TypeInfo: Sendable {
7979
///
8080
/// - Parameters:
8181
/// - type: The type which this instance should describe.
82-
init(describing type: any ~Copyable.Type) {
82+
init(describing type: (some ~Copyable).Type) {
8383
_kind = .type(type)
8484
}
8585

@@ -88,8 +88,21 @@ public struct TypeInfo: Sendable {
8888
///
8989
/// - Parameters:
9090
/// - value: The value whose type this instance should describe.
91-
init(describingTypeOf value: Any) {
92-
self.init(describing: Swift.type(of: value))
91+
init(describingTypeOf value: some Any) {
92+
#if !hasFeature(Embedded)
93+
let value = value as Any
94+
#endif
95+
let type = Swift.type(of: value)
96+
self.init(describing: type)
97+
}
98+
99+
/// Initialize an instance of this type describing the type of the specified
100+
/// value.
101+
///
102+
/// - Parameters:
103+
/// - value: The value whose type this instance should describe.
104+
init<T>(describingTypeOf value: borrowing T) where T: ~Copyable {
105+
self.init(describing: T.self)
93106
}
94107
}
95108

Sources/Testing/Test+Macro.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,16 @@ extension Test {
157157
///
158158
/// - Warning: This function is used to implement the `@Test` macro. Do not
159159
/// call it directly.
160-
public static func __function(
160+
public static func __function<S>(
161161
named testFunctionName: String,
162-
in containingType: (any ~Copyable.Type)?,
162+
in containingType: S.Type?,
163163
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
164164
displayName: String? = nil,
165165
traits: [any TestTrait],
166166
sourceLocation: SourceLocation,
167167
parameters: [__Parameter] = [],
168168
testFunction: @escaping @Sendable () async throws -> Void
169-
) -> Self {
169+
) -> Self where S: ~Copyable {
170170
// Don't use Optional.map here due to a miscompile/crash. Expand out to an
171171
// if expression instead. SEE: rdar://134280902
172172
let containingTypeInfo: TypeInfo? = if let containingType {
@@ -241,17 +241,17 @@ extension Test {
241241
///
242242
/// - Warning: This function is used to implement the `@Test` macro. Do not
243243
/// call it directly.
244-
public static func __function<C>(
244+
public static func __function<S, C>(
245245
named testFunctionName: String,
246-
in containingType: (any ~Copyable.Type)?,
246+
in containingType: S.Type?,
247247
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
248248
displayName: String? = nil,
249249
traits: [any TestTrait],
250250
arguments collection: @escaping @Sendable () async throws -> C,
251251
sourceLocation: SourceLocation,
252252
parameters paramTuples: [__Parameter],
253253
testFunction: @escaping @Sendable (C.Element) async throws -> Void
254-
) -> Self where C: Collection & Sendable, C.Element: Sendable {
254+
) -> Self where S: ~Copyable, C: Collection & Sendable, C.Element: Sendable {
255255
let containingTypeInfo: TypeInfo? = if let containingType {
256256
TypeInfo(describing: containingType)
257257
} else {
@@ -388,17 +388,17 @@ extension Test {
388388
///
389389
/// - Warning: This function is used to implement the `@Test` macro. Do not
390390
/// call it directly.
391-
public static func __function<C1, C2>(
391+
public static func __function<S, C1, C2>(
392392
named testFunctionName: String,
393-
in containingType: (any ~Copyable.Type)?,
393+
in containingType: S.Type?,
394394
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
395395
displayName: String? = nil,
396396
traits: [any TestTrait],
397397
arguments collection1: @escaping @Sendable () async throws -> C1, _ collection2: @escaping @Sendable () async throws -> C2,
398398
sourceLocation: SourceLocation,
399399
parameters paramTuples: [__Parameter],
400400
testFunction: @escaping @Sendable (C1.Element, C2.Element) async throws -> Void
401-
) -> Self where C1: Collection & Sendable, C1.Element: Sendable, C2: Collection & Sendable, C2.Element: Sendable {
401+
) -> Self where S: ~Copyable, C1: Collection & Sendable, C1.Element: Sendable, C2: Collection & Sendable, C2.Element: Sendable {
402402
let containingTypeInfo: TypeInfo? = if let containingType {
403403
TypeInfo(describing: containingType)
404404
} else {
@@ -416,17 +416,17 @@ extension Test {
416416
///
417417
/// - Warning: This function is used to implement the `@Test` macro. Do not
418418
/// call it directly.
419-
public static func __function<C, E1, E2>(
419+
public static func __function<S, C, E1, E2>(
420420
named testFunctionName: String,
421-
in containingType: (any ~Copyable.Type)?,
421+
in containingType: S.Type?,
422422
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
423423
displayName: String? = nil,
424424
traits: [any TestTrait],
425425
arguments collection: @escaping @Sendable () async throws -> C,
426426
sourceLocation: SourceLocation,
427427
parameters paramTuples: [__Parameter],
428428
testFunction: @escaping @Sendable ((E1, E2)) async throws -> Void
429-
) -> Self where C: Collection & Sendable, C.Element == (E1, E2), E1: Sendable, E2: Sendable {
429+
) -> Self where S: ~Copyable, C: Collection & Sendable, C.Element == (E1, E2), E1: Sendable, E2: Sendable {
430430
let containingTypeInfo: TypeInfo? = if let containingType {
431431
TypeInfo(describing: containingType)
432432
} else {
@@ -447,17 +447,17 @@ extension Test {
447447
///
448448
/// - Warning: This function is used to implement the `@Test` macro. Do not
449449
/// call it directly.
450-
public static func __function<Key, Value>(
450+
public static func __function<S, Key, Value>(
451451
named testFunctionName: String,
452-
in containingType: (any ~Copyable.Type)?,
452+
in containingType: S.Type?,
453453
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
454454
displayName: String? = nil,
455455
traits: [any TestTrait],
456456
arguments dictionary: @escaping @Sendable () async throws -> Dictionary<Key, Value>,
457457
sourceLocation: SourceLocation,
458458
parameters paramTuples: [__Parameter],
459459
testFunction: @escaping @Sendable ((Key, Value)) async throws -> Void
460-
) -> Self where Key: Sendable, Value: Sendable {
460+
) -> Self where S: ~Copyable, Key: Sendable, Value: Sendable {
461461
let containingTypeInfo: TypeInfo? = if let containingType {
462462
TypeInfo(describing: containingType)
463463
} else {
@@ -472,17 +472,17 @@ extension Test {
472472
///
473473
/// - Warning: This function is used to implement the `@Test` macro. Do not
474474
/// call it directly.
475-
public static func __function<C1, C2>(
475+
public static func __function<S, C1, C2>(
476476
named testFunctionName: String,
477-
in containingType: (any ~Copyable.Type)?,
477+
in containingType: S.Type?,
478478
xcTestCompatibleSelector: __XCTestCompatibleSelector?,
479479
displayName: String? = nil,
480480
traits: [any TestTrait],
481481
arguments zippedCollections: @escaping @Sendable () async throws -> Zip2Sequence<C1, C2>,
482482
sourceLocation: SourceLocation,
483483
parameters paramTuples: [__Parameter],
484484
testFunction: @escaping @Sendable (C1.Element, C2.Element) async throws -> Void
485-
) -> Self where C1: Collection & Sendable, C1.Element: Sendable, C2: Collection & Sendable, C2.Element: Sendable {
485+
) -> Self where S: ~Copyable, C1: Collection & Sendable, C1.Element: Sendable, C2: Collection & Sendable, C2.Element: Sendable {
486486
let containingTypeInfo: TypeInfo? = if let containingType {
487487
TypeInfo(describing: containingType)
488488
} else {

Sources/TestingMacros/TestDeclarationMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
382382

383383
// Get the name of the type containing the function for passing to the test
384384
// factory function later.
385-
let typeNameExpr: ExprSyntax = typeName.map { "\($0).self" } ?? "nil"
385+
let typeNameExpr: ExprSyntax = typeName.map { "\($0).self" } ?? "nil as Swift.Never.Type?"
386386

387387
if typeName != nil, let genericGuardDecl = makeGenericGuardDecl(guardingAgainst: functionDecl, in: context) {
388388
result.append(genericGuardDecl)

Tests/TestingTests/MiscellaneousTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ struct MiscellaneousTests {
560560
let line = 12345
561561
let column = 67890
562562
let sourceLocation = SourceLocation(fileID: fileID, filePath: filePath, line: line, column: column)
563-
let testFunction = Test.__function(named: "myTestFunction()", in: nil, xcTestCompatibleSelector: nil, displayName: nil, traits: [], sourceLocation: sourceLocation) {}
563+
let testFunction = Test.__function(named: "myTestFunction()", in: nil as Never.Type?, xcTestCompatibleSelector: nil, displayName: nil, traits: [], sourceLocation: sourceLocation) {}
564564
#expect(String(describing: testFunction.id) == "Module.myTestFunction()/Y.swift:12345:67890")
565565
}
566566

Tests/TestingTests/SwiftPMTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ struct SwiftPMTests {
285285
@Test("Unsupported ABI version")
286286
func unsupportedABIVersion() async throws {
287287
let versionNumber = VersionNumber(-100, 0)
288-
let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map(TypeInfo.init(describing:))
288+
let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map {TypeInfo(describing: $0) }
289289
#expect(versionTypeInfo == nil)
290290
}
291291

@@ -294,7 +294,7 @@ struct SwiftPMTests {
294294
#expect(swiftCompilerVersion >= VersionNumber(6, 0))
295295
#expect(swiftCompilerVersion < VersionNumber(8, 0), "Swift 8.0 is here! Please update this test.")
296296
let versionNumber = VersionNumber(8, 0)
297-
let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map(TypeInfo.init(describing:))
297+
let versionTypeInfo = ABI.version(forVersionNumber: versionNumber).map {TypeInfo(describing: $0) }
298298
#expect(versionTypeInfo == nil)
299299
}
300300

Tests/TestingTests/TypeInfoTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ struct TypeInfoTests {
122122
#expect(!TypeInfo(describing: String.self).isSwiftEnumeration)
123123
#expect(TypeInfo(describing: SomeEnum.self).isSwiftEnumeration)
124124
}
125+
126+
@Test func typeOfMoveOnlyValueIsInferred() {
127+
let value = MoveOnlyType()
128+
#expect(TypeInfo(describingTypeOf: value).unqualifiedName == "MoveOnlyType")
129+
}
125130
}
126131

127132
// MARK: - Fixtures
@@ -131,3 +136,5 @@ extension String {
131136
}
132137

133138
private enum SomeEnum {}
139+
140+
private struct MoveOnlyType: ~Copyable {}

0 commit comments

Comments
 (0)