Merge pull request #5331 from slavapestov/more-resilience-fixes

More resilience fixes
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index 31ac6a9..a53fe5d 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -1889,8 +1889,11 @@
       CS->TC.diagnose(loc, diag::candidate_inaccessible, decl->getName(),
                       decl->getFormalAccess());
     }
-    for (auto cand : candidates)
-      CS->TC.diagnose(cand.getDecl(),diag::decl_declared_here, decl->getName());
+    for (auto cand : candidates) {
+      if (auto decl = cand.getDecl()) {
+        CS->TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
+      }
+    }
     
     return true;
   }
@@ -2247,7 +2250,8 @@
   assert(isMemberConstraint(constraint));
   
   auto memberName = constraint->getMember();
-  
+  auto isInitializer = memberName.isSimpleName(CS->TC.Context.Id_init);
+
   // Get the referenced base expression from the failed constraint, along with
   // the SourceRange for the member ref.  In "x.y", this returns the expr for x
   // and the source range for y.
@@ -2340,12 +2344,21 @@
       .highlight(anchor->getSourceRange()).highlight(memberRange);
     return true;
   }
-  
-  MemberLookupResult result =
-    CS->performMemberLookup(constraint->getKind(), constraint->getMember(),
-                            baseTy, constraint->getFunctionRefKind(),
-                            constraint->getLocator(),
-                            /*includeInaccessibleMembers*/true);
+
+  // If this is initializer/constructor lookup we are dealing this.
+  if (isInitializer) {
+    // Let's check what is the base type we are trying to look it up on
+    // because only MetatypeType is viable to find constructor on, as per
+    // rules in ConstraintSystem::performMemberLookup.
+    if (!baseTy->is<AnyMetatypeType>()) {
+      baseTy = MetatypeType::get(baseTy, CS->getASTContext());
+    }
+  }
+
+  MemberLookupResult result = CS->performMemberLookup(
+      constraint->getKind(), memberName, baseTy,
+      constraint->getFunctionRefKind(), constraint->getLocator(),
+      /*includeInaccessibleMembers*/ true);
 
   switch (result.OverallResult) {
   case MemberLookupResult::Unsolved:      
@@ -2361,33 +2374,65 @@
   case MemberLookupResult::HasResults:
     break;
   }
-  
-  // If this is a failing lookup, it has no viable candidates here.
-  if (result.ViableCandidates.empty()) {
-    // Diagnose 'super.init', which can only appear inside another initializer,
-    // specially.
-    if (result.UnviableCandidates.empty() &&
-        memberName.isSimpleName(CS->TC.Context.Id_init) &&
-        !baseObjTy->is<MetatypeType>()) {
-      if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(expr)) {
-        if (isa<SuperRefExpr>(ctorRef->getBase())) {
-          diagnose(anchor->getLoc(),
-                   diag::super_initializer_not_in_initializer);
-          return true;
-        }
-        
-        // Suggest inserting a call to 'type(of:)' to construct another object
-        // of the same dynamic type.
-        SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange();
-        
-        // Surround the caller in `type(of:)`.
-        diagnose(anchor->getLoc(), diag::init_not_instance_member)
-          .fixItInsert(fixItRng.Start, "type(of: ")
-          .fixItInsertAfter(fixItRng.End, ")");
-        return true;
+
+  // Since the lookup was allowing inaccessible members, let's check
+  // if it found anything of that sort, which is easy to diagnose.
+  bool allUnavailable = !CS->TC.getLangOpts().DisableAvailabilityChecking;
+  for (auto &member : result.ViableCandidates) {
+    if (!member.isDecl()) {
+      // if there is no declaration, this choice is implicitly available.
+      allUnavailable = false;
+      continue;
+    }
+
+    auto decl = member.getDecl();
+    // Check availability of the found choice.
+    if (!decl->getAttrs().isUnavailable(CS->getASTContext()))
+      allUnavailable = false;
+
+    if (decl->isAccessibleFrom(CS->DC))
+      continue;
+
+    if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
+      CS->TC.diagnose(anchor->getLoc(), diag::init_candidate_inaccessible,
+                      CD->getResultType(), decl->getFormalAccess());
+    } else {
+      CS->TC.diagnose(anchor->getLoc(), diag::candidate_inaccessible,
+                      decl->getName(), decl->getFormalAccess());
+    }
+
+    for (auto &candidate : result.ViableCandidates) {
+      if (auto decl = candidate.getDecl()) {
+        CS->TC.diagnose(decl, diag::decl_declared_here, decl->getFullName());
       }
     }
 
+    return true;
+  }
+
+  // Diagnose 'super.init', which can only appear inside another initializer,
+  // specially.
+  if (result.UnviableCandidates.empty() && isInitializer &&
+      !baseObjTy->is<MetatypeType>()) {
+    if (auto ctorRef = dyn_cast<UnresolvedDotExpr>(expr)) {
+      if (isa<SuperRefExpr>(ctorRef->getBase())) {
+        diagnose(anchor->getLoc(), diag::super_initializer_not_in_initializer);
+        return true;
+      }
+
+      // Suggest inserting a call to 'type(of:)' to construct another object
+      // of the same dynamic type.
+      SourceRange fixItRng = ctorRef->getNameLoc().getSourceRange();
+
+      // Surround the caller in `type(of:)`.
+      diagnose(anchor->getLoc(), diag::init_not_instance_member)
+          .fixItInsert(fixItRng.Start, "type(of: ")
+          .fixItInsertAfter(fixItRng.End, ")");
+      return true;
+    }
+  }
+
+  if (result.ViableCandidates.empty()) {
     // FIXME: Dig out the property DeclNameLoc.
     diagnoseUnviableLookupResults(result, baseObjTy, anchor, memberName,
                                   DeclNameLoc(memberRange.Start),
@@ -2395,14 +2440,6 @@
     return true;
   }
   
-  
-  bool allUnavailable = !CS->TC.getLangOpts().DisableAvailabilityChecking;
-  for (auto match : result.ViableCandidates) {
-    if (!match.isDecl() ||
-        !match.getDecl()->getAttrs().isUnavailable(CS->getASTContext()))
-      allUnavailable = false;
-  }
-  
   if (allUnavailable) {
     auto firstDecl = result.ViableCandidates[0].getDecl();
     // FIXME: We need the enclosing CallExpr to rewrite the argument labels.
diff --git a/test/Constraints/super_constructor.swift b/test/Constraints/super_constructor.swift
index 6cc73dd..93993ac 100644
--- a/test/Constraints/super_constructor.swift
+++ b/test/Constraints/super_constructor.swift
@@ -53,3 +53,14 @@
   }
 }
 
+// SR-2484: Bad diagnostic for incorrectly calling private init
+class SR_2484 {
+  private init() {} // expected-note {{'init()' declared here}}
+  private init(a: Int) {} // expected-note {{'init(a:)' declared here}}
+}
+
+class Impl_2484 : SR_2484 {
+  init() {
+    super.init() // expected-error {{'SR_2484' initializer is inaccessible due to 'private' protection level}}
+  }
+}
diff --git a/test/NameBinding/Inputs/accessibility_other.swift b/test/NameBinding/Inputs/accessibility_other.swift
index 75a5bba..266e439 100644
--- a/test/NameBinding/Inputs/accessibility_other.swift
+++ b/test/NameBinding/Inputs/accessibility_other.swift
@@ -11,7 +11,7 @@
 }
 
 struct PrivateInit {
-  private init() {}  // expected-note {{'init' declared here}}
+  private init() {}  // expected-note {{'init()' declared here}}
 }
 
 extension Foo {