Skip to content

Commit e765464

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

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
@@ -5678,6 +5678,7 @@ instantiateWitnessTable(const Metadata *Type,
56785678
void **fullTable) {
56795679
auto protocol = conformance->getProtocol();
56805680
auto genericTable = conformance->getGenericWitnessTable();
5681+
auto *genericArgs = Type->getGenericArgs();
56815682

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

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

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

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

stdlib/public/runtime/MetadataLookup.cpp

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

12851285
// Add metadata for each canonical generic parameter.
1286+
auto packShapeDescriptors = generics->getGenericPackShapeDescriptors();
1287+
unsigned packIdx = 0;
1288+
12861289
for (unsigned i = 0; i != n; ++i) {
12871290
const auto &param = genericParams[i];
12881291
auto arg = allGenericArgs[i];
@@ -1313,7 +1316,20 @@ _gatherGenericParameters(const ContextDescriptor *context,
13131316
}
13141317

13151318
if (param.hasKeyArgument()) {
1316-
allGenericArgsVec.push_back(arg.getMetadataPack().getPointer());
1319+
auto packShapeDescriptor = packShapeDescriptors[packIdx];
1320+
assert(packShapeDescriptor.Kind == GenericPackKind::Metadata);
1321+
assert(packShapeDescriptor.Index == allGenericArgsVec.size());
1322+
assert(packShapeDescriptor.ShapeClass < packShapeHeader.NumShapeClasses);
1323+
1324+
auto argPack = arg.getMetadataPack();
1325+
assert(argPack.getLifetime() == PackLifetime::OnHeap);
1326+
1327+
// Fill in the length for each shape class.
1328+
allGenericArgsVec[packShapeDescriptor.ShapeClass] =
1329+
reinterpret_cast<const void *>(argPack.getNumElements());
1330+
1331+
allGenericArgsVec.push_back(argPack.getPointer());
1332+
++packIdx;
13171333
}
13181334

13191335
break;
@@ -1327,22 +1343,6 @@ _gatherGenericParameters(const ContextDescriptor *context,
13271343
});
13281344
}
13291345
}
1330-
1331-
// Fill in the length for each shape class.
1332-
auto packShapeDescriptors = generics->getGenericPackShapeDescriptors();
1333-
for (auto packShapeDescriptor : packShapeDescriptors) {
1334-
if (packShapeDescriptor.Kind != GenericPackKind::Metadata)
1335-
continue;
1336-
1337-
assert(packShapeDescriptor.Index < allGenericArgsVec.size());
1338-
assert(packShapeDescriptor.ShapeClass < packShapeHeader.NumShapeClasses);
1339-
1340-
MetadataPackPointer pack(allGenericArgsVec[packShapeDescriptor.Index]);
1341-
assert(pack.getLifetime() == PackLifetime::OnHeap);
1342-
1343-
allGenericArgsVec[packShapeDescriptor.ShapeClass] =
1344-
reinterpret_cast<const void *>(pack.getNumElements());
1345-
}
13461346
}
13471347

13481348
// 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)