Implement reflection support for Symbolic Extended Existential types.

This patch adds a new SymbolicExtendedExistentialTypeRef kind, and
wires it up in TypeDecoder, TypeRefBuilder, TypeLowering, and
ASTDemangler.

This is tested indirectly via the matching LLDB commit.
This commit is contained in:
Adrian Prantl
2025-08-01 13:51:22 -07:00
parent 10345d3ad0
commit eabcf41a54
11 changed files with 401 additions and 131 deletions

View File

@@ -193,6 +193,7 @@ public:
};
using IndexType = uint64_t;
using RemoteAddressType = std::pair<uint64_t, uint8_t>;
friend class NodeFactory;
@@ -209,14 +210,20 @@ private:
IndexType Index;
NodePointer InlineChildren[2];
NodeVector Children;
RemoteAddressType RemoteAddress;
};
Kind NodeKind;
enum class PayloadKind : uint8_t {
None = 0, OneChild = 1, TwoChildren = 2,
Text, Index, ManyChildren
None = 0,
OneChild = 1,
TwoChildren = 2,
Text,
Index,
ManyChildren,
RemoteAddress
};
PayloadKind NodePayloadKind;
@@ -231,6 +238,10 @@ private:
: NodeKind(k), NodePayloadKind(PayloadKind::Index) {
Index = index;
}
Node(Kind k, uint64_t remoteAddress, uint8_t addressSpace)
: NodeKind(k), NodePayloadKind(PayloadKind::RemoteAddress) {
RemoteAddress = {remoteAddress, addressSpace};
}
Node(const Node &) = delete;
Node &operator=(const Node &) = delete;
@@ -284,6 +295,14 @@ public:
return Index;
}
bool hasRemoteAddress() const {
return NodePayloadKind == PayloadKind::RemoteAddress;
}
std::pair<uint64_t, uint8_t> getRemoteAddress() const {
assert(hasRemoteAddress());
return RemoteAddress;
}
using iterator = const NodePointer *;
size_t getNumChildren() const {

View File

@@ -249,6 +249,12 @@ public:
/// Creates a node of kind \p K with an \p Index payload.
NodePointer createNode(Node::Kind K, Node::IndexType Index);
/// Creates a node of kind \p K with a \p RemoteAddress payload.
///
/// These nodes are created and consumed by the reflection library.
NodePointer createNode(Node::Kind K, uint64_t RemoteAddress,
uint8_t AddressSpace);
/// Creates a node of kind \p K with a \p Text payload.
///
/// The \p Text string must be already allocated with the Factory and therefore

View File

@@ -573,6 +573,43 @@ void decodeRequirement(
}
}
/// Extract the protocol and requirement nodes from a shape symbol.
static inline std::pair<NodePointer, NodePointer>
decodeShape(NodePointer Node) {
if (!Node || Node->getKind() != Node::Kind::Global ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
Node = Node->getChild(0);
if (Node && (Node->getKind() == Node::Kind::Uniquable) &&
Node->getNumChildren() == 1)
Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::ExtendedExistentialTypeShape ||
Node->getNumChildren() != 2)
return {nullptr, nullptr};
Node = Node->getChild(1);
if (!Node || Node->getKind() != Node::Kind::Type ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::ConstrainedExistential ||
Node->getNumChildren() != 2)
return {nullptr, nullptr};
NodePointer Requirements = Node->getChild(1);
if (!Requirements || Requirements->getKind() !=
Node::Kind::ConstrainedExistentialRequirementList)
return {nullptr, nullptr};
Node = Node->getChild(0);
if (!Node || Node->getKind() != Node::Kind::Type ||
Node->getNumChildren() != 1)
return {nullptr, nullptr};
NodePointer Protocol = Node;
if (!Protocol)
return {nullptr, nullptr};
return {Protocol, Requirements};
}
#define MAKE_NODE_TYPE_ERROR(Node, Fmt, ...) \
TYPE_LOOKUP_ERROR_FMT("TypeDecoder.h:%u: Node kind %u \"%.*s\" - " Fmt, \
__LINE__, (unsigned)Node->getKind(), \

View File

@@ -480,16 +480,13 @@ public:
// Try to preserve a reference to an OpaqueTypeDescriptor
// symbolically, since we'd like to read out and resolve the type ref
// to the underlying type if available.
if (useOpaqueTypeSymbolicReferences
&& context.isResolved()
&& context.getResolved()->getKind() == ContextDescriptorKind::OpaqueType){
// FIXME: this loses the address space. This can be fixed by adding an
// opaque field in Node that can store the address space. This
// wouldn't degrade performance as Node's address is part of an union
// which is 16 bytes longs
if (useOpaqueTypeSymbolicReferences && context.isResolved() &&
context.getResolved()->getKind() ==
ContextDescriptorKind::OpaqueType) {
return dem.createNode(
Node::Kind::OpaqueTypeDescriptorSymbolicReference,
context.getResolved().getRemoteAddress().getRawAddress());
context.getResolved().getRemoteAddress().getRawAddress(),
context.getResolved().getRemoteAddress().getAddressSpace());
}
return buildContextMangling(context, dem);
@@ -504,15 +501,16 @@ public:
// existential type shape.
return dem.createNode(
Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getRawAddress());
resolved.getResolvedAddress().getRawAddress(),
resolved.getResolvedAddress().getAddressSpace());
}
case Demangle::SymbolicReferenceKind::NonUniqueExtendedExistentialTypeShape: {
// The symbolic reference points at a non-unique extended
// existential type shape.
// FIXME: this loses the address space.
return dem.createNode(
Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference,
resolved.getResolvedAddress().getRawAddress());
resolved.getResolvedAddress().getRawAddress(),
resolved.getResolvedAddress().getAddressSpace());
}
case Demangle::SymbolicReferenceKind::ObjectiveCProtocol: {
// 'resolved' points to a struct of two relative addresses.
@@ -879,6 +877,73 @@ public:
return resolver.swiftProtocol(Demangled);
}
BuiltType readTypeFromShape(
RemoteAbsolutePointer shapeAddress,
std::function<std::optional<std::vector<BuiltType>>(unsigned)> getArgs) {
RemoteAddress addr = shapeAddress.getResolvedAddress();
ShapeRef Shape = readShape(addr);
if (!Shape)
return BuiltType();
assert(Shape->hasGeneralizationSignature());
// Pull out the existential type from the mangled type name.
Demangler dem;
auto mangledExistentialAddr =
resolveRelativeField(Shape, Shape->ExistentialType);
auto node =
readMangledName(mangledExistentialAddr, MangledNameKind::Type, dem);
if (!node)
return BuiltType();
BuiltType builtProto = decodeMangledType(node).getType();
if (!builtProto)
return BuiltType();
if (auto builtArgs = getArgs(Shape->getGenSigArgumentLayoutSizeInWords())) {
// Build up a substitution map for the generalized signature.
BuiltGenericSignature sig =
decodeRuntimeGenericSignature(Shape,
Shape->getGeneralizationSignature())
.getType();
if (!sig)
return BuiltType();
BuiltSubstitutionMap subst =
Builder.createSubstitutionMap(sig, *builtArgs);
if (subst.empty())
return BuiltType();
builtProto = Builder.subst(builtProto, subst);
if (!builtProto)
return BuiltType();
}
// Read the type expression to build up any remaining layers of
// existential metatype.
if (Shape->Flags.hasTypeExpression()) {
Demangler dem;
// Read the mangled name.
auto mangledContextName = Shape->getTypeExpression();
auto mangledNameAddress =
resolveRelativeField(Shape, mangledContextName->name);
auto node =
readMangledName(mangledNameAddress, MangledNameKind::Type, dem);
if (!node)
return BuiltType();
while (node->getKind() == Demangle::Node::Kind::Type &&
node->hasChildren() &&
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype &&
node->getChild(0)->getNumChildren()) {
builtProto = Builder.createExistentialMetatypeType(builtProto);
node = node->getChild(0)->getChild(0);
}
}
return builtProto;
}
/// Given a remote pointer to metadata, attempt to turn it into a type.
BuiltType
readTypeFromMetadata(RemoteAddress MetadataAddress,
@@ -1091,82 +1156,27 @@ public:
}
case MetadataKind::ExtendedExistential: {
auto Exist = cast<TargetExtendedExistentialTypeMetadata<Runtime>>(Meta);
// Read the shape for this existential.
RemoteAddress shapeAddress = stripSignedPointer(Exist->Shape);
ShapeRef Shape = readShape(shapeAddress);
if (!Shape)
return BuiltType();
const unsigned shapeArgumentCount
= Shape->getGenSigArgumentLayoutSizeInWords();
// Pull out the arguments to the generalization signature.
assert(Shape->hasGeneralizationSignature());
std::vector<BuiltType> builtArgs;
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
auto remoteArg = Exist->getGeneralizationArguments()[i];
auto remoteArgAddress =
RemoteAddress(remoteArg, MetadataAddress.getAddressSpace());
auto builtArg =
readTypeFromMetadata(remoteArgAddress, false, recursion_limit);
if (!builtArg)
return BuiltType();
builtArgs.push_back(builtArg);
}
// Pull out the existential type from the mangled type name.
Demangler dem;
auto mangledExistentialAddr =
resolveRelativeField(Shape, Shape->ExistentialType);
auto node =
readMangledName(mangledExistentialAddr, MangledNameKind::Type, dem);
if (!node)
return BuiltType();
BuiltType builtProto = decodeMangledType(node).getType();
if (!builtProto)
return BuiltType();
// Build up a substitution map for the generalized signature.
BuiltGenericSignature sig =
decodeRuntimeGenericSignature(Shape,
Shape->getGeneralizationSignature())
.getType();
if (!sig)
return BuiltType();
BuiltSubstitutionMap subst =
Builder.createSubstitutionMap(sig, builtArgs);
if (subst.empty())
return BuiltType();
builtProto = Builder.subst(builtProto, subst);
if (!builtProto)
return BuiltType();
// Read the type expression to build up any remaining layers of
// existential metatype.
if (Shape->Flags.hasTypeExpression()) {
Demangler dem;
// Read the mangled name.
auto mangledContextName = Shape->getTypeExpression();
auto mangledNameAddress =
resolveRelativeField(Shape, mangledContextName->name);
auto node =
readMangledName(mangledNameAddress, MangledNameKind::Type, dem);
if (!node)
return BuiltType();
while (node->getKind() == Demangle::Node::Kind::Type &&
node->getNumChildren() &&
node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype &&
node->getChild(0)->getNumChildren()) {
builtProto = Builder.createExistentialMetatypeType(builtProto);
node = node->getChild(0)->getChild(0);
}
}
auto builtProto = readTypeFromShape(
RemoteAddress(shapeAddress),
[&](unsigned shapeArgumentCount)
-> std::optional<std::vector<BuiltType>> {
// Pull out the arguments to the generalization signature.
std::vector<BuiltType> builtArgs;
for (unsigned i = 0; i < shapeArgumentCount; ++i) {
auto remoteArg = Exist->getGeneralizationArguments()[i];
auto builtArg = readTypeFromMetadata(
remote::RemoteAddress(remoteArg,
shapeAddress.getAddressSpace()),
false, recursion_limit);
if (!builtArg)
return std::nullopt;
builtArgs.push_back(builtArg);
}
return builtArgs;
});
TypeCache[TypeCacheKey] = builtProto;
return builtProto;
}
@@ -1405,51 +1415,51 @@ public:
if (!address)
return nullptr;
using ShapeHeader = TargetExtendedExistentialTypeShape<Runtime>;
auto cached = ShapeCache.find(address);
if (cached != ShapeCache.end())
return ShapeRef(address,
reinterpret_cast<const TargetExtendedExistentialTypeShape<Runtime> *>(
cached->second.get()));
return ShapeRef(
address, reinterpret_cast<const ShapeHeader *>(cached->second.get()));
ExtendedExistentialTypeShapeFlags flags;
if (!Reader->readBytes(address, (uint8_t *)&flags, sizeof(flags)))
return nullptr;
// Read the size of the requirement signature.
uint64_t reqSigGenericSize = 0;
uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader);
uint64_t descriptorSize;
{
GenericContextDescriptorHeader header;
auto headerAddr = address + sizeof(flags);
if (!Reader->readBytes(headerAddr, (uint8_t *)&header, sizeof(header)))
auto readResult =
Reader->readBytes(RemoteAddress(address), sizeof(ShapeHeader));
if (!readResult)
return nullptr;
auto shapeHeader =
reinterpret_cast<const ShapeHeader *>(readResult.get());
reqSigGenericSize = reqSigGenericSize
+ (header.NumParams + 3u & ~3u)
+ header.NumRequirements
* sizeof(TargetGenericRequirementDescriptor<Runtime>);
// Read the size of the requirement signature.
uint64_t reqSigGenericSize = 0;
auto flags = shapeHeader->Flags;
auto &reqSigHeader = shapeHeader->ReqSigHeader;
reqSigGenericSize =
reqSigGenericSize + (reqSigHeader.NumParams + 3u & ~3u) +
reqSigHeader.NumRequirements *
sizeof(TargetGenericRequirementDescriptor<Runtime>);
uint64_t typeExprSize =
flags.hasTypeExpression() ? sizeof(StoredPointer) : 0;
uint64_t suggestedVWSize =
flags.hasSuggestedValueWitnesses() ? sizeof(StoredPointer) : 0;
descriptorSize = sizeof(shapeHeader) + typeExprSize + suggestedVWSize +
reqSigGenericSize;
}
uint64_t typeExprSize = flags.hasTypeExpression() ? sizeof(StoredPointer) : 0;
uint64_t suggestedVWSize = flags.hasSuggestedValueWitnesses() ? sizeof(StoredPointer) : 0;
uint64_t size = sizeof(ExtendedExistentialTypeShapeFlags) +
sizeof(TargetRelativeDirectPointer<Runtime, const char,
/*nullable*/ false>) +
genericHeaderSize + typeExprSize + suggestedVWSize +
reqSigGenericSize;
if (size > MaxMetadataSize)
if (descriptorSize > MaxMetadataSize)
return nullptr;
auto readResult = Reader->readBytes(address, size);
auto readResult = Reader->readBytes(RemoteAddress(address), descriptorSize);
if (!readResult)
return nullptr;
auto descriptor =
reinterpret_cast<const TargetExtendedExistentialTypeShape<Runtime> *>(
readResult.get());
auto descriptor = reinterpret_cast<const ShapeHeader *>(readResult.get());
ShapeCache.insert(
std::make_pair(address, std::move(readResult)));
ShapeCache.insert(std::make_pair(address, std::move(readResult)));
return ShapeRef(address, descriptor);
}

View File

@@ -731,6 +731,64 @@ public:
}
};
class SymbolicExtendedExistentialTypeRef final : public TypeRef {
const ProtocolCompositionTypeRef *Protocol;
std::vector<TypeRefRequirement> Requirements;
std::vector<const TypeRef *> Arguments;
ExtendedExistentialTypeShapeFlags Flags;
static TypeRefID Profile(const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Arguments,
ExtendedExistentialTypeShapeFlags Flags) {
TypeRefID ID;
ID.addPointer(Protocol);
for (auto reqt : Requirements) {
ID.addPointer(reqt.getFirstType());
if (reqt.getKind() != RequirementKind::Layout)
ID.addPointer(reqt.getSecondType());
else
ID.addInteger(
unsigned(0)); // FIXME: Layout constraints aren't implemented yet
ID.addInteger(unsigned(reqt.getKind()));
}
for (auto &Arg : Arguments)
ID.addPointer(Arg);
return ID;
}
public:
SymbolicExtendedExistentialTypeRef(
const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Args,
ExtendedExistentialTypeShapeFlags Flags)
: TypeRef(TypeRefKind::SymbolicExtendedExistential), Protocol(Protocol),
Requirements(Requirements), Arguments(Args), Flags(Flags) {}
template <typename Allocator>
static const SymbolicExtendedExistentialTypeRef *
create(Allocator &A, const ProtocolCompositionTypeRef *Protocol,
llvm::ArrayRef<TypeRefRequirement> Requirements,
llvm::ArrayRef<const TypeRef *> Args,
ExtendedExistentialTypeShapeFlags Flags) {
FIND_OR_CREATE_TYPEREF(A, SymbolicExtendedExistentialTypeRef, Protocol,
Requirements, Args, Flags);
}
const ProtocolCompositionTypeRef *getProtocol() const { return Protocol; }
llvm::ArrayRef<TypeRefRequirement> getRequirements() const {
return Requirements;
}
llvm::ArrayRef<const TypeRef *> getArguments() const { return Arguments; }
ExtendedExistentialTypeShapeFlags getFlags() const { return Flags; }
static bool classof(const TypeRef *TR) {
return TR->getKind() == TypeRefKind::SymbolicExtendedExistential;
}
};
class MetatypeTypeRef final : public TypeRef {
const TypeRef *InstanceType;
bool WasAbstract;

View File

@@ -1113,12 +1113,9 @@ public:
// Try to resolve to the underlying type, if we can.
if (opaqueDescriptor->getKind() ==
Node::Kind::OpaqueTypeDescriptorSymbolicReference) {
// FIXME: Node should carry a data structure that can fit a remote
// address. For now assume that this is a virtual address.
auto [address, space] = opaqueDescriptor->getRemoteAddress();
auto underlyingTy = OpaqueUnderlyingTypeReader(
remote::RemoteAddress(opaqueDescriptor->getIndex(),
remote::RemoteAddress::DefaultAddressSpace),
ordinal);
remote::RemoteAddress(address, space), ordinal);
if (!underlyingTy)
return nullptr;
@@ -1293,8 +1290,28 @@ public:
const TypeRef *
createSymbolicExtendedExistentialType(NodePointer shapeNode,
llvm::ArrayRef<const TypeRef *> args) {
// Can't handle this here.
return nullptr;
// Non-unique shape symbols start with an offset to a cache variable, right
// before the shape. Metadata pointers point directly to the shape, but when
// reading from a shape symbol, this needs to be corrected.
uint32_t offset = 0;
if (shapeNode->getKind() ==
Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference)
offset = sizeof(uint32_t);
auto [address, space] = shapeNode->getRemoteAddress();
remote::RemoteAddress shape(address, space);
shape += offset;
return OpaqueShapeReader(
shape,
[&](unsigned shapeArgumentCount)
-> std::optional<std::vector<const TypeRef *>> {
if (args.size() != shapeArgumentCount)
return std::nullopt;
if (llvm::any_of(
args, [](const TypeRef *arg) { return !arg->isConcrete(); }))
return std::nullopt;
return args;
});
}
const ExistentialMetatypeTypeRef *createExistentialMetatypeType(
@@ -1322,8 +1339,7 @@ public:
const DependentMemberTypeRef *
createDependentMemberType(const std::string &member, const TypeRef *base) {
// Should not have unresolved dependent member types here.
return nullptr;
return DependentMemberTypeRef::create(*this, member, base, "");
}
const DependentMemberTypeRef *
@@ -1489,6 +1505,13 @@ private:
using PointerReader =
std::function<std::optional<remote::RemoteAbsolutePointer>(
remote::RemoteAddress, unsigned)>;
using ShapeReader = std::function<const TypeRef *(
remote::RemoteAbsolutePointer,
std::function<std::optional<std::vector<const TypeRef *>>(unsigned)>)>;
using PointerSymbolResolver =
std::function<std::optional<remote::RemoteAbsolutePointer>(
remote::RemoteAddress)>;
using DynamicSymbolResolver =
std::function<std::optional<remote::RemoteAbsolutePointer>(
remote::RemoteAddress)>;
@@ -1521,6 +1544,8 @@ private:
ByteReader OpaqueByteReader;
StringReader OpaqueStringReader;
PointerReader OpaquePointerReader;
ShapeReader OpaqueShapeReader;
PointerSymbolResolver OpaquePointerSymbolResolver;
DynamicSymbolResolver OpaqueDynamicSymbolResolver;
IntVariableReader OpaqueIntVariableReader;
@@ -1559,6 +1584,18 @@ public:
-> std::optional<remote::RemoteAbsolutePointer> {
return reader.Reader->readPointer(address, size);
}),
OpaqueShapeReader(
[&reader](remote::RemoteAbsolutePointer pointer,
std::function<std::optional<std::vector<const TypeRef *>>(
unsigned)>
getArgs) -> const TypeRef * {
return reader.readTypeFromShape(pointer, getArgs);
}),
OpaquePointerSymbolResolver(
[&reader](remote::RemoteAddress address)
-> std::optional<remote::RemoteAbsolutePointer> {
return reader.Reader->resolvePointerAsSymbol(address);
}),
OpaqueDynamicSymbolResolver(
[&reader](remote::RemoteAddress address)
-> std::optional<remote::RemoteAbsolutePointer> {
@@ -1710,9 +1747,10 @@ public:
Node::Kind::OpaqueTypeDescriptorSymbolicReference) {
// FIXME: Node should carry a data structure that can fit a remote
// address. For now assume that this is a process address.
auto [address, space] =
opaqueTypeChildDemangleTree->getRemoteAddress();
extractOpaqueTypeProtocolRequirements<ObjCInteropKind, PointerSize>(
remote::RemoteAddress(opaqueTypeChildDemangleTree->getIndex(),
remote::RemoteAddress::DefaultAddressSpace),
remote::RemoteAddress(address, space),
opaqueTypeConformanceRequirements, sameTypeRequirements);
}
}

View File

@@ -23,6 +23,7 @@ TYPEREF(Tuple, TypeRef)
TYPEREF(Function, TypeRef)
TYPEREF(ProtocolComposition, TypeRef)
TYPEREF(ConstrainedExistential, TypeRef)
TYPEREF(SymbolicExtendedExistential, TypeRef)
TYPEREF(Metatype, TypeRef)
TYPEREF(ExistentialMetatype, TypeRef)
TYPEREF(GenericTypeParameter, TypeRef)

View File

@@ -791,7 +791,9 @@ Type ASTBuilder::createConstrainedExistentialType(
if (auto *memberTy = req.getFirstType()->getAs<DependentMemberType>()) {
if (memberTy->getBase()->is<GenericTypeParamType>()) {
// This is the only case we understand so far.
primaryAssociatedTypes[memberTy->getAssocType()] = req.getSecondType();
if (auto *assocTy = memberTy->getAssocType())
primaryAssociatedTypes[assocTy] = req.getSecondType();
continue;
}
}
@@ -809,10 +811,11 @@ Type ASTBuilder::createConstrainedExistentialType(
llvm::SmallVector<Type, 4> args;
for (auto *assocTy : proto->getPrimaryAssociatedTypes()) {
auto found = primaryAssociatedTypes.find(assocTy);
if (found == primaryAssociatedTypes.end())
return protoTy;
args.push_back(found->second);
claimed.insert(found->first);
if (found != primaryAssociatedTypes.end()) {
args.push_back(found->second);
claimed.insert(found->first);
continue;
}
}
// We may not have any arguments because the constrained existential is a

View File

@@ -601,6 +601,11 @@ NodePointer NodeFactory::createNode(Node::Kind K) {
NodePointer NodeFactory::createNode(Node::Kind K, Node::IndexType Index) {
return new (Allocate<Node>()) Node(K, Index);
}
NodePointer NodeFactory::createNode(Node::Kind K, uint64_t RemoteAddress,
uint8_t AddressSpace) {
return new (Allocate<Node>()) Node(K, RemoteAddress, AddressSpace);
}
NodePointer NodeFactory::createNodeWithAllocatedText(Node::Kind K,
llvm::StringRef Text) {
return new (Allocate<Node>()) Node(K, Text);

View File

@@ -1153,6 +1153,7 @@ class ExistentialTypeInfoBuilder {
TypeConverter &TC;
std::vector<const TypeRef *> Protocols;
const TypeRef *Superclass = nullptr;
remote::RemoteAbsolutePointer Shape;
ExistentialTypeRepresentation Representation;
ReferenceCounting Refcounting;
bool ObjC;
@@ -1320,6 +1321,24 @@ public:
Representation = ExistentialTypeRepresentation::Class;
}
void addShape(const ProtocolCompositionTypeRef *Protocol,
ExtendedExistentialTypeShapeFlags Flags) {
switch (Flags.getSpecialKind()) {
case ExtendedExistentialTypeShapeFlags::SpecialKind::Class:
Representation = ExistentialTypeRepresentation::Class;
break;
case ExtendedExistentialTypeShapeFlags::SpecialKind::Metatype:
case ExtendedExistentialTypeShapeFlags::SpecialKind::ExplicitLayout:
case ExtendedExistentialTypeShapeFlags::SpecialKind::None:
Representation = ExistentialTypeRepresentation::Opaque;
break;
}
if (Protocol)
for (auto *Protocol : Protocol->getProtocols())
addProtocol(Protocol);
}
const TypeInfo *build(remote::TypeInfoProvider *ExternalTypeInfo) {
examineProtocols();
@@ -1779,6 +1798,11 @@ public:
return true;
}
bool visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
return true;
}
bool
visitSILBoxTypeRef(const SILBoxTypeRef *SB) {
return true;
@@ -1922,6 +1946,11 @@ public:
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation visitMetatypeTypeRef(const MetatypeTypeRef *M) {
if (M->wasAbstract())
return MetatypeRepresentation::Thick;
@@ -2519,6 +2548,13 @@ public:
return builder.buildMetatype(ExternalTypeInfo);
}
const TypeInfo *visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
ExistentialTypeInfoBuilder builder(TC);
builder.addShape(SEET->getProtocol(), SEET->getFlags());
return builder.build(ExternalTypeInfo);
}
const TypeInfo *
visitGenericTypeParameterTypeRef(const GenericTypeParameterTypeRef *GTP) {
DEBUG_LOG(fprintf(stderr, "Unresolved generic TypeRef: "); GTP->dump());

View File

@@ -289,6 +289,15 @@ public:
stream << ")";
}
void visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *CET) {
printHeader("symbolic_extended_existential_type");
printRec(CET->getProtocol());
for (auto &arg : CET->getArguments())
printRec(arg);
stream << ")";
}
void visitMetatypeTypeRef(const MetatypeTypeRef *M) {
printHeader("metatype");
if (M->wasAbstract())
@@ -513,6 +522,15 @@ struct TypeRefIsConcrete
return visit(CET->getBase());
}
bool visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
visit(SEET->getProtocol());
for (auto &Arg : SEET->getArguments())
if (!visit(Arg))
return false;
return true;
}
bool visitMetatypeTypeRef(const MetatypeTypeRef *M) {
return visit(M->getInstanceType());
}
@@ -952,6 +970,19 @@ public:
return node;
}
Demangle::NodePointer visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
auto node = Dem.createNode(Node::Kind::ConstrainedExistential);
node->addChild(visit(SEET->getProtocol()), Dem);
auto constraintList =
Dem.createNode(Node::Kind::ConstrainedExistentialRequirementList);
for (auto req : SEET->getRequirements())
constraintList->addChild(visitTypeRefRequirement(req), Dem);
node->addChild(constraintList, Dem);
// FIXME: This is lossy. We're dropping the Arguments here.
return node;
}
Demangle::NodePointer visitMetatypeTypeRef(const MetatypeTypeRef *M) {
auto node = Dem.createNode(Node::Kind::Metatype);
// FIXME: This is lossy. @objc_metatype is also abstract.
@@ -1354,6 +1385,11 @@ public:
CET->getRequirements());
}
const TypeRef *visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
return SEET;
}
const TypeRef *visitMetatypeTypeRef(const MetatypeTypeRef *M) {
return MetatypeTypeRef::create(Builder, visit(M->getInstanceType()),
/*WasAbstract=*/true);
@@ -1641,6 +1677,27 @@ public:
constraints);
}
const TypeRef *visitSymbolicExtendedExistentialTypeRef(
const SymbolicExtendedExistentialTypeRef *SEET) {
std::vector<TypeRefRequirement> reqs;
for (auto &req : SEET->getRequirements()) {
auto substReq = visitTypeRefRequirement(req);
if (!substReq)
continue;
reqs.emplace_back(*substReq);
}
std::vector<const TypeRef *> args;
for (auto *arg : SEET->getArguments()) {
auto *substArg = visit(arg);
if (!substArg)
return nullptr;
args.push_back(substArg);
}
return SymbolicExtendedExistentialTypeRef::create(
Builder, SEET->getProtocol(), reqs, args, SEET->getFlags());
}
const TypeRef *
visitGenericTypeParameterTypeRef(const GenericTypeParameterTypeRef *GTP) {
auto found = Substitutions.find({GTP->getDepth(), GTP->getIndex()});