@@ -779,7 +779,10 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
779
779
});
780
780
}
781
781
782
- bool SendableCheckContext::isExplicitSendableConformance () const {
782
+ bool SendableCheckContext::warnInMinimalChecking () const {
783
+ if (preconcurrencyContext)
784
+ return false ;
785
+
783
786
if (!conformanceCheck)
784
787
return false ;
785
788
@@ -797,7 +800,7 @@ bool SendableCheckContext::isExplicitSendableConformance() const {
797
800
DiagnosticBehavior SendableCheckContext::defaultDiagnosticBehavior () const {
798
801
// If we're not supposed to diagnose existing data races from this context,
799
802
// ignore the diagnostic entirely.
800
- if (!isExplicitSendableConformance () &&
803
+ if (!warnInMinimalChecking () &&
801
804
!shouldDiagnoseExistingDataRaces (fromDC))
802
805
return DiagnosticBehavior::Ignore;
803
806
@@ -816,9 +819,7 @@ SendableCheckContext::implicitSendableDiagnosticBehavior() const {
816
819
LLVM_FALLTHROUGH;
817
820
818
821
case StrictConcurrency::Minimal:
819
- // Explicit Sendable conformances always diagnose, even when strict
820
- // strict checking is disabled.
821
- if (isExplicitSendableConformance ())
822
+ if (warnInMinimalChecking ())
822
823
return DiagnosticBehavior::Warning;
823
824
824
825
return DiagnosticBehavior::Ignore;
@@ -832,6 +833,13 @@ SendableCheckContext::implicitSendableDiagnosticBehavior() const {
832
833
// / nominal type.
833
834
DiagnosticBehavior SendableCheckContext::diagnosticBehavior (
834
835
NominalTypeDecl *nominal) const {
836
+ // If we're in a preconcurrency context, don't override the default behavior
837
+ // based on explicit conformances. For example, a @preconcurrency @Sendable
838
+ // closure should not warn about an explicitly unavailable Sendable
839
+ // conformance in minimal checking.
840
+ if (preconcurrencyContext)
841
+ return defaultDiagnosticBehavior ();
842
+
835
843
if (hasExplicitSendableConformance (nominal))
836
844
return DiagnosticBehavior::Warning;
837
845
@@ -2759,11 +2767,16 @@ namespace {
2759
2767
continue ;
2760
2768
2761
2769
auto *closure = localFunc.getAbstractClosureExpr ();
2770
+ auto *explicitClosure = dyn_cast_or_null<ClosureExpr>(closure);
2771
+
2772
+ bool preconcurrency = false ;
2773
+ if (explicitClosure) {
2774
+ preconcurrency = explicitClosure->isIsolatedByPreconcurrency ();
2775
+ }
2762
2776
2763
2777
// Diagnose a `self` capture inside an escaping `sending`
2764
2778
// `@Sendable` closure in a deinit, which almost certainly
2765
2779
// means `self` would escape deinit at runtime.
2766
- auto *explicitClosure = dyn_cast_or_null<ClosureExpr>(closure);
2767
2780
auto *dc = getDeclContext ();
2768
2781
if (explicitClosure && isa<DestructorDecl>(dc) &&
2769
2782
!explicitClosure->getType ()->isNoEscape () &&
@@ -2773,7 +2786,8 @@ namespace {
2773
2786
if (var && var->isSelfParameter ()) {
2774
2787
ctx.Diags .diagnose (explicitClosure->getLoc (),
2775
2788
diag::self_capture_deinit_task)
2776
- .warnUntilSwiftVersion (6 );
2789
+ .limitBehaviorWithPreconcurrency (DiagnosticBehavior::Warning,
2790
+ preconcurrency);
2777
2791
}
2778
2792
}
2779
2793
@@ -2801,6 +2815,9 @@ namespace {
2801
2815
if (type->hasError ())
2802
2816
continue ;
2803
2817
2818
+ SendableCheckContext sendableContext (getDeclContext (),
2819
+ preconcurrency);
2820
+
2804
2821
if (closure && closure->isImplicit ()) {
2805
2822
auto *patternBindingDecl = getTopPatternBindingDecl ();
2806
2823
if (patternBindingDecl && patternBindingDecl->isAsyncLet ()) {
@@ -2811,20 +2828,20 @@ namespace {
2811
2828
2812
2829
// Fallback to a generic implicit capture missing sendable
2813
2830
// conformance diagnostic.
2814
- diagnoseNonSendableTypes (type, getDeclContext () ,
2831
+ diagnoseNonSendableTypes (type, sendableContext ,
2815
2832
/* inDerivedConformance*/ Type (),
2816
2833
capture.getLoc (),
2817
2834
diag::implicit_non_sendable_capture,
2818
2835
decl->getName ());
2819
2836
} else if (fnType->isSendable ()) {
2820
- diagnoseNonSendableTypes (type, getDeclContext () ,
2837
+ diagnoseNonSendableTypes (type, sendableContext ,
2821
2838
/* inDerivedConformance*/ Type (),
2822
2839
capture.getLoc (),
2823
2840
diag::non_sendable_capture,
2824
2841
decl->getName (),
2825
2842
/* closure=*/ closure != nullptr );
2826
2843
} else {
2827
- diagnoseNonSendableTypes (type, getDeclContext () ,
2844
+ diagnoseNonSendableTypes (type, sendableContext ,
2828
2845
/* inDerivedConformance*/ Type (),
2829
2846
capture.getLoc (),
2830
2847
diag::non_sendable_isolated_capture,
@@ -4066,7 +4083,12 @@ namespace {
4066
4083
if (!mayExecuteConcurrentlyWith (dc, findCapturedDeclContext (value)))
4067
4084
return false ;
4068
4085
4069
- SendableCheckContext sendableBehavior (dc);
4086
+ bool preconcurrency = false ;
4087
+ if (auto *closure = dyn_cast<ClosureExpr>(dc)) {
4088
+ preconcurrency = closure->isIsolatedByPreconcurrency ();
4089
+ }
4090
+
4091
+ SendableCheckContext sendableBehavior (dc, preconcurrency);
4070
4092
auto limit = sendableBehavior.defaultDiagnosticBehavior ();
4071
4093
4072
4094
// Check whether this is a local variable, in which case we can
@@ -4096,7 +4118,7 @@ namespace {
4096
4118
ctx.Diags
4097
4119
.diagnose (loc, diag::concurrent_access_of_inout_param,
4098
4120
param->getName ())
4099
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4121
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4100
4122
return true ;
4101
4123
}
4102
4124
}
@@ -4111,7 +4133,7 @@ namespace {
4111
4133
loc, diag::concurrent_access_of_local_capture,
4112
4134
parent.dyn_cast <LoadExpr *>(),
4113
4135
var)
4114
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4136
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4115
4137
return true ;
4116
4138
}
4117
4139
@@ -4121,7 +4143,7 @@ namespace {
4121
4143
4122
4144
func->diagnose (diag::local_function_executed_concurrently, func)
4123
4145
.fixItInsert (func->getAttributeInsertionLoc (false ), " @Sendable " )
4124
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4146
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4125
4147
4126
4148
// Add the @Sendable attribute implicitly, so we don't diagnose
4127
4149
// again.
@@ -4131,7 +4153,8 @@ namespace {
4131
4153
}
4132
4154
4133
4155
// Concurrent access to some other local.
4134
- ctx.Diags .diagnose (loc, diag::concurrent_access_local, value);
4156
+ ctx.Diags .diagnose (loc, diag::concurrent_access_local, value)
4157
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency);
4135
4158
value->diagnose (
4136
4159
diag::kind_declared_here, value->getDescriptiveKind ());
4137
4160
return true ;
@@ -6194,7 +6217,8 @@ bool swift::contextRequiresStrictConcurrencyChecking(
6194
6217
const DeclContext *dc,
6195
6218
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
6196
6219
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
6197
- switch (dc->getASTContext ().LangOpts .StrictConcurrencyLevel ) {
6220
+ auto concurrencyLevel = dc->getASTContext ().LangOpts .StrictConcurrencyLevel ;
6221
+ switch (concurrencyLevel) {
6198
6222
case StrictConcurrency::Complete:
6199
6223
return true ;
6200
6224
@@ -6214,7 +6238,20 @@ bool swift::contextRequiresStrictConcurrencyChecking(
6214
6238
6215
6239
// Don't take any more cues if this only got its type information by
6216
6240
// being provided to a `@preconcurrency` operation.
6241
+ //
6242
+ // FIXME: contextRequiresStrictConcurrencyChecking is called from
6243
+ // within the constraint system, but closures are only set to be isolated
6244
+ // by preconcurrency in solution application because it's dependent on
6245
+ // overload resolution. The constraint system either needs to check its
6246
+ // own state on the current path, or not make type inference decisions based
6247
+ // on concurrency checking level.
6217
6248
if (isolatedByPreconcurrency (explicitClosure)) {
6249
+ // If we're in minimal checking, preconcurrency always suppresses
6250
+ // diagnostics. Targeted checking will still produce diagnostics if
6251
+ // the outer context has adopted explicit concurrency features.
6252
+ if (concurrencyLevel == StrictConcurrency::Minimal)
6253
+ return false ;
6254
+
6218
6255
dc = dc->getParent ();
6219
6256
continue ;
6220
6257
}
0 commit comments