Skip to content

Commit

Permalink
Merge pull request #73310 from hborla/async-stream-sendable-error
Browse files Browse the repository at this point in the history
[Concurrency] Stage in new `Async{Throwing}Stream.init(unfolding:)` errors as warnings.
  • Loading branch information
hborla committed May 1, 2024
2 parents 4e474d8 + 7f5e47e commit 4368125
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 24 deletions.
12 changes: 10 additions & 2 deletions lib/Sema/TypeCheckEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,14 +1183,21 @@ class ApplyClassifier {
return Classification();
}

bool isContextPreconcurrency() const {
if (!DC)
return false;

return getActorIsolationOfContext(DC).preconcurrency();
}

/// Whether a missing 'await' error on accessing an async var should be
/// downgraded to a warning.
///
/// Missing 'await' errors are downgraded for synchronous access to isolated
/// global or static 'let' variables, which was previously accepted in
/// compiler versions before 5.10, or for declarations marked preconcurrency.
bool downgradeAsyncAccessToWarning(Decl *decl) {
if (decl->preconcurrency()) {
if (decl->preconcurrency() || isContextPreconcurrency()) {
return true;
}

Expand Down Expand Up @@ -1339,7 +1346,8 @@ class ApplyClassifier {

// Downgrade missing 'await' errors for preconcurrency references.
result.setDowngradeToWarning(
result.hasAsync() && fnRef.isPreconcurrency());
result.hasAsync() &&
(fnRef.isPreconcurrency() || isContextPreconcurrency()));

auto classifyApplyEffect = [&](EffectKind kind) {
if (!fnType->hasEffect(kind) &&
Expand Down
14 changes: 2 additions & 12 deletions stdlib/public/Concurrency/AsyncStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,21 +330,11 @@ public struct AsyncStream<Element> {
/// }
///
///
@_alwaysEmitIntoClient
@_silgen_name("$sScS9unfolding8onCancelScSyxGxSgyYac_yyYbcSgtcfC")
@preconcurrency // Original API had `@Sendable` only on `onCancel`
public init(
unfolding produce: @escaping @Sendable () async -> Element?,
onCancel: (@Sendable () -> Void)? = nil
) {
self.init(
unfolding: produce as () async -> Element?,
onCancel: onCancel
)
}

@usableFromInline
internal init(
unfolding produce: @escaping () async -> Element?,
onCancel: (@Sendable () -> Void)? = nil
) {
let storage: _AsyncStreamCriticalStorage<Optional<() async -> Element?>>
= .create(produce)
Expand Down
11 changes: 1 addition & 10 deletions stdlib/public/Concurrency/AsyncThrowingStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -369,18 +369,9 @@ public struct AsyncThrowingStream<Element, Failure: Error> {
/// print(error)
/// }
///
@_alwaysEmitIntoClient
@preconcurrency
public init(
unfolding produce: @escaping @Sendable () async throws -> Element?
) where Failure == Error {
self.init(
unfolding: produce as () async throws -> Element?
)
}

@usableFromInline
internal init(
unfolding produce: @escaping () async throws -> Element?
) where Failure == Error {
let storage: _AsyncStreamCriticalStorage<Optional<() async throws -> Element?>>
= .create(produce)
Expand Down
29 changes: 29 additions & 0 deletions test/Concurrency/sendable_checking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,32 @@ final class UseNonisolatedUnsafe: Sendable {
}
}
}

@available(SwiftStdlib 5.1, *)
@preconcurrency
func preconcurrencyContext(_: @escaping @Sendable () -> Void) {}

@available(SwiftStdlib 5.1, *)
@MainActor
struct DowngradeForPreconcurrency {
func capture(completion: @escaping @MainActor () -> Void) {
preconcurrencyContext {
Task {
completion()
// expected-warning@-1 2 {{capture of 'completion' with non-sendable type '@MainActor () -> Void' in a `@Sendable` closure; this is an error in the Swift 6 language mode}}
// expected-note@-2 2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
// expected-warning@-3 {{expression is 'async' but is not marked with 'await'; this is an error in the Swift 6 language mode}}
// expected-note@-4 {{calls to parameter 'completion' from outside of its actor context are implicitly asynchronous}}
}
}
}

var x: Int
func createStream() -> AsyncStream<Int> {
AsyncStream<Int> {
self.x
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in the Swift 6 language mode}}
// expected-note@-2 {{property access is 'async'}}
}
}
}
3 changes: 3 additions & 0 deletions test/api-digester/stability-concurrency-abi.test
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ Func withCheckedThrowingContinuation(function:_:) has parameter 1 type change fr
Func withCheckedContinuation(function:_:) has been renamed to Func withCheckedContinuation(isolation:function:_:)
Func withCheckedContinuation(function:_:) has mangled name changing from '_Concurrency.withCheckedContinuation<A>(function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A' to '_Concurrency.withCheckedContinuation<A>(isolation: isolated Swift.Optional<Swift.Actor>, function: Swift.String, _: (Swift.CheckedContinuation<A, Swift.Never>) -> ()) async -> A'

// AsyncStream.init(unfolding:onCancel:) uses @_silgen_name to preserve mangling after adding @preconcurrency.
Constructor AsyncStream.init(unfolding:onCancel:) has mangled name changing from 'Swift.AsyncStream.init(unfolding: () async -> Swift.Optional<A>, onCancel: Swift.Optional<@Sendable () -> ()>) -> Swift.AsyncStream<A>' to 'Swift.AsyncStream.init(unfolding: () async -> Swift.Optional<A>, onCancel: Swift.Optional<() -> ()>) -> Swift.AsyncStream<A>'

// SerialExecutor gained `enqueue(_: __owned Job)`, protocol requirements got default implementations
Func SerialExecutor.enqueue(_:) has been added as a protocol requirement

Expand Down

0 comments on commit 4368125

Please sign in to comment.