@@ -553,11 +553,32 @@ bool swift::isSendableType(ModuleDecl *module, Type type) {
553
553
});
554
554
}
555
555
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
+
556
576
// / Produce a diagnostic for a single instance of a non-Sendable type where
557
577
// / a Sendable type is required.
558
578
static bool diagnoseSingleNonSendableType (
559
579
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) {
561
582
562
583
auto behavior = DiagnosticBehavior::Unspecified;
563
584
@@ -594,23 +615,20 @@ static bool diagnoseSingleNonSendableType(
594
615
behavior = DiagnosticBehavior::Warning;
595
616
}
596
617
597
- bool wasError = diagnose (type, behavior);
618
+ DiagnosticBehavior actualBehavior;
619
+ bool wasError;
620
+ std::tie (actualBehavior, wasError) = diagnose (type, behavior);
598
621
599
- if (type->is <FunctionType>()) {
622
+ if (actualBehavior == DiagnosticBehavior::Ignore) {
623
+ // Don't emit any other diagnostics.
624
+ } else if (type->is <FunctionType>()) {
600
625
ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
601
626
} else if (nominal && nominal->getParentModule () == module &&
602
627
(isa<StructDecl>(nominal) || isa<EnumDecl>(nominal))) {
603
628
auto note = nominal->diagnose (
604
629
diag::add_nominal_sendable_conformance,
605
630
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 );
614
632
} else if (nominal) {
615
633
nominal->diagnose (
616
634
diag::non_sendable_nominal, nominal->getDescriptiveKind (),
@@ -622,7 +640,8 @@ static bool diagnoseSingleNonSendableType(
622
640
623
641
bool swift::diagnoseNonSendableTypes (
624
642
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) {
626
645
// If the Sendable protocol is missing, do nothing.
627
646
auto proto = module ->getASTContext ().getProtocol (KnownProtocolKind::Sendable);
628
647
if (!proto)
@@ -710,6 +729,81 @@ void swift::diagnoseMissingSendableConformance(
710
729
type, module , loc, diag::non_sendable_type);
711
730
}
712
731
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
+
713
807
// / Determine whether this is the main actor type.
714
808
// / FIXME: the diagnostics engine has a copy of this.
715
809
static bool isMainActor (Type type) {
@@ -3413,13 +3507,16 @@ static bool checkSendableInstanceStorage(
3413
3507
[&](Type type, DiagnosticBehavior suggestedBehavior) {
3414
3508
auto action = limitSendableInstanceBehavior (
3415
3509
langOpts, check, suggestedBehavior);
3510
+ if (check == SendableCheck::Implicit)
3511
+ return action;
3512
+
3416
3513
property->diagnose (diag::non_concurrent_type_member,
3417
3514
false , property->getName (),
3418
3515
nominal->getDescriptiveKind (),
3419
3516
nominal->getName (),
3420
3517
propertyType)
3421
3518
.limitBehavior (action.first );
3422
- return action. second ;
3519
+ return action;
3423
3520
});
3424
3521
3425
3522
if (diagnosedProperty) {
@@ -3450,13 +3547,16 @@ static bool checkSendableInstanceStorage(
3450
3547
[&](Type type, DiagnosticBehavior suggestedBehavior) {
3451
3548
auto action = limitSendableInstanceBehavior (
3452
3549
langOpts, check, suggestedBehavior);
3550
+ if (check == SendableCheck::Implicit)
3551
+ return action;
3552
+
3453
3553
element->diagnose (diag::non_concurrent_type_member,
3454
3554
true , element->getName (),
3455
3555
nominal->getDescriptiveKind (),
3456
3556
nominal->getName (),
3457
3557
type)
3458
3558
.limitBehavior (action.first );
3459
- return action. second ;
3559
+ return action;
3460
3560
});
3461
3561
3462
3562
if (diagnosedElement) {
0 commit comments