@@ -877,82 +877,107 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
877877 return defaultBehavior;
878878}
879879
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) {
886883 auto behavior = DiagnosticBehavior::Unspecified;
887884
888- auto module = fromContext.fromDC ->getParentModule ();
889- ASTContext &ctx = module ->getASTContext ();
890- auto nominal = type->getAnyNominal ();
891885 if (nominal) {
892886 behavior = fromContext.diagnosticBehavior (nominal);
893887 } else {
894888 behavior = fromContext.defaultDiagnosticBehavior ();
895889 }
896890
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 );
915911 }
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 ());
921912
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 ();
933922
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 " );
947928
948- sourceFile->setImportUsedPreconcurrency (*import );
949- }
929+ sourceFile->setImportUsedPreconcurrency (*import );
950930 }
951931 }
952932
953933 return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed;
954934}
955935
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+
956981bool swift::diagnoseNonSendableTypes (
957982 Type type, SendableCheckContext fromContext, SourceLoc loc,
958983 llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
0 commit comments