@@ -748,6 +748,7 @@ bool SendableCheckContext::isExplicitSendableConformance() const {
748748
749749 case SendableCheck::ImpliedByStandardProtocol:
750750 case SendableCheck::Implicit:
751+ case SendableCheck::ImplicitForExternallyVisible:
751752 return false ;
752753 }
753754}
@@ -861,7 +862,7 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
861862 // enclosing inferred types non-Sendable.
862863 if (defaultBehavior == DiagnosticBehavior::Ignore &&
863864 nominal->getParentSourceFile () &&
864- conformanceCheck && *conformanceCheck == SendableCheck::Implicit )
865+ conformanceCheck && isImplicitSendableCheck ( *conformanceCheck) )
865866 return DiagnosticBehavior::Warning;
866867
867868 return defaultBehavior;
@@ -4053,7 +4054,7 @@ static bool checkSendableInstanceStorage(
40534054 bool operator ()(VarDecl *property, Type propertyType) {
40544055 // Classes with mutable properties are not Sendable.
40554056 if (property->supportsMutation () && isa<ClassDecl>(nominal)) {
4056- if (check == SendableCheck::Implicit ) {
4057+ if (isImplicitSendableCheck ( check) ) {
40574058 invalid = true ;
40584059 return true ;
40594060 }
@@ -4074,8 +4075,14 @@ static bool checkSendableInstanceStorage(
40744075 diagnoseNonSendableTypes (
40754076 propertyType, SendableCheckContext (dc, check), property->getLoc (),
40764077 [&](Type type, DiagnosticBehavior behavior) {
4077- if (check == SendableCheck::Implicit) {
4078- // If we are to ignore this diagnose, just continue.
4078+ if (isImplicitSendableCheck (check)) {
4079+ // If this is for an externally-visible conformance, fail.
4080+ if (check == SendableCheck::ImplicitForExternallyVisible) {
4081+ invalid = true ;
4082+ return true ;
4083+ }
4084+
4085+ // If we are to ignore this diagnostic, just continue.
40794086 if (behavior == DiagnosticBehavior::Ignore)
40804087 return false ;
40814088
@@ -4093,7 +4100,7 @@ static bool checkSendableInstanceStorage(
40934100
40944101 if (invalid) {
40954102 // For implicit checks, bail out early if anything failed.
4096- if (check == SendableCheck::Implicit )
4103+ if (isImplicitSendableCheck ( check) )
40974104 return true ;
40984105 }
40994106
@@ -4105,8 +4112,14 @@ static bool checkSendableInstanceStorage(
41054112 diagnoseNonSendableTypes (
41064113 elementType, SendableCheckContext (dc, check), element->getLoc (),
41074114 [&](Type type, DiagnosticBehavior behavior) {
4108- if (check == SendableCheck::Implicit) {
4109- // If we are to ignore this diagnose, just continue.
4115+ if (isImplicitSendableCheck (check)) {
4116+ // If this is for an externally-visible conformance, fail.
4117+ if (check == SendableCheck::ImplicitForExternallyVisible) {
4118+ invalid = true ;
4119+ return true ;
4120+ }
4121+
4122+ // If we are to ignore this diagnostic, just continue.
41104123 if (behavior == DiagnosticBehavior::Ignore)
41114124 return false ;
41124125
@@ -4124,7 +4137,7 @@ static bool checkSendableInstanceStorage(
41244137
41254138 if (invalid) {
41264139 // For implicit checks, bail out early if anything failed.
4127- if (check == SendableCheck::Implicit )
4140+ if (isImplicitSendableCheck ( check) )
41284141 return true ;
41294142 }
41304143
@@ -4352,21 +4365,27 @@ ProtocolConformance *GetImplicitSendableRequest::evaluate(
43524365 if (!isa<StructDecl>(nominal) && !isa<EnumDecl>(nominal))
43534366 return nullptr ;
43544367
4355- // Public, non-frozen structs and enums defined in Swift don't get implicit
4356- // Sendable conformances.
4357- if (!nominal->getASTContext ().LangOpts .EnableInferPublicSendable &&
4358- nominal->getFormalAccessScope (
4359- /* useDC=*/ nullptr ,
4360- /* treatUsableFromInlineAsPublic=*/ true ).isPublic () &&
4361- !(nominal->hasClangNode () ||
4362- nominal->getAttrs ().hasAttribute <FixedLayoutAttr>() ||
4363- nominal->getAttrs ().hasAttribute <FrozenAttr>())) {
4368+ SendableCheck check;
4369+
4370+ // Okay to infer Sendable conformance for non-public types or when
4371+ // specifically requested.
4372+ if (nominal->getASTContext ().LangOpts .EnableInferPublicSendable ||
4373+ !nominal->getFormalAccessScope (
4374+ /* useDC=*/ nullptr , /* treatUsableFromInlineAsPublic=*/ true )
4375+ .isPublic ()) {
4376+ check = SendableCheck::Implicit;
4377+ } else if (nominal->hasClangNode () ||
4378+ nominal->getAttrs ().hasAttribute <FixedLayoutAttr>() ||
4379+ nominal->getAttrs ().hasAttribute <FrozenAttr>()) {
4380+ // @_frozen public types can also infer Sendable, but be more careful here.
4381+ check = SendableCheck::ImplicitForExternallyVisible;
4382+ } else {
4383+ // No inference.
43644384 return nullptr ;
43654385 }
43664386
43674387 // Check the instance storage for Sendable conformance.
4368- if (checkSendableInstanceStorage (
4369- nominal, nominal, SendableCheck::Implicit))
4388+ if (checkSendableInstanceStorage (nominal, nominal, check))
43704389 return nullptr ;
43714390
43724391 return formConformance (nullptr );
0 commit comments