Merge pull request #21478 from jrose-apple/5.0-conditionally-retro
[5.0] [ABI] [Mangling] Disambiguate protocol-conformance-ref better
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 41829c7..34bef31 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -633,7 +633,9 @@
::
concrete-protocol-conformance ::= type protocol-conformance-ref any-protocol-conformance-list 'HC'
- protocol-conformance-ref ::= protocol module? 'HP'
+ protocol-conformance-ref ::= protocol 'HP' // same module as conforming type
+ protocol-conformance-ref ::= protocol 'Hp' // same module as protocol
+ protocol-conformance-ref ::= protocol module // "retroactive"
any-protocol-conformance ::= concrete-protocol-conformance
any-protocol-conformance ::= dependent-protocol-conformance
@@ -651,10 +653,13 @@
dependent-associated-conformance ::= type protocol
A compact representation used to represent mangled protocol conformance witness
-arguments at runtime. The ``module`` is only specified for conformances that are
-"retroactive", meaning that the context in which the conformance is defined is
-in neither the protocol or type module. The concrete protocol conformances that
-follow are for the conditional conformance requirements.
+arguments at runtime. The ``module`` is only specified for conformances that
+are "retroactive", meaning that the context in which the conformance is defined
+is in neither the protocol or type module. For a non-retroactive conformance
+where both the type *and* the protocol are in the same module, or for
+synthesized conformances that have no owning module, the "HP" operator is
+preferred. The concrete protocol conformances that follow are for the
+conditional conformance requirements.
Dependent protocol conformances mangle the access path required to extract a
protocol conformance from some conformance passed into the environment. The
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index 76b0d38..31bca5f 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -156,7 +156,9 @@
CONTEXT_NODE(Protocol)
CONTEXT_NODE(ProtocolSymbolicReference)
NODE(ProtocolConformance)
-NODE(ProtocolConformanceRef)
+NODE(ProtocolConformanceRefInTypeModule)
+NODE(ProtocolConformanceRefInProtocolModule)
+NODE(ProtocolConformanceRefInOtherModule)
NODE(ProtocolDescriptor)
NODE(ProtocolConformanceDescriptor)
NODE(ProtocolList)
diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h
index b416b7e..9c3dbd0 100644
--- a/include/swift/Demangling/Demangler.h
+++ b/include/swift/Demangling/Demangler.h
@@ -458,7 +458,7 @@
NodePointer getDependentGenericParamType(int depth, int index);
NodePointer demangleGenericParamIndex();
NodePointer popProtocolConformance();
- NodePointer demangleProtocolConformanceRef();
+ NodePointer demangleRetroactiveProtocolConformanceRef();
NodePointer popAnyProtocolConformance();
NodePointer demangleConcreteProtocolConformance();
NodePointer popDependentProtocolConformance();
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index d009098..2b6374f 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -1110,6 +1110,24 @@
}
}
+static bool conformanceHasIdentity(const RootProtocolConformance *root) {
+ auto conformance = dyn_cast<NormalProtocolConformance>(root);
+ if (!conformance) {
+ assert(isa<SelfProtocolConformance>(root));
+ return true;
+ }
+
+ // Synthesized non-unique conformances all get collapsed together at run time.
+ if (conformance->isSynthesizedNonUnique())
+ return false;
+
+ // Objective-C protocol conformances are checked by the ObjC runtime.
+ if (conformance->getProtocol()->isObjC())
+ return false;
+
+ return true;
+}
+
/// Determine whether the given protocol conformance is itself retroactive,
/// meaning that there might be multiple conflicting conformances of the
/// same type to the same protocol.
@@ -1120,20 +1138,7 @@
return false; // self-conformances are never retroactive.
}
- /// Non-retroactive conformances are... never retroactive.
- if (!conformance->isRetroactive())
- return false;
-
- /// Synthesized non-unique conformances all get collapsed together at run
- /// time.
- if (conformance->isSynthesizedNonUnique())
- return false;
-
- /// Objective-C protocol conformances don't have identity.
- if (conformance->getProtocol()->isObjC())
- return false;
-
- return true;
+ return conformance->isRetroactive();
}
/// Determine whether the given protocol conformance contains a retroactive
@@ -1142,16 +1147,32 @@
const ProtocolConformance *conformance,
ModuleDecl *module) {
// If the root conformance is retroactive, it's retroactive.
- if (isRetroactiveConformance(conformance->getRootConformance()))
+ const RootProtocolConformance *rootConformance =
+ conformance->getRootConformance();
+ if (isRetroactiveConformance(rootConformance) &&
+ conformanceHasIdentity(rootConformance))
return true;
- // If any of the substitutions used to form this conformance are retroactive,
- // it's retroactive.
+ // If the conformance is conditional and any of the substitutions used to
+ // satisfy the conditions are retroactive, it's retroactive.
auto subMap = conformance->getSubstitutions(module);
- for (auto conformance : subMap.getConformances()) {
- if (conformance.isConcrete() &&
- containsRetroactiveConformance(conformance.getConcrete(), module))
+ for (auto requirement : rootConformance->getConditionalRequirements()) {
+ if (requirement.getKind() != RequirementKind::Conformance)
+ continue;
+ ProtocolDecl *proto =
+ requirement.getSecondType()->castTo<ProtocolType>()->getDecl();
+ Optional<ProtocolConformanceRef> conformance =
+ subMap.lookupConformance(requirement.getFirstType()->getCanonicalType(),
+ proto);
+ if (!conformance) {
+ // This should only happen when mangling invalid ASTs, but that happens
+ // for indexing purposes.
+ continue;
+ }
+ if (conformance->isConcrete() &&
+ containsRetroactiveConformance(conformance->getConcrete(), module)) {
return true;
+ }
}
return false;
@@ -2289,12 +2310,19 @@
appendProtocolName(conformance->getProtocol());
// For retroactive conformances, add a reference to the module in which the
- // conformance resides. For @objc protocols, there is no point: conformances
- // are global anyway.
- if (isRetroactiveConformance(conformance))
+ // conformance resides. Otherwise, use an operator to indicate which known
+ // module it's associated with.
+ if (!conformanceHasIdentity(conformance)) {
+ // Same as "conformance module matches type", below.
+ appendOperator("HP");
+ } else if (isRetroactiveConformance(conformance)) {
appendModule(conformance->getDeclContext()->getParentModule());
-
- appendOperator("HP");
+ } else if (conformance->getDeclContext()->getParentModule() ==
+ conformance->getType()->getAnyNominal()->getParentModule()) {
+ appendOperator("HP");
+ } else {
+ appendOperator("Hp");
+ }
}
/// Retrieve the index of the conformance requirement indicated by the
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index d9729b7..522944f 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -610,7 +610,12 @@
case 'C': return demangleConcreteProtocolConformance();
case 'D': return demangleDependentProtocolConformanceRoot();
case 'I': return demangleDependentProtocolConformanceInherited();
- case 'P': return demangleProtocolConformanceRef();
+ case 'P':
+ return createWithChild(
+ Node::Kind::ProtocolConformanceRefInTypeModule, popProtocol());
+ case 'p':
+ return createWithChild(
+ Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol());
default:
pushBack();
pushBack();
@@ -1295,22 +1300,27 @@
});
}
-NodePointer Demangler::demangleProtocolConformanceRef() {
+NodePointer Demangler::demangleRetroactiveProtocolConformanceRef() {
NodePointer module = popModule();
NodePointer proto = popProtocol();
auto protocolConformanceRef =
- createWithChild(Node::Kind::ProtocolConformanceRef, proto);
-
- // The module is optional, present only for retroactive conformances. Add it
- // as the second child.
- if (protocolConformanceRef && module)
- protocolConformanceRef->addChild(module, *this);
+ createWithChildren(Node::Kind::ProtocolConformanceRefInOtherModule,
+ proto, module);
return protocolConformanceRef;
}
NodePointer Demangler::demangleConcreteProtocolConformance() {
NodePointer conditionalConformanceList = popAnyProtocolConformanceList();
- NodePointer conformanceRef = popNode(Node::Kind::ProtocolConformanceRef);
+
+ NodePointer conformanceRef =
+ popNode(Node::Kind::ProtocolConformanceRefInTypeModule);
+ if (!conformanceRef) {
+ conformanceRef =
+ popNode(Node::Kind::ProtocolConformanceRefInProtocolModule);
+ }
+ if (!conformanceRef)
+ conformanceRef = demangleRetroactiveProtocolConformanceRef();
+
NodePointer type = popNode(Node::Kind::Type);
return createWithChildren(Node::Kind::ConcreteProtocolConformance,
type, conformanceRef, conditionalConformanceList);
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 611609b..b2d764e 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -497,7 +497,9 @@
case Node::Kind::DependentProtocolConformanceAssociated:
case Node::Kind::DependentProtocolConformanceInherited:
case Node::Kind::DependentProtocolConformanceRoot:
- case Node::Kind::ProtocolConformanceRef:
+ case Node::Kind::ProtocolConformanceRefInTypeModule:
+ case Node::Kind::ProtocolConformanceRefInProtocolModule:
+ case Node::Kind::ProtocolConformanceRefInOtherModule:
case Node::Kind::DynamicallyReplaceableFunctionKey:
case Node::Kind::DynamicallyReplaceableFunctionImpl:
case Node::Kind::DynamicallyReplaceableFunctionVar:
@@ -2171,7 +2173,16 @@
<< " ";
printChildren(Node);
return nullptr;
- case Node::Kind::ProtocolConformanceRef:
+ case Node::Kind::ProtocolConformanceRefInTypeModule:
+ Printer << "protocol conformance ref (type's module) ";
+ printChildren(Node);
+ return nullptr;
+ case Node::Kind::ProtocolConformanceRefInProtocolModule:
+ Printer << "protocol conformance ref (protocol's module) ";
+ printChildren(Node);
+ return nullptr;
+ case Node::Kind::ProtocolConformanceRefInOtherModule:
+ Printer << "protocol conformance ref (retroactive) ";
printChildren(Node);
return nullptr;
}
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 8caafc6..211606f 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -680,7 +680,15 @@
unreachable("Retroactive conformances aren't in the old mangling");
}
-void Remangler::mangleProtocolConformanceRef(Node *node) {
+void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) {
+ unreachable("Protocol conformance references aren't in the old mangling");
+}
+
+void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) {
+ unreachable("Protocol conformance references aren't in the old mangling");
+}
+
+void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) {
unreachable("Protocol conformance references aren't in the old mangling");
}
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 0f61baf..85a1c70 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -1653,16 +1653,24 @@
mangle(GenSig);
}
-void Remangler::mangleProtocolConformanceRef(Node *node) {
+void Remangler::mangleProtocolConformanceRefInTypeModule(Node *node) {
manglePureProtocol(node->getChild(0));
- if (node->getNumChildren() > 1)
- mangleChildNode(node, 1);
Buffer << "HP";
}
+void Remangler::mangleProtocolConformanceRefInProtocolModule(Node *node) {
+ manglePureProtocol(node->getChild(0));
+ Buffer << "Hp";
+}
+
+void Remangler::mangleProtocolConformanceRefInOtherModule(Node *node) {
+ manglePureProtocol(node->getChild(0));
+ mangleChildNode(node, 1);
+}
+
void Remangler::mangleConcreteProtocolConformance(Node *node) {
mangleType(node->getChild(0));
- mangleProtocolConformanceRef(node->getChild(1));
+ mangle(node->getChild(1));
if (node->getNumChildren() > 2)
mangleAnyProtocolConformanceList(node->getChild(2));
else
diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt
index 4ff70e7..ab00374 100644
--- a/test/Demangle/Inputs/manglings.txt
+++ b/test/Demangle/Inputs/manglings.txt
@@ -301,7 +301,9 @@
_T0So11CrappyColorVs16RawRepresentableSCMA ---> reflection metadata associated type descriptor __C.CrappyColor : Swift.RawRepresentable in __C_Synthesized
$S28protocol_conformance_records15NativeValueTypeVAA8RuncibleAAMc ---> protocol conformance descriptor for protocol_conformance_records.NativeValueType : protocol_conformance_records.Runcible in protocol_conformance_records
$SSC9SomeErrorLeVD ---> __C_Synthesized.related decl 'e' for SomeError
-$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAHPyHCg_AiJ1QAAHPyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
+$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAyHCg_AiJ1QAAyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
+$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PHPyHCg_AiJ1QHPyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
+$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PHpyHCg_AiJ1QHpyHCg1_GF ---> mangling_retroactive.test0(mangling_retroactive.Z<RetroactiveB.X, Swift.Int, RetroactiveB.Y>) -> ()
_T0LiteralAByxGxd_tcfC ---> _T0LiteralAByxGxd_tcfC
_T0XZ ---> _T0XZ
_TTSf0os___TFVs17_LegacyStringCore15_invariantCheckfT_T_ ---> function signature specialization <Arg[0] = Guaranteed To Owned and Exploded> of Swift._LegacyStringCore._invariantCheck() -> ()
diff --git a/test/SILGen/mangling_retroactive.swift b/test/SILGen/mangling_retroactive.swift
index 2c865b1..f6873f3 100644
--- a/test/SILGen/mangling_retroactive.swift
+++ b/test/SILGen/mangling_retroactive.swift
@@ -12,14 +12,14 @@
extension X: P { } // retroactive
extension Y: Q { } // retroactive
-// CHECK: sil hidden @$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAHPyHCg_AiJ1QAAHPyHCg1_GF
+// CHECK: sil hidden @$s20mangling_retroactive5test0yyAA1ZVy12RetroactiveB1XVSiAE1YVAG0D1A1PAAyHCg_AiJ1QAAyHCg1_GF
func test0(_: Z<X, Int, Y>) { }
struct Z2<T: P> {
struct Inner<V: Q> { }
}
-// CHECK: sil hidden @$s20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg0_GF
+// CHECK: sil hidden @$s20mangling_retroactive5test1yyAA2Z2V5InnerVy12RetroactiveB1XV_AG1YVAI0F1A1PAAyHCg_AkL1QAAyHCg0_GF
func test1(_: Z2<X>.Inner<Y>) { }
extension X: Hashable {
@@ -38,5 +38,52 @@
struct RequiresEquatable<T: Equatable> { }
// Conditional requirement involves retroactive conformances.
-// CHECK: sil hidden @$s20mangling_retroactive5test2yyAA17RequiresEquatableVyAA1ZVy12RetroactiveB1XVSiAG1YVAI0F1A1PAAHPyHCg_AkL1QAAHPyHCg1_GAOSQHPAISHAAHPyHC_AKSQAAHPyHCHCg_GF
+// CHECK: sil hidden @$s20mangling_retroactive5test2yyAA17RequiresEquatableVyAA1ZVy12RetroactiveB1XVSiAG1YVAI0F1A1PAAyHCg_AkL1QAAyHCg1_GAOSQHPAISHAAyHC_AKSQAAyHCHCg_GF
func test2(_: RequiresEquatable<Z<X, Int, Y>>) { }
+
+struct UnconditionallyP<T: Q>: P {}
+struct RequiresP<T: P> {}
+
+// RequiresP uses a non-retroactive conformance for its generic param
+// UnconditionallyP, even though UnconditionallyP's generic param uses a
+// retroactive conformance to conform to Q.
+func rdar46735592(_: RequiresP<UnconditionallyP<Y>>) { }
+// CHECK: sil hidden @$s20mangling_retroactive12rdar46735592yyAA9RequiresPVyAA16UnconditionallyPVy12RetroactiveB1YVAI0F1A1QAAyHCg_GGF
+
+struct QImpl: Q {}
+struct ConditionallyP<T> {}
+extension ConditionallyP: P where T: Q {}
+
+func useConditionallyP(_: RequiresP<ConditionallyP<QImpl>>) {}
+func useConditionallyP_retroactive(_: RequiresP<ConditionallyP<Y>>) {}
+// CHECK: sil hidden @$s20mangling_retroactive17useConditionallyPyyAA9RequiresPVyAA0D1PVyAA5QImplVGGF
+// CHECK: sil hidden @$s20mangling_retroactive018useConditionallyP_B0yyAA9RequiresPVyAA0D1PVy12RetroactiveB1YVGAJ0F1A1PHPAiK1QAAyHC_HCg_GF
+
+protocol Wrapper {
+ associatedtype Wrapped
+}
+struct WrapperImpl<Wrapped>: Wrapper {}
+
+struct IndirectlyConditionallyP<T: Wrapper> {}
+extension IndirectlyConditionallyP: P where T.Wrapped: Q {}
+
+func useIndirectlyConditionallyP(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<QImpl>>>) {}
+func useIndirectlyConditionallyP_retroactive(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<Y>>>) {}
+// CHECK: sil hidden @$s20mangling_retroactive27useIndirectlyConditionallyPyyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
+// CHECK: sil hidden @$s20mangling_retroactive028useIndirectlyConditionallyP_B0yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVy12RetroactiveB1YVGGAM0I1A1PHPAkN1QAAyHC_HCg_GF
+
+struct IndirectlyConditionallyP2<T> {}
+extension IndirectlyConditionallyP2: P where T: Wrapper, T.Wrapped: Q {}
+
+func useIndirectlyConditionallyP2(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<QImpl>>>) {}
+func useIndirectlyConditionallyP2_retroactive(_: RequiresP<IndirectlyConditionallyP<WrapperImpl<Y>>>) {}
+// CHECK: sil hidden @$s20mangling_retroactive28useIndirectlyConditionallyP2yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVyAA5QImplVGGGF
+// CHECK: sil hidden @$s20mangling_retroactive029useIndirectlyConditionallyP2_B0yyAA9RequiresPVyAA0dE1PVyAA11WrapperImplVy12RetroactiveB1YVGGAM0J1A1PHPAkN1QAAyHC_HCg_GF
+
+protocol NonRetroactive {}
+extension Y: NonRetroactive {}
+struct ConditionallyP2<T> {}
+extension ConditionallyP2: P where T: Q, T: NonRetroactive {}
+
+func useConditionallyP2(_: RequiresP<ConditionallyP2<Y>>) {}
+// CHECK: sil hidden @$s20mangling_retroactive18useConditionallyP2yyAA9RequiresPVyAA0dE0Vy12RetroactiveB1YVGAJ0G1A1PHPAiK1QAAyHC_AiA03NonG0HpyHCHCg_GF