Skip to content

Commit ecd83fa

Browse files
committed
[Runtime] Use retroactive protocol conformances when demangling to metadata
Extend TypeDecoder with the ability to demangle (concrete) protocol conformances, and pass along demangled retroactive conformances to it’s builder’s createBoundGenericType(). Extend the mangled name -> metadata code in the runtime to use retroactive conformances when satisfying generic requirements. If a retroactive conformance is provided, the corresponding witness table will be used instead of the one found by swift_conformsToProtocol(). This allows us to properly demangle type names involving retroactive conformances.
1 parent cbed03d commit ecd83fa

File tree

10 files changed

+261
-43
lines changed

10 files changed

+261
-43
lines changed

include/swift/AST/ASTDemangler.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ class ASTBuilder {
5050
using BuiltType = swift::Type;
5151
using BuiltNominalTypeDecl = swift::NominalTypeDecl *;
5252
using BuiltProtocolDecl = swift::ProtocolDecl *;
53+
using BuiltProtocolConformanceRef = swift::NormalProtocolConformance *;
54+
using BuiltProtocolConformance = void *; // a swift::ProtocolConformanceRef
5355
explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {}
5456

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

7072
Type createNominalType(NominalTypeDecl *decl, Type parent);
7173

72-
Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args);
73-
74-
Type createBoundGenericType(NominalTypeDecl *decl, ArrayRef<Type> args,
75-
Type parent);
74+
Type createBoundGenericType(
75+
NominalTypeDecl *decl, ArrayRef<Type> args,
76+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive);
77+
Type createBoundGenericType(
78+
NominalTypeDecl *decl, ArrayRef<Type> args,
79+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
80+
Type parent);
7681

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

110115
Type getOpaqueType();
111116

117+
BuiltProtocolConformanceRef
118+
createProtocolConformanceRef(Type conformingType, ProtocolDecl *protocol,
119+
StringRef module);
120+
121+
BuiltProtocolConformance
122+
createProtocolConformance(Type conformingType,
123+
NormalProtocolConformance *normal,
124+
ArrayRef<BuiltProtocolConformance> conditionalReqs);
125+
112126
private:
113127
bool validateNominalParent(NominalTypeDecl *decl, Type parent);
114128
DeclContext *findDeclContext(const Demangle::NodePointer &node);

include/swift/Demangling/TypeDecoder.h

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ class TypeDecoder {
111111
using BuiltType = typename BuilderType::BuiltType;
112112
using BuiltNominalTypeDecl = typename BuilderType::BuiltNominalTypeDecl;
113113
using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl;
114+
using BuiltProtocolConformanceRef =
115+
typename BuilderType::BuiltProtocolConformanceRef;
116+
using BuiltProtocolConformance =
117+
typename BuilderType::BuiltProtocolConformance;
114118
using NodeKind = Demangle::Node::Kind;
115119

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

187+
// Generic arguments.
183188
std::vector<BuiltType> args;
184-
185189
const auto &genericArgs = Node->getChild(1);
186-
assert(genericArgs->getKind() == NodeKind::TypeList);
190+
if (genericArgs->getKind() != NodeKind::TypeList)
191+
return BuiltType();
187192

188193
for (auto genericArg : *genericArgs) {
189194
auto paramType = decodeMangledType(genericArg);
@@ -192,7 +197,23 @@ class TypeDecoder {
192197
args.push_back(paramType);
193198
}
194199

195-
return Builder.createBoundGenericType(typeDecl, args, parent);
200+
// Retroactive conformances.
201+
std::vector<std::pair<unsigned, BuiltProtocolConformance>> retroactive;
202+
if (Node->getNumChildren() > 2 &&
203+
Node->getChild(2)->getKind() == NodeKind::TypeList) {
204+
for (auto retroNode : *Node->getChild(2)) {
205+
if (retroNode->getKind() != NodeKind::RetroactiveConformance ||
206+
!retroNode->hasIndex() || retroNode->getNumChildren() < 1)
207+
continue;
208+
209+
if (auto conformance =
210+
decodeMangledProtocolConformance(retroNode->getChild(0)))
211+
retroactive.push_back({retroNode->getIndex(), conformance});
212+
}
213+
}
214+
215+
return Builder.createBoundGenericType(typeDecl, args, retroactive,
216+
parent);
196217
}
197218
case NodeKind::BuiltinTypeName: {
198219
auto mangledName = Demangle::mangleNode(Node);
@@ -517,6 +538,73 @@ class TypeDecoder {
517538
}
518539
}
519540

541+
/// Given a demangle tree, attempt to turn it into a protocol conformance.
542+
BuiltProtocolConformance decodeMangledProtocolConformance(
543+
const Demangle::NodePointer &Node) {
544+
if (!Node) return BuiltProtocolConformance();
545+
546+
using NodeKind = Demangle::Node::Kind;
547+
switch (Node->getKind()) {
548+
case NodeKind::ConcreteProtocolConformance: {
549+
if (Node->getNumChildren() < 2)
550+
return BuiltProtocolConformance();
551+
552+
// Conforming type.
553+
BuiltType conformingType = decodeMangledType(Node->getChild(0));
554+
if (!conformingType)
555+
return BuiltProtocolConformance();
556+
557+
// Protocol conformance reference.
558+
auto conformanceRef = BuiltProtocolConformanceRef();
559+
auto conformanceRefNode = Node->getChild(1);
560+
if (conformanceRefNode->getKind() == NodeKind::ProtocolConformanceRef &&
561+
conformanceRefNode->getNumChildren() > 0) {
562+
// Protocol we are referring to.
563+
auto protocol =
564+
decodeMangledProtocolType(conformanceRefNode->getChild(0));
565+
if (!protocol)
566+
return BuiltProtocolConformance();
567+
568+
// The module in which the conformance resides, if it's retroactive.
569+
StringRef module;
570+
if (conformanceRefNode->getNumChildren() > 1 &&
571+
conformanceRefNode->getChild(1)->getKind() == NodeKind::Module) {
572+
module = conformanceRefNode->getChild(1)->getText();
573+
}
574+
575+
// Resolve the conformance reference.
576+
conformanceRef =
577+
Builder.createProtocolConformanceRef(conformingType, protocol,
578+
module);
579+
if (!conformanceRef)
580+
return BuiltProtocolConformance();
581+
} else {
582+
return BuiltProtocolConformance();
583+
}
584+
585+
// Conditional requirements.
586+
std::vector<BuiltProtocolConformance> conditionalReqs;
587+
if (Node->getNumChildren() > 2 &&
588+
Node->getChild(2)->getKind() == NodeKind::AnyProtocolConformanceList){
589+
for (auto conditionalReqNode : *Node->getChild(2)) {
590+
auto conditionalReq =
591+
decodeMangledProtocolConformance(conditionalReqNode);
592+
if (!conditionalReq)
593+
return BuiltProtocolConformance();
594+
595+
conditionalReqs.push_back(conditionalReq);
596+
}
597+
}
598+
599+
return Builder.createProtocolConformance(conformingType, conformanceRef,
600+
conditionalReqs);
601+
}
602+
603+
// FIXME: Dependent protocol conformances.
604+
default:
605+
return BuiltProtocolConformance();
606+
}
607+
}
520608
private:
521609
bool decodeMangledNominalType(Demangle::NodePointer node,
522610
BuiltNominalTypeDecl &typeDecl,

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ class TypeRefBuilder {
162162
using BuiltNominalTypeDecl = Optional<std::string>;
163163
using BuiltProtocolDecl = Optional<std::pair<std::string, bool /*isObjC*/>>;
164164

165+
// FIXME: These are stubs
166+
using BuiltProtocolConformanceRef = char;
167+
using BuiltProtocolConformance = char;
168+
165169
TypeRefBuilder();
166170

167171
TypeRefBuilder(const TypeRefBuilder &other) = delete;
@@ -240,15 +244,21 @@ class TypeRefBuilder {
240244
}
241245

242246
const BoundGenericTypeRef *
243-
createBoundGenericType(const Optional<std::string> &mangledName,
244-
const std::vector<const TypeRef *> &args) {
247+
createBoundGenericType(
248+
const Optional<std::string> &mangledName,
249+
const std::vector<const TypeRef *> &args,
250+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive) {
251+
// FIXME: Retroactive conformances.
245252
return BoundGenericTypeRef::create(*this, *mangledName, args, nullptr);
246253
}
247254

248255
const BoundGenericTypeRef *
249-
createBoundGenericType(const Optional<std::string> &mangledName,
250-
const std::vector<const TypeRef *> &args,
251-
const TypeRef *parent) {
256+
createBoundGenericType(
257+
const Optional<std::string> &mangledName,
258+
const std::vector<const TypeRef *> &args,
259+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
260+
const TypeRef *parent) {
261+
// FIXME: Retroactive conformances.
252262
return BoundGenericTypeRef::create(*this, *mangledName, args, parent);
253263
}
254264

@@ -349,6 +359,22 @@ class TypeRefBuilder {
349359
return OpaqueTypeRef::get();
350360
}
351361

362+
BuiltProtocolConformanceRef createProtocolConformanceRef(
363+
BuiltType conformingType,
364+
BuiltProtocolDecl protocol,
365+
StringRef module) {
366+
// FIXME: Implement protocol conformance descriptor lookup.
367+
return false;
368+
}
369+
370+
BuiltProtocolConformance createProtocolConformance(
371+
BuiltType conformingType,
372+
BuiltProtocolConformanceRef conformance,
373+
ArrayRef<BuiltProtocolConformance> conditionalReqs) {
374+
// FIXME: Implement witness table computation.
375+
return false;
376+
}
377+
352378
///
353379
/// Parsing reflection metadata
354380
///

include/swift/Remote/MetadataReader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ class MetadataReader {
16941694
auto builtGenerics = getGenericSubst(metadata, descriptor);
16951695
if (builtGenerics.empty())
16961696
return BuiltType();
1697-
nominal = Builder.createBoundGenericType(typeDecl, builtGenerics);
1697+
nominal = Builder.createBoundGenericType(typeDecl, builtGenerics, { });
16981698
} else {
16991699
nominal = Builder.createNominalType(typeDecl);
17001700
}

lib/AST/ASTDemangler.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ Type ASTBuilder::createNominalType(NominalTypeDecl *decl, Type parent) {
8686
return NominalType::get(decl, parent, Ctx);
8787
}
8888

89-
Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
90-
ArrayRef<Type> args) {
89+
Type ASTBuilder::createBoundGenericType(
90+
NominalTypeDecl *decl,
91+
ArrayRef<Type> args,
92+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive) {
9193
// If the declaration isn't generic, fail.
9294
if (!decl->isGenericContext())
9395
return Type();
@@ -123,9 +125,11 @@ Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
123125
return substType;
124126
}
125127

126-
Type ASTBuilder::createBoundGenericType(NominalTypeDecl *decl,
127-
ArrayRef<Type> args,
128-
Type parent) {
128+
Type ASTBuilder::createBoundGenericType(
129+
NominalTypeDecl *decl,
130+
ArrayRef<Type> args,
131+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
132+
Type parent) {
129133
// If the declaration isn't generic, fail.
130134
if (!decl->getGenericParams())
131135
return Type();
@@ -685,3 +689,20 @@ ASTBuilder::findForeignNominalTypeDecl(StringRef name,
685689

686690
return consumer.Result;
687691
}
692+
693+
auto ASTBuilder::createProtocolConformanceRef(Type conformingType,
694+
ProtocolDecl *protocol,
695+
StringRef module)
696+
-> BuiltProtocolConformanceRef {
697+
// FIXME: Implement lookup.
698+
return nullptr;
699+
}
700+
701+
auto ASTBuilder::createProtocolConformance(
702+
Type conformingType,
703+
NormalProtocolConformance *normal,
704+
ArrayRef<BuiltProtocolConformance> conditionalReqs)
705+
-> BuiltProtocolConformance {
706+
// FIXME: Implement specialization.
707+
return nullptr;
708+
}

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,8 @@ class DecodedMetadataBuilder {
929929
using BuiltType = const Metadata *;
930930
using BuiltNominalTypeDecl = const TypeContextDescriptor *;
931931
using BuiltProtocolDecl = ProtocolDescriptorRef;
932+
using BuiltProtocolConformance = const WitnessTable *;
933+
using BuiltProtocolConformanceRef = const ProtocolConformanceDescriptor *;
932934

933935
Demangle::NodeFactory &getNodeFactory() { return demangler; }
934936

@@ -979,12 +981,14 @@ class DecodedMetadataBuilder {
979981
BuiltType parent) const {
980982
// Treat nominal type creation the same way as generic type creation,
981983
// but with no generic arguments at this level.
982-
return createBoundGenericType(metadataOrTypeDecl, { }, parent);
984+
return createBoundGenericType(metadataOrTypeDecl, { }, { }, parent);
983985
}
984986

985-
BuiltType createBoundGenericType(BuiltNominalTypeDecl typeDecl,
986-
const ArrayRef<BuiltType> genericArgs,
987-
const BuiltType parent) const {
987+
BuiltType createBoundGenericType(
988+
BuiltNominalTypeDecl typeDecl,
989+
const ArrayRef<BuiltType> genericArgs,
990+
ArrayRef<std::pair<unsigned, BuiltProtocolConformance>> retroactive,
991+
const BuiltType parent) const {
988992
// Figure out the various levels of generic parameters we have in
989993
// this type.
990994
std::vector<unsigned> genericParamCounts;
@@ -1045,7 +1049,14 @@ class DecodedMetadataBuilder {
10451049
bool failed =
10461050
_checkGenericRequirements(genericContext->getGenericRequirements(),
10471051
allGenericArgsVec, substitutions,
1048-
substitutions);
1052+
substitutions,
1053+
[&](unsigned index) -> const WitnessTable * {
1054+
for (const auto &retro : retroactive) {
1055+
if (retro.first == index)
1056+
return retro.second;
1057+
}
1058+
return nullptr;
1059+
});
10491060
if (failed)
10501061
return BuiltType();
10511062

@@ -1169,6 +1180,29 @@ class DecodedMetadataBuilder {
11691180
return BuiltType();
11701181
}
11711182

1183+
BuiltProtocolConformanceRef createProtocolConformanceRef(
1184+
BuiltType conformingType,
1185+
BuiltProtocolDecl protocol,
1186+
StringRef module) {
1187+
return _conformsToSwiftProtocol(conformingType, protocol.getSwiftProtocol(),
1188+
module);
1189+
}
1190+
1191+
BuiltProtocolConformance createProtocolConformance(
1192+
BuiltType conformingType,
1193+
BuiltProtocolConformanceRef conformance,
1194+
ArrayRef<BuiltProtocolConformance> conditionalReqs) {
1195+
// Make sure we have the right number of conditional requirements.
1196+
if (conditionalReqs.size() !=
1197+
conformance->getConditionalRequirements().size())
1198+
return BuiltProtocolConformance();
1199+
1200+
// Retrieve the specific witness table.
1201+
return swift_getWitnessTable(
1202+
conformance, conformingType,
1203+
reinterpret_cast<const void * const *>(conditionalReqs.data()));
1204+
}
1205+
11721206
TypeReferenceOwnership getReferenceOwnership() const {
11731207
return ReferenceOwnership;
11741208
}

stdlib/public/runtime/Private.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,17 @@ class TypeInfo {
341341
/// generic requirements (e.g., those that need to be
342342
/// passed to an instantiation function) will be added to this vector.
343343
///
344+
/// \param getWitnessTable Function object that returns the Ith witness table,
345+
/// if it's already known. This can return NULL to indicate that the witness
346+
/// table should be looked up dynamically.
347+
///
344348
/// \returns true if an error occurred, false otherwise.
345349
bool _checkGenericRequirements(
346-
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
347-
std::vector<const void *> &extraArguments,
348-
SubstFlatGenericParameterFn substFlatGenericParam,
349-
SubstGenericParameterFn substGenericParam);
350+
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
351+
std::vector<const void *> &extraArguments,
352+
SubstFlatGenericParameterFn substFlatGenericParam,
353+
SubstGenericParameterFn substGenericParam,
354+
std::function<const WitnessTable *(unsigned index)> getWitnessTable);
350355

351356
/// A helper function which avoids performing a store if the destination
352357
/// address already contains the source value. This is useful when

0 commit comments

Comments
 (0)