Skip to content

Add Sendable conformance#582

Merged
natecook1000 merged 11 commits into
apple:mainfrom
vlm:add-sendable-conformance
Nov 17, 2023
Merged

Add Sendable conformance#582
natecook1000 merged 11 commits into
apple:mainfrom
vlm:add-sendable-conformance

Conversation

@vlm
Copy link
Copy Markdown
Contributor

@vlm vlm commented Aug 26, 2023

It can be useful to send AsyncParsableCommand as an argument to some function. This is trivial to do in a non-async context. However, in async context the type that is sent as an argument has to be Sendable. This patch adds Sendable conformance so this becomes expressible and warning-free:

struct Args: AsyncParsableCommand, Sendable {
    func run() async throws {
        Task { await otherFunction(arguments: self) }
    }
}

The warnings will become errors in Swift 6, so this is a forward-looking change.

Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary

@vlm vlm force-pushed the add-sendable-conformance branch from 8e9e8af to 8b68689 Compare August 26, 2023 19:58
@vlm vlm added the enhancement New feature or request label Aug 26, 2023
@vlm vlm requested a review from natecook1000 August 26, 2023 19:59
@natecook1000
Copy link
Copy Markdown
Member

Thanks for this, @vlm! Do we not need to declare the Parsed enum as sendable as well? That can indirectly store a user-supplied closure via initializers that include a transform parameter, which could break encapsulation. Should we look at adding @Sendable annotations to those closures at the same time?

@vlm
Copy link
Copy Markdown
Contributor Author

vlm commented Sep 6, 2023

@natecook1000 looking...

@vlm vlm force-pushed the add-sendable-conformance branch from 8b68689 to aec234d Compare September 6, 2023 23:24
@vlm
Copy link
Copy Markdown
Contributor Author

vlm commented Sep 6, 2023

@natecook1000 these conformances doesn't appear to be required. Added a test to showcase that. No warnings.

https://github.com/apple/swift-argument-parser/pull/582/files#diff-1d0a514c56a2c811f846acdce3410d034f8008d908b6180d6a4fa1d536a279c3R36

vlm and others added 6 commits September 8, 2023 01:23
This derives the `hasUpdated` check from the parsed values data type,
rather than storing it in the closure (which breaks sendability) or
passing it through the closure invocation (which wasn't finished
enough to actually work).
This allows for a stronger, compiler-supported guarantee of
sendability when a compound `ParsableArguments` or `ParsableCommand`
type is marked `Sendable`. Most transformations shouldn't be a
problem, since the general case is that these are pure string ->
value transformations.

In cases where making such a transformation sendable is impossible,
an author can always change the property to be just a string and
perform the transformation within the context of the command's
execution, in either the `run()` or `validate()` methods.
@natecook1000
Copy link
Copy Markdown
Member

@swift-ci Please test

@rauhul
Copy link
Copy Markdown
Collaborator

rauhul commented Nov 4, 2023

Is it possible to put the additional sendable restrictions behind conditional compilation so this change isn't source breaking?

Comment thread Package@swift-5.6.swift Outdated
dependencies: ["ArgumentParserToolInfo"],
exclude: ["CMakeLists.txt"]),
exclude: ["CMakeLists.txt"],
swiftSettings: [.unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"])]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is a "very bad idea" ™️ - anyone who pulls in the 5.6 manifest will see this propagated to their library or application and potentially introduce compiler errors and warnings.

We solved this in Vapor with a 5.9 specific manifest using the experimental feature flag which restricts it to that package - e.g. https://github.com/vapor/vapor/blob/main/Package%40swift-5.9.swift#L96

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Definitely! Thanks for that note — I was planning to just remove the flag, and didn't realize that enableExperimentalFeature allows us to keep the setting package-local.

@natecook1000
Copy link
Copy Markdown
Member

@rauhul None of these changes should be source breaking, since checking is only a warning until you upgrade to Swift 6 mode. Additionally, to turn off the warnings making other source changes, a package that depends on ArgumentParser can add @preconcurrency to their import statement.

This adds the `@preconcurrency` attribute to all public APIs that
have changed to take a `@Sendable` closure. This will ease the
migration path for sendable adoption for ArgumentParser users, since
a warning will only appear for using these APIs (like the `transform`
parameter in an @option or @argument) once they've turned on strict
concurrency checking.

I'm also backing out changes that avoided those warnings in the tests
and examples, since in most cases those warnings are spurious;
unapplied functions don't capture state. See
https://forums.swift.org/t/pitch-inferring-sendable-for-methods-and-key-path-literals/68011
for more on this and hopefully an upcoming fix for these issues.
In order to provide `@preconcurrency` support, the package needs to
have a minimum Swift requirement of 5.7. This makes that change and
updates the README to indicate this for the next version.
@natecook1000 natecook1000 force-pushed the add-sendable-conformance branch from de76384 to 2812f57 Compare November 16, 2023 19:52
@natecook1000
Copy link
Copy Markdown
Member

@swift-ci Please test

@natecook1000 natecook1000 merged commit 511a72a into apple:main Nov 17, 2023
@vlm vlm deleted the add-sendable-conformance branch December 12, 2023 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants