@@ -2885,15 +2885,6 @@ class ObjCImplementationChecker {
2885
2885
// / Candidates with their explicit ObjC names, if any.
2886
2886
llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16 > unmatchedCandidates;
2887
2887
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
-
2897
2888
public:
2898
2889
ObjCImplementationChecker (ExtensionDecl *ext)
2899
2890
: diags(ext->getASTContext ().Diags)
@@ -2915,8 +2906,30 @@ class ObjCImplementationChecker {
2915
2906
}
2916
2907
2917
2908
private:
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 ;
2920
2933
}
2921
2934
2922
2935
void addRequirements (IterableDeclContext *idc) {
@@ -2932,12 +2945,13 @@ class ObjCImplementationChecker {
2932
2945
if (member->getAttrs ().isUnavailable (member->getASTContext ()))
2933
2946
continue ;
2934
2947
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
+
2935
2953
auto inserted = unmatchedRequirements.insert (member);
2936
2954
assert (inserted && " objc interface member added twice?" );
2937
-
2938
- if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2939
- objcMethodRequirements[getObjCMethodKey (func)].push_back (func);
2940
- }
2941
2955
}
2942
2956
}
2943
2957
@@ -3034,19 +3048,6 @@ class ObjCImplementationChecker {
3034
3048
}
3035
3049
};
3036
3050
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
-
3050
3051
void matchRequirementsAtThreshold (MatchOutcome threshold) {
3051
3052
SmallString<32 > scratch;
3052
3053
@@ -3106,14 +3107,11 @@ class ObjCImplementationChecker {
3106
3107
// removing them.
3107
3108
requirementsToRemove.set_union (matchedRequirements.matches );
3108
3109
3109
- if (! areRequirementsAmbiguous ( matchedRequirements, cand) ) {
3110
+ if (matchedRequirements. matches . size () == 1 ) {
3110
3111
// Note that this is BestMatchList::insert(), so it'll only keep the
3111
3112
// 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 );
3117
3115
continue ;
3118
3116
}
3119
3117
@@ -3195,35 +3193,6 @@ class ObjCImplementationChecker {
3195
3193
unmatchedCandidates.erase (cand);
3196
3194
}
3197
3195
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
-
3227
3196
static bool areSwiftNamesEqual (DeclName lhs, DeclName rhs) {
3228
3197
// Conflate `foo()` and `foo`. This allows us to diagnose
3229
3198
// method-vs.-property mistakes more nicely.
@@ -3237,8 +3206,8 @@ class ObjCImplementationChecker {
3237
3206
return lhs == rhs;
3238
3207
}
3239
3208
3240
- MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
3241
- ObjCSelector explicitObjCName) const {
3209
+ MatchOutcome matchesImpl (ValueDecl *req, ValueDecl *cand,
3210
+ ObjCSelector explicitObjCName) const {
3242
3211
bool hasObjCNameMatch =
3243
3212
req->getObjCRuntimeName () == cand->getObjCRuntimeName ();
3244
3213
bool hasSwiftNameMatch = areSwiftNamesEqual (req->getName (), cand->getName ());
@@ -3254,10 +3223,7 @@ class ObjCImplementationChecker {
3254
3223
&& req->getObjCRuntimeName () != explicitObjCName)
3255
3224
return MatchOutcome::WrongExplicitObjCName;
3256
3225
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)
3261
3227
return MatchOutcome::WrongSwiftName;
3262
3228
3263
3229
if (!hasObjCNameMatch)
@@ -3287,6 +3253,17 @@ class ObjCImplementationChecker {
3287
3253
return MatchOutcome::Match;
3288
3254
}
3289
3255
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
+
3290
3267
void diagnoseOutcome (MatchOutcome outcome, ValueDecl *req, ValueDecl *cand,
3291
3268
ObjCSelector explicitObjCName) {
3292
3269
auto reqObjCName = *req->getObjCRuntimeName ();
0 commit comments