Skip to content

Commit 69c05c0

Browse files
authored
Merge pull request #25386 from DougGregor/property-wrappers-memberwise-and-default-init
2 parents 512ddff + 5244805 commit 69c05c0

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
@@ -5150,6 +5150,10 @@ class VarDecl : public AbstractStorageDecl {
51505150
/// \end
51515151
bool isPropertyWrapperInitializedWithInitialValue() const;
51525152

5153+
/// Whether the memberwise initializer parameter for a property with a property wrapper type
5154+
/// uses the wrapped type.
5155+
bool isPropertyMemberwiseInitializedWithWrappedType() const;
5156+
51535157
/// If this property is the backing storage for a property with an attached
51545158
/// property wrapper, return the original property.
51555159
///

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)