Skip to content

Commit e41d1ef

Browse files
committed
[PropertyWrappers] Try to find the best default value initializer if we have multiple inits, before diagnosing them as ambiguous
1 parent 22bbaea commit e41d1ef

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,41 @@ static ConstructorDecl *findDefaultInit(ASTContext &ctx,
221221
init->getParameters()->getArray(),
222222
[](const ParamDecl *decl) { return decl->isDefaultArgument(); });
223223

224-
// Only add non-synthesized initializers.
225-
if (allParamsHaveDefaultArg && !init->isImplicit()) {
224+
if (allParamsHaveDefaultArg) {
226225
defaultValueInitializers.push_back(init);
227226
}
228227
}
229228

229+
if (defaultValueInitializers.size() > 1) {
230+
// Let's find the single most specialized init. If we don't have one, then
231+
// we'll diagnose later.
232+
if (auto TC = static_cast<TypeChecker *>(ctx.getLazyResolver())) {
233+
Optional<unsigned> bestIdx;
234+
for (unsigned i = 1, n = defaultValueInitializers.size(); i != n; ++i) {
235+
auto bestOrPrevIdx = bestIdx ? bestIdx.getValue() : i - 1;
236+
auto firstInit =
237+
cast<ValueDecl>(defaultValueInitializers[bestOrPrevIdx]);
238+
auto secondInit = cast<ValueDecl>(defaultValueInitializers[i]);
239+
240+
switch (TC->compareDeclarations(nominal, firstInit, secondInit)) {
241+
case Comparison::Better:
242+
bestIdx = bestOrPrevIdx;
243+
break;
244+
case Comparison::Worse:
245+
bestIdx = i;
246+
break;
247+
case Comparison::Unordered:
248+
break;
249+
}
250+
}
251+
252+
if (bestIdx.hasValue()) {
253+
auto bestInit = defaultValueInitializers[bestIdx.getValue()];
254+
defaultValueInitializers = {bestInit};
255+
}
256+
}
257+
}
258+
230259
switch (defaultValueInitializers.size()) {
231260
case 0:
232261
return nullptr;
@@ -235,7 +264,7 @@ static ConstructorDecl *findDefaultInit(ASTContext &ctx,
235264
break;
236265

237266
default:
238-
// Diagnose ambiguous init() initializers.
267+
// Diagnose ambiguous default value initializers.
239268
nominal->diagnose(diag::property_wrapper_ambiguous_default_value_init,
240269
nominal->getDeclaredType());
241270
for (auto init : defaultValueInitializers) {
@@ -245,7 +274,7 @@ static ConstructorDecl *findDefaultInit(ASTContext &ctx,
245274
return nullptr;
246275
}
247276

248-
// 'init()' must be as accessible as the nominal type.
277+
// The initializer must be as accessible as the nominal type.
249278
auto init = defaultValueInitializers.front();
250279
if (init->getFormalAccess() < nominal->getFormalAccess()) {
251280
init->diagnose(diag::property_wrapper_type_requirement_not_accessible,

test/decl/var/property_wrappers.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,12 +1730,14 @@ struct TestConcrete1 {
17301730
// Two initializers that can default initialize the wrapper //
17311731

17321732
@propertyWrapper
1733-
struct SR_11477_W1 { // expected-error {{property wrapper type 'SR_11477_W1' has multiple default-value initializers}}
1733+
struct SR_11477_W1 { // Okay, because we'll pick the best one here
17341734
let name: String
17351735

1736-
init() {} // expected-note {{initializer 'init()' declared here}}
1736+
init() {
1737+
self.name = "Init"
1738+
}
17371739

1738-
init(name: String = "DefaultParamInit") { // expected-note {{initializer 'init(name:)' declared here}}
1740+
init(name: String = "DefaultParamInit") {
17391741
self.name = name
17401742
}
17411743

0 commit comments

Comments
 (0)