Skip to content

[interop][SwiftToCxx] add support for invoking methods in generic structs & unify function and struct generics #60892

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 4 commits into from
Sep 1, 2022
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
39 changes: 36 additions & 3 deletions include/swift/IRGen/IRABIDetailsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,45 @@ class IRABIDetailsProvider {
};

/// Information about any ABI additional parameters.
struct ABIAdditionalParam {
enum class ABIParameterRole { GenericRequirementRole, Self, Error };
class ABIAdditionalParam {
public:
enum class ABIParameterRole {
/// A parameter that corresponds to a generic requirement that must be
/// fullfilled by a call to this function.
GenericRequirement,
/// A parameter that corresponds to a Swift type pointer sourced from a
/// valid metadata source, like the type of another argument.
GenericTypeMetadataSource,
/// A parameter that corresponds to the 'self' parameter.
Self,
/// The Swift error parameter.
Error
};

inline ABIParameterRole getRole() const { return role; }

inline GenericRequirement getGenericRequirement() {
assert(role == ABIParameterRole::GenericRequirement);
return *genericRequirement;
}

inline CanType getMetadataSourceType() {
assert(role == ABIParameterRole::GenericTypeMetadataSource);
return canType;
}

private:
inline ABIAdditionalParam(
ABIParameterRole role,
llvm::Optional<GenericRequirement> genericRequirement, CanType canType)
: role(role), genericRequirement(genericRequirement), canType(canType) {
}

ABIParameterRole role;
llvm::Optional<GenericRequirement> genericRequirement;
TypeDecl *type;
CanType canType;

friend class IRABIDetailsProviderImpl;
};

/// Returns the size and alignment for the given type, or \c None if the type
Expand Down
13 changes: 7 additions & 6 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ namespace {
unsigned AsyncResumeFunctionSwiftSelfIdx = 0;
FunctionPointerKind FnKind;
bool ShouldComputeABIDetails;
SmallVector<GenericRequirement, 4> GenericRequirements;
SmallVector<PolymorphicSignatureExpandedTypeSource, 4>
polymorphicSignatureTypeSources;

SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
FunctionPointerKind fnKind,
Expand Down Expand Up @@ -1631,9 +1632,9 @@ void SignatureExpansion::expandParameters() {
// Next, the generic signature.
if (hasPolymorphicParameters(FnType) &&
!FnKind.shouldSuppressPolymorphicArguments())
expandPolymorphicSignature(IGM, FnType, ParamIRTypes,
ShouldComputeABIDetails ? &GenericRequirements
: nullptr);
expandPolymorphicSignature(
IGM, FnType, ParamIRTypes,
ShouldComputeABIDetails ? &polymorphicSignatureTypeSources : nullptr);

// Certain special functions are passed the continuation directly.
if (FnKind.shouldPassContinuationDirectly()) {
Expand Down Expand Up @@ -1931,8 +1932,8 @@ Signature SignatureExpansion::getSignature() {
result.ExtraDataKind = ExtraData::kindForMember<void>();
}
if (ShouldComputeABIDetails)
result.ABIDetails =
SignatureExpansionABIDetails{std::move(GenericRequirements)};
result.ABIDetails = SignatureExpansionABIDetails{
std::move(polymorphicSignatureTypeSources)};
return result;
}

Expand Down
17 changes: 12 additions & 5 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3462,26 +3462,33 @@ namespace {
: PolymorphicConvention(IGM, fn) {}

void expand(SmallVectorImpl<llvm::Type *> &out,
SmallVectorImpl<GenericRequirement> *reqs) {
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *reqs) {
auto outStartSize = out.size();
(void)outStartSize;
for (auto &source : getSources())
addEarlySource(source, out);
addEarlySource(source, out, reqs);

enumerateUnfulfilledRequirements([&](GenericRequirement reqt) {
if (reqs)
reqs->push_back(reqt);
out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy
: IGM.TypeMetadataPtrTy);
});
assert((!reqs || reqs->size() == (out.size() - outStartSize)) &&
"missing type source for type");
}

private:
/// Add signature elements for the source metadata.
void addEarlySource(const MetadataSource &source,
SmallVectorImpl<llvm::Type*> &out) {
void addEarlySource(
const MetadataSource &source, SmallVectorImpl<llvm::Type *> &out,
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *reqs) {
switch (source.getKind()) {
case MetadataSource::Kind::ClassPointer: return; // already accounted for
case MetadataSource::Kind::Metadata: return; // already accounted for
case MetadataSource::Kind::GenericLValueMetadata:
if (reqs)
reqs->push_back(source);
return out.push_back(IGM.TypeMetadataPtrTy);
case MetadataSource::Kind::SelfMetadata:
case MetadataSource::Kind::SelfWitnessTable:
Expand All @@ -3498,7 +3505,7 @@ namespace {
void irgen::expandPolymorphicSignature(
IRGenModule &IGM, CanSILFunctionType polyFn,
SmallVectorImpl<llvm::Type *> &out,
SmallVectorImpl<GenericRequirement> *outReqs) {
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *outReqs) {
ExpandPolymorphicSignature(IGM, polyFn).expand(out, outReqs);
}

Expand Down
89 changes: 4 additions & 85 deletions lib/IRGen/GenProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "Fulfillment.h"
#include "GenericRequirement.h"
#include "MetadataSource.h"

namespace llvm {
class Type;
Expand Down Expand Up @@ -48,6 +49,7 @@ namespace irgen {
class MetadataPath;
class MetadataResponse;
class NativeCCEntryPointArgumentEmission;
class PolymorphicSignatureExpandedTypeSource;
class ProtocolInfo;
class TypeInfo;

Expand Down Expand Up @@ -102,7 +104,8 @@ namespace irgen {
void expandPolymorphicSignature(
IRGenModule &IGM, CanSILFunctionType type,
SmallVectorImpl<llvm::Type *> &types,
SmallVectorImpl<GenericRequirement> *outReqs = nullptr);
SmallVectorImpl<PolymorphicSignatureExpandedTypeSource> *outReqs =
nullptr);

/// Return the number of trailing arguments necessary for calling a
/// witness method.
Expand Down Expand Up @@ -179,90 +182,6 @@ namespace irgen {
CanType srcType,
ProtocolConformanceRef conformance);

class MetadataSource {
public:
enum class Kind {
/// Metadata is derived from a source class pointer.
ClassPointer,

/// Metadata is derived from a type metadata pointer.
Metadata,

/// Metadata is derived from the origin type parameter.
GenericLValueMetadata,

/// Metadata is obtained directly from the from a Self metadata
/// parameter passed via the WitnessMethod convention.
SelfMetadata,

/// Metadata is derived from the Self witness table parameter
/// passed via the WitnessMethod convention.
SelfWitnessTable,

/// Metadata is obtained directly from the FixedType indicated. Used with
/// Objective-C generics, where the actual argument is erased at runtime
/// and its existential bound is used instead.
ErasedTypeMetadata,
};

static bool requiresSourceIndex(Kind kind) {
return (kind == Kind::ClassPointer ||
kind == Kind::Metadata ||
kind == Kind::GenericLValueMetadata);
}

static bool requiresFixedType(Kind kind) {
return (kind == Kind::ErasedTypeMetadata);
}

enum : unsigned { InvalidSourceIndex = ~0U };

private:
/// The kind of source this is.
Kind TheKind;

/// For ClassPointer, Metadata, and GenericLValueMetadata, the source index;
/// for ErasedTypeMetadata, the type; for others, Index should be set to
/// InvalidSourceIndex.
union {
unsigned Index;
CanType FixedType;
};

public:
CanType Type;

MetadataSource(Kind kind, CanType type)
: TheKind(kind), Index(InvalidSourceIndex), Type(type)
{
assert(!requiresSourceIndex(kind) && !requiresFixedType(kind));
}


MetadataSource(Kind kind, CanType type, unsigned index)
: TheKind(kind), Index(index), Type(type) {
assert(requiresSourceIndex(kind));
assert(index != InvalidSourceIndex);
}

MetadataSource(Kind kind, CanType type, CanType fixedType)
: TheKind(kind), FixedType(fixedType), Type(type) {
assert(requiresFixedType(kind));
}

Kind getKind() const { return TheKind; }

unsigned getParamIndex() const {
assert(requiresSourceIndex(getKind()));
return Index;
}

CanType getFixedType() const {
assert(requiresFixedType(getKind()));
return FixedType;
}
};

using GenericParamFulfillmentCallback =
llvm::function_ref<void(CanType genericParamType,
const MetadataSource &source,
Expand Down
26 changes: 18 additions & 8 deletions lib/IRGen/IRABIDetailsProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,30 @@ class IRABIDetailsProviderImpl {
auto signature = Signature::getUncached(IGM, silFuncType, funcPointerKind,
/*shouldComputeABIDetail=*/true);

for (const auto &reqt : signature.getABIDetails().GenericRequirements) {
params.push_back({IRABIDetailsProvider::ABIAdditionalParam::
ABIParameterRole::GenericRequirementRole,
reqt, typeConverter.Context.getOpaquePointerDecl()});
using ABIAdditionalParam = IRABIDetailsProvider::ABIAdditionalParam;
using ParamRole = ABIAdditionalParam::ABIParameterRole;
for (const auto &typeSource :
signature.getABIDetails().polymorphicSignatureExpandedTypeSources) {
typeSource.visit(
[&](const GenericRequirement &reqt) {
params.push_back(ABIAdditionalParam(ParamRole::GenericRequirement,
reqt, CanType()));
},
[&](const MetadataSource &metadataSource) {
auto index = metadataSource.getParamIndex();
auto canType =
silFuncType->getParameters()[index].getInterfaceType();
params.push_back(ABIAdditionalParam(
ParamRole::GenericTypeMetadataSource, llvm::None, canType));
});
}
for (auto attrSet : signature.getAttributes()) {
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftSelf))
params.push_back(
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Self,
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
ABIAdditionalParam(ParamRole::Self, llvm::None, CanType()));
if (attrSet.hasAttribute(llvm::Attribute::AttrKind::SwiftError))
params.push_back(
{IRABIDetailsProvider::ABIAdditionalParam::ABIParameterRole::Error,
llvm::None, typeConverter.Context.getOpaquePointerDecl()});
ABIAdditionalParam(ParamRole::Error, llvm::None, CanType()));
}
return params;
}
Expand Down
108 changes: 108 additions & 0 deletions lib/IRGen/MetadataSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//===--- MetadataSource.h - structure for the source of metadata *- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_IRGEN_METADATA_SOURCE_H
#define SWIFT_IRGEN_METADATA_SOURCE_H

#include "swift/AST/Types.h"

namespace swift {
namespace irgen {

class MetadataSource {
public:
enum class Kind {
/// Metadata is derived from a source class pointer.
ClassPointer,

/// Metadata is derived from a type metadata pointer.
Metadata,

/// Metadata is derived from the origin type parameter.
GenericLValueMetadata,

/// Metadata is obtained directly from the from a Self metadata
/// parameter passed via the WitnessMethod convention.
SelfMetadata,

/// Metadata is derived from the Self witness table parameter
/// passed via the WitnessMethod convention.
SelfWitnessTable,

/// Metadata is obtained directly from the FixedType indicated. Used with
/// Objective-C generics, where the actual argument is erased at runtime
/// and its existential bound is used instead.
ErasedTypeMetadata,
};

static bool requiresSourceIndex(Kind kind) {
return (kind == Kind::ClassPointer ||
kind == Kind::Metadata ||
kind == Kind::GenericLValueMetadata);
}

static bool requiresFixedType(Kind kind) {
return (kind == Kind::ErasedTypeMetadata);
}

enum : unsigned { InvalidSourceIndex = ~0U };

private:
/// The kind of source this is.
Kind TheKind;

/// For ClassPointer, Metadata, and GenericLValueMetadata, the source index;
/// for ErasedTypeMetadata, the type; for others, Index should be set to
/// InvalidSourceIndex.
union {
unsigned Index;
CanType FixedType;
};

public:
CanType Type;

MetadataSource(Kind kind, CanType type)
: TheKind(kind), Index(InvalidSourceIndex), Type(type)
{
assert(!requiresSourceIndex(kind) && !requiresFixedType(kind));
}


MetadataSource(Kind kind, CanType type, unsigned index)
: TheKind(kind), Index(index), Type(type) {
assert(requiresSourceIndex(kind));
assert(index != InvalidSourceIndex);
}

MetadataSource(Kind kind, CanType type, CanType fixedType)
: TheKind(kind), FixedType(fixedType), Type(type) {
assert(requiresFixedType(kind));
}

Kind getKind() const { return TheKind; }

unsigned getParamIndex() const {
assert(requiresSourceIndex(getKind()));
return Index;
}

CanType getFixedType() const {
assert(requiresFixedType(getKind()));
return FixedType;
}
};

} // end namespace irgen
} // end namespace swift

#endif
Loading