@@ -877,82 +877,107 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
877
877
return defaultBehavior;
878
878
}
879
879
880
- // / Produce a diagnostic for a single instance of a non-Sendable type where
881
- // / a Sendable type is required.
882
- static bool diagnoseSingleNonSendableType (
883
- Type type, SendableCheckContext fromContext, SourceLoc loc,
884
- llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
885
-
880
+ bool swift::diagnoseSendabilityErrorBasedOn (
881
+ NominalTypeDecl *nominal, SendableCheckContext fromContext,
882
+ llvm::function_ref<bool (DiagnosticBehavior)> diagnose) {
886
883
auto behavior = DiagnosticBehavior::Unspecified;
887
884
888
- auto module = fromContext.fromDC ->getParentModule ();
889
- ASTContext &ctx = module ->getASTContext ();
890
- auto nominal = type->getAnyNominal ();
891
885
if (nominal) {
892
886
behavior = fromContext.diagnosticBehavior (nominal);
893
887
} else {
894
888
behavior = fromContext.defaultDiagnosticBehavior ();
895
889
}
896
890
897
- bool wasSuppressed = diagnose (type, behavior);
898
-
899
- if (behavior == DiagnosticBehavior::Ignore || wasSuppressed) {
900
- // Don't emit any other diagnostics.
901
- } else if (type->is <FunctionType>()) {
902
- ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
903
- } else if (nominal && nominal->getParentModule () == module ) {
904
- // If the nominal type is in the current module, suggest adding
905
- // `Sendable` if it might make sense. Otherwise, just complain.
906
- if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
907
- auto note = nominal->diagnose (
908
- diag::add_nominal_sendable_conformance,
909
- nominal->getDescriptiveKind (), nominal->getName ());
910
- addSendableFixIt (nominal, note, /* unchecked=*/ false );
911
- } else {
912
- nominal->diagnose (
913
- diag::non_sendable_nominal, nominal->getDescriptiveKind (),
914
- nominal->getName ());
891
+ bool wasSuppressed = diagnose (behavior);
892
+
893
+ bool emittedDiagnostics =
894
+ behavior != DiagnosticBehavior::Ignore && !wasSuppressed;
895
+
896
+ // When the type is explicitly Sendable *or* explicitly non-Sendable, we
897
+ // assume it has been audited and `@preconcurrency` is not recommended even
898
+ // though it would actually affect the diagnostic.
899
+ bool nominalIsImportedAndHasImplicitSendability =
900
+ nominal &&
901
+ nominal->getParentModule () != fromContext.fromDC ->getParentModule () &&
902
+ !hasExplicitSendableConformance (nominal);
903
+
904
+ if (emittedDiagnostics && nominalIsImportedAndHasImplicitSendability) {
905
+ // This type was imported from another module; try to find the
906
+ // corresponding import.
907
+ Optional<AttributedImport<swift::ImportedModule>> import ;
908
+ SourceFile *sourceFile = fromContext.fromDC ->getParentSourceFile ();
909
+ if (sourceFile) {
910
+ import = findImportFor (nominal, fromContext.fromDC );
915
911
}
916
- } else if (nominal) {
917
- // Note which nominal type does not conform to `Sendable`.
918
- nominal->diagnose (
919
- diag::non_sendable_nominal, nominal->getDescriptiveKind (),
920
- nominal->getName ());
921
912
922
- // When the type is explicitly Sendable *or* explicitly non-Sendable, we
923
- // assume it has been audited and `@preconcurrency` is not recommended even
924
- // though it would actually affect the diagnostic.
925
- if (!hasExplicitSendableConformance (nominal)) {
926
- // This type was imported from another module; try to find the
927
- // corresponding import.
928
- Optional<AttributedImport<swift::ImportedModule>> import ;
929
- SourceFile *sourceFile = fromContext.fromDC ->getParentSourceFile ();
930
- if (sourceFile) {
931
- import = findImportFor (nominal, fromContext.fromDC );
932
- }
913
+ // If we found the import that makes this nominal type visible, remark
914
+ // that it can be @preconcurrency import.
915
+ // Only emit this remark once per source file, because it can happen a
916
+ // lot.
917
+ if (import && !import ->options .contains (ImportFlags::Preconcurrency) &&
918
+ import ->importLoc .isValid () && sourceFile &&
919
+ !sourceFile->hasImportUsedPreconcurrency (*import )) {
920
+ SourceLoc importLoc = import ->importLoc ;
921
+ ASTContext &ctx = nominal->getASTContext ();
933
922
934
- // If we found the import that makes this nominal type visible, remark
935
- // that it can be @preconcurrency import.
936
- // Only emit this remark once per source file, because it can happen a
937
- // lot.
938
- if (import && !import ->options .contains (ImportFlags::Preconcurrency) &&
939
- import ->importLoc .isValid () && sourceFile &&
940
- !sourceFile->hasImportUsedPreconcurrency (*import )) {
941
- SourceLoc importLoc = import ->importLoc ;
942
- ctx.Diags .diagnose (
943
- importLoc, diag::add_predates_concurrency_import,
944
- ctx.LangOpts .isSwiftVersionAtLeast (6 ),
945
- nominal->getParentModule ()->getName ())
946
- .fixItInsert (importLoc, " @preconcurrency " );
923
+ ctx.Diags .diagnose (
924
+ importLoc, diag::add_predates_concurrency_import,
925
+ ctx.LangOpts .isSwiftVersionAtLeast (6 ),
926
+ nominal->getParentModule ()->getName ())
927
+ .fixItInsert (importLoc, " @preconcurrency " );
947
928
948
- sourceFile->setImportUsedPreconcurrency (*import );
949
- }
929
+ sourceFile->setImportUsedPreconcurrency (*import );
950
930
}
951
931
}
952
932
953
933
return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed;
954
934
}
955
935
936
+ // / Produce a diagnostic for a single instance of a non-Sendable type where
937
+ // / a Sendable type is required.
938
+ static bool diagnoseSingleNonSendableType (
939
+ Type type, SendableCheckContext fromContext, SourceLoc loc,
940
+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
941
+
942
+ auto module = fromContext.fromDC ->getParentModule ();
943
+ auto nominal = type->getAnyNominal ();
944
+
945
+ return diagnoseSendabilityErrorBasedOn (nominal, fromContext,
946
+ [&](DiagnosticBehavior behavior) {
947
+ bool wasSuppressed = diagnose (type, behavior);
948
+
949
+ // Don't emit the following notes if we didn't have any diagnostics to
950
+ // attach them to.
951
+ if (wasSuppressed || behavior == DiagnosticBehavior::Ignore)
952
+ return true ;
953
+
954
+ if (type->is <FunctionType>()) {
955
+ module ->getASTContext ().Diags
956
+ .diagnose (loc, diag::nonsendable_function_type);
957
+ } else if (nominal && nominal->getParentModule () == module ) {
958
+ // If the nominal type is in the current module, suggest adding
959
+ // `Sendable` if it might make sense. Otherwise, just complain.
960
+ if (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal)) {
961
+ auto note = nominal->diagnose (
962
+ diag::add_nominal_sendable_conformance,
963
+ nominal->getDescriptiveKind (), nominal->getName ());
964
+ addSendableFixIt (nominal, note, /* unchecked=*/ false );
965
+ } else {
966
+ nominal->diagnose (
967
+ diag::non_sendable_nominal, nominal->getDescriptiveKind (),
968
+ nominal->getName ());
969
+ }
970
+ } else if (nominal) {
971
+ // Note which nominal type does not conform to `Sendable`.
972
+ nominal->diagnose (
973
+ diag::non_sendable_nominal, nominal->getDescriptiveKind (),
974
+ nominal->getName ());
975
+ }
976
+
977
+ return false ;
978
+ });
979
+ }
980
+
956
981
bool swift::diagnoseNonSendableTypes (
957
982
Type type, SendableCheckContext fromContext, SourceLoc loc,
958
983
llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
0 commit comments