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,52 +89,63 @@ 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 hasExtraneousParam = false ;
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 (!argumentLabel.empty () && param->getArgumentName () == argumentLabel &&
135
+ !argumentParam) {
136
+ argumentParam = param;
116
137
continue ;
117
138
}
118
139
119
140
if (param->isDefaultArgument ())
120
141
continue ;
121
142
122
- // Forget we had a match.
123
- wrappedValueParam = nullptr ;
143
+ // Skip this init as the param doesn't meet the above criteria
144
+ hasExtraneousParam = true ;
124
145
break ;
125
146
}
126
147
127
- if (!wrappedValueParam )
148
+ if (hasExtraneousParam )
128
149
continue ;
129
150
130
151
// Failable initializers cannot be used.
@@ -141,33 +162,37 @@ static ConstructorDecl *findInitialValueInit(
141
162
continue ;
142
163
}
143
164
144
- if (!wrappedValueParam->hasInterfaceType ())
145
- continue ;
165
+ // Additional checks for initial-value and wrapped-value initializers
166
+ if (initKind != PropertyWrapperInitKind::Default) {
167
+ if (!argumentParam)
168
+ continue ;
146
169
147
- if (wrappedValueParam-> isInOut () || wrappedValueParam-> isVariadic ())
148
- continue ;
170
+ if (!argumentParam-> hasInterfaceType ())
171
+ continue ;
149
172
150
- auto paramType = wrappedValueParam->getInterfaceType ();
151
- if (wrappedValueParam->isAutoClosure ()) {
152
- if (auto *fnType = paramType->getAs <FunctionType>())
153
- paramType = fnType->getResult ();
154
- }
173
+ if (argumentParam->isInOut () || argumentParam->isVariadic ())
174
+ continue ;
155
175
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 ;
176
+ auto paramType = argumentParam->getInterfaceType ();
177
+ if (argumentParam->isAutoClosure ()) {
178
+ if (auto *fnType = paramType->getAs <FunctionType>())
179
+ paramType = fnType->getResult ();
180
+ }
181
+
182
+ // The parameter type must be the same as the type of `valueVar` or an
183
+ // autoclosure thereof.
184
+ if (!paramType->isEqual (valueVar->getValueInterfaceType ())) {
185
+ nonviable.push_back (std::make_tuple (
186
+ init, NonViableReason::ParameterTypeMismatch, paramType));
187
+ continue ;
188
+ }
163
189
}
164
190
165
- // Check the type
166
- initialValueInitializers.push_back (init);
191
+ viableInitializers.push_back (init);
167
192
}
168
193
169
194
// If we found some nonviable candidates but no viable ones, complain.
170
- if (initialValueInitializers .empty () && !nonviable.empty ()) {
195
+ if (viableInitializers .empty () && !nonviable.empty ()) {
171
196
for (const auto &candidate : nonviable) {
172
197
auto init = std::get<0 >(candidate);
173
198
auto reason = std::get<1 >(candidate);
@@ -187,69 +212,15 @@ static ConstructorDecl *findInitialValueInit(
187
212
188
213
case NonViableReason::ParameterTypeMismatch:
189
214
init->diagnose (diag::property_wrapper_wrong_initial_value_init,
190
- init->getFullName (), paramType, valueVarType);
215
+ init->getFullName (), paramType,
216
+ valueVar->getValueInterfaceType ());
191
217
valueVar->diagnose (diag::decl_declared_here, valueVar->getFullName ());
192
218
break ;
193
219
}
194
220
}
195
221
}
196
222
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
- DeclName initName (ctx, DeclBaseName::createConstructor (),
207
- ArrayRef<Identifier>());
208
- SmallVector<ValueDecl *, 2 > decls;
209
- nominal->lookupQualified (nominal, initName, NL_QualifiedDefault, decls);
210
- for (const auto &decl : decls) {
211
- auto init = dyn_cast<ConstructorDecl>(decl);
212
- if (!init || init->getDeclContext () != nominal)
213
- continue ;
214
-
215
- defaultValueInitializers.push_back (init);
216
- }
217
-
218
- switch (defaultValueInitializers.size ()) {
219
- case 0 :
220
- return nullptr ;
221
-
222
- case 1 :
223
- break ;
224
-
225
- default :
226
- // Diagnose ambiguous init() initializers.
227
- nominal->diagnose (diag::property_wrapper_ambiguous_default_value_init,
228
- nominal->getDeclaredType ());
229
- for (auto init : defaultValueInitializers) {
230
- init->diagnose (diag::kind_declname_declared_here,
231
- init->getDescriptiveKind (), init->getFullName ());
232
- }
233
- return nullptr ;
234
- }
235
-
236
- // 'init()' must be as accessible as the nominal type.
237
- auto init = defaultValueInitializers.front ();
238
- if (init->getFormalAccess () < nominal->getFormalAccess ()) {
239
- init->diagnose (diag::property_wrapper_type_requirement_not_accessible,
240
- init->getFormalAccess (), init->getDescriptiveKind (),
241
- init->getFullName (), nominal->getDeclaredType (),
242
- nominal->getFormalAccess ());
243
- return nullptr ;
244
- }
245
-
246
- // The initializer must not be failable.
247
- if (init->isFailable ()) {
248
- init->diagnose (diag::property_wrapper_failable_init, initName);
249
- return nullptr ;
250
- }
251
-
252
- return init;
223
+ return viableInitializers.empty () ? nullptr : viableInitializers.front ();
253
224
}
254
225
255
226
// / Determine whether we have a suitable static subscript to which we
@@ -335,10 +306,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
335
306
336
307
PropertyWrapperTypeInfo result;
337
308
result.valueVar = valueVar;
338
- if (findInitialValueInit (ctx, nominal, valueVar, ctx.Id_wrappedValue ))
309
+ if (findSuitableWrapperInit (ctx, nominal, valueVar,
310
+ PropertyWrapperInitKind::WrappedValue))
339
311
result.wrappedValueInit = PropertyWrapperTypeInfo::HasWrappedValueInit;
340
- else if (auto init = findInitialValueInit (
341
- ctx, nominal, valueVar, ctx. Id_initialValue )) {
312
+ else if (auto init = findSuitableWrapperInit (
313
+ ctx, nominal, valueVar, PropertyWrapperInitKind::InitialValue )) {
342
314
result.wrappedValueInit = PropertyWrapperTypeInfo::HasInitialValueInit;
343
315
344
316
if (init->getLoc ().isValid ()) {
@@ -355,7 +327,11 @@ PropertyWrapperTypeInfoRequest::evaluate(
355
327
}
356
328
}
357
329
358
- result.defaultInit = findDefaultInit (ctx, nominal);
330
+ if (findSuitableWrapperInit (ctx, nominal, /* valueVar=*/ nullptr ,
331
+ PropertyWrapperInitKind::Default)) {
332
+ result.defaultInit = PropertyWrapperTypeInfo::HasDefaultValueInit;
333
+ }
334
+
359
335
result.projectedValueVar =
360
336
findValueProperty (ctx, nominal, ctx.Id_projectedValue ,
361
337
/* allowMissing=*/ true );
0 commit comments