Skip to content

Commit e0e2d77

Browse files
authored
Merge pull request swiftlang#25752 from DougGregor/property-wrapper-default-arg-default-init
[SE-0258] Enable default argument for wrapped property going through init()
2 parents ec1a690 + 22e40fe commit e0e2d77

File tree

4 files changed

+56
-13
lines changed

4 files changed

+56
-13
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,11 @@ bool PatternBindingDecl::isDefaultInitializable(unsigned i) const {
15861586
if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) {
15871587
if (wrapperInfo.defaultInit)
15881588
return true;
1589+
1590+
// If one of the attached wrappers is missing an initialValue
1591+
// initializer, cannot default-initialize.
1592+
if (!singleVar->allAttachedPropertyWrappersHaveInitialValueInit())
1593+
return false;
15891594
}
15901595
}
15911596

lib/Sema/CodeSynthesis.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,18 +2197,18 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
21972197
if (!var->getParentPattern()->getSingleVar())
21982198
return;
21992199

2200-
// Determine whether this variable will be 'nil' initialized.
2201-
bool isNilInitialized =
2202-
(isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
2203-
!var->isParentInitialized()) ||
2204-
var->getAttrs().hasAttribute<LazyAttr>();
2205-
22062200
// Whether we have explicit initialization.
22072201
bool isExplicitlyInitialized = var->isParentInitialized();
22082202

2209-
// If this is neither nil-initialized nor explicitly initialized, don't add
2210-
// anything.
2211-
if (!isNilInitialized && !isExplicitlyInitialized)
2203+
// Whether we can default-initialize this property.
2204+
auto binding = var->getParentPatternBinding();
2205+
bool isDefaultInitializable =
2206+
var->getAttrs().hasAttribute<LazyAttr>() ||
2207+
(binding && binding->isDefaultInitializable());
2208+
2209+
// If this is neither explicitly initialized nor
2210+
// default-initializable, don't add anything.
2211+
if (!isExplicitlyInitialized && !isDefaultInitializable)
22122212
return;
22132213

22142214
// We can add a default value now.
@@ -2224,14 +2224,16 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
22242224
// default arg. All lazy variables return a nil literal as well. *Note* that
22252225
// the type will always be a sugared T? because we don't default init an
22262226
// explicit Optional<T>.
2227+
bool isNilInitialized =
2228+
var->getAttrs().hasAttribute<LazyAttr>() ||
2229+
(!isExplicitlyInitialized && isDefaultInitializable &&
2230+
var->getValueInterfaceType()->getAnyNominal() == ctx.getOptionalDecl() &&
2231+
!var->getAttachedPropertyWrapperTypeInfo(0).defaultInit);
22272232
if (isNilInitialized) {
22282233
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
22292234
return;
22302235
}
22312236

2232-
// Explicitly initialize.
2233-
assert(isExplicitlyInitialized);
2234-
22352237
// If there's a backing storage property, the memberwise initializer
22362238
// will be in terms of that.
22372239
VarDecl *backingStorageVar = var->getPropertyWrapperBackingProperty();

test/IDE/print_property_wrappers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ struct HasWrappers {
4747
var z: String
4848

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

5353
func trigger() {

test/decl/var/property_wrappers.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ struct WrapperWithInitialValue<T> {
1717
}
1818
}
1919

20+
@propertyWrapper
21+
struct WrapperWithDefaultInit<T> {
22+
private var stored: T?
23+
24+
var wrappedValue: T {
25+
get { stored! }
26+
set { stored = newValue }
27+
}
28+
29+
init() {
30+
self.stored = nil
31+
}
32+
}
33+
2034
@propertyWrapper
2135
struct WrapperAcceptingAutoclosure<T> {
2236
private let fn: () -> T
@@ -610,6 +624,21 @@ struct DefaultedMemberwiseInits {
610624

611625
@WrapperWithInitialValue(initialValue: 17)
612626
var z: Int
627+
628+
@WrapperWithDefaultInit
629+
var w: Int
630+
631+
@WrapperWithDefaultInit
632+
var optViaDefaultInit: Int?
633+
634+
@WrapperWithInitialValue
635+
var optViaInitialValue: Int?
636+
}
637+
638+
639+
struct CannotDefaultMemberwiseOptionalInit { // expected-note{{'init(x:)' declared here}}
640+
@Wrapper
641+
var x: Int?
613642
}
614643

615644
func testDefaultedMemberwiseInits() {
@@ -622,6 +651,13 @@ func testDefaultedMemberwiseInits() {
622651
_ = DefaultedMemberwiseInits(y: 42)
623652
_ = DefaultedMemberwiseInits(x: Wrapper(wrappedValue: false))
624653
_ = DefaultedMemberwiseInits(z: WrapperWithInitialValue(initialValue: 42))
654+
_ = DefaultedMemberwiseInits(w: WrapperWithDefaultInit())
655+
_ = DefaultedMemberwiseInits(optViaDefaultInit: WrapperWithDefaultInit())
656+
_ = DefaultedMemberwiseInits(optViaInitialValue: nil)
657+
_ = DefaultedMemberwiseInits(optViaInitialValue: 42)
658+
659+
_ = CannotDefaultMemberwiseOptionalInit() // expected-error{{missing argument for parameter 'x' in call}}
660+
_ = CannotDefaultMemberwiseOptionalInit(x: Wrapper(wrappedValue: nil))
625661
}
626662

627663
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)