Skip to content

Commit d1cb930

Browse files
committed
Runtime: Support for conditional conformances with pack conformance requirements
1 parent c84a14f commit d1cb930

File tree

6 files changed

+136
-39
lines changed

6 files changed

+136
-39
lines changed

include/swift/ABI/Metadata.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,6 +2596,7 @@ struct TargetProtocolConformanceDescriptor final
25962596
TargetProtocolConformanceDescriptor<Runtime>,
25972597
TargetRelativeContextPointer<Runtime>,
25982598
TargetGenericRequirementDescriptor<Runtime>,
2599+
GenericPackShapeDescriptor,
25992600
TargetResilientWitnessesHeader<Runtime>,
26002601
TargetResilientWitness<Runtime>,
26012602
TargetGenericWitnessTable<Runtime>> {
@@ -2604,6 +2605,7 @@ struct TargetProtocolConformanceDescriptor final
26042605
TargetProtocolConformanceDescriptor<Runtime>,
26052606
TargetRelativeContextPointer<Runtime>,
26062607
TargetGenericRequirementDescriptor<Runtime>,
2608+
GenericPackShapeDescriptor,
26072609
TargetResilientWitnessesHeader<Runtime>,
26082610
TargetResilientWitness<Runtime>,
26092611
TargetGenericWitnessTable<Runtime>>;
@@ -2695,12 +2697,19 @@ struct TargetProtocolConformanceDescriptor final
26952697

26962698
/// Retrieve the conditional requirements that must also be
26972699
/// satisfied
2698-
llvm::ArrayRef<GenericRequirementDescriptor>
2700+
llvm::ArrayRef<TargetGenericRequirementDescriptor<Runtime>>
26992701
getConditionalRequirements() const {
2700-
return {this->template getTrailingObjects<GenericRequirementDescriptor>(),
2702+
return {this->template getTrailingObjects<TargetGenericRequirementDescriptor<Runtime>>(),
27012703
Flags.getNumConditionalRequirements()};
27022704
}
27032705

2706+
/// Retrieve the pack shape descriptors for the conditional pack requirements.
2707+
llvm::ArrayRef<GenericPackShapeDescriptor>
2708+
getConditionalPackShapeDescriptors() const {
2709+
return {this->template getTrailingObjects<GenericPackShapeDescriptor>(),
2710+
Flags.getNumConditionalPackShapeDescriptors()};
2711+
}
2712+
27042713
/// Get the directly-referenced witness table pattern, which may also
27052714
/// serve as the witness table.
27062715
const swift::TargetWitnessTable<Runtime> *getWitnessTablePattern() const {
@@ -2759,6 +2768,10 @@ struct TargetProtocolConformanceDescriptor final
27592768
return Flags.getNumConditionalRequirements();
27602769
}
27612770

2771+
size_t numTrailingObjects(OverloadToken<GenericPackShapeDescriptor>) const {
2772+
return Flags.getNumConditionalPackShapeDescriptors();
2773+
}
2774+
27622775
size_t numTrailingObjects(OverloadToken<ResilientWitnessesHeader>) const {
27632776
return Flags.hasResilientWitnesses() ? 1 : 0;
27642777
}

include/swift/ABI/MetadataValues.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -662,17 +662,20 @@ class ConformanceFlags {
662662
enum : int_type {
663663
UnusedLowBits = 0x07, // historical conformance kind
664664

665-
TypeMetadataKindMask = 0x7 << 3, // 8 type reference kinds
665+
TypeMetadataKindMask = 0x7u << 3, // 8 type reference kinds
666666
TypeMetadataKindShift = 3,
667667

668-
IsRetroactiveMask = 0x01 << 6,
669-
IsSynthesizedNonUniqueMask = 0x01 << 7,
668+
IsRetroactiveMask = 0x01u << 6,
669+
IsSynthesizedNonUniqueMask = 0x01u << 7,
670670

671-
NumConditionalRequirementsMask = 0xFF << 8,
671+
NumConditionalRequirementsMask = 0xFFu << 8,
672672
NumConditionalRequirementsShift = 8,
673673

674-
HasResilientWitnessesMask = 0x01 << 16,
675-
HasGenericWitnessTableMask = 0x01 << 17,
674+
HasResilientWitnessesMask = 0x01u << 16,
675+
HasGenericWitnessTableMask = 0x01u << 17,
676+
677+
NumConditionalPackDescriptorsMask = 0xFFu << 24,
678+
NumConditionalPackDescriptorsShift = 24
676679
};
677680

678681
int_type Value;
@@ -702,6 +705,11 @@ class ConformanceFlags {
702705
| (n << NumConditionalRequirementsShift));
703706
}
704707

708+
ConformanceFlags withNumConditionalPackDescriptors(unsigned n) const {
709+
return ConformanceFlags((Value & ~NumConditionalPackDescriptorsMask)
710+
| (n << NumConditionalPackDescriptorsShift));
711+
}
712+
705713
ConformanceFlags withHasResilientWitnesses(bool hasResilientWitnesses) const {
706714
return ConformanceFlags((Value & ~HasResilientWitnessesMask)
707715
| (hasResilientWitnesses? HasResilientWitnessesMask
@@ -747,6 +755,12 @@ class ConformanceFlags {
747755
>> NumConditionalRequirementsShift;
748756
}
749757

758+
/// Retrieve the # of conditional pack shape descriptors.
759+
unsigned getNumConditionalPackShapeDescriptors() const {
760+
return (Value & NumConditionalPackDescriptorsMask)
761+
>> NumConditionalPackDescriptorsShift;
762+
}
763+
750764
/// Whether this conformance has any resilient witnesses.
751765
bool hasResilientWitnesses() const {
752766
return Value & HasResilientWitnessesMask;

stdlib/public/runtime/Metadata.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5679,6 +5679,7 @@ instantiateWitnessTable(const Metadata *Type,
56795679
void **fullTable) {
56805680
auto protocol = conformance->getProtocol();
56815681
auto genericTable = conformance->getGenericWitnessTable();
5682+
auto *genericArgs = Type->getGenericArgs();
56825683

56835684
// The number of witnesses provided by the table pattern.
56845685
size_t numPatternWitnesses = genericTable->WitnessTableSizeInWords;
@@ -5720,20 +5721,38 @@ instantiateWitnessTable(const Metadata *Type,
57205721
// requirements into the private area.
57215722
{
57225723
unsigned currentInstantiationArg = 0;
5723-
auto copyNextInstantiationArg = [&] {
5724-
assert(currentInstantiationArg < privateSizeInWords);
5725-
table[-1 - (int)currentInstantiationArg] =
5726-
const_cast<void *>(instantiationArgs[currentInstantiationArg]);
5727-
++currentInstantiationArg;
5728-
};
5724+
5725+
llvm::ArrayRef<GenericPackShapeDescriptor> packShapeDescriptors =
5726+
conformance->getConditionalPackShapeDescriptors();
5727+
unsigned packIdx = 0;
57295728

57305729
for (const auto &conditionalRequirement
57315730
: conformance->getConditionalRequirements()) {
5732-
if (conditionalRequirement.Flags.hasKeyArgument())
5733-
copyNextInstantiationArg();
5731+
if (!conditionalRequirement.Flags.hasKeyArgument())
5732+
continue;
57345733

5735-
assert(!conditionalRequirement.Flags.isPackRequirement() &&
5736-
"Packs not supported here yet");
5734+
assert(currentInstantiationArg < privateSizeInWords);
5735+
5736+
auto *instantiationArg = instantiationArgs[currentInstantiationArg];
5737+
5738+
// Heap-allocate witness tables for conditional pack conformance requirements.
5739+
if (conditionalRequirement.Flags.isPackRequirement()) {
5740+
auto packShapeDescriptor = packShapeDescriptors[packIdx];
5741+
assert(packShapeDescriptor.Kind == GenericPackKind::WitnessTable);
5742+
assert(packShapeDescriptor.Index == currentInstantiationArg);
5743+
size_t count = reinterpret_cast<const size_t>(
5744+
genericArgs[packShapeDescriptor.ShapeClass]);
5745+
5746+
auto *wtable = reinterpret_cast<const WitnessTable * const*>(instantiationArg);
5747+
wtable = swift_allocateWitnessTablePack(wtable, count);
5748+
5749+
instantiationArg = wtable;
5750+
++packIdx;
5751+
}
5752+
5753+
table[-1 - (int)currentInstantiationArg] = const_cast<void *>(instantiationArg);
5754+
5755+
++currentInstantiationArg;
57375756
}
57385757
}
57395758

@@ -6048,6 +6067,9 @@ instantiateRelativeWitnessTable(const Metadata *Type,
60486067
: conformance->getConditionalRequirements()) {
60496068
if (conditionalRequirement.Flags.hasKeyArgument())
60506069
copyNextInstantiationArg();
6070+
6071+
assert(!conditionalRequirement.Flags.isPackRequirement() &&
6072+
"Not supported yet");
60516073
}
60526074
}
60536075

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,9 @@ _gatherGenericParameters(const ContextDescriptor *context,
12881288
}
12891289

12901290
// Add metadata for each canonical generic parameter.
1291+
auto packShapeDescriptors = generics->getGenericPackShapeDescriptors();
1292+
unsigned packIdx = 0;
1293+
12911294
for (unsigned i = 0; i != n; ++i) {
12921295
const auto &param = genericParams[i];
12931296
auto arg = allGenericArgs[i];
@@ -1318,7 +1321,20 @@ _gatherGenericParameters(const ContextDescriptor *context,
13181321
}
13191322

13201323
if (param.hasKeyArgument()) {
1321-
allGenericArgsVec.push_back(arg.getMetadataPack().getPointer());
1324+
auto packShapeDescriptor = packShapeDescriptors[packIdx];
1325+
assert(packShapeDescriptor.Kind == GenericPackKind::Metadata);
1326+
assert(packShapeDescriptor.Index == allGenericArgsVec.size());
1327+
assert(packShapeDescriptor.ShapeClass < packShapeHeader.NumShapeClasses);
1328+
1329+
auto argPack = arg.getMetadataPack();
1330+
assert(argPack.getLifetime() == PackLifetime::OnHeap);
1331+
1332+
// Fill in the length for each shape class.
1333+
allGenericArgsVec[packShapeDescriptor.ShapeClass] =
1334+
reinterpret_cast<const void *>(argPack.getNumElements());
1335+
1336+
allGenericArgsVec.push_back(argPack.getPointer());
1337+
++packIdx;
13221338
}
13231339

13241340
break;
@@ -1332,22 +1348,6 @@ _gatherGenericParameters(const ContextDescriptor *context,
13321348
});
13331349
}
13341350
}
1335-
1336-
// Fill in the length for each shape class.
1337-
auto packShapeDescriptors = generics->getGenericPackShapeDescriptors();
1338-
for (auto packShapeDescriptor : packShapeDescriptors) {
1339-
if (packShapeDescriptor.Kind != GenericPackKind::Metadata)
1340-
continue;
1341-
1342-
assert(packShapeDescriptor.Index < allGenericArgsVec.size());
1343-
assert(packShapeDescriptor.ShapeClass < packShapeHeader.NumShapeClasses);
1344-
1345-
MetadataPackPointer pack(allGenericArgsVec[packShapeDescriptor.Index]);
1346-
assert(pack.getLifetime() == PackLifetime::OnHeap);
1347-
1348-
allGenericArgsVec[packShapeDescriptor.ShapeClass] =
1349-
reinterpret_cast<const void *>(pack.getNumElements());
1350-
}
13511351
}
13521352

13531353
// Check whether the generic requirements are satisfied, collecting
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking)
2+
3+
// REQUIRES: executable_test
4+
5+
// UNSUPPORTED: use_os_stdlib
6+
// UNSUPPORTED: back_deployment_runtime
7+
8+
import StdlibUnittest
9+
10+
var conformances = TestSuite("VariadicGenericConformances")
11+
12+
protocol P {
13+
static func foobar() -> [String]
14+
}
15+
16+
struct G<each T> {}
17+
18+
extension G: P where repeat each T: P {
19+
static func foobar() -> [String] {
20+
var result: [String] = []
21+
repeat result += (each T).foobar()
22+
return result
23+
}
24+
}
25+
26+
extension Int: P {
27+
static func foobar() -> [String] {
28+
return ["Int"]
29+
}
30+
}
31+
32+
extension String: P {
33+
static func foobar() -> [String] {
34+
return ["String"]
35+
}
36+
}
37+
38+
func callFoobar<T: P>(_: T) -> [String] {
39+
return T.foobar()
40+
}
41+
42+
conformances.test("conditional") {
43+
expectEqual([], callFoobar(G< >()))
44+
expectEqual(["Int"], callFoobar(G<Int>()))
45+
expectEqual(["Int", "String"], callFoobar(G<Int, String>()))
46+
}
47+
48+
runAllTests()

test/Interpreter/variadic_generic_conformances.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import StdlibUnittest
99

10-
var tuples = TestSuite("VariadicGenericConformances")
10+
var conformances = TestSuite("VariadicGenericConformances")
1111

1212
protocol TypeMaker {
1313
func makeType() -> Any.Type
@@ -29,7 +29,7 @@ struct ElementTupleMaker<each T: Sequence> : TypeMaker {
2929
}
3030
}
3131

32-
tuples.test("makeTuple1") {
32+
conformances.test("makeTuple1") {
3333
expectEqual("()", _typeName(makeTypeIndirectly(TupleMaker< >())))
3434

3535
// FIXME: This should unwrap the one-element tuple!
@@ -38,7 +38,7 @@ tuples.test("makeTuple1") {
3838
expectEqual("(Swift.Int, Swift.Bool)", _typeName(makeTypeIndirectly(TupleMaker<Int, Bool>())))
3939
}
4040

41-
tuples.test("makeTuple2") {
41+
conformances.test("makeTuple2") {
4242
expectEqual("()", _typeName(makeTypeIndirectly(ElementTupleMaker< >())))
4343

4444
// FIXME: This should unwrap the one-element tuple!
@@ -88,7 +88,7 @@ func testPackRequirements2<T: HasPackRequirements, each U: Q>(_ t: T, _ u: repea
8888
return t.doStuff2(repeat each u)
8989
}
9090

91-
tuples.test("packRequirements") {
91+
conformances.test("packRequirements") {
9292
expectEqual(([1], ["hi"], [false]), testPackRequirements1(ConformsPackRequirements(), 1, "hi", false))
9393
expectEqual(([1], ["hi"], [false]), testPackRequirements2(ConformsPackRequirements(), 1, "hi", false))
9494
}

0 commit comments

Comments
 (0)