-
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
[SR-10950] Property wrappers: @autoclosure not working? #53341
Comments
The autoclosure describes the behavior of how that one stored property is initialized, but it doesn't describe the behavior of the memberwise initializer synthesized for the entire struct. @DougGregor, should it? |
For what it's worth, the output is the same if I move the initialization of the property into the struct, like this: struct N {
@Lazy var number: Int = { () -> Int in
print("-- Initializing Lazy storage")
return 23
}()
}
print("++ Initializing N")
var n = N()
print("++ Printing number")
print(n.number)
/* prints:
++ Initializing N
-- Initializing Lazy storage
++ Printing number
23
*/ @belkadan This suggest to me that it's irrelevant whether I use the struct's initializer or the property's initializer. Or I'm still misunderstanding what's supposed to happen. |
I do think there's a problem here because: 1. The behaviour of the property-wrapped struct N {
lazy var number: Int = { () -> Int in
print("-- Initializing Lazy storage")
return 23
}()
}
// '++ Printing number' comes before '-- Initializing Lazy storage' 2. The behaviour of the property-wrapped struct N {
var _number: Lazy<Int> = Lazy<Int>(wrappedValue: { () -> Int in
print("-- Initializing Lazy storage")
return 23
}())
var number: Int {
mutating get { return _number.wrappedValue }
set(v) { _number.wrappedValue = v }
}
}
// '++ Printing number' comes before '-- Initializing Lazy storage' |
Again, it's specifically a problem with the synthesized memberwise initializer, not with the property itself. @swift-ci create |
Ah, you're right, I wasn't reading it correctly at all. Sorry! |
As it turns out, the memberwise initializer is indeed involved. Under certain conditions, the implicitly generated memberwise initializer arg for a property-wrapped struct member would be of the the wrapped type rather than the wrapper type. For example: @propertyWrapper
struct Wrap {
var wrappedValue: Int
init(wrappedValue: Int) { self.wrappedValue = wrappedValue }
}
struct N {
@Wrap var number = computeThing()
}
func computeThing() -> Int { return 0 }
// Implicit memberwise initializer for N in swiftc -emit-silgen is:
// N.init(number: Int = computeThing())
// (Here, the number arg is Int, not Wrap) This is currently true even if the @propertyWrapper
struct Wrap {
var wrappedValue: Int
init(wrappedValue: @autoclosure () -> Int) { self.wrappedValue = wrappedValue() }
}
struct N {
@Wrap var number = computeThing()
}
func computeThing() -> Int { return 0 }
// Implicit memberwise initializer for N in swiftc -emit-silgen is:
// N.init(number: Int = computeThing())
// (Here too, the number arg is Int, not Wrap) So, the autoclosed expression To fix this, we need to handle the autoclosure case specially. When we find an autoclosure in the innermost wrapper, we could take one of these approaches: 1. The memberwise initializer arg should be the wrapper type (Wrap) instead of the wrapped type (Int), so N would then be memberwise initialized as I think approach #2 is better and will work on a PR with this approach. In addition, if we find an autoclosure in a non-innermost wrapper, I think we should make the memberwise initializer take an arg of the wrapper type. |
@roop Great analysis, thanks for getting to the bottom of this. |
@roop Thanks so much for the PR. |
@roop are you still working on this? |
@theblixguy Yes. I'll update the status in the PR in a couple of days and tag you. |
Confirmed with DEVELOPMENT-SNAPSHOT-2020-03-22-a that @roop and @DougGregor fixed this with #30537 Thank you! |
Environment
macOS 10.14.5
Swift snapshot 5.1-DEVELOPMENT-SNAPSHOT-2019-06-16-a
Additional Detail from JIRA
md5: 504a059be79e3a05b7670b7c6174d327
Issue Description:
Maybe I'm misunderstanding something, but does adding
@autoclosure
to theinit(wrappedValue: )
initializer of a property wrapper actually have any effect?I copied the sample code for
Lazy
from the SE-0258 proppoal, and then I initialize the lazy value with a closure that prints when it's getting called.Paste this code into a file "propertywrapper.swift":
Actual output (Swift 5.1 dev snapshot 2019-06-16a):
Note that "– Initializing Lazy storage" appears before "++ Printing number". I would have expected these lines to be reversed because of the
@autoclosure
attribute of theinit(wrappedValue: )
initializer.Expected output:
The text was updated successfully, but these errors were encountered: