Skip to content

Commit 57c69d9

Browse files
committed
[SE-0258] Clean up memberwise initializer / default-initialization interaction
When the backing storage of a wrapped property is default-initialized via the property wrapper type's init(), don't count that as a direct initialization of the backing storage for the purposes of constructing the memberwise initializer. Instead, treat this case the same as if there were no initializer, keying the form of the memberwise initializer off the presence of init(initialValue:). (cherry picked from commit 5244805)
1 parent f7331dd commit 57c69d9

File tree

6 files changed

+67
-29
lines changed

6 files changed

+67
-29
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5125,6 +5125,10 @@ class VarDecl : public AbstractStorageDecl {
51255125
/// \end
51265126
bool isPropertyWrapperInitializedWithInitialValue() const;
51275127

5128+
/// Whether the memberwise initializer parameter for a property with a property wrapper type
5129+
/// uses the wrapped type.
5130+
bool isPropertyMemberwiseInitializedWithWrappedType() const;
5131+
51285132
/// If this property is the backing storage for a property with an attached
51295133
/// property wrapper, return the original property.
51305134
///

lib/AST/Decl.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5397,10 +5397,6 @@ VarDecl *VarDecl::getPropertyWrapperBackingProperty() const {
53975397
}
53985398

53995399
bool VarDecl::isPropertyWrapperInitializedWithInitialValue() const {
5400-
auto &ctx = getASTContext();
5401-
if (!ctx.getLazyResolver())
5402-
return false;
5403-
54045400
auto customAttr = getAttachedPropertyWrapper();
54055401
if (!customAttr)
54065402
return false;
@@ -5419,9 +5415,33 @@ bool VarDecl::isPropertyWrapperInitializedWithInitialValue() const {
54195415
if (customAttr->getArg() != nullptr)
54205416
return false;
54215417

5422-
// If the property wrapper is default-initializable, it's the wrapper
5423-
// being initialized.
5424-
if (PBD->isDefaultInitializable(0))
5418+
// Default initialization does not use a value.
5419+
auto wrapperTypeInfo = getAttachedPropertyWrapperTypeInfo();
5420+
if (wrapperTypeInfo.defaultInit)
5421+
return false;
5422+
5423+
// There is no initializer, so the initialization form depends on
5424+
// whether the property wrapper type has an init(initialValue:).
5425+
return wrapperTypeInfo.initialValueInit != nullptr;
5426+
}
5427+
5428+
bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
5429+
auto customAttr = getAttachedPropertyWrapper();
5430+
if (!customAttr)
5431+
return false;
5432+
5433+
auto *PBD = getParentPatternBinding();
5434+
if (!PBD)
5435+
return false;
5436+
5437+
// If there was an initializer on the original property, initialize
5438+
// via the initial value.
5439+
if (PBD->getPatternList()[0].getEqualLoc().isValid())
5440+
return true;
5441+
5442+
// If there was an initializer on the attribute itself, initialize
5443+
// via the full wrapper.
5444+
if (customAttr->getArg() != nullptr)
54255445
return false;
54265446

54275447
// There is no initializer, so the initialization form depends on

lib/SILGen/SILGen.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,10 +1120,13 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
11201120
// If this is the backing storage for a property with an attached wrapper
11211121
// that was initialized with `=`, use that expression as the initializer.
11221122
if (auto originalProperty = var->getOriginalWrappedProperty()) {
1123-
auto wrapperInfo =
1124-
originalProperty->getPropertyWrapperBackingPropertyInfo();
1125-
if (wrapperInfo.originalInitialValue)
1126-
init = wrapperInfo.originalInitialValue;
1123+
if (originalProperty
1124+
->isPropertyMemberwiseInitializedWithWrappedType()) {
1125+
auto wrapperInfo =
1126+
originalProperty->getPropertyWrapperBackingPropertyInfo();
1127+
if (wrapperInfo.originalInitialValue)
1128+
init = wrapperInfo.originalInitialValue;
1129+
}
11271130
}
11281131

11291132
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);

lib/SILGen/SILGenConstructor.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static bool maybeEmitPropertyWrapperInitFromValue(
112112
llvm::function_ref<void(Expr *)> body) {
113113
auto originalProperty = field->getOriginalWrappedProperty();
114114
if (!originalProperty ||
115-
!originalProperty->isPropertyWrapperInitializedWithInitialValue())
115+
!originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
116116
return false;
117117

118118
auto wrapperInfo = originalProperty->getPropertyWrapperBackingPropertyInfo();
@@ -991,11 +991,15 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
991991
// property wrapper initialized with `=`, inject the value into an
992992
// instance of the wrapper.
993993
if (auto singleVar = pbd->getSingleVar()) {
994-
(void)maybeEmitPropertyWrapperInitFromValue(
995-
*this, init, singleVar, std::move(result),
996-
[&](Expr *expr) {
997-
result = emitRValue(expr);
998-
});
994+
auto originalVar = singleVar->getOriginalWrappedProperty();
995+
if (originalVar &&
996+
originalVar->isPropertyWrapperInitializedWithInitialValue()) {
997+
(void)maybeEmitPropertyWrapperInitFromValue(
998+
*this, init, singleVar, std::move(result),
999+
[&](Expr *expr) {
1000+
result = emitRValue(expr);
1001+
});
1002+
}
9991003
}
10001004

10011005
emitMemberInit(*this, selfDecl, entry.getPattern(), std::move(result));

lib/Sema/CodeSynthesis.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,12 +2070,18 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
20702070
if (!var->getParentPattern()->getSingleVar())
20712071
return;
20722072

2073-
// If we don't have an expression initializer or silgen can't assign a default
2074-
// initializer, then we can't generate a default value. An example of where
2075-
// silgen can assign a default is var x: Int? where the default is nil.
2076-
// If the variable is lazy, go ahead and give it a default value.
2077-
if (!var->getAttrs().hasAttribute<LazyAttr>() &&
2078-
!var->getParentPatternBinding()->isDefaultInitializable())
2073+
// Determine whether this variable will be 'nil' initialized.
2074+
bool isNilInitialized =
2075+
(isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
2076+
!var->isParentInitialized()) ||
2077+
var->getAttrs().hasAttribute<LazyAttr>();
2078+
2079+
// Whether we have explicit initialization.
2080+
bool isExplicitlyInitialized = var->isParentInitialized();
2081+
2082+
// If this is neither nil-initialized nor explicitly initialized, don't add
2083+
// anything.
2084+
if (!isNilInitialized && !isExplicitlyInitialized)
20792085
return;
20802086

20812087
// We can add a default value now.
@@ -2091,13 +2097,14 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
20912097
// default arg. All lazy variables return a nil literal as well. *Note* that
20922098
// the type will always be a sugared T? because we don't default init an
20932099
// explicit Optional<T>.
2094-
if ((isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
2095-
!var->isParentInitialized()) ||
2096-
var->getAttrs().hasAttribute<LazyAttr>()) {
2100+
if (isNilInitialized) {
20972101
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
20982102
return;
20992103
}
21002104

2105+
// Explicitly initialize.
2106+
assert(isExplicitlyInitialized);
2107+
21012108
// If there's a backing storage property, the memberwise initializer
21022109
// will be in terms of that.
21032110
VarDecl *backingStorageVar = var->getPropertyWrapperBackingProperty();
@@ -2157,7 +2164,7 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
21572164
// accept a value of the original property type. Otherwise, the
21582165
// memberwise initializer will be in terms of the backing storage
21592166
// type.
2160-
if (!var->isPropertyWrapperInitializedWithInitialValue()) {
2167+
if (!var->isPropertyMemberwiseInitializedWithWrappedType()) {
21612168
varInterfaceType = backingPropertyType;
21622169
}
21632170
}

test/IDE/print_property_wrappers.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ struct HasWrappers {
4747
var z: String
4848

4949
// Memberwise initializer.
50-
// CHECK: init(x: Wrapper<Int> = Wrapper(closure: foo), y: Bool = true, z: Wrapper<String> = Wrapper())
50+
// CHECK: init(x: Wrapper<Int> = Wrapper(closure: foo), y: Bool = true, z: String)
5151
}
5252

5353
func trigger() {
54-
_ = HasWrappers(y: false)
54+
_ = HasWrappers(y: false, z: "hello")
5555
}

0 commit comments

Comments
 (0)