@@ -618,10 +618,25 @@ static DiagnosticBehavior defaultSendableDiagnosticBehavior(
618
618
return DiagnosticBehavior::Unspecified;
619
619
}
620
620
621
+ bool SendableCheckContext::isExplicitSendableConformance () const {
622
+ if (!conformanceCheck)
623
+ return false ;
624
+
625
+ switch (*conformanceCheck) {
626
+ case SendableCheck::Explicit:
627
+ return true ;
628
+
629
+ case SendableCheck::ImpliedByStandardProtocol:
630
+ case SendableCheck::Implicit:
631
+ return false ;
632
+ }
633
+ }
634
+
621
635
DiagnosticBehavior SendableCheckContext::defaultDiagnosticBehavior () const {
622
636
// If we're not supposed to diagnose existing data races from this context,
623
637
// ignore the diagnostic entirely.
624
- if (!shouldDiagnoseExistingDataRaces (fromDC))
638
+ if (!isExplicitSendableConformance () &&
639
+ !shouldDiagnoseExistingDataRaces (fromDC))
625
640
return DiagnosticBehavior::Ignore;
626
641
627
642
return defaultSendableDiagnosticBehavior (fromDC->getASTContext ().LangOpts );
@@ -633,21 +648,8 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
633
648
NominalTypeDecl *nominal) const {
634
649
// Determine whether the type was explicitly non-Sendable.
635
650
auto nominalModule = nominal->getParentModule ();
636
- bool isExplicitlyNonSendable = nominalModule->isConcurrencyChecked ();
637
-
638
- // If we are performing an explicit conformance check, always consider this
639
- // to be an explicitly non-Sendable type.
640
- if (conformanceCheck) {
641
- switch (*conformanceCheck) {
642
- case SendableCheck::Explicit:
643
- isExplicitlyNonSendable = true ;
644
- break ;
645
-
646
- case SendableCheck::ImpliedByStandardProtocol:
647
- case SendableCheck::Implicit:
648
- break ;
649
- }
650
- }
651
+ bool isExplicitlyNonSendable = nominalModule->isConcurrencyChecked () ||
652
+ isExplicitSendableConformance ();
651
653
652
654
// Determine whether this nominal type is visible via a @_predatesConcurrency
653
655
// import.
@@ -679,8 +681,7 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
679
681
// / a Sendable type is required.
680
682
static bool diagnoseSingleNonSendableType (
681
683
Type type, SendableCheckContext fromContext, SourceLoc loc,
682
- llvm::function_ref<
683
- std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
684
+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
684
685
685
686
auto behavior = DiagnosticBehavior::Unspecified;
686
687
@@ -693,11 +694,9 @@ static bool diagnoseSingleNonSendableType(
693
694
behavior = fromContext.defaultDiagnosticBehavior ();
694
695
}
695
696
696
- DiagnosticBehavior actualBehavior;
697
- bool wasError;
698
- std::tie (actualBehavior, wasError) = diagnose (type, behavior);
697
+ bool wasSuppressed = diagnose (type, behavior);
699
698
700
- if (actualBehavior == DiagnosticBehavior::Ignore) {
699
+ if (behavior == DiagnosticBehavior::Ignore || wasSuppressed ) {
701
700
// Don't emit any other diagnostics.
702
701
} else if (type->is <FunctionType>()) {
703
702
ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
@@ -713,13 +712,12 @@ static bool diagnoseSingleNonSendableType(
713
712
nominal->getName ());
714
713
}
715
714
716
- return wasError ;
715
+ return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed ;
717
716
}
718
717
719
718
bool swift::diagnoseNonSendableTypes (
720
719
Type type, SendableCheckContext fromContext, SourceLoc loc,
721
- llvm::function_ref<
722
- std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
720
+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
723
721
auto module = fromContext.fromDC ->getParentModule ();
724
722
725
723
// If the Sendable protocol is missing, do nothing.
@@ -3640,44 +3638,6 @@ bool swift::contextUsesConcurrencyFeatures(const DeclContext *dc) {
3640
3638
return false ;
3641
3639
}
3642
3640
3643
- // / Limit the diagnostic behavior used when performing checks for the Sendable
3644
- // / instance storage of Sendable types.
3645
- // /
3646
- // / \returns a pair containing the diagnostic behavior that should be used
3647
- // / for this diagnostic, as well as a Boolean value indicating whether to
3648
- // / treat this as an error.
3649
- static std::pair<DiagnosticBehavior, bool > limitSendableInstanceBehavior (
3650
- const LangOptions &langOpts, SendableCheck check,
3651
- DiagnosticBehavior suggestedBehavior) {
3652
- // Is an error suggested?
3653
- bool suggestedError = suggestedBehavior == DiagnosticBehavior::Unspecified ||
3654
- suggestedBehavior == DiagnosticBehavior::Error;
3655
- switch (check) {
3656
- case SendableCheck::Implicit:
3657
- // For implicit checks, we always ignore the diagnostic and fail.
3658
- return std::make_pair (DiagnosticBehavior::Ignore, true );
3659
-
3660
- case SendableCheck::Explicit:
3661
- // Bump warnings up to errors due to explicit Sendable conformance.
3662
- if (suggestedBehavior == DiagnosticBehavior::Warning)
3663
- return std::make_pair (DiagnosticBehavior::Unspecified, true );
3664
-
3665
- return std::make_pair (suggestedBehavior, suggestedError);
3666
-
3667
- case SendableCheck::ImpliedByStandardProtocol:
3668
- // If we aren't in Swift 6, downgrade diagnostics.
3669
- if (!langOpts.isSwiftVersionAtLeast (6 )) {
3670
- if (langOpts.WarnConcurrency &&
3671
- suggestedBehavior != DiagnosticBehavior::Ignore)
3672
- return std::make_pair (DiagnosticBehavior::Warning, false );
3673
-
3674
- return std::make_pair (DiagnosticBehavior::Ignore, false );
3675
- }
3676
-
3677
- return std::make_pair (suggestedBehavior, suggestedError);
3678
- }
3679
- }
3680
-
3681
3641
namespace {
3682
3642
// / Visit the instance storage of the given nominal type as seen through
3683
3643
// / the given declaration context.
@@ -3749,38 +3709,36 @@ static bool checkSendableInstanceStorage(
3749
3709
if (check == SendableCheck::Implicit)
3750
3710
return true ;
3751
3711
3752
- auto action = limitSendableInstanceBehavior (
3753
- langOpts, check, DiagnosticBehavior::Unspecified);
3754
-
3755
- property->diagnose (diag::concurrent_value_class_mutable_property,
3756
- property->getName (), nominal->getDescriptiveKind (),
3757
- nominal->getName ())
3758
- .limitBehavior (action.first );
3759
- invalid = invalid || action.second ;
3712
+ auto behavior = SendableCheckContext (
3713
+ dc, check).defaultDiagnosticBehavior ();
3714
+ if (behavior != DiagnosticBehavior::Ignore) {
3715
+ property->diagnose (diag::concurrent_value_class_mutable_property,
3716
+ property->getName (), nominal->getDescriptiveKind (),
3717
+ nominal->getName ())
3718
+ .limitBehavior (behavior);
3719
+ }
3720
+ invalid = invalid || (behavior == DiagnosticBehavior::Unspecified);
3760
3721
return true ;
3761
3722
}
3762
3723
3763
3724
// Check that the property type is Sendable.
3764
- bool diagnosedProperty = diagnoseNonSendableTypes (
3725
+ diagnoseNonSendableTypes (
3765
3726
propertyType, SendableCheckContext (dc, check), property->getLoc (),
3766
- [&](Type type, DiagnosticBehavior suggestedBehavior ) {
3767
- auto action = limitSendableInstanceBehavior (
3768
- langOpts, check, suggestedBehavior) ;
3769
- if (check == SendableCheck::Implicit)
3770
- return action;
3727
+ [&](Type type, DiagnosticBehavior behavior ) {
3728
+ if (check == SendableCheck::Implicit) {
3729
+ invalid = true ;
3730
+ return true ;
3731
+ }
3771
3732
3772
3733
property->diagnose (diag::non_concurrent_type_member,
3773
- false , property->getName (),
3734
+ propertyType, false , property->getName (),
3774
3735
nominal->getDescriptiveKind (),
3775
- nominal->getName (),
3776
- propertyType)
3777
- .limitBehavior (action.first );
3778
- return action;
3736
+ nominal->getName ())
3737
+ .limitBehavior (behavior);
3738
+ return false ;
3779
3739
});
3780
3740
3781
- if (diagnosedProperty) {
3782
- invalid = true ;
3783
-
3741
+ if (invalid) {
3784
3742
// For implicit checks, bail out early if anything failed.
3785
3743
if (check == SendableCheck::Implicit)
3786
3744
return true ;
@@ -3791,26 +3749,23 @@ static bool checkSendableInstanceStorage(
3791
3749
3792
3750
// / Handle an enum associated value.
3793
3751
bool operator ()(EnumElementDecl *element, Type elementType) {
3794
- bool diagnosedElement = diagnoseNonSendableTypes (
3752
+ diagnoseNonSendableTypes (
3795
3753
elementType, SendableCheckContext (dc, check), element->getLoc (),
3796
- [&](Type type, DiagnosticBehavior suggestedBehavior ) {
3797
- auto action = limitSendableInstanceBehavior (
3798
- langOpts, check, suggestedBehavior) ;
3799
- if (check == SendableCheck::Implicit)
3800
- return action;
3754
+ [&](Type type, DiagnosticBehavior behavior ) {
3755
+ if (check == SendableCheck::Implicit) {
3756
+ invalid = true ;
3757
+ return true ;
3758
+ }
3801
3759
3802
- element->diagnose (diag::non_concurrent_type_member,
3760
+ element->diagnose (diag::non_concurrent_type_member, type,
3803
3761
true , element->getName (),
3804
3762
nominal->getDescriptiveKind (),
3805
- nominal->getName (),
3806
- type)
3807
- .limitBehavior (action.first );
3808
- return action;
3763
+ nominal->getName ())
3764
+ .limitBehavior (behavior);
3765
+ return false ;
3809
3766
});
3810
3767
3811
- if (diagnosedElement) {
3812
- invalid = true ;
3813
-
3768
+ if (invalid) {
3814
3769
// For implicit checks, bail out early if anything failed.
3815
3770
if (check == SendableCheck::Implicit)
3816
3771
return true ;
@@ -3859,46 +3814,43 @@ bool swift::checkSendableConformance(
3859
3814
3860
3815
// Sendable can only be used in the same source file.
3861
3816
auto conformanceDecl = conformanceDC->getAsDecl ();
3862
- const LangOptions &langOpts = conformanceDC->getASTContext ().LangOpts ;
3863
- DiagnosticBehavior behavior;
3864
- bool diagnosticCausesFailure;
3865
- std::tie (behavior, diagnosticCausesFailure) = limitSendableInstanceBehavior (
3866
- langOpts, check, DiagnosticBehavior::Unspecified);
3867
- if (!conformanceDC->getParentSourceFile () ||
3817
+ auto behavior = SendableCheckContext (conformanceDC)
3818
+ .defaultDiagnosticBehavior ();
3819
+ if (conformanceDC->getParentSourceFile () &&
3820
+ nominal->getParentSourceFile () &&
3868
3821
conformanceDC->getParentSourceFile () != nominal->getParentSourceFile ()) {
3869
3822
conformanceDecl->diagnose (diag::concurrent_value_outside_source_file,
3870
3823
nominal->getDescriptiveKind (),
3871
3824
nominal->getName ())
3872
- .limitBehavior (behavior);
3825
+ .limitBehavior (behavior);
3873
3826
3874
- if (diagnosticCausesFailure )
3827
+ if (behavior == DiagnosticBehavior::Unspecified )
3875
3828
return true ;
3876
3829
}
3877
3830
3878
- if (classDecl) {
3831
+ if (classDecl && classDecl->getParentSourceFile ()) {
3832
+ bool isInherited = isa<InheritedProtocolConformance>(conformance);
3833
+
3879
3834
// An non-final class cannot conform to `Sendable`.
3880
3835
if (!classDecl->isSemanticallyFinal ()) {
3881
3836
classDecl->diagnose (diag::concurrent_value_nonfinal_class,
3882
3837
classDecl->getName ())
3883
- .limitBehavior (behavior);
3838
+ .limitBehavior (behavior);
3884
3839
3885
- if (diagnosticCausesFailure )
3840
+ if (behavior == DiagnosticBehavior::Unspecified )
3886
3841
return true ;
3887
3842
}
3888
3843
3889
- // A 'Sendable' class cannot inherit from another class, although
3890
- // we allow `NSObject` for Objective-C interoperability.
3891
- if (!isa<InheritedProtocolConformance>(conformance)) {
3844
+ if (!isInherited) {
3845
+ // A 'Sendable' class cannot inherit from another class, although
3846
+ // we allow `NSObject` for Objective-C interoperability.
3892
3847
if (auto superclassDecl = classDecl->getSuperclassDecl ()) {
3893
3848
if (!superclassDecl->isNSObject ()) {
3894
3849
classDecl->diagnose (
3895
3850
diag::concurrent_value_inherit,
3896
3851
nominal->getASTContext ().LangOpts .EnableObjCInterop ,
3897
- classDecl->getName ())
3898
- .limitBehavior (behavior);
3899
-
3900
- if (diagnosticCausesFailure)
3901
- return true ;
3852
+ classDecl->getName ());
3853
+ return true ;
3902
3854
}
3903
3855
}
3904
3856
}
0 commit comments