Skip to content

Commit 290e527

Browse files
committed
[Interop][SwiftToCxx] Initial support for getting associated values from enum
improve test cases add support for primitive types
1 parent 1f9ffc0 commit 290e527

10 files changed

+498
-174
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,13 @@ class DeclAndTypePrinter::Implementation
388388
}
389389

390390
void visitEnumDeclCxx(EnumDecl *ED) {
391+
assert(owningPrinter.outputLang == OutputLanguageMode::Cxx);
392+
391393
// FIXME: Print enum's availability
392-
ClangValueTypePrinter printer(os, owningPrinter.prologueOS,
393-
owningPrinter.typeMapping,
394-
owningPrinter.interopContext);
395-
printer.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
394+
ClangValueTypePrinter valueTypePrinter(os, owningPrinter.prologueOS,
395+
owningPrinter.typeMapping,
396+
owningPrinter.interopContext);
397+
valueTypePrinter.printValueTypeDecl(ED, /*bodyPrinter=*/[&]() {
396398
ClangSyntaxPrinter syntaxPrinter(os);
397399
auto elementTagMapping =
398400
owningPrinter.interopContext.getIrABIDetails().getEnumTagMapping(ED);
@@ -418,6 +420,7 @@ class DeclAndTypePrinter::Implementation
418420
os << " inline operator cases() const {\n";
419421
os << " switch (_getEnumTag()) {\n";
420422
for (const auto &pair : elementTagMapping) {
423+
// TODO: have to use global variable for resilient enum
421424
os << " case " << pair.second << ": return cases::";
422425
syntaxPrinter.printIdentifier(pair.first->getNameStr());
423426
os << ";\n";
@@ -427,7 +430,11 @@ class DeclAndTypePrinter::Implementation
427430
os << " }\n"; // switch's closing bracket
428431
os << " }\n"; // operator cases()'s closing bracket
429432

430-
// Printing predicates
433+
// Printing case-related functions
434+
DeclAndTypeClangFunctionPrinter clangFuncPrinter(
435+
os, owningPrinter.prologueOS, owningPrinter.typeMapping,
436+
owningPrinter.interopContext);
437+
431438
for (const auto &pair : elementTagMapping) {
432439
os << " inline bool is";
433440
auto name = pair.first->getNameStr().str();
@@ -436,6 +443,54 @@ class DeclAndTypePrinter::Implementation
436443
os << " return *this == cases::";
437444
syntaxPrinter.printIdentifier(pair.first->getNameStr());
438445
os << ";\n }\n";
446+
447+
if (!pair.first->hasAssociatedValues()) {
448+
continue;
449+
}
450+
451+
auto associatedValueList = pair.first->getParameterList();
452+
// TODO: add tuple type support
453+
if (associatedValueList->size() > 1) {
454+
continue;
455+
}
456+
auto firstType = associatedValueList->front()->getType();
457+
auto firstTypeDecl = firstType->getNominalOrBoundGenericNominal();
458+
OptionalTypeKind optKind;
459+
std::tie(firstType, optKind) =
460+
getObjectTypeAndOptionality(firstTypeDecl, firstType);
461+
462+
// FIXME: (tongjie) may have to forward declare return type
463+
os << " inline ";
464+
clangFuncPrinter.printClangFunctionReturnType(
465+
firstType, optKind, firstTypeDecl->getModuleContext(),
466+
owningPrinter.outputLang);
467+
os << " get" << name << "() const {\n";
468+
os << " if (!is" << name << "()) abort();\n";
469+
os << " auto thisCopy = *this;\n";
470+
os << " char * _Nonnull payloadFromDestruction = "
471+
"thisCopy._destructiveProjectEnumData();\n";
472+
if (auto knownCxxType =
473+
owningPrinter.typeMapping.getKnownCxxTypeInfo(firstTypeDecl)) {
474+
os << " ";
475+
clangFuncPrinter.printClangFunctionReturnType(
476+
firstType, optKind, firstTypeDecl->getModuleContext(),
477+
owningPrinter.outputLang);
478+
os << " result;\n";
479+
os << " "
480+
"memcpy(&result, payloadFromDestruction, sizeof(result));\n";
481+
os << " return result;\n";
482+
} else {
483+
os << " return " << cxx_synthesis::getCxxImplNamespaceName();
484+
os << "::";
485+
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
486+
os << "::returnNewValue([&](char * _Nonnull result) {\n";
487+
os << " " << cxx_synthesis::getCxxImplNamespaceName();
488+
os << "::";
489+
ClangValueTypePrinter::printCxxImplClassName(os, firstTypeDecl);
490+
os << "::initializeWithTake(result, payloadFromDestruction);\n";
491+
os << " });\n";
492+
}
493+
os << " }\n";
439494
}
440495
os << "\n";
441496
});

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,17 @@ class CFunctionSignatureTypePrinter
194194

195195
} // end namespace
196196

197+
void DeclAndTypeClangFunctionPrinter::printClangFunctionReturnType(
198+
Type ty, OptionalTypeKind optKind, ModuleDecl *moduleContext,
199+
OutputLanguageMode outputLang) {
200+
CFunctionSignatureTypePrinter typePrinter(
201+
os, cPrologueOS, typeMapping, outputLang, interopContext,
202+
CFunctionSignatureTypePrinterModifierDelegate(), moduleContext,
203+
FunctionSignatureTypeUse::ReturnType);
204+
// Param for indirect return cannot be marked as inout
205+
typePrinter.visit(ty, optKind, /*isInOutParam=*/false);
206+
}
207+
197208
void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
198209
const AbstractFunctionDecl *FD, StringRef name, Type resultTy,
199210
FunctionSignatureKind kind, ArrayRef<AdditionalParam> additionalParams,
@@ -231,12 +242,7 @@ void DeclAndTypeClangFunctionPrinter::printFunctionSignature(
231242
Type objTy;
232243
std::tie(objTy, retKind) =
233244
DeclAndTypePrinter::getObjectTypeAndOptionality(FD, resultTy);
234-
CFunctionSignatureTypePrinter typePrinter(
235-
os, cPrologueOS, typeMapping, outputLang, interopContext,
236-
CFunctionSignatureTypePrinterModifierDelegate(), emittedModule,
237-
FunctionSignatureTypeUse::ReturnType);
238-
// Param for indirect return cannot be marked as inout
239-
typePrinter.visit(objTy, retKind, /*isInOutParam=*/false);
245+
printClangFunctionReturnType(objTy, retKind, emittedModule, outputLang);
240246
} else {
241247
os << "void";
242248
}

lib/PrintAsClang/PrintClangFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
#ifndef SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
1414
#define SWIFT_PRINTASCLANG_PRINTCLANGFUNCTION_H
1515

16+
#include "OutputLanguageMode.h"
1617
#include "swift/AST/Type.h"
1718
#include "swift/Basic/LLVM.h"
19+
#include "swift/ClangImporter/ClangImporter.h"
1820
#include "llvm/ADT/ArrayRef.h"
1921
#include "llvm/ADT/Optional.h"
2022
#include "llvm/ADT/StringRef.h"
@@ -100,6 +102,11 @@ class DeclAndTypeClangFunctionPrinter {
100102
StringRef swiftSymbolName, Type resultTy,
101103
bool isDefinition);
102104

105+
/// Print Swift type as C/C++ type, as the return type of a C/C++ function.
106+
void printClangFunctionReturnType(Type ty, OptionalTypeKind optKind,
107+
ModuleDecl *moduleContext,
108+
OutputLanguageMode outputLang);
109+
103110
private:
104111
void printCxxToCFunctionParameterUse(
105112
Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut,

lib/PrintAsClang/PrintClangValueType.cpp

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,30 @@ static void printCxxTypeName(raw_ostream &os, const NominalTypeDecl *type,
4444
printer.printBaseName(type);
4545
}
4646

47-
/// Print out the C++ type name of the implementation class that provides hidden
48-
/// access to the private class APIs.
49-
static void printCxxImplClassName(raw_ostream &os,
50-
const NominalTypeDecl *type) {
47+
void ClangValueTypePrinter::printCxxImplClassName(raw_ostream &os,
48+
const NominalTypeDecl *type) {
5149
os << "_impl_";
5250
ClangSyntaxPrinter(os).printBaseName(type);
5351
}
5452

53+
void ClangValueTypePrinter::printMetadataAccessAsVariable(
54+
raw_ostream &os, StringRef metadataFuncName, int indent,
55+
StringRef varName) {
56+
ClangSyntaxPrinter printer(os);
57+
os << std::string(indent, ' ') << "auto " << varName << " = "
58+
<< cxx_synthesis::getCxxImplNamespaceName() << "::";
59+
printer.printSwiftTypeMetadataAccessFunctionCall(metadataFuncName);
60+
os << ";\n";
61+
}
62+
63+
void ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
64+
raw_ostream &os, StringRef metadataFuncName, int indent,
65+
StringRef metadataVarName, StringRef vwTableVarName) {
66+
ClangSyntaxPrinter printer(os);
67+
printMetadataAccessAsVariable(os, metadataFuncName, indent, metadataVarName);
68+
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
69+
}
70+
5571
static void
5672
printCValueTypeStorageStruct(raw_ostream &os, const NominalTypeDecl *typeDecl,
5773
IRABIDetailsProvider::SizeAndAlignment layout) {
@@ -111,6 +127,18 @@ void ClangValueTypePrinter::printValueTypeDecl(
111127
typeMetadataFuncName);
112128
});
113129

130+
auto printEnumVWTableVariable = [&](StringRef metadataName = "metadata",
131+
StringRef vwTableName = "vwTable",
132+
StringRef enumVWTableName =
133+
"enumVWTable") {
134+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
135+
os, typeMetadataFuncName);
136+
os << " const auto *" << enumVWTableName << " = reinterpret_cast<";
137+
ClangSyntaxPrinter(os).printSwiftImplQualifier();
138+
os << "EnumValueWitnessTable";
139+
os << " *>(" << vwTableName << ");\n";
140+
};
141+
114142
// Print out the C++ class itself.
115143
os << "class ";
116144
ClangSyntaxPrinter(os).printBaseName(typeDecl);
@@ -121,11 +149,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
121149
os << " inline ~";
122150
printer.printBaseName(typeDecl);
123151
os << "() {\n";
124-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
125-
<< "::";
126-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
127-
os << ";\n";
128-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
152+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
153+
os, typeMetadataFuncName);
129154
os << " vwTable->destroy(_getOpaquePointer(), metadata._0);\n";
130155
os << " }\n";
131156

@@ -134,11 +159,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
134159
os << "(const ";
135160
printer.printBaseName(typeDecl);
136161
os << " &other) {\n";
137-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
138-
<< "::";
139-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
140-
os << ";\n";
141-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
162+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
163+
os, typeMetadataFuncName);
142164
if (isOpaqueLayout) {
143165
os << " _storage = ";
144166
printer.printSwiftImplQualifier();
@@ -176,11 +198,8 @@ void ClangValueTypePrinter::printValueTypeDecl(
176198
os << " _make() {";
177199
if (isOpaqueLayout) {
178200
os << "\n";
179-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
180-
<< "::";
181-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
182-
os << ";\n";
183-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
201+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
202+
os, typeMetadataFuncName);
184203
os << " return ";
185204
printer.printBaseName(typeDecl);
186205
os << "(vwTable);\n }\n";
@@ -200,19 +219,17 @@ void ClangValueTypePrinter::printValueTypeDecl(
200219
os << ".getOpaquePointer()";
201220
os << "; }\n";
202221
os << "\n";
203-
// Print out helper function for getting enum tag for enum type
222+
// Print out helper function for enums
204223
if (isa<EnumDecl>(typeDecl)) {
224+
os << " inline char * _Nonnull _destructiveProjectEnumData() {\n";
225+
printEnumVWTableVariable();
226+
os << " enumVWTable->destructiveProjectEnumData(_getOpaquePointer(), "
227+
"metadata._0);\n";
228+
os << " return _getOpaquePointer();\n";
229+
os << " }\n";
205230
// FIXME: (tongjie) return type should be unsigned
206231
os << " inline int _getEnumTag() const {\n";
207-
os << " auto metadata = " << cxx_synthesis::getCxxImplNamespaceName()
208-
<< "::";
209-
printer.printSwiftTypeMetadataAccessFunctionCall(typeMetadataFuncName);
210-
os << ";\n";
211-
printer.printValueWitnessTableAccessSequenceFromTypeMetadata("metadata");
212-
os << " const auto *enumVWTable = reinterpret_cast<";
213-
ClangSyntaxPrinter(os).printSwiftImplQualifier();
214-
os << "EnumValueWitnessTable";
215-
os << " *>(vwTable);\n";
232+
printEnumVWTableVariable();
216233
os << " return enumVWTable->getEnumTag(_getOpaquePointer(), "
217234
"metadata._0);\n";
218235
os << " }\n";
@@ -259,6 +276,17 @@ void ClangValueTypePrinter::printValueTypeDecl(
259276
os << " callable(result._getOpaquePointer());\n";
260277
os << " return result;\n";
261278
os << " }\n";
279+
// Print out helper function for initializeWithTake
280+
// TODO: (tongjie) support opaque layout
281+
if (!isOpaqueLayout) {
282+
os << " static inline void initializeWithTake(char * _Nonnull "
283+
"destStorage, char * _Nonnull srcStorage) {\n";
284+
ClangValueTypePrinter::printValueWitnessTableAccessAsVariable(
285+
os, typeMetadataFuncName);
286+
os << " vwTable->initializeWithTake(destStorage, srcStorage, "
287+
"metadata._0);\n";
288+
os << " }\n";
289+
}
262290

263291
os << "};\n";
264292
});

lib/PrintAsClang/PrintClangValueType.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ class ClangValueTypePrinter {
7676
const ModuleDecl *moduleContext,
7777
llvm::function_ref<void()> bodyPrinter);
7878

79+
/// Print out the C++ type name of the implementation class that provides
80+
/// hidden access to the private class APIs.
81+
static void printCxxImplClassName(raw_ostream &os,
82+
const NominalTypeDecl *type);
83+
84+
/// Print a variable that can be used to access type's metadata function
85+
static void printMetadataAccessAsVariable(raw_ostream &os,
86+
StringRef metadataFuncName,
87+
int indent = 4,
88+
StringRef varName = "metadata");
89+
90+
/// Print a variable that can be used to access type's metadata function and
91+
/// value witness table
92+
static void printValueWitnessTableAccessAsVariable(
93+
raw_ostream &os, StringRef metadataFuncName, int indent = 4,
94+
StringRef metadataVarName = "metadata",
95+
StringRef vwTableVarName = "vwTable");
96+
7997
private:
8098
/// Prints out the C stub name used to pass/return value directly for the
8199
/// given value type.

0 commit comments

Comments
 (0)