@@ -2892,15 +2892,6 @@ class ObjCImplementationChecker {
2892
2892
// / Candidates with their explicit ObjC names, if any.
2893
2893
llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16 > unmatchedCandidates;
2894
2894
2895
- // / Key that can be used to uniquely identify a particular Objective-C
2896
- // / method.
2897
- using ObjCMethodKey = std::pair<ObjCSelector, char >;
2898
-
2899
- // / Mapping from Objective-C methods to the set of requirements within this
2900
- // / protocol that have the same selector and instance/class designation.
2901
- llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4 >
2902
- objcMethodRequirements;
2903
-
2904
2895
public:
2905
2896
ObjCImplementationChecker (ExtensionDecl *ext)
2906
2897
: diags(ext->getASTContext ().Diags)
@@ -2922,8 +2913,30 @@ class ObjCImplementationChecker {
2922
2913
}
2923
2914
2924
2915
private:
2925
- auto getObjCMethodKey (AbstractFunctionDecl *func) const -> ObjCMethodKey {
2926
- return ObjCMethodKey (func->getObjCSelector (), func->isInstanceMember ());
2916
+ static bool hasAsync (ValueDecl *member) {
2917
+ if (!member)
2918
+ return false ;
2919
+
2920
+ if (auto func = dyn_cast<AbstractFunctionDecl>(member))
2921
+ return func->hasAsync ();
2922
+
2923
+ if (auto storage = dyn_cast<AbstractStorageDecl>(member))
2924
+ return hasAsync (storage->getEffectfulGetAccessor ());
2925
+
2926
+ return false ;
2927
+ }
2928
+
2929
+ static ValueDecl *getAsyncAlternative (ValueDecl *req) {
2930
+ if (auto func = dyn_cast<AbstractFunctionDecl>(req)) {
2931
+ auto asyncFunc = func->getAsyncAlternative ();
2932
+
2933
+ if (auto asyncAccessor = dyn_cast<AccessorDecl>(asyncFunc))
2934
+ return asyncAccessor->getStorage ();
2935
+
2936
+ return asyncFunc;
2937
+ }
2938
+
2939
+ return nullptr ;
2927
2940
}
2928
2941
2929
2942
void addRequirements (IterableDeclContext *idc) {
@@ -2939,12 +2952,13 @@ class ObjCImplementationChecker {
2939
2952
if (member->getAttrs ().isUnavailable (member->getASTContext ()))
2940
2953
continue ;
2941
2954
2955
+ // Skip async versions of members. We'll match against the completion
2956
+ // handler versions, hopping over to `getAsyncAlternative()` if needed.
2957
+ if (hasAsync (member))
2958
+ continue ;
2959
+
2942
2960
auto inserted = unmatchedRequirements.insert (member);
2943
2961
assert (inserted && " objc interface member added twice?" );
2944
-
2945
- if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2946
- objcMethodRequirements[getObjCMethodKey (func)].push_back (func);
2947
- }
2948
2962
}
2949
2963
}
2950
2964
@@ -3041,19 +3055,6 @@ class ObjCImplementationChecker {
3041
3055
}
3042
3056
};
3043
3057
3044
- // / Determine whether the set of matched requirements are ambiguous for the
3045
- // / given candidate.
3046
- bool areRequirementsAmbiguous (const BestMatchList &reqs, ValueDecl *cand) {
3047
- if (reqs.matches .size () != 2 )
3048
- return reqs.matches .size () > 2 ;
3049
-
3050
- bool firstIsAsyncAlternative =
3051
- matchesAsyncAlternative (reqs.matches [0 ], cand);
3052
- bool secondIsAsyncAlternative =
3053
- matchesAsyncAlternative (reqs.matches [1 ], cand);
3054
- return firstIsAsyncAlternative == secondIsAsyncAlternative;
3055
- }
3056
-
3057
3058
void matchRequirementsAtThreshold (MatchOutcome threshold) {
3058
3059
SmallString<32 > scratch;
3059
3060
@@ -3113,14 +3114,11 @@ class ObjCImplementationChecker {
3113
3114
// removing them.
3114
3115
requirementsToRemove.set_union (matchedRequirements.matches );
3115
3116
3116
- if (! areRequirementsAmbiguous ( matchedRequirements, cand) ) {
3117
+ if (matchedRequirements. matches . size () == 1 ) {
3117
3118
// Note that this is BestMatchList::insert(), so it'll only keep the
3118
3119
// matches with the best outcomes.
3119
- for (auto req : matchedRequirements.matches ) {
3120
- matchesByRequirement[req]
3121
- .insert (cand, matchedRequirements.currentOutcome );
3122
- }
3123
-
3120
+ matchesByRequirement[matchedRequirements.matches .front ()]
3121
+ .insert (cand, matchedRequirements.currentOutcome );
3124
3122
continue ;
3125
3123
}
3126
3124
@@ -3202,35 +3200,6 @@ class ObjCImplementationChecker {
3202
3200
unmatchedCandidates.erase (cand);
3203
3201
}
3204
3202
3205
- // / Whether the candidate matches the async alternative of the given
3206
- // / requirement.
3207
- bool matchesAsyncAlternative (ValueDecl *req, ValueDecl *cand) const {
3208
- auto reqFunc = dyn_cast<AbstractFunctionDecl>(req);
3209
- if (!reqFunc)
3210
- return false ;
3211
-
3212
- auto candFunc = dyn_cast<AbstractFunctionDecl>(cand);
3213
- if (!candFunc)
3214
- return false ;
3215
-
3216
- if (reqFunc->hasAsync () == candFunc->hasAsync ())
3217
- return false ;
3218
-
3219
- auto otherReqFuncs =
3220
- objcMethodRequirements.find (getObjCMethodKey (reqFunc));
3221
- if (otherReqFuncs == objcMethodRequirements.end ())
3222
- return false ;
3223
-
3224
- for (auto otherReqFunc : otherReqFuncs->second ) {
3225
- if (otherReqFunc->getName () == cand->getName () &&
3226
- otherReqFunc->hasAsync () == candFunc->hasAsync () &&
3227
- req->getObjCRuntimeName () == cand->getObjCRuntimeName ())
3228
- return true ;
3229
- }
3230
-
3231
- return false ;
3232
- }
3233
-
3234
3203
static bool areSwiftNamesEqual (DeclName lhs, DeclName rhs) {
3235
3204
// Conflate `foo()` and `foo`. This allows us to diagnose
3236
3205
// method-vs.-property mistakes more nicely.
@@ -3244,8 +3213,8 @@ class ObjCImplementationChecker {
3244
3213
return lhs == rhs;
3245
3214
}
3246
3215
3247
- MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
3248
- ObjCSelector explicitObjCName) const {
3216
+ MatchOutcome matchesImpl (ValueDecl *req, ValueDecl *cand,
3217
+ ObjCSelector explicitObjCName) const {
3249
3218
bool hasObjCNameMatch =
3250
3219
req->getObjCRuntimeName () == cand->getObjCRuntimeName ();
3251
3220
bool hasSwiftNameMatch = areSwiftNamesEqual (req->getName (), cand->getName ());
@@ -3261,10 +3230,7 @@ class ObjCImplementationChecker {
3261
3230
&& req->getObjCRuntimeName () != explicitObjCName)
3262
3231
return MatchOutcome::WrongExplicitObjCName;
3263
3232
3264
- // If the ObjC selectors matched but the Swift names do not, and these are
3265
- // functions with mismatched 'async', check whether the "other" requirement
3266
- // (the completion-handler or async version)'s Swift name matches.
3267
- if (!hasSwiftNameMatch && !matchesAsyncAlternative (req, cand))
3233
+ if (!hasSwiftNameMatch)
3268
3234
return MatchOutcome::WrongSwiftName;
3269
3235
3270
3236
if (!hasObjCNameMatch)
@@ -3294,6 +3260,17 @@ class ObjCImplementationChecker {
3294
3260
return MatchOutcome::Match;
3295
3261
}
3296
3262
3263
+ MatchOutcome matches (ValueDecl *req, ValueDecl *cand,
3264
+ ObjCSelector explicitObjCName) const {
3265
+ // If the candidate we're considering is async, see if the requirement has
3266
+ // an async alternate and try to match against that instead.
3267
+ if (hasAsync (cand))
3268
+ if (auto asyncAltReq = getAsyncAlternative (req))
3269
+ return matchesImpl (asyncAltReq, cand, explicitObjCName);
3270
+
3271
+ return matchesImpl (req, cand, explicitObjCName);
3272
+ }
3273
+
3297
3274
void diagnoseOutcome (MatchOutcome outcome, ValueDecl *req, ValueDecl *cand,
3298
3275
ObjCSelector explicitObjCName) {
3299
3276
auto reqObjCName = *req->getObjCRuntimeName ();
0 commit comments