Skip to content

[Concurrency] Implicit global actor attributes imply Sendable. #73666

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

Merged
merged 2 commits into from
May 16, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6055,7 +6055,7 @@ ProtocolConformance *swift::deriveImplicitSendableConformance(
}

// A non-protocol type with a global actor is implicitly Sendable.
if (nominal->getGlobalActorAttr()) {
if (getActorIsolation(nominal).isGlobalActor()) {
// Form the implicit conformance to Sendable.
return formConformance(nullptr);
}
Expand Down
20 changes: 20 additions & 0 deletions test/Concurrency/sendable_checking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -407,3 +407,23 @@ struct DowngradeForPreconcurrency {
}
}
}

@available(SwiftStdlib 5.1, *)
@MainActor protocol InferMainActor {}

@available(SwiftStdlib 5.1, *)
struct ImplicitSendableViaMain: InferMainActor {}

@available(SwiftStdlib 5.1, *)
extension ImplicitSendableViaMain {
nonisolated func capture() {
Task { @MainActor in
_ = self
}
}
}

@available(SwiftStdlib 5.1, *)
struct TestImplicitSendable: Sendable {
var x: ImplicitSendableViaMain
}
25 changes: 11 additions & 14 deletions validation-test/Sema/SwiftUI/rdar76252310.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5 -strict-concurrency=targeted
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5 -strict-concurrency=complete

// REQUIRES: objc_interop
// REQUIRES: OS=macosx

import SwiftUI

class Visibility: ObservableObject { // expected-note 2{{class 'Visibility' does not conform to the 'Sendable' protocol}}
@MainActor
class Visibility: ObservableObject {
nonisolated init() {}

@Published var yes = false // some nonsense
}

struct CoffeeTrackerView: View { // expected-note 4{{consider making struct 'CoffeeTrackerView' conform to the 'Sendable' protocol}}
struct CoffeeTrackerView: View {
nonisolated init() {}

@ObservedObject var showDrinkList: Visibility = Visibility()

var storage: Visibility = Visibility()
Expand All @@ -34,24 +39,16 @@ func fromMainActor() async {


func fromConcurrencyAware() async {
// expected-note@+3 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}
// expected-warning@+2 {{expression is 'async' but is not marked with 'await'}}
// expected-warning@+1 {{non-sendable type 'CoffeeTrackerView' returned by call to main actor-isolated function cannot cross actor boundary}}
let view = CoffeeTrackerView()
let view = CoffeeTrackerView() // synthesized 'init' is 'nonisolated'

// expected-warning@+4 {{non-sendable type 'CoffeeTrackerView' passed in implicitly asynchronous call to main actor-isolated property 'body' cannot cross actor boundary}}
// expected-note@+3 {{property access is 'async'}}
// expected-warning@+2 {{non-sendable type 'some View' in implicitly asynchronous access to main actor-isolated property 'body' cannot cross actor boundary}}
// expected-warning@+1 {{expression is 'async' but is not marked with 'await'}}
_ = view.body

// expected-warning@+4 {{non-sendable type 'CoffeeTrackerView' passed in implicitly asynchronous call to main actor-isolated property 'showDrinkList' cannot cross actor boundary}}
// expected-note@+3 {{property access is 'async'}}
// expected-warning@+2 {{non-sendable type 'Visibility' in implicitly asynchronous access to main actor-isolated property 'showDrinkList' cannot cross actor boundary}}
// expected-note@+2 {{property access is 'async'}}
// expected-warning@+1 {{expression is 'async' but is not marked with 'await'}}
_ = view.showDrinkList

// expected-warning@+2 {{non-sendable type 'CoffeeTrackerView' passed in implicitly asynchronous call to main actor-isolated property 'storage' cannot cross actor boundary}}
// expected-warning@+1 {{non-sendable type 'Visibility' in implicitly asynchronous access to main actor-isolated property 'storage' cannot cross actor boundary}}
_ = await view.storage
_ = view.storage
}