Skip to content

Commit b5830e1

Browse files
committed
---
yaml --- r: 349052 b: refs/heads/master c: 370f47c h: refs/heads/master
1 parent 95dfed6 commit b5830e1

File tree

5 files changed

+96
-152
lines changed

5 files changed

+96
-152
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 7e31d7a7175df0e7750c86f2bab76bf7619881a8
2+
refs/heads/master: 370f47c27a80a12e8ddb73c586782825cd883c22
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4533,8 +4533,6 @@ ERROR(property_wrapper_wrong_initial_value_init, none,
45334533
(DeclName, Type, Type))
45344534
ERROR(property_wrapper_failable_init, none,
45354535
"%0 cannot be failable", (DeclName))
4536-
ERROR(property_wrapper_ambiguous_default_value_init, none,
4537-
"property wrapper type %0 has multiple default-value initializers", (Type))
45384536
ERROR(property_wrapper_type_requirement_not_accessible,none,
45394537
"%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have "
45404538
"more restrictive access than its enclosing property wrapper type %3 "

trunk/include/swift/AST/PropertyWrappers.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ struct PropertyWrapperTypeInfo {
4343
HasInitialValueInit
4444
} wrappedValueInit = NoWrappedValueInit;
4545

46-
/// The initializer `init()` that will be called to default-initialize a
46+
/// The initializer that will be called to default-initialize a
4747
/// value with an attached property wrapper.
48-
ConstructorDecl *defaultInit = nullptr;
48+
enum {
49+
NoDefaultValueInit = 0,
50+
HasDefaultValueInit
51+
} defaultInit = NoDefaultValueInit;
4952

5053
/// The property through which the projection value ($foo) will be accessed.
5154
///

trunk/lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 84 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
#include "swift/AST/TypeCheckRequests.h"
2727
using namespace swift;
2828

29+
/// The kind of property initializer to look for
30+
enum class PropertyWrapperInitKind {
31+
/// An initial-value initializer (i.e. `init(initialValue:)`)
32+
InitialValue,
33+
/// An wrapped-value initializer (i.e. `init(wrappedValue:)`)
34+
WrappedValue,
35+
/// An default-value initializer (i.e. `init()` or `init(defaultArgs...)`)
36+
Default
37+
};
38+
2939
/// Find the named property in a property wrapper to which access will
3040
/// be delegated.
3141
static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
@@ -79,54 +89,71 @@ static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
7989
return var;
8090
}
8191

82-
/// Determine whether we have a suitable wrapped-value initializer within
83-
/// a property wrapper type.
84-
static ConstructorDecl *findInitialValueInit(
85-
ASTContext &ctx,
86-
NominalTypeDecl *nominal,
87-
VarDecl *valueVar,
88-
Identifier argumentLabel) {
89-
// Retrieve the type of the 'value' property.
90-
Type valueVarType = valueVar->getValueInterfaceType();
91-
92+
/// Determine whether we have a suitable initializer within a property wrapper
93+
/// type.
94+
static ConstructorDecl *
95+
findSuitableWrapperInit(ASTContext &ctx, NominalTypeDecl *nominal,
96+
VarDecl *valueVar, PropertyWrapperInitKind initKind) {
9297
enum class NonViableReason {
9398
Failable,
9499
ParameterTypeMismatch,
95100
Inaccessible,
96101
};
97-
SmallVector<std::tuple<ConstructorDecl*, NonViableReason, Type>, 2> nonviable;
98-
SmallVector<ConstructorDecl *, 2> initialValueInitializers;
99102

103+
SmallVector<std::tuple<ConstructorDecl *, NonViableReason, Type>, 2>
104+
nonviable;
105+
SmallVector<ConstructorDecl *, 2> viableInitializers;
100106
SmallVector<ValueDecl *, 2> decls;
107+
108+
Identifier argumentLabel;
109+
switch (initKind) {
110+
case PropertyWrapperInitKind::InitialValue:
111+
argumentLabel = ctx.Id_initialValue;
112+
break;
113+
case PropertyWrapperInitKind::WrappedValue:
114+
argumentLabel = ctx.Id_wrappedValue;
115+
break;
116+
case PropertyWrapperInitKind::Default:
117+
break;
118+
}
119+
101120
nominal->lookupQualified(nominal, DeclBaseName::createConstructor(),
102121
NL_QualifiedDefault, decls);
103122
for (const auto &decl : decls) {
104123
auto init = dyn_cast<ConstructorDecl>(decl);
105-
if (!init || init->getDeclContext() != nominal || init->getGenericParams())
124+
if (!init || init->getDeclContext() != nominal || init->isGeneric())
106125
continue;
107126

127+
ParamDecl *argumentParam = nullptr;
128+
bool allArgsDefault = true;
108129
// Check whether every parameter meets one of the following criteria:
109130
// (1) The parameter has a default argument, or
110131
// (2) The parameter has the given argument label.
111-
ParamDecl *wrappedValueParam = nullptr;
112132
for (auto param : *init->getParameters()) {
113133
// Recognize the first parameter with the requested argument label.
114-
if (param->getArgumentName() == argumentLabel && !wrappedValueParam) {
115-
wrappedValueParam = param;
134+
if (param->getArgumentName() == argumentLabel && !argumentParam) {
135+
argumentParam = param;
116136
continue;
117137
}
118138

119-
if (param->isDefaultArgument())
139+
if (param->isDefaultArgument()) {
140+
allArgsDefault &= true;
120141
continue;
121-
122-
// Forget we had a match.
123-
wrappedValueParam = nullptr;
124-
break;
142+
} else {
143+
// Forget we had a match.
144+
allArgsDefault = false;
145+
argumentParam = nullptr;
146+
break;
147+
}
125148
}
126149

127-
if (!wrappedValueParam)
150+
if (initKind != PropertyWrapperInitKind::Default && !argumentParam)
128151
continue;
129152

153+
if (initKind == PropertyWrapperInitKind::Default && !allArgsDefault) {
154+
continue;
155+
}
156+
130157
// Failable initializers cannot be used.
131158
if (init->isFailable()) {
132159
nonviable.push_back(
@@ -141,33 +168,37 @@ static ConstructorDecl *findInitialValueInit(
141168
continue;
142169
}
143170

144-
if (!wrappedValueParam->hasInterfaceType())
145-
continue;
171+
// Additional checks for initial-value and wrapped-value initializers
172+
if (initKind != PropertyWrapperInitKind::Default) {
173+
if (!argumentParam)
174+
continue;
146175

147-
if (wrappedValueParam->isInOut() || wrappedValueParam->isVariadic())
148-
continue;
176+
if (!argumentParam->hasInterfaceType())
177+
continue;
149178

150-
auto paramType = wrappedValueParam->getInterfaceType();
151-
if (wrappedValueParam->isAutoClosure()) {
152-
if (auto *fnType = paramType->getAs<FunctionType>())
153-
paramType = fnType->getResult();
154-
}
179+
if (argumentParam->isInOut() || argumentParam->isVariadic())
180+
continue;
155181

156-
// The parameter type must be the same as the type of `valueVar` or an
157-
// autoclosure thereof.
158-
if (!paramType->isEqual(valueVarType)) {
159-
nonviable.push_back(
160-
std::make_tuple(init, NonViableReason::ParameterTypeMismatch,
161-
paramType));
162-
continue;
182+
auto paramType = argumentParam->getInterfaceType();
183+
if (argumentParam->isAutoClosure()) {
184+
if (auto *fnType = paramType->getAs<FunctionType>())
185+
paramType = fnType->getResult();
186+
}
187+
188+
// The parameter type must be the same as the type of `valueVar` or an
189+
// autoclosure thereof.
190+
if (!paramType->isEqual(valueVarType)) {
191+
nonviable.push_back(std::make_tuple(
192+
init, NonViableReason::ParameterTypeMismatch, paramType));
193+
continue;
194+
}
163195
}
164196

165-
// Check the type
166-
initialValueInitializers.push_back(init);
197+
viableInitializers.push_back(init);
167198
}
168199

169200
// If we found some nonviable candidates but no viable ones, complain.
170-
if (initialValueInitializers.empty() && !nonviable.empty()) {
201+
if (viableInitializers.empty() && !nonviable.empty()) {
171202
for (const auto &candidate : nonviable) {
172203
auto init = std::get<0>(candidate);
173204
auto reason = std::get<1>(candidate);
@@ -187,110 +218,15 @@ static ConstructorDecl *findInitialValueInit(
187218

188219
case NonViableReason::ParameterTypeMismatch:
189220
init->diagnose(diag::property_wrapper_wrong_initial_value_init,
190-
init->getFullName(), paramType, valueVarType);
221+
init->getFullName(), paramType,
222+
valueVar->getValueInterfaceType());
191223
valueVar->diagnose(diag::decl_declared_here, valueVar->getFullName());
192224
break;
193225
}
194226
}
195227
}
196228

197-
return initialValueInitializers.empty() ? nullptr
198-
: initialValueInitializers.front();
199-
}
200-
201-
/// Determine whether we have a suitable init() within a property
202-
/// wrapper type.
203-
static ConstructorDecl *findDefaultInit(ASTContext &ctx,
204-
NominalTypeDecl *nominal) {
205-
SmallVector<ConstructorDecl *, 2> defaultValueInitializers;
206-
SmallVector<ValueDecl *, 2> decls;
207-
auto initName = DeclBaseName::createConstructor();
208-
nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
209-
for (const auto &decl : decls) {
210-
auto init = dyn_cast<ConstructorDecl>(decl);
211-
if (!init || init->getDeclContext() != nominal || init->isGeneric())
212-
continue;
213-
214-
assert(init->hasParameterList());
215-
// A constructor which does not have any parameters or where all the
216-
// parameters have a default argument can be used to default initialize
217-
// the property wrapper type.
218-
//
219-
// A constructor with no parameters will satisfy the check below.
220-
bool allParamsHaveDefaultArg = llvm::all_of(
221-
init->getParameters()->getArray(),
222-
[](const ParamDecl *decl) { return decl->isDefaultArgument(); });
223-
224-
if (allParamsHaveDefaultArg) {
225-
defaultValueInitializers.push_back(init);
226-
}
227-
}
228-
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-
259-
switch (defaultValueInitializers.size()) {
260-
case 0:
261-
return nullptr;
262-
263-
case 1:
264-
break;
265-
266-
default:
267-
// Diagnose ambiguous default value initializers.
268-
nominal->diagnose(diag::property_wrapper_ambiguous_default_value_init,
269-
nominal->getDeclaredType());
270-
for (auto init : defaultValueInitializers) {
271-
init->diagnose(diag::kind_declname_declared_here,
272-
init->getDescriptiveKind(), init->getFullName());
273-
}
274-
return nullptr;
275-
}
276-
277-
// The initializer must be as accessible as the nominal type.
278-
auto init = defaultValueInitializers.front();
279-
if (init->getFormalAccess() < nominal->getFormalAccess()) {
280-
init->diagnose(diag::property_wrapper_type_requirement_not_accessible,
281-
init->getFormalAccess(), init->getDescriptiveKind(),
282-
init->getFullName(), nominal->getDeclaredType(),
283-
nominal->getFormalAccess());
284-
return nullptr;
285-
}
286-
287-
// The initializer must not be failable.
288-
if (init->isFailable()) {
289-
init->diagnose(diag::property_wrapper_failable_init, initName);
290-
return nullptr;
291-
}
292-
293-
return init;
229+
return viableInitializers.empty() ? nullptr : viableInitializers.front();
294230
}
295231

296232
/// Determine whether we have a suitable static subscript to which we
@@ -376,10 +312,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
376312

377313
PropertyWrapperTypeInfo result;
378314
result.valueVar = valueVar;
379-
if (findInitialValueInit(ctx, nominal, valueVar, ctx.Id_wrappedValue))
315+
if (findSuitableWrapperInit(ctx, nominal, valueVar,
316+
PropertyWrapperInitKind::WrappedValue))
380317
result.wrappedValueInit = PropertyWrapperTypeInfo::HasWrappedValueInit;
381-
else if (auto init = findInitialValueInit(
382-
ctx, nominal, valueVar, ctx.Id_initialValue)) {
318+
else if (auto init = findSuitableWrapperInit(
319+
ctx, nominal, valueVar, PropertyWrapperInitKind::InitialValue)) {
383320
result.wrappedValueInit = PropertyWrapperTypeInfo::HasInitialValueInit;
384321

385322
if (init->getLoc().isValid()) {
@@ -396,7 +333,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
396333
}
397334
}
398335

399-
result.defaultInit = findDefaultInit(ctx, nominal);
336+
if (findSuitableWrapperInit(ctx, nominal, /*valueVar=*/nullptr,
337+
PropertyWrapperInitKind::Default)) {
338+
result.defaultInit = PropertyWrapperTypeInfo::HasDefaultValueInit;
339+
}
340+
400341
result.projectedValueVar =
401342
findValueProperty(ctx, nominal, ctx.Id_projectedValue,
402343
/*allowMissing=*/true);

trunk/test/decl/var/property_wrappers.swift

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

17321732
@propertyWrapper
1733-
struct SR_11477_W1 { // Okay, because we'll pick the best one here
1733+
struct SR_11477_W1 { // Okay
17341734
let name: String
17351735

17361736
init() {
@@ -1749,12 +1749,14 @@ struct SR_11477_W1 { // Okay, because we'll pick the best one here
17491749
// Two initializers with default arguments that can default initialize the wrapper //
17501750

17511751
@propertyWrapper
1752-
struct SR_11477_W2 { // expected-error {{property wrapper type 'SR_11477_W2' has multiple default-value initializers}}
1752+
struct SR_11477_W2 { // Okay
17531753
let name: String
17541754

1755-
init(anotherName: String = "DefaultParamInit") {} // expected-note {{initializer 'init(anotherName:)' declared here}}
1755+
init(anotherName: String = "DefaultParamInit1") {
1756+
self.name = anotherName
1757+
}
17561758

1757-
init(name: String = "DefaultParamInit") { // expected-note {{initializer 'init(name:)' declared here}}
1759+
init(name: String = "DefaultParamInit2") {
17581760
self.name = name
17591761
}
17601762

0 commit comments

Comments
 (0)