@@ -109,16 +109,18 @@ Solution::computeSubstitutions(GenericSignature sig,
109
109
lookupConformanceFn);
110
110
}
111
111
112
- static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate (
113
- ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
114
- clang::FunctionDecl *specialized) {
112
+ // Derive a concrete function type for fdecl by substituting the generic args
113
+ // and use that to derive the corresponding function type and parameter list.
114
+ static std::pair<FunctionType *, ParameterList *>
115
+ substituteFunctionTypeAndParamList (ASTContext &ctx, AbstractFunctionDecl *fdecl,
116
+ SubstitutionMap subst) {
115
117
FunctionType *newFnType = nullptr ;
116
118
// Create a new ParameterList with the substituted type.
117
119
if (auto oldFnType = dyn_cast<GenericFunctionType>(
118
- oldDecl ->getInterfaceType ().getPointer ())) {
120
+ fdecl ->getInterfaceType ().getPointer ())) {
119
121
newFnType = oldFnType->substGenericArgs (subst);
120
122
} else {
121
- newFnType = cast<FunctionType>(oldDecl ->getInterfaceType ().getPointer ());
123
+ newFnType = cast<FunctionType>(fdecl ->getInterfaceType ().getPointer ());
122
124
}
123
125
// The constructor type is a function type as follows:
124
126
// (CType.Type) -> (Generic) -> CType
@@ -127,22 +129,49 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
127
129
// In either case, we only want the result of that function type because that
128
130
// is the function type with the generic params that need to be substituted:
129
131
// (Generic) -> CType
130
- if (isa<ConstructorDecl>(oldDecl ) || oldDecl ->isInstanceMember () ||
131
- oldDecl ->isStatic ())
132
+ if (isa<ConstructorDecl>(fdecl ) || fdecl ->isInstanceMember () ||
133
+ fdecl ->isStatic ())
132
134
newFnType = cast<FunctionType>(newFnType->getResult ().getPointer ());
133
135
SmallVector<ParamDecl *, 4 > newParams;
134
136
unsigned i = 0 ;
137
+
135
138
for (auto paramTy : newFnType->getParams ()) {
136
- auto *oldParamDecl = oldDecl ->getParameters ()->get (i);
139
+ auto *oldParamDecl = fdecl ->getParameters ()->get (i);
137
140
auto *newParamDecl =
138
- ParamDecl::cloneWithoutType (oldDecl ->getASTContext (), oldParamDecl);
141
+ ParamDecl::cloneWithoutType (fdecl ->getASTContext (), oldParamDecl);
139
142
newParamDecl->setInterfaceType (paramTy.getParameterType ());
140
143
newParams.push_back (newParamDecl);
141
144
(void )++i;
142
145
}
143
146
auto *newParamList =
144
147
ParameterList::create (ctx, SourceLoc (), newParams, SourceLoc ());
145
148
149
+ return {newFnType, newParamList};
150
+ }
151
+
152
+ static ValueDecl *generateSpecializedCXXFunctionTemplate (
153
+ ASTContext &ctx, AbstractFunctionDecl *oldDecl, SubstitutionMap subst,
154
+ clang::FunctionDecl *specialized) {
155
+ auto newFnTypeAndParams = substituteFunctionTypeAndParamList (ctx, oldDecl, subst);
156
+ auto newFnType = newFnTypeAndParams.first ;
157
+ auto paramList = newFnTypeAndParams.second ;
158
+
159
+ SmallVector<ParamDecl *, 4 > newParamsWithoutMetatypes;
160
+ for (auto param : *paramList ) {
161
+ if (isa<FuncDecl>(oldDecl) &&
162
+ isa<MetatypeType>(param->getType ().getPointer ())) {
163
+ // Metatype parameters are added synthetically to account for template
164
+ // params that don't make it to the function signature. These shouldn't
165
+ // exist in the resulting specialized FuncDecl. Note that this doesn't
166
+ // affect constructors because all template params for a constructor
167
+ // must be in the function signature by design.
168
+ continue ;
169
+ }
170
+ newParamsWithoutMetatypes.push_back (param);
171
+ }
172
+ auto *newParamList =
173
+ ParameterList::create (ctx, SourceLoc (), newParamsWithoutMetatypes, SourceLoc ());
174
+
146
175
if (isa<ConstructorDecl>(oldDecl)) {
147
176
DeclName ctorName (ctx, DeclBaseName::createConstructor (), newParamList);
148
177
auto newCtorDecl = ConstructorDecl::createImported (
@@ -152,7 +181,7 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
152
181
/* throws=*/ false , /* throwsLoc=*/ SourceLoc (),
153
182
newParamList, /* genericParams=*/ nullptr ,
154
183
oldDecl->getDeclContext ());
155
- return ConcreteDeclRef ( newCtorDecl) ;
184
+ return newCtorDecl;
156
185
}
157
186
158
187
// Generate a name for the specialized function.
@@ -176,7 +205,48 @@ static ConcreteDeclRef generateDeclRefForSpecializedCXXFunctionTemplate(
176
205
newFnDecl->setImportAsStaticMember ();
177
206
}
178
207
newFnDecl->setSelfAccessKind (cast<FuncDecl>(oldDecl)->getSelfAccessKind ());
179
- return ConcreteDeclRef (newFnDecl);
208
+ return newFnDecl;
209
+ }
210
+
211
+ // Synthesizes the body of a thunk that takes extra metatype arguments and
212
+ // skips over them to forward them along to the FuncDecl contained by context.
213
+ // This is used when importing a C++ templated function where the template params
214
+ // are not used in the function signature. We supply the type params as explicit
215
+ // metatype arguments to aid in typechecking, but they shouldn't be forwarded to
216
+ // the corresponding C++ function.
217
+ static std::pair<BraceStmt *, bool >
218
+ synthesizeForwardingThunkBody (AbstractFunctionDecl *afd, void *context) {
219
+ ASTContext &ctx = afd->getASTContext ();
220
+
221
+ auto thunkDecl = cast<FuncDecl>(afd);
222
+ auto specializedFuncDecl = static_cast <FuncDecl *>(context);
223
+
224
+ SmallVector<Argument, 8 > forwardingParams;
225
+ for (auto param : *thunkDecl->getParameters ()) {
226
+ if (isa<MetatypeType>(param->getType ().getPointer ())) {
227
+ continue ;
228
+ }
229
+ auto paramRefExpr = new (ctx) DeclRefExpr (param, DeclNameLoc (),
230
+ /* Implicit=*/ true );
231
+ paramRefExpr->setType (param->getType ());
232
+ forwardingParams.push_back (Argument (SourceLoc (), Identifier (), paramRefExpr));
233
+ }
234
+
235
+ auto *specializedFuncDeclRef = new (ctx) DeclRefExpr (ConcreteDeclRef (specializedFuncDecl),
236
+ DeclNameLoc (), true );
237
+ specializedFuncDeclRef->setType (specializedFuncDecl->getInterfaceType ());
238
+
239
+ auto argList = ArgumentList::createImplicit (ctx, forwardingParams);
240
+ auto *specializedFuncCallExpr = CallExpr::createImplicit (ctx, specializedFuncDeclRef, argList);
241
+ specializedFuncCallExpr->setType (thunkDecl->getResultInterfaceType ());
242
+ specializedFuncCallExpr->setThrows (false );
243
+
244
+ auto returnStmt = new (ctx) ReturnStmt (SourceLoc (), specializedFuncCallExpr,
245
+ /* implicit=*/ true );
246
+
247
+ auto body = BraceStmt::create (ctx, SourceLoc (), {returnStmt}, SourceLoc (),
248
+ /* implicit=*/ true );
249
+ return {body, /* isTypeChecked=*/ true };
180
250
}
181
251
182
252
ConcreteDeclRef
@@ -215,13 +285,35 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
215
285
const_cast <clang::FunctionTemplateDecl *>(
216
286
cast<clang::FunctionTemplateDecl>(decl->getClangDecl ())),
217
287
subst);
218
- return generateDeclRefForSpecializedCXXFunctionTemplate (
288
+ auto newDecl = generateSpecializedCXXFunctionTemplate (
219
289
decl->getASTContext (), cast<AbstractFunctionDecl>(decl), subst, newFn);
290
+ if (auto fn = dyn_cast<FuncDecl>(decl)) {
291
+ if (newFn->getNumParams () != fn->getParameters ()->size ()) {
292
+ // We added additional metatype parameters to aid template
293
+ // specialization, which are no longer now that we've specialized
294
+ // this function. Create a thunk that only forwards the original
295
+ // parameters along to the clang function.
296
+ auto thunkTypeAndParamList = substituteFunctionTypeAndParamList (decl->getASTContext (),
297
+ fn, subst);
298
+ auto thunk = FuncDecl::createImplicit (
299
+ fn->getASTContext (), fn->getStaticSpelling (), fn->getName (),
300
+ fn->getNameLoc (), fn->hasAsync (), fn->hasThrows (),
301
+ /* genericParams=*/ nullptr , thunkTypeAndParamList.second ,
302
+ thunkTypeAndParamList.first ->getResult (), fn->getDeclContext ());
303
+ thunk->copyFormalAccessFrom (fn);
304
+ thunk->setBodySynthesizer (synthesizeForwardingThunkBody, cast<FuncDecl>(newDecl));
305
+ thunk->setSelfAccessKind (fn->getSelfAccessKind ());
306
+
307
+ return ConcreteDeclRef (thunk);
308
+ }
309
+ }
310
+ return ConcreteDeclRef (newDecl);
220
311
}
221
312
222
313
return ConcreteDeclRef (decl, subst);
223
314
}
224
315
316
+
225
317
ConstraintLocator *Solution::getCalleeLocator (ConstraintLocator *locator,
226
318
bool lookThroughApply) const {
227
319
auto &cs = getConstraintSystem ();
0 commit comments