@@ -112,7 +112,7 @@ Solution::computeSubstitutions(GenericSignature sig,
112
112
// On Windows and 32-bit platforms we need to force "Int" to actually be
113
113
// re-imported as "Int." This is needed because otherwise, we cannot round-trip
114
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."
115
+ // "long long" and then back into Swift as "Int64" not "Int."
116
116
static ValueDecl *rewriteIntegerTypes (SubstitutionMap subst, ValueDecl *oldDecl,
117
117
AbstractFunctionDecl *newDecl) {
118
118
auto originalFnSubst = cast<AbstractFunctionDecl>(oldDecl)
@@ -172,51 +172,116 @@ static ValueDecl *rewriteIntegerTypes(SubstitutionMap subst, ValueDecl *oldDecl,
172
172
newFnDecl->setSelfAccessKind (func->getSelfAccessKind ());
173
173
newFnDecl->setSelfIndex (func->getSelfIndex ());
174
174
}
175
+
175
176
return newFnDecl;
176
177
}
177
178
}
178
179
179
180
return newDecl;
180
181
}
181
182
182
- // Derive a concrete function type for fdecl by substituting the generic args
183
- // and use that to derive the corresponding function type and parameter list.
184
- static std::pair<FunctionType *, ParameterList *>
185
- substituteFunctionTypeAndParamList (ASTContext &ctx, AbstractFunctionDecl *fdecl,
186
- SubstitutionMap subst) {
187
- FunctionType *newFnType = nullptr ;
188
- // Create a new ParameterList with the substituted type.
189
- if (auto oldFnType = dyn_cast<GenericFunctionType>(
190
- fdecl->getInterfaceType ().getPointer ())) {
191
- newFnType = oldFnType->substGenericArgs (subst);
192
- } else {
193
- newFnType = cast<FunctionType>(fdecl->getInterfaceType ().getPointer ());
183
+ // Synthesize a thunk body for the function created in
184
+ // "addThunkForDependentTypes". This will just cast all params and forward them
185
+ // along to the specialized function. It will also cast the result before
186
+ // returning it.
187
+ static std::pair<BraceStmt *, bool >
188
+ synthesizeDependentTypeThunkParamForwarding (AbstractFunctionDecl *afd, void *context) {
189
+ ASTContext &ctx = afd->getASTContext ();
190
+
191
+ auto thunkDecl = cast<FuncDecl>(afd);
192
+ auto specializedFuncDecl = static_cast <FuncDecl *>(context);
193
+
194
+ SmallVector<Argument, 8 > forwardingParams;
195
+ unsigned paramIndex = 0 ;
196
+ for (auto param : *thunkDecl->getParameters ()) {
197
+ if (isa<MetatypeType>(param->getType ().getPointer ())) {
198
+ paramIndex++;
199
+ continue ;
200
+ }
201
+
202
+ auto paramRefExpr = new (ctx) DeclRefExpr (param, DeclNameLoc (),
203
+ /* Implicit=*/ true );
204
+ paramRefExpr->setType (param->getType ());
205
+
206
+ auto specParamTy = specializedFuncDecl->getParameters ()->get (paramIndex)->getType ();
207
+ auto cast = ForcedCheckedCastExpr::createImplicit (
208
+ ctx, paramRefExpr, specParamTy);
209
+
210
+ forwardingParams.push_back (Argument (SourceLoc (), Identifier (), cast));
211
+ paramIndex++;
194
212
}
195
- // The constructor type is a function type as follows:
196
- // (CType.Type) -> (Generic) -> CType
197
- // And a method's function type is as follows:
198
- // (inout CType) -> (Generic) -> Void
199
- // In either case, we only want the result of that function type because that
200
- // is the function type with the generic params that need to be substituted:
201
- // (Generic) -> CType
202
- if (isa<ConstructorDecl>(fdecl) || fdecl->isInstanceMember () ||
203
- fdecl->isStatic ())
204
- newFnType = cast<FunctionType>(newFnType->getResult ().getPointer ());
205
- SmallVector<ParamDecl *, 4 > newParams;
206
- unsigned i = 0 ;
207
213
208
- for (auto paramTy : newFnType->getParams ()) {
209
- auto *oldParamDecl = fdecl->getParameters ()->get (i);
210
- auto *newParamDecl =
211
- ParamDecl::cloneWithoutType (fdecl->getASTContext (), oldParamDecl);
212
- newParamDecl->setInterfaceType (paramTy.getParameterType ());
213
- newParams.push_back (newParamDecl);
214
- (void )++i;
214
+ auto *specializedFuncDeclRef = new (ctx) DeclRefExpr (ConcreteDeclRef (specializedFuncDecl),
215
+ DeclNameLoc (), true );
216
+ specializedFuncDeclRef->setType (specializedFuncDecl->getInterfaceType ());
217
+
218
+ auto argList = ArgumentList::createImplicit (ctx, forwardingParams);
219
+ auto *specializedFuncCallExpr = CallExpr::createImplicit (ctx, specializedFuncDeclRef, argList);
220
+ specializedFuncCallExpr->setType (specializedFuncDecl->getResultInterfaceType ());
221
+ specializedFuncCallExpr->setThrows (false );
222
+
223
+ auto cast = ForcedCheckedCastExpr::createImplicit (
224
+ ctx, specializedFuncCallExpr, thunkDecl->getResultInterfaceType ());
225
+
226
+ auto returnStmt = new (ctx) ReturnStmt (SourceLoc (), cast, /* implicit=*/ true );
227
+ auto body = BraceStmt::create (ctx, SourceLoc (), {returnStmt}, SourceLoc (),
228
+ /* implicit=*/ true );
229
+ return {body, /* isTypeChecked=*/ true };
230
+ }
231
+
232
+ // Create a thunk to map functions with dependent types to their specialized
233
+ // version. For example, create a thunk with type (Any) -> Any to wrap a
234
+ // specialized function template with type (Dependent<T>) -> Dependent<T>.
235
+ static ValueDecl *addThunkForDependentTypes (FuncDecl *oldDecl,
236
+ FuncDecl *newDecl) {
237
+ bool updatedAnyParams = false ;
238
+
239
+ SmallVector<ParamDecl *, 4 > fixedParameters;
240
+ unsigned parameterIndex = 0 ;
241
+ for (auto *newFnParam : *newDecl->getParameters ()) {
242
+ // If the un-specialized function had a parameter with type "Any" preserve
243
+ // that parameter. Otherwise, use the new function parameter.
244
+ auto oldParamType = oldDecl->getParameters ()->get (parameterIndex)->getType ();
245
+ if (oldParamType->isEqual (newDecl->getASTContext ().TheAnyType )) {
246
+ updatedAnyParams = true ;
247
+ auto newParam =
248
+ ParamDecl::cloneWithoutType (newDecl->getASTContext (), newFnParam);
249
+ newParam->setInterfaceType (oldParamType);
250
+ fixedParameters.push_back (newParam);
251
+ } else {
252
+ fixedParameters.push_back (newFnParam);
253
+ }
254
+ parameterIndex++;
215
255
}
216
- auto *newParamList =
217
- ParameterList::create (ctx, SourceLoc (), newParams, SourceLoc ());
218
256
219
- return {newFnType, newParamList};
257
+ // If we don't need this thunk, bail out.
258
+ if (!updatedAnyParams &&
259
+ !oldDecl->getResultInterfaceType ()->isEqual (
260
+ oldDecl->getASTContext ().TheAnyType ))
261
+ return newDecl;
262
+
263
+ auto fixedParams =
264
+ ParameterList::create (newDecl->getASTContext (), fixedParameters);
265
+
266
+ Type fixedResultType;
267
+ if (oldDecl->getResultInterfaceType ()->isEqual (
268
+ oldDecl->getASTContext ().TheAnyType ))
269
+ fixedResultType = oldDecl->getASTContext ().TheAnyType ;
270
+ else
271
+ fixedResultType = newDecl->getResultInterfaceType ();
272
+
273
+ // We have to rebuild the whole function.
274
+ auto newFnDecl = FuncDecl::createImplicit (
275
+ newDecl->getASTContext (), newDecl->getStaticSpelling (),
276
+ newDecl->getName (), newDecl->getNameLoc (), newDecl->hasAsync (),
277
+ newDecl->hasThrows (), /* genericParams=*/ nullptr , fixedParams,
278
+ fixedResultType, newDecl->getDeclContext ());
279
+ newFnDecl->copyFormalAccessFrom (newDecl);
280
+ newFnDecl->setBodySynthesizer (synthesizeDependentTypeThunkParamForwarding, newDecl);
281
+ newFnDecl->setSelfAccessKind (newDecl->getSelfAccessKind ());
282
+ newFnDecl->getAttrs ().add (
283
+ new (newDecl->getASTContext ()) TransparentAttr (/* IsImplicit=*/ true ));
284
+ return newFnDecl;
220
285
}
221
286
222
287
// Synthesizes the body of a thunk that takes extra metatype arguments and
@@ -267,16 +332,55 @@ static ValueDecl *generateThunkForExtraMetatypes(SubstitutionMap subst,
267
332
// specialization, which are no longer now that we've specialized
268
333
// this function. Create a thunk that only forwards the original
269
334
// parameters along to the clang function.
270
- auto thunkTypeAndParamList = substituteFunctionTypeAndParamList (oldDecl->getASTContext (),
271
- oldDecl, subst);
335
+ SmallVector<ParamDecl *, 4 > newParams;
336
+
337
+ for (auto param : *newDecl->getParameters ()) {
338
+ auto *newParamDecl = ParamDecl::clone (newDecl->getASTContext (), param);
339
+ newParams.push_back (newParamDecl);
340
+ }
341
+
342
+ auto originalFnSubst = cast<AbstractFunctionDecl>(oldDecl)
343
+ ->getInterfaceType ()
344
+ ->getAs <GenericFunctionType>()
345
+ ->substGenericArgs (subst);
346
+ // The constructor type is a function type as follows:
347
+ // (CType.Type) -> (Generic) -> CType
348
+ // And a method's function type is as follows:
349
+ // (inout CType) -> (Generic) -> Void
350
+ // In either case, we only want the result of that function type because that
351
+ // is the function type with the generic params that need to be substituted:
352
+ // (Generic) -> CType
353
+ if (isa<ConstructorDecl>(oldDecl) || oldDecl->isInstanceMember () ||
354
+ oldDecl->isStatic ())
355
+ originalFnSubst = cast<FunctionType>(originalFnSubst->getResult ().getPointer ());
356
+
357
+ for (auto paramTy : originalFnSubst->getParams ()) {
358
+ if (!paramTy.getPlainType ()->is <MetatypeType>())
359
+ continue ;
360
+
361
+ auto dc = newDecl->getDeclContext ();
362
+ auto paramVarDecl =
363
+ new (newDecl->getASTContext ()) ParamDecl (
364
+ SourceLoc (), SourceLoc (), Identifier (), SourceLoc (),
365
+ newDecl->getASTContext ().getIdentifier (" _" ), dc);
366
+ paramVarDecl->setInterfaceType (paramTy.getPlainType ());
367
+ paramVarDecl->setSpecifier (ParamSpecifier::Default);
368
+ newParams.push_back (paramVarDecl);
369
+ }
370
+
371
+ auto *newParamList =
372
+ ParameterList::create (newDecl->getASTContext (), SourceLoc (), newParams, SourceLoc ());
373
+
272
374
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 );
375
+ newDecl ->getASTContext (), newDecl ->getStaticSpelling (), oldDecl->getName (),
376
+ newDecl ->getNameLoc (), newDecl ->hasAsync (), newDecl ->hasThrows (),
377
+ /* genericParams=*/ nullptr , newParamList ,
378
+ newDecl-> getResultInterfaceType (), newDecl ->getDeclContext ());
379
+ thunk->copyFormalAccessFrom (newDecl );
278
380
thunk->setBodySynthesizer (synthesizeForwardingThunkBody, newDecl);
279
- thunk->setSelfAccessKind (oldDecl->getSelfAccessKind ());
381
+ thunk->setSelfAccessKind (newDecl->getSelfAccessKind ());
382
+ thunk->getAttrs ().add (
383
+ new (newDecl->getASTContext ()) TransparentAttr (/* IsImplicit=*/ true ));
280
384
281
385
return thunk;
282
386
}
@@ -326,6 +430,10 @@ static ConcreteDeclRef getCXXFunctionTemplateSpecialization(SubstitutionMap subs
326
430
}
327
431
}
328
432
433
+ if (auto fn = dyn_cast<FuncDecl>(decl)) {
434
+ newDecl = addThunkForDependentTypes (fn, cast<FuncDecl>(newDecl));
435
+ }
436
+
329
437
if (auto fn = dyn_cast<FuncDecl>(decl)) {
330
438
if (newFn->getNumParams () != fn->getParameters ()->size ()) {
331
439
newDecl = generateThunkForExtraMetatypes (subst, fn,
0 commit comments