Skip to content

Conditional conformances for variadic generic types #66814

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
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
5 changes: 3 additions & 2 deletions include/swift/ABI/GenericContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ class TargetGenericRequirementDescriptor {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Param);
}

/// Retrieve the right-hand type for a SameType or BaseClass requirement.
/// Retrieve the right-hand type for a SameType, BaseClass or SameShape requirement.
llvm::StringRef getMangledTypeName() const {
assert(getKind() == GenericRequirementKind::SameType ||
getKind() == GenericRequirementKind::BaseClass);
getKind() == GenericRequirementKind::BaseClass ||
getKind() == GenericRequirementKind::SameShape);
return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get());
}

Expand Down
17 changes: 15 additions & 2 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2596,6 +2596,7 @@ struct TargetProtocolConformanceDescriptor final
TargetProtocolConformanceDescriptor<Runtime>,
TargetRelativeContextPointer<Runtime>,
TargetGenericRequirementDescriptor<Runtime>,
GenericPackShapeDescriptor,
TargetResilientWitnessesHeader<Runtime>,
TargetResilientWitness<Runtime>,
TargetGenericWitnessTable<Runtime>> {
Expand All @@ -2604,6 +2605,7 @@ struct TargetProtocolConformanceDescriptor final
TargetProtocolConformanceDescriptor<Runtime>,
TargetRelativeContextPointer<Runtime>,
TargetGenericRequirementDescriptor<Runtime>,
GenericPackShapeDescriptor,
TargetResilientWitnessesHeader<Runtime>,
TargetResilientWitness<Runtime>,
TargetGenericWitnessTable<Runtime>>;
Expand Down Expand Up @@ -2695,12 +2697,19 @@ struct TargetProtocolConformanceDescriptor final

/// Retrieve the conditional requirements that must also be
/// satisfied
llvm::ArrayRef<GenericRequirementDescriptor>
llvm::ArrayRef<TargetGenericRequirementDescriptor<Runtime>>
getConditionalRequirements() const {
return {this->template getTrailingObjects<GenericRequirementDescriptor>(),
return {this->template getTrailingObjects<TargetGenericRequirementDescriptor<Runtime>>(),
Flags.getNumConditionalRequirements()};
}

/// Retrieve the pack shape descriptors for the conditional pack requirements.
llvm::ArrayRef<GenericPackShapeDescriptor>
getConditionalPackShapeDescriptors() const {
return {this->template getTrailingObjects<GenericPackShapeDescriptor>(),
Flags.getNumConditionalPackShapeDescriptors()};
}

/// Get the directly-referenced witness table pattern, which may also
/// serve as the witness table.
const swift::TargetWitnessTable<Runtime> *getWitnessTablePattern() const {
Expand Down Expand Up @@ -2759,6 +2768,10 @@ struct TargetProtocolConformanceDescriptor final
return Flags.getNumConditionalRequirements();
}

size_t numTrailingObjects(OverloadToken<GenericPackShapeDescriptor>) const {
return Flags.getNumConditionalPackShapeDescriptors();
}

size_t numTrailingObjects(OverloadToken<ResilientWitnessesHeader>) const {
return Flags.hasResilientWitnesses() ? 1 : 0;
}
Expand Down
26 changes: 20 additions & 6 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,17 +662,20 @@ class ConformanceFlags {
enum : int_type {
UnusedLowBits = 0x07, // historical conformance kind

TypeMetadataKindMask = 0x7 << 3, // 8 type reference kinds
TypeMetadataKindMask = 0x7u << 3, // 8 type reference kinds
TypeMetadataKindShift = 3,

IsRetroactiveMask = 0x01 << 6,
IsSynthesizedNonUniqueMask = 0x01 << 7,
IsRetroactiveMask = 0x01u << 6,
IsSynthesizedNonUniqueMask = 0x01u << 7,

NumConditionalRequirementsMask = 0xFF << 8,
NumConditionalRequirementsMask = 0xFFu << 8,
NumConditionalRequirementsShift = 8,

HasResilientWitnessesMask = 0x01 << 16,
HasGenericWitnessTableMask = 0x01 << 17,
HasResilientWitnessesMask = 0x01u << 16,
HasGenericWitnessTableMask = 0x01u << 17,

NumConditionalPackDescriptorsMask = 0xFFu << 24,
NumConditionalPackDescriptorsShift = 24
};

int_type Value;
Expand Down Expand Up @@ -702,6 +705,11 @@ class ConformanceFlags {
| (n << NumConditionalRequirementsShift));
}

ConformanceFlags withNumConditionalPackDescriptors(unsigned n) const {
return ConformanceFlags((Value & ~NumConditionalPackDescriptorsMask)
| (n << NumConditionalPackDescriptorsShift));
}

ConformanceFlags withHasResilientWitnesses(bool hasResilientWitnesses) const {
return ConformanceFlags((Value & ~HasResilientWitnessesMask)
| (hasResilientWitnesses? HasResilientWitnessesMask
Expand Down Expand Up @@ -747,6 +755,12 @@ class ConformanceFlags {
>> NumConditionalRequirementsShift;
}

/// Retrieve the # of conditional pack shape descriptors.
unsigned getNumConditionalPackShapeDescriptors() const {
return (Value & NumConditionalPackDescriptorsMask)
>> NumConditionalPackDescriptorsShift;
}

/// Whether this conformance has any resilient witnesses.
bool hasResilientWitnesses() const {
return Value & HasResilientWitnessesMask;
Expand Down
14 changes: 14 additions & 0 deletions lib/IRGen/Fulfillment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,22 @@ bool FulfillmentMap::searchConformance(

SILWitnessTable::enumerateWitnessTableConditionalConformances(
conformance, [&](unsigned index, CanType type, ProtocolDecl *protocol) {
Optional<unsigned> packExpansionComponent;

if (auto packType = dyn_cast<PackType>(type)) {
auto param =
getSingletonPackExpansionParameter(packType, interestingKeys,
packExpansionComponent);
if (!param)
return /*finished?*/ false;
type = param;
}

MetadataPath conditionalPath = path;
conditionalPath.addConditionalConformanceComponent(index);
if (packExpansionComponent)
conditionalPath.addPackExpansionPatternComponent(*packExpansionComponent);

hadFulfillment |=
searchWitnessTable(IGM, type, protocol, sourceIndex,
std::move(conditionalPath), interestingKeys);
Expand Down
37 changes: 22 additions & 15 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,21 +566,7 @@ namespace {
B.addInt(IGM.Int16Ty, shapes.size());

// Emit each GenericPackShapeDescriptor collected previously.
for (const auto &packArg : packArgs) {
// Kind
B.addInt(IGM.Int16Ty, uint16_t(packArg.Kind));

// Index
B.addInt(IGM.Int16Ty, packArg.Index);

// ShapeClass
auto found = std::find(shapes.begin(), shapes.end(), packArg.ReducedShape);
assert(found != shapes.end());
B.addInt(IGM.Int16Ty, found - shapes.begin());

// Unused
B.addInt(IGM.Int16Ty, 0);
}
irgen::addGenericPackShapeDescriptors(IGM, B, shapes, packArgs);
}

uint8_t getVersion() {
Expand Down Expand Up @@ -6580,6 +6566,27 @@ GenericArgumentMetadata irgen::addGenericRequirements(
return metadata;
}

void irgen::addGenericPackShapeDescriptors(IRGenModule &IGM,
ConstantStructBuilder &B,
ArrayRef<CanType> shapes,
ArrayRef<GenericPackArgument> packArgs) {
for (const auto &packArg : packArgs) {
// Kind
B.addInt(IGM.Int16Ty, uint16_t(packArg.Kind));

// Index
B.addInt(IGM.Int16Ty, packArg.Index);

// ShapeClass
auto found = std::find(shapes.begin(), shapes.end(), packArg.ReducedShape);
assert(found != shapes.end());
B.addInt(IGM.Int16Ty, found - shapes.begin());

// Unused
B.addInt(IGM.Int16Ty, 0);
}
}

//===----------------------------------------------------------------------===//
// Other metadata.
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 9 additions & 0 deletions lib/IRGen/GenMeta.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@ namespace irgen {
GenericSignature sig,
ArrayRef<Requirement> requirements);

/// Add generic pack shape descriptors to the given constant struct builder.
///
/// These appear in generic type metadata, and conformance descriptors with
/// conditional pack requirements.
void addGenericPackShapeDescriptors(IRGenModule &IGM,
ConstantStructBuilder &B,
ArrayRef<CanType> shapes,
ArrayRef<GenericPackArgument> packArgs);

llvm::GlobalValue *emitAsyncFunctionPointer(IRGenModule &IGM,
llvm::Function *function,
LinkEntity entity,
Expand Down
59 changes: 41 additions & 18 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,10 @@ namespace {
ConformanceDescription Description;
ConformanceFlags Flags;

using PlaceholderPosition =
ConstantAggregateBuilderBase::PlaceholderPosition;
Optional<PlaceholderPosition> FlagsPP;

public:
ProtocolConformanceDescriptorBuilder(
IRGenModule &IGM,
Expand All @@ -1960,6 +1964,11 @@ namespace {
addResilientWitnesses();
addGenericWitnessTable();

// We fill the flags last, since we continue filling them in
// after the call to addFlags() deposits the placeholder.
B.fillPlaceholderWithInt(*FlagsPP, IGM.Int32Ty,
Flags.getIntValue());

B.suggestType(IGM.ProtocolConformanceDescriptorTy);
}

Expand All @@ -1981,13 +1990,6 @@ namespace {
}

void addWitnessTable() {
// Note the number of conditional requirements.
unsigned numConditional = 0;
if (auto normal = dyn_cast<NormalProtocolConformance>(Conformance)) {
numConditional = normal->getConditionalRequirements().size();
}
Flags = Flags.withNumConditionalRequirements(numConditional);

// Relative reference to the witness table.
B.addRelativeAddressOrNull(Description.pattern);
}
Expand All @@ -2001,13 +2003,9 @@ namespace {
Flags = Flags.withIsRetroactive(false)
.withIsSynthesizedNonUnique(false);
}
Flags = Flags.withHasResilientWitnesses(
!Description.resilientWitnesses.empty());
Flags =
Flags.withHasGenericWitnessTable(Description.requiresSpecialization);

// Add the flags.
B.addInt32(Flags.getIntValue());
// Add a placeholder for the flags.
FlagsPP = B.addPlaceholderWithSize(IGM.Int32Ty);
}

void addContext() {
Expand All @@ -2025,19 +2023,42 @@ namespace {

void addConditionalRequirements() {
auto normal = dyn_cast<NormalProtocolConformance>(Conformance);
if (!normal || normal->getConditionalRequirements().empty())
if (!normal)
return;

auto nominal = normal->getType()->getAnyNominal();
irgen::addGenericRequirements(IGM, B,
nominal->getGenericSignatureOfContext(),
normal->getConditionalRequirements());
auto condReqs = normal->getConditionalRequirements();
if (condReqs.empty())
return;

Flags = Flags.withNumConditionalRequirements(condReqs.size());

auto nominal = normal->getDeclContext()->getSelfNominalTypeDecl();
auto sig = nominal->getGenericSignatureOfContext();
auto metadata = irgen::addGenericRequirements(IGM, B, sig, condReqs);

Flags = Flags.withNumConditionalPackDescriptors(
metadata.GenericPackArguments.size());

// Collect the shape classes from the nominal type's generic signature.
sig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
if (canonical && param->isParameterPack()) {
auto reducedShape = sig->getReducedShape(param)->getCanonicalType();
if (reducedShape->isEqual(param))
metadata.ShapeClasses.push_back(reducedShape);
}
});

irgen::addGenericPackShapeDescriptors(
IGM, B, metadata.ShapeClasses,
metadata.GenericPackArguments);
}

void addResilientWitnesses() {
if (Description.resilientWitnesses.empty())
return;

Flags = Flags.withHasResilientWitnesses(true);

// TargetResilientWitnessesHeader
ArrayRef<llvm::Constant *> witnesses = Description.resilientWitnesses;
B.addInt32(witnesses.size());
Expand Down Expand Up @@ -2098,6 +2119,8 @@ namespace {
if (!Description.requiresSpecialization)
return;

Flags = Flags.withHasGenericWitnessTable(true);

// WitnessTableSizeInWords
B.addInt(IGM.Int16Ty, Description.witnessTableSize);
// WitnessTablePrivateSizeInWordsAndRequiresInstantiation
Expand Down
14 changes: 10 additions & 4 deletions lib/IRGen/LocalTypeData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,18 +473,24 @@ void IRGenFunction::bindLocalTypeDataFromSelfWitnessTable(
SILWitnessTable::enumerateWitnessTableConditionalConformances(
conformance,
[&](unsigned index, CanType type, ProtocolDecl *proto) {
auto archetype = getTypeInContext(type);
if (isa<ArchetypeType>(archetype)) {
if (auto packType = dyn_cast<PackType>(type)) {
if (auto expansion = packType.unwrapSingletonPackExpansion())
type = expansion.getPatternType();
}

type = getTypeInContext(type);

if (isa<ArchetypeType>(type)) {
WitnessIndex wIndex(privateWitnessTableIndexToTableOffset(index),
/*prefix*/ false);

auto table = loadConditionalConformance(*this ,selfTable,
wIndex.forProtocolWitnessTable());
table = Builder.CreateBitCast(table, IGM.WitnessTablePtrTy);
setProtocolWitnessTableName(IGM, table, archetype, proto);
setProtocolWitnessTableName(IGM, table, type, proto);

setUnscopedLocalTypeData(
archetype,
type,
LocalTypeDataKind::forAbstractProtocolWitnessTable(proto),
table);
}
Expand Down
Loading