@@ -109,6 +109,76 @@ Solution::computeSubstitutions(GenericSignature sig,
109
109
lookupConformanceFn);
110
110
}
111
111
112
+ // On Windows and 32-bit platforms we need to force "Int" to actually be
113
+ // re-imported as "Int." This is needed because otherwise, we cannot round-trip
114
+ // "Int" and "UInt". For example, on Windows, "Int" will be imported into C++ as
115
+ // "long long" and then back into Swift as "Int64" not "Int."
116
+ static ValueDecl *rewriteIntegerTypes (SubstitutionMap subst, ValueDecl *oldDecl,
117
+ AbstractFunctionDecl *newDecl) {
118
+ auto originalFnSubst = cast<AbstractFunctionDecl>(oldDecl)
119
+ ->getInterfaceType ()
120
+ ->getAs <GenericFunctionType>()
121
+ ->substGenericArgs (subst);
122
+ // The constructor type is a function type as follows:
123
+ // (CType.Type) -> (Generic) -> CType
124
+ // And a method's function type is as follows:
125
+ // (inout CType) -> (Generic) -> Void
126
+ // In either case, we only want the result of that function type because that
127
+ // is the function type with the generic params that need to be substituted:
128
+ // (Generic) -> CType
129
+ if (isa<ConstructorDecl>(oldDecl) || oldDecl->isInstanceMember () ||
130
+ oldDecl->isStatic ())
131
+ originalFnSubst = cast<FunctionType>(originalFnSubst->getResult ().getPointer ());
132
+
133
+ SmallVector<ParamDecl *, 4 > fixedParameters;
134
+ unsigned parameterIndex = 0 ;
135
+ for (auto *newFnParam : *newDecl->getParameters ()) {
136
+ // If the user substituted this param with an (U)Int, use (U)Int.
137
+ auto substParamType =
138
+ originalFnSubst->getParams ()[parameterIndex].getParameterType ();
139
+ if (substParamType->isEqual (newDecl->getASTContext ().getIntType ()) ||
140
+ substParamType->isEqual (newDecl->getASTContext ().getUIntType ())) {
141
+ auto intParam =
142
+ ParamDecl::cloneWithoutType (newDecl->getASTContext (), newFnParam);
143
+ intParam->setInterfaceType (substParamType);
144
+ fixedParameters.push_back (intParam);
145
+ } else {
146
+ fixedParameters.push_back (newFnParam);
147
+ }
148
+ parameterIndex++;
149
+ }
150
+
151
+ auto fixedParams =
152
+ ParameterList::create (newDecl->getASTContext (), fixedParameters);
153
+ newDecl->setParameters (fixedParams);
154
+
155
+ // Now fix the result type:
156
+ if (originalFnSubst->getResult ()->isEqual (
157
+ newDecl->getASTContext ().getIntType ()) ||
158
+ originalFnSubst->getResult ()->isEqual (
159
+ newDecl->getASTContext ().getUIntType ())) {
160
+ // Constructors don't have a result.
161
+ if (auto func = dyn_cast<FuncDecl>(newDecl)) {
162
+ // We have to rebuild the whole function.
163
+ auto newFnDecl = FuncDecl::createImported (
164
+ func->getASTContext (), func->getNameLoc (),
165
+ func->getName (), func->getNameLoc (),
166
+ func->hasAsync (), func->hasThrows (),
167
+ fixedParams, originalFnSubst->getResult (),
168
+ /* genericParams=*/ nullptr , func->getDeclContext (), newDecl->getClangDecl ());
169
+ if (func->isStatic ()) newFnDecl->setStatic ();
170
+ if (func->isImportAsStaticMember ()) newFnDecl->setImportAsStaticMember ();
171
+ if (func->getImportAsMemberStatus ().isInstance ()) {
172
+ newFnDecl->setSelfAccessKind (func->getSelfAccessKind ());
173
+ newFnDecl->setSelfIndex (func->getSelfIndex ());
174
+ }
175
+ return newFnDecl;
176
+ }
177
+ }
178
+
179
+ return newDecl;
180
+ }
181
+
112
182
// Derive a concrete function type for fdecl by substituting the generic args
113
183
// and use that to derive the corresponding function type and parameter list.
114
184
static std::pair<FunctionType *, ParameterList *>
@@ -190,20 +260,32 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
190
260
return {body, /* isTypeChecked=*/ true };
191
261
}
192
262
193
- ConcreteDeclRef
194
- Solution::resolveConcreteDeclRef (ValueDecl *decl,
195
- ConstraintLocator *locator) const {
196
- if (!decl)
197
- return ConcreteDeclRef ();
198
-
199
- // Get the generic signatue of the decl and compute the substitutions.
200
- auto sig = decl->getInnermostDeclContext ()->getGenericSignatureOfContext ();
201
- auto subst = computeSubstitutions (sig, locator);
263
+ static ValueDecl *generateThunkForExtraMetatypes (SubstitutionMap subst,
264
+ FuncDecl *oldDecl,
265
+ FuncDecl *newDecl) {
266
+ // We added additional metatype parameters to aid template
267
+ // specialization, which are no longer now that we've specialized
268
+ // this function. Create a thunk that only forwards the original
269
+ // parameters along to the clang function.
270
+ auto thunkTypeAndParamList = substituteFunctionTypeAndParamList (oldDecl->getASTContext (),
271
+ oldDecl, subst);
272
+ auto thunk = FuncDecl::createImplicit (
273
+ oldDecl->getASTContext (), oldDecl->getStaticSpelling (), oldDecl->getName (),
274
+ oldDecl->getNameLoc (), oldDecl->hasAsync (), oldDecl->hasThrows (),
275
+ /* genericParams=*/ nullptr , thunkTypeAndParamList.second ,
276
+ thunkTypeAndParamList.first ->getResult (), oldDecl->getDeclContext ());
277
+ thunk->copyFormalAccessFrom (oldDecl);
278
+ thunk->setBodySynthesizer (synthesizeForwardingThunkBody, newDecl);
279
+ thunk->setSelfAccessKind (oldDecl->getSelfAccessKind ());
280
+
281
+ return thunk;
282
+ }
202
283
203
- // Lazily instantiate function definitions for class template specializations.
204
- // Members of a class template specialization will be instantiated here (not
205
- // when imported). If this method has already be instantiated, then this is a
206
- // no-op.
284
+ // Lazily instantiate function definitions for class template specializations.
285
+ // Members of a class template specialization will be instantiated here (not
286
+ // when imported). If this method has already be instantiated, then this is a
287
+ // no-op.
288
+ static void maybeInstantiateCXXMethodDefinition (ValueDecl *decl) {
207
289
if (const auto *constMethod =
208
290
dyn_cast_or_null<clang::CXXMethodDecl>(decl->getClangDecl ())) {
209
291
auto method = const_cast <clang::CXXMethodDecl *>(constMethod);
@@ -214,114 +296,62 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
214
296
->getClangSema ()
215
297
.InstantiateFunctionDefinition (method->getLocation (), method);
216
298
}
299
+ }
217
300
218
- // If this is a C++ function template, get it's specialization for the given
219
- // substitution map and update the decl accordingly.
220
- if (isa_and_nonnull<clang::FunctionTemplateDecl>(decl->getClangDecl ())) {
221
- auto *newFn =
222
- decl->getASTContext ()
223
- .getClangModuleLoader ()
224
- ->instantiateCXXFunctionTemplate (
225
- decl->getASTContext (),
226
- const_cast <clang::FunctionTemplateDecl *>(
227
- cast<clang::FunctionTemplateDecl>(decl->getClangDecl ())),
228
- subst);
229
- // We failed to specialize this function template. The compiler is going to
230
- // exit soon. Return something valid in the meantime.
231
- if (!newFn)
232
- return ConcreteDeclRef (decl);
233
-
234
- auto newDecl = cast_or_null<ValueDecl>(
235
- decl->getASTContext ().getClangModuleLoader ()->importDeclDirectly (
236
- newFn));
237
-
238
- if (auto fn = dyn_cast<AbstractFunctionDecl>(newDecl)) {
239
- if (!subst.empty ()) {
240
- auto originalFnSubst = cast<AbstractFunctionDecl>(decl)
241
- ->getInterfaceType ()
242
- ->getAs <GenericFunctionType>()
243
- ->substGenericArgs (subst);
244
- // The constructor type is a function type as follows:
245
- // (CType.Type) -> (Generic) -> CType
246
- // And a method's function type is as follows:
247
- // (inout CType) -> (Generic) -> Void
248
- // In either case, we only want the result of that function type because that
249
- // is the function type with the generic params that need to be substituted:
250
- // (Generic) -> CType
251
- if (isa<ConstructorDecl>(decl) || decl->isInstanceMember () ||
252
- decl->isStatic ())
253
- originalFnSubst = cast<FunctionType>(originalFnSubst->getResult ().getPointer ());
254
-
255
- SmallVector<ParamDecl *, 4 > fixedParameters;
256
- unsigned parameterIndex = 0 ;
257
- for (auto *newFnParam : *fn->getParameters ()) {
258
- // If the user substituted this param with an (U)Int, use (U)Int.
259
- auto substParamType =
260
- originalFnSubst->getParams ()[parameterIndex].getParameterType ();
261
- if (substParamType->isEqual (fn->getASTContext ().getIntType ()) ||
262
- substParamType->isEqual (fn->getASTContext ().getUIntType ())) {
263
- auto intParam =
264
- ParamDecl::cloneWithoutType (fn->getASTContext (), newFnParam);
265
- intParam->setInterfaceType (substParamType);
266
- fixedParameters.push_back (intParam);
267
- } else {
268
- fixedParameters.push_back (newFnParam);
269
- }
270
- parameterIndex++;
271
- }
301
+ static ConcreteDeclRef getCXXFunctionTemplateSpecialization (SubstitutionMap subst,
302
+ ValueDecl *decl) {
303
+ assert (isa<clang::FunctionTemplateDecl>(decl->getClangDecl ()) &&
304
+ " This API should only be used with function templates." );
272
305
273
- auto fixedParams =
274
- ParameterList::create (fn->getASTContext (), fixedParameters);
275
- fn->setParameters (fixedParams);
276
-
277
- // Now fix the result type:
278
- if (originalFnSubst->getResult ()->isEqual (
279
- fn->getASTContext ().getIntType ()) ||
280
- originalFnSubst->getResult ()->isEqual (
281
- fn->getASTContext ().getUIntType ())) {
282
- // Constructors don't have a result.
283
- if (auto func = dyn_cast<FuncDecl>(fn)) {
284
- // We have to rebuild the whole function.
285
- auto newFnDecl = FuncDecl::createImported (
286
- func->getASTContext (), func->getNameLoc (),
287
- func->getName (), func->getNameLoc (),
288
- func->hasAsync (), func->hasThrows (),
289
- fixedParams, originalFnSubst->getResult (),
290
- /* genericParams=*/ nullptr , func->getDeclContext (), newFn);
291
- if (func->isStatic ()) newFnDecl->setStatic ();
292
- if (func->isImportAsStaticMember ()) newFnDecl->setImportAsStaticMember ();
293
- if (func->getImportAsMemberStatus ().isInstance ()) {
294
- newFnDecl->setSelfAccessKind (func->getSelfAccessKind ());
295
- newFnDecl->setSelfIndex (func->getSelfIndex ());
296
- }
297
- newDecl = newFnDecl;
298
- }
299
- }
300
- }
306
+ auto *newFn =
307
+ decl->getASTContext ()
308
+ .getClangModuleLoader ()
309
+ ->instantiateCXXFunctionTemplate (
310
+ decl->getASTContext (),
311
+ const_cast <clang::FunctionTemplateDecl *>(
312
+ cast<clang::FunctionTemplateDecl>(decl->getClangDecl ())),
313
+ subst);
314
+ // We failed to specialize this function template. The compiler is going to
315
+ // exit soon. Return something valid in the meantime.
316
+ if (!newFn)
317
+ return ConcreteDeclRef (decl);
318
+
319
+ auto newDecl = cast_or_null<ValueDecl>(
320
+ decl->getASTContext ().getClangModuleLoader ()->importDeclDirectly (
321
+ newFn));
322
+
323
+ if (auto fn = dyn_cast<AbstractFunctionDecl>(newDecl)) {
324
+ if (!subst.empty ()) {
325
+ newDecl = rewriteIntegerTypes (subst, decl, fn);
301
326
}
327
+ }
302
328
303
- if (auto fn = dyn_cast<FuncDecl>(decl)) {
304
- if (newFn->getNumParams () != fn->getParameters ()->size ()) {
305
- // We added additional metatype parameters to aid template
306
- // specialization, which are no longer now that we've specialized
307
- // this function. Create a thunk that only forwards the original
308
- // parameters along to the clang function.
309
- auto thunkTypeAndParamList = substituteFunctionTypeAndParamList (decl->getASTContext (),
310
- fn, subst);
311
- auto thunk = FuncDecl::createImplicit (
312
- fn->getASTContext (), fn->getStaticSpelling (), fn->getName (),
313
- fn->getNameLoc (), fn->hasAsync (), fn->hasThrows (),
314
- /* genericParams=*/ nullptr , thunkTypeAndParamList.second ,
315
- thunkTypeAndParamList.first ->getResult (), fn->getDeclContext ());
316
- thunk->copyFormalAccessFrom (fn);
317
- thunk->setBodySynthesizer (synthesizeForwardingThunkBody, cast<FuncDecl>(newDecl));
318
- thunk->setSelfAccessKind (fn->getSelfAccessKind ());
319
-
320
- newDecl = thunk;
321
- }
329
+ if (auto fn = dyn_cast<FuncDecl>(decl)) {
330
+ if (newFn->getNumParams () != fn->getParameters ()->size ()) {
331
+ newDecl = generateThunkForExtraMetatypes (subst, fn,
332
+ cast<FuncDecl>(newDecl));
322
333
}
334
+ }
335
+
336
+ return ConcreteDeclRef (newDecl);
337
+ }
323
338
324
- return ConcreteDeclRef (newDecl);
339
+ ConcreteDeclRef
340
+ Solution::resolveConcreteDeclRef (ValueDecl *decl,
341
+ ConstraintLocator *locator) const {
342
+ if (!decl)
343
+ return ConcreteDeclRef ();
344
+
345
+ // Get the generic signatue of the decl and compute the substitutions.
346
+ auto sig = decl->getInnermostDeclContext ()->getGenericSignatureOfContext ();
347
+ auto subst = computeSubstitutions (sig, locator);
348
+
349
+ maybeInstantiateCXXMethodDefinition (decl);
350
+
351
+ // If this is a C++ function template, get it's specialization for the given
352
+ // substitution map and update the decl accordingly.
353
+ if (isa_and_nonnull<clang::FunctionTemplateDecl>(decl->getClangDecl ())) {
354
+ return getCXXFunctionTemplateSpecialization (subst, decl);
325
355
}
326
356
327
357
return ConcreteDeclRef (decl, subst);
0 commit comments