Skip to content

Commit 87f7b4e

Browse files
authored
Merge pull request #14368 from DougGregor/se-0143-runtime-conditional-conformances
2 parents 5663b44 + 81f1574 commit 87f7b4e

File tree

12 files changed

+389
-250
lines changed

12 files changed

+389
-250
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ Swift 5.0
2929
circumstances with very simple values, so this is unlikely to affect
3030
real-world code.)
3131

32+
* [SE-0143][]
33+
34+
Runtime query of conditional conformances is now implemented. Therefore,
35+
a dynamic cast such as `value as? P`, where the dynamic type of `value`
36+
conditional conforms to `P`, will succeed when the conditional
37+
requirements are met.
3238

3339
Swift 4.1
3440
---------

include/swift/Runtime/Metadata.h

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,6 +2278,13 @@ struct TargetTypeMetadataRecord {
22782278

22792279
using TypeMetadataRecord = TargetTypeMetadataRecord<InProcess>;
22802280

2281+
template<typename Runtime> struct TargetContextDescriptor;
2282+
2283+
template<typename Runtime>
2284+
using RelativeContextPointer =
2285+
RelativeIndirectablePointer<const TargetContextDescriptor<Runtime>,
2286+
/*nullable*/ true>;
2287+
22812288
/// The structure of a protocol reference record.
22822289
template <typename Runtime>
22832290
struct TargetProtocolRecord {
@@ -2290,18 +2297,37 @@ struct TargetProtocolRecord {
22902297
};
22912298
using ProtocolRecord = TargetProtocolRecord<InProcess>;
22922299

2300+
template<typename Runtime> class TargetGenericRequirementDescriptor;
2301+
22932302
/// The structure of a protocol conformance.
22942303
///
22952304
/// This contains enough static information to recover the witness table for a
22962305
/// type's conformance to a protocol.
22972306
template <typename Runtime>
2298-
struct TargetProtocolConformanceDescriptor {
2307+
struct TargetProtocolConformanceDescriptor final
2308+
: public swift::ABI::TrailingObjects<
2309+
TargetProtocolConformanceDescriptor<Runtime>,
2310+
RelativeContextPointer<Runtime>,
2311+
TargetGenericRequirementDescriptor<Runtime>> {
2312+
2313+
using TrailingObjects = swift::ABI::TrailingObjects<
2314+
TargetProtocolConformanceDescriptor<Runtime>,
2315+
RelativeContextPointer<Runtime>,
2316+
TargetGenericRequirementDescriptor<Runtime>>;
2317+
friend TrailingObjects;
2318+
2319+
template<typename T>
2320+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
2321+
22992322
public:
23002323
using WitnessTableAccessorFn
23012324
= const TargetWitnessTable<Runtime> *(const TargetMetadata<Runtime>*,
23022325
const TargetWitnessTable<Runtime> **,
23032326
size_t);
23042327

2328+
using GenericRequirementDescriptor =
2329+
TargetGenericRequirementDescriptor<Runtime>;
2330+
23052331
private:
23062332
/// The protocol being conformed to.
23072333
///
@@ -2381,7 +2407,22 @@ struct TargetProtocolConformanceDescriptor {
23812407

23822408
return nullptr;
23832409
}
2384-
2410+
2411+
/// Retrieve the context of a retroactive conformance.
2412+
const TargetContextDescriptor<Runtime> *getRetroactiveContext() const {
2413+
if (!Flags.isRetroactive()) return nullptr;
2414+
2415+
return this->template getTrailingObjects<RelativeContextPointer<Runtime>>();
2416+
}
2417+
2418+
/// Retrieve the conditional requirements that must also be
2419+
/// satisfied
2420+
llvm::ArrayRef<GenericRequirementDescriptor>
2421+
getConditionalRequirements() const {
2422+
return {this->template getTrailingObjects<GenericRequirementDescriptor>(),
2423+
Flags.getNumConditionalRequirements()};
2424+
}
2425+
23852426
/// Get the directly-referenced static witness table.
23862427
const swift::TargetWitnessTable<Runtime> *getStaticWitnessTable() const {
23872428
switch (getConformanceKind()) {
@@ -2416,7 +2457,7 @@ struct TargetProtocolConformanceDescriptor {
24162457
/// type.
24172458
const swift::TargetWitnessTable<Runtime> *
24182459
getWitnessTable(const TargetMetadata<Runtime> *type) const;
2419-
2460+
24202461
#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP
24212462
void dump() const;
24222463
#endif
@@ -2430,6 +2471,16 @@ struct TargetProtocolConformanceDescriptor {
24302471
/// 2. Has a valid conformance kind.
24312472
void verify() const LLVM_ATTRIBUTE_USED;
24322473
#endif
2474+
2475+
private:
2476+
size_t numTrailingObjects(
2477+
OverloadToken<RelativeContextPointer<Runtime>>) const {
2478+
return Flags.isRetroactive() ? 1 : 0;
2479+
}
2480+
2481+
size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
2482+
return Flags.getNumConditionalRequirements();
2483+
}
24332484
};
24342485
using ProtocolConformanceDescriptor
24352486
= TargetProtocolConformanceDescriptor<InProcess>;
@@ -2441,14 +2492,6 @@ using TargetProtocolConformanceRecord =
24412492

24422493
using ProtocolConformanceRecord = TargetProtocolConformanceRecord<InProcess>;
24432494

2444-
2445-
template<typename Runtime> struct TargetContextDescriptor;
2446-
2447-
template<typename Runtime>
2448-
using RelativeContextPointer =
2449-
RelativeIndirectablePointer<const TargetContextDescriptor<Runtime>,
2450-
/*nullable*/ true>;
2451-
24522495
template<typename Runtime>
24532496
struct TargetGenericContext;
24542497

@@ -2702,7 +2745,25 @@ class TargetGenericRequirementDescriptor {
27022745
assert(getKind() == GenericRequirementKind::Layout);
27032746
return Layout;
27042747
}
2748+
2749+
/// Determine whether this generic requirement has a known kind.
2750+
///
2751+
/// \returns \c false for any future generic requirement kinds.
2752+
bool hasKnownKind() const {
2753+
switch (getKind()) {
2754+
case GenericRequirementKind::BaseClass:
2755+
case GenericRequirementKind::Layout:
2756+
case GenericRequirementKind::Protocol:
2757+
case GenericRequirementKind::SameConformance:
2758+
case GenericRequirementKind::SameType:
2759+
return true;
2760+
}
2761+
2762+
return false;
2763+
}
27052764
};
2765+
using GenericRequirementDescriptor =
2766+
TargetGenericRequirementDescriptor<InProcess>;
27062767

27072768
/// CRTP class for a context descriptor that includes trailing generic
27082769
/// context description.

lib/IRGen/GenDecl.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,8 @@ namespace {
25792579
addConformingType();
25802580
addWitnessTable();
25812581
addFlags();
2582+
addContext();
2583+
addConditionalRequirements();
25822584

25832585
B.suggestType(IGM.ProtocolConformanceDescriptorTy);
25842586
}
@@ -2650,6 +2652,27 @@ namespace {
26502652
// Add the flags.
26512653
B.addInt32(Flags.getIntValue());
26522654
}
2655+
2656+
void addContext() {
2657+
if (!Conformance->isRetroactive())
2658+
return;
2659+
2660+
auto moduleContext =
2661+
Conformance->getDeclContext()->getModuleScopeContext();
2662+
ConstantReference moduleContextRef =
2663+
IGM.getAddrOfParentContextDescriptor(moduleContext);
2664+
B.addRelativeAddress(moduleContextRef);
2665+
}
2666+
2667+
void addConditionalRequirements() {
2668+
if (Conformance->getConditionalRequirements().empty())
2669+
return;
2670+
2671+
auto nominal = Conformance->getType()->getAnyNominal();
2672+
irgen::addGenericRequirements(IGM, B,
2673+
nominal->getGenericSignatureOfContext(),
2674+
Conformance->getConditionalRequirements());
2675+
}
26532676
};
26542677
}
26552678

0 commit comments

Comments
 (0)