Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Concurrency] Stage in new Async{Throwing}Stream.init(unfolding:) errors as warnings. #73310

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,9 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
bool accessWithinModule =
(fromModule == var->getDeclContext()->getParentModule());

if (varIsolation.getKind() == ActorIsolation::NonisolatedUnsafe)
return true;

if (!var->isLet()) {
ASTContext &ctx = var->getASTContext();
if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability)) {
Expand Down
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
19 changes: 17 additions & 2 deletions test/Concurrency/flow_isolation.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// RUN: %target-swift-frontend -strict-concurrency=complete -swift-version 5 -parse-as-library -emit-sil -verify %s
// RUN: %target-swift-frontend -strict-concurrency=complete -swift-version 5 -parse-as-library -emit-sil -verify %s -enable-upcoming-feature RegionBasedIsolation

// REQUIRES: asserts

func randomBool() -> Bool { return false }
func logTransaction(_ i: Int) {}

Expand Down Expand Up @@ -815,3 +813,20 @@ func testActorWithInitAccessorInit() {
}
}
}

@available(SwiftStdlib 5.1, *)
actor TestNonisolatedUnsafe {
private nonisolated(unsafe) var child: OtherActor!
init() {
child = OtherActor(parent: self)
}
}

@available(SwiftStdlib 5.1, *)
actor OtherActor {
unowned nonisolated let parent: any Actor

init(parent: any Actor) {
self.parent = parent
}
}
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