Skip to content

Commit e5a4879

Browse files
committed
[interop][SwiftToCxx] add support for returning generic types bounded to concrete generic params
1 parent 0468c8a commit e5a4879

File tree

7 files changed

+144
-126
lines changed

7 files changed

+144
-126
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,14 @@ class CFunctionSignatureTypePrinter
184184
ClangRepresentation visitEnumType(EnumType *ET,
185185
Optional<OptionalTypeKind> optionalKind,
186186
bool isInOutParam) {
187-
return visitValueType(ET->getNominalOrBoundGenericNominal(), ET,
187+
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(), ET,
188188
optionalKind, isInOutParam);
189189
}
190190

191191
ClangRepresentation visitStructType(StructType *ST,
192192
Optional<OptionalTypeKind> optionalKind,
193193
bool isInOutParam) {
194-
return visitValueType(ST->getNominalOrBoundGenericNominal(), ST,
194+
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(), ST,
195195
optionalKind, isInOutParam);
196196
}
197197

@@ -212,11 +212,10 @@ class CFunctionSignatureTypePrinter
212212
return result;
213213
}
214214

215-
ClangRepresentation visitValueType(const NominalTypeDecl *decl,
216-
NominalType *NT,
217-
Optional<OptionalTypeKind> optionalKind,
218-
bool isInOutParam,
219-
ArrayRef<Type> genericArgs = {}) {
215+
ClangRepresentation
216+
visitValueType(TypeBase *type, const NominalTypeDecl *decl, NominalType *NT,
217+
Optional<OptionalTypeKind> optionalKind, bool isInOutParam,
218+
ArrayRef<Type> genericArgs = {}) {
220219
if (NT)
221220
assert(isa<StructType>(NT) || isa<EnumType>(NT));
222221
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl));
@@ -249,9 +248,14 @@ class CFunctionSignatureTypePrinter
249248
}
250249

251250
} else if (languageMode != OutputLanguageMode::Cxx) {
252-
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
253-
.printValueTypeParameterType(decl, languageMode, moduleContext,
254-
isInOutParam);
251+
if (!isInOutParam) {
252+
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
253+
.printCStubType(type, decl, genericArgs);
254+
} else {
255+
// Directly pass the pointer (from getOpaquePointer) to C interface
256+
// when in inout mode
257+
os << "char * _Nonnull";
258+
}
255259
} else {
256260
if (!isInOutParam) {
257261
os << "const ";
@@ -262,15 +266,21 @@ class CFunctionSignatureTypePrinter
262266
return result;
263267
}
264268
} else {
265-
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
266-
.printValueTypeReturnType(
267-
decl, languageMode,
268-
modifiersDelegate.mapValueTypeUseKind
269-
? (*modifiersDelegate.mapValueTypeUseKind)(
270-
ClangValueTypePrinter::TypeUseKind::CxxTypeName)
271-
: ClangValueTypePrinter::TypeUseKind::CxxTypeName,
272-
moduleContext);
273-
return visitGenericArgs(genericArgs);
269+
ClangValueTypePrinter printer(os, cPrologueOS, typeMapping,
270+
interopContext);
271+
if (languageMode != OutputLanguageMode::Cxx)
272+
printer.printCStubType(type, decl, genericArgs);
273+
else
274+
printer.printValueTypeReturnType(
275+
decl, languageMode,
276+
modifiersDelegate.mapValueTypeUseKind
277+
? (*modifiersDelegate.mapValueTypeUseKind)(
278+
ClangValueTypePrinter::TypeUseKind::CxxTypeName)
279+
: ClangValueTypePrinter::TypeUseKind::CxxTypeName,
280+
moduleContext);
281+
return languageMode != OutputLanguageMode::Cxx
282+
? ClangRepresentation::representable
283+
: visitGenericArgs(genericArgs);
274284
}
275285
return ClangRepresentation::representable;
276286
}
@@ -305,8 +315,8 @@ class CFunctionSignatureTypePrinter
305315
bool isInOutParam) {
306316
if (printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
307317
return ClangRepresentation::representable;
308-
return visitValueType(BGT->getDecl(), nullptr, optionalKind, isInOutParam,
309-
BGT->getGenericArgs());
318+
return visitValueType(BGT, BGT->getDecl(), nullptr, optionalKind,
319+
isInOutParam, BGT->getGenericArgs());
310320
}
311321

312322
ClangRepresentation
@@ -737,8 +747,13 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
737747
printCallToCFunc(/*additionalParam=*/returnParam);
738748
});
739749
} else {
750+
ArrayRef<Type> genericArgs;
751+
// FIXME: Do we need to account for any sugar?
752+
if (const auto *bgt = resultTy->getAs<BoundGenericType>())
753+
genericArgs = bgt->getGenericArgs();
740754
valueTypePrinter.printValueTypeDirectReturnScaffold(
741-
decl, moduleContext,
755+
decl, genericArgs, moduleContext,
756+
[&]() { printTypeImplTypeSpecifier(resultTy, moduleContext); },
742757
[&]() { printCallToCFunc(/*additionalParam=*/None); });
743758
}
744759
return;

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 46 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "OutputLanguageMode.h"
1616
#include "PrimitiveTypeMapping.h"
1717
#include "SwiftToClangInteropContext.h"
18+
#include "swift/AST/ASTMangler.h"
1819
#include "swift/AST/Decl.h"
1920
#include "swift/AST/ParameterList.h"
2021
#include "swift/AST/Type.h"
@@ -27,11 +28,22 @@
2728
using namespace swift;
2829

2930
/// Print out the C type name of a struct/enum declaration.
30-
static void printCTypeName(raw_ostream &os, const NominalTypeDecl *type) {
31+
static void printCTypeName(raw_ostream &os, const NominalTypeDecl *type,
32+
ArrayRef<Type> genericArgs = {}) {
3133
ClangSyntaxPrinter printer(os);
3234
printer.printModuleNameCPrefix(*type->getParentModule());
3335
// FIXME: add nested type qualifiers to fully disambiguate the name.
3436
printer.printBaseName(type);
37+
if (!genericArgs.empty()) {
38+
os << '_';
39+
llvm::interleave(
40+
genericArgs, os,
41+
[&](Type t) {
42+
swift::Mangle::ASTMangler mangler;
43+
os << mangler.mangleTypeWithoutPrefix(t);
44+
},
45+
"_");
46+
}
3547
}
3648

3749
/// Print out the C++ type name of a struct/enum declaration.
@@ -402,29 +414,19 @@ void ClangValueTypePrinter::printValueTypeDecl(
402414
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName);
403415
}
404416

405-
/// Print the name of the C stub struct for passing/returning a value type
406-
/// directly to/from swiftcc function.
407-
static void printStubCTypeName(raw_ostream &os, const NominalTypeDecl *type) {
408-
os << "swift_interop_stub_";
409-
printCTypeName(os, type);
410-
}
411-
412417
/// Print out the C stub struct that's used to pass/return a value type directly
413418
/// to/from swiftcc function.
414419
static void
415-
printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
420+
printCStructStubForDirectPassing(raw_ostream &os, StringRef stubName, Type type,
416421
PrimitiveTypeMapping &typeMapping,
417422
SwiftToClangInteropContext &interopContext) {
418423
// Print out a C stub for this value type.
419424
os << "// Stub struct to be used to pass/return values to/from Swift "
420425
"functions.\n";
421-
os << "struct ";
422-
printStubCTypeName(os, SD);
423-
os << " {\n";
426+
os << "struct " << stubName << " {\n";
424427
llvm::SmallVector<std::pair<clang::CharUnits, clang::CharUnits>, 8> fields;
425428
interopContext.getIrABIDetails().enumerateDirectPassingRecordMembers(
426-
SD->getDeclaredType(),
427-
[&](clang::CharUnits offset, clang::CharUnits end, Type t) {
429+
type, [&](clang::CharUnits offset, clang::CharUnits end, Type t) {
428430
auto info =
429431
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
430432
if (!info)
@@ -436,13 +438,12 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
436438
fields.push_back(std::make_pair(offset, end));
437439
});
438440
os << "};\n\n";
441+
auto minimalStubName = stubName;
442+
minimalStubName.consume_front("swift_interop_stub_");
439443

440444
// Emit a stub that returns a value directly from swiftcc function.
441-
os << "static inline void swift_interop_returnDirect_";
442-
printCTypeName(os, SD);
443-
os << "(char * _Nonnull result, struct ";
444-
printStubCTypeName(os, SD);
445-
os << " value";
445+
os << "static inline void swift_interop_returnDirect_" << minimalStubName;
446+
os << "(char * _Nonnull result, struct " << stubName << " value";
446447
os << ") __attribute__((always_inline)) {\n";
447448
for (size_t i = 0; i < fields.size(); ++i) {
448449
os << " memcpy(result + " << fields[i].first.getQuantity() << ", "
@@ -452,14 +453,10 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
452453
os << "}\n\n";
453454

454455
// Emit a stub that is used to pass value type directly to swiftcc function.
455-
os << "static inline struct ";
456-
printStubCTypeName(os, SD);
457-
os << " swift_interop_passDirect_";
458-
printCTypeName(os, SD);
456+
os << "static inline struct " << stubName << " swift_interop_passDirect_"
457+
<< minimalStubName;
459458
os << "(const char * _Nonnull value) __attribute__((always_inline)) {\n";
460-
os << " struct ";
461-
printStubCTypeName(os, SD);
462-
os << " result;\n";
459+
os << " struct " << stubName << " result;\n";
463460
for (size_t i = 0; i < fields.size(); ++i) {
464461
os << " memcpy(&result._" << (i + 1) << ", value + "
465462
<< fields[i].first.getQuantity() << ", "
@@ -469,38 +466,6 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
469466
os << "}\n\n";
470467
}
471468

472-
void ClangValueTypePrinter::printCStubTypeName(const NominalTypeDecl *type) {
473-
printStubCTypeName(os, type);
474-
// Ensure the stub is declared in the header.
475-
interopContext.runIfStubForDeclNotEmitted(type, [&]() {
476-
printCStructStubForDirectPassing(cPrologueOS, type, typeMapping,
477-
interopContext);
478-
});
479-
}
480-
481-
void ClangValueTypePrinter::printValueTypeParameterType(
482-
const NominalTypeDecl *type, OutputLanguageMode outputLang,
483-
const ModuleDecl *moduleContext, bool isInOutParam) {
484-
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
485-
if (outputLang != OutputLanguageMode::Cxx) {
486-
if (!isInOutParam) {
487-
// C functions only take stub values directly as parameters.
488-
os << "struct ";
489-
printCStubTypeName(type);
490-
} else {
491-
// Directly pass the pointer (from getOpaquePointer) to C interface
492-
// when in inout mode
493-
os << "char * _Nonnull";
494-
}
495-
return;
496-
}
497-
if (!isInOutParam) {
498-
os << "const ";
499-
}
500-
printCxxTypeName(os, type, moduleContext);
501-
os << '&';
502-
}
503-
504469
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
505470
bool isIndirect, const NominalTypeDecl *type,
506471
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
@@ -531,6 +496,7 @@ void ClangValueTypePrinter::printValueTypeReturnType(
531496
const NominalTypeDecl *type, OutputLanguageMode outputLang,
532497
TypeUseKind typeUse, const ModuleDecl *moduleContext) {
533498
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
499+
assert(outputLang == OutputLanguageMode::Cxx);
534500
// FIXME: make a type use.
535501
if (outputLang == OutputLanguageMode::Cxx) {
536502
if (typeUse == TypeUseKind::CxxTypeName)
@@ -542,12 +508,27 @@ void ClangValueTypePrinter::printValueTypeReturnType(
542508
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
543509
printCxxImplClassName(os, type);
544510
}
545-
} else {
546-
os << "struct ";
547-
printCStubTypeName(type);
548511
}
549512
}
550513

514+
void ClangValueTypePrinter::printCStubType(Type type,
515+
const NominalTypeDecl *typeDecl,
516+
ArrayRef<Type> genericArgs) {
517+
os << "struct ";
518+
std::string stubName;
519+
{
520+
llvm::raw_string_ostream stubNameOS(stubName);
521+
stubNameOS << "swift_interop_stub_";
522+
printCTypeName(stubNameOS, typeDecl, genericArgs);
523+
}
524+
os << stubName;
525+
// Ensure the stub is declared in the header.
526+
interopContext.runIfStubForDeclNotEmitted(stubName, [&]() {
527+
printCStructStubForDirectPassing(cPrologueOS, stubName, type, typeMapping,
528+
interopContext);
529+
});
530+
}
531+
551532
void ClangValueTypePrinter::printValueTypeIndirectReturnScaffold(
552533
const NominalTypeDecl *type, const ModuleDecl *moduleContext,
553534
llvm::function_ref<void()> typePrinter,
@@ -562,19 +543,17 @@ void ClangValueTypePrinter::printValueTypeIndirectReturnScaffold(
562543
}
563544

564545
void ClangValueTypePrinter::printValueTypeDirectReturnScaffold(
565-
const NominalTypeDecl *type, const ModuleDecl *moduleContext,
546+
const NominalTypeDecl *type, ArrayRef<Type> genericArgs,
547+
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
566548
llvm::function_ref<void()> bodyPrinter) {
567549
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
568550
os << " return ";
569-
ClangSyntaxPrinter(os).printModuleNamespaceQualifiersIfNeeded(
570-
type->getModuleContext(), moduleContext);
571-
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
572-
printCxxImplClassName(os, type);
551+
typePrinter();
573552
os << "::returnNewValue([&](char * _Nonnull result) {\n";
574553
os << " ";
575554
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
576555
<< "swift_interop_returnDirect_";
577-
printCTypeName(os, type);
556+
printCTypeName(os, type, genericArgs);
578557
os << "(result, ";
579558
bodyPrinter();
580559
os << ");\n";

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ class ClangValueTypePrinter {
4343
void printValueTypeDecl(const NominalTypeDecl *typeDecl,
4444
llvm::function_ref<void(void)> bodyPrinter);
4545

46-
/// Print the pararameter type that referes to a Swift struct type in C/C++.
47-
void printValueTypeParameterType(const NominalTypeDecl *type,
48-
OutputLanguageMode outputLang,
49-
const ModuleDecl *moduleContext,
50-
bool isInOutParam);
51-
5246
/// Print the use of a C++ struct/enum parameter value as it's passed to the
5347
/// underlying C function that represents the native Swift function.
5448
void printParameterCxxToCUseScaffold(
@@ -71,6 +65,14 @@ class ClangValueTypePrinter {
7165
TypeUseKind typeUse,
7266
const ModuleDecl *moduleContext);
7367

68+
/// Prints out the C stub name used to pass/return value directly for the
69+
/// given value type.
70+
///
71+
/// If the C stub isn't declared yet in the emitted header, that declaration
72+
/// will be emitted by this function.
73+
void printCStubType(Type type, const NominalTypeDecl *typeDecl,
74+
ArrayRef<Type> genericArgs);
75+
7476
/// Print the supporting code that's required to indirectly return a C++
7577
/// class that represents a Swift value type as it's being indirectly passed
7678
/// from the C function that represents the native Swift function.
@@ -82,10 +84,10 @@ class ClangValueTypePrinter {
8284
/// Print the supporting code that's required to directly return a C++ class
8385
/// that represents a Swift value type as it's being returned from the C
8486
/// function that represents the native Swift function.
85-
void
86-
printValueTypeDirectReturnScaffold(const NominalTypeDecl *typeDecl,
87-
const ModuleDecl *moduleContext,
88-
llvm::function_ref<void()> bodyPrinter);
87+
void printValueTypeDirectReturnScaffold(
88+
const NominalTypeDecl *typeDecl, ArrayRef<Type> genericArgs,
89+
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
90+
llvm::function_ref<void()> bodyPrinter);
8991

9092
/// Print out the C++ type name of the implementation class that provides
9193
/// hidden access to the private class APIs.
@@ -113,13 +115,6 @@ class ClangValueTypePrinter {
113115
static void forwardDeclType(raw_ostream &os, const NominalTypeDecl *typeDecl);
114116

115117
private:
116-
/// Prints out the C stub name used to pass/return value directly for the
117-
/// given value type.
118-
///
119-
/// If the C stub isn't declared yet in the emitted header, that declaration
120-
/// will be emitted by this function.
121-
void printCStubTypeName(const NominalTypeDecl *type);
122-
123118
raw_ostream &os;
124119
raw_ostream &cPrologueOS;
125120
PrimitiveTypeMapping &typeMapping;

lib/PrintAsClang/SwiftToClangInteropContext.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ IRABIDetailsProvider &SwiftToClangInteropContext::getIrABIDetails() {
2828
}
2929

3030
void SwiftToClangInteropContext::runIfStubForDeclNotEmitted(
31-
const Decl *d, llvm::function_ref<void(void)> function) {
32-
auto result = emittedStubs.insert(d);
31+
StringRef stubName, llvm::function_ref<void(void)> function) {
32+
auto result = emittedStubs.insert(stubName);
3333
if (result.second)
3434
function();
3535
}

0 commit comments

Comments
 (0)