Concurrency checking bug?

public class SimpleSingleton {
    public var someState = 0
    
    private init() {
    }
    
    static public let shared = SimpleSingleton()
}

Class property 'shared' is not concurrency-safe because it is not either conforming to 'Sendable' or isolated to a global actor; this is an error in Swift 6

  1. The above example is a simplified version of the actual class; my actual class would generate the warning above, while this simplified version does not, in case you are inclined to try. I'd post the more complex example but...

  2. ... when I take my more complex example, which is a nested class, out of being nested, the warning goes away. And, sometimes the warning goes away for a little while, only to come back. Which leads me to think this is a bug.

Right?

Is there any way that this venerable pattern is no longer legal going to be legal with strict concurrency?

I don’t think anyone is going to be able to tell you why an error occurs or if it’s a bug if you don’t post something that actually triggers it.

Fair enough. It's actually hard to isolate it down to an example that consistently fails. I'll see what I can do.

If you want to keep this pattern in a class, the. you need to choose, and apply, some
isolation to the class that lets the compiler know on what “thread” the variables can be accessed synchronously.

A common pattern that i’ve seen is to constrain the class to only be used on @MainActor, but if that’s relevant really depends on your use case.

What I’ve been doing lately for the few bits of singleton goodness I need is to make a single globalActor, build that up as a singleton, and stash state within it - but that mandates async calls to access the data, which may be inconvenient based on where you’re accessing from.

If this is its own subsystem that’s “running on its own in the background”, it might also be a good to isolate that to a global actor that you create - then access in and out of the global actor will still need to be with async calls, but once inside the isolation area of that actor, you can use all the classes synchronously (at least, the ones constrained to that global actor).

That helping at all?

This property is a shared mutable state, that why it is not safe in terms of concurrency.
It is possible to mutate public var someState = 0 property via static public let shared from multiple threads.

So I actually have several static members. It’s not actually a singleton, in fact there are a couple of different “sentinel” types e.g.

static let missing = …
static let shared = …
static let yetAnother = …

but the compiler only complains about one particular one. But it got me thinking that maybe strict checking would outlaw singletons so I made a simpler question first.

Any, why not complain about all my static members? Why does it only hate on particular one?

Could be just the first one, and if you comment it out (or reorder) the compiler will complain about another?