Skip to content

Commit 7d71d64

Browse files
authored
Merge pull request #60835 from hyp/eng/generic-methods-gogo
[interop][SwiftToCxx] add support for generic methods
2 parents 095226f + a89d4f3 commit 7d71d64

File tree

5 files changed

+102
-35
lines changed

5 files changed

+102
-35
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

+32-25
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,9 @@ class DeclAndTypePrinter::Implementation
753753
typeDeclContext, accessor, funcABI->getSymbolName(), resultTy,
754754
/*isDefinition=*/false);
755755
} else {
756-
declPrinter.printCxxMethod(typeDeclContext, AFD,
757-
funcABI->getSymbolName(), resultTy,
758-
/*isDefinition=*/false);
756+
declPrinter.printCxxMethod(
757+
typeDeclContext, AFD, funcABI->getSymbolName(), resultTy,
758+
/*isDefinition=*/false, funcABI->additionalParams);
759759
}
760760

761761
DeclAndTypeClangFunctionPrinter defPrinter(
@@ -769,9 +769,9 @@ class DeclAndTypePrinter::Implementation
769769
typeDeclContext, accessor, funcABI->getSymbolName(), resultTy,
770770
/*isDefinition=*/true);
771771
} else {
772-
defPrinter.printCxxMethod(typeDeclContext, AFD,
773-
funcABI->getSymbolName(), resultTy,
774-
/*isDefinition=*/true);
772+
defPrinter.printCxxMethod(
773+
typeDeclContext, AFD, funcABI->getSymbolName(), resultTy,
774+
/*isDefinition=*/true, funcABI->additionalParams);
775775
}
776776

777777
// FIXME: SWIFT_WARN_UNUSED_RESULT
@@ -1068,6 +1068,9 @@ class DeclAndTypePrinter::Implementation
10681068

10691069
bool useMangledSymbolName() const { return !isCDecl; }
10701070

1071+
SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
1072+
additionalParams;
1073+
10711074
private:
10721075
bool isCDecl;
10731076
StringRef symbolName;
@@ -1078,7 +1081,8 @@ class DeclAndTypePrinter::Implementation
10781081
AbstractFunctionDecl *FD, Type resultTy,
10791082
llvm::SmallVector<IRABIDetailsProvider::ABIAdditionalParam, 1> ABIparams,
10801083
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
1081-
&params) {
1084+
&params,
1085+
Optional<NominalTypeDecl *> selfTypeDeclContext = None) {
10821086
for (auto param : ABIparams) {
10831087
if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
10841088
ABIParameterRole::GenericRequirementRole)
@@ -1090,7 +1094,9 @@ class DeclAndTypePrinter::Implementation
10901094
IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self)
10911095
params.push_back(
10921096
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
1093-
resultTy->getASTContext().getOpaquePointerType(),
1097+
selfTypeDeclContext
1098+
? (*selfTypeDeclContext)->getDeclaredType()
1099+
: resultTy->getASTContext().getOpaquePointerType(),
10941100
/*isIndirect=*/
10951101
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
10961102
else if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
@@ -1135,23 +1141,29 @@ class DeclAndTypePrinter::Implementation
11351141
owningPrinter.interopContext, owningPrinter);
11361142
auto ABIparams = owningPrinter.interopContext.getIrABIDetails()
11371143
.getFunctionABIAdditionalParams(FD);
1138-
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
1139-
additionalParams;
1140-
if (selfTypeDeclContext && !isa<ConstructorDecl>(FD)) {
1141-
additionalParams.push_back(
1144+
// FIXME: Ideally direct 'self' would come from IR provider too.
1145+
if (selfTypeDeclContext && !isa<ConstructorDecl>(FD) &&
1146+
llvm::find_if(
1147+
ABIparams,
1148+
[](const IRABIDetailsProvider::ABIAdditionalParam &Param) {
1149+
return Param.role == IRABIDetailsProvider::ABIAdditionalParam::
1150+
ABIParameterRole::Self;
1151+
}) == ABIparams.end()) {
1152+
funcABI.additionalParams.push_back(
11421153
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
11431154
(*selfTypeDeclContext)->getDeclaredType(),
11441155
/*isIndirect=*/
11451156
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
11461157
}
1147-
// FIXME: Fix the method 'self' parameter.
1148-
if (!selfTypeDeclContext && !ABIparams.empty())
1149-
convertABIAdditionalParams(FD, resultTy, ABIparams, additionalParams);
1158+
if (!ABIparams.empty())
1159+
convertABIAdditionalParams(FD, resultTy, ABIparams,
1160+
funcABI.additionalParams,
1161+
/*selfContext=*/selfTypeDeclContext);
11501162

11511163
auto representation = funcPrinter.printFunctionSignature(
11521164
FD, funcABI.getSymbolName(), resultTy,
11531165
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto,
1154-
additionalParams);
1166+
funcABI.additionalParams);
11551167
if (representation.isUnsupported()) {
11561168
// FIXME: Emit remark about unemitted declaration.
11571169
return None;
@@ -1195,12 +1207,6 @@ class DeclAndTypePrinter::Implementation
11951207
DeclAndTypeClangFunctionPrinter funcPrinter(
11961208
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
11971209
owningPrinter.interopContext, owningPrinter);
1198-
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
1199-
additionalParams;
1200-
auto ABIparams = owningPrinter.interopContext.getIrABIDetails()
1201-
.getFunctionABIAdditionalParams(FD);
1202-
if (!ABIparams.empty())
1203-
convertABIAdditionalParams(FD, resultTy, ABIparams, additionalParams);
12041210
DeclAndTypeClangFunctionPrinter::FunctionSignatureModifiers modifiers;
12051211
modifiers.isInline = true;
12061212
auto result = funcPrinter.printFunctionSignature(
@@ -1215,9 +1221,10 @@ class DeclAndTypePrinter::Implementation
12151221
printFunctionClangAttributes(FD, funcTy);
12161222
printAvailability(FD);
12171223
os << " {\n";
1218-
funcPrinter.printCxxThunkBody(
1219-
funcABI.getSymbolName(), FD->getModuleContext(), resultTy,
1220-
FD->getParameters(), additionalParams, funcTy->isThrowing(), funcTy);
1224+
funcPrinter.printCxxThunkBody(funcABI.getSymbolName(),
1225+
FD->getModuleContext(), resultTy,
1226+
FD->getParameters(), funcABI.additionalParams,
1227+
funcTy->isThrowing(), funcTy);
12211228
os << "}\n";
12221229
}
12231230

lib/PrintAsClang/PrintClangFunction.cpp

+4-9
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,8 @@ static StringRef getConstructorName(const AbstractFunctionDecl *FD) {
717717

718718
void DeclAndTypeClangFunctionPrinter::printCxxMethod(
719719
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
720-
StringRef swiftSymbolName, Type resultTy, bool isDefinition) {
720+
StringRef swiftSymbolName, Type resultTy, bool isDefinition,
721+
ArrayRef<AdditionalParam> additionalParams) {
721722
bool isConstructor = isa<ConstructorDecl>(FD);
722723
os << " ";
723724

@@ -744,15 +745,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
744745

745746
os << " {\n";
746747
// FIXME: should it be objTy for resultTy?
747-
SmallVector<AdditionalParam, 2> additionalParams;
748-
if (!isConstructor)
749-
additionalParams.push_back(AdditionalParam{
750-
AdditionalParam::Role::Self,
751-
typeDeclContext->getDeclaredType(),
752-
/*isIndirect=*/isMutating,
753-
});
754748
printCxxThunkBody(swiftSymbolName, FD->getModuleContext(), resultTy,
755-
FD->getParameters(), additionalParams, FD->hasThrows());
749+
FD->getParameters(), additionalParams, FD->hasThrows(),
750+
FD->getInterfaceType()->castTo<AnyFunctionType>());
756751
os << " }\n";
757752
}
758753

lib/PrintAsClang/PrintClangFunction.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ class DeclAndTypeClangFunctionPrinter {
126126
/// constructors.
127127
void printCxxMethod(const NominalTypeDecl *typeDeclContext,
128128
const AbstractFunctionDecl *FD, StringRef swiftSymbolName,
129-
Type resultTy, bool isDefinition);
129+
Type resultTy, bool isDefinition,
130+
ArrayRef<AdditionalParam> additionalParams);
130131

131132
/// Print the C++ getter/setter method signature.
132133
void printCxxPropertyAccessorMethod(const NominalTypeDecl *typeDeclContext,

test/Interop/SwiftToCxx/generics/generic-function-execution.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,23 @@ int main() {
206206
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
207207
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 4294902062)
208208
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 65233)
209+
{
210+
auto x = createTestSmallStruct(42);
211+
int passThru = x.genericMethodPassThrough((int)555);
212+
assert(passThru == 555);
213+
auto xprime = x.genericMethodPassThrough(x);
214+
genericPrintFunction(xprime);
215+
x.genericMethodMutTake((uint32_t)16);
216+
genericPrintFunction(xprime);
217+
genericPrintFunction(x);
218+
x.genericMethodMutTake(xprime);
219+
genericPrintFunction(xprime);
220+
genericPrintFunction(x);
221+
}
222+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 42)
223+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 42)
224+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 58)
225+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 42)
226+
// CHECK-NEXT: TestSmallStruct value=TestSmallStruct(x1: 57)
209227
return 0;
210228
}

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

+46
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,34 @@ public func createTestLargeStruct(_ x: Int) -> TestLargeStruct {
7272
return TestLargeStruct(x)
7373
}
7474

75+
@frozen
7576
public struct TestSmallStruct {
7677
var x1: UInt32
7778

7879
public mutating func mut() {
7980
x1 = ~x1
8081
}
82+
83+
public func genericMethodPassThrough<T>(_ x: T) -> T {
84+
return x
85+
}
86+
87+
public mutating func genericMethodMutTake<T>(_ x: T) {
88+
if let y = x as? UInt32 {
89+
x1 += y
90+
} else {
91+
x1 -= 1
92+
}
93+
}
8194
}
8295

8396
public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
8497
return TestSmallStruct(x1: x)
8598
}
8699

100+
// CHECK: SWIFT_EXTERN void $s9Functions15TestSmallStructV24genericMethodPassThroughyxxlF(SWIFT_INDIRECT_RESULT void * _Nonnull, const void * _Nonnull x, struct swift_interop_stub_Functions_TestSmallStruct _self, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericMethodPassThrough(_:)
101+
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions15TestSmallStructV20genericMethodMutTakeyyxlF(const void * _Nonnull x, void * _Nonnull , SWIFT_CONTEXT void * _Nonnull _self) SWIFT_NOEXCEPT SWIFT_CALL; // genericMethodMutTake(_:)
102+
87103
// CHECK: SWIFT_EXTERN void $s9Functions20genericPrintFunctionyyxlF(const void * _Nonnull x, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunction(_:)
88104
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions32genericPrintFunctionMultiGenericyySi_xxSiq_tr0_lF(ptrdiff_t x, const void * _Nonnull t1, const void * _Nonnull t1p, ptrdiff_t y, const void * _Nonnull t2, void * _Nonnull , void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionMultiGeneric(_:_:_:_:_:)
89105
// CHECK-NEXT: SWIFT_EXTERN void $s9Functions26genericPrintFunctionTwoArgyyx_SitlF(const void * _Nonnull x, ptrdiff_t y, void * _Nonnull ) SWIFT_NOEXCEPT SWIFT_CALL; // genericPrintFunctionTwoArg(_:_:)
@@ -95,6 +111,13 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
95111
// Skip templates in impl classes.
96112
// CHECK: _impl_TestSmallStruct
97113
// 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);
119+
// CHECK: template<class T>
120+
// CHECK-NEXT: returnNewValue
98121

99122
// CHECK: template<class T>
100123
// CHECK-NEXT: requires swift::isUsableInGenericContext<T>
@@ -139,3 +162,26 @@ public func createTestSmallStruct(_ x: UInt32) -> TestSmallStruct {
139162
// CHECK-NEXT: inline void genericSwap(T & x, T & y) noexcept {
140163
// CHECK-NEXT: return _impl::$s9Functions11genericSwapyyxz_xztlF(swift::_impl::getOpaquePointer(x), swift::_impl::getOpaquePointer(y), swift::getTypeMetadata<T>());
141164
// CHECK-NEXT: }
165+
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) {
170+
// 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>());
176+
// CHECK-NEXT: });
177+
// 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>());
180+
// CHECK-NEXT: return returnValue;
181+
// CHECK-NEXT: }
182+
// 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());
187+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)