Hey folks! I'm currently doing a pass over the compiler's concurrency-related diagnostic messages to make them friendlier and more understandable. If there are any specific diagnostics that you struggled to understand or weren't actionable enough, please let me know in this thread. Feel free to link to existing forum topics that discussed how to resolve specific concurrency diagnostics.
For most of them, the problem is that you have to have quite a deep understanding of the concurrency features, to understand what the right solution is. Makes it quite hard for people new to concurrency to pick the solution that's going to work, and I don't really know what to do about that.
One that is often simple to resolve is the "global var of non-Sendable type"; I'd love a fix-it on that to change var to let, so long as the type is Sendable and non-optional.
This might be "outside" a discussion specifically about Swift (the language itself)… but I've seen a few instances of SwiftUI protocols that (I would think) should conform to execute only on MainActor that currently are not specified for MainActor. This is a little ambiguous right now because it's not completely clear if this MainActor conformance is coming from the SwiftUI team (in a future beta this summer) or if MainActor conformance is never coming and engineers have to defensively code around that. But this might be an appropriate discussion for Apple Developer Forums.
I think the diagnostics have been much-improved since Swift 5.10 here. But, I do really like explicit distinction between "actor" and "main actor" since it's such a common thing.
Here's another of me just typo'ing while trying to use an isolated parameter and getting very confused about the resulting error. I wouldn't be surprised if this actually really tricky to address, but thought I'd include it just in case.
And another that I personally find confusing about the "implicit" vs "explicit" nature of the asynchronous call in question.
I think this is a wonderful one where RBI detecting a pretty subtle issue, but the diagnostics make it hard to understand.
Some things SwiftUI are definitely still buggy regarding the Main Actor isolation.
E.g. SwiftUI.Commands has a nonisolated protocol requirement but has an internal method which is main-actor isolated which produces an error in Swift 6.
As the UI should always run on the main actor, I guess Apple will add the missing isolation annotations in future betas and I would not start working around the warnings/errors (in some cases impossible) just to make the first beta happy.
Actor-isolated value of type '() async -> ()' passed as a strongly transferred parameter; later accesses could race
I think some guidance would be helpful for this one. It's unclear what I should do to fix that. I'm also not sure what it means from reading it without also reading a few proposals, but that might be an unrealistic goal.
Oh, thank you for pointing this out! I also don't know what it means for a value to be "strongly" transferred I know what "transferring" means, but it's now called "sending", and I don't know what it means for that operation to happen "strongly" or why that would have any implication on what you need to do in source to avoid the risk of a data race.
Yes, concurrency annotations in SwiftUI are outside of the core language, and feedback about the annotations themselves or the lack thereof should be provided via Apple Feedback reports. However, if you're getting any compiler diagnostics that don't make sense that involve the SwiftUI concurrency annotations, please feel free to post specific cases here, as I'm sure the associated compiler error messages could use improvement.
Apologies if this is out of scope for your project. Here I'm conforming an actor to a standard protocol.
public protocol FooProtocol {
var callCount: Int { get set }
}
public actor Foo: FooProtocol {
public var callCount = 0 // error here
}
Error
Actor-isolated property 'callCount' cannot be used to satisfy nonisolated protocol requirement
Fixit: Add '@preconcurrency' to the 'FooProtocol' conformance to defer isolation checking to run time
The fixit feels like a stopgap solution. My understanding (which could easily be wrong) is that the longer term solution is to have FooProtocol inherit from Actor. It also could just be me, but the use of isolated and nonisolated feels unfamiliar. Better wording might note that the compiler needs to understand when a property has to be accessed asynchronously, and the protocol currently doesn't provide that information.
I'm going to start splitting off branches from my current project for better context. Two more errors.
The use of self here is confusing because we're in a function. Sending 'self'-isolated value of type 'repeat each A' with later accesses to actor-isolated context risks causing data races
A minimal repro case with the same error. I don't understand at all why this isn't allowed. This one could be an odd interaction between parameter packs and actors because I couldn't get it to reproduce without a parameter pack.
actor FooActor<each T> {
var messages: [(repeat each T)] = []
func message(_ num: repeat each T) {
messages.append((repeat each num))
}
}
func foo() async {
let fooActor = FooActor<Int>()
await fooActor.message(10)
}
This is from the error above that one in the screenshot. I think we're getting some compiler-internal keywords here or something.
Unforutnately, I don't know if adding an Actor conformance to your protocol will actually help in this situation. Synchronous setters and actors don't mix well, so I think you may be just kicking the can down the road to the call sites. Actors are fundamentally asynchronous so they are hard to use with synchronous protocols.
But I agree that more context could help. Another note indicating that you could use a nonisolated computed property could be nice. But, that would prevent you from using actor-isolated state.
I guess the compiler could also suggest a change to the protocol, if it is defined within the same module. But I'm not sure what suggestion would be reasonable...