-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Factor isDefaultInitializable logic for reuse #11902
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
Factor isDefaultInitializable logic for reuse #11902
Conversation
@swift-ci Please test |
include/swift/AST/Pattern.h
Outdated
@@ -191,6 +191,9 @@ class alignas(8) Pattern { | |||
/// Does this binding declare something that requires storage? | |||
bool hasStorage() const; | |||
|
|||
/// Can this binding be initialized with a default value? | |||
bool isDefaultInitializable() const; |
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.
This is the negation of isNeverDefaultInitializable
which is used across multiple files and had to be extracted. isNeverDefaultInitializable
seemed strange to expose, though; if there's a better name for this, I think we should use it. I don't think that negation is strong enough to promise default initializability...
lib/AST/Decl.cpp
Outdated
@@ -1132,6 +1132,69 @@ VarDecl *PatternBindingDecl::getSingleVar() const { | |||
return nullptr; | |||
} | |||
|
|||
/// Check whether the given type representation will be | |||
/// default-initializable. | |||
static bool isDefaultInitializable(TypeRepr *typeRepr) { |
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.
We said we didn't really want to expose this on TypeRepr
directly, so this is copied as-is to here.
lib/Sema/TypeCheckDecl.cpp
Outdated
@@ -4204,7 +4122,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> { | |||
TC.checkTypeModifyingDeclAttributes(var); | |||
|
|||
// Decide whether we should suppress default initialization. | |||
if (isNeverDefaultInitializable(PBD->getPattern(i))) | |||
if (!PBD->getPattern(i)->isDefaultInitializable()) |
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.
This is the one remaining call to isNeverDefaultInitializable
on a Pattern
outside of PatternBindingDecl.cpp
Build failed |
Hmm, looks like dispatch test failure on Linux |
Hm, I see the problem. Maybe it should look like this: bool isDefaultInitializable(unsigned i) const;
bool isDefaultInitializable() const {
for (unsigned i = 0, e = getNumPatternEntries(); i < e; ++i)
if (!isDefaultInitializable(i))
return false;
return true;
} Then you can fold all the checks together, and still have something reasonable for initializer synthesis. |
@jrose-apple That's cleaner — thanks! 🙂 I'll put that together now. |
8c9d9f8
to
789ae9d
Compare
@jrose-apple Cleaned this up a bit — let me know if there's anything you think can be further improved |
@swift-ci Please test |
Build failed |
Build failed |
include/swift/AST/Decl.h
Outdated
/// Can this binding be default initialized? | ||
bool isDefaultInitializable() const { | ||
if (!hasStorage()) | ||
return false; |
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'm not sure this is correct. If the binding doesn't have storage, it doesn't need to be default-initialized. That seems closer to a true
than a false
for me, but honestly I'd just leave it as an assertion.
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.
If whether the binding has storage or not doesn't bear on whether default initialization can happen, does asserting have any value over just taking this check out altogether? Because this was private implementation before the assertion was reasonable, but I don't know whether it makes that much sense now, no?
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 assertion would indicate that it is a programmer error to call it in a context where you don't already know whether the PBD has storage. It's also questionable whether true
or false
would be the right answer in that scenario anyway, so an assertion gets you out of having to answer the question.
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.
Fair enough 👍 I'll bring that back
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.
Looks good, apart from the one early exit comment.
@jrose-apple Hmm, in practice, it looks like exposing class X {
lazy var abc: String? = {
return "hello!"
}()
} produces
The underlying storage for if (auto typedPattern = dyn_cast<TypedPattern>(entry.getPattern()))
if (auto typeRepr = typedPattern->getTypeLoc().getTypeRepr()) // has a TypeLoc but the TypeLoc doesn't have a TypeRepr
if (::isDefaultInitializable(typeRepr))
return true; The original code only checked whether the pattern using You understand the nuances here better than I do. Is it more appropriate to simply expose |
@swift-ci Please test |
Build failed |
Build failed |
lib/AST/Decl.cpp
Outdated
if (auto *varDecl = typedPattern->getSingleVar()) | ||
// Lazy storage is never user accessible. | ||
if (!varDecl->isUserAccessible()) { | ||
auto type = typedPattern->getTypeLoc().getType()->getCanonicalType(); |
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.
No need for the getCanonicalType
here; getAnyOptionalObjectType
will already do it.
(In general that's true of nearly all our type operations; the ones where you actually need to get the canonical type manually are the exception rather than the rule.)
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.
Ah, makes sense; I'll remove that. These changes still look reasonable to you otherwise, yes?
832b03f
to
6fa8788
Compare
@swift-ci Please test |
Build failed |
Build failed |
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.
Yep, looks good. Thanks for pulling this out; it's an improvement even without your use case.
lib/AST/Decl.cpp
Outdated
@@ -1132,6 +1132,94 @@ VarDecl *PatternBindingDecl::getSingleVar() const { | |||
return nullptr; | |||
} | |||
|
|||
/// Check whether the given type representation will be | |||
/// default-initializable. | |||
static bool isDefaultInitializable(TypeRepr *typeRepr) { |
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.
This and the Pattern *
below could be using const
.
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.
Will fix before merging. Thanks for taking the time to answer all of my questions — I appreciate the patience. 😄
Factors isDefaultInitializable logic from TypeChecker::addImplicitConstructors (and others) so it can be reused for Codable synthesis.
6fa8788
to
cda3bf1
Compare
@swift-ci Please test and merge |
What's in this pull request?
Factors
isDefaultInitializable
logic out fromTypeChecker::addImplicitConstructors
(and others) so it can be reused forCodable
synthesis. See discussion in comments on #11854.