-
Notifications
You must be signed in to change notification settings - Fork 10.5k
DefiniteInitialization: correctly handle implicit closures. #35276
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
@swift-ci test |
Build failed |
@swift-ci smoke test macOS |
@@ -0,0 +1,50 @@ | |||
// RUN: %target-swift-frontend -emit-sil %s -o /dev/null | |||
|
|||
// Test boolean operators with implicit closures |
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.
I need a sil test case before I can approve this.
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.
I added one.
SILModule &Module; | ||
const DIMemoryObjectInfo &TheMemory; | ||
DIElementUseInfo &UseInfo; | ||
FunctionSet &visitedClosures; |
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.
Nitpick: to be consistent with the other members this should be VisitedClosures
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.
done
SILArgument *arg = callee->getArgument(argIndex); | ||
|
||
// Bail if arg is not the original 'self' object, but e.g. a projected member. | ||
if (arg->getType().getObjectType() != TheMemory.getType()) |
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.
What if TheMemory.getType() is an address-only type because 'self' has an address-only field?
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.
TheMemory
is always an object type. I added an assert
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.
Should it be a CanType instead of a SILType then, if the address/object bit is not used?
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.
maybe
} | ||
} | ||
|
||
struct NestedClosures { |
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.
Please add a test for a generic struct or a struct with an existential field to test the address only case
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.
done
init(_ a: Bool) { | ||
x = false | ||
y = false | ||
z = false || (y || (x || a)) |
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.
Does your code behave the same with explicit "self." qualification too?
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.
yes. I added a test
|
||
init() { | ||
x = false | ||
y = false || forward(&x) |
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.
Can you add some invalid test cases as well, to ensure we still diagnose when the field is not initialized?
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.
Another case to test is partial initialization:
init(b: Bool) {
if b {
x = false
}
y = false || x
}
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.
The invalid test cases are in definite_init_closures_fail.swift
.
I added a test for partial initialization
f9af384
to
7c47929
Compare
@swift-ci smoke test |
Thanks! LGTM. |
@swift-ci smoke test linux |
Correctly handle implicit closures in initializers, e.g. with boolean operators: init() { bool_member1 = false bool_member2 = false || bool_member1 // implicit closure } The implicit closure ('bool_member1' at the RHS of the || operator) captures the whole self, but only uses 'bool_member1'. If the whole captured 'self' is considered as use, we would get a "'self.bool_member2' not initialized" error at the partial_apply. Therefore look into the body of the closure and only add the actually used members. rdar://66420045
7c47929
to
c452e4c
Compare
@swift-ci smoke test |
@swift-ci smoke test macOS |
Correctly handle implicit closures in initializers, e.g. with boolean operators:
The implicit closure ('bool_member1' at the RHS of the || operator) captures the whole self, but only uses 'bool_member1'.
If the whole captured 'self' is considered as use, we would get a "'self.bool_member2' not initialized" error at the partial_apply.
Therefore look into the body of the closure and only add the actually used members.
rdar://66420045