Skip to content

Commit 031b779

Browse files
committed
[interop][SwiftToCxx] add support for returning generic types bounded to concrete generic params
1 parent c526ac8 commit 031b779

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
@@ -190,14 +190,14 @@ class CFunctionSignatureTypePrinter
190190
ClangRepresentation visitEnumType(EnumType *ET,
191191
Optional<OptionalTypeKind> optionalKind,
192192
bool isInOutParam) {
193-
return visitValueType(ET->getNominalOrBoundGenericNominal(), ET,
193+
return visitValueType(ET, ET->getNominalOrBoundGenericNominal(), ET,
194194
optionalKind, isInOutParam);
195195
}
196196

197197
ClangRepresentation visitStructType(StructType *ST,
198198
Optional<OptionalTypeKind> optionalKind,
199199
bool isInOutParam) {
200-
return visitValueType(ST->getNominalOrBoundGenericNominal(), ST,
200+
return visitValueType(ST, ST->getNominalOrBoundGenericNominal(), ST,
201201
optionalKind, isInOutParam);
202202
}
203203

@@ -218,11 +218,10 @@ class CFunctionSignatureTypePrinter
218218
return result;
219219
}
220220

221-
ClangRepresentation visitValueType(const NominalTypeDecl *decl,
222-
NominalType *NT,
223-
Optional<OptionalTypeKind> optionalKind,
224-
bool isInOutParam,
225-
ArrayRef<Type> genericArgs = {}) {
221+
ClangRepresentation
222+
visitValueType(TypeBase *type, const NominalTypeDecl *decl, NominalType *NT,
223+
Optional<OptionalTypeKind> optionalKind, bool isInOutParam,
224+
ArrayRef<Type> genericArgs = {}) {
226225
if (NT)
227226
assert(isa<StructType>(NT) || isa<EnumType>(NT));
228227
assert(isa<StructDecl>(decl) || isa<EnumDecl>(decl));
@@ -255,9 +254,14 @@ class CFunctionSignatureTypePrinter
255254
}
256255

257256
} else if (languageMode != OutputLanguageMode::Cxx) {
258-
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
259-
.printValueTypeParameterType(decl, languageMode, moduleContext,
260-
isInOutParam);
257+
if (!isInOutParam) {
258+
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
259+
.printCStubType(type, decl, genericArgs);
260+
} else {
261+
// Directly pass the pointer (from getOpaquePointer) to C interface
262+
// when in inout mode
263+
os << "char * _Nonnull";
264+
}
261265
} else {
262266
if (!isInOutParam) {
263267
os << "const ";
@@ -268,15 +272,21 @@ class CFunctionSignatureTypePrinter
268272
return result;
269273
}
270274
} else {
271-
ClangValueTypePrinter(os, cPrologueOS, typeMapping, interopContext)
272-
.printValueTypeReturnType(
273-
decl, languageMode,
274-
modifiersDelegate.mapValueTypeUseKind
275-
? (*modifiersDelegate.mapValueTypeUseKind)(
276-
ClangValueTypePrinter::TypeUseKind::CxxTypeName)
277-
: ClangValueTypePrinter::TypeUseKind::CxxTypeName,
278-
moduleContext);
279-
return visitGenericArgs(genericArgs);
275+
ClangValueTypePrinter printer(os, cPrologueOS, typeMapping,
276+
interopContext);
277+
if (languageMode != OutputLanguageMode::Cxx)
278+
printer.printCStubType(type, decl, genericArgs);
279+
else
280+
printer.printValueTypeReturnType(
281+
decl, languageMode,
282+
modifiersDelegate.mapValueTypeUseKind
283+
? (*modifiersDelegate.mapValueTypeUseKind)(
284+
ClangValueTypePrinter::TypeUseKind::CxxTypeName)
285+
: ClangValueTypePrinter::TypeUseKind::CxxTypeName,
286+
moduleContext);
287+
return languageMode != OutputLanguageMode::Cxx
288+
? ClangRepresentation::representable
289+
: visitGenericArgs(genericArgs);
280290
}
281291
return ClangRepresentation::representable;
282292
}
@@ -311,8 +321,8 @@ class CFunctionSignatureTypePrinter
311321
bool isInOutParam) {
312322
if (printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
313323
return ClangRepresentation::representable;
314-
return visitValueType(BGT->getDecl(), nullptr, optionalKind, isInOutParam,
315-
BGT->getGenericArgs());
324+
return visitValueType(BGT, BGT->getDecl(), nullptr, optionalKind,
325+
isInOutParam, BGT->getGenericArgs());
316326
}
317327

318328
ClangRepresentation
@@ -743,8 +753,13 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
743753
printCallToCFunc(/*additionalParam=*/returnParam);
744754
});
745755
} else {
756+
ArrayRef<Type> genericArgs;
757+
// FIXME: Do we need to account for any sugar?
758+
if (const auto *bgt = resultTy->getAs<BoundGenericType>())
759+
genericArgs = bgt->getGenericArgs();
746760
valueTypePrinter.printValueTypeDirectReturnScaffold(
747-
decl, moduleContext,
761+
decl, genericArgs, moduleContext,
762+
[&]() { printTypeImplTypeSpecifier(resultTy, moduleContext); },
748763
[&]() { printCallToCFunc(/*additionalParam=*/None); });
749764
}
750765
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.
@@ -385,29 +397,19 @@ void ClangValueTypePrinter::printValueTypeDecl(
385397
printTypeGenericTraits(os, typeDecl, typeMetadataFuncName);
386398
}
387399

388-
/// Print the name of the C stub struct for passing/returning a value type
389-
/// directly to/from swiftcc function.
390-
static void printStubCTypeName(raw_ostream &os, const NominalTypeDecl *type) {
391-
os << "swift_interop_stub_";
392-
printCTypeName(os, type);
393-
}
394-
395400
/// Print out the C stub struct that's used to pass/return a value type directly
396401
/// to/from swiftcc function.
397402
static void
398-
printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
403+
printCStructStubForDirectPassing(raw_ostream &os, StringRef stubName, Type type,
399404
PrimitiveTypeMapping &typeMapping,
400405
SwiftToClangInteropContext &interopContext) {
401406
// Print out a C stub for this value type.
402407
os << "// Stub struct to be used to pass/return values to/from Swift "
403408
"functions.\n";
404-
os << "struct ";
405-
printStubCTypeName(os, SD);
406-
os << " {\n";
409+
os << "struct " << stubName << " {\n";
407410
llvm::SmallVector<std::pair<clang::CharUnits, clang::CharUnits>, 8> fields;
408411
interopContext.getIrABIDetails().enumerateDirectPassingRecordMembers(
409-
SD->getDeclaredType(),
410-
[&](clang::CharUnits offset, clang::CharUnits end, Type t) {
412+
type, [&](clang::CharUnits offset, clang::CharUnits end, Type t) {
411413
auto info =
412414
typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal());
413415
if (!info)
@@ -419,13 +421,12 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
419421
fields.push_back(std::make_pair(offset, end));
420422
});
421423
os << "};\n\n";
424+
auto minimalStubName = stubName;
425+
minimalStubName.consume_front("swift_interop_stub_");
422426

423427
// Emit a stub that returns a value directly from swiftcc function.
424-
os << "static inline void swift_interop_returnDirect_";
425-
printCTypeName(os, SD);
426-
os << "(char * _Nonnull result, struct ";
427-
printStubCTypeName(os, SD);
428-
os << " value";
428+
os << "static inline void swift_interop_returnDirect_" << minimalStubName;
429+
os << "(char * _Nonnull result, struct " << stubName << " value";
429430
os << ") __attribute__((always_inline)) {\n";
430431
for (size_t i = 0; i < fields.size(); ++i) {
431432
os << " memcpy(result + " << fields[i].first.getQuantity() << ", "
@@ -435,14 +436,10 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
435436
os << "}\n\n";
436437

437438
// Emit a stub that is used to pass value type directly to swiftcc function.
438-
os << "static inline struct ";
439-
printStubCTypeName(os, SD);
440-
os << " swift_interop_passDirect_";
441-
printCTypeName(os, SD);
439+
os << "static inline struct " << stubName << " swift_interop_passDirect_"
440+
<< minimalStubName;
442441
os << "(const char * _Nonnull value) __attribute__((always_inline)) {\n";
443-
os << " struct ";
444-
printStubCTypeName(os, SD);
445-
os << " result;\n";
442+
os << " struct " << stubName << " result;\n";
446443
for (size_t i = 0; i < fields.size(); ++i) {
447444
os << " memcpy(&result._" << (i + 1) << ", value + "
448445
<< fields[i].first.getQuantity() << ", "
@@ -452,38 +449,6 @@ printCStructStubForDirectPassing(raw_ostream &os, const NominalTypeDecl *SD,
452449
os << "}\n\n";
453450
}
454451

455-
void ClangValueTypePrinter::printCStubTypeName(const NominalTypeDecl *type) {
456-
printStubCTypeName(os, type);
457-
// Ensure the stub is declared in the header.
458-
interopContext.runIfStubForDeclNotEmitted(type, [&]() {
459-
printCStructStubForDirectPassing(cPrologueOS, type, typeMapping,
460-
interopContext);
461-
});
462-
}
463-
464-
void ClangValueTypePrinter::printValueTypeParameterType(
465-
const NominalTypeDecl *type, OutputLanguageMode outputLang,
466-
const ModuleDecl *moduleContext, bool isInOutParam) {
467-
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
468-
if (outputLang != OutputLanguageMode::Cxx) {
469-
if (!isInOutParam) {
470-
// C functions only take stub values directly as parameters.
471-
os << "struct ";
472-
printCStubTypeName(type);
473-
} else {
474-
// Directly pass the pointer (from getOpaquePointer) to C interface
475-
// when in inout mode
476-
os << "char * _Nonnull";
477-
}
478-
return;
479-
}
480-
if (!isInOutParam) {
481-
os << "const ";
482-
}
483-
printCxxTypeName(os, type, moduleContext);
484-
os << '&';
485-
}
486-
487452
void ClangValueTypePrinter::printParameterCxxToCUseScaffold(
488453
bool isIndirect, const NominalTypeDecl *type,
489454
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
@@ -514,6 +479,7 @@ void ClangValueTypePrinter::printValueTypeReturnType(
514479
const NominalTypeDecl *type, OutputLanguageMode outputLang,
515480
TypeUseKind typeUse, const ModuleDecl *moduleContext) {
516481
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
482+
assert(outputLang == OutputLanguageMode::Cxx);
517483
// FIXME: make a type use.
518484
if (outputLang == OutputLanguageMode::Cxx) {
519485
if (typeUse == TypeUseKind::CxxTypeName)
@@ -525,12 +491,27 @@ void ClangValueTypePrinter::printValueTypeReturnType(
525491
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
526492
printCxxImplClassName(os, type);
527493
}
528-
} else {
529-
os << "struct ";
530-
printCStubTypeName(type);
531494
}
532495
}
533496

497+
void ClangValueTypePrinter::printCStubType(Type type,
498+
const NominalTypeDecl *typeDecl,
499+
ArrayRef<Type> genericArgs) {
500+
os << "struct ";
501+
std::string stubName;
502+
{
503+
llvm::raw_string_ostream stubNameOS(stubName);
504+
stubNameOS << "swift_interop_stub_";
505+
printCTypeName(stubNameOS, typeDecl, genericArgs);
506+
}
507+
os << stubName;
508+
// Ensure the stub is declared in the header.
509+
interopContext.runIfStubForDeclNotEmitted(stubName, [&]() {
510+
printCStructStubForDirectPassing(cPrologueOS, stubName, type, typeMapping,
511+
interopContext);
512+
});
513+
}
514+
534515
void ClangValueTypePrinter::printValueTypeIndirectReturnScaffold(
535516
const NominalTypeDecl *type, const ModuleDecl *moduleContext,
536517
llvm::function_ref<void()> typePrinter,
@@ -545,19 +526,17 @@ void ClangValueTypePrinter::printValueTypeIndirectReturnScaffold(
545526
}
546527

547528
void ClangValueTypePrinter::printValueTypeDirectReturnScaffold(
548-
const NominalTypeDecl *type, const ModuleDecl *moduleContext,
529+
const NominalTypeDecl *type, ArrayRef<Type> genericArgs,
530+
const ModuleDecl *moduleContext, llvm::function_ref<void()> typePrinter,
549531
llvm::function_ref<void()> bodyPrinter) {
550532
assert(isa<StructDecl>(type) || isa<EnumDecl>(type));
551533
os << " return ";
552-
ClangSyntaxPrinter(os).printModuleNamespaceQualifiersIfNeeded(
553-
type->getModuleContext(), moduleContext);
554-
os << cxx_synthesis::getCxxImplNamespaceName() << "::";
555-
printCxxImplClassName(os, type);
534+
typePrinter();
556535
os << "::returnNewValue([&](char * _Nonnull result) {\n";
557536
os << " ";
558537
os << cxx_synthesis::getCxxImplNamespaceName() << "::"
559538
<< "swift_interop_returnDirect_";
560-
printCTypeName(os, type);
539+
printCTypeName(os, type, genericArgs);
561540
os << "(result, ";
562541
bodyPrinter();
563542
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)