-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
[Sema] Diagnose 'nonisolated' attribute on wrapped properties #60475
[Sema] Diagnose 'nonisolated' attribute on wrapped properties #60475
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
@swift-ci please smoke test |
I assume we need to take this into 5.7 too? |
Yes, please open 5.7 PR for this! |
Sorry, but this is not an acceptable solution to me (author of both #59380 and #59494). It forbids behavior that was sound with understanding of Swift concurrency. I am making nontrivial use of The compiler could detect |
This behavior is not sound, that's why we must ban it until we have a way to make the property wrapper storage immutable actor state. Otherwise, this is fundamentally unsafe.
This still isn't safe because the accessor will still read from mutable actor-isolated state. @theblixguy is going to start a discussion on the Swift Forums to brainstorm ways to enable using |
Thanks for the comment Holly. I see that proper safety would be ideal, but in the meantime applying |
@b8591340 FWIW I agree that this is not a solution to the issues that you filed. We should keep those open. |
The problem is that there isn't a way to protect access to the backing storage in the actor. I don't believe there's a way to mark variables as |
I guess I could have a faulty model of When you say backing storage do you mean that computed vars in import Foundation
import UIKit
import os
let offsets = Offsets()
final class Offsets: @unchecked Sendable {
var lock = os_unfair_lock_s()
var data = [Int]()
func new(offset: Int) -> Int {
os_unfair_lock_lock (&lock)
defer { os_unfair_lock_unlock(&lock) }
let index = data.count
data.append(offset)
return index
}
func write(offset value: Int, at index: Int) {
os_unfair_lock_lock (&lock)
defer { os_unfair_lock_unlock(&lock) }
data[index] = value
}
func read(at index: Int) -> Int {
os_unfair_lock_lock (&lock)
defer { os_unfair_lock_unlock(&lock) }
return data[index]
}
}
@propertyWrapper
struct Wrapper: @unchecked Sendable {
var wrappedValue: Int
{ _read { yield offsets.read(at: index) }
nonmutating set { offsets.write(offset: newValue, at: index) } }
@inlinable
public init(wrappedValue offset: Int)
{ index = offsets.new(offset: offset) }
public let index: Int
}
final class UIViewSubclass: UIView {
@Wrapper nonisolated var offset = 0
} |
For final class UIViewSubclass: UIView {
@Wrapper nonisolated var offset = 0
} The property wrapper transformation does this: // Implicitly @MainActor isolated
final class UIViewSubclass: UIView {
private var _offset: Wrapper<Int> = Wrapper(wrappedValue: 0) // <--- MainActor-isolated mutable state!
nonisolated var offset: Int {
get { return _offset.wrappedValue } // <--- error! access to MainActor-isolated state in a nonisolated context
}
} The fact that the computed property was synthesized was circumventing the regular actor isolation checking, which is the bug that was fixed by this PR. |
I see, thanks Holly! Would making the property wrapper implementation emit a It seems like it would be a first-step measure that would be as safe as |
Follow up to #60421.
Diagnose use of
nonisolated
on wrapped properties, because we currently do not support it. This is because the backing property is a storedvar
and so cannot be marked asnonisolated
(otherwise you would be able to mutate the state from outside the actor, which is an unsafe operation). We could potentially support it in the future by allowing users to mark the backing property as a storedlet
instead, then it would be safe to addnonisolated
to the wrapped property.Resolves #59380
Resolves #59494