Skip to content

Commit 5244805

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:).
1 parent 5e00f01 commit 5244805

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
@@ -5142,6 +5142,10 @@ class VarDecl : public AbstractStorageDecl {
51425142
/// \end
51435143
bool isPropertyWrapperInitializedWithInitialValue() const;
51445144

5145+
/// Whether the memberwise initializer parameter for a property with a property wrapper type
5146+
/// uses the wrapped type.
5147+
bool isPropertyMemberwiseInitializedWithWrappedType() const;
5148+
51455149
/// If this property is the backing storage for a property with an attached
51465150
/// property wrapper, return the original property.
51475151
///

lib/AST/Decl.cpp

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

54755475
bool VarDecl::isPropertyWrapperInitializedWithInitialValue() const {
5476-
auto &ctx = getASTContext();
5477-
if (!ctx.getLazyResolver())
5478-
return false;
5479-
54805476
auto customAttr = getAttachedPropertyWrapper();
54815477
if (!customAttr)
54825478
return false;
@@ -5495,9 +5491,33 @@ bool VarDecl::isPropertyWrapperInitializedWithInitialValue() const {
54955491
if (customAttr->getArg() != nullptr)
54965492
return false;
54975493

5498-
// If the property wrapper is default-initializable, it's the wrapper
5499-
// being initialized.
5500-
if (PBD->isDefaultInitializable(0))
5494+
// Default initialization does not use a value.
5495+
auto wrapperTypeInfo = getAttachedPropertyWrapperTypeInfo();
5496+
if (wrapperTypeInfo.defaultInit)
5497+
return false;
5498+
5499+
// There is no initializer, so the initialization form depends on
5500+
// whether the property wrapper type has an init(initialValue:).
5501+
return wrapperTypeInfo.initialValueInit != nullptr;
5502+
}
5503+
5504+
bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
5505+
auto customAttr = getAttachedPropertyWrapper();
5506+
if (!customAttr)
5507+
return false;
5508+
5509+
auto *PBD = getParentPatternBinding();
5510+
if (!PBD)
5511+
return false;
5512+
5513+
// If there was an initializer on the original property, initialize
5514+
// via the initial value.
5515+
if (PBD->getPatternList()[0].getEqualLoc().isValid())
5516+
return true;
5517+
5518+
// If there was an initializer on the attribute itself, initialize
5519+
// via the full wrapper.
5520+
if (customAttr->getArg() != nullptr)
55015521
return false;
55025522

55035523
// 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
@@ -1137,10 +1137,13 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
11371137
// If this is the backing storage for a property with an attached wrapper
11381138
// that was initialized with `=`, use that expression as the initializer.
11391139
if (auto originalProperty = var->getOriginalWrappedProperty()) {
1140-
auto wrapperInfo =
1141-
originalProperty->getPropertyWrapperBackingPropertyInfo();
1142-
if (wrapperInfo.originalInitialValue)
1143-
init = wrapperInfo.originalInitialValue;
1140+
if (originalProperty
1141+
->isPropertyMemberwiseInitializedWithWrappedType()) {
1142+
auto wrapperInfo =
1143+
originalProperty->getPropertyWrapperBackingPropertyInfo();
1144+
if (wrapperInfo.originalInitialValue)
1145+
init = wrapperInfo.originalInitialValue;
1146+
}
11441147
}
11451148

11461149
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();
@@ -981,11 +981,15 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
981981
// property wrapper initialized with `=`, inject the value into an
982982
// instance of the wrapper.
983983
if (auto singleVar = pbd->getSingleVar()) {
984-
(void)maybeEmitPropertyWrapperInitFromValue(
985-
*this, init, singleVar, std::move(result),
986-
[&](Expr *expr) {
987-
result = emitRValue(expr);
988-
});
984+
auto originalVar = singleVar->getOriginalWrappedProperty();
985+
if (originalVar &&
986+
originalVar->isPropertyWrapperInitializedWithInitialValue()) {
987+
(void)maybeEmitPropertyWrapperInitFromValue(
988+
*this, init, singleVar, std::move(result),
989+
[&](Expr *expr) {
990+
result = emitRValue(expr);
991+
});
992+
}
989993
}
990994

991995
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
@@ -2247,12 +2247,18 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
22472247
if (!var->getParentPattern()->getSingleVar())
22482248
return;
22492249

2250-
// If we don't have an expression initializer or silgen can't assign a default
2251-
// initializer, then we can't generate a default value. An example of where
2252-
// silgen can assign a default is var x: Int? where the default is nil.
2253-
// If the variable is lazy, go ahead and give it a default value.
2254-
if (!var->getAttrs().hasAttribute<LazyAttr>() &&
2255-
!var->getParentPatternBinding()->isDefaultInitializable())
2250+
// Determine whether this variable will be 'nil' initialized.
2251+
bool isNilInitialized =
2252+
(isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
2253+
!var->isParentInitialized()) ||
2254+
var->getAttrs().hasAttribute<LazyAttr>();
2255+
2256+
// Whether we have explicit initialization.
2257+
bool isExplicitlyInitialized = var->isParentInitialized();
2258+
2259+
// If this is neither nil-initialized nor explicitly initialized, don't add
2260+
// anything.
2261+
if (!isNilInitialized && !isExplicitlyInitialized)
22562262
return;
22572263

22582264
// We can add a default value now.
@@ -2268,13 +2274,14 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
22682274
// default arg. All lazy variables return a nil literal as well. *Note* that
22692275
// the type will always be a sugared T? because we don't default init an
22702276
// explicit Optional<T>.
2271-
if ((isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
2272-
!var->isParentInitialized()) ||
2273-
var->getAttrs().hasAttribute<LazyAttr>()) {
2277+
if (isNilInitialized) {
22742278
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
22752279
return;
22762280
}
22772281

2282+
// Explicitly initialize.
2283+
assert(isExplicitlyInitialized);
2284+
22782285
// If there's a backing storage property, the memberwise initializer
22792286
// will be in terms of that.
22802287
VarDecl *backingStorageVar = var->getPropertyWrapperBackingProperty();
@@ -2334,7 +2341,7 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
23342341
// accept a value of the original property type. Otherwise, the
23352342
// memberwise initializer will be in terms of the backing storage
23362343
// type.
2337-
if (!var->isPropertyWrapperInitializedWithInitialValue()) {
2344+
if (!var->isPropertyMemberwiseInitializedWithWrappedType()) {
23382345
varInterfaceType = backingPropertyType;
23392346
}
23402347
}

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)