@@ -81,88 +81,121 @@ static VarDecl *findValueProperty(ASTContext &ctx, NominalTypeDecl *nominal,
81
81
82
82
// / Determine whether we have a suitable wrapped-value initializer within
83
83
// / a property wrapper type.
84
- static ConstructorDecl *findInitialValueInit (ASTContext &ctx,
85
- NominalTypeDecl *nominal,
86
- VarDecl *valueVar,
87
- Identifier argumentLabel) {
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
+ enum class NonViableReason {
93
+ Failable,
94
+ ParameterTypeMismatch,
95
+ Inaccessible,
96
+ };
97
+ SmallVector<std::tuple<ConstructorDecl*, NonViableReason, Type>, 2 > nonviable;
88
98
SmallVector<ConstructorDecl *, 2 > initialValueInitializers;
89
- DeclName initName (ctx, DeclBaseName::createConstructor (), {argumentLabel});
99
+
90
100
SmallVector<ValueDecl *, 2 > decls;
91
- nominal->lookupQualified (nominal, initName, NL_QualifiedDefault, decls);
101
+ nominal->lookupQualified (nominal, DeclBaseName::createConstructor (),
102
+ NL_QualifiedDefault, decls);
92
103
for (const auto &decl : decls) {
93
104
auto init = dyn_cast<ConstructorDecl>(decl);
94
- if (!init || init->getDeclContext () != nominal)
105
+ if (!init || init->getDeclContext () != nominal || init-> getGenericParams () )
95
106
continue ;
96
107
97
- initialValueInitializers.push_back (init);
98
- }
99
-
100
- switch (initialValueInitializers.size ()) {
101
- case 0 :
102
- return nullptr ;
108
+ // Check whether every parameter meets one of the following criteria:
109
+ // (1) The parameter has a default argument, or
110
+ // (2) The parameter has the given argument label.
111
+ ParamDecl *wrappedValueParam = nullptr ;
112
+ for (auto param : *init->getParameters ()) {
113
+ // Recognize the first parameter with the requested argument label.
114
+ if (param->getArgumentName () == argumentLabel && !wrappedValueParam) {
115
+ wrappedValueParam = param;
116
+ continue ;
117
+ }
103
118
104
- case 1 :
105
- break ;
119
+ if (param-> getDefaultArgumentKind () != DefaultArgumentKind::None)
120
+ continue ;
106
121
107
- default :
108
- // Diagnose ambiguous initializers.
109
- nominal->diagnose (diag::property_wrapper_ambiguous_initial_value_init,
110
- nominal->getDeclaredType ());
111
- for (auto init : initialValueInitializers) {
112
- init->diagnose (diag::kind_declname_declared_here,
113
- init->getDescriptiveKind (), init->getFullName ());
122
+ // Forget we had a match.
123
+ wrappedValueParam = nullptr ;
124
+ break ;
114
125
}
115
- return nullptr ;
116
- }
117
126
118
- // The initializer must be as accessible as the nominal type.
119
- auto init = initialValueInitializers.front ();
120
- if (init->getFormalAccess () < nominal->getFormalAccess ()) {
121
- init->diagnose (diag::property_wrapper_type_requirement_not_accessible,
122
- init->getFormalAccess (), init->getDescriptiveKind (),
123
- init->getFullName (), nominal->getDeclaredType (),
124
- nominal->getFormalAccess ());
125
- return nullptr ;
126
- }
127
+ if (!wrappedValueParam)
128
+ continue ;
127
129
128
- // Retrieve the type of the 'value' property.
129
- Type valueVarType = valueVar->getValueInterfaceType ();
130
+ // Failable initializers cannot be used.
131
+ if (init->isFailable ()) {
132
+ nonviable.push_back (
133
+ std::make_tuple (init, NonViableReason::Failable, Type ()));
134
+ continue ;
135
+ }
130
136
131
- // Retrieve the parameter type of the initializer.
132
- Type paramType;
133
- if (auto *curriedInitType =
134
- init->getInterfaceType ()->getAs <AnyFunctionType>()) {
135
- if (auto *initType =
136
- curriedInitType->getResult ()->getAs <AnyFunctionType>()) {
137
- if (initType->getParams ().size () == 1 ) {
138
- const auto ¶m = initType->getParams ()[0 ];
139
- if (!param.isInOut () && !param.isVariadic ()) {
140
- paramType = param.getPlainType ();
141
- if (param.isAutoClosure ()) {
142
- if (auto *fnType = paramType->getAs <FunctionType>())
143
- paramType = fnType->getResult ();
144
- }
145
- }
137
+ // Check accessibility.
138
+ if (init->getFormalAccess () < nominal->getFormalAccess ()) {
139
+ nonviable.push_back (
140
+ std::make_tuple (init, NonViableReason::Inaccessible, Type ()));
141
+ continue ;
142
+ }
143
+
144
+ Type paramType;
145
+ if (!wrappedValueParam->isInOut () && !wrappedValueParam->isVariadic ()) {
146
+ paramType = wrappedValueParam->getInterfaceType ();
147
+ if (wrappedValueParam->isAutoClosure ()) {
148
+ if (auto *fnType = paramType->getAs <FunctionType>())
149
+ paramType = fnType->getResult ();
146
150
}
147
151
}
148
- }
152
+
153
+ if (!paramType)
154
+ continue ;
149
155
150
- // The parameter type must be the same as the type of `valueVar` or an
151
- // autoclosure thereof.
152
- if (!paramType->isEqual (valueVarType)) {
153
- init->diagnose (diag::property_wrapper_wrong_initial_value_init, initName,
154
- paramType, valueVarType);
155
- valueVar->diagnose (diag::decl_declared_here, valueVar->getFullName ());
156
- return nullptr ;
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 ;
163
+ }
164
+
165
+ // Check the type
166
+ initialValueInitializers.push_back (init);
157
167
}
158
168
159
- // The initializer must not be failable.
160
- if (init->isFailable ()) {
161
- init->diagnose (diag::property_wrapper_failable_init, initName);
162
- return nullptr ;
169
+ // If we found some nonviable candidates but no viable ones, complain.
170
+ if (initialValueInitializers.empty () && !nonviable.empty ()) {
171
+ for (const auto &candidate : nonviable) {
172
+ auto init = std::get<0 >(candidate);
173
+ auto reason = std::get<1 >(candidate);
174
+ auto paramType = std::get<2 >(candidate);
175
+ switch (reason) {
176
+ case NonViableReason::Failable:
177
+ init->diagnose (diag::property_wrapper_failable_init,
178
+ init->getFullName ());
179
+ break ;
180
+
181
+ case NonViableReason::Inaccessible:
182
+ init->diagnose (diag::property_wrapper_type_requirement_not_accessible,
183
+ init->getFormalAccess (), init->getDescriptiveKind (),
184
+ init->getFullName (), nominal->getDeclaredType (),
185
+ nominal->getFormalAccess ());
186
+ break ;
187
+
188
+ case NonViableReason::ParameterTypeMismatch:
189
+ init->diagnose (diag::property_wrapper_wrong_initial_value_init,
190
+ init->getFullName (), paramType, valueVarType);
191
+ valueVar->diagnose (diag::decl_declared_here, valueVar->getFullName ());
192
+ break ;
193
+ }
194
+ }
163
195
}
164
196
165
- return init;
197
+ return initialValueInitializers.empty () ? nullptr
198
+ : initialValueInitializers.front ();
166
199
}
167
200
168
201
// / Determine whether we have a suitable init() within a property
@@ -302,22 +335,23 @@ PropertyWrapperTypeInfoRequest::evaluate(
302
335
303
336
PropertyWrapperTypeInfo result;
304
337
result.valueVar = valueVar;
305
- result.wrappedValueInit =
306
- findInitialValueInit (ctx, nominal, valueVar, ctx.Id_wrappedValue );
307
-
308
- if (!result.wrappedValueInit ) {
309
- // Look for the older name init(initialValue:).
310
- result.wrappedValueInit =
311
- findInitialValueInit (ctx, nominal, valueVar, ctx.Id_initialValue );
312
- if (result.wrappedValueInit &&
313
- result.wrappedValueInit ->getLoc ().isValid ()) {
314
- auto diag = result.wrappedValueInit ->diagnose (
315
- diag::property_wrapper_init_initialValue);
316
- auto param = result.wrappedValueInit ->getParameters ()->get (0 );
317
- if (param->getArgumentNameLoc ().isValid ())
318
- diag.fixItReplace (param->getArgumentNameLoc (), " wrappedValue" );
319
- else
320
- diag.fixItInsert (param->getLoc (), " wrappedValue " );
338
+ if (findInitialValueInit (ctx, nominal, valueVar, ctx.Id_wrappedValue ))
339
+ result.wrappedValueInit = PropertyWrapperTypeInfo::HasWrappedValueInit;
340
+ else if (auto init = findInitialValueInit (
341
+ ctx, nominal, valueVar, ctx.Id_initialValue )) {
342
+ result.wrappedValueInit = PropertyWrapperTypeInfo::HasInitialValueInit;
343
+
344
+ if (init->getLoc ().isValid ()) {
345
+ auto diag = init->diagnose (diag::property_wrapper_init_initialValue);
346
+ for (auto param : *init->getParameters ()) {
347
+ if (param->getArgumentName () == ctx.Id_initialValue ) {
348
+ if (param->getArgumentNameLoc ().isValid ())
349
+ diag.fixItReplace (param->getArgumentNameLoc (), " wrappedValue" );
350
+ else
351
+ diag.fixItInsert (param->getLoc (), " wrappedValue " );
352
+ break ;
353
+ }
354
+ }
321
355
}
322
356
}
323
357
@@ -647,12 +681,18 @@ Expr *swift::buildPropertyWrapperInitialValueCall(
647
681
// call `init(wrappedValue:)` directly.
648
682
auto attr = wrapperAttrs[i];
649
683
if (!attr->getArg () || ignoreAttributeArgs) {
650
- Identifier argName = ctx.Id_wrappedValue ;
651
- if (auto init
652
- = var->getAttachedPropertyWrapperTypeInfo (i).wrappedValueInit ) {
653
- argName = init->getFullName ().getArgumentNames ()[0 ];
684
+ Identifier argName;
685
+ switch (var->getAttachedPropertyWrapperTypeInfo (i).wrappedValueInit ) {
686
+ case PropertyWrapperTypeInfo::HasInitialValueInit:
687
+ argName = ctx.Id_initialValue ;
688
+ break ;
689
+
690
+ case PropertyWrapperTypeInfo::HasWrappedValueInit:
691
+ case PropertyWrapperTypeInfo::NoWrappedValueInit:
692
+ argName = ctx.Id_wrappedValue ;
693
+ break ;
654
694
}
655
-
695
+
656
696
auto endLoc = initializer->getEndLoc ();
657
697
if (endLoc.isInvalid () && startLoc.isValid ())
658
698
endLoc = wrapperAttrs[i]->getTypeLoc ().getSourceRange ().End ;
0 commit comments