Skip to content

Commit 117dc27

Browse files
authored
Merge pull request #21450 from jrose-apple/conditionally-retro
[ABI] [Mangling] Only look for retroactive conformances in conditional reqs
2 parents 3844dfd + 0ca4d55 commit 117dc27

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
@@ -1105,48 +1105,69 @@ void ASTMangler::appendBoundGenericArgs(Type type, bool &isFirstArgList) {
11051105
}
11061106
}
11071107

1108-
/// Determine whether the given protocol conformance is itself retroactive,
1109-
/// meaning that there might be multiple conflicting conformances of the
1110-
/// same type to the same protocol.
1111-
static bool isRetroactiveConformance(const RootProtocolConformance *root) {
1108+
static bool conformanceHasIdentity(const RootProtocolConformance *root) {
11121109
auto conformance = dyn_cast<NormalProtocolConformance>(root);
11131110
if (!conformance) {
11141111
assert(isa<SelfProtocolConformance>(root));
1115-
return false; // self-conformances are never retroactive.
1112+
return true;
11161113
}
11171114

1118-
/// Non-retroactive conformances are... never retroactive.
1119-
if (!conformance->isRetroactive())
1120-
return false;
1121-
1122-
/// Synthesized non-unique conformances all get collapsed together at run
1123-
/// time.
1115+
// Synthesized non-unique conformances all get collapsed together at run time.
11241116
if (conformance->isSynthesizedNonUnique())
11251117
return false;
11261118

1127-
/// Objective-C protocol conformances don't have identity.
1119+
// Objective-C protocol conformances are checked by the ObjC runtime.
11281120
if (conformance->getProtocol()->isObjC())
11291121
return false;
11301122

11311123
return true;
11321124
}
11331125

1126+
/// Determine whether the given protocol conformance is itself retroactive,
1127+
/// meaning that there might be multiple conflicting conformances of the
1128+
/// same type to the same protocol.
1129+
static bool isRetroactiveConformance(const RootProtocolConformance *root) {
1130+
auto conformance = dyn_cast<NormalProtocolConformance>(root);
1131+
if (!conformance) {
1132+
assert(isa<SelfProtocolConformance>(root));
1133+
return false; // self-conformances are never retroactive.
1134+
}
1135+
1136+
return conformance->isRetroactive();
1137+
}
1138+
11341139
/// Determine whether the given protocol conformance contains a retroactive
11351140
/// protocol conformance anywhere in it.
11361141
static bool containsRetroactiveConformance(
11371142
const ProtocolConformance *conformance,
11381143
ModuleDecl *module) {
11391144
// If the root conformance is retroactive, it's retroactive.
1140-
if (isRetroactiveConformance(conformance->getRootConformance()))
1145+
const RootProtocolConformance *rootConformance =
1146+
conformance->getRootConformance();
1147+
if (isRetroactiveConformance(rootConformance) &&
1148+
conformanceHasIdentity(rootConformance))
11411149
return true;
11421150

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

11521173
return false;
@@ -2278,12 +2299,19 @@ void ASTMangler::appendProtocolConformanceRef(
22782299
appendProtocolName(conformance->getProtocol());
22792300

22802301
// For retroactive conformances, add a reference to the module in which the
2281-
// conformance resides. For @objc protocols, there is no point: conformances
2282-
// are global anyway.
2283-
if (isRetroactiveConformance(conformance))
2302+
// conformance resides. Otherwise, use an operator to indicate which known
2303+
// module it's associated with.
2304+
if (!conformanceHasIdentity(conformance)) {
2305+
// Same as "conformance module matches type", below.
2306+
appendOperator("HP");
2307+
} else if (isRetroactiveConformance(conformance)) {
22842308
appendModule(conformance->getDeclContext()->getParentModule());
2285-
2286-
appendOperator("HP");
2309+
} else if (conformance->getDeclContext()->getParentModule() ==
2310+
conformance->getType()->getAnyNominal()->getParentModule()) {
2311+
appendOperator("HP");
2312+
} else {
2313+
appendOperator("Hp");
2314+
}
22872315
}
22882316

22892317
/// 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:
@@ -2172,7 +2174,16 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
21722174
<< " ";
21732175
printChildren(Node);
21742176
return nullptr;
2175-
case Node::Kind::ProtocolConformanceRef:
2177+
case Node::Kind::ProtocolConformanceRefInTypeModule:
2178+
Printer << "protocol conformance ref (type's module) ";
2179+
printChildren(Node);
2180+
return nullptr;
2181+
case Node::Kind::ProtocolConformanceRefInProtocolModule:
2182+
Printer << "protocol conformance ref (protocol's module) ";
2183+
printChildren(Node);
2184+
return nullptr;
2185+
case Node::Kind::ProtocolConformanceRefInOtherModule:
2186+
Printer << "protocol conformance ref (retroactive) ";
21762187
printChildren(Node);
21772188
return nullptr;
21782189
}

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
@@ -1655,16 +1655,24 @@ void Remangler::mangleProtocolConformance(Node *node) {
16551655
mangle(GenSig);
16561656
}
16571657

1658-
void Remangler::mangleProtocolConformanceRef(Node *node) {
1658+
void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) {
16591659
manglePureProtocol(node->getChild(0));
1660-
if (node->getNumChildren() > 1)
1661-
mangleChildNode(node, 1);
16621660
Buffer << "HP";
16631661
}
16641662

1663+
void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) {
1664+
manglePureProtocol(node->getChild(0));
1665+
Buffer << "Hp";
1666+
}
1667+
1668+
void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) {
1669+
manglePureProtocol(node->getChild(0));
1670+
mangleChildNode(node, 1);
1671+
}
1672+
16651673
void Remangler::mangleConcreteProtocolConformance(Node *node) {
16661674
mangleType(node->getChild(0));
1667-
mangleProtocolConformanceRef(node->getChild(1));
1675+
mangle(node->getChild(1));
16681676
if (node->getNumChildren() > 2)
16691677
mangleAnyProtocolConformanceList(node->getChild(2));
16701678
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 [ossa] @$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAHPyHCg_AiJ1QAAHPyHCg1_GF
15+
// CHECK: sil hidden [ossa] @$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 [ossa] @$s20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg0_GF
22+
// CHECK: sil hidden [ossa] @$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 [ossa] @$s20mangling_retroactive5test2yyAA17RequiresEquatableVyAA1ZVy12RetroactiveB1XVSiAG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg1_GAOSQHPAISHAAHPyHC_AKSQAAHPyHCHCg_GF
41+
// CHECK: sil hidden [ossa] @$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 [ossa] @$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 [ossa] @$s20mangling_retroactive17useConditionallyPyyAA9RequiresPVyAA0D1PVyAA5QImplVGGF
60+
// CHECK: sil hidden [ossa] @$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 [ossa] @$s20mangling_retroactive27useIndirectlyConditionallyPyyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
73+
// CHECK: sil hidden [ossa] @$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 [ossa] @$s20mangling_retroactive28useIndirectlyConditionallyP2yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
81+
// CHECK: sil hidden [ossa] @$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 [ossa] @$s20mangling_retroactive18useConditionallyP2yyAA9RequiresPVyAA0dE0Vy12RetroactiveB1YVGAJ0G1A1PHPAiK1QAAyHC_AiA03NonG0HpyHCHCg_GF

0 commit comments

Comments
 (0)