@@ -553,11 +553,32 @@ bool swift::isSendableType(ModuleDecl *module, Type type) {
553553 });
554554}
555555
556+ // / Add Fix-It text for the given nominal type to adopt Sendable.
557+ static void addSendableFixIt (
558+ const NominalTypeDecl *nominal, InFlightDiagnostic &diag, bool unchecked) {
559+ if (nominal->getInherited ().empty ()) {
560+ SourceLoc fixItLoc = nominal->getBraces ().Start ;
561+ if (unchecked)
562+ diag.fixItInsert (fixItLoc, " : @unchecked Sendable" );
563+ else
564+ diag.fixItInsert (fixItLoc, " : Sendable" );
565+ } else {
566+ ASTContext &ctx = nominal->getASTContext ();
567+ SourceLoc fixItLoc = nominal->getInherited ().back ().getSourceRange ().End ;
568+ fixItLoc = Lexer::getLocForEndOfToken (ctx.SourceMgr , fixItLoc);
569+ if (unchecked)
570+ diag.fixItInsert (fixItLoc, " , @unchecked Sendable" );
571+ else
572+ diag.fixItInsert (fixItLoc, " , Sendable" );
573+ }
574+ }
575+
556576// / Produce a diagnostic for a single instance of a non-Sendable type where
557577// / a Sendable type is required.
558578static bool diagnoseSingleNonSendableType (
559579 Type type, ModuleDecl *module , SourceLoc loc,
560- llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
580+ llvm::function_ref<
581+ std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
561582
562583 auto behavior = DiagnosticBehavior::Unspecified;
563584
@@ -594,23 +615,20 @@ static bool diagnoseSingleNonSendableType(
594615 behavior = DiagnosticBehavior::Warning;
595616 }
596617
597- bool wasError = diagnose (type, behavior);
618+ DiagnosticBehavior actualBehavior;
619+ bool wasError;
620+ std::tie (actualBehavior, wasError) = diagnose (type, behavior);
598621
599- if (type->is <FunctionType>()) {
622+ if (actualBehavior == DiagnosticBehavior::Ignore) {
623+ // Don't emit any other diagnostics.
624+ } else if (type->is <FunctionType>()) {
600625 ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
601626 } else if (nominal && nominal->getParentModule () == module &&
602627 (isa<StructDecl>(nominal) || isa<EnumDecl>(nominal))) {
603628 auto note = nominal->diagnose (
604629 diag::add_nominal_sendable_conformance,
605630 nominal->getDescriptiveKind (), nominal->getName ());
606- if (nominal->getInherited ().empty ()) {
607- SourceLoc fixItLoc = nominal->getBraces ().Start ;
608- note.fixItInsert (fixItLoc, " : Sendable " );
609- } else {
610- SourceLoc fixItLoc = nominal->getInherited ().back ().getSourceRange ().End ;
611- fixItLoc = Lexer::getLocForEndOfToken (ctx.SourceMgr , fixItLoc);
612- note.fixItInsert (fixItLoc, " , Sendable" );
613- }
631+ addSendableFixIt (nominal, note, /* unchecked=*/ false );
614632 } else if (nominal) {
615633 nominal->diagnose (
616634 diag::non_sendable_nominal, nominal->getDescriptiveKind (),
@@ -622,7 +640,8 @@ static bool diagnoseSingleNonSendableType(
622640
623641bool swift::diagnoseNonSendableTypes (
624642 Type type, ModuleDecl *module , SourceLoc loc,
625- llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
643+ llvm::function_ref<
644+ std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
626645 // If the Sendable protocol is missing, do nothing.
627646 auto proto = module ->getASTContext ().getProtocol (KnownProtocolKind::Sendable);
628647 if (!proto)
@@ -710,6 +729,81 @@ void swift::diagnoseMissingSendableConformance(
710729 type, module , loc, diag::non_sendable_type);
711730}
712731
732+ static bool checkSendableInstanceStorage (
733+ NominalTypeDecl *nominal, DeclContext *dc, SendableCheck check);
734+
735+ void swift::diagnoseMissingExplicitSendable (NominalTypeDecl *nominal) {
736+ // Only diagnose when explicitly requested.
737+ ASTContext &ctx = nominal->getASTContext ();
738+ if (!ctx.LangOpts .RequireExplicitSendable )
739+ return ;
740+
741+ if (nominal->getLoc ().isInvalid ())
742+ return ;
743+
744+ // Protocols aren't checked.
745+ if (isa<ProtocolDecl>(nominal))
746+ return ;
747+
748+ // Actors are always Sendable.
749+ if (auto classDecl = dyn_cast<ClassDecl>(nominal))
750+ if (classDecl->isActor ())
751+ return ;
752+
753+ // Only public/open types have this check.
754+ if (!nominal->getFormalAccessScope (
755+ /* useDC=*/ nullptr ,
756+ /* treatUsableFromInlineAsPublic=*/ true ).isPublic ())
757+ return ;
758+
759+ // FIXME: Check for explicit "do not conform to Sendable" marker.
760+
761+ // Look for any conformance to `Sendable`.
762+ auto proto = ctx.getProtocol (KnownProtocolKind::Sendable);
763+ if (!proto)
764+ return ;
765+
766+ SmallVector<ProtocolConformance *, 2 > conformances;
767+ if (nominal->lookupConformance (proto, conformances))
768+ return ;
769+
770+ // Diagnose it.
771+ nominal->diagnose (
772+ diag::public_decl_needs_sendable, nominal->getDescriptiveKind (),
773+ nominal->getName ());
774+
775+ // Note to add a Sendable conformance, possibly an unchecked one.
776+ {
777+ bool isUnchecked = false ;
778+
779+ // Non-final classes can only have @unchecked.
780+ if (auto classDecl = dyn_cast<ClassDecl>(nominal)) {
781+ if (!classDecl->isFinal ())
782+ isUnchecked = true ;
783+ }
784+
785+ // NOTE: We might need to introduce a conditional conformance here.
786+ if (!isUnchecked &&
787+ checkSendableInstanceStorage (
788+ nominal, nominal, SendableCheck::Implicit)) {
789+ isUnchecked = true ;
790+ }
791+
792+ auto note = nominal->diagnose (
793+ isUnchecked ? diag::explicit_unchecked_sendable
794+ : diag::add_nominal_sendable_conformance,
795+ nominal->getDescriptiveKind (), nominal->getName ());
796+ addSendableFixIt (nominal, note, isUnchecked);
797+ }
798+
799+ // Note to disable the warning.
800+ nominal->diagnose (
801+ diag::explicit_disable_sendable, nominal->getDescriptiveKind (),
802+ nominal->getName ())
803+ .fixItInsert (nominal->getAttributeInsertionLoc (/* forModifier=*/ false ),
804+ " @_nonSendable " );
805+ }
806+
713807// / Determine whether this is the main actor type.
714808// / FIXME: the diagnostics engine has a copy of this.
715809static bool isMainActor (Type type) {
@@ -3413,13 +3507,16 @@ static bool checkSendableInstanceStorage(
34133507 [&](Type type, DiagnosticBehavior suggestedBehavior) {
34143508 auto action = limitSendableInstanceBehavior (
34153509 langOpts, check, suggestedBehavior);
3510+ if (check == SendableCheck::Implicit)
3511+ return action;
3512+
34163513 property->diagnose (diag::non_concurrent_type_member,
34173514 false , property->getName (),
34183515 nominal->getDescriptiveKind (),
34193516 nominal->getName (),
34203517 propertyType)
34213518 .limitBehavior (action.first );
3422- return action. second ;
3519+ return action;
34233520 });
34243521
34253522 if (diagnosedProperty) {
@@ -3450,13 +3547,16 @@ static bool checkSendableInstanceStorage(
34503547 [&](Type type, DiagnosticBehavior suggestedBehavior) {
34513548 auto action = limitSendableInstanceBehavior (
34523549 langOpts, check, suggestedBehavior);
3550+ if (check == SendableCheck::Implicit)
3551+ return action;
3552+
34533553 element->diagnose (diag::non_concurrent_type_member,
34543554 true , element->getName (),
34553555 nominal->getDescriptiveKind (),
34563556 nominal->getName (),
34573557 type)
34583558 .limitBehavior (action.first );
3459- return action. second ;
3559+ return action;
34603560 });
34613561
34623562 if (diagnosedElement) {
0 commit comments