Merge pull request #11242 from slavapestov/ambiguous-requirement-witness-subclass-existential-4.0

Sema: Fix requirement/witness disambiguation for subclass existentials [4.0]
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index 8f73302..b37f2f9 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -16,6 +16,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "TypeChecker.h"
+#include "swift/AST/ExistentialLayout.h"
 #include "swift/AST/Initializer.h"
 #include "swift/AST/NameLookup.h"
 #include "swift/AST/ProtocolConformance.h"
@@ -120,27 +121,48 @@
       if (!Options.contains(NameLookupFlags::ProtocolMembers) ||
           !isa<ProtocolDecl>(foundDC) ||
           isa<GenericTypeParamDecl>(found) ||
-          (isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator()) ||
-          foundInType->isAnyExistentialType()) {
+          (isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator())) {
         addResult(found);
         return;
       }
 
       assert(isa<ProtocolDecl>(foundDC));
 
+      auto conformingType = foundInType;
+
+      // When performing a lookup on a subclass existential, we might
+      // find a member of the class that witnesses a requirement on a
+      // protocol that the class conforms to.
+      //
+      // Since subclass existentials don't normally conform to protocols,
+      // pull out the superclass instead, and use that below.
+      if (foundInType->isExistentialType()) {
+        auto layout = foundInType->getExistentialLayout();
+        if (layout.superclass)
+          conformingType = layout.superclass;
+      }
+
       // If we found something within the protocol itself, and our
       // search began somewhere that is not in a protocol or extension
       // thereof, remap this declaration to the witness.
       if (foundInType->is<ArchetypeType>() ||
+          foundInType->isExistentialType() ||
           Options.contains(NameLookupFlags::PerformConformanceCheck)) {
         // Dig out the protocol conformance.
-        auto conformance = TC.conformsToProtocol(foundInType, foundProto, DC,
+        auto conformance = TC.conformsToProtocol(conformingType, foundProto, DC,
                                                  conformanceOptions);
-        if (!conformance)
+        if (!conformance) {
+          // If there's no conformance, we have an existential
+          // and we found a member from one of the protocols, and
+          // not a class constraint if any.
+          assert(foundInType->isExistentialType());
+          addResult(found);
           return;
+        }
 
         if (conformance->isAbstract()) {
-          assert(foundInType->is<ArchetypeType>());
+          assert(foundInType->is<ArchetypeType>() ||
+                 foundInType->isExistentialType());
           addResult(found);
           return;
         }
@@ -161,6 +183,10 @@
 
         // FIXME: the "isa<ProtocolDecl>()" check will be wrong for
         // default implementations in protocols.
+        //
+        // If we have an imported conformance or the witness could
+        // not be deserialized, getWitnessDecl() will just return
+        // the requirement, so just drop the lookup result here.
         if (witness && !isa<ProtocolDecl>(witness->getDeclContext()))
           addResult(witness);
 
diff --git a/test/ClangImporter/subclass_existentials.swift b/test/ClangImporter/subclass_existentials.swift
index 3050b5b..690d30c 100644
--- a/test/ClangImporter/subclass_existentials.swift
+++ b/test/ClangImporter/subclass_existentials.swift
@@ -35,3 +35,7 @@
     return g!
   }
 }
+
+// Make sure the method lookup is not ambiguous
+
+_ = Coat.fashionStatement.wear()
diff --git a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
index ffd5deb..1ad3a5c 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/Foundation.h
@@ -1086,13 +1086,21 @@
   FictionalServerErrorMeltedDown = 1
 } FictionalServerErrorCode;
 
+@protocol Wearable
+- (void)wear;
+@end
+
 @protocol Garment
 @end
 
 @protocol Cotton
 @end
 
-@interface Coat
+@interface Coat : NSObject<Wearable>
+
+- (void)wear;
+@property (class) Coat <Wearable> *fashionStatement;
+
 @end
 
 @protocol NSLaundry