Skip to content

Commit d5c531f

Browse files
committed
[interop][SwiftToCxx] experimentally expose exposable Swift's Array members to C++
1 parent 1a449f5 commit d5c531f

File tree

5 files changed

+80
-16
lines changed

5 files changed

+80
-16
lines changed

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,6 +1818,8 @@ class DeclAndTypePrinter::Implementation
18181818
}
18191819

18201820
void visitSubscriptDecl(SubscriptDecl *SD) {
1821+
if (outputLang == OutputLanguageMode::Cxx)
1822+
return;
18211823
assert(SD->isInstanceMember() && "static subscripts not supported");
18221824

18231825
bool isNSUIntegerSubscript = false;
@@ -2522,9 +2524,9 @@ static bool isAsyncAlternativeOfOtherDecl(const ValueDecl *VD) {
25222524
return false;
25232525
}
25242526

2525-
static bool hasExposeAttr(const ValueDecl *VD) {
2527+
static bool hasExposeAttr(const ValueDecl *VD, bool isExtension = false) {
25262528
if (isa<NominalTypeDecl>(VD) && VD->getModuleContext()->isStdlibModule()) {
2527-
if (VD == VD->getASTContext().getStringDecl())
2529+
if (VD == VD->getASTContext().getStringDecl() && !isExtension)
25282530
return true;
25292531
if (VD == VD->getASTContext().getArrayDecl())
25302532
return true;
@@ -2534,6 +2536,26 @@ static bool hasExposeAttr(const ValueDecl *VD) {
25342536
return true;
25352537
if (const auto *NMT = dyn_cast<NominalTypeDecl>(VD->getDeclContext()))
25362538
return hasExposeAttr(NMT);
2539+
if (const auto *ED = dyn_cast<ExtensionDecl>(VD->getDeclContext())) {
2540+
// FIXME: Do not expose 'index' methods as the overloads are conflicting.
2541+
// this should either be prohibited in the stdlib module, or the overloads
2542+
// should be renamed automatically or using the expose attribute.
2543+
if (ED->getExtendedNominal() == VD->getASTContext().getArrayDecl()) {
2544+
if (isa<AbstractFunctionDecl>(VD) &&
2545+
!cast<AbstractFunctionDecl>(VD)
2546+
->getName()
2547+
.getBaseName()
2548+
.isSpecial() &&
2549+
cast<AbstractFunctionDecl>(VD)
2550+
->getName()
2551+
.getBaseName()
2552+
.getIdentifier()
2553+
.str()
2554+
.contains_insensitive("index"))
2555+
return false;
2556+
}
2557+
return hasExposeAttr(ED->getExtendedNominal(), /*isExtension=*/true);
2558+
}
25372559
return false;
25382560
}
25392561

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,11 @@ class ModuleWriter {
227227

228228
void forwardDeclare(const NominalTypeDecl *NTD,
229229
llvm::function_ref<void(void)> Printer) {
230-
if (NTD->getModuleContext()->isStdlibModule())
231-
return;
230+
if (NTD->getModuleContext()->isStdlibModule()) {
231+
if (outputLangMode != OutputLanguageMode::Cxx ||
232+
!printer.shouldInclude(NTD))
233+
return;
234+
}
232235
auto &state = seenTypes[NTD];
233236
if (state.second)
234237
return;

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ class CFunctionSignatureTypePrinter
295295
if (!declPrinter.shouldInclude(decl))
296296
return ClangRepresentation::unsupported; // FIXME: propagate why it's not
297297
// exposed.
298-
298+
// FIXME: Support Optional<T>.
299+
if (optionalKind && *optionalKind != OTK_None)
300+
return ClangRepresentation::unsupported;
299301
// Only C++ mode supports struct types.
300302
if (languageMode != OutputLanguageMode::Cxx)
301303
return ClangRepresentation::unsupported;
@@ -337,36 +339,45 @@ class CFunctionSignatureTypePrinter
337339
return ClangRepresentation::representable;
338340
}
339341

340-
bool printIfKnownGenericStruct(const BoundGenericStructType *BGT,
341-
Optional<OptionalTypeKind> optionalKind,
342-
bool isInOutParam) {
342+
Optional<ClangRepresentation>
343+
printIfKnownGenericStruct(const BoundGenericStructType *BGT,
344+
Optional<OptionalTypeKind> optionalKind,
345+
bool isInOutParam) {
343346
auto bgsTy = Type(const_cast<BoundGenericStructType *>(BGT));
344347
bool isConst;
345348
if (bgsTy->isUnsafePointer())
346349
isConst = true;
347350
else if (bgsTy->isUnsafeMutablePointer())
348351
isConst = false;
349352
else
350-
return false;
353+
return None;
351354

352355
auto args = BGT->getGenericArgs();
353356
assert(args.size() == 1);
354-
visitPart(args.front(), OTK_None, /*isInOutParam=*/false);
357+
llvm::SaveAndRestore<FunctionSignatureTypeUse> typeUseNormal(
358+
typeUseKind, FunctionSignatureTypeUse::TypeReference);
359+
// FIXME: We can definitely support pointers to known Clang types.
360+
if (!isKnownCType(args.front(), typeMapping))
361+
return ClangRepresentation(ClangRepresentation::unsupported);
362+
auto partRepr = visitPart(args.front(), OTK_None, /*isInOutParam=*/false);
363+
if (partRepr.isUnsupported())
364+
return partRepr;
355365
if (isConst)
356366
os << " const";
357367
os << " *";
358368
printNullability(optionalKind);
359369
if (isInOutParam)
360370
printInoutTypeModifier();
361-
return true;
371+
return ClangRepresentation(ClangRepresentation::representable);
362372
}
363373

364374
ClangRepresentation
365375
visitBoundGenericStructType(BoundGenericStructType *BGT,
366376
Optional<OptionalTypeKind> optionalKind,
367377
bool isInOutParam) {
368-
if (printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
369-
return ClangRepresentation::representable;
378+
if (auto result =
379+
printIfKnownGenericStruct(BGT, optionalKind, isInOutParam))
380+
return *result;
370381
return visitValueType(BGT, BGT->getDecl(), optionalKind, isInOutParam,
371382
BGT->getGenericArgs());
372383
}
@@ -375,11 +386,17 @@ class CFunctionSignatureTypePrinter
375386
visitGenericTypeParamType(GenericTypeParamType *genericTpt,
376387
Optional<OptionalTypeKind> optionalKind,
377388
bool isInOutParam) {
389+
// FIXME: Support Optional<T>.
390+
if (optionalKind && *optionalKind != OTK_None)
391+
return ClangRepresentation::unsupported;
378392
bool isParam = typeUseKind == FunctionSignatureTypeUse::ParamType;
379393
if (isParam && !isInOutParam)
380394
os << "const ";
381395
// FIXME: handle optionalKind.
382396
if (languageMode != OutputLanguageMode::Cxx) {
397+
// Note: This can happen for UnsafeMutablePointer<T>.
398+
if (typeUseKind != FunctionSignatureTypeUse::ParamType)
399+
return ClangRepresentation::unsupported;
383400
assert(typeUseKind == FunctionSignatureTypeUse::ParamType);
384401
// Pass an opaque param in C mode.
385402
os << "void * _Nonnull";
@@ -1194,9 +1211,11 @@ void DeclAndTypeClangFunctionPrinter::printCxxPropertyAccessorMethod(
11941211
bool DeclAndTypeClangFunctionPrinter::hasKnownOptionalNullableCxxMapping(
11951212
Type type) {
11961213
if (auto optionalObjectType = type->getOptionalObjectType()) {
1197-
if (auto typeInfo = typeMapping.getKnownCxxTypeInfo(
1198-
optionalObjectType->getNominalOrBoundGenericNominal())) {
1199-
return typeInfo->canBeNullable;
1214+
if (optionalObjectType->getNominalOrBoundGenericNominal()) {
1215+
if (auto typeInfo = typeMapping.getKnownCxxTypeInfo(
1216+
optionalObjectType->getNominalOrBoundGenericNominal())) {
1217+
return typeInfo->canBeNullable;
1218+
}
12001219
}
12011220
}
12021221
return false;

test/Interop/SwiftToCxx/stdlib/array/array-execution.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,18 @@ int main() {
4242
UseArray::printArray(UseArray::passthroughArray(val));
4343
}
4444
// CHECK: [2, 2]
45+
{
46+
auto val = Array<int>::init();
47+
val.append(-11);
48+
UseArray::printArray(val);
49+
assert(val.getCount() == 1);
50+
assert(val.getCapacity() >= 1);
51+
auto firstInt = val.remove(0);
52+
assert(firstInt == -11);
53+
assert(val.getCount() == 0);
54+
UseArray::printArray(val);
55+
}
56+
// CHECK-NEXT: [-11]
57+
// CHECK-NEXT: []
4558
return 0;
4659
}

test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
// CHECK: namespace Swift {
88

9+
// CHECK: class String;
10+
911
// CHECK: template<class T_0_0>
1012
// CHECK: template<class T_0_0>
1113
// CHECK-NEXT: requires swift::isUsableInGenericContext<T_0_0>
@@ -15,6 +17,11 @@
1517
// CHECK: }
1618
// CHECK-NEXT: inline Array(const Array &other) {
1719
// CHECK: }
20+
// CHECK: static inline Array<T_0_0> init();
21+
// CHECK: inline void append(const T_0_0& newElement);
22+
// CHECK: inline T_0_0 remove(swift::Int index);
23+
// CHECK: inline swift::Int getCount() const;
24+
// CHECK: inline swift::Int getCapacity() const;
1825

1926
// CHECK: class String final {
2027
// CHECK-NEXT: public:

0 commit comments

Comments
 (0)