swiftlang / swift

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

Init accessor unexpected behavior when initializing optional value #74114

Open MahdiBM opened 5 months ago

MahdiBM commented 5 months ago

Description

See Reproduction. self._name = newValue?.description does not compile presumably because it modifies the optional value, but something like self._name = newValue does compile.

Reproduction

struct MyType {
    var _name: String?
    var name: String? {
        @storageRestrictions(initializes: _name)
        init {
///     ^~~~~
///     error: property '_name' not initialized by init accessor
            self._name = newValue?.description
        }
        get {
            self._name
        }
    }
}

Expected behavior

No errors.

Environment

Tested on Swift 5.10 and Swift 6 nightly docker images.

Additional information

Workaround:

        ...
        @storageRestrictions(initializes: _name)
        init {
+           self._name = nil
            self._name = newValue?.description
        }
        ....
Rajveer100 commented 4 months ago

@AnthonyLatsis Property wrappers are only applied when the property is accessed or modified, and they don't fundamentally change the behavior of properties themselves.

So, in essence, the compiler doesn't enforce the initialization requirement for _name because it's not being accessed or modified in a way that triggers the property wrapper's logic. This behavior might seem unexpected, but it's consistent with how property wrappers are designed to work in Swift.

Correct me if I misunderstood.

MahdiBM commented 4 months ago

@Rajveer100 there are no property wrappers here though.

@storageRestrictions is an attribute to help the compiler in enforcing stuff like definite initialization in init accessors.

The rest is also unrelated to property wrappers, in this certain issue.

Rajveer100 commented 4 months ago

I see, my bad 🙂.

AnthonyLatsis commented 4 months ago

I think you are mixing up property wrappers with init accessors. An init accessor must initialize (set) the properties listed in the initializes argument of the attached storageRestrictions attribute. The body of the accessor, self._name = newValue?.description, is an unconditional assignment to _name, so I, too, expect this code to compile successfully.

Rajveer100 commented 4 months ago

But the newValue may not have been initialised in the first place right, so accessing the description would not make sense?

AnthonyLatsis commented 4 months ago

newValue is the init accessor’s implicit parameter, like in regular set accessors. It cannot be uninitialized.