[swift6] Fix async execute() losing a cancellation while the request is created

Merged
SP
14d ago
+15-0

Fixes #25182.

_execute() relies on onCancel to cancel the request, but a Task cancellation that lands while execute(completion:) is still creating the request finds nothing to cancel, and the request goes out anyway. After execute(completion:) returns, the request is set, so re-checking Task.isCancelled there and cancelling closes the gap.

RequestTask itself is intentionally left as is. Remembering a cancel() that arrives before a request is set would break callers that wrap a builder in RxSwift/Combine and call cancel() on disposal (also after completion), then re-execute the same builder on retry.

Tested in a downstream project with a builder whose execute(completion:) cancels the current Task before setting its request: without the change the request stays active, with it the request is cancelled.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/swift6*.yaml || exit
    
    Commit all changed files.
  • @mention the technical committee: @jgavris @ehyche @Edubits @jaz-ah @4brunu @dydus0x14

Summary by cubic

Fixes a race in Swift 6's async execute() where a Task cancellation arriving while the request is still being created could be lost, letting the request go out anyway. After execute(completion:) sets the request, the code now re-checks Task.isCancelled and cancels the request if needed.

RequestTask behavior is intentionally unchanged: remembering a cancel() that arrives before a request is set would break callers that wrap builders in RxSwift/Combine and cancel on disposal, then re-execute the same builder on retry.