Skip to content

Commit ab31a0d

Browse files
committed
[PropertyWrappers] Allow constructors with default arguments to be found by findDefaultInit()
1 parent 5e1f790 commit ab31a0d

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,31 @@ static ConstructorDecl *findInitialValueInit(
203203
static ConstructorDecl *findDefaultInit(ASTContext &ctx,
204204
NominalTypeDecl *nominal) {
205205
SmallVector<ConstructorDecl *, 2> defaultValueInitializers;
206-
DeclName initName(ctx, DeclBaseName::createConstructor(),
207-
ArrayRef<Identifier>());
208206
SmallVector<ValueDecl *, 2> decls;
207+
auto initName = DeclBaseName::createConstructor();
209208
nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
210209
for (const auto &decl : decls) {
211210
auto init = dyn_cast<ConstructorDecl>(decl);
212211
if (!init || init->getDeclContext() != nominal)
213212
continue;
214213

215-
defaultValueInitializers.push_back(init);
214+
// A constructor which does not have any parameters or where all the
215+
// parameters have a default argument can be used to default initialize
216+
// the property wrapper type.
217+
assert(init->hasParameterList());
218+
auto hasParams = init->getParameters()->size() > 0;
219+
auto allParamsHaveDefaultArg = false;
220+
221+
if (hasParams) {
222+
allParamsHaveDefaultArg = llvm::all_of(
223+
init->getParameters()->getArray(),
224+
[](const ParamDecl *decl) { return decl->isDefaultArgument(); });
225+
}
226+
227+
// Skip synthesized default initializers
228+
if (!hasParams || (allParamsHaveDefaultArg && !init->isImplicit())) {
229+
defaultValueInitializers.push_back(init);
230+
}
216231
}
217232

218233
switch (defaultValueInitializers.size()) {

test/SILOptimizer/di_property_wrappers.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,33 @@ func testComposed() {
422422
// CHECK-NEXT: .. init Wrapper2<Int>(wrappedValue: 17)
423423
}
424424

425+
// SR-11477
426+
427+
@propertyWrapper
428+
struct SR_11477_W {
429+
let name: String
430+
431+
init(name: String = "DefaultParamInit") {
432+
self.name = name
433+
}
434+
435+
var wrappedValue: Int {
436+
get { return 0 }
437+
}
438+
}
439+
440+
struct SR_11477_C {
441+
@SR_11477_W var property: Int
442+
init() {}
443+
func foo() { print(_property.name) }
444+
}
445+
446+
func testWrapperInitWithDefaultArg() {
447+
let use = SR_11477_C()
448+
449+
use.foo()
450+
// CHECK: DefaultParamInit
451+
}
425452

426453
testIntStruct()
427454
testIntClass()
@@ -431,3 +458,4 @@ testDefaultInit()
431458
testOptIntStruct()
432459
testDefaultNilOptIntStruct()
433460
testComposed()
461+
testWrapperInitWithDefaultArg()

test/decl/var/property_wrappers.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,3 +1724,54 @@ struct TestConcrete1 {
17241724
// ...
17251725
}
17261726
}
1727+
1728+
// SR-11477
1729+
1730+
// Two initializers that can default initialize the wrapper //
1731+
1732+
@propertyWrapper
1733+
struct SR_11477_W1 { // expected-error {{property wrapper type 'SR_11477_W1' has multiple default-value initializers}}
1734+
let name: String
1735+
1736+
init() {} // expected-note {{initializer 'init()' declared here}}
1737+
1738+
init(name: String = "DefaultParamInit") { // expected-note {{initializer 'init(name:)' declared here}}
1739+
self.name = name
1740+
}
1741+
1742+
var wrappedValue: Int {
1743+
get { return 0 }
1744+
}
1745+
}
1746+
1747+
// Two initializers with default arguments that can default initialize the wrapper //
1748+
1749+
@propertyWrapper
1750+
struct SR_11477_W2 { // expected-error {{property wrapper type 'SR_11477_W2' has multiple default-value initializers}}
1751+
let name: String
1752+
1753+
init(anotherName: String = "DefaultParamInit") {} // expected-note {{initializer 'init(anotherName:)' declared here}}
1754+
1755+
init(name: String = "DefaultParamInit") { // expected-note {{initializer 'init(name:)' declared here}}
1756+
self.name = name
1757+
}
1758+
1759+
var wrappedValue: Int {
1760+
get { return 0 }
1761+
}
1762+
}
1763+
1764+
// Single initializer that can default initialize the wrapper //
1765+
1766+
@propertyWrapper
1767+
struct SR_11477_W3 { // Okay
1768+
let name: String
1769+
1770+
init() {
1771+
self.name = "Init"
1772+
}
1773+
1774+
var wrappedValue: Int {
1775+
get { return 0 }
1776+
}
1777+
}

0 commit comments

Comments
 (0)