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?
+}