Skip to content

[cxx-interop] Support types nested in extensions #82712

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions lib/AST/SwiftNameTranslation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,6 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
auto r = ctx.getIdentifier(os.str());
return r.str();
}

// FIXME: String.Index should be exposed as String::Index, not
// _String_Index.
if (VD->getBaseIdentifier().str() == "Index") {
return "String_Index";
}
}

return VD->getBaseIdentifier().str();
Expand Down
21 changes: 14 additions & 7 deletions lib/PrintAsClang/ClangSyntaxPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/SwiftNameTranslation.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Assertions.h"
#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -131,20 +132,25 @@ void ClangSyntaxPrinter::printClangTypeReference(const clang::Decl *typeDecl) {
bool ClangSyntaxPrinter::printNestedTypeNamespaceQualifiers(const ValueDecl *D,
bool forC) const {
bool first = true;
while (auto parent = dyn_cast_or_null<NominalTypeDecl>(
D->getDeclContext()->getAsDecl())) {
while (auto parent = D->getDeclContext()->getAsDecl()) {
const auto *parentNTD = dyn_cast<NominalTypeDecl>(parent);
if (!parentNTD)
if (const auto *ED = dyn_cast<ExtensionDecl>(parent))
parentNTD = ED->getExtendedNominal();
if (!parentNTD)
continue;
// C++ namespaces are imported as enums.
if (parent->hasClangNode() &&
isa<clang::NamespaceDecl>(parent->getClangNode().getAsDecl()))
if (parentNTD->hasClangNode() &&
isa<clang::NamespaceDecl>(parentNTD->getClangNode().getAsDecl()))
break;
if (!first)
os << (forC ? "_" : "::");
first = false;
if (!forC)
os << "__";
printBaseName(parent);
printBaseName(parentNTD);
os << "Nested";
D = parent;
D = parentNTD;
}
return first;
}
Expand Down Expand Up @@ -207,7 +213,8 @@ void ClangSyntaxPrinter::printNamespace(
void ClangSyntaxPrinter::printParentNamespaceForNestedTypes(
const ValueDecl *D, llvm::function_ref<void(raw_ostream &OS)> bodyPrinter,
NamespaceTrivia trivia) const {
if (!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl()) ||
if ((!isa_and_nonnull<NominalTypeDecl>(D->getDeclContext()->getAsDecl()) &&
!isa_and_nonnull<ExtensionDecl>(D->getDeclContext()->getAsDecl())) ||
importer::isClangNamespace(D->getDeclContext())) {
bodyPrinter(os);
return;
Expand Down
8 changes: 8 additions & 0 deletions lib/PrintAsClang/ModuleContentsWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,10 @@ class ModuleWriter {
return false;

(void)forwardDeclareMemberTypes(CD->getAllMembers(), CD);
for (const auto *ed :
printer.getInteropContext().getExtensionsForNominalType(CD)) {
(void)forwardDeclareMemberTypes(ed->getAllMembers(), CD);
}
auto [it, inserted] =
seenTypes.try_emplace(CD, EmissionState::NotYetDefined, false);
if (outputLangMode == OutputLanguageMode::Cxx &&
Expand Down Expand Up @@ -868,6 +872,10 @@ class ModuleWriter {

if (outputLangMode == OutputLanguageMode::Cxx) {
forwardDeclareMemberTypes(ED->getAllMembers(), ED);
for (const auto *ed :
printer.getInteropContext().getExtensionsForNominalType(ED)) {
(void)forwardDeclareMemberTypes(ed->getAllMembers(), ED);
}
forwardDeclareCxxValueTypeIfNeeded(ED);
}

Expand Down
14 changes: 7 additions & 7 deletions test/Interop/SwiftToCxx/stdlib/swift-stdlib-in-cxx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
// CHECK: }
// CHECK-NEXT: static SWIFT_INLINE_THUNK String init() SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK void append(const String& other)
// CHECK: SWIFT_INLINE_THUNK UTF8View getUtf8() const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: SWIFT_INLINE_THUNK void setUtf8(const UTF8View& newValue) SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK __StringNested::UTF8View getUtf8() const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: SWIFT_INLINE_THUNK void setUtf8(const __StringNested::UTF8View& newValue) SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK operator NSString * _Nonnull () const noexcept {
// CHECK-NEXT: return (__bridge_transfer NSString *)(_impl::$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF(_impl::swift_interop_passDirect_Swift_String(_getOpaquePointer())));
// CHECK-NEXT: }
Expand Down Expand Up @@ -120,11 +120,11 @@
// CHECK: class SWIFT_SYMBOL({{.*}}) UTF8View final {
// CHECK: SWIFT_INLINE_PRIVATE_HELPER UTF8View(UTF8View &&) noexcept {
// CHECK: }
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getStartIndex() const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: SWIFT_INLINE_THUNK String_Index getEndIndex() const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK swift::Optional<String_Index> indexOffsetByLimitedBy(const String_Index& i, swift::Int n, const String_Index& limit) const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK swift::Int distanceFromTo(const String_Index& i, const String_Index& j) const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK uint8_t operator [](const String_Index& i) const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: SWIFT_INLINE_THUNK __StringNested::Index getStartIndex() const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: SWIFT_INLINE_THUNK __StringNested::Index getEndIndex() const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK swift::Optional<__StringNested::Index> indexOffsetByLimitedBy(const __StringNested::Index& i, swift::Int n, const __StringNested::Index& limit) const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK swift::Int distanceFromTo(const __StringNested::Index& i, const __StringNested::Index& j) const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK uint8_t operator [](const __StringNested::Index& i) const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK String getDescription() const SWIFT_SYMBOL({{.*}});
// CHECK: SWIFT_INLINE_THUNK swift::Int getCount() const SWIFT_SYMBOL({{.*}});
// CHECK-NEXT: private:
Expand Down
13 changes: 13 additions & 0 deletions test/Interop/SwiftToCxx/structs/nested-structs-in-cxx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ extension RecordConfig.File {
public func getFileExtension() -> String { ".wav" }
}

extension RecordConfig {
public struct NestedInExtension {
public var foo: Int
}
}

extension AudioFileType {
public struct NestedInExtension {
public var foo: Int
}
}


public func getFiles() -> [RecordConfig.File] {
[]
}