@@ -2885,15 +2885,6 @@ class ObjCImplementationChecker {
28852885 // / Candidates with their explicit ObjC names, if any.
28862886 llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16 > unmatchedCandidates;
28872887
2888- // / Key that can be used to uniquely identify a particular Objective-C
2889- // / method.
2890- using ObjCMethodKey = std::pair<ObjCSelector, char >;
2891-
2892- // / Mapping from Objective-C methods to the set of requirements within this
2893- // / protocol that have the same selector and instance/class designation.
2894- llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4 >
2895- objcMethodRequirements;
2896-
28972888public:
28982889 ObjCImplementationChecker (ExtensionDecl *ext)
28992890 : diags(ext->getASTContext ().Diags)
@@ -2915,8 +2906,30 @@ class ObjCImplementationChecker {
29152906 }
29162907
29172908private:
2918- auto getObjCMethodKey (AbstractFunctionDecl *func) const -> ObjCMethodKey {
2919- return ObjCMethodKey (func->getObjCSelector (), func->isInstanceMember ());
2909+ static bool hasAsync (ValueDecl *member) {
2910+ if (!member)
2911+ return false ;
2912+
2913+ if (auto func = dyn_cast<AbstractFunctionDecl>(member))
2914+ return func->hasAsync ();
2915+
2916+ if (auto storage = dyn_cast<AbstractStorageDecl>(member))
2917+ return hasAsync (storage->getEffectfulGetAccessor ());
2918+
2919+ return false ;
2920+ }
2921+
2922+ static ValueDecl *getAsyncAlternative (ValueDecl *req) {
2923+ if (auto func = dyn_cast<AbstractFunctionDecl>(req)) {
2924+ auto asyncFunc = func->getAsyncAlternative ();
2925+
2926+ if (auto asyncAccessor = dyn_cast<AccessorDecl>(asyncFunc))
2927+ return asyncAccessor->getStorage ();
2928+
2929+ return asyncFunc;
2930+ }
2931+
2932+ return nullptr ;
29202933 }
29212934
29222935 void addRequirements (IterableDeclContext *idc) {
@@ -2932,12 +2945,13 @@ class ObjCImplementationChecker {
29322945 if (member->getAttrs ().isUnavailable (member->getASTContext ()))
29332946 continue ;
29342947
2948+ // Skip async versions of members. We'll match against the completion
2949+ // handler versions, hopping over to `getAsyncAlternative()` if needed.
2950+ if (hasAsync (member))
2951+ continue ;
2952+
29352953 auto inserted = unmatchedRequirements.insert (member);
29362954 assert (inserted && " objc interface member added twice?" );
2937-
2938- if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2939- objcMethodRequirements[getObjCMethodKey (func)].push_back (func);
2940- }
29412955 }
29422956 }
29432957
@@ -3034,19 +3048,6 @@ class ObjCImplementationChecker {
30343048 }
30353049 };
30363050
3037- // / Determine whether the set of matched requirements are ambiguous for the
3038- // / given candidate.
3039- bool areRequirementsAmbiguous (const BestMatchList &reqs, ValueDecl *cand) {
3040- if (reqs.matches .size () != 2 )
3041- return reqs.matches .size () > 2 ;
3042-
3043- bool firstIsAsyncAlternative =
3044- matchesAsyncAlternative (reqs.matches [0 ], cand);
3045- bool secondIsAsyncAlternative =
3046- matchesAsyncAlternative (reqs.matches [1 ], cand);
3047- return firstIsAsyncAlternative == secondIsAsyncAlternative;
3048- }
3049-
30503051 void matchRequirementsAtThreshold (MatchOutcome threshold) {
30513052 SmallString<32 > scratch;
30523053
@@ -3106,14 +3107,11 @@ class ObjCImplementationChecker {
31063107 // removing them.
31073108 requirementsToRemove.set_union (matchedRequirements.matches );
31083109
3109- if (! areRequirementsAmbiguous ( matchedRequirements, cand) ) {
3110+ if (matchedRequirements. matches . size () == 1 ) {
31103111 // Note that this is BestMatchList::insert(), so it'll only keep the
31113112 // matches with the best outcomes.
3112- for (auto req : matchedRequirements.matches ) {
3113- matchesByRequirement[req]
3114- .insert (cand, matchedRequirements.currentOutcome );
3115- }
3116-
3113+ matchesByRequirement[matchedRequirements.matches .front ()]
3114+ .insert (cand, matchedRequirements.currentOutcome );
31173115 continue ;
31183116 }
31193117
@@ -3195,35 +3193,6 @@ class ObjCImplementationChecker {
31953193 unmatchedCandidates.erase (cand);
31963194 }
31973195
3198- // / Whether the candidate matches the async alternative of the given
3199- // / requirement.
3200- bool matchesAsyncAlternative (ValueDecl *req, ValueDecl *cand) const {
3201- auto reqFunc = dyn_cast<AbstractFunctionDecl>(req);
3202- if (!reqFunc)
3203- return false ;
3204-
3205- auto candFunc = dyn_cast<AbstractFunctionDecl>(cand);
3206- if (!candFunc)
3207- return false ;
3208-
3209- if (reqFunc->hasAsync () == candFunc->hasAsync ())
3210- return false ;
3211-
3212- auto otherReqFuncs =
3213- objcMethodRequirements.find (getObjCMethodKey (reqFunc));
3214- if (otherReqFuncs == objcMethodRequirements.end ())
3215- return false ;
3216-
3217- for (auto otherReqFunc : otherReqFuncs->second ) {
3218- if (otherReqFunc->getName () == cand->getName () &&
3219- otherReqFunc->hasAsync () == candFunc->hasAsync () &&
3220- req->getObjCRuntimeName () == cand->getObjCRuntimeName ())
3221- return true ;
3222- }
3223-
3224- return false ;
3225- }
3226-
32273196 static bool areSwiftNamesEqual (DeclName lhs, DeclName rhs) {
32283197 // Conflate `foo()` and `foo`. This allows us to diagnose
32293198 // method-vs.-property mistakes more nicely.
@@ -3237,8 +3206,8 @@ class ObjCImplementationChecker {
32373206 return lhs == rhs;
32383207 }
32393208
3240- MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
3241- ObjCSelector explicitObjCName) const {
3209+ MatchOutcome matchesImpl (ValueDecl *req, ValueDecl *cand,
3210+ ObjCSelector explicitObjCName) const {
32423211 bool hasObjCNameMatch =
32433212 req->getObjCRuntimeName () == cand->getObjCRuntimeName ();
32443213 bool hasSwiftNameMatch = areSwiftNamesEqual (req->getName (), cand->getName ());
@@ -3254,10 +3223,7 @@ class ObjCImplementationChecker {
32543223 && req->getObjCRuntimeName () != explicitObjCName)
32553224 return MatchOutcome::WrongExplicitObjCName;
32563225
3257- // If the ObjC selectors matched but the Swift names do not, and these are
3258- // functions with mismatched 'async', check whether the "other" requirement
3259- // (the completion-handler or async version)'s Swift name matches.
3260- if (!hasSwiftNameMatch && !matchesAsyncAlternative (req, cand))
3226+ if (!hasSwiftNameMatch)
32613227 return MatchOutcome::WrongSwiftName;
32623228
32633229 if (!hasObjCNameMatch)
@@ -3287,6 +3253,17 @@ class ObjCImplementationChecker {
32873253 return MatchOutcome::Match;
32883254 }
32893255
3256+ MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
3257+ ObjCSelector explicitObjCName) const {
3258+ // If the candidate we're considering is async, see if the requirement has
3259+ // an async alternate and try to match against that instead.
3260+ if (hasAsync (cand))
3261+ if (auto asyncAltReq = getAsyncAlternative (req))
3262+ return matchesImpl (asyncAltReq, cand, explicitObjCName);
3263+
3264+ return matchesImpl (req, cand, explicitObjCName);
3265+ }
3266+
32903267 void diagnoseOutcome (MatchOutcome outcome, ValueDecl *req, ValueDecl *cand,
32913268 ObjCSelector explicitObjCName) {
32923269 auto reqObjCName = *req->getObjCRuntimeName ();
0 commit comments