Skip to content

Simplify the expansion of @Test by eliminating the isolated thunk.#1592

Open
grynspan wants to merge 4 commits intomainfrom
jgrynspan/simplify-test-macro-expansion
Open

Simplify the expansion of @Test by eliminating the isolated thunk.#1592
grynspan wants to merge 4 commits intomainfrom
jgrynspan/simplify-test-macro-expansion

Conversation

@grynspan
Copy link
Contributor

This PR removes one of the thunks we emit when expanding @Test. For example, given the following test function:

@Test func foo() {}

We currently emit, approximately:

@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@Sendable private  func $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_() async throws -> Void {
  @Sendable func $s12TestingTests3foo4TestfMp_7__localfMu_(_:isolated (any _Concurrency.Actor)?=Testing.__defaultSynchronousIsolationContext) async throws {
    _ = unsafe try await Testing.__requiringUnsafe(Testing.__requiringTry(Testing.__requiringAwait(foo())))
  }
  try await $s12TestingTests3foo4TestfMp_7__localfMu_()
}

@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
@Sendable private  func $s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_() async -> Testing.Test {
  return .__function(
  named: "foo()",
  in: nil as Swift.Never.Type?,
  xcTestCompatibleSelector: nil,
  traits: [],sourceBounds: Testing.__SourceBounds(__uncheckedLowerBound: Testing.SourceLocation(__uncheckedFileID: "TestingTests/ZipTests.swift", filePath: "/Volumes/Dev/Source/swift-testing-public/Tests/TestingTests/ZipTests.swift", line: 30, column: 2), upperBound: (30, 20)),
  parameters: [],
  testFunction: $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_
)
}

@section("__DATA_CONST,__swift5_tests")
@used
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
private nonisolated  let $s12TestingTests3foo4TestfMp_33testContentRecord152ec26a56a4f672fMu_: Testing.__TestContentRecord = (
  0x74657374, /* 'test' */
  0,
  { outValue, type, _, _ in
    Testing.Test.__store($s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_, into: outValue, asTypeAt: type)
  },
  0,
  0
)

Note that the first thunk function has a nested thunk function that serves only to impose actor isolation on the actual test function. This change replaces that thunk with nonisolated(nonsending) in appropriate locations throughout the macro target and library target. After this change, we emit a simpler expansion:

@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@Sendable private nonisolated(nonsending)  func $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_() async throws -> Void {
  _ = unsafe try await Testing.__requiringUnsafe(Testing.__requiringTry(Testing.__requiringAwait(foo())))
}

@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@Sendable private nonisolated(nonsending)  func $s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_() async -> Testing.Test {
  return .__function(
  named: "foo()",
  in: nil as Swift.Never.Type?,
  xcTestCompatibleSelector: nil,
  traits: [],sourceBounds: Testing.__SourceBounds(__uncheckedLowerBound: Testing.SourceLocation(__uncheckedFileID: "TestingTests/ZipTests.swift", filePath: "/Volumes/Dev/Source/swift-testing-public/Tests/TestingTests/ZipTests.swift", line: 30, column: 2), upperBound: (30, 20)),
  parameters: [],
  testFunction: $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_
)
}

@section("__DATA_CONST,__swift5_tests")
@used
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
private nonisolated  let $s12TestingTests3foo4TestfMp_33testContentRecord152ec26a56a4f672fMu_: Testing.__TestContentRecord = (
  0x74657374, /* 'test' */
  0,
  { outValue, type, _, _ in
  Testing.Test.__store($s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_, into: outValue, asTypeAt: type)
},
  0,
  0
)

Checklist:

  • Code and documentation should follow the style of the Style Guide.
  • If public symbols are renamed or modified, DocC references should be updated.

@grynspan grynspan added this to the Swift 6.4.0 (main) milestone Feb 25, 2026
@grynspan grynspan self-assigned this Feb 25, 2026
@grynspan grynspan added enhancement New feature or request concurrency 🔀 Swift concurrency/sendability issues macros 🔭 Related to Swift macros such as @Test or #expect labels Feb 25, 2026
This PR removes one of the thunks we emit when expanding `@Test`. For example,
given the following test function:

```swift
@test func foo() {}
```

We currently emit, approximately:

```swift
@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@sendable private  func $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_() async throws -> Void {
  @sendable func $s12TestingTests3foo4TestfMp_7__localfMu_(_:isolated (any _Concurrency.Actor)?=Testing.__defaultSynchronousIsolationContext) async throws {
    _ = unsafe try await Testing.__requiringUnsafe(Testing.__requiringTry(Testing.__requiringAwait(foo())))
  }
  try await $s12TestingTests3foo4TestfMp_7__localfMu_()
}

@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
@sendable private  func $s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_() async -> Testing.Test {
  return .__function(
  named: "foo()",
  in: nil as Swift.Never.Type?,
  xcTestCompatibleSelector: nil,
  traits: [],sourceBounds: Testing.__SourceBounds(__uncheckedLowerBound: Testing.SourceLocation(__uncheckedFileID: "TestingTests/ZipTests.swift", filePath: "/Volumes/Dev/Source/swift-testing-public/Tests/TestingTests/ZipTests.swift", line: 30, column: 2), upperBound: (30, 20)),
  parameters: [],
  testFunction: $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_
)
}

@section("__DATA_CONST,__swift5_tests")
@used
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
private nonisolated  let $s12TestingTests3foo4TestfMp_33testContentRecord152ec26a56a4f672fMu_: Testing.__TestContentRecord = (
  0x74657374, /* 'test' */
  0,
  { outValue, type, _, _ in
    Testing.Test.__store($s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_, into: outValue, asTypeAt: type)
  },
  0,
  0
)
```

Note that the first thunk function has a nested thunk function that serves only
to impose actor isolation on the actual test function. This change replaces that
thunk with `nonisolated(nonsending)` in appropriate locations throughout the
macro target and library target. After this change, we emit a simpler expansion:

```swift
@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@sendable private nonisolated(nonsending)  func $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_() async throws -> Void {
  _ = unsafe try await Testing.__requiringUnsafe(Testing.__requiringTry(Testing.__requiringAwait(foo())))
}

@available(*, deprecated, message: "This function is an implementation detail of the testing library. Do not use it directly.")
@sendable private nonisolated(nonsending)  func $s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_() async -> Testing.Test {
  return .__function(
  named: "foo()",
  in: nil as Swift.Never.Type?,
  xcTestCompatibleSelector: nil,
  traits: [],sourceBounds: Testing.__SourceBounds(__uncheckedLowerBound: Testing.SourceLocation(__uncheckedFileID: "TestingTests/ZipTests.swift", filePath: "/Volumes/Dev/Source/swift-testing-public/Tests/TestingTests/ZipTests.swift", line: 30, column: 2), upperBound: (30, 20)),
  parameters: [],
  testFunction: $s12TestingTests3foo4TestfMp_17Z152ec26a56a4f672fMu_
)
}

@section("__DATA_CONST,__swift5_tests")
@used
@available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.")
private nonisolated  let $s12TestingTests3foo4TestfMp_33testContentRecord152ec26a56a4f672fMu_: Testing.__TestContentRecord = (
  0x74657374, /* 'test' */
  0,
  { outValue, type, _, _ in
  Testing.Test.__store($s12TestingTests3foo4TestfMp_25generator152ec26a56a4f672fMu_, into: outValue, asTypeAt: type)
},
  0,
  0
)
```
@grynspan grynspan force-pushed the jgrynspan/simplify-test-macro-expansion branch from 674bad0 to 9608c1d Compare February 25, 2026 19:16
#expect(i == j)
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: this seems unnecessary

Copy link
Contributor

@harlanhaskins harlanhaskins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's quite nice to see language features obviating the need for workarounds in our code. Very nice

@grynspan
Copy link
Contributor Author

Compiler angry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

concurrency 🔀 Swift concurrency/sendability issues enhancement New feature or request macros 🔭 Related to Swift macros such as @Test or #expect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants