Skip to content
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
4 changes: 4 additions & 0 deletions lib/PrintAsClang/DeclAndTypePrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@

#include "OutputLanguageMode.h"

#include "PrintClangFunction.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/Type.h"
// for OptionalTypeKind
#include "swift/AST/TypeRepr.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "llvm/ADT/StringSet.h"

Expand Down Expand Up @@ -56,6 +58,7 @@ class DeclAndTypePrinter {
private:
class Implementation;
friend class Implementation;
friend class DeclAndTypeClangFunctionPrinter;

ModuleDecl &M;
raw_ostream &os;
Expand All @@ -69,6 +72,7 @@ class DeclAndTypePrinter {
bool requiresExposedAttribute;
llvm::StringSet<> &exposedModules;
OutputLanguageMode outputLang;
llvm::DenseMap<Type, std::optional<ClangRepresentation>> typeRepresentations;

/// The name 'CFTypeRef'.
///
Expand Down
18 changes: 16 additions & 2 deletions lib/PrintAsClang/PrintClangFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1895,13 +1895,27 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::getTypeRepresentation(
PrimitiveTypeMapping &typeMapping,
SwiftToClangInteropContext &interopContext, DeclAndTypePrinter &declPrinter,
const ModuleDecl *emittedModule, Type ty) {
auto [it, inserted] = declPrinter.typeRepresentations.try_emplace(ty);
// If we already seen the type but do not have a representation yet assume
// representable for now. This can happen for recursive types like:
//
// public enum E {
// case foo([E?])
// }
//
// We make a decision about these types when the function that first
// encountered them returns.
if (!inserted)
return it->second ? (*it->second) : ClangRepresentation::representable;
CFunctionSignatureTypePrinterModifierDelegate delegate;
CFunctionSignatureTypePrinter typePrinter(
llvm::nulls(), llvm::nulls(), typeMapping, OutputLanguageMode::Cxx,
interopContext, delegate, emittedModule, declPrinter,
FunctionSignatureTypeUse::TypeReference);
return typePrinter.visit(ty, OptionalTypeKind::OTK_None,
/*isInOutParam=*/false);
auto result = typePrinter.visit(ty, OptionalTypeKind::OTK_None,
/*isInOutParam=*/false);
declPrinter.typeRepresentations[ty] = result;
return result;
}

void DeclAndTypeClangFunctionPrinter::printTypeName(
Expand Down
12 changes: 12 additions & 0 deletions test/Interop/SwiftToCxx/enums/recursive-enum.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -module-name Enums -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/enums.h
// RUN: %FileCheck %s < %t/enums.h

// RUN: %check-interop-cxx-header-in-clang(%t/enums.h -Wno-unused-private-field -Wno-unused-function -DSWIFT_CXX_INTEROP_HIDE_STL_OVERLAY)

public enum E {
case foo([E?])
}

// CHECK: class SWIFT_SYMBOL("s:5Enums1EO") E final {
// CHECK: SWIFT_INLINE_THUNK swift::Array<swift::Optional<E>> getFoo() const;