-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[SILGen/DI] InitAccessors: Fix handling of nonmutating set
when type has other stored properties
#68875
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
Conversation
The closure with applied base is not escaping and gets applied only once (when self is fully initialized). Let's make sure that the partial application results in on-stack closure that borrows "self" instead of copying it.
…sign_by_wrapper` For cases where init accessor field has a nonmutating set we need ignore copies and borrows associated with load of "self" because they are going to be erased together with the setter application by DI.
@swift-ci please test |
@swift-ci please test source compatibility |
@swift-ci please build toolchain macOS |
@swift-ci please test source compatibility release |
@swift-ci please test source compatibility debug |
This failure in distributed actors looks unrelated but I am going to wait for main branch suite run to complete. |
Thanks @xedin for fixing this. Would it be possible to get this fix into the 5.9.x branch/release as well? |
Unfortunately I think it might be too risky of a change for 5.9.x but I'll see what I can do. |
Hello @xedin, I tried your fix out in the latest Xcode 15.3 beta (15E5178i), and it seem to work fine for the examples I reported, but if I change them slightly to include e.g. let constant it fails to compile again struct Test {
let id: UUID
private var _count: Int
var count: Int
{
@storageRestrictions(initializes: _count)
init {
_count = newValue
}
get {
_count
}
nonmutating set {
// Update store
}
}
init(id: UUID, count: Int) {
self.id = id
self.count = count // << Variable 'self._count' used before being initialized
}
} |
I will take a look! |
Hm, |
This appears to be related to the UUID, if I change the type of |
Interesting. Switching UUID to Date also fails. |
Right, I think both Date and UUID are big enough to force indirect access to the |
I think I figured it out, the problem is not actually SILGen, it's Sema because it generates a load from "self" of |
Here is the fix - #71248 |
@xedin I tested the above with the latest Xcode beta, and it seems to work, but if I modify it slightly it still fails with the same error (the below is a closer match to how my macro is generating its code). struct Test {
let id: UUID
private var _count: Int
var count: Int
{
@storageRestrictions(initializes: _count)
init {
_count = newValue
}
_read {
yield _count
}
nonmutating _modify {
var val = _count
yield &val
}
}
init(id: UUID, count: Int) {
self.id = id
self.count = count // << Variable 'self._count' used before being initialized
} // << Return from initializer without initializing all stored properties
} |
The original change supported only the case where all stored properties were controlled
by an init accessor but when other fields were involved SILGen would emitted copies of
loaded "self" for each setter application which is redundant and due to the fact that the
setter was escaping.
These changes make partial application of the setter non-escaping which means that
"self" can be borrowed instead of copied.
Resolves: #67827