Skip to content

Commit 4154b56

Browse files
committed
[interop][SwiftToCxx] unify generic function printing with generic struct printing
This is a pre-requisite for supporting methods in generic structs.
1 parent 9835888 commit 4154b56

File tree

3 files changed

+95
-116
lines changed

3 files changed

+95
-116
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -328,24 +328,20 @@ class CFunctionSignatureTypePrinter
328328
visitGenericTypeParamType(GenericTypeParamType *genericTpt,
329329
Optional<OptionalTypeKind> optionalKind,
330330
bool isInOutParam) {
331-
// FIXME: handle optionalKind.
332-
if (typeUseKind == FunctionSignatureTypeUse::ReturnType ||
333-
typeUseKind == FunctionSignatureTypeUse::TypeReference) {
334-
// generic is always returned indirectly in C signature.
335-
assert(languageMode == OutputLanguageMode::Cxx);
336-
os << genericTpt->getName();
337-
return ClangRepresentation::representable;
338-
}
339-
if (!isInOutParam)
331+
bool isParam = typeUseKind == FunctionSignatureTypeUse::ParamType;
332+
if (isParam && !isInOutParam)
340333
os << "const ";
341-
if (languageMode == OutputLanguageMode::Cxx) {
342-
// Pass a reference to a template type.
343-
os << genericTpt->getName();
344-
os << " &";
334+
// FIXME: handle optionalKind.
335+
if (languageMode != OutputLanguageMode::Cxx) {
336+
assert(typeUseKind == FunctionSignatureTypeUse::ParamType);
337+
// Pass an opaque param in C mode.
338+
os << "void * _Nonnull";
345339
return ClangRepresentation::representable;
346340
}
347-
// Pass an opaque param in C mode.
348-
os << "void * _Nonnull";
341+
ClangSyntaxPrinter(os).printGenericTypeParamTypeName(genericTpt);
342+
// Pass a reference to the template type.
343+
if (isParam)
344+
os << '&';
349345
return ClangRepresentation::representable;
350346
}
351347

@@ -385,31 +381,13 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature(
385381
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams,
386382
FunctionSignatureModifiers modifiers) {
387383
if (FD->isGeneric()) {
388-
auto Signature = FD->getGenericSignature();
384+
auto Signature = FD->getGenericSignature().getCanonicalSignature();
389385
auto Requirements = Signature.getRequirements();
390386
// FIXME: Support generic requirements.
391387
if (!Requirements.empty())
392388
return ClangRepresentation::unsupported;
393-
if (kind == FunctionSignatureKind::CxxInlineThunk) {
394-
os << "template<";
395-
llvm::interleaveComma(FD->getGenericParams()->getParams(), os,
396-
[&](const GenericTypeParamDecl *genericParam) {
397-
os << "class ";
398-
ClangSyntaxPrinter(os).printBaseName(
399-
genericParam);
400-
});
401-
os << ">\n";
402-
os << "requires ";
403-
llvm::interleave(
404-
FD->getGenericParams()->getParams(), os,
405-
[&](const GenericTypeParamDecl *genericParam) {
406-
os << "swift::isUsableInGenericContext<";
407-
ClangSyntaxPrinter(os).printBaseName(genericParam);
408-
os << ">";
409-
},
410-
" && ");
411-
os << "\n";
412-
}
389+
if (kind == FunctionSignatureKind::CxxInlineThunk)
390+
ClangSyntaxPrinter(os).printGenericSignature(Signature);
413391
}
414392
auto emittedModule = FD->getModuleContext();
415393
OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto
@@ -672,14 +650,10 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
672650
assert(!genericRequirement.Protocol);
673651
if (auto *gtpt = genericRequirement.TypeParameter
674652
->getAs<GenericTypeParamType>()) {
675-
assert(funcType);
676-
auto *gft = dyn_cast<GenericFunctionType>(funcType);
677-
if (gtpt->getDepth() == 0) {
678-
os << "swift::getTypeMetadata<"
679-
<< gft->getGenericParams()[gtpt->getIndex()]->getName()
680-
<< ">()";
681-
return;
682-
}
653+
os << "swift::getTypeMetadata<";
654+
ClangSyntaxPrinter(os).printGenericTypeParamTypeName(gtpt);
655+
os << ">()";
656+
return;
683657
}
684658
os << "ERROR";
685659
return;
@@ -706,20 +680,25 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
706680
// indirectly by a pointer.
707681
if (!isKnownCxxType(resultTy, typeMapping) &&
708682
!hasKnownOptionalNullableCxxMapping(resultTy)) {
709-
if (resultTy->is<GenericTypeParamType>()) {
683+
if (const auto *gtpt = resultTy->getAs<GenericTypeParamType>()) {
710684
std::string returnAddress;
711685
llvm::raw_string_ostream ros(returnAddress);
712686
ros << "reinterpret_cast<void *>(&returnValue)";
713-
StringRef resultTyName = "T"; // FIXME
687+
std::string resultTyName;
688+
{
689+
llvm::raw_string_ostream os(resultTyName);
690+
ClangSyntaxPrinter(os).printGenericTypeParamTypeName(gtpt);
691+
}
714692

715693
os << " if constexpr (std::is_base_of<::swift::"
716-
<< cxx_synthesis::getCxxImplNamespaceName()
717-
<< "::RefCountedClass, T>::value) {\n";
694+
<< cxx_synthesis::getCxxImplNamespaceName() << "::RefCountedClass, "
695+
<< resultTyName << ">::value) {\n";
718696
os << " void *returnValue;\n ";
719697
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));
720698
os << ";\n";
721699
os << " return ::swift::" << cxx_synthesis::getCxxImplNamespaceName()
722-
<< "::implClassFor<T>::type::makeRetained(returnValue);\n";
700+
<< "::implClassFor<" << resultTyName
701+
<< ">::type::makeRetained(returnValue);\n";
723702
os << " } else if constexpr (::swift::"
724703
<< cxx_synthesis::getCxxImplNamespaceName() << "::isValueType<"
725704
<< resultTyName << ">) {\n";
@@ -729,7 +708,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
729708
printCallToCFunc(/*additionalParam=*/StringRef("returnValue"));
730709
os << ";\n });\n";
731710
os << " } else {\n";
732-
os << " T returnValue;\n";
711+
os << " " << resultTyName << " returnValue;\n";
733712
printCallToCFunc(/*additionalParam=*/StringRef(ros.str()));
734713
os << ";\n return returnValue;\n";
735714
os << " }\n";

test/Interop/SwiftToCxx/generics/generic-function-in-cxx.swift

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -110,78 +110,78 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
110110

111111
// Skip templates in impl classes.
112112
// CHECK: _impl_TestSmallStruct
113-
// CHECK: template<class T>
114-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
115-
// CHECK-NEXT: inline T genericMethodPassThrough(const T & x) const;
116-
// CHECK-NEXT: template<class T>
117-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
118-
// CHECK-NEXT: inline void genericMethodMutTake(const T & x);
113+
// CHECK: template<class T_0_0>
114+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
115+
// CHECK-NEXT: inline T_0_0 genericMethodPassThrough(const T_0_0& x) const;
116+
// CHECK-NEXT: template<class T_0_0>
117+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
118+
// CHECK-NEXT: inline void genericMethodMutTake(const T_0_0& x);
119119
// CHECK: template<class T>
120120
// CHECK-NEXT: returnNewValue
121121

122-
// CHECK: template<class T>
123-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
124-
// CHECK-NEXT: inline void genericPrintFunction(const T & x) noexcept {
125-
// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
122+
// CHECK: template<class T_0_0>
123+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
124+
// CHECK-NEXT: inline void genericPrintFunction(const T_0_0& x) noexcept {
125+
// CHECK-NEXT: return _impl::$s9Functions20genericPrintFunctionyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T_0_0>());
126126
// CHECK-NEXT: }
127127

128128

129-
// CHECK: template<class T1, class T2>
130-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T1> && swift::isUsableInGenericContext<T2>
131-
// CHECK-NEXT: inline void genericPrintFunctionMultiGeneric(swift::Int x, const T1 & t1, const T1 & t1p, swift::Int y, const T2 & t2) noexcept {
132-
// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, swift::_impl::getOpaquePointer(t1), swift::_impl::getOpaquePointer(t1p), y, swift::_impl::getOpaquePointer(t2), swift::getTypeMetadata<T1>(), swift::getTypeMetadata<T2>());
129+
// CHECK: template<class T_0_0, class T_0_1>
130+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0> && swift::isUsableInGenericContext<T_0_1>
131+
// CHECK-NEXT: inline void genericPrintFunctionMultiGeneric(swift::Int x, const T_0_0& t1, const T_0_0& t1p, swift::Int y, const T_0_1& t2) noexcept {
132+
// CHECK-NEXT: return _impl::$s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(x, swift::_impl::getOpaquePointer(t1), swift::_impl::getOpaquePointer(t1p), y, swift::_impl::getOpaquePointer(t2), swift::getTypeMetadata<T_0_0>(), swift::getTypeMetadata<T_0_1>());
133133
// CHECK-NEXT: }
134134

135135

136-
// CHECK: template<class T>
137-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
138-
// CHECK-NEXT: inline void genericPrintFunctionTwoArg(const T & x, swift::Int y) noexcept {
139-
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(swift::_impl::getOpaquePointer(x), y, swift::getTypeMetadata<T>());
136+
// CHECK: template<class T_0_0>
137+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
138+
// CHECK-NEXT: inline void genericPrintFunctionTwoArg(const T_0_0& x, swift::Int y) noexcept {
139+
// CHECK-NEXT: return _impl::$s9Functions26genericPrintFunctionTwoArgyyx_SitlF(swift::_impl::getOpaquePointer(x), y, swift::getTypeMetadata<T_0_0>());
140140
// CHECK-NEXT: }
141141

142-
// CHECK: template<class T>
143-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
144-
// CHECK-NEXT: inline T genericRet(const T & x) noexcept SWIFT_WARN_UNUSED_RESULT {
145-
// CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T>::value) {
142+
// CHECK: template<class T_0_0>
143+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
144+
// CHECK-NEXT: inline T_0_0 genericRet(const T_0_0& x) noexcept SWIFT_WARN_UNUSED_RESULT {
145+
// CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T_0_0>::value) {
146146
// CHECK-NEXT: void *returnValue;
147-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
148-
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::makeRetained(returnValue);
149-
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T>) {
150-
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::returnNewValue([&](void * _Nonnull returnValue) {
151-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
147+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T_0_0>());
148+
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::makeRetained(returnValue);
149+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T_0_0>) {
150+
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::returnNewValue([&](void * _Nonnull returnValue) {
151+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(returnValue, swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T_0_0>());
152152
// CHECK-NEXT: });
153153
// CHECK-NEXT: } else {
154-
// CHECK-NEXT: T returnValue;
155-
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>());
154+
// CHECK-NEXT: T_0_0 returnValue;
155+
// CHECK-NEXT: _impl::$s9Functions10genericRetyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T_0_0>());
156156
// CHECK-NEXT: return returnValue;
157157
// CHECK-NEXT: }
158158
// CHECK-NEXT: }
159159

160-
// CHECK: template<class T>
161-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
162-
// CHECK-NEXT: inline void genericSwap(T & x, T & y) noexcept {
163-
// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T>());
160+
// CHECK: template<class T_0_0>
161+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
162+
// CHECK-NEXT: inline void genericSwap(T_0_0& x, T_0_0& y) noexcept {
163+
// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T_0_0>());
164164
// CHECK-NEXT: }
165165

166-
// CHECK: template<class T>
167-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
168-
// CHECK-NEXT: inline T TestSmallStruct::genericMethodPassThrough(const T & x) const {
169-
// CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T>::value) {
166+
// CHECK: template<class T_0_0>
167+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
168+
// CHECK-NEXT: inline T_0_0 TestSmallStruct::genericMethodPassThrough(const T_0_0& x) const {
169+
// CHECK-NEXT: if constexpr (std::is_base_of<::swift::_impl::RefCountedClass, T_0_0>::value) {
170170
// CHECK-NEXT: void *returnValue;
171-
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T>());
172-
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::makeRetained(returnValue);
173-
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T>) {
174-
// CHECK-NEXT: return ::swift::_impl::implClassFor<T>::type::returnNewValue([&](void * _Nonnull returnValue) {
175-
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(returnValue, swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T>());
171+
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T_0_0>());
172+
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::makeRetained(returnValue);
173+
// CHECK-NEXT: } else if constexpr (::swift::_impl::isValueType<T_0_0>) {
174+
// CHECK-NEXT: return ::swift::_impl::implClassFor<T_0_0>::type::returnNewValue([&](void * _Nonnull returnValue) {
175+
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(returnValue, swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T_0_0>());
176176
// CHECK-NEXT: });
177177
// CHECK-NEXT: } else {
178-
// CHECK-NEXT: T returnValue;
179-
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T>());
178+
// CHECK-NEXT: T_0_0 returnValue;
179+
// CHECK-NEXT: _impl::$s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(reinterpret_cast<void *>(&returnValue), swift::_impl::getOpaquePointer(x), _impl::swift_interop_passDirect_Functions_TestSmallStruct(_getOpaquePointer()), swift::getTypeMetadata<T_0_0>());
180180
// CHECK-NEXT: return returnValue;
181181
// CHECK-NEXT: }
182182
// CHECK-NEXT: }
183-
// CHECK-NEXT: template<class T>
184-
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
185-
// CHECK-NEXT: inline void TestSmallStruct::genericMethodMutTake(const T & x) {
186-
// CHECK-NEXT: return _impl::$s9Functions15TestSmallStructV20genericMethodMutTakeyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T>(), _getOpaquePointer());
183+
// CHECK-NEXT: template<class T_0_0>
184+
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
185+
// CHECK-NEXT: inline void TestSmallStruct::genericMethodMutTake(const T_0_0& x) {
186+
// CHECK-NEXT: return _impl::$s9Functions15TestSmallStructV20genericMethodMutTakeyyxlF(swift::_impl::getOpaquePointer(x), swift::getTypeMetadata<T_0_0>(), _getOpaquePointer());
187187
// CHECK-NEXT: }

0 commit comments

Comments
 (0)