Merge pull request #19482 from compnerd/windows-arches

diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake
index 4f97023..cfc1e80 100644
--- a/cmake/modules/AddSwift.cmake
+++ b/cmake/modules/AddSwift.cmake
@@ -132,10 +132,11 @@
   endif()
 
   if("${CFLAGS_SDK}" STREQUAL "ANDROID")
-    list(APPEND result
-      "--sysroot=${SWIFT_SDK_ANDROID_ARCH_${CFLAGS_ARCH}_PATH}"
-      # Use the linker included in the Android NDK.
-      "-B" "${SWIFT_SDK_ANDROID_ARCH_${CFLAGS_ARCH}_NDK_PREBUILT_PATH}/${SWIFT_SDK_ANDROID_ARCH_${CFLAGS_ARCH}_NDK_TRIPLE}/bin/")
+    # lld can handle targeting the android build.  However, if lld is not
+    # enabled, then fallback to the linker included in the android NDK.
+    if(NOT SWIFT_ENABLE_LLD_LINKER)
+      list(APPEND result "-B" "${SWIFT_SDK_ANDROID_ARCH_${CFLAGS_ARCH}_NDK_PREBUILT_PATH}/${SWIFT_SDK_ANDROID_ARCH_${CFLAGS_ARCH}_NDK_TRIPLE}/bin")
+    endif()
   endif()
 
   if(IS_DARWIN)
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 370dcf8..09f67de 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -3116,6 +3116,16 @@
   /// called to make it immediately visible.
   void makeMemberVisible(ValueDecl *member);
 
+  /// Special-behaviour flags passed to lookupDirect()
+  enum class LookupDirectFlags {
+    /// Whether to avoid loading any new extension.
+    /// Used by the module loader to break recursion.
+    IgnoreNewExtensions = 1 << 0,
+    /// Whether to include @_implements members.
+    /// Used by conformance-checking to find special @_implements members.
+    IncludeAttrImplements = 1 << 1,
+  };
+
   /// Find all of the declarations with the given name within this nominal type
   /// and its extensions.
   ///
@@ -3123,11 +3133,9 @@
   /// protocols to which the nominal type conforms. Furthermore, the resulting
   /// set of declarations has not been filtered for visibility, nor have
   /// overridden declarations been removed.
-  ///
-  /// \param ignoreNewExtensions Whether to avoid loading any new extension.
-  /// Used by the module loader to break recursion.
   TinyPtrVector<ValueDecl *> lookupDirect(DeclName name,
-                                          bool ignoreNewExtensions = false);
+                                          OptionSet<LookupDirectFlags> flags =
+                                          OptionSet<LookupDirectFlags>());
 
   /// Collect the set of protocols to which this type should implicitly
   /// conform, such as AnyObject (for classes).
diff --git a/include/swift/AST/LookupKinds.h b/include/swift/AST/LookupKinds.h
index 5d735f0..71a61f5 100644
--- a/include/swift/AST/LookupKinds.h
+++ b/include/swift/AST/LookupKinds.h
@@ -57,6 +57,9 @@
   /// This lookup should only return type declarations.
   NL_OnlyTypes = 0x80,
 
+  /// Include synonyms declared with @_implements()
+  NL_IncludeAttributeImplements = 0x100,
+
   /// This lookup is known to not add any additional dependencies to the
   /// primary source file.
   ///
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index ceedb10..5fb65dd 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -55,7 +55,7 @@
 /// describe what change you made. The content of this comment isn't important;
 /// it just ensures a conflict if two people change the module format.
 /// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t VERSION_MINOR = 448; // Last change: assoc type default is interface type
+const uint16_t VERSION_MINOR = 449; // Last change: serialize @_implements names
 
 using DeclIDField = BCFixed<31>;
 
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b113b25..cecae36 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3252,8 +3252,10 @@
 
 bool ClassDecl::hasMissingDesignatedInitializers() const {
   auto *mutableThis = const_cast<ClassDecl *>(this);
+  auto flags = OptionSet<LookupDirectFlags>();
+  flags |= LookupDirectFlags::IgnoreNewExtensions;
   (void)mutableThis->lookupDirect(DeclBaseName::createConstructor(),
-                                  /*ignoreNewExtensions*/true);
+                                  flags);
   return Bits.ClassDecl.HasMissingDesignatedInitializers;
 }
 
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 7588277..b157b4f 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -2124,8 +2124,9 @@
     ProtocolDecl *proto = conforms.first;
 
     // Look for an associated type and/or concrete type with this name.
-    for (auto member : proto->lookupDirect(name,
-                                           /*ignoreNewExtensions=*/true)) {
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+    for (auto member : proto->lookupDirect(name, flags)) {
       // If this is an associated type, record whether it is the best
       // associated type we've seen thus far.
       if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index 699a8b7..07c9d79 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -1339,8 +1339,11 @@
   if (!vd)
     return;
 
-  // Unnamed entities cannot be found by name lookup.
-  if (!vd->hasName())
+  // @_implements members get added under their declared name.
+  auto A = vd->getAttrs().getAttribute<ImplementsAttr>();
+
+  // Unnamed entities w/o @_implements synonyms cannot be found by name lookup.
+  if (!A && !vd->hasName())
     return;
 
   // If this declaration is already in the lookup table, don't add it
@@ -1353,6 +1356,10 @@
   // Add this declaration to the lookup set under its compound name and simple
   // name.
   vd->getFullName().addToLookupTable(Lookup, vd);
+
+  // And if given a synonym, under that name too.
+  if (A)
+    A->getMemberName().addToLookupTable(Lookup, vd);
 }
 
 void MemberLookupTable::addMembers(DeclRange members) {
@@ -1592,9 +1599,31 @@
   LookupTable.getPointer()->addMember(member);
 }
 
+
+static TinyPtrVector<ValueDecl *>
+maybeFilterOutAttrImplements(TinyPtrVector<ValueDecl *> decls,
+                             DeclName name,
+                             bool includeAttrImplements) {
+  if (includeAttrImplements)
+    return decls;
+  TinyPtrVector<ValueDecl*> result;
+  for (auto V : decls) {
+    // Filter-out any decl that doesn't have the name we're looking for
+    // (asserting as a consistency-check that such entries all have
+    // @_implements attrs for the name!)
+    if (V->getFullName().matchesRef(name)) {
+      result.push_back(V);
+    } else {
+      auto A = V->getAttrs().getAttribute<ImplementsAttr>();
+      assert(A && A->getMemberName().matchesRef(name));
+    }
+  }
+  return result;
+}
+
 TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
                                                   DeclName name,
-                                                  bool ignoreNewExtensions) {
+                                                  OptionSet<LookupDirectFlags> flags) {
   ASTContext &ctx = getASTContext();
   if (auto s = ctx.Stats) {
     ++s->getFrontendCounters().NominalTypeLookupDirectCount;
@@ -1605,6 +1634,12 @@
   bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading &&
                                     hasLazyMembers());
 
+  bool ignoreNewExtensions =
+      flags.contains(LookupDirectFlags::IgnoreNewExtensions);
+
+  bool includeAttrImplements =
+      flags.contains(LookupDirectFlags::IncludeAttrImplements);
+
   // FIXME: At present, lazy member loading conflicts with a bunch of other code
   // that appears to special-case initializers (clang-imported initializer
   // sorting, implicit initializer synthesis), so for the time being we have to
@@ -1663,7 +1698,8 @@
 
     // We found something; return it.
     if (known != LookupTable.getPointer()->end())
-      return known->second;
+      return maybeFilterOutAttrImplements(known->second, name,
+                                          includeAttrImplements);
 
     // If we have no more second chances, stop now.
     if (!useNamedLazyMemberLoading || i > 0)
@@ -2004,7 +2040,10 @@
 
     // Look for results within the current nominal type and its extensions.
     bool currentIsProtocol = isa<ProtocolDecl>(current);
-    for (auto decl : current->lookupDirect(member)) {
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    if (options & NL_IncludeAttributeImplements)
+      flags |= NominalTypeDecl::LookupDirectFlags::IncludeAttrImplements;
+    for (auto decl : current->lookupDirect(member, flags)) {
       // If we're performing a type lookup, don't even attempt to validate
       // the decl if its not a type.
       if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 3146a6a..fd2a7f6 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -2634,7 +2634,9 @@
       isa<StructDecl>(baseType) && !baseType->hasLazyMembers() &&
       baseType->isChildContextOf(this)) {
     auto *mutableBase = const_cast<NominalTypeDecl *>(baseType);
-    auto codeEnum = mutableBase->lookupDirect(name,/*ignoreNewExtensions*/true);
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+    auto codeEnum = mutableBase->lookupDirect(name, flags);
     // Double-check that we actually have a good result. It's possible what we
     // found is /not/ a synthesized error struct, but just something that looks
     // like it. But if we still found a good result we should return that.
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 1d77e3b8..1c7eb07 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -6093,9 +6093,11 @@
   SmallVector<AnyFunctionType::Param, 4> allocParams;
   bodyParams->getParams(allocParams);
 
-  bool ignoreNewExtensions = isa<ClassDecl>(dc);
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  if (isa<ClassDecl>(dc))
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
   for (auto other : ownerNominal->lookupDirect(importedName.getDeclName(),
-                                               ignoreNewExtensions)) {
+                                               flags)) {
     auto ctor = dyn_cast<ConstructorDecl>(other);
     if (!ctor || ctor->isInvalid() ||
         ctor->getAttrs().isUnavailable(Impl.SwiftContext) ||
diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp
index 3d7628b..bfebccd 100644
--- a/lib/ClangImporter/ImportType.cpp
+++ b/lib/ClangImporter/ImportType.cpp
@@ -797,8 +797,9 @@
         if (attr->getProtocolKind() ==
             KnownProtocolKind::BridgedStoredNSError) {
           auto &ctx = nominal->getASTContext();
-          auto lookup = nominal->lookupDirect(ctx.Id_Code,
-                                              /*ignoreNewExtensions=*/true);
+          auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+          flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+          auto lookup = nominal->lookupDirect(ctx.Id_Code, flags);
           for (auto found : lookup) {
             if (auto codeDecl = dyn_cast<TypeDecl>(found))
               return codeDecl;
diff --git a/lib/IDE/ModuleInterfacePrinting.cpp b/lib/IDE/ModuleInterfacePrinting.cpp
index cdf9d35..b82f9b6 100644
--- a/lib/IDE/ModuleInterfacePrinting.cpp
+++ b/lib/IDE/ModuleInterfacePrinting.cpp
@@ -231,8 +231,9 @@
   if (auto nominal =
         const_cast<NominalTypeDecl *>(dyn_cast<NominalTypeDecl>(decl))) {
     auto &ctx = nominal->getASTContext();
-    for (auto code : nominal->lookupDirect(ctx.Id_Code,
-                                           /*ignoreNewExtensions=*/true)) {
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+    for (auto code : nominal->lookupDirect(ctx.Id_Code, flags)) {
       if (auto clangDecl = code->getClangDecl())
         return clangDecl;
     }
diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp
index ef1a958..6c69919 100644
--- a/lib/RemoteAST/RemoteAST.cpp
+++ b/lib/RemoteAST/RemoteAST.cpp
@@ -402,8 +402,10 @@
     if (!base->isTypeParameter())
       return Type();
 
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
     for (auto member : protocol->lookupDirect(Ctx.getIdentifier(member),
-                                              /*ignoreNew=*/true)) {
+                                              flags)) {
       if (auto assocType = dyn_cast<AssociatedTypeDecl>(member))
         return DependentMemberType::get(base, assocType);
     }
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index 41cdd8b..7072316 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -214,7 +214,9 @@
   auto &ctx = getASTContext();
   FuncDecl *found = nullptr;
   DeclName name(ctx, ctx.Id_bridgeToObjectiveC, llvm::ArrayRef<Identifier>());
-  for (auto member : proto->lookupDirect(name, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto member : proto->lookupDirect(name, flags)) {
     if (auto func = dyn_cast<FuncDecl>(member)) {
       found = func;
       break;
@@ -245,7 +247,9 @@
   FuncDecl *found = nullptr;
   DeclName name(ctx, ctx.getIdentifier("_unconditionallyBridgeFromObjectiveC"),
                 llvm::makeArrayRef(Identifier()));
-  for (auto member : proto->lookupDirect(name, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto member : proto->lookupDirect(name, flags)) {
     if (auto func = dyn_cast<FuncDecl>(member)) {
       found = func;
       break;
@@ -275,7 +279,9 @@
   auto &ctx = getASTContext();
   AssociatedTypeDecl *found = nullptr;
   DeclName name(ctx.Id_ObjectiveCType);
-  for (auto member : proto->lookupDirect(name, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto member : proto->lookupDirect(name, flags)) {
     if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
       found = assocType;
       break;
@@ -325,7 +331,9 @@
   // Look for _nsError.
   auto &ctx = getASTContext();
   VarDecl *found = nullptr;
-  for (auto member : proto->lookupDirect(ctx.Id_nsError, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto member : proto->lookupDirect(ctx.Id_nsError, flags)) {
     if (auto var = dyn_cast<VarDecl>(member)) {
       found = var;
       break;
diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp
index 2f7b004..410aae8 100644
--- a/lib/SILOptimizer/Transforms/Outliner.cpp
+++ b/lib/SILOptimizer/Transforms/Outliner.cpp
@@ -145,7 +145,9 @@
   FuncDecl *Requirement = nullptr;
   // bridgeToObjectiveC
   DeclName Name(Ctx, Ctx.Id_bridgeToObjectiveC, llvm::ArrayRef<Identifier>());
-  for (auto Member : Proto->lookupDirect(Name, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto Member : Proto->lookupDirect(Name, flags)) {
     if (auto Func = dyn_cast<FuncDecl>(Member)) {
       Requirement = Func;
       break;
@@ -175,7 +177,9 @@
   // _unconditionallyBridgeFromObjectiveC
   DeclName Name(Ctx, Ctx.getIdentifier("_unconditionallyBridgeFromObjectiveC"),
                 llvm::makeArrayRef(Identifier()));
-  for (auto Member : Proto->lookupDirect(Name, true)) {
+  auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+  flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+  for (auto Member : Proto->lookupDirect(Name, flags)) {
     if (auto Func = dyn_cast<FuncDecl>(Member)) {
       Requirement = Func;
       break;
diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp
index 832210d..c2315a6 100644
--- a/lib/Sema/TypeCheckDeclOverride.cpp
+++ b/lib/Sema/TypeCheckDeclOverride.cpp
@@ -1700,9 +1700,11 @@
 
     // Look for associated types with the same name.
     bool foundAny = false;
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
     for (auto member : inheritedProto->lookupDirect(
                                               assocType->getFullName(),
-                                              /*ignoreNewExtensions=*/true)) {
+                                              flags)) {
       if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
         overriddenAssocTypes.push_back(assocType);
         foundAny = true;
diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp
index 656deb9..e3a2d0a 100644
--- a/lib/Sema/TypeCheckNameLookup.cpp
+++ b/lib/Sema/TypeCheckNameLookup.cpp
@@ -376,6 +376,9 @@
   if (options.contains(NameLookupFlags::ProtocolMembers))
     subOptions |= NL_ProtocolMembers;
 
+  if (options.contains(NameLookupFlags::IncludeAttributeImplements))
+    subOptions |= NL_IncludeAttributeImplements;
+
   // We handle our own overriding/shadowing filtering.
   subOptions &= ~NL_RemoveOverridden;
   subOptions &= ~NL_RemoveNonVisible;
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index a518deb..39476e2 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -867,10 +867,49 @@
   return matchWitness(tc, dc, req, witness, setup, matchTypes, finalize);
 }
 
+static bool
+witnessHasImplementsAttrForRequiredName(ValueDecl *witness,
+                                        ValueDecl *requirement) {
+  if (auto A = witness->getAttrs().getAttribute<ImplementsAttr>()) {
+    return A->getMemberName() == requirement->getFullName();
+  }
+  return false;
+}
+
+static bool
+witnessHasImplementsAttrForExactRequirement(ValueDecl *witness,
+                                            ValueDecl *requirement) {
+  assert(requirement->isProtocolRequirement());
+  auto *PD = cast<ProtocolDecl>(requirement->getDeclContext());
+  if (auto A = witness->getAttrs().getAttribute<ImplementsAttr>()) {
+    Type T = A->getProtocolType().getType();
+    if (T->castTo<ProtocolType>()->getDecl() == PD) {
+      return A->getMemberName() == requirement->getFullName();
+    }
+  }
+  return false;
+}
+
 /// \brief Determine whether one requirement match is better than the other.
 static bool isBetterMatch(TypeChecker &tc, DeclContext *dc,
+                          ValueDecl *requirement,
                           const RequirementMatch &match1,
                           const RequirementMatch &match2) {
+
+  // Special case to prefer a witness with @_implements(Foo, bar) over one without
+  // it, when the requirement was exactly for Foo.bar.
+  bool match1ImplementsAttr =
+    witnessHasImplementsAttrForExactRequirement(match1.Witness,
+                                                requirement);
+  bool match2ImplementsAttr =
+    witnessHasImplementsAttrForExactRequirement(match2.Witness,
+                                                requirement);
+  if (match1ImplementsAttr && !match2ImplementsAttr) {
+    return true;
+  } else if (!match1ImplementsAttr && match2ImplementsAttr) {
+    return false;
+  }
+
   // Check whether one declaration is better than the other.
   switch (tc.compareDeclarations(dc, match1.Witness, match2.Witness)) {
   case Comparison::Better:
@@ -894,41 +933,19 @@
 
 WitnessChecker::WitnessChecker(TypeChecker &tc, ProtocolDecl *proto,
                                Type adoptee, DeclContext *dc)
-    : TC(tc), Proto(proto), Adoptee(adoptee), DC(dc) {
-  if (auto N = DC->getSelfNominalTypeDecl()) {
-    for (auto D : N->getMembers()) {
-      if (auto V = dyn_cast<ValueDecl>(D)) {
-        if (!V->hasName())
-          continue;
-        if (auto A = V->getAttrs().getAttribute<ImplementsAttr>()) {
-          A->getMemberName().addToLookupTable(ImplementsTable, V);
-        }
-      }
-    }
-  }
-}
+    : TC(tc), Proto(proto), Adoptee(adoptee), DC(dc) {}
 
 void
 WitnessChecker::lookupValueWitnessesViaImplementsAttr(
     ValueDecl *req, SmallVector<ValueDecl *, 4> &witnesses) {
-  if (!req->isProtocolRequirement())
-    return;
-  if (!req->hasName())
-    return;
-  auto *PD = dyn_cast<ProtocolDecl>(req->getDeclContext());
-  if (!PD)
-    return;
-  auto i = ImplementsTable.find(req->getFullName());
-  if (i == ImplementsTable.end())
-    return;
-  for (auto candidate : i->second) {
-    if (auto A = candidate->getAttrs().getAttribute<ImplementsAttr>()) {
-      Type T = A->getProtocolType().getType();
-      if (auto *PT = T->getAs<ProtocolType>()) {
-        if (PT->getDecl() == PD) {
-          witnesses.push_back(candidate);
-        }
-      }
+  auto lookupOptions = defaultMemberTypeLookupOptions;
+  lookupOptions -= NameLookupFlags::PerformConformanceCheck;
+  lookupOptions |= NameLookupFlags::IncludeAttributeImplements;
+  auto candidates = TC.lookupMember(DC, Adoptee, req->getFullName(),
+                                    lookupOptions);
+  for (auto candidate : candidates) {
+    if (witnessHasImplementsAttrForExactRequirement(candidate.getValueDecl(), req)) {
+      witnesses.push_back(candidate.getValueDecl());
     }
   }
 }
@@ -936,7 +953,8 @@
 SmallVector<ValueDecl *, 4>
 WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) {
   assert(!isa<AssociatedTypeDecl>(req) && "Not for lookup for type witnesses*");
-  
+  assert(req->isProtocolRequirement());
+
   SmallVector<ValueDecl *, 4> witnesses;
 
   // Do an initial check to see if there are any @_implements remappings
@@ -1113,7 +1131,7 @@
     // Find the best match.
     bestIdx = 0;
     for (unsigned i = 1, n = matches.size(); i != n; ++i) {
-      if (isBetterMatch(TC, DC, matches[i], matches[bestIdx]))
+      if (isBetterMatch(TC, DC, requirement, matches[i], matches[bestIdx]))
         bestIdx = i;
     }
 
@@ -1122,7 +1140,7 @@
       if (i == bestIdx)
         continue;
 
-      if (!isBetterMatch(TC, DC, matches[bestIdx], matches[i])) {
+      if (!isBetterMatch(TC, DC, requirement, matches[bestIdx], matches[i])) {
         isReallyBest = false;
         break;
       }
@@ -2530,15 +2548,6 @@
   }
 }
 
-static bool
-witnessHasImplementsAttrForRequirement(ValueDecl *witness,
-                                       ValueDecl *requirement) {
-  if (auto A = witness->getAttrs().getAttribute<ImplementsAttr>()) {
-    return A->getMemberName() == requirement->getFullName();
-  }
-  return false;
-}
-
 /// Determine the given witness has a same-type constraint constraining the
 /// given 'Self' type, and return the requirement that does.
 ///
@@ -2797,7 +2806,7 @@
     // If the name didn't actually line up, complain.
     if (ignoringNames &&
         requirement->getFullName() != best.Witness->getFullName() &&
-        !witnessHasImplementsAttrForRequirement(best.Witness, requirement)) {
+        !witnessHasImplementsAttrForRequiredName(best.Witness, requirement)) {
 
       diagnoseOrDefer(requirement, false,
         [witness, requirement](NormalProtocolConformance *conformance) {
@@ -4793,9 +4802,10 @@
           continue;
 
         bool valueIsType = isa<TypeDecl>(value);
+        auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+        flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
         for (auto requirement
-                : diag.Protocol->lookupDirect(value->getFullName(),
-                                              /*ignoreNewExtensions=*/true)) {
+                : diag.Protocol->lookupDirect(value->getFullName(), flags)) {
           auto requirementIsType = isa<TypeDecl>(requirement);
           if (valueIsType != requirementIsType)
             continue;
@@ -4991,7 +5001,9 @@
     if (!proto->isObjC()) continue;
 
     Optional<ProtocolConformance *> conformance;
-    for (auto req : proto->lookupDirect(name, true)) {
+    auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+    flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
+    for (auto req : proto->lookupDirect(name, flags)) {
       // Skip anything in a protocol extension.
       if (req->getDeclContext() != proto) continue;
 
diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp
index db5b516..b5b5a7c 100644
--- a/lib/Sema/TypeCheckProtocolInference.cpp
+++ b/lib/Sema/TypeCheckProtocolInference.cpp
@@ -418,6 +418,8 @@
     auto req = dyn_cast<ValueDecl>(member);
     if (!req)
       continue;
+    if (!req->isProtocolRequirement())
+      continue;
 
     // Infer type witnesses for associated types.
     if (auto assocType = dyn_cast<AssociatedTypeDecl>(req)) {
@@ -1076,9 +1078,10 @@
         // Find an associated type with the same name in the given
         // protocol.
         AssociatedTypeDecl *foundAssocType = nullptr;
+        auto flags = OptionSet<NominalTypeDecl::LookupDirectFlags>();
+        flags |= NominalTypeDecl::LookupDirectFlags::IgnoreNewExtensions;
         for (auto result : thisProto->lookupDirect(
-                                             assocType->getName(),
-                                             /*ignoreNewExtensions=*/true)) {
+                                             assocType->getName(), flags)) {
           foundAssocType = dyn_cast<AssociatedTypeDecl>(result);
           if (foundAssocType) break;
         }
diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h
index 6d13959..537a641 100644
--- a/lib/Sema/TypeChecker.h
+++ b/lib/Sema/TypeChecker.h
@@ -299,6 +299,8 @@
   /// Whether to include results from outside the innermost scope that has a
   /// result.
   IncludeOuterResults = 0x20,
+  /// Whether to consider synonyms declared through @_implements().
+  IncludeAttributeImplements = 0x40,
 };
 
 /// A set of options that control name lookup.
diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp
index 92b07f5..66013ce 100644
--- a/lib/Serialization/Serialization.cpp
+++ b/lib/Serialization/Serialization.cpp
@@ -1814,6 +1814,16 @@
         (*memberTable)[parentID].push_back(memberID);
       }
 
+      // Same as above, but for @_implements attributes
+      if (auto A = VD->getAttrs().getAttribute<ImplementsAttr>()) {
+        std::unique_ptr<DeclMembersTable> &memberTable =
+          DeclMemberNames[A->getMemberName().getBaseName()].second;
+        if (!memberTable) {
+          memberTable = llvm::make_unique<DeclMembersTable>();
+        }
+        (*memberTable)[parentID].push_back(memberID);
+      }
+
       // Possibly add a record to ClassMembersForDynamicLookup too.
       if (isClass) {
         if (VD->canBeAccessedByDynamicLookup()) {
diff --git a/test/attr/attr_implements.swift b/test/attr/attr_implements.swift
index 5d2fd6e..5f1da10 100644
--- a/test/attr/attr_implements.swift
+++ b/test/attr/attr_implements.swift
@@ -70,3 +70,23 @@
 
 // print(s.f(x:1, y:2))
 
+
+// Next test is for rdar://43804798
+//
+// When choosing between an @_implements-provided implementation of a specific
+// protocol's witness (Equatable / Comparable in particular), we want to choose
+// the @_implements-provided one when we're looking up from a context that only
+// knows the protocol bound, and the non-@_implements-provided one when we're
+// looking up from a context that knows the full type.
+
+struct SpecificType : Equatable {
+  @_implements(Equatable, ==(_:_:))
+  static func bar(_: SpecificType, _: SpecificType) -> Bool { return true }
+  static func ==(_: SpecificType, _: SpecificType) -> Bool { return false }
+}
+
+func trueWhenJustEquatable<T: Equatable>(_ x: T) -> Bool { return x == x }
+func falseWhenSpecificType(_ x: SpecificType) -> Bool { return x == x }
+
+assert(trueWhenJustEquatable(SpecificType()))
+assert(!falseWhenSpecificType(SpecificType()))
diff --git a/test/attr/attr_implements_fp.swift b/test/attr/attr_implements_fp.swift
new file mode 100644
index 0000000..f8ae784
--- /dev/null
+++ b/test/attr/attr_implements_fp.swift
@@ -0,0 +1,116 @@
+// RUN: %empty-directory(%t)
+// RUN: echo 'main()' >%t/main.swift
+// RUN: %target-swiftc_driver -o %t/a.out %s %t/main.swift
+// RUN: %target-codesign %t/a.out
+// RUN: %target-run %t/a.out | %FileCheck %s
+// REQUIRES: executable_test
+
+// This is a more-thorough and explicit test for rdar://43804798 that uses @_implements to
+// achieve "Comparable Floating Point values are FP-like when known to be FP, Comparable-like
+// when only known to be comparable".
+
+// Could calls to the different comparison operators.
+public var comparedAsComparablesCount : Int = 0
+public var comparedAsFauxtsCount : Int = 0
+
+public protocol FauxtingPoint : Comparable {
+  static var nan: Self { get }
+  static var one: Self { get }
+  static var two: Self { get }
+}
+
+public protocol BinaryFauxtingPoint: FauxtingPoint {
+  var bitPattern: UInt8 { get }
+}
+
+public extension BinaryFauxtingPoint {
+  // This version of < will be called in a context that only knows it has a Comparable.
+  @_implements(Comparable, <(_:_:))
+  static func _ComparableLessThan(_ lhs: Fauxt, _ rhs: Fauxt) -> Bool {
+    print("compared as Comparables")
+    comparedAsComparablesCount += 1
+    return lhs.bitPattern < rhs.bitPattern
+  }
+}
+
+public enum State {
+  case Nan
+  case One
+  case Two
+}
+
+public struct Fauxt {
+  let state: State
+  init(_ s: State) {
+    state = s
+  }
+  public static var nan: Fauxt {
+    return Fauxt(State.Nan)
+  }
+  public static var one: Fauxt {
+    return Fauxt(State.One)
+  }
+  public static var two: Fauxt {
+    return Fauxt(State.Two)
+  }
+}
+
+extension Fauxt: BinaryFauxtingPoint {
+  // Requirement from BinaryFauxtingPoint
+  public var bitPattern: UInt8 {
+    switch state {
+    case .One:
+      return 1
+    case .Two:
+      return 2
+    case .Nan:
+      return 0xff
+    }
+  }
+}
+
+public extension Fauxt {
+  // This version of < will be called in a context that knows it has a Fauxt.
+  // It is inside an extension of Fauxt rather than the declaration of Fauxt
+  // itself in order to avoid a warning about near-matches with the defaulted
+  // requirement from Comparable.< up above.
+  static func <(_ lhs: Fauxt, _ rhs: Fauxt) -> Bool {
+    print("compared as Fauxts")
+    comparedAsFauxtsCount += 1
+    if lhs.state == .Nan || rhs.state == .Nan {
+      return false
+    } else {
+      return lhs.bitPattern < rhs.bitPattern
+    }
+  }
+}
+
+public func compare_Comparables<T:Comparable>(_ x: T, _ y: T) -> Bool {
+  return x < y
+}
+
+public func compare_Fauxts(_ x: Fauxt, _ y: Fauxt) -> Bool {
+  return x < y
+}
+
+public func main() {
+  assert(compare_Comparables(Fauxt.one, Fauxt.two))
+  assert(comparedAsComparablesCount == 1)
+  // CHECK: compared as Comparables
+  assert(compare_Comparables(Fauxt.one, Fauxt.nan))
+  assert(comparedAsComparablesCount == 2)
+  // CHECK: compared as Comparables
+  assert(!compare_Comparables(Fauxt.nan, Fauxt.one))
+  assert(comparedAsComparablesCount == 3)
+  // CHECK: compared as Comparables
+
+  assert(compare_Fauxts(Fauxt.one, Fauxt.two))
+  assert(comparedAsFauxtsCount == 1)
+  // CHECK: compared as Fauxts
+  assert(!compare_Fauxts(Fauxt.one, Fauxt.nan))
+  assert(comparedAsFauxtsCount == 2)
+  // CHECK: compared as Fauxts
+  assert(!compare_Fauxts(Fauxt.nan, Fauxt.one))
+  assert(comparedAsFauxtsCount == 3)
+  // CHECK: compared as Fauxts
+}
diff --git a/test/attr/attr_implements_serial.swift b/test/attr/attr_implements_serial.swift
new file mode 100644
index 0000000..b5e5583
--- /dev/null
+++ b/test/attr/attr_implements_serial.swift
@@ -0,0 +1,35 @@
+// RUN: %empty-directory(%t)
+// RUN: echo 'client()' >%t/main.swift
+// RUN: %target-swiftc_driver -module-name AttrImplFP -emit-module -emit-module-path %t/AttrImplFP.swiftmodule -emit-library -o %t/library.%target-dylib-extension %S/attr_implements_fp.swift
+// RUN: %target-swiftc_driver -I %t -o %t/a.out %s %t/main.swift %t/library.%target-dylib-extension
+// RUN: %target-codesign %t/a.out
+// RUN: %target-codesign %t/library.%target-dylib-extension
+// RUN: %target-run %t/a.out | %FileCheck %s
+// REQUIRES: executable_test
+
+// This test just checks that the lookup-table entries for @_implements are
+// also written-to and read-from serialized .swiftmodules
+
+import AttrImplFP
+
+public func client() {
+  assert(compare_Comparables(Fauxt.one, Fauxt.two))
+  assert(comparedAsComparablesCount == 1)
+  // CHECK: compared as Comparables
+  assert(compare_Comparables(Fauxt.one, Fauxt.nan))
+  assert(comparedAsComparablesCount == 2)
+  // CHECK: compared as Comparables
+  assert(!compare_Comparables(Fauxt.nan, Fauxt.one))
+  assert(comparedAsComparablesCount == 3)
+  // CHECK: compared as Comparables
+
+  assert(compare_Fauxts(Fauxt.one, Fauxt.two))
+  assert(comparedAsFauxtsCount == 1)
+  // CHECK: compared as Fauxts
+  assert(!compare_Fauxts(Fauxt.one, Fauxt.nan))
+  assert(comparedAsFauxtsCount == 2)
+  // CHECK: compared as Fauxts
+  assert(!compare_Fauxts(Fauxt.nan, Fauxt.one))
+  assert(comparedAsFauxtsCount == 3)
+  // CHECK: compared as Fauxts
+}
diff --git a/test/decl/protocol/req/associated_type_inference.swift b/test/decl/protocol/req/associated_type_inference.swift
index b00165e..8d8b92f 100644
--- a/test/decl/protocol/req/associated_type_inference.swift
+++ b/test/decl/protocol/req/associated_type_inference.swift
@@ -501,3 +501,10 @@
 struct Foo: RefinesAssocWithDefault {
 }
 
+protocol P20 {
+  associatedtype T // expected-note{{protocol requires nested type 'T'; do you want to add it?}}
+  typealias TT = T?
+}
+struct S19 : P20 {  // expected-error{{type 'S19' does not conform to protocol 'P20'}}
+  typealias TT = Int?
+}