Merge pull request #15373 from eeckstein/fix-bca-4.1

BasicCalleeAnalysis: fix a problem with witness method visibility.
diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp
index d83cdd7..3bab8d2 100644
--- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp
+++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp
@@ -142,12 +142,28 @@
       continue;
     }
 
-    auto Witness = WT.getConformance()->getWitness(Requirement.getDecl(),
-                                                   nullptr);
-    auto DeclRef = SILDeclRef(Witness.getDecl());
+    bool canCallUnknown = false;
 
-    bool canCallUnknown = !calleesAreStaticallyKnowable(M, DeclRef);
-
+    auto Conf = WT.getConformance();
+    switch (Conf->getProtocol()->getEffectiveAccess()) {
+      case AccessLevel::Open:
+        llvm_unreachable("protocols cannot have open access level");
+      case AccessLevel::Public:
+        canCallUnknown = true;
+        break;
+      case AccessLevel::Internal:
+        if (!M.isWholeModule()) {
+          canCallUnknown = true;
+          break;
+        }
+        LLVM_FALLTHROUGH;
+      case AccessLevel::FilePrivate:
+      case AccessLevel::Private: {
+        auto Witness = Conf->getWitness(Requirement.getDecl(), nullptr);
+        auto DeclRef = SILDeclRef(Witness.getDecl());
+        canCallUnknown = !calleesAreStaticallyKnowable(M, DeclRef);
+      }
+    }
     if (canCallUnknown)
       TheCallees.setInt(true);
   }
diff --git a/test/SILOptimizer/basic-callee-printer.sil b/test/SILOptimizer/basic-callee-printer.sil
index 5c3433b..f7a325a 100644
--- a/test/SILOptimizer/basic-callee-printer.sil
+++ b/test/SILOptimizer/basic-callee-printer.sil
@@ -666,3 +666,40 @@
   #SomeItem.init!initializer.1: SomeChildItem_initializer
   #SomeChildItem.deinit!deallocator: SomeChildItem_destructor
 }
+
+public protocol PublicProtocol {
+  func foo()
+}
+
+struct SingleConformance : PublicProtocol {
+  func foo()
+}
+
+public func testit(p: PublicProtocol)
+
+sil private [transparent] [thunk] @foo_impl : $@convention(witness_method: PublicProtocol) (@in_guaranteed SingleConformance) -> () {
+bb0(%0 : $*SingleConformance):
+  %4 = tuple ()
+  return %4 : $()
+}
+
+// CHECK: Function call site:
+// CHECK:   witness_method $@opened{{.*}} PublicProtocol
+// CHECK:   apply {{.*}} PublicProtocol
+// CHECK-NOWMO: Incomplete callee list? : Yes
+// CHECK-WMO: Incomplete callee list? : Yes
+// CHECK: Known callees:
+sil @call_foo : $@convention(thin) (@in PublicProtocol) -> () {
+bb0(%0 : $*PublicProtocol):
+  %5 = open_existential_addr immutable_access %0 : $*PublicProtocol to $*@opened("2226A1AC-2B95-11E8-BDF4-D0817AD3F637") PublicProtocol
+  %6 = witness_method $@opened("2226A1AC-2B95-11E8-BDF4-D0817AD3F637") PublicProtocol, #PublicProtocol.foo!1 : <Self where Self : PublicProtocol> (Self) -> () -> (), %5 : $*@opened("2226A1AC-2B95-11E8-BDF4-D0817AD3F637") PublicProtocol : $@convention(witness_method: PublicProtocol) <τ_0_0 where τ_0_0 : PublicProtocol> (@in_guaranteed τ_0_0) -> ()
+  %7 = apply %6<@opened("2226A1AC-2B95-11E8-BDF4-D0817AD3F637") PublicProtocol>(%5) : $@convention(witness_method: PublicProtocol) <τ_0_0 where τ_0_0 : PublicProtocol> (@in_guaranteed τ_0_0) -> ()
+  destroy_addr %0 : $*PublicProtocol
+  %10 = tuple ()
+  return %10 : $()
+}
+
+sil_witness_table hidden SingleConformance: PublicProtocol module nix {
+  method #PublicProtocol.foo!1: <Self where Self : PublicProtocol> (Self) -> () -> () : @foo_impl
+}
+