Skip to content

Commit 75dbd13

Browse files
committed
[interop][SwiftToCxx] add support for invoking methods in generic structs
1 parent 19120f9 commit 75dbd13

16 files changed

+330
-88
lines changed

include/swift/IRGen/IRABIDetailsProvider.h

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,45 @@ class IRABIDetailsProvider {
4949
};
5050

5151
/// Information about any ABI additional parameters.
52-
struct ABIAdditionalParam {
53-
enum class ABIParameterRole { GenericRequirementRole, Self, Error };
52+
class ABIAdditionalParam {
53+
public:
54+
enum class ABIParameterRole {
55+
/// A parameter that corresponds to a generic requirement that must be
56+
/// fullfilled by a call to this function.
57+
GenericRequirement,
58+
/// A parameter that corresponds to a Swift type pointer sourced from a
59+
/// valid metadata source, like the type of another argument.
60+
GenericTypeMetadataSource,
61+
/// A parameter that corresponds to the 'self' parameter.
62+
Self,
63+
/// The Swift error parameter.
64+
Error
65+
};
66+
67+
inline ABIParameterRole getRole() const { return role; }
68+
69+
inline GenericRequirement getGenericRequirement() {
70+
assert(role == ABIParameterRole::GenericRequirement);
71+
return *genericRequirement;
72+
}
73+
74+
inline CanType getMetadataSourceType() {
75+
assert(role == ABIParameterRole::GenericTypeMetadataSource);
76+
return canType;
77+
}
78+
79+
private:
80+
inline ABIAdditionalParam(
81+
ABIParameterRole role,
82+
llvm::Optional<GenericRequirement> genericRequirement, CanType canType)
83+
: role(role), genericRequirement(genericRequirement), canType(canType) {
84+
}
5485

5586
ABIParameterRole role;
5687
llvm::Optional<GenericRequirement> genericRequirement;
57-
TypeDecl *type;
88+
CanType canType;
89+
90+
friend class IRABIDetailsProviderImpl;
5891
};
5992

6093
/// Returns the size and alignment for the given type, or \c None if the type

lib/IRGen/GenCall.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@ namespace {
397397
unsigned AsyncResumeFunctionSwiftSelfIdx = 0;
398398
FunctionPointerKind FnKind;
399399
bool ShouldComputeABIDetails;
400-
SmallVector<GenericRequirement, 4> GenericRequirements;
400+
SmallVector<PolymorphicSignatureExpandedTypeSource, 4>
401+
polymorphicSignatureTypeSources;
401402

402403
SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
403404
FunctionPointerKind fnKind,
@@ -1631,9 +1632,9 @@ void SignatureExpansion::expandParameters() {
16311632
// Next, the generic signature.
16321633
if (hasPolymorphicParameters(FnType) &&
16331634
!FnKind.shouldSuppressPolymorphicArguments())
1634-
expandPolymorphicSignature(IGM, FnType, ParamIRTypes,
1635-
ShouldComputeABIDetails ? &GenericRequirements
1636-
: nullptr);
1635+
expandPolymorphicSignature(
1636+
IGM, FnType, ParamIRTypes,
1637+
ShouldComputeABIDetails ? &polymorphicSignatureTypeSources : nullptr);
16371638

16381639
// Certain special functions are passed the continuation directly.
16391640
if (FnKind.shouldPassContinuationDirectly()) {
@@ -1931,8 +1932,8 @@ Signature SignatureExpansion::getSignature() {
19311932
result.ExtraDataKind = ExtraData::kindForMember<void>();
19321933
}
19331934
if (ShouldComputeABIDetails)
1934-
result.ABIDetails =
1935-
SignatureExpansionABIDetails{std::move(GenericRequirements)};
1935+
result.ABIDetails = SignatureExpansionABIDetails{
1936+
std::move(polymorphicSignatureTypeSources)};
19361937
return result;
19371938
}
19381939

lib/IRGen/GenProto.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3462,26 +3462,33 @@ namespace {
34623462
: PolymorphicConvention(IGM, fn) {}
34633463

34643464
void expand(SmallVectorImpl<llvm::Type *> &out,
3465-
SmallVectorImpl<GenericRequirement> *reqs) {
3465+
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *reqs) {
3466+
auto outStartSize = out.size();
3467+
(void)outStartSize;
34663468
for (auto &source : getSources())
3467-
addEarlySource(source, out);
3469+
addEarlySource(source, out, reqs);
34683470

34693471
enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
34703472
if (reqs)
34713473
reqs->push_back(reqt);
34723474
out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
34733475
: IGM.TypeMetadataPtrTy);
34743476
});
3477+
assert((!reqs || reqs->size() == (out.size() - outStartSize)) &&
3478+
"missing type source for type");
34753479
}
34763480

34773481
private:
34783482
/// Add signature elements for the source metadata.
3479-
void addEarlySource(const MetadataSource &source,
3480-
SmallVectorImpl<llvm::Type*> &out) {
3483+
void addEarlySource(
3484+
const MetadataSource &source, SmallVectorImpl<llvm::Type *> &out,
3485+
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *reqs) {
34813486
switch (source.getKind()) {
34823487
case MetadataSource::Kind::ClassPointer: return; // already accounted for
34833488
case MetadataSource::Kind::Metadata: return; // already accounted for
34843489
case MetadataSource::Kind::GenericLValueMetadata:
3490+
if (reqs)
3491+
reqs->push_back(source);
34853492
return out.push_back(IGM.TypeMetadataPtrTy);
34863493
case MetadataSource::Kind::SelfMetadata:
34873494
case MetadataSource::Kind::SelfWitnessTable:
@@ -3498,7 +3505,7 @@ namespace {
34983505
void irgen::expandPolymorphicSignature(
34993506
IRGenModule &IGM, CanSILFunctionType polyFn,
35003507
SmallVectorImpl<llvm::Type *> &out,
3501-
SmallVectorImpl<GenericRequirement> *outReqs) {
3508+
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *outReqs) {
35023509
ExpandPolymorphicSignature(IGM, polyFn).expand(out, outReqs);
35033510
}
35043511

lib/IRGen/GenProto.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ namespace irgen {
4949
class MetadataPath;
5050
class MetadataResponse;
5151
class NativeCCEntryPointArgumentEmission;
52+
class PolymorphicSignatureExpandedTypeSource;
5253
class ProtocolInfo;
5354
class TypeInfo;
5455

@@ -103,7 +104,8 @@ namespace irgen {
103104
void expandPolymorphicSignature(
104105
IRGenModule &IGM, CanSILFunctionType type,
105106
SmallVectorImpl<llvm::Type *> &types,
106-
SmallVectorImpl<GenericRequirement> *outReqs = nullptr);
107+
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *outReqs =
108+
nullptr);
107109

108110
/// Return the number of trailing arguments necessary for calling a
109111
/// witness method.

lib/IRGen/IRABIDetailsProvider.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,30 @@ class IRABIDetailsProviderImpl {
167167
auto signature = Signature::getUncached(IGM, silFuncType, funcPointerKind,
168168
/*shouldComputeABIDetail=*/true);
169169

170-
for (const auto &reqt : signature.getABIDetails().GenericRequirements) {
171-
params.push_back({IRABIDetailsProvider::ABIAdditionalParam::
172-
ABIParameterRole::GenericRequirementRole,
173-
reqt, typeConverter.Context.getOpaquePointerDecl()});
170+
using ABIAdditionalParam = IRABIDetailsProvider::ABIAdditionalParam;
171+
using ParamRole = ABIAdditionalParam::ABIParameterRole;
172+
for (const auto &typeSource :
173+
signature.getABIDetails().polymorphicSignatureExpandedTypeSources) {
174+
typeSource.visit(
175+
[&](const GenericRequirement &reqt) {
176+
params.push_back(ABIAdditionalParam(ParamRole::GenericRequirement,
177+
reqt, CanType()));
178+
},
179+
[&](const MetadataSource &metadataSource) {
180+
auto index = metadataSource.getParamIndex();
181+
auto canType =
182+
silFuncType->getParameters()[index].getInterfaceType();
183+
params.push_back(ABIAdditionalParam(
184+
ParamRole::GenericTypeMetadataSource, llvm::None, canType));
185+
});
174186
}
175187
for (auto attrSet : signature.getAttributes()) {
176188
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftSelf))
177189
params.push_back(
178-
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self,
179-
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
190+
ABIAdditionalParam(ParamRole::Self, llvm::None, CanType()));
180191
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftError))
181192
params.push_back(
182-
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Error,
183-
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
193+
ABIAdditionalParam(ParamRole::Error, llvm::None, CanType()));
184194
}
185195
return params;
186196
}

lib/IRGen/Signature.h

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef SWIFT_IRGEN_SIGNATURE_H
1919
#define SWIFT_IRGEN_SIGNATURE_H
2020

21+
#include "MetadataSource.h"
2122
#include "swift/AST/GenericRequirement.h"
2223
#include "swift/AST/Types.h"
2324
#include "swift/Basic/ExternalUnion.h"
@@ -96,10 +97,38 @@ class AsyncInfo {
9697
uint32_t AsyncResumeFunctionSwiftSelfIdx = 0;
9798
};
9899

100+
/// Represents the source of the corresponding type pointer computed
101+
/// during the expansion of the polymorphic signature.
102+
///
103+
/// The source is either a \c GenericRequirement, or a \c MetadataSource.
104+
class PolymorphicSignatureExpandedTypeSource {
105+
public:
106+
inline PolymorphicSignatureExpandedTypeSource(
107+
const GenericRequirement &requirement)
108+
: requirement(requirement){};
109+
inline PolymorphicSignatureExpandedTypeSource(
110+
const MetadataSource &metadataSource)
111+
: metadataSource(metadataSource) {}
112+
113+
inline void
114+
visit(llvm::function_ref<void(const GenericRequirement &)> requirementVisitor,
115+
llvm::function_ref<void(const MetadataSource &)> metadataSourceVisitor)
116+
const {
117+
if (requirement)
118+
return requirementVisitor(*requirement);
119+
return metadataSourceVisitor(*metadataSource);
120+
}
121+
122+
private:
123+
llvm::Optional<GenericRequirement> requirement;
124+
llvm::Optional<MetadataSource> metadataSource;
125+
};
126+
99127
/// Recorded information about the specific ABI details.
100128
struct SignatureExpansionABIDetails {
101-
/// Generic requirements added to the signature during expansion.
102-
llvm::SmallVector<GenericRequirement, 2> GenericRequirements;
129+
/// Type sources added to the signature during expansion.
130+
llvm::SmallVector<PolymorphicSignatureExpandedTypeSource, 2>
131+
polymorphicSignatureExpandedTypeSources;
103132
};
104133

105134
/// A signature represents something which can actually be called.

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,33 @@ void ClangSyntaxPrinter::printModuleNamespaceQualifiersIfNeeded(
7070
os << "::";
7171
}
7272

73+
bool ClangSyntaxPrinter::printNominalTypeOutsideMemberDeclTemplateSpecifiers(
74+
const NominalTypeDecl *typeDecl) {
75+
// FIXME: Full qualifiers for nested types?
76+
if (!typeDecl->isGeneric())
77+
return true;
78+
printGenericSignature(
79+
typeDecl->getGenericSignature().getCanonicalSignature());
80+
return false;
81+
}
82+
83+
void ClangSyntaxPrinter::printNominalTypeReference(
84+
const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) {
85+
printModuleNamespaceQualifiersIfNeeded(typeDecl->getModuleContext(),
86+
moduleContext);
87+
// FIXME: Full qualifiers for nested types?
88+
ClangSyntaxPrinter(os).printBaseName(typeDecl);
89+
if (typeDecl->isGeneric())
90+
printGenericSignatureParams(
91+
typeDecl->getGenericSignature().getCanonicalSignature());
92+
}
93+
94+
void ClangSyntaxPrinter::printNominalTypeQualifier(
95+
const NominalTypeDecl *typeDecl, const ModuleDecl *moduleContext) {
96+
printNominalTypeReference(typeDecl, moduleContext);
97+
os << "::";
98+
}
99+
73100
/// Print a C++ namespace declaration with the give name and body.
74101
void ClangSyntaxPrinter::printNamespace(
75102
llvm::function_ref<void(raw_ostream &OS)> namePrinter,

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,43 @@ class ClangSyntaxPrinter {
6565
printModuleNamespaceQualifiersIfNeeded(const ModuleDecl *referencedModule,
6666
const ModuleDecl *currentContext);
6767

68+
/// Print out additional C++ `template` and `requires` clauses that
69+
/// are required to emit a member definition outside a C++ class that is
70+
/// generated for the given Swift type declaration.
71+
///
72+
/// \returns true if nothing was printed.
73+
///
74+
/// Examples:
75+
/// 1) For Swift's `String` type, it will print nothing.
76+
/// 2) For Swift's `Array<T>` type, it will print `template<class
77+
/// T_0_0>\nrequires swift::isUsableInGenericContext<T_0_0>\n`
78+
bool printNominalTypeOutsideMemberDeclTemplateSpecifiers(
79+
const NominalTypeDecl *typeDecl);
80+
81+
/// Print out the C++ class access qualifier for the given Swift type
82+
/// declaration.
83+
///
84+
/// Examples:
85+
/// 1) For Swift's `String` type, it will print `String
86+
/// 2) For Swift's `Array<T>` type, it will print `Array<T_0_0>
87+
/// 3) For Swift's `Array<T>.Index` type, it will print
88+
/// `Array<T_0_0>::Index` 4) For Swift's `String` type in another module,
89+
/// it will print `Swift::String`
90+
void printNominalTypeReference(const NominalTypeDecl *typeDecl,
91+
const ModuleDecl *moduleContext);
92+
93+
/// Print out the C++ class access qualifier for the given Swift type
94+
/// declaration.
95+
///
96+
/// Examples:
97+
/// 1) For Swift's `String` type, it will print `String::`.
98+
/// 2) For Swift's `Array<T>` type, it will print `Array<T_0_0>::`
99+
/// 3) For Swift's `Array<T>.Index` type, it will print
100+
/// `Array<T_0_0>::Index::` 4) For Swift's `String` type in another module,
101+
/// it will print `Swift::String::`
102+
void printNominalTypeQualifier(const NominalTypeDecl *typeDecl,
103+
const ModuleDecl *moduleContext);
104+
68105
/// Print a C++ namespace declaration with the give name and body.
69106
void
70107
printNamespace(llvm::function_ref<void(raw_ostream &OS)> namePrinter,

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,32 +1228,41 @@ class DeclAndTypePrinter::Implementation
12281228

12291229
// Converts the array of ABIAdditionalParam into an array of AdditionalParam
12301230
void convertABIAdditionalParams(
1231-
AbstractFunctionDecl *FD, Type resultTy,
1231+
AbstractFunctionDecl *FD,
12321232
llvm::SmallVector<IRABIDetailsProvider::ABIAdditionalParam, 1> ABIparams,
12331233
llvm::SmallVector<DeclAndTypeClangFunctionPrinter::AdditionalParam, 2>
12341234
&params,
12351235
Optional<NominalTypeDecl *> selfTypeDeclContext = None) {
12361236
for (auto param : ABIparams) {
1237-
if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
1238-
ABIParameterRole::GenericRequirementRole)
1237+
using Role = IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole;
1238+
switch (param.getRole()) {
1239+
case Role::GenericRequirement:
12391240
params.push_back({DeclAndTypeClangFunctionPrinter::AdditionalParam::
12401241
Role::GenericRequirement,
1241-
resultTy->getASTContext().getOpaquePointerType(),
1242-
/*isIndirect=*/false, param.genericRequirement});
1243-
else if (param.role ==
1244-
IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self)
1242+
FD->getASTContext().getOpaquePointerType(),
1243+
/*isIndirect=*/false, param.getGenericRequirement()});
1244+
break;
1245+
case Role::GenericTypeMetadataSource:
1246+
params.push_back({DeclAndTypeClangFunctionPrinter::AdditionalParam::
1247+
Role::GenericTypeMetadata,
1248+
param.getMetadataSourceType(), /*isIndirect=*/false,
1249+
None});
1250+
break;
1251+
case Role::Self:
12451252
params.push_back(
12461253
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
12471254
selfTypeDeclContext
1248-
? (*selfTypeDeclContext)->getDeclaredType()
1249-
: resultTy->getASTContext().getOpaquePointerType(),
1255+
? (*selfTypeDeclContext)->getDeclaredInterfaceType()
1256+
: FD->getASTContext().getOpaquePointerType(),
12501257
/*isIndirect=*/
12511258
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
1252-
else if (param.role == IRABIDetailsProvider::ABIAdditionalParam::
1253-
ABIParameterRole::Error)
1259+
break;
1260+
case Role::Error:
12541261
params.push_back(
12551262
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Error,
1256-
resultTy->getASTContext().getOpaquePointerType()});
1263+
FD->getASTContext().getOpaquePointerType()});
1264+
break;
1265+
}
12571266
}
12581267
}
12591268

@@ -1296,18 +1305,19 @@ class DeclAndTypePrinter::Implementation
12961305
llvm::find_if(
12971306
ABIparams,
12981307
[](const IRABIDetailsProvider::ABIAdditionalParam &Param) {
1299-
return Param.role == IRABIDetailsProvider::ABIAdditionalParam::
1300-
ABIParameterRole::Self;
1308+
return Param.getRole() ==
1309+
IRABIDetailsProvider::ABIAdditionalParam::
1310+
ABIParameterRole::Self;
13011311
}) == ABIparams.end()) {
1312+
(*selfTypeDeclContext)->getDeclaredInterfaceType();
13021313
funcABI.additionalParams.push_back(
13031314
{DeclAndTypeClangFunctionPrinter::AdditionalParam::Role::Self,
1304-
(*selfTypeDeclContext)->getDeclaredType(),
1315+
(*selfTypeDeclContext)->getDeclaredInterfaceType(),
13051316
/*isIndirect=*/
13061317
isa<FuncDecl>(FD) ? cast<FuncDecl>(FD)->isMutating() : false});
13071318
}
13081319
if (!ABIparams.empty())
1309-
convertABIAdditionalParams(FD, resultTy, ABIparams,
1310-
funcABI.additionalParams,
1320+
convertABIAdditionalParams(FD, ABIparams, funcABI.additionalParams,
13111321
/*selfContext=*/selfTypeDeclContext);
13121322

13131323
auto representation = funcPrinter.printFunctionSignature(

0 commit comments

Comments
 (0)