@@ -109,6 +109,76 @@ Solution::computeSubstitutions(GenericSignature sig,
109109 lookupConformanceFn);
110110}
111111
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+
112182// Derive a concrete function type for fdecl by substituting the generic args
113183// and use that to derive the corresponding function type and parameter list.
114184static std::pair<FunctionType *, ParameterList *>
@@ -190,20 +260,32 @@ synthesizeForwardingThunkBody(AbstractFunctionDecl *afd, void *context) {
190260 return {body, /* isTypeChecked=*/ true };
191261}
192262
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+ }
202283
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) {
207289 if (const auto *constMethod =
208290 dyn_cast_or_null<clang::CXXMethodDecl>(decl->getClangDecl ())) {
209291 auto method = const_cast <clang::CXXMethodDecl *>(constMethod);
@@ -214,114 +296,62 @@ Solution::resolveConcreteDeclRef(ValueDecl *decl,
214296 ->getClangSema ()
215297 .InstantiateFunctionDefinition (method->getLocation (), method);
216298 }
299+ }
217300
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." );
272305
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);
301326 }
327+ }
302328
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));
322333 }
334+ }
335+
336+ return ConcreteDeclRef (newDecl);
337+ }
323338
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);
325355 }
326356
327357 return ConcreteDeclRef (decl, subst);
0 commit comments