Skip to content

Commit 8c2551f

Browse files
authored
Merge pull request #21478 from jrose-apple/5.0-conditionally-retro
[5.0] [ABI] [Mangling] Disambiguate protocol-conformance-ref better
2 parents f47a967 + a0a2ad4 commit 8c2551f

File tree

10 files changed

+171
-50
lines changed

10 files changed

+171
-50
lines changed

docs/ABI/Mangling.rst

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,9 @@ Property behaviors are implemented using private protocol conformances.
633633
::
634634

635635
concrete-protocol-conformance ::= type protocol-conformance-ref any-protocol-conformance-list 'HC'
636-
protocol-conformance-ref ::= protocol module? 'HP'
636+
protocol-conformance-ref ::= protocol 'HP' // same module as conforming type
637+
protocol-conformance-ref ::= protocol 'Hp' // same module as protocol
638+
protocol-conformance-ref ::= protocol module // "retroactive"
637639

638640
any-protocol-conformance ::= concrete-protocol-conformance
639641
any-protocol-conformance ::= dependent-protocol-conformance
@@ -651,10 +653,13 @@ Property behaviors are implemented using private protocol conformances.
651653
dependent-associated-conformance ::= type protocol
652654

653655
A compact representation used to represent mangled protocol conformance witness
654-
arguments at runtime. The ``module`` is only specified for conformances that are
655-
"retroactive", meaning that the context in which the conformance is defined is
656-
in neither the protocol or type module. The concrete protocol conformances that
657-
follow are for the conditional conformance requirements.
656+
arguments at runtime. The ``module`` is only specified for conformances that
657+
are "retroactive", meaning that the context in which the conformance is defined
658+
is in neither the protocol or type module. For a non-retroactive conformance
659+
where both the type *and* the protocol are in the same module, or for
660+
synthesized conformances that have no owning module, the "HP" operator is
661+
preferred. The concrete protocol conformances that follow are for the
662+
conditional conformance requirements.
658663

659664
Dependent protocol conformances mangle the access path required to extract a
660665
protocol conformance from some conformance passed into the environment. The

include/swift/Demangling/DemangleNodes.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,9 @@ NODE(PropertyDescriptor)
156156
CONTEXT_NODE(Protocol)
157157
CONTEXT_NODE(ProtocolSymbolicReference)
158158
NODE(ProtocolConformance)
159-
NODE(ProtocolConformanceRef)
159+
NODE(ProtocolConformanceRefInTypeModule)
160+
NODE(ProtocolConformanceRefInProtocolModule)
161+
NODE(ProtocolConformanceRefInOtherModule)
160162
NODE(ProtocolDescriptor)
161163
NODE(ProtocolConformanceDescriptor)
162164
NODE(ProtocolList)

include/swift/Demangling/Demangler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ class Demangler : public NodeFactory {
458458
NodePointer getDependentGenericParamType(int depth, int index);
459459
NodePointer demangleGenericParamIndex();
460460
NodePointer popProtocolConformance();
461-
NodePointer demangleProtocolConformanceRef();
461+
NodePointer demangleRetroactiveProtocolConformanceRef();
462462
NodePointer popAnyProtocolConformance();
463463
NodePointer demangleConcreteProtocolConformance();
464464
NodePointer popDependentProtocolConformance();

lib/AST/ASTMangler.cpp

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,48 +1110,69 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
11101110
}
11111111
}
11121112

1113-
/// Determine whether the given protocol conformance is itself retroactive,
1114-
/// meaning that there might be multiple conflicting conformances of the
1115-
/// same type to the same protocol.
1116-
static bool isRetroactiveConformance(const RootProtocolConformance *root) {
1113+
static bool conformanceHasIdentity(const RootProtocolConformance *root) {
11171114
auto conformance = dyn_cast<NormalProtocolConformance>(root);
11181115
if (!conformance) {
11191116
assert(isa<SelfProtocolConformance>(root));
1120-
return false; // self-conformances are never retroactive.
1117+
return true;
11211118
}
11221119

1123-
/// Non-retroactive conformances are... never retroactive.
1124-
if (!conformance->isRetroactive())
1125-
return false;
1126-
1127-
/// Synthesized non-unique conformances all get collapsed together at run
1128-
/// time.
1120+
// Synthesized non-unique conformances all get collapsed together at run time.
11291121
if (conformance->isSynthesizedNonUnique())
11301122
return false;
11311123

1132-
/// Objective-C protocol conformances don't have identity.
1124+
// Objective-C protocol conformances are checked by the ObjC runtime.
11331125
if (conformance->getProtocol()->isObjC())
11341126
return false;
11351127

11361128
return true;
11371129
}
11381130

1131+
/// Determine whether the given protocol conformance is itself retroactive,
1132+
/// meaning that there might be multiple conflicting conformances of the
1133+
/// same type to the same protocol.
1134+
static bool isRetroactiveConformance(const RootProtocolConformance *root) {
1135+
auto conformance = dyn_cast<NormalProtocolConformance>(root);
1136+
if (!conformance) {
1137+
assert(isa<SelfProtocolConformance>(root));
1138+
return false; // self-conformances are never retroactive.
1139+
}
1140+
1141+
return conformance->isRetroactive();
1142+
}
1143+
11391144
/// Determine whether the given protocol conformance contains a retroactive
11401145
/// protocol conformance anywhere in it.
11411146
static bool containsRetroactiveConformance(
11421147
const ProtocolConformance *conformance,
11431148
ModuleDecl *module) {
11441149
// If the root conformance is retroactive, it's retroactive.
1145-
if (isRetroactiveConformance(conformance->getRootConformance()))
1150+
const RootProtocolConformance *rootConformance =
1151+
conformance->getRootConformance();
1152+
if (isRetroactiveConformance(rootConformance) &&
1153+
conformanceHasIdentity(rootConformance))
11461154
return true;
11471155

1148-
// If any of the substitutions used to form this conformance are retroactive,
1149-
// it's retroactive.
1156+
// If the conformance is conditional and any of the substitutions used to
1157+
// satisfy the conditions are retroactive, it's retroactive.
11501158
auto subMap = conformance->getSubstitutions(module);
1151-
for (auto conformance : subMap.getConformances()) {
1152-
if (conformance.isConcrete() &&
1153-
containsRetroactiveConformance(conformance.getConcrete(), module))
1159+
for (auto requirement : rootConformance->getConditionalRequirements()) {
1160+
if (requirement.getKind() != RequirementKind::Conformance)
1161+
continue;
1162+
ProtocolDecl *proto =
1163+
requirement.getSecondType()->castTo<ProtocolType>()->getDecl();
1164+
Optional<ProtocolConformanceRef> conformance =
1165+
subMap.lookupConformance(requirement.getFirstType()->getCanonicalType(),
1166+
proto);
1167+
if (!conformance) {
1168+
// This should only happen when mangling invalid ASTs, but that happens
1169+
// for indexing purposes.
1170+
continue;
1171+
}
1172+
if (conformance->isConcrete() &&
1173+
containsRetroactiveConformance(conformance->getConcrete(), module)) {
11541174
return true;
1175+
}
11551176
}
11561177

11571178
return false;
@@ -2289,12 +2310,19 @@ void ASTMangler::appendProtocolConformanceRef(
22892310
appendProtocolName(conformance->getProtocol());
22902311

22912312
// For retroactive conformances, add a reference to the module in which the
2292-
// conformance resides. For @objc protocols, there is no point: conformances
2293-
// are global anyway.
2294-
if (isRetroactiveConformance(conformance))
2313+
// conformance resides. Otherwise, use an operator to indicate which known
2314+
// module it's associated with.
2315+
if (!conformanceHasIdentity(conformance)) {
2316+
// Same as "conformance module matches type", below.
2317+
appendOperator("HP");
2318+
} else if (isRetroactiveConformance(conformance)) {
22952319
appendModule(conformance->getDeclContext()->getParentModule());
2296-
2297-
appendOperator("HP");
2320+
} else if (conformance->getDeclContext()->getParentModule() ==
2321+
conformance->getType()->getAnyNominal()->getParentModule()) {
2322+
appendOperator("HP");
2323+
} else {
2324+
appendOperator("Hp");
2325+
}
22982326
}
22992327

23002328
/// Retrieve the index of the conformance requirement indicated by the

lib/Demangling/Demangler.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,12 @@ NodePointer Demangler::demangleOperator() {
610610
case 'C': return demangleConcreteProtocolConformance();
611611
case 'D': return demangleDependentProtocolConformanceRoot();
612612
case 'I': return demangleDependentProtocolConformanceInherited();
613-
case 'P': return demangleProtocolConformanceRef();
613+
case 'P':
614+
return createWithChild(
615+
Node::Kind::ProtocolConformanceRefInTypeModule, popProtocol());
616+
case 'p':
617+
return createWithChild(
618+
Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol());
614619
default:
615620
pushBack();
616621
pushBack();
@@ -1295,22 +1300,27 @@ NodePointer Demangler::popAnyProtocolConformance() {
12951300
});
12961301
}
12971302

1298-
NodePointer Demangler::demangleProtocolConformanceRef() {
1303+
NodePointer Demangler::demangleRetroactiveProtocolConformanceRef() {
12991304
NodePointer module = popModule();
13001305
NodePointer proto = popProtocol();
13011306
auto protocolConformanceRef =
1302-
createWithChild(Node::Kind::ProtocolConformanceRef, proto);
1303-
1304-
// The module is optional, present only for retroactive conformances. Add it
1305-
// as the second child.
1306-
if (protocolConformanceRef && module)
1307-
protocolConformanceRef->addChild(module, *this);
1307+
createWithChildren(Node::Kind::ProtocolConformanceRefInOtherModule,
1308+
proto, module);
13081309
return protocolConformanceRef;
13091310
}
13101311

13111312
NodePointer Demangler::demangleConcreteProtocolConformance() {
13121313
NodePointer conditionalConformanceList = popAnyProtocolConformanceList();
1313-
NodePointer conformanceRef = popNode(Node::Kind::ProtocolConformanceRef);
1314+
1315+
NodePointer conformanceRef =
1316+
popNode(Node::Kind::ProtocolConformanceRefInTypeModule);
1317+
if (!conformanceRef) {
1318+
conformanceRef =
1319+
popNode(Node::Kind::ProtocolConformanceRefInProtocolModule);
1320+
}
1321+
if (!conformanceRef)
1322+
conformanceRef = demangleRetroactiveProtocolConformanceRef();
1323+
13141324
NodePointer type = popNode(Node::Kind::Type);
13151325
return createWithChildren(Node::Kind::ConcreteProtocolConformance,
13161326
type, conformanceRef, conditionalConformanceList);

lib/Demangling/NodePrinter.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,9 @@ class NodePrinter {
497497
case Node::Kind::DependentProtocolConformanceAssociated:
498498
case Node::Kind::DependentProtocolConformanceInherited:
499499
case Node::Kind::DependentProtocolConformanceRoot:
500-
case Node::Kind::ProtocolConformanceRef:
500+
case Node::Kind::ProtocolConformanceRefInTypeModule:
501+
case Node::Kind::ProtocolConformanceRefInProtocolModule:
502+
case Node::Kind::ProtocolConformanceRefInOtherModule:
501503
case Node::Kind::DynamicallyReplaceableFunctionKey:
502504
case Node::Kind::DynamicallyReplaceableFunctionImpl:
503505
case Node::Kind::DynamicallyReplaceableFunctionVar:
@@ -2171,7 +2173,16 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
21712173
<< " ";
21722174
printChildren(Node);
21732175
return nullptr;
2174-
case Node::Kind::ProtocolConformanceRef:
2176+
case Node::Kind::ProtocolConformanceRefInTypeModule:
2177+
Printer << "protocol conformance ref (type's module) ";
2178+
printChildren(Node);
2179+
return nullptr;
2180+
case Node::Kind::ProtocolConformanceRefInProtocolModule:
2181+
Printer << "protocol conformance ref (protocol's module) ";
2182+
printChildren(Node);
2183+
return nullptr;
2184+
case Node::Kind::ProtocolConformanceRefInOtherModule:
2185+
Printer << "protocol conformance ref (retroactive) ";
21752186
printChildren(Node);
21762187
return nullptr;
21772188
}

lib/Demangling/OldRemangler.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,15 @@ void Remangler::mangleRetroactiveConformance(Node *node) {
680680
unreachable("Retroactive conformances aren't in the old mangling");
681681
}
682682

683-
void Remangler::mangleProtocolConformanceRef(Node *node) {
683+
void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) {
684+
unreachable("Protocol conformance references aren't in the old mangling");
685+
}
686+
687+
void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) {
688+
unreachable("Protocol conformance references aren't in the old mangling");
689+
}
690+
691+
void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) {
684692
unreachable("Protocol conformance references aren't in the old mangling");
685693
}
686694

lib/Demangling/Remangler.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,16 +1653,24 @@ void Remangler::mangleProtocolConformance(Node *node) {
16531653
mangle(GenSig);
16541654
}
16551655

1656-
void Remangler::mangleProtocolConformanceRef(Node *node) {
1656+
void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) {
16571657
manglePureProtocol(node->getChild(0));
1658-
if (node->getNumChildren() > 1)
1659-
mangleChildNode(node, 1);
16601658
Buffer << "HP";
16611659
}
16621660

1661+
void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) {
1662+
manglePureProtocol(node->getChild(0));
1663+
Buffer << "Hp";
1664+
}
1665+
1666+
void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) {
1667+
manglePureProtocol(node->getChild(0));
1668+
mangleChildNode(node, 1);
1669+
}
1670+
16631671
void Remangler::mangleConcreteProtocolConformance(Node *node) {
16641672
mangleType(node->getChild(0));
1665-
mangleProtocolConformanceRef(node->getChild(1));
1673+
mangle(node->getChild(1));
16661674
if (node->getNumChildren() > 2)
16671675
mangleAnyProtocolConformanceList(node->getChild(2));
16681676
else

test/Demangle/Inputs/manglings.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ _T0So13GenericOptionas8HashableSCsACP9hashValueSivgTW ---> {T:} protocol witness
301301
_T0So11CrappyColorVs16RawRepresentableSCMA ---> reflection metadata associated type descriptor __C.CrappyColor : Swift.RawRepresentable in __C_Synthesized
302302
$S28protocol_conformance_records15NativeValueTypeVAA8RuncibleAAMc ---> protocol conformance descriptor for protocol_conformance_records.NativeValueType : protocol_conformance_records.Runcible in protocol_conformance_records
303303
$SSC9SomeErrorLeVD ---> __C_Synthesized.related decl 'e' for SomeError
304-
$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAHPyHCg_AiJ1QAAHPyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
304+
$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAyHCg_AiJ1QAAyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
305+
$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PHPyHCg_AiJ1QHPyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
306+
$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PHpyHCg_AiJ1QHpyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
305307
_T0LiteralAByxGxd_tcfC ---> _T0LiteralAByxGxd_tcfC
306308
_T0XZ ---> _T0XZ
307309
_TTSf0os___TFVs17_LegacyStringCore15_invariantCheckfT_T_ ---> function signature specialization <Arg[0] = Guaranteed To Owned and Exploded> of Swift._LegacyStringCore._invariantCheck() -> ()

test/SILGen/mangling_retroactive.swift

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ struct Z<T: P, U: Hashable, V: Q> { }
1212
extension X: P { } // retroactive
1313
extension Y: Q { } // retroactive
1414

15-
// CHECK: sil hidden @$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAHPyHCg_AiJ1QAAHPyHCg1_GF
15+
// CHECK: sil hidden @$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAyHCg_AiJ1QAAyHCg1_GF
1616
func test0(_: Z<X, Int, Y>) { }
1717

1818
struct Z2<T: P> {
1919
struct Inner<V: Q> { }
2020
}
2121

22-
// CHECK: sil hidden @$s20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg0_GF
22+
// CHECK: sil hidden @$s20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAyHCg_AkL1QAAyHCg0_GF
2323
func test1(_: Z2<X>.Inner<Y>) { }
2424

2525
extension X: Hashable {
@@ -38,5 +38,52 @@ extension Z: Equatable where T: Hashable, V: Equatable {
3838
struct RequiresEquatable<T: Equatable> { }
3939

4040
// Conditional requirement involves retroactive conformances.
41-
// CHECK: sil hidden @$s20mangling_retroactive5test2yyAA17RequiresEquatableVyAA1ZVy12RetroactiveB1XVSiAG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg1_GAOSQHPAISHAAHPyHC_AKSQAAHPyHCHCg_GF
41+
// CHECK: sil hidden @$s20mangling_retroactive5test2yyAA17RequiresEquatableVyAA1ZVy12RetroactiveB1XVSiAG1YVAI0F1A1PAAyHCg_AkL1QAAyHCg1_GAOSQHPAISHAAyHC_AKSQAAyHCHCg_GF
4242
func test2(_: RequiresEquatable<Z<X, Int, Y>>) { }
43+
44+
struct UnconditionallyP<T: Q>: P {}
45+
struct RequiresP<T: P> {}
46+
47+
// RequiresP uses a non-retroactive conformance for its generic param
48+
// UnconditionallyP, even though UnconditionallyP's generic param uses a
49+
// retroactive conformance to conform to Q.
50+
func rdar46735592(_: RequiresP<UnconditionallyP<Y>>) { }
51+
// CHECK: sil hidden @$s20mangling_retroactive12rdar46735592yyAA9RequiresPVyAA16UnconditionallyPVy12RetroactiveB1YVAI0F1A1QAAyHCg_GGF
52+
53+
struct QImpl: Q {}
54+
struct ConditionallyP<T> {}
55+
extension ConditionallyP: P where T: Q {}
56+
57+
func useConditionallyP(_: RequiresP<ConditionallyP<QImpl>>) {}
58+
func useConditionallyP_retroactive(_: RequiresP<ConditionallyP<Y>>) {}
59+
// CHECK: sil hidden @$s20mangling_retroactive17useConditionallyPyyAA9RequiresPVyAA0D1PVyAA5QImplVGGF
60+
// CHECK: sil hidden @$s20mangling_retroactive018useConditionallyP_B0yyAA9RequiresPVyAA0D1PVy12RetroactiveB1YVGAJ0F1A1PHPAiK1QAAyHC_HCg_GF
61+
62+
protocol Wrapper {
63+
associatedtype Wrapped
64+
}
65+
struct WrapperImpl<Wrapped>: Wrapper {}
66+
67+
struct IndirectlyConditionallyP<T: Wrapper> {}
68+
extension IndirectlyConditionallyP: P where T.Wrapped: Q {}
69+
70+
func useIndirectlyConditionallyP(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<QImpl>>>) {}
71+
func useIndirectlyConditionallyP_retroactive(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<Y>>>) {}
72+
// CHECK: sil hidden @$s20mangling_retroactive27useIndirectlyConditionallyPyyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
73+
// CHECK: sil hidden @$s20mangling_retroactive028useIndirectlyConditionallyP_B0yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVy12RetroactiveB1YVGGAM0I1A1PHPAkN1QAAyHC_HCg_GF
74+
75+
struct IndirectlyConditionallyP2<T> {}
76+
extension IndirectlyConditionallyP2: P where T: Wrapper, T.Wrapped: Q {}
77+
78+
func useIndirectlyConditionallyP2(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<QImpl>>>) {}
79+
func useIndirectlyConditionallyP2_retroactive(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<Y>>>) {}
80+
// CHECK: sil hidden @$s20mangling_retroactive28useIndirectlyConditionallyP2yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
81+
// CHECK: sil hidden @$s20mangling_retroactive029useIndirectlyConditionallyP2_B0yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVy12RetroactiveB1YVGGAM0J1A1PHPAkN1QAAyHC_HCg_GF
82+
83+
protocol NonRetroactive {}
84+
extension Y: NonRetroactive {}
85+
struct ConditionallyP2<T> {}
86+
extension ConditionallyP2: P where T: Q, T: NonRetroactive {}
87+
88+
func useConditionallyP2(_: RequiresP<ConditionallyP2<Y>>) {}
89+
// CHECK: sil hidden @$s20mangling_retroactive18useConditionallyP2yyAA9RequiresPVyAA0dE0Vy12RetroactiveB1YVGAJ0G1A1PHPAiK1QAAyHC_AiA03NonG0HpyHCHCg_GF

0 commit comments

Comments
 (0)