@@ -1840,54 +1840,39 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
18401840# pragma mark Witness resolution
18411841
18421842// / Retrieve the Objective-C method key from the given function.
1843- namespace {
1844- using ObjCMethodKey = std::pair<ObjCSelector, char >;
1845- using ObjCRequirementMap = llvm::SmallDenseMap<ObjCMethodKey,
1846- TinyPtrVector<AbstractFunctionDecl *>, 4 >;
1847- }
1848-
1849- // / Retrieve the Objective-C method key from the given function.
1850- static ObjCMethodKey getObjCMethodKey (AbstractFunctionDecl *func) {
1843+ ObjCRequirementMap::MethodKey
1844+ ObjCRequirementMap::getObjCMethodKey (AbstractFunctionDecl *func) {
18511845 return std::make_pair (func->getObjCSelector (), func->isInstanceMember ());
18521846}
18531847
18541848// / Precompute map for getObjCRequirements().
1855- static ObjCRequirementMap getObjCRequirementMap (ProtocolDecl *proto) {
1856- ObjCRequirementMap map;
1857-
1858- if (!proto->isObjC ())
1859- return map;
1849+ ObjCRequirementMap
1850+ ObjCRequirementMapRequest::evaluate (Evaluator &evaluator,
1851+ const ProtocolDecl *proto) const {
1852+ // This map only applies to Obj-C protocols so it's wasteful to evaluate this
1853+ // request and cache the result for non-Obj-C protocols.
1854+ assert (proto->isObjC ());
18601855
1856+ ObjCRequirementMap map;
18611857 for (auto requirement : proto->getProtocolRequirements ()) {
18621858 auto funcRequirement = dyn_cast<AbstractFunctionDecl>(requirement);
18631859 if (!funcRequirement)
18641860 continue ;
18651861
1866- map[ getObjCMethodKey (funcRequirement)]. push_back (funcRequirement);
1862+ map. addRequirement (funcRequirement);
18671863 }
18681864
18691865 return map;
18701866}
18711867
1872- // / Retrieve the Objective-C requirements in this protocol that have the
1873- // / given Objective-C method key.
1874- static ArrayRef<AbstractFunctionDecl *>
1875- getObjCRequirements (const ObjCRequirementMap &map, ObjCMethodKey key) {
1876- auto known = map.find (key);
1877- if (known == map.end ())
1878- return { };
1879-
1880- return known->second ;
1881- }
1882-
18831868// / @returns a non-null requirement if the given requirement is part of a
18841869// / group of ObjC requirements that share the same ObjC method key.
18851870// / The first such requirement that the predicate function returns true for
18861871// / is the requirement required by this function. Otherwise, nullptr is
18871872// / returned.
18881873static ValueDecl *getObjCRequirementSibling (
1889- ProtocolDecl *proto, ValueDecl *requirement, const ObjCRequirementMap &map,
1890- llvm::function_ref<bool (AbstractFunctionDecl*)> predicate) {
1874+ ProtocolDecl *proto, ValueDecl *requirement,
1875+ llvm::function_ref<bool (AbstractFunctionDecl *)> predicate) {
18911876 if (!proto->isObjC ())
18921877 return nullptr ;
18931878
@@ -1896,8 +1881,8 @@ static ValueDecl *getObjCRequirementSibling(
18961881
18971882 // We only care about functions
18981883 if (auto fnRequirement = dyn_cast<AbstractFunctionDecl>(requirement)) {
1899- auto fnSelector = getObjCMethodKey (fnRequirement );
1900- auto similarRequirements = getObjCRequirements ( map, fnSelector );
1884+ auto map = proto-> getObjCRequiremenMap ( );
1885+ auto similarRequirements = map. getRequirements (fnRequirement );
19011886 // ... whose selector is one that maps to multiple requirement declarations.
19021887 for (auto candidate : similarRequirements) {
19031888 if (candidate == fnRequirement)
@@ -1948,9 +1933,8 @@ class MultiConformanceChecker {
19481933 NormalProtocolConformance *conformance);
19491934
19501935 // / Determine whether the given requirement was left unsatisfied.
1951- bool isUnsatisfiedReq (
1952- NormalProtocolConformance *conformance, ValueDecl *req,
1953- const ObjCRequirementMap &map);
1936+ bool isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req);
1937+
19541938public:
19551939 MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
19561940
@@ -1977,9 +1961,8 @@ class MultiConformanceChecker {
19771961
19781962}
19791963
1980- bool MultiConformanceChecker::
1981- isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req,
1982- const ObjCRequirementMap &map) {
1964+ bool MultiConformanceChecker::isUnsatisfiedReq (
1965+ NormalProtocolConformance *conformance, ValueDecl *req) {
19831966 if (conformance->isInvalid ()) return false ;
19841967 if (isa<TypeDecl>(req)) return false ;
19851968
@@ -1993,7 +1976,7 @@ isUnsatisfiedReq(NormalProtocolConformance *conformance, ValueDecl *req,
19931976 // If another @objc requirement refers to the same Objective-C
19941977 // method, this requirement isn't unsatisfied.
19951978 if (getObjCRequirementSibling (
1996- proto, req, map, [conformance](AbstractFunctionDecl *cand) {
1979+ proto, req, [conformance](AbstractFunctionDecl *cand) {
19971980 return static_cast <bool >(conformance->getWitness (cand));
19981981 })) {
19991982 return false ;
@@ -2034,12 +2017,11 @@ void MultiConformanceChecker::checkAllConformances() {
20342017 if (!anyInvalid) {
20352018 // Check whether there are any unsatisfied requirements.
20362019 auto proto = conformance->getProtocol ();
2037- ObjCRequirementMap map = getObjCRequirementMap (proto);
20382020
20392021 for (auto *req : proto->getProtocolRequirements ()) {
20402022 // If the requirement is unsatisfied, we might want to warn
20412023 // about near misses; record it.
2042- if (isUnsatisfiedReq (conformance, req, map )) {
2024+ if (isUnsatisfiedReq (conformance, req)) {
20432025 UnsatisfiedReqs.push_back (req);
20442026 continue ;
20452027 }
@@ -3726,10 +3708,8 @@ hasSatisfiedObjCSiblingRequirement(ProtocolDecl *proto,
37263708 if (!proto->isObjC ())
37273709 return false ;
37283710
3729- auto map = getObjCRequirementMap (proto);
3730-
37313711 if (getObjCRequirementSibling (
3732- proto, fnRequirement, map,
3712+ proto, fnRequirement,
37333713 [proto, conformance](AbstractFunctionDecl *candidate) {
37343714 // FIXME: This performs a recursive lookup in the lazy case, so
37353715 // we have to dodge the cycle.
@@ -3962,6 +3942,27 @@ getAdopteeSelfSameTypeConstraint(ClassDecl *selfClass, ValueDecl *witness) {
39623942 return target;
39633943}
39643944
3945+ static bool allowOptionalWitness (ProtocolDecl *proto,
3946+ NormalProtocolConformance *conformance,
3947+ ValueDecl *requirement) {
3948+ auto Attrs = requirement->getAttrs ();
3949+
3950+ // An optional requirement is trivially satisfied with an empty requirement.
3951+ if (Attrs.hasAttribute <OptionalAttr>())
3952+ return true ;
3953+
3954+ // An 'unavailable' requirement is treated like an optional requirement.
3955+ if (Attrs.isUnavailable (proto->getASTContext ()))
3956+ return true ;
3957+
3958+ // A requirement with a satisfied Obj-C alternative requirement is effectively
3959+ // optional.
3960+ if (hasSatisfiedObjCSiblingRequirement (proto, conformance, requirement))
3961+ return true ;
3962+
3963+ return false ;
3964+ }
3965+
39653966void ConformanceChecker::checkNonFinalClassWitness (ValueDecl *requirement,
39663967 ValueDecl *witness) {
39673968 auto *classDecl = DC->getSelfClassDecl ();
@@ -4388,7 +4389,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43884389 //
43894390 // Treat 'unavailable' implicitly as if it were 'optional'.
43904391 // The compiler will reject actual uses.
4391- if (allowOptionalWitness (requirement)) {
4392+ if (allowOptionalWitness (Proto, Conformance, requirement)) {
43924393 return ResolveWitnessResult::Missing;
43934394 }
43944395
@@ -4561,7 +4562,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDefault(
45614562 ValueDecl *requirement) {
45624563 assert (!isa<AssociatedTypeDecl>(requirement) && " Use resolveTypeWitnessVia*" );
45634564
4564- if (allowOptionalWitness (requirement)) {
4565+ if (allowOptionalWitness (Proto, Conformance, requirement)) {
45654566 recordOptionalWitness (requirement);
45664567 return ResolveWitnessResult::Success;
45674568 }
@@ -4632,25 +4633,6 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
46324633 }
46334634}
46344635
4635- bool ConformanceChecker::allowOptionalWitness (ValueDecl *requirement) {
4636- auto Attrs = requirement->getAttrs ();
4637-
4638- // An optional requirement is trivially satisfied with an empty requirement.
4639- if (Attrs.hasAttribute <OptionalAttr>())
4640- return true ;
4641-
4642- // An 'unavailable' requirement is treated like an optional requirement.
4643- if (Attrs.isUnavailable (getASTContext ()))
4644- return true ;
4645-
4646- // A requirement with a satisfied Obj-C alternative requirement is effectively
4647- // optional.
4648- if (hasSatisfiedObjCSiblingRequirement (Proto, Conformance, requirement))
4649- return true ;
4650-
4651- return false ;
4652- }
4653-
46544636// / FIXME: It feels like this could be part of findExistentialSelfReferences().
46554637static std::optional<Requirement>
46564638hasInvariantSelfRequirement (const ProtocolDecl *proto,
@@ -4973,7 +4955,6 @@ hasInvalidTypeInConformanceContext(const ValueDecl *requirement,
49734955
49744956void ConformanceChecker::resolveValueWitnesses () {
49754957 bool usesPreconcurrencyConformance = false ;
4976- auto objcRequirementMap = getObjCRequirementMap (Proto);
49774958
49784959 for (auto *requirement : Proto->getProtocolRequirements ()) {
49794960 // Associated type requirements handled elsewhere.
@@ -5119,7 +5100,7 @@ void ConformanceChecker::resolveValueWitnesses() {
51195100 // async-looking ObjC protocol method requirement into two Swift protocol
51205101 // requirements: an async version and a sync version. Exactly one of the two
51215102 // must be witnessed by the conformer.
5122- if (getObjCRequirementSibling (Proto, requirement, objcRequirementMap,
5103+ if (getObjCRequirementSibling (Proto, requirement,
51235104 [this ](AbstractFunctionDecl *cand) {
51245105 return static_cast <bool >(
51255106 this ->Conformance ->getWitness (cand));
0 commit comments