Skip to content

Commit 1efe2bc

Browse files
committed
[Mangling] Introduce mangling for protocol conformances.
Introduce complete mangling for references to protocol conformances: * Mangle requirements of conditional conformances when present. * Mangle conformance access paths for generic environment-dependent conformances. * Abstract protocol conformance references so we can introduce symbolic references for them.
1 parent d1089c3 commit 1efe2bc

File tree

9 files changed

+475
-5
lines changed

9 files changed

+475
-5
lines changed

docs/ABI/Mangling.rst

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ The following symbolic reference kinds are currently implemented:
8787
protocol-conformance-ref ::= '\x03' .{4} // Reference points directly to protocol conformance descriptor (NOT IMPLEMENTED)
8888
protocol-conformance-ref ::= '\x04' .{4} // Reference points indirectly to protocol conformance descriptor (NOT IMPLEMENTED)
8989

90+
dependent-associated-conformance ::= '\x05' .{4} // Reference points directly to associated conformance descriptor (NOT IMPLEMENTED)
91+
dependent-associated-conformance ::= '\x06' .{4} // Reference points indirectly to associated conformance descriptor (NOT IMPLEMENTED)
9092

9193
Globals
9294
~~~~~~~
@@ -619,13 +621,43 @@ Property behaviors are implemented using private protocol conformances.
619621

620622
::
621623

622-
concrete-protocol-conformance ::= type protocol-conformance-ref
624+
concrete-protocol-conformance ::= type protocol-conformance-ref any-protocol-conformance-list 'HC'
623625
protocol-conformance-ref ::= protocol module?
624626

627+
any-protocol-conformance ::= concrete-protocol-conformance
628+
any-protocol-conformance ::= dependent-protocol-conformance
629+
630+
any-protocol-conformance-list ::= any-protocol-conformance '_' any-protocol-conformance-list
631+
any-protocol-conformance-list ::= empty-list
632+
633+
DEPENDENT-CONFORMANCE-INDEX ::= INDEX
634+
635+
dependent-protocol-conformance ::= type protocol 'HD' DEPENDENT-CONFORMANCE-INDEX
636+
dependent-protocol-conformance ::= dependent-protocol-conformance protocol 'HI' DEPENDENT-CONFORMANCE-INDEX
637+
dependent-protocol-conformance ::= dependent-protocol-conformance
638+
dependent-associated-conformance 'HA' DEPENDENT-CONFORMANCE-INDEX
639+
640+
dependent-associated-conformance ::= type protocol
641+
625642
A compact representation used to represent mangled protocol conformance witness
626-
arguments at runtime. The ``module`` is only specified for conformances that
627-
are "retroactive", meaning that the context in which the conformance is defined
628-
is in neither the protocol or type module.
643+
arguments at runtime. The ``module`` is only specified for conformances that are
644+
"retroactive", meaning that the context in which the conformance is defined is
645+
in neither the protocol or type module. The concrete protocol conformances that
646+
follow are for the conditional conformance requirements.
647+
648+
Dependent protocol conformances mangle the access path required to extract a
649+
protocol conformance from some conformance passed into the environment. The
650+
first case (operator "HD") is the leaf requirement, containing a dependent type
651+
and the protocol it conforms to. The remaining dependent protocol conformance
652+
manglings describe lookups performed on their child dependent protocol
653+
conformances. The "HI" operator retrieves the named inherited protocol from the
654+
witness table produced by the child. The "HA" operator refers to an associated
655+
conformance within the witness table, identified by the dependent type and
656+
protocol. In all cases, the DEPENDENT-CONFORMANCE-INDEX is an INDEX value
657+
indicating the position of the appropriate value within the generic environment
658+
(for "HD") or witness table (for "HI" and "HA") when it is known to be at a
659+
fixed position. A position of zero is used to indicate "unknown"; all other
660+
values are adjusted by 1.
629661

630662
::
631663

include/swift/AST/ASTMangler.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class NamedDecl;
2424
namespace swift {
2525

2626
class AbstractClosureExpr;
27+
class ConformanceAccessPath;
2728

2829
namespace Mangle {
2930

@@ -299,7 +300,11 @@ class ASTMangler : public Mangler {
299300
void appendEntity(const ValueDecl *decl);
300301

301302
void appendProtocolConformance(const ProtocolConformance *conformance);
302-
303+
void appendProtocolConformanceRef(
304+
const NormalProtocolConformance *conformance);
305+
void appendConcreteProtocolConformance(
306+
const ProtocolConformance *conformance);
307+
void appendDependentProtocolConformance(const ConformanceAccessPath &path);
303308
void appendOpParamForLayoutConstraint(LayoutConstraint Layout);
304309

305310
void appendSymbolicReference(SymbolicReferent referent);

include/swift/Demangling/DemangleNodes.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
CONTEXT_NODE(Allocator)
2828
CONTEXT_NODE(AnonymousContext)
29+
NODE(AnyProtocolConformanceList)
2930
NODE(ArgumentTuple)
3031
NODE(AssociatedType)
3132
NODE(AssociatedTypeRef)
@@ -44,11 +45,13 @@ NODE(BuiltinTypeName)
4445
NODE(CFunctionPointer)
4546
CONTEXT_NODE(Class)
4647
NODE(ClassMetadataBaseOffset)
48+
NODE(ConcreteProtocolConformance)
4749
CONTEXT_NODE(Constructor)
4850
NODE(CoroutineContinuationPrototype)
4951
CONTEXT_NODE(Deallocator)
5052
NODE(DeclContext)
5153
CONTEXT_NODE(DefaultArgumentInitializer)
54+
NODE(DependentAssociatedConformance)
5255
NODE(DependentAssociatedTypeRef)
5356
NODE(DependentGenericConformanceRequirement)
5457
NODE(DependentGenericParamCount)
@@ -59,6 +62,9 @@ NODE(DependentGenericSignature)
5962
NODE(DependentGenericType)
6063
NODE(DependentMemberType)
6164
NODE(DependentPseudogenericSignature)
65+
NODE(DependentProtocolConformanceRoot)
66+
NODE(DependentProtocolConformanceInherited)
67+
NODE(DependentProtocolConformanceAssociated)
6268
CONTEXT_NODE(Destructor)
6369
CONTEXT_NODE(DidSet)
6470
NODE(Directness)
@@ -146,6 +152,7 @@ NODE(PropertyDescriptor)
146152
CONTEXT_NODE(Protocol)
147153
CONTEXT_NODE(ProtocolSymbolicReference)
148154
NODE(ProtocolConformance)
155+
NODE(ProtocolConformanceRef)
149156
NODE(ProtocolDescriptor)
150157
NODE(ProtocolConformanceDescriptor)
151158
NODE(ProtocolList)

include/swift/Demangling/Demangler.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ class Demangler : public NodeFactory {
440440
NodePointer demangleBoundGenericArgs(NodePointer nominalType,
441441
const Vector<NodePointer> &TypeLists,
442442
size_t TypeListIdx);
443+
NodePointer popAnyProtocolConformanceList();
443444
NodePointer demangleRetroactiveConformance();
444445
NodePointer demangleInitializer();
445446
NodePointer demangleImplParamConvention();
@@ -457,6 +458,14 @@ class Demangler : public NodeFactory {
457458
NodePointer getDependentGenericParamType(int depth, int index);
458459
NodePointer demangleGenericParamIndex();
459460
NodePointer popProtocolConformance();
461+
NodePointer popProtocolConformanceRef();
462+
NodePointer popAnyProtocolConformance();
463+
NodePointer demangleConcreteProtocolConformance();
464+
NodePointer popDependentProtocolConformance();
465+
NodePointer demangleDependentProtocolConformanceRoot();
466+
NodePointer demangleDependentProtocolConformanceInherited();
467+
NodePointer popDependentAssociatedConformance();
468+
NodePointer demangleDependentProtocolConformanceAssociated();
460469
NodePointer demangleThunkOrSpecialization();
461470
NodePointer demangleGenericSpecialization(Node::Kind SpecKind);
462471
NodePointer demangleFunctionSpecialization();

lib/AST/ASTMangler.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,6 +2240,138 @@ ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance) {
22402240
}
22412241
}
22422242

2243+
void ASTMangler::appendProtocolConformanceRef(
2244+
const NormalProtocolConformance *conformance) {
2245+
// FIXME: Symbolic reference to the protocol conformance descriptor.
2246+
appendProtocolName(conformance->getProtocol());
2247+
2248+
// For retroactive conformances, add a reference to the module in which the
2249+
// conformance resides. For @objc protocols, there is no point: conformances
2250+
// are global anyway.
2251+
if (conformance->isRetroactive() && !conformance->isSynthesizedNonUnique() &&
2252+
!conformance->getProtocol()->isObjC())
2253+
appendModule(conformance->getDeclContext()->getParentModule());
2254+
}
2255+
2256+
/// Retrieve the index of the conformance requirement indicated by the
2257+
/// conformance access path entry within the given set of requirements.
2258+
static unsigned conformanceRequirementIndex(
2259+
const ConformanceAccessPath::Entry &entry,
2260+
ArrayRef<Requirement> requirements) {
2261+
unsigned result = 0;
2262+
for (const auto &req : requirements) {
2263+
if (req.getKind() != RequirementKind::Conformance)
2264+
continue;
2265+
2266+
if (req.getFirstType()->isEqual(entry.first) &&
2267+
req.getSecondType()->castTo<ProtocolType>()->getDecl() == entry.second)
2268+
return result;
2269+
2270+
++result;
2271+
}
2272+
2273+
llvm_unreachable("Conformance access path step is missing from requirements");
2274+
}
2275+
2276+
void ASTMangler::appendDependentProtocolConformance(
2277+
const ConformanceAccessPath &path) {
2278+
ProtocolDecl *currentProtocol = nullptr;
2279+
for (const auto &entry : path) {
2280+
// After each step, update the current protocol to refer to where we
2281+
// are.
2282+
SWIFT_DEFER {
2283+
currentProtocol = entry.second;
2284+
};
2285+
2286+
// The first entry is the "root". Find this requirement in the generic
2287+
// signature.
2288+
if (!currentProtocol) {
2289+
appendType(entry.first);
2290+
appendProtocolName(entry.second);
2291+
auto index =
2292+
conformanceRequirementIndex(entry,
2293+
CurGenericSignature->getRequirements());
2294+
appendOperator("HD", index + 1);
2295+
continue;
2296+
}
2297+
2298+
// Conformances are relative to the current protocol's requirement
2299+
// signature.
2300+
auto index =
2301+
conformanceRequirementIndex(entry,
2302+
currentProtocol->getRequirementSignature());
2303+
2304+
// Inherited conformance.
2305+
bool isInheritedConformance =
2306+
entry.first->isEqual(currentProtocol->getProtocolSelfType());
2307+
if (isInheritedConformance) {
2308+
appendProtocolName(entry.second);
2309+
appendOperator("HI", index + 1);
2310+
continue;
2311+
}
2312+
2313+
// Associated conformance.
2314+
// FIXME: Symbolic reference.
2315+
appendType(entry.first);
2316+
appendProtocolName(entry.second);
2317+
2318+
// For non-resilient protocols, encode the index.
2319+
bool isResilient =
2320+
currentProtocol->isResilient(Mod, ResilienceExpansion::Maximal);
2321+
appendOperator("HA", isResilient ? 0 : index + 1);
2322+
}
2323+
}
2324+
2325+
void ASTMangler::appendConcreteProtocolConformance(
2326+
const ProtocolConformance *conformance) {
2327+
auto module = conformance->getDeclContext()->getParentModule();
2328+
2329+
// Conforming type.
2330+
Type conformingType = conformance->getType();
2331+
if (conformingType->hasArchetype())
2332+
conformingType = conformingType->mapTypeOutOfContext();
2333+
appendType(conformingType->getCanonicalType());
2334+
2335+
// Protocol conformance reference.
2336+
appendProtocolConformanceRef(conformance->getRootNormalConformance());
2337+
2338+
// Conditional conformance requirements.
2339+
bool firstRequirement = true;
2340+
for (const auto &conditionalReq : conformance->getConditionalRequirements()) {
2341+
switch (conditionalReq.getKind()) {
2342+
case RequirementKind::Layout:
2343+
case RequirementKind::SameType:
2344+
case RequirementKind::Superclass:
2345+
continue;
2346+
2347+
case RequirementKind::Conformance: {
2348+
auto type = conditionalReq.getFirstType();
2349+
if (type->hasArchetype())
2350+
type = type->mapTypeOutOfContext();
2351+
CanType canType = type->getCanonicalType(CurGenericSignature);
2352+
auto proto =
2353+
conditionalReq.getSecondType()->castTo<ProtocolType>()->getDecl();
2354+
if (canType->isTypeParameter()) {
2355+
assert(CurGenericSignature &&
2356+
"Need a generic signature to resolve conformance");
2357+
auto conformanceAccessPath =
2358+
CurGenericSignature->getConformanceAccessPath(type, proto);
2359+
appendDependentProtocolConformance(conformanceAccessPath);
2360+
} else {
2361+
auto conditionalConf = module->lookupConformance(canType, proto);
2362+
appendConcreteProtocolConformance(conditionalConf->getConcrete());
2363+
}
2364+
appendListSeparator(firstRequirement);
2365+
break;
2366+
}
2367+
}
2368+
}
2369+
if (firstRequirement)
2370+
appendOperator("y");
2371+
2372+
appendOperator("HC");
2373+
}
2374+
22432375
void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
22442376
assert(layout);
22452377
switch (layout->getKind()) {

0 commit comments

Comments
 (0)