26
26
#include " swift/AST/TypeCheckRequests.h"
27
27
using namespace swift ;
28
28
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
+
29
39
// / Find the named property in a property wrapper to which access will
30
40
// / be delegated.
31
41
static VarDecl *findValueProperty (ASTContext &ctx, NominalTypeDecl *nominal,
@@ -79,54 +89,71 @@ static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
79
89
return var;
80
90
}
81
91
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) {
92
97
enum class NonViableReason {
93
98
Failable,
94
99
ParameterTypeMismatch,
95
100
Inaccessible,
96
101
};
97
- SmallVector<std::tuple<ConstructorDecl*, NonViableReason, Type>, 2 > nonviable;
98
- SmallVector<ConstructorDecl *, 2 > initialValueInitializers;
99
102
103
+ SmallVector<std::tuple<ConstructorDecl *, NonViableReason, Type>, 2 >
104
+ nonviable;
105
+ SmallVector<ConstructorDecl *, 2 > viableInitializers;
100
106
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
+
101
120
nominal->lookupQualified (nominal, DeclBaseName::createConstructor (),
102
121
NL_QualifiedDefault, decls);
103
122
for (const auto &decl : decls) {
104
123
auto init = dyn_cast<ConstructorDecl>(decl);
105
- if (!init || init->getDeclContext () != nominal || init->getGenericParams ())
124
+ if (!init || init->getDeclContext () != nominal || init->isGeneric ())
106
125
continue ;
107
126
127
+ ParamDecl *argumentParam = nullptr ;
128
+ bool allArgsDefault = true ;
108
129
// Check whether every parameter meets one of the following criteria:
109
130
// (1) The parameter has a default argument, or
110
131
// (2) The parameter has the given argument label.
111
- ParamDecl *wrappedValueParam = nullptr ;
112
132
for (auto param : *init->getParameters ()) {
113
133
// 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;
116
136
continue ;
117
137
}
118
138
119
- if (param->isDefaultArgument ())
139
+ if (param->isDefaultArgument ()) {
140
+ allArgsDefault &= true ;
120
141
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
+ }
125
148
}
126
149
127
- if (!wrappedValueParam )
150
+ if (initKind != PropertyWrapperInitKind::Default && !argumentParam )
128
151
continue ;
129
152
153
+ if (initKind == PropertyWrapperInitKind::Default && !allArgsDefault) {
154
+ continue ;
155
+ }
156
+
130
157
// Failable initializers cannot be used.
131
158
if (init->isFailable ()) {
132
159
nonviable.push_back (
@@ -141,33 +168,37 @@ static ConstructorDecl *findInitialValueInit(
141
168
continue ;
142
169
}
143
170
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 ;
146
175
147
- if (wrappedValueParam-> isInOut () || wrappedValueParam-> isVariadic ())
148
- continue ;
176
+ if (!argumentParam-> hasInterfaceType ())
177
+ continue ;
149
178
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 ;
155
181
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
+ }
163
195
}
164
196
165
- // Check the type
166
- initialValueInitializers.push_back (init);
197
+ viableInitializers.push_back (init);
167
198
}
168
199
169
200
// If we found some nonviable candidates but no viable ones, complain.
170
- if (initialValueInitializers .empty () && !nonviable.empty ()) {
201
+ if (viableInitializers .empty () && !nonviable.empty ()) {
171
202
for (const auto &candidate : nonviable) {
172
203
auto init = std::get<0 >(candidate);
173
204
auto reason = std::get<1 >(candidate);
@@ -187,110 +218,15 @@ static ConstructorDecl *findInitialValueInit(
187
218
188
219
case NonViableReason::ParameterTypeMismatch:
189
220
init->diagnose (diag::property_wrapper_wrong_initial_value_init,
190
- init->getFullName (), paramType, valueVarType);
221
+ init->getFullName (), paramType,
222
+ valueVar->getValueInterfaceType ());
191
223
valueVar->diagnose (diag::decl_declared_here, valueVar->getFullName ());
192
224
break ;
193
225
}
194
226
}
195
227
}
196
228
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 ();
294
230
}
295
231
296
232
// / Determine whether we have a suitable static subscript to which we
@@ -376,10 +312,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
376
312
377
313
PropertyWrapperTypeInfo result;
378
314
result.valueVar = valueVar;
379
- if (findInitialValueInit (ctx, nominal, valueVar, ctx.Id_wrappedValue ))
315
+ if (findSuitableWrapperInit (ctx, nominal, valueVar,
316
+ PropertyWrapperInitKind::WrappedValue))
380
317
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 )) {
383
320
result.wrappedValueInit = PropertyWrapperTypeInfo::HasInitialValueInit;
384
321
385
322
if (init->getLoc ().isValid ()) {
@@ -396,7 +333,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
396
333
}
397
334
}
398
335
399
- result.defaultInit = findDefaultInit (ctx, nominal);
336
+ if (findSuitableWrapperInit (ctx, nominal, /* valueVar=*/ nullptr ,
337
+ PropertyWrapperInitKind::Default)) {
338
+ result.defaultInit = PropertyWrapperTypeInfo::HasDefaultValueInit;
339
+ }
340
+
400
341
result.projectedValueVar =
401
342
findValueProperty (ctx, nominal, ctx.Id_projectedValue ,
402
343
/* allowMissing=*/ true );
0 commit comments