Skip to content

[WIP] [Runtime] Use retroactive protocol conformances when demangling to metadata #20424

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

Closed
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
10 changes: 8 additions & 2 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2293,11 +2293,17 @@ struct TargetProtocolConformanceDescriptor final
return TypeRef.getTypeContextDescriptor(getTypeKind());
}

/// Whether this is a retroactive conformance.
bool isRetroactive() const {
return Flags.isRetroactive();
}

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

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

/// Whether this conformance is non-unique because it has been synthesized
Expand Down
22 changes: 18 additions & 4 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class ASTBuilder {
using BuiltType = swift::Type;
using BuiltNominalTypeDecl = swift::NominalTypeDecl *;
using BuiltProtocolDecl = swift::ProtocolDecl *;
using BuiltProtocolConformanceRef = swift::NormalProtocolConformance *;
using BuiltProtocolConformance = void *; // a swift::ProtocolConformanceRef
explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {}

ASTContext &getASTContext() { return Ctx; }
Expand All @@ -69,10 +71,13 @@ class ASTBuilder {

Type createNominalType(NominalTypeDecl *decl, Type parent);

Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args);

Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args,
Type parent);
Type createBoundGenericType(
NominalTypeDecl *decl, ArrayRef<Type> args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive);
Type createBoundGenericType(
NominalTypeDecl *decl, ArrayRef<Type> args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
Type parent);

Type createTupleType(ArrayRef<Type> eltTypes, StringRef labels,
bool isVariadic);
Expand Down Expand Up @@ -109,6 +114,15 @@ class ASTBuilder {

Type getOpaqueType();

BuiltProtocolConformanceRef
createProtocolConformanceRef(Type conformingType, ProtocolDecl *protocol,
StringRef module);

BuiltProtocolConformance
createProtocolConformance(Type conformingType,
NormalProtocolConformance *normal,
ArrayRef<BuiltProtocolConformance> conditionalReqs);

private:
bool validateNominalParent(NominalTypeDecl *decl, Type parent);
DeclContext *findDeclContext(const Demangle::NodePointer &node);
Expand Down
94 changes: 91 additions & 3 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ class TypeDecoder {
using BuiltType = typename BuilderType::BuiltType;
using BuiltNominalTypeDecl = typename BuilderType::BuiltNominalTypeDecl;
using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl;
using BuiltProtocolConformanceRef =
typename BuilderType::BuiltProtocolConformanceRef;
using BuiltProtocolConformance =
typename BuilderType::BuiltProtocolConformance;
using NodeKind = Demangle::Node::Kind;

BuilderType &Builder;
Expand Down Expand Up @@ -180,10 +184,11 @@ class TypeDecoder {
if (!decodeMangledNominalType(Node->getChild(0), typeDecl, parent))
return BuiltType();

// Generic arguments.
std::vector<BuiltType> args;

const auto &genericArgs = Node->getChild(1);
assert(genericArgs->getKind() == NodeKind::TypeList);
if (genericArgs->getKind() != NodeKind::TypeList)
return BuiltType();

for (auto genericArg : *genericArgs) {
auto paramType = decodeMangledType(genericArg);
Expand All @@ -192,7 +197,23 @@ class TypeDecoder {
args.push_back(paramType);
}

return Builder.createBoundGenericType(typeDecl, args, parent);
// Retroactive conformances.
std::vector<std::pair<unsigned, BuiltProtocolConformance>> retroactive;
if (Node->getNumChildren() > 2 &&
Node->getChild(2)->getKind() == NodeKind::TypeList) {
for (auto retroNode : *Node->getChild(2)) {
if (retroNode->getKind() != NodeKind::RetroactiveConformance ||
!retroNode->hasIndex() || retroNode->getNumChildren() < 1)
continue;

if (auto conformance =
decodeMangledProtocolConformance(retroNode->getChild(0)))
retroactive.push_back({retroNode->getIndex(), conformance});
}
}

return Builder.createBoundGenericType(typeDecl, args, retroactive,
parent);
}
case NodeKind::BuiltinTypeName: {
auto mangledName = Demangle::mangleNode(Node);
Expand Down Expand Up @@ -517,6 +538,73 @@ class TypeDecoder {
}
}

/// Given a demangle tree, attempt to turn it into a protocol conformance.
BuiltProtocolConformance decodeMangledProtocolConformance(
const Demangle::NodePointer &Node) {
if (!Node) return BuiltProtocolConformance();

using NodeKind = Demangle::Node::Kind;
switch (Node->getKind()) {
case NodeKind::ConcreteProtocolConformance: {
if (Node->getNumChildren() < 2)
return BuiltProtocolConformance();

// Conforming type.
BuiltType conformingType = decodeMangledType(Node->getChild(0));
if (!conformingType)
return BuiltProtocolConformance();

// Protocol conformance reference.
auto conformanceRef = BuiltProtocolConformanceRef();
auto conformanceRefNode = Node->getChild(1);
if (conformanceRefNode->getKind() == NodeKind::ProtocolConformanceRef &&
conformanceRefNode->getNumChildren() > 0) {
// Protocol we are referring to.
auto protocol =
decodeMangledProtocolType(conformanceRefNode->getChild(0));
if (!protocol)
return BuiltProtocolConformance();

// The module in which the conformance resides, if it's retroactive.
StringRef module;
if (conformanceRefNode->getNumChildren() > 1 &&
conformanceRefNode->getChild(1)->getKind() == NodeKind::Module) {
module = conformanceRefNode->getChild(1)->getText();
}

// Resolve the conformance reference.
conformanceRef =
Builder.createProtocolConformanceRef(conformingType, protocol,
module);
if (!conformanceRef)
return BuiltProtocolConformance();
} else {
return BuiltProtocolConformance();
}

// Conditional requirements.
std::vector<BuiltProtocolConformance> conditionalReqs;
if (Node->getNumChildren() > 2 &&
Node->getChild(2)->getKind() == NodeKind::AnyProtocolConformanceList){
for (auto conditionalReqNode : *Node->getChild(2)) {
auto conditionalReq =
decodeMangledProtocolConformance(conditionalReqNode);
if (!conditionalReq)
return BuiltProtocolConformance();

conditionalReqs.push_back(conditionalReq);
}
}

return Builder.createProtocolConformance(conformingType, conformanceRef,
conditionalReqs);
}

// FIXME: Dependent protocol conformances.
default:
return BuiltProtocolConformance();
}
}
private:
bool decodeMangledNominalType(Demangle::NodePointer node,
BuiltNominalTypeDecl &typeDecl,
Expand Down
36 changes: 31 additions & 5 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class TypeRefBuilder {
using BuiltNominalTypeDecl = Optional<std::string>;
using BuiltProtocolDecl = Optional<std::pair<std::string, bool /*isObjC*/>>;

// FIXME: These are stubs
using BuiltProtocolConformanceRef = char;
using BuiltProtocolConformance = char;

TypeRefBuilder();

TypeRefBuilder(const TypeRefBuilder &other) = delete;
Expand Down Expand Up @@ -240,15 +244,21 @@ class TypeRefBuilder {
}

const BoundGenericTypeRef *
createBoundGenericType(const Optional<std::string> &mangledName,
const std::vector<const TypeRef *> &args) {
createBoundGenericType(
const Optional<std::string> &mangledName,
const std::vector<const TypeRef *> &args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive) {
// FIXME: Retroactive conformances.
return BoundGenericTypeRef::create(*this, *mangledName, args, nullptr);
}

const BoundGenericTypeRef *
createBoundGenericType(const Optional<std::string> &mangledName,
const std::vector<const TypeRef *> &args,
const TypeRef *parent) {
createBoundGenericType(
const Optional<std::string> &mangledName,
const std::vector<const TypeRef *> &args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
const TypeRef *parent) {
// FIXME: Retroactive conformances.
return BoundGenericTypeRef::create(*this, *mangledName, args, parent);
}

Expand Down Expand Up @@ -349,6 +359,22 @@ class TypeRefBuilder {
return OpaqueTypeRef::get();
}

BuiltProtocolConformanceRef createProtocolConformanceRef(
BuiltType conformingType,
BuiltProtocolDecl protocol,
StringRef module) {
// FIXME: Implement protocol conformance descriptor lookup.
return false;
}

BuiltProtocolConformance createProtocolConformance(
BuiltType conformingType,
BuiltProtocolConformanceRef conformance,
ArrayRef<BuiltProtocolConformance> conditionalReqs) {
// FIXME: Implement witness table computation.
return false;
}

///
/// Parsing reflection metadata
///
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,7 @@ class MetadataReader {
auto builtGenerics = getGenericSubst(metadata, descriptor);
if (builtGenerics.empty())
return BuiltType();
nominal = Builder.createBoundGenericType(typeDecl, builtGenerics);
nominal = Builder.createBoundGenericType(typeDecl, builtGenerics, { });
} else {
nominal = Builder.createNominalType(typeDecl);
}
Expand Down
31 changes: 26 additions & 5 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ Type ASTBuilder::createNominalType(NominalTypeDecl *decl, Type parent) {
return NominalType::get(decl, parent, Ctx);
}

Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
ArrayRef<Type> args) {
Type ASTBuilder::createBoundGenericType(
NominalTypeDecl *decl,
ArrayRef<Type> args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive) {
// If the declaration isn't generic, fail.
if (!decl->isGenericContext())
return Type();
Expand Down Expand Up @@ -123,9 +125,11 @@ Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
return substType;
}

Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
ArrayRef<Type> args,
Type parent) {
Type ASTBuilder::createBoundGenericType(
NominalTypeDecl *decl,
ArrayRef<Type> args,
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
Type parent) {
// If the declaration isn't generic, fail.
if (!decl->getGenericParams())
return Type();
Expand Down Expand Up @@ -685,3 +689,20 @@ ASTBuilder::findForeignNominalTypeDecl(StringRef name,

return consumer.Result;
}

auto ASTBuilder::createProtocolConformanceRef(Type conformingType,
ProtocolDecl *protocol,
StringRef module)
-> BuiltProtocolConformanceRef {
// FIXME: Implement lookup.
return nullptr;
}

auto ASTBuilder::createProtocolConformance(
Type conformingType,
NormalProtocolConformance *normal,
ArrayRef<BuiltProtocolConformance> conditionalReqs)
-> BuiltProtocolConformance {
// FIXME: Implement specialization.
return nullptr;
}
10 changes: 6 additions & 4 deletions stdlib/public/runtime/AnyHashableSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct HashableConformanceEntry {
// FIXME(performance): consider merging this cache into the regular
// protocol conformance cache.
static ConcurrentMap<HashableConformanceEntry, /*Destructor*/ false>
HashableConformances;
HashableConformances;

template<bool KnownToConformToHashable>
LLVM_ATTRIBUTE_ALWAYS_INLINE
Expand All @@ -80,16 +80,18 @@ static const Metadata *findHashableBaseTypeImpl(const Metadata *type) {
HashableConformances.find(HashableConformanceKey{type})) {
return entry->baseTypeThatConformsToHashable;
}
if (!KnownToConformToHashable &&
!swift_conformsToProtocol(type, &HashableProtocolDescriptor)) {

auto conformance =
_conformsToSwiftProtocol(type, &HashableProtocolDescriptor, StringRef());
if (!KnownToConformToHashable && !conformance) {
// Don't cache the negative response because we don't invalidate
// this cache when a new conformance is loaded dynamically.
return nullptr;
}
// By this point, `type` is known to conform to `Hashable`.

const Metadata *baseTypeThatConformsToHashable =
findConformingSuperclass(type, &HashableProtocolDescriptor);
findConformingSuperclass(type, conformance);
HashableConformances.getOrInsert(HashableConformanceKey{type},
baseTypeThatConformsToHashable);
return baseTypeThatConformsToHashable;
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4117,7 +4117,7 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request,
// For a class, chase the superclass chain up until we hit the
// type that specified the conformance.
auto originalConformingType = findConformingSuperclass(conformingType,
protocol);
conformance);
SubstGenericParametersFromMetadata substitutions(originalConformingType);
assocTypeMetadata = _getTypeByMangledName(mangledName, substitutions);
}
Expand Down
Loading