Merge pull request #7893 from DougGregor/sr-3917-3.1

[3.1] [SR-3917] Allow missing witnesses for optional and unavailable requirements
diff --git a/include/swift/AST/TypeMatcher.h b/include/swift/AST/TypeMatcher.h
index 5899d5b..113644e 100644
--- a/include/swift/AST/TypeMatcher.h
+++ b/include/swift/AST/TypeMatcher.h
@@ -213,20 +213,7 @@
     TRIVIAL_CASE(DynamicSelfType)
     TRIVIAL_CASE(ArchetypeType)
     TRIVIAL_CASE(GenericTypeParamType)
-
-    bool visitDependentMemberType(CanDependentMemberType firstDepMember,
-                                  Type secondType) {
-      if (auto secondDepMember = secondType->getAs<DependentMemberType>()) {
-        if (firstDepMember->getAssocType() != secondDepMember->getAssocType() ||
-            firstDepMember->getName() != secondDepMember->getName())
-          return mismatch(firstDepMember.getPointer(), secondDepMember);
-
-        return this->visit(firstDepMember.getBase(),
-                           secondDepMember->getBase());
-      }
-
-      return mismatch(firstDepMember.getPointer(), secondType);
-    }
+    TRIVIAL_CASE(DependentMemberType)
 
     /// FIXME: Split this out into cases?
     bool visitAnyFunctionType(CanAnyFunctionType firstFunc, Type secondType) {
diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp
index 7919fe0..80d87d7 100644
--- a/lib/AST/SubstitutionMap.cpp
+++ b/lib/AST/SubstitutionMap.cpp
@@ -17,6 +17,7 @@
 #include "swift/AST/ASTContext.h"
 #include "swift/AST/SubstitutionMap.h"
 #include "swift/AST/Decl.h"
+#include "swift/AST/Module.h"
 #include "swift/AST/ProtocolConformance.h"
 #include "swift/AST/Types.h"
 
@@ -70,7 +71,8 @@
   }
 
   // Check if we have substitutions from one of our parent types.
-  return forEachParent(type, [&](CanType parent, AssociatedTypeDecl *assocType)
+  auto result = forEachParent(type,
+    [&](CanType parent, AssociatedTypeDecl *assocType)
       -> Optional<ProtocolConformanceRef> {
 
     auto *parentProto = assocType->getProtocol();
@@ -87,6 +89,18 @@
 
     return lookupConformance(proto, sub.getConformances());
   });
+
+  // FIXME: Narrow fix for broken conformance lookup
+  if (!result || result->isAbstract()) {
+    auto substTy = type.subst(*this);
+    if (!substTy)
+      return result;
+
+    auto *M = proto->getParentModule();
+    return M->lookupConformance(substTy, proto, nullptr);
+  }
+
+  return result;
 }
 
 void SubstitutionMap::
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index e724eec..2652de0 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -37,6 +37,9 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/SaveAndRestore.h"
 
+#define DEBUG_TYPE "protocol-conformance-checking"
+#include "llvm/Support/Debug.h"
+
 using namespace swift;
 
 namespace {
@@ -3015,6 +3018,9 @@
   };
 
   for (auto witness : lookupValueWitnesses(req, /*ignoringNames=*/nullptr)) {
+    DEBUG(llvm::dbgs() << "Inferring associated types from decl:\n";
+          witness->dump(llvm::dbgs()));
+  
     // If the potential witness came from an extension, and our `Self`
     // type can't use it regardless of what associated types we end up
     // inferring, skip the witness.
@@ -3035,18 +3041,27 @@
 }
       auto &result = witnessResult.Inferred[i];
 
+      DEBUG(llvm::dbgs() << "Considering whether " << result.first->getName()
+                         << " can infer to:\n";
+            result.second->dump(llvm::dbgs()));
+
       // Filter out errors.
-      if (result.second->hasError())
+      if (result.second->hasError()) {
+        DEBUG(llvm::dbgs() << "-- has error type\n");
         REJECT;
+      }
 
       // Filter out duplicates.
       if (!known.insert({result.first, result.second->getCanonicalType()})
-                .second)
+                .second) {
+        DEBUG(llvm::dbgs() << "-- duplicate\n");
         REJECT;
+      }
      
       // Filter out circular possibilities, e.g. that
       // AssocType == S.AssocType or
       // AssocType == Foo<S.AssocType>.
+      bool canInferFromOtherAssociatedType = false;
       bool containsTautologicalType =
         result.second.findIf([&](Type t) -> bool {
           auto dmt = t->getAs<DependentMemberType>();
@@ -3058,11 +3073,63 @@
           if (!dmt->getBase()->isEqual(Conformance->getType()))
             return false;
           
+          // If this associated type is same-typed to another associated type
+          // on `Self`, then it may still be an interesting candidate if we find
+          // an answer for that other type.
+          auto witnessContext = witness->getDeclContext();
+          if (witnessContext->getAsProtocolExtensionContext()
+              && witnessContext->getGenericSignatureOfContext()) {
+            auto selfTy = witnessContext->getSelfInterfaceType();
+            auto selfAssocTy = DependentMemberType::get(selfTy,
+                                                        dmt->getAssocType());
+            for (auto &reqt : witnessContext->getGenericSignatureOfContext()
+                                            ->getRequirements()) {
+              switch (reqt.getKind()) {
+              case RequirementKind::Conformance:
+              case RequirementKind::Superclass:
+              case RequirementKind::Layout:
+                break;
+              
+              case RequirementKind::SameType:
+                Type other;
+                if (reqt.getFirstType()->isEqual(selfAssocTy)) {
+                  other = reqt.getSecondType();
+                } else if (reqt.getSecondType()->isEqual(selfAssocTy)) {
+                  other = reqt.getFirstType();
+                } else {
+                  break;
+                }
+                
+                if (auto otherAssoc = other->getAs<DependentMemberType>()) {
+                  if (otherAssoc->getBase()->isEqual(selfTy)) {
+                    auto otherDMT = DependentMemberType::get(dmt->getBase(),
+                                                    otherAssoc->getAssocType());
+                    
+                    // We may be able to infer one associated type from the
+                    // other.
+                    result.second = result.second.transform([&](Type t) -> Type{
+                      if (t->isEqual(dmt))
+                        return otherDMT;
+                      return t;
+                    });
+                    canInferFromOtherAssociatedType = true;
+                    DEBUG(llvm::dbgs() << "++ we can same-type to:\n";
+                          result.second->dump(llvm::dbgs()));
+                    return false;
+                  }
+                }
+                break;
+              }
+            }
+          }
+          
           return true;
         });
       
-      if (containsTautologicalType)
+      if (containsTautologicalType) {
+        DEBUG(llvm::dbgs() << "-- tautological\n");
         REJECT;
+      }
       
       // Check that the type witness doesn't contradict an
       // explicitly-given type witness. If it does contradict, throw out the
@@ -3079,19 +3146,27 @@
         auto newWitness = result.second->getCanonicalType();
         if (!newWitness->hasTypeParameter()
             && !existingWitness->isEqual(newWitness)) {
+          DEBUG(llvm::dbgs() << "** contradicts explicit type witness, "
+                                "rejecting inference from this decl\n");
           goto next_witness;
         }
       }
       
-      // Check that the type witness meets the
-      // requirements on the associated type.
-      if (auto failed = checkTypeWitness(TC, DC, result.first,
-                                         result.second)) {
-        witnessResult.NonViable.push_back(
-                            std::make_tuple(result.first,result.second,failed));
-        REJECT;
+      // If we same-typed to another unresolved associated type, we won't
+      // be able to check conformances yet.
+      if (!canInferFromOtherAssociatedType) {
+        // Check that the type witness meets the
+        // requirements on the associated type.
+        if (auto failed = checkTypeWitness(TC, DC, result.first,
+                                           result.second)) {
+          witnessResult.NonViable.push_back(
+                              std::make_tuple(result.first,result.second,failed));
+          DEBUG(llvm::dbgs() << "-- doesn't fulfill requirements\n");
+          REJECT;
+        }
       }
       
+      DEBUG(llvm::dbgs() << "++ seems legit\n");
       ++i;
     }
 #undef REJECT
@@ -3605,6 +3680,8 @@
 
   // Infer type witnesses from value witnesses.
   auto inferred = inferTypeWitnessesViaValueWitnesses(unresolvedAssocTypes);
+  DEBUG(llvm::dbgs() << "Candidates for inference:\n";
+        dumpInferredAssociatedTypes(inferred));
 
   // Compute the set of solutions.
   SmallVector<std::pair<ValueDecl *, ValueDecl *>, 4> valueWitnesses;
@@ -3794,6 +3871,9 @@
         Type replaced = known->first.transform(foldDependentMemberTypes);
         if (replaced.isNull())
           return true;
+        
+        if (checkTypeWitness(TC, DC, assocType, replaced))
+          return true;
 
         known->first = replaced;
       }
diff --git a/test/Constraints/associated_types.swift b/test/Constraints/associated_types.swift
index 2436e92..9fa2709 100644
--- a/test/Constraints/associated_types.swift
+++ b/test/Constraints/associated_types.swift
@@ -37,3 +37,50 @@
 func spoon<S: Spoon>(_ s: S) {
   let _: S.Runcee?
 }
+
+// SR-4143
+
+protocol SameTypedDefault {
+    associatedtype X
+    associatedtype Y
+    static var x: X { get }
+    static var y: Y { get }
+}
+extension SameTypedDefault where Y == X {
+    static var x: X {
+        return y
+    }
+}
+
+struct UsesSameTypedDefault: SameTypedDefault {
+    static var y: Int {
+        return 0
+    }
+}
+
+protocol XReqt {}
+protocol YReqt {}
+
+protocol SameTypedDefaultWithReqts {
+    associatedtype X: XReqt // expected-note{{}}
+    associatedtype Y: YReqt // expected-note{{}}
+    static var x: X { get }
+    static var y: Y { get }
+}
+extension SameTypedDefaultWithReqts where Y == X {
+    static var x: X {
+        return y
+    }
+}
+
+struct XYType: XReqt, YReqt {}
+struct YType: YReqt {}
+
+struct UsesSameTypedDefaultWithReqts: SameTypedDefaultWithReqts {
+    static var y: XYType { return XYType() }
+}
+
+// expected-error@+1{{does not conform}}
+struct UsesSameTypedDefaultWithoutSatisfyingReqts: SameTypedDefaultWithReqts {
+    static var y: YType { return YType() }
+}
diff --git a/validation-test/compiler_crashers_2_fixed/0076-sr3500.swift b/validation-test/compiler_crashers_2_fixed/0076-sr3500.swift
new file mode 100644
index 0000000..f931112
--- /dev/null
+++ b/validation-test/compiler_crashers_2_fixed/0076-sr3500.swift
@@ -0,0 +1,12 @@
+// RUN: %target-swift-frontend %s -emit-ir
+
+protocol A {
+  associatedtype Coordinate: Strideable
+  func doSomething(_: Range<Coordinate>) -> Coordinate.Stride
+}
+
+extension A where Coordinate == Int {
+  func extensionFunc(_ range: Range<Coordinate>) {
+    _ = doSomething(range)
+  }
+}