@@ -3435,6 +3435,7 @@ class ObjCImplementationChecker {
3435
3435
WrongWritability,
3436
3436
WrongRequiredAttr,
3437
3437
WrongForeignErrorConvention,
3438
+ WrongSendability,
3438
3439
3439
3440
Match,
3440
3441
MatchWithExplicitObjCName,
@@ -3621,70 +3622,93 @@ class ObjCImplementationChecker {
3621
3622
return lhs == rhs;
3622
3623
}
3623
3624
3624
- static bool matchParamTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3625
+ static MatchOutcome matchParamTypes (Type reqTy, Type implTy,
3626
+ ValueDecl *implDecl) {
3625
3627
TypeMatchOptions matchOpts = {};
3626
-
3627
3628
// Try a plain type match.
3628
3629
if (implTy->matchesParameter (reqTy, matchOpts))
3629
- return true ;
3630
+ return MatchOutcome::Match ;
3630
3631
3631
- // If the implementation type is IUO, try unwrapping it .
3632
- if ( auto unwrappedImplTy = implTy-> getOptionalObjectType ())
3633
- return implDecl-> isImplicitlyUnwrappedOptional ()
3634
- && unwrappedImplTy-> matchesParameter (reqTy, matchOpts) ;
3632
+ // Try to drop `@Sendable` .
3633
+ {
3634
+ auto ignoreSendable =
3635
+ matchOpts | TypeMatchFlags::IgnoreFunctionSendability ;
3635
3636
3636
- return false ;
3637
+ if (implTy->matchesParameter (reqTy, ignoreSendable))
3638
+ return MatchOutcome::WrongSendability;
3639
+ }
3640
+
3641
+ if (implDecl) {
3642
+ // If the implementation type is IUO, try unwrapping it.
3643
+ if (auto unwrappedImplTy = implTy->getOptionalObjectType ())
3644
+ return implDecl->isImplicitlyUnwrappedOptional () &&
3645
+ unwrappedImplTy->matchesParameter (reqTy, matchOpts)
3646
+ ? MatchOutcome::Match
3647
+ : MatchOutcome::WrongType;
3648
+ }
3649
+
3650
+ return MatchOutcome::WrongType;
3637
3651
}
3638
3652
3639
- static bool matchTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3653
+ static MatchOutcome matchTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3640
3654
TypeMatchOptions matchOpts = {};
3641
3655
3642
3656
// Try a plain type match.
3643
3657
if (reqTy->matches (implTy, matchOpts))
3644
- return true ;
3658
+ return MatchOutcome::Match ;
3645
3659
3646
3660
// If the implementation type is optional, try unwrapping it.
3647
3661
if (auto unwrappedImplTy = implTy->getOptionalObjectType ())
3648
- return implDecl->isImplicitlyUnwrappedOptional ()
3649
- && reqTy->matches (unwrappedImplTy, matchOpts);
3662
+ return implDecl->isImplicitlyUnwrappedOptional () &&
3663
+ reqTy->matches (unwrappedImplTy, matchOpts)
3664
+ ? MatchOutcome::Match
3665
+ : MatchOutcome::WrongType;
3650
3666
3651
3667
// Apply these rules to the result type and parameters if it's a function
3652
3668
// type.
3653
- if (auto funcReqTy = reqTy->getAs <AnyFunctionType>())
3654
- if (auto funcImplTy = implTy->getAs <AnyFunctionType>())
3655
- return funcReqTy->matchesFunctionType (funcImplTy, matchOpts,
3656
- [=]() -> bool {
3657
- auto reqParams = funcReqTy->getParams ();
3658
- auto implParams = funcImplTy->getParams ();
3659
- if (reqParams.size () != implParams.size ())
3660
- return false ;
3661
-
3662
- ParameterList *implParamList = nullptr ;
3663
- if (auto afd = dyn_cast<AbstractFunctionDecl>(implDecl))
3664
- implParamList = afd->getParameters ();
3665
-
3666
- for (auto i : indices (reqParams)) {
3667
- const auto &reqParam = reqParams[i];
3668
- const auto &implParam = implParams[i];
3669
- if (implParamList) {
3670
- // Some of the parameters may be IUOs; apply special logic.
3671
- if (!matchParamTypes (reqParam.getOldType (),
3672
- implParam.getOldType (),
3673
- implParamList->get (i)))
3669
+ if (auto funcReqTy = reqTy->getAs <AnyFunctionType>()) {
3670
+ if (auto funcImplTy = implTy->getAs <AnyFunctionType>()) {
3671
+ bool hasSendabilityMismatches = false ;
3672
+ bool isMatch = funcReqTy->matchesFunctionType (
3673
+ funcImplTy, matchOpts, [=, &hasSendabilityMismatches]() -> bool {
3674
+ auto reqParams = funcReqTy->getParams ();
3675
+ auto implParams = funcImplTy->getParams ();
3676
+ if (reqParams.size () != implParams.size ())
3674
3677
return false ;
3675
- } else {
3676
- // IUOs not allowed here; apply ordinary logic.
3677
- if (!reqParam.getOldType ()->matchesParameter (
3678
- implParam.getOldType (), matchOpts))
3679
- return false ;
3680
- }
3681
- }
3682
3678
3683
- return matchTypes (funcReqTy-> getResult (), funcImplTy-> getResult (),
3684
- implDecl);
3685
- } );
3679
+ ParameterList *implParamList = nullptr ;
3680
+ if ( auto afd = dyn_cast<AbstractFunctionDecl>( implDecl))
3681
+ implParamList = afd-> getParameters ( );
3686
3682
3687
- return false ;
3683
+ for (auto i : indices (reqParams)) {
3684
+ const auto &reqParam = reqParams[i];
3685
+ const auto &implParam = implParams[i];
3686
+
3687
+ auto outcome = matchParamTypes (
3688
+ reqParam.getOldType (), implParam.getOldType (),
3689
+ implParamList ? implParamList->get (i) : nullptr );
3690
+
3691
+ if (outcome == MatchOutcome::WrongSendability)
3692
+ hasSendabilityMismatches = true ;
3693
+
3694
+ if (outcome < MatchOutcome::WrongSendability)
3695
+ return false ;
3696
+ }
3697
+
3698
+ return matchTypes (funcReqTy->getResult (), funcImplTy->getResult (),
3699
+ implDecl) == MatchOutcome::Match;
3700
+ });
3701
+
3702
+ if (isMatch) {
3703
+ return hasSendabilityMismatches ? MatchOutcome::WrongSendability
3704
+ : MatchOutcome::Match;
3705
+ }
3706
+
3707
+ return MatchOutcome::WrongType;
3708
+ }
3709
+ }
3710
+
3711
+ return MatchOutcome::WrongType;
3688
3712
}
3689
3713
3690
3714
static Type getMemberType (ValueDecl *decl) {
@@ -3729,7 +3753,9 @@ class ObjCImplementationChecker {
3729
3753
if (cand->getKind () != req->getKind ())
3730
3754
return MatchOutcome::WrongDeclKind;
3731
3755
3732
- if (!matchTypes (getMemberType (req), getMemberType (cand), cand))
3756
+ auto matchTypesOutcome =
3757
+ matchTypes (getMemberType (req), getMemberType (cand), cand);
3758
+ if (matchTypesOutcome == MatchOutcome::WrongType)
3733
3759
return MatchOutcome::WrongType;
3734
3760
3735
3761
if (auto reqVar = dyn_cast<AbstractStorageDecl>(req))
@@ -3750,6 +3776,15 @@ class ObjCImplementationChecker {
3750
3776
if (explicitObjCName)
3751
3777
return MatchOutcome::MatchWithExplicitObjCName;
3752
3778
3779
+ // Sendable mismatches are downgraded to warnings because ObjC
3780
+ // declarations are `@preconcurrency`, we need to make sure
3781
+ // that there are no other problems before returning `WrongSendability`.
3782
+ if (matchTypesOutcome == MatchOutcome::WrongSendability)
3783
+ return MatchOutcome::WrongSendability;
3784
+
3785
+ ASSERT (matchTypesOutcome == MatchOutcome::Match &&
3786
+ " unexpected matchTypes() return" );
3787
+
3753
3788
return MatchOutcome::Match;
3754
3789
}
3755
3790
@@ -3787,6 +3822,13 @@ class ObjCImplementationChecker {
3787
3822
diagnoseVTableUse (cand);
3788
3823
return ;
3789
3824
3825
+ case MatchOutcome::WrongSendability:
3826
+ diagnose (cand, diag::objc_implementation_sendability_mismatch, cand,
3827
+ getMemberType (cand), getMemberType (req))
3828
+ .limitBehaviorWithPreconcurrency (DiagnosticBehavior::Warning,
3829
+ /* preconcurrency*/ true );
3830
+ return ;
3831
+
3790
3832
case MatchOutcome::WrongImplicitObjCName:
3791
3833
case MatchOutcome::WrongExplicitObjCName: {
3792
3834
auto diag = diagnose (cand, diag::objc_implementation_wrong_objc_name,
0 commit comments