Skip to content

Commit 83e3f96

Browse files
committed
[nfc] Re-factor logic in resolveConcreteDeclRef into separate static functions.
1 parent a1f9aae commit 83e3f96

File tree

1 file changed

+145
-115
lines changed

1 file changed

+145
-115
lines changed

lib/Sema/CSApply.cpp

Lines changed: 145 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
114184
static 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

Comments
 (0)