swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.3k stars 10.34k forks source link

Possible bug when property wrapper's wrappedValue marked as global actor #63346

Closed hiragram closed 10 months ago

hiragram commented 1 year ago

Description

Property wrapper seems to have a problem if its wrappedValue is marked with global actor.

When a property wrapper's wrappedValue is @MainActor , a struct whole itself which has a property using the property wrapper becomes @MainActor. This behavior looks incorrect.

Minimal reproduction code below.

Steps to reproduce

@propertyWrapper struct Wrap<T> {
    init(wrappedValue: T) {
        self.wrappedValue = wrappedValue
    }

    @MainActor var wrappedValue: T
}

struct Foo {
    @Wrap var a: Int = 1
}

Foo() // Error

The error is:

error: call to main actor-isolated initializer 'init()' in a synchronous nonisolated context
note: calls to initializer 'init()' from outside of its actor context are implicitly asynchronous

Other cases

How I met this problem

I met this problem when using SwiftUI. Reproduction code:

class ViewModel: ObservableObject {
    var value: Int = 1
}

struct Foo: View, Equatable {
    @ObservedObject var vm: ViewModel

    nonisolated static func == (lhs: Foo, rhs: Foo) -> Bool {
        lhs.vm.value == rhs.vm.value // Main actor-isolated property 'vm' can not be referenced from a non-isolated context
    }

    var body: some View {
        EmptyView()
    }
}

Expected behavior

Actor of wrappedValue does not affect to actor of type which owns the property wrapper as a property.

Environment

Thanks @omochi for supporting investigation.

hborla commented 10 months ago

This is addressed by SE-0401: Remove Actor Inference caused by Property Wrappers