@@ -3436,6 +3436,8 @@ class ObjCImplementationChecker {
3436
3436
WrongRequiredAttr,
3437
3437
WrongForeignErrorConvention,
3438
3438
3439
+ WrongSendability,
3440
+
3439
3441
Match,
3440
3442
MatchWithExplicitObjCName,
3441
3443
@@ -3621,70 +3623,99 @@ class ObjCImplementationChecker {
3621
3623
return lhs == rhs;
3622
3624
}
3623
3625
3624
- static bool matchParamTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3625
- TypeMatchOptions matchOpts = {};
3626
-
3626
+ static MatchOutcome matchParamTypes (Type reqTy, Type implTy,
3627
+ ValueDecl *implDecl,
3628
+ TypeMatchOptions matchOpts = {}) {
3627
3629
// Try a plain type match.
3628
3630
if (implTy->matchesParameter (reqTy, matchOpts))
3629
- return true ;
3631
+ return MatchOutcome::Match ;
3630
3632
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) ;
3633
+ // Try to drop `@Sendable` .
3634
+ {
3635
+ auto ignoreSendable =
3636
+ matchOpts | TypeMatchFlags::IgnoreFunctionSendability ;
3635
3637
3636
- return false ;
3638
+ if (implTy->matchesParameter (reqTy, ignoreSendable))
3639
+ return MatchOutcome::WrongSendability;
3640
+ }
3641
+
3642
+ if (matchOpts.contains (TypeMatchFlags::AllowNonOptionalForIUOParam)) {
3643
+ ASSERT (implDecl);
3644
+
3645
+ // If the implementation type is IUO, try unwrapping it.
3646
+ if (auto unwrappedImplTy = implTy->getOptionalObjectType ())
3647
+ return implDecl->isImplicitlyUnwrappedOptional () &&
3648
+ unwrappedImplTy->matchesParameter (reqTy, matchOpts)
3649
+ ? MatchOutcome::Match
3650
+ : MatchOutcome::WrongType;
3651
+ }
3652
+
3653
+ return MatchOutcome::WrongType;
3637
3654
}
3638
3655
3639
- static bool matchTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3656
+ static MatchOutcome matchTypes (Type reqTy, Type implTy, ValueDecl *implDecl) {
3640
3657
TypeMatchOptions matchOpts = {};
3641
3658
3642
3659
// Try a plain type match.
3643
3660
if (reqTy->matches (implTy, matchOpts))
3644
- return true ;
3661
+ return MatchOutcome::Match ;
3645
3662
3646
3663
// If the implementation type is optional, try unwrapping it.
3647
3664
if (auto unwrappedImplTy = implTy->getOptionalObjectType ())
3648
- return implDecl->isImplicitlyUnwrappedOptional ()
3649
- && reqTy->matches (unwrappedImplTy, matchOpts);
3665
+ return implDecl->isImplicitlyUnwrappedOptional () &&
3666
+ reqTy->matches (unwrappedImplTy, matchOpts)
3667
+ ? MatchOutcome::Match
3668
+ : MatchOutcome::WrongType;
3650
3669
3651
3670
// Apply these rules to the result type and parameters if it's a function
3652
3671
// 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)))
3672
+ if (auto funcReqTy = reqTy->getAs <AnyFunctionType>()) {
3673
+ if (auto funcImplTy = implTy->getAs <AnyFunctionType>()) {
3674
+ bool hasSendabilityMismatches = false ;
3675
+ bool isMatch = funcReqTy->matchesFunctionType (
3676
+ funcImplTy, matchOpts, [=, &hasSendabilityMismatches]() -> bool {
3677
+ auto reqParams = funcReqTy->getParams ();
3678
+ auto implParams = funcImplTy->getParams ();
3679
+ if (reqParams.size () != implParams.size ())
3674
3680
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
3681
3683
- return matchTypes (funcReqTy-> getResult (), funcImplTy-> getResult (),
3684
- implDecl);
3685
- } );
3682
+ ParameterList *implParamList = nullptr ;
3683
+ if ( auto afd = dyn_cast<AbstractFunctionDecl>( implDecl))
3684
+ implParamList = afd-> getParameters ( );
3686
3685
3687
- return false ;
3686
+ for (auto i : indices (reqParams)) {
3687
+ const auto &reqParam = reqParams[i];
3688
+ const auto &implParam = implParams[i];
3689
+
3690
+ TypeMatchOptions options = {};
3691
+ if (implParamList)
3692
+ options |= TypeMatchFlags::AllowNonOptionalForIUOParam;
3693
+
3694
+ auto outcome = matchParamTypes (
3695
+ reqParam.getOldType (), implParam.getOldType (),
3696
+ implParamList ? implParamList->get (i) : nullptr , options);
3697
+
3698
+ if (outcome == MatchOutcome::WrongSendability)
3699
+ hasSendabilityMismatches = true ;
3700
+
3701
+ if (outcome < MatchOutcome::WrongSendability)
3702
+ return false ;
3703
+ }
3704
+
3705
+ return matchTypes (funcReqTy->getResult (), funcImplTy->getResult (),
3706
+ implDecl) == MatchOutcome::Match;
3707
+ });
3708
+
3709
+ if (isMatch) {
3710
+ return hasSendabilityMismatches ? MatchOutcome::WrongSendability
3711
+ : MatchOutcome::Match;
3712
+ }
3713
+
3714
+ return MatchOutcome::WrongType;
3715
+ }
3716
+ }
3717
+
3718
+ return MatchOutcome::WrongType;
3688
3719
}
3689
3720
3690
3721
static Type getMemberType (ValueDecl *decl) {
@@ -3729,8 +3760,10 @@ class ObjCImplementationChecker {
3729
3760
if (cand->getKind () != req->getKind ())
3730
3761
return MatchOutcome::WrongDeclKind;
3731
3762
3732
- if (!matchTypes (getMemberType (req), getMemberType (cand), cand))
3733
- return MatchOutcome::WrongType;
3763
+ auto matchTypesOutcome =
3764
+ matchTypes (getMemberType (req), getMemberType (cand), cand);
3765
+ if (matchTypesOutcome < MatchOutcome::Match)
3766
+ return matchTypesOutcome;
3734
3767
3735
3768
if (auto reqVar = dyn_cast<AbstractStorageDecl>(req))
3736
3769
if (reqVar->isSettable (nullptr ) &&
@@ -3787,6 +3820,13 @@ class ObjCImplementationChecker {
3787
3820
diagnoseVTableUse (cand);
3788
3821
return ;
3789
3822
3823
+ case MatchOutcome::WrongSendability:
3824
+ diagnose (cand, diag::objc_implementation_sendability_mismatch, cand,
3825
+ getMemberType (cand), getMemberType (req))
3826
+ .limitBehaviorWithPreconcurrency (DiagnosticBehavior::Warning,
3827
+ /* preconcurrency*/ true );
3828
+ return ;
3829
+
3790
3830
case MatchOutcome::WrongImplicitObjCName:
3791
3831
case MatchOutcome::WrongExplicitObjCName: {
3792
3832
auto diag = diagnose (cand, diag::objc_implementation_wrong_objc_name,
0 commit comments