Skip to content

[Runtime] SE-0143: Evaluate conditional conformances at runtime. #14368

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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Swift 5.0
circumstances with very simple values, so this is unlikely to affect
real-world code.)

* [SE-0143][]

Runtime query of conditional conformances is now implemented. Therefore,
a dynamic cast such as `value as? P`, where the dynamic type of `value`
conditional conforms to `P`, will succeed when the conditional
Copy link
Contributor

@jckarter jckarter Feb 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*conditionally conforms

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, thanks. I'll fix that in a follow-up commit.

requirements are met.

Swift 4.1
---------
Expand Down
83 changes: 72 additions & 11 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2278,6 +2278,13 @@ struct TargetTypeMetadataRecord {

using TypeMetadataRecord = TargetTypeMetadataRecord<InProcess>;

template<typename Runtime> struct TargetContextDescriptor;

template<typename Runtime>
using RelativeContextPointer =
RelativeIndirectablePointer<const TargetContextDescriptor<Runtime>,
/*nullable*/ true>;

/// The structure of a protocol reference record.
template <typename Runtime>
struct TargetProtocolRecord {
Expand All @@ -2290,18 +2297,37 @@ struct TargetProtocolRecord {
};
using ProtocolRecord = TargetProtocolRecord<InProcess>;

template<typename Runtime> class TargetGenericRequirementDescriptor;

/// The structure of a protocol conformance.
///
/// This contains enough static information to recover the witness table for a
/// type's conformance to a protocol.
template <typename Runtime>
struct TargetProtocolConformanceDescriptor {
struct TargetProtocolConformanceDescriptor final
: public swift::ABI::TrailingObjects<
TargetProtocolConformanceDescriptor<Runtime>,
RelativeContextPointer<Runtime>,
TargetGenericRequirementDescriptor<Runtime>> {

using TrailingObjects = swift::ABI::TrailingObjects<
TargetProtocolConformanceDescriptor<Runtime>,
RelativeContextPointer<Runtime>,
TargetGenericRequirementDescriptor<Runtime>>;
friend TrailingObjects;

template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;

public:
using WitnessTableAccessorFn
= const TargetWitnessTable<Runtime> *(const TargetMetadata<Runtime>*,
const TargetWitnessTable<Runtime> **,
size_t);

using GenericRequirementDescriptor =
TargetGenericRequirementDescriptor<Runtime>;

private:
/// The protocol being conformed to.
///
Expand Down Expand Up @@ -2381,7 +2407,22 @@ struct TargetProtocolConformanceDescriptor {

return nullptr;
}


/// Retrieve the context of a retroactive conformance.
const TargetContextDescriptor<Runtime> *getRetroactiveContext() const {
if (!Flags.isRetroactive()) return nullptr;

return this->template getTrailingObjects<RelativeContextPointer<Runtime>>();
}

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

/// Get the directly-referenced static witness table.
const swift::TargetWitnessTable<Runtime> *getStaticWitnessTable() const {
switch (getConformanceKind()) {
Expand Down Expand Up @@ -2416,7 +2457,7 @@ struct TargetProtocolConformanceDescriptor {
/// type.
const swift::TargetWitnessTable<Runtime> *
getWitnessTable(const TargetMetadata<Runtime> *type) const;

#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP
void dump() const;
#endif
Expand All @@ -2430,6 +2471,16 @@ struct TargetProtocolConformanceDescriptor {
/// 2. Has a valid conformance kind.
void verify() const LLVM_ATTRIBUTE_USED;
#endif

private:
size_t numTrailingObjects(
OverloadToken<RelativeContextPointer<Runtime>>) const {
return Flags.isRetroactive() ? 1 : 0;
}

size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
return Flags.getNumConditionalRequirements();
}
};
using ProtocolConformanceDescriptor
= TargetProtocolConformanceDescriptor<InProcess>;
Expand All @@ -2441,14 +2492,6 @@ using TargetProtocolConformanceRecord =

using ProtocolConformanceRecord = TargetProtocolConformanceRecord<InProcess>;


template<typename Runtime> struct TargetContextDescriptor;

template<typename Runtime>
using RelativeContextPointer =
RelativeIndirectablePointer<const TargetContextDescriptor<Runtime>,
/*nullable*/ true>;

template<typename Runtime>
struct TargetGenericContext;

Expand Down Expand Up @@ -2702,7 +2745,25 @@ class TargetGenericRequirementDescriptor {
assert(getKind() == GenericRequirementKind::Layout);
return Layout;
}

/// Determine whether this generic requirement has a known kind.
///
/// \returns \c false for any future generic requirement kinds.
bool hasKnownKind() const {
switch (getKind()) {
case GenericRequirementKind::BaseClass:
case GenericRequirementKind::Layout:
case GenericRequirementKind::Protocol:
case GenericRequirementKind::SameConformance:
case GenericRequirementKind::SameType:
return true;
}

return false;
}
};
using GenericRequirementDescriptor =
TargetGenericRequirementDescriptor<InProcess>;

/// CRTP class for a context descriptor that includes trailing generic
/// context description.
Expand Down
23 changes: 23 additions & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,8 @@ namespace {
addConformingType();
addWitnessTable();
addFlags();
addContext();
addConditionalRequirements();

B.suggestType(IGM.ProtocolConformanceDescriptorTy);
}
Expand Down Expand Up @@ -2650,6 +2652,27 @@ namespace {
// Add the flags.
B.addInt32(Flags.getIntValue());
}

void addContext() {
if (!Conformance->isRetroactive())
return;

auto moduleContext =
Conformance->getDeclContext()->getModuleScopeContext();
ConstantReference moduleContextRef =
IGM.getAddrOfParentContextDescriptor(moduleContext);
B.addRelativeAddress(moduleContextRef);
}

void addConditionalRequirements() {
if (Conformance->getConditionalRequirements().empty())
return;

auto nominal = Conformance->getType()->getAnyNominal();
irgen::addGenericRequirements(IGM, B,
nominal->getGenericSignatureOfContext(),
Conformance->getConditionalRequirements());
}
};
}

Expand Down
Loading