@@ -2882,6 +2882,15 @@ class ObjCImplementationChecker {
28822882 // / Candidates with their explicit ObjC names, if any.
28832883 llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16 > unmatchedCandidates;
28842884
2885+ // / Key that can be used to uniquely identify a particular Objective-C
2886+ // / method.
2887+ using ObjCMethodKey = std::pair<ObjCSelector, char >;
2888+
2889+ // / Mapping from Objective-C methods to the set of requirements within this
2890+ // / protocol that have the same selector and instance/class designation.
2891+ llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4 >
2892+ objcMethodRequirements;
2893+
28852894public:
28862895 ObjCImplementationChecker (ExtensionDecl *ext)
28872896 : diags(ext->getASTContext ().Diags)
@@ -2903,6 +2912,10 @@ class ObjCImplementationChecker {
29032912 }
29042913
29052914private:
2915+ auto getObjCMethodKey (AbstractFunctionDecl *func) const -> ObjCMethodKey {
2916+ return ObjCMethodKey (func->getObjCSelector (), func->isInstanceMember ());
2917+ }
2918+
29062919 void addRequirements (IterableDeclContext *idc) {
29072920 assert (idc->getDecl ()->hasClangNode ());
29082921 for (Decl *_member : idc->getMembers ()) {
@@ -2918,6 +2931,10 @@ class ObjCImplementationChecker {
29182931
29192932 auto inserted = unmatchedRequirements.insert (member);
29202933 assert (inserted && " objc interface member added twice?" );
2934+
2935+ if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2936+ objcMethodRequirements[getObjCMethodKey (func)].push_back (func);
2937+ }
29212938 }
29222939 }
29232940
@@ -3011,6 +3028,19 @@ class ObjCImplementationChecker {
30113028 }
30123029 };
30133030
3031+ // / Determine whether the set of matched requirements are ambiguous for the
3032+ // / given candidate.
3033+ bool areRequirementsAmbiguous (const BestMatchList &reqs, ValueDecl *cand) {
3034+ if (reqs.matches .size () != 2 )
3035+ return reqs.matches .size () > 2 ;
3036+
3037+ bool firstIsAsyncAlternative =
3038+ matchesAsyncAlternative (reqs.matches [0 ], cand);
3039+ bool secondIsAsyncAlternative =
3040+ matchesAsyncAlternative (reqs.matches [1 ], cand);
3041+ return firstIsAsyncAlternative == secondIsAsyncAlternative;
3042+ }
3043+
30143044 void matchRequirementsAtThreshold (MatchOutcome threshold) {
30153045 SmallString<32 > scratch;
30163046
@@ -3070,11 +3100,14 @@ class ObjCImplementationChecker {
30703100 // removing them.
30713101 requirementsToRemove.set_union (matchedRequirements.matches );
30723102
3073- if (matchedRequirements. matches . size () == 1 ) {
3103+ if (! areRequirementsAmbiguous (matchedRequirements, cand) ) {
30743104 // Note that this is BestMatchList::insert(), so it'll only keep the
30753105 // matches with the best outcomes.
3076- matchesByRequirement[matchedRequirements.matches .front ()]
3077- .insert (cand, matchedRequirements.currentOutcome );
3106+ for (auto req : matchedRequirements.matches ) {
3107+ matchesByRequirement[req]
3108+ .insert (cand, matchedRequirements.currentOutcome );
3109+ }
3110+
30783111 continue ;
30793112 }
30803113
@@ -3156,6 +3189,35 @@ class ObjCImplementationChecker {
31563189 unmatchedCandidates.erase (cand);
31573190 }
31583191
3192+ // / Whether the candidate matches the async alternative of the given
3193+ // / requirement.
3194+ bool matchesAsyncAlternative (ValueDecl *req, ValueDecl *cand) const {
3195+ auto reqFunc = dyn_cast<AbstractFunctionDecl>(req);
3196+ if (!reqFunc)
3197+ return false ;
3198+
3199+ auto candFunc = dyn_cast<AbstractFunctionDecl>(cand);
3200+ if (!candFunc)
3201+ return false ;
3202+
3203+ if (reqFunc->hasAsync () == candFunc->hasAsync ())
3204+ return false ;
3205+
3206+ auto otherReqFuncs =
3207+ objcMethodRequirements.find (getObjCMethodKey (reqFunc));
3208+ if (otherReqFuncs == objcMethodRequirements.end ())
3209+ return false ;
3210+
3211+ for (auto otherReqFunc : otherReqFuncs->second ) {
3212+ if (otherReqFunc->getName () == cand->getName () &&
3213+ otherReqFunc->hasAsync () == candFunc->hasAsync () &&
3214+ req->getObjCRuntimeName () == cand->getObjCRuntimeName ())
3215+ return true ;
3216+ }
3217+
3218+ return false ;
3219+ }
3220+
31593221 MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
31603222 ObjCSelector explicitObjCName) const {
31613223 bool hasObjCNameMatch =
@@ -3173,7 +3235,10 @@ class ObjCImplementationChecker {
31733235 && req->getObjCRuntimeName () != explicitObjCName)
31743236 return MatchOutcome::WrongExplicitObjCName;
31753237
3176- if (!hasSwiftNameMatch)
3238+ // If the ObjC selectors matched but the Swift names do not, and these are
3239+ // functions with mismatched 'async', check whether the "other" requirement
3240+ // (the completion-handler or async version)'s Swift name matches.
3241+ if (!hasSwiftNameMatch && !matchesAsyncAlternative (req, cand))
31773242 return MatchOutcome::WrongSwiftName;
31783243
31793244 if (!hasObjCNameMatch)
0 commit comments