@@ -757,82 +757,107 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
757
757
return defaultBehavior;
758
758
}
759
759
760
- // / Produce a diagnostic for a single instance of a non-Sendable type where
761
- // / a Sendable type is required.
762
- static bool diagnoseSingleNonSendableType (
763
- Type type, SendableCheckContext fromContext, SourceLoc loc,
764
- llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
765
-
760
+ bool swift::diagnoseSendabilityErrorBasedOn (
761
+ NominalTypeDecl *nominal, SendableCheckContext fromContext,
762
+ llvm::function_ref<bool (DiagnosticBehavior)> diagnose) {
766
763
auto behavior = DiagnosticBehavior::Unspecified;
767
764
768
- auto module = fromContext.fromDC ->getParentModule ();
769
- ASTContext &ctx = module ->getASTContext ();
770
- auto nominal = type->getAnyNominal ();
771
765
if (nominal) {
772
766
behavior = fromContext.diagnosticBehavior (nominal);
773
767
} else {
774
768
behavior = fromContext.defaultDiagnosticBehavior ();
775
769
}
776
770
777
- bool wasSuppressed = diagnose (type, behavior);
778
-
779
- if (behavior == DiagnosticBehavior::Ignore || wasSuppressed) {
780
- // Don't emit any other diagnostics.
781
- } else if (type->is <FunctionType>()) {
782
- ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
783
- } else if (nominal && nominal->getParentModule () == module ) {
784
- // If the nominal type is in the current module, suggest adding
785
- // `Sendable` if it might make sense. Otherwise, just complain.
786
- if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
787
- auto note = nominal->diagnose (
788
- diag::add_nominal_sendable_conformance,
789
- nominal->getDescriptiveKind (), nominal->getName ());
790
- addSendableFixIt (nominal, note, /* unchecked=*/ false );
791
- } else {
792
- nominal->diagnose (
793
- diag::non_sendable_nominal, nominal->getDescriptiveKind (),
794
- nominal->getName ());
771
+ bool wasSuppressed = diagnose (behavior);
772
+
773
+ bool emittedDiagnostics =
774
+ behavior != DiagnosticBehavior::Ignore && !wasSuppressed;
775
+
776
+ // When the type is explicitly Sendable *or* explicitly non-Sendable, we
777
+ // assume it has been audited and `@preconcurrency` is not recommended even
778
+ // though it would actually affect the diagnostic.
779
+ bool nominalIsImportedAndHasImplicitSendability =
780
+ nominal &&
781
+ nominal->getParentModule () != fromContext.fromDC ->getParentModule () &&
782
+ !hasExplicitSendableConformance (nominal);
783
+
784
+ if (emittedDiagnostics && nominalIsImportedAndHasImplicitSendability) {
785
+ // This type was imported from another module; try to find the
786
+ // corresponding import.
787
+ Optional<AttributedImport<swift::ImportedModule>> import ;
788
+ SourceFile *sourceFile = fromContext.fromDC ->getParentSourceFile ();
789
+ if (sourceFile) {
790
+ import = findImportFor (nominal, fromContext.fromDC );
795
791
}
796
- } else if (nominal) {
797
- // Note which nominal type does not conform to `Sendable`.
798
- nominal->diagnose (
799
- diag::non_sendable_nominal, nominal->getDescriptiveKind (),
800
- nominal->getName ());
801
792
802
- // When the type is explicitly Sendable *or* explicitly non-Sendable, we
803
- // assume it has been audited and `@preconcurrency` is not recommended even
804
- // though it would actually affect the diagnostic.
805
- if (!hasExplicitSendableConformance (nominal)) {
806
- // This type was imported from another module; try to find the
807
- // corresponding import.
808
- Optional<AttributedImport<swift::ImportedModule>> import ;
809
- SourceFile *sourceFile = fromContext.fromDC ->getParentSourceFile ();
810
- if (sourceFile) {
811
- import = findImportFor (nominal, fromContext.fromDC );
812
- }
793
+ // If we found the import that makes this nominal type visible, remark
794
+ // that it can be @preconcurrency import.
795
+ // Only emit this remark once per source file, because it can happen a
796
+ // lot.
797
+ if (import && !import ->options .contains (ImportFlags::Preconcurrency) &&
798
+ import ->importLoc .isValid () && sourceFile &&
799
+ !sourceFile->hasImportUsedPreconcurrency (*import )) {
800
+ SourceLoc importLoc = import ->importLoc ;
801
+ ASTContext &ctx = nominal->getASTContext ();
813
802
814
- // If we found the import that makes this nominal type visible, remark
815
- // that it can be @preconcurrency import.
816
- // Only emit this remark once per source file, because it can happen a
817
- // lot.
818
- if (import && !import ->options .contains (ImportFlags::Preconcurrency) &&
819
- import ->importLoc .isValid () && sourceFile &&
820
- !sourceFile->hasImportUsedPreconcurrency (*import )) {
821
- SourceLoc importLoc = import ->importLoc ;
822
- ctx.Diags .diagnose (
823
- importLoc, diag::add_predates_concurrency_import,
824
- ctx.LangOpts .isSwiftVersionAtLeast (6 ),
825
- nominal->getParentModule ()->getName ())
826
- .fixItInsert (importLoc, " @preconcurrency " );
803
+ ctx.Diags .diagnose (
804
+ importLoc, diag::add_predates_concurrency_import,
805
+ ctx.LangOpts .isSwiftVersionAtLeast (6 ),
806
+ nominal->getParentModule ()->getName ())
807
+ .fixItInsert (importLoc, " @preconcurrency " );
827
808
828
- sourceFile->setImportUsedPreconcurrency (*import );
829
- }
809
+ sourceFile->setImportUsedPreconcurrency (*import );
830
810
}
831
811
}
832
812
833
813
return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed;
834
814
}
835
815
816
+ // / Produce a diagnostic for a single instance of a non-Sendable type where
817
+ // / a Sendable type is required.
818
+ static bool diagnoseSingleNonSendableType (
819
+ Type type, SendableCheckContext fromContext, SourceLoc loc,
820
+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
821
+
822
+ auto module = fromContext.fromDC ->getParentModule ();
823
+ auto nominal = type->getAnyNominal ();
824
+
825
+ return diagnoseSendabilityErrorBasedOn (nominal, fromContext,
826
+ [&](DiagnosticBehavior behavior) {
827
+ bool wasSuppressed = diagnose (type, behavior);
828
+
829
+ // Don't emit the following notes if we didn't have any diagnostics to
830
+ // attach them to.
831
+ if (wasSuppressed || behavior == DiagnosticBehavior::Ignore)
832
+ return true ;
833
+
834
+ if (type->is <FunctionType>()) {
835
+ module ->getASTContext ().Diags
836
+ .diagnose (loc, diag::nonsendable_function_type);
837
+ } else if (nominal && nominal->getParentModule () == module ) {
838
+ // If the nominal type is in the current module, suggest adding
839
+ // `Sendable` if it might make sense. Otherwise, just complain.
840
+ if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
841
+ auto note = nominal->diagnose (
842
+ diag::add_nominal_sendable_conformance,
843
+ nominal->getDescriptiveKind (), nominal->getName ());
844
+ addSendableFixIt (nominal, note, /* unchecked=*/ false );
845
+ } else {
846
+ nominal->diagnose (
847
+ diag::non_sendable_nominal, nominal->getDescriptiveKind (),
848
+ nominal->getName ());
849
+ }
850
+ } else if (nominal) {
851
+ // Note which nominal type does not conform to `Sendable`.
852
+ nominal->diagnose (
853
+ diag::non_sendable_nominal, nominal->getDescriptiveKind (),
854
+ nominal->getName ());
855
+ }
856
+
857
+ return false ;
858
+ });
859
+ }
860
+
836
861
bool swift::diagnoseNonSendableTypes (
837
862
Type type, SendableCheckContext fromContext, SourceLoc loc,
838
863
llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
0 commit comments