Skip to content

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

Merged
merged 2 commits into from
Jan 8, 2021

Conversation

eeckstein
Copy link
Contributor

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

@eeckstein eeckstein requested a review from gottesmm January 6, 2021 10:01
@eeckstein
Copy link
Contributor Author

@swift-ci test

@swift-ci
Copy link
Contributor

swift-ci commented Jan 6, 2021

Build failed
Swift Test OS X Platform
Git Sha - f9af384b7cc720058c4bdd7e982f05963dea9423

@eeckstein
Copy link
Contributor Author

@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
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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

Copy link
Contributor Author

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())
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe

}
}

struct NestedClosures {
Copy link
Contributor

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

Copy link
Contributor Author

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))
Copy link
Contributor

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?

Copy link
Contributor Author

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)
Copy link
Contributor

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?

Copy link
Contributor

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
}

Copy link
Contributor Author

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

@eeckstein eeckstein force-pushed the di-implicit-closures branch from f9af384 to 7c47929 Compare January 7, 2021 11:30
@eeckstein
Copy link
Contributor Author

@swift-ci smoke test

@slavapestov
Copy link
Contributor

Thanks! LGTM.

@eeckstein
Copy link
Contributor Author

@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
@eeckstein eeckstein force-pushed the di-implicit-closures branch from 7c47929 to c452e4c Compare January 7, 2021 22:47
@eeckstein
Copy link
Contributor Author

@swift-ci smoke test

@eeckstein
Copy link
Contributor Author

@swift-ci smoke test macOS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants