@@ -757,82 +757,107 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
757757 return defaultBehavior;
758758}
759759
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) {
766763 auto behavior = DiagnosticBehavior::Unspecified;
767764
768- auto module = fromContext.fromDC ->getParentModule ();
769- ASTContext &ctx = module ->getASTContext ();
770- auto nominal = type->getAnyNominal ();
771765 if (nominal) {
772766 behavior = fromContext.diagnosticBehavior (nominal);
773767 } else {
774768 behavior = fromContext.defaultDiagnosticBehavior ();
775769 }
776770
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 );
795791 }
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 ());
801792
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 ();
813802
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 " );
827808
828- sourceFile->setImportUsedPreconcurrency (*import );
829- }
809+ sourceFile->setImportUsedPreconcurrency (*import );
830810 }
831811 }
832812
833813 return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed;
834814}
835815
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+
836861bool swift::diagnoseNonSendableTypes (
837862 Type type, SendableCheckContext fromContext, SourceLoc loc,
838863 llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
0 commit comments