@@ -650,10 +650,17 @@ DiagnosticBehavior SendableCheckContext::defaultDiagnosticBehavior() const {
650
650
return defaultSendableDiagnosticBehavior (fromDC->getASTContext ().LangOpts );
651
651
}
652
652
653
- // / Determine whether the given nominal type that is within the current module
654
- // / has an explicit Sendable.
655
- static bool hasExplicitSendableConformance (NominalTypeDecl *nominal) {
653
+ // / Determine whether the given nominal type has an explicit Sendable
654
+ // / conformance (regardless of its availability).
655
+ static bool hasExplicitSendableConformance (NominalTypeDecl *nominal,
656
+ bool applyModuleDefault = true ) {
656
657
ASTContext &ctx = nominal->getASTContext ();
658
+ auto nominalModule = nominal->getParentModule ();
659
+
660
+ // In a concurrency-checked module, a missing conformance is equivalent to
661
+ // an explicitly unavailable one. If we want to apply this rule, do so now.
662
+ if (applyModuleDefault && nominalModule->isConcurrencyChecked ())
663
+ return true ;
657
664
658
665
// Look for any conformance to `Sendable`.
659
666
auto proto = ctx.getProtocol (KnownProtocolKind::Sendable);
@@ -662,7 +669,7 @@ static bool hasExplicitSendableConformance(NominalTypeDecl *nominal) {
662
669
663
670
// Look for a conformance. If it's present and not (directly) missing,
664
671
// we're done.
665
- auto conformance = nominal-> getParentModule () ->lookupConformance (
672
+ auto conformance = nominalModule ->lookupConformance (
666
673
nominal->getDeclaredInterfaceType (), proto, /* allowMissing=*/ true );
667
674
return conformance &&
668
675
!(isa<BuiltinProtocolConformance>(conformance.getConcrete ()) &&
@@ -706,18 +713,13 @@ static Optional<AttributedImport<ImportedModule>> findImportFor(
706
713
// / nominal type.
707
714
DiagnosticBehavior SendableCheckContext::diagnosticBehavior (
708
715
NominalTypeDecl *nominal) const {
709
- // Determine whether the type was explicitly non-Sendable.
710
- auto nominalModule = nominal->getParentModule ();
711
- bool isExplicitlyNonSendable = nominalModule->isConcurrencyChecked () ||
712
- hasExplicitSendableConformance (nominal);
713
-
714
716
// Determine whether this nominal type is visible via a @preconcurrency
715
717
// import.
716
718
auto import = findImportFor (nominal, fromDC);
719
+ auto sourceFile = fromDC->getParentSourceFile ();
717
720
718
721
// When the type is explicitly non-Sendable...
719
- auto sourceFile = fromDC->getParentSourceFile ();
720
- if (isExplicitlyNonSendable) {
722
+ if (hasExplicitSendableConformance (nominal)) {
721
723
// @preconcurrency imports downgrade the diagnostic to a warning in Swift 6,
722
724
if (import && import ->options .contains (ImportFlags::Preconcurrency)) {
723
725
if (sourceFile)
@@ -737,7 +739,7 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
737
739
if (sourceFile)
738
740
sourceFile->setImportUsedPreconcurrency (*import );
739
741
740
- return nominalModule ->getASTContext ().LangOpts .isSwiftVersionAtLeast (6 )
742
+ return nominal ->getASTContext ().LangOpts .isSwiftVersionAtLeast (6 )
741
743
? DiagnosticBehavior::Warning
742
744
: DiagnosticBehavior::Ignore;
743
745
}
@@ -797,29 +799,34 @@ static bool diagnoseSingleNonSendableType(
797
799
diag::non_sendable_nominal, nominal->getDescriptiveKind (),
798
800
nominal->getName ());
799
801
800
- // This type was imported from another module; try to find the
801
- // corresponding import.
802
- Optional<AttributedImport<swift::ImportedModule>> import ;
803
- SourceFile *sourceFile = fromContext.fromDC ->getParentSourceFile ();
804
- if (sourceFile) {
805
- import = findImportFor (nominal, fromContext.fromDC );
806
- }
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
+ }
807
813
808
- // If we found the import that makes this nominal type visible, remark
809
- // that it can be @preconcurrency import.
810
- // Only emit this remark once per source file, because it can happen a
811
- // lot.
812
- if (import && !import ->options .contains (ImportFlags::Preconcurrency) &&
813
- import ->importLoc .isValid () && sourceFile &&
814
- !sourceFile->hasImportUsedPreconcurrency (*import )) {
815
- SourceLoc importLoc = import ->importLoc ;
816
- ctx.Diags .diagnose (
817
- importLoc, diag::add_predates_concurrency_import,
818
- ctx.LangOpts .isSwiftVersionAtLeast (6 ),
819
- nominal->getParentModule ()->getName ())
820
- .fixItInsert (importLoc, " @preconcurrency " );
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 " );
821
827
822
- sourceFile->setImportUsedPreconcurrency (*import );
828
+ sourceFile->setImportUsedPreconcurrency (*import );
829
+ }
823
830
}
824
831
}
825
832
@@ -1036,7 +1043,7 @@ void swift::diagnoseMissingExplicitSendable(NominalTypeDecl *nominal) {
1036
1043
return ;
1037
1044
1038
1045
// If the conformance is explicitly stated, do nothing.
1039
- if (hasExplicitSendableConformance (nominal))
1046
+ if (hasExplicitSendableConformance (nominal, /* applyModuleDefault= */ false ))
1040
1047
return ;
1041
1048
1042
1049
// Diagnose it.
0 commit comments