Skip to content

Commit 9464060

Browse files
authored
Merge pull request #20230 from DougGregor/mangled-protocol-conformances
[Mangling] Introduce mangling for protocol conformances.
2 parents 43f04ee + 8906b06 commit 9464060

17 files changed

+596
-43
lines changed

docs/ABI/Mangling.rst

Lines changed: 37 additions & 5 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

@@ -685,7 +717,7 @@ from any character in a ``<GENERIC-PARAM-COUNT>``.
685717

686718
::
687719

688-
retroactive-conformance ::= protocol-conformance 'g' INDEX
720+
retroactive-conformance ::= any-protocol-conformance 'g' INDEX
689721

690722
When a protocol conformance used to satisfy one of a bound generic type's
691723
generic requirements is retroactive (i.e., it is specified in a module other

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: 180 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,48 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
11121112
}
11131113
}
11141114

1115+
/// Determine whether the given protocol conformance is itself retroactive,
1116+
/// meaning that there might be multiple conflicting conformances of the
1117+
/// same type to the same protocol.
1118+
static bool isRetroactiveConformance(
1119+
const NormalProtocolConformance *conformance) {
1120+
/// Non-retroactive conformances are... never retroactive.
1121+
if (!conformance->isRetroactive())
1122+
return false;
1123+
1124+
/// Synthesized non-unique conformances all get collapsed together at run
1125+
/// time.
1126+
if (conformance->isSynthesizedNonUnique())
1127+
return false;
1128+
1129+
/// Objective-C protocol conformances don't have identity.
1130+
if (conformance->getProtocol()->isObjC())
1131+
return false;
1132+
1133+
return true;
1134+
}
1135+
1136+
/// Determine whether the given protocol conformance contains a retroactive
1137+
/// protocol conformance anywhere in it.
1138+
static bool containsRetroactiveConformance(
1139+
const ProtocolConformance *conformance,
1140+
ModuleDecl *module) {
1141+
// If the root conformance is retroactive, it's retroactive.
1142+
if (isRetroactiveConformance(conformance->getRootNormalConformance()))
1143+
return true;
1144+
1145+
// If any of the substitutions used to form this conformance are retroactive,
1146+
// it's retroactive.
1147+
auto subMap = conformance->getSubstitutions(module);
1148+
for (auto conformance : subMap.getConformances()) {
1149+
if (conformance.isConcrete() &&
1150+
containsRetroactiveConformance(conformance.getConcrete(), module))
1151+
return true;
1152+
}
1153+
1154+
return false;
1155+
}
1156+
11151157
void ASTMangler::appendRetroactiveConformances(Type type) {
11161158
auto nominal = type->getAnyNominal();
11171159
if (!nominal) return;
@@ -1124,28 +1166,20 @@ void ASTMangler::appendRetroactiveConformances(Type type) {
11241166
if (subMap.empty()) return;
11251167

11261168
unsigned numProtocolRequirements = 0;
1127-
for (const auto &req: genericSig->getRequirements()) {
1128-
if (req.getKind() != RequirementKind::Conformance)
1129-
continue;
1130-
1169+
for (auto conformance : subMap.getConformances()) {
11311170
SWIFT_DEFER {
11321171
++numProtocolRequirements;
11331172
};
11341173

1135-
// Fast path: we're in the module of the protocol.
1136-
auto proto = req.getSecondType()->castTo<ProtocolType>()->getDecl();
1137-
if (proto->getModuleContext() == module)
1174+
// Ignore abstract conformances.
1175+
if (!conformance.isConcrete())
11381176
continue;
11391177

1140-
auto conformance =
1141-
subMap.lookupConformance(req.getFirstType()->getCanonicalType(), proto);
1142-
if (!conformance || !conformance->isConcrete()) continue;
1143-
1144-
auto normal = conformance->getConcrete()->getRootNormalConformance();
1145-
if (!normal->isRetroactive() || normal->isSynthesizedNonUnique())
1178+
// Skip non-retroactive conformances.
1179+
if (!containsRetroactiveConformance(conformance.getConcrete(), module))
11461180
continue;
11471181

1148-
appendProtocolConformance(normal);
1182+
appendConcreteProtocolConformance(conformance.getConcrete());
11491183
appendOperator("g", Index(numProtocolRequirements));
11501184
}
11511185
}
@@ -2240,6 +2274,138 @@ ASTMangler::appendProtocolConformance(const ProtocolConformance *conformance) {
22402274
}
22412275
}
22422276

2277+
void ASTMangler::appendProtocolConformanceRef(
2278+
const NormalProtocolConformance *conformance) {
2279+
// FIXME: Symbolic reference to the protocol conformance descriptor.
2280+
appendProtocolName(conformance->getProtocol());
2281+
2282+
// For retroactive conformances, add a reference to the module in which the
2283+
// conformance resides. For @objc protocols, there is no point: conformances
2284+
// are global anyway.
2285+
if (conformance->isRetroactive() && !conformance->isSynthesizedNonUnique() &&
2286+
!conformance->getProtocol()->isObjC())
2287+
appendModule(conformance->getDeclContext()->getParentModule());
2288+
}
2289+
2290+
/// Retrieve the index of the conformance requirement indicated by the
2291+
/// conformance access path entry within the given set of requirements.
2292+
static unsigned conformanceRequirementIndex(
2293+
const ConformanceAccessPath::Entry &entry,
2294+
ArrayRef<Requirement> requirements) {
2295+
unsigned result = 0;
2296+
for (const auto &req : requirements) {
2297+
if (req.getKind() != RequirementKind::Conformance)
2298+
continue;
2299+
2300+
if (req.getFirstType()->isEqual(entry.first) &&
2301+
req.getSecondType()->castTo<ProtocolType>()->getDecl() == entry.second)
2302+
return result;
2303+
2304+
++result;
2305+
}
2306+
2307+
llvm_unreachable("Conformance access path step is missing from requirements");
2308+
}
2309+
2310+
void ASTMangler::appendDependentProtocolConformance(
2311+
const ConformanceAccessPath &path) {
2312+
ProtocolDecl *currentProtocol = nullptr;
2313+
for (const auto &entry : path) {
2314+
// After each step, update the current protocol to refer to where we
2315+
// are.
2316+
SWIFT_DEFER {
2317+
currentProtocol = entry.second;
2318+
};
2319+
2320+
// The first entry is the "root". Find this requirement in the generic
2321+
// signature.
2322+
if (!currentProtocol) {
2323+
appendType(entry.first);
2324+
appendProtocolName(entry.second);
2325+
auto index =
2326+
conformanceRequirementIndex(entry,
2327+
CurGenericSignature->getRequirements());
2328+
appendOperator("HD", index + 1);
2329+
continue;
2330+
}
2331+
2332+
// Conformances are relative to the current protocol's requirement
2333+
// signature.
2334+
auto index =
2335+
conformanceRequirementIndex(entry,
2336+
currentProtocol->getRequirementSignature());
2337+
2338+
// Inherited conformance.
2339+
bool isInheritedConformance =
2340+
entry.first->isEqual(currentProtocol->getProtocolSelfType());
2341+
if (isInheritedConformance) {
2342+
appendProtocolName(entry.second);
2343+
appendOperator("HI", index + 1);
2344+
continue;
2345+
}
2346+
2347+
// Associated conformance.
2348+
// FIXME: Symbolic reference.
2349+
appendType(entry.first);
2350+
appendProtocolName(entry.second);
2351+
2352+
// For non-resilient protocols, encode the index.
2353+
bool isResilient =
2354+
currentProtocol->isResilient(Mod, ResilienceExpansion::Maximal);
2355+
appendOperator("HA", isResilient ? 0 : index + 1);
2356+
}
2357+
}
2358+
2359+
void ASTMangler::appendConcreteProtocolConformance(
2360+
const ProtocolConformance *conformance) {
2361+
auto module = conformance->getDeclContext()->getParentModule();
2362+
2363+
// Conforming type.
2364+
Type conformingType = conformance->getType();
2365+
if (conformingType->hasArchetype())
2366+
conformingType = conformingType->mapTypeOutOfContext();
2367+
appendType(conformingType->getCanonicalType());
2368+
2369+
// Protocol conformance reference.
2370+
appendProtocolConformanceRef(conformance->getRootNormalConformance());
2371+
2372+
// Conditional conformance requirements.
2373+
bool firstRequirement = true;
2374+
for (const auto &conditionalReq : conformance->getConditionalRequirements()) {
2375+
switch (conditionalReq.getKind()) {
2376+
case RequirementKind::Layout:
2377+
case RequirementKind::SameType:
2378+
case RequirementKind::Superclass:
2379+
continue;
2380+
2381+
case RequirementKind::Conformance: {
2382+
auto type = conditionalReq.getFirstType();
2383+
if (type->hasArchetype())
2384+
type = type->mapTypeOutOfContext();
2385+
CanType canType = type->getCanonicalType(CurGenericSignature);
2386+
auto proto =
2387+
conditionalReq.getSecondType()->castTo<ProtocolType>()->getDecl();
2388+
if (canType->isTypeParameter()) {
2389+
assert(CurGenericSignature &&
2390+
"Need a generic signature to resolve conformance");
2391+
auto conformanceAccessPath =
2392+
CurGenericSignature->getConformanceAccessPath(type, proto);
2393+
appendDependentProtocolConformance(conformanceAccessPath);
2394+
} else {
2395+
auto conditionalConf = module->lookupConformance(canType, proto);
2396+
appendConcreteProtocolConformance(conditionalConf->getConcrete());
2397+
}
2398+
appendListSeparator(firstRequirement);
2399+
break;
2400+
}
2401+
}
2402+
}
2403+
if (firstRequirement)
2404+
appendOperator("y");
2405+
2406+
appendOperator("HC");
2407+
}
2408+
22432409
void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
22442410
assert(layout);
22452411
switch (layout->getKind()) {

lib/AST/ProtocolConformance.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,19 @@ bool NormalProtocolConformance::isRetroactive() const {
363363
// If the conformance occurs in the same module as the conforming type
364364
// definition, this is not a retroactive conformance.
365365
if (auto nominal = getType()->getAnyNominal()) {
366-
if (module == nominal->getParentModule())
366+
auto nominalModule = nominal->getParentModule();
367+
368+
// Consider the overlay module to be the "home" of a nominal type
369+
// defined in a Clang module.
370+
if (auto nominalClangModule =
371+
dyn_cast<ClangModuleUnit>(nominal->getModuleScopeContext())) {
372+
if (auto clangLoader = nominal->getASTContext().getClangModuleLoader()) {
373+
if (auto overlayModule = nominalClangModule->getAdapterModule())
374+
nominalModule = overlayModule;
375+
}
376+
}
377+
378+
if (module == nominalModule)
367379
return false;
368380
}
369381

0 commit comments

Comments
 (0)