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