@@ -788,7 +788,10 @@ static bool shouldDiagnoseExistingDataRaces(const DeclContext *dc) {
788
788
});
789
789
}
790
790
791
- bool SendableCheckContext::isExplicitSendableConformance () const {
791
+ bool SendableCheckContext::warnInMinimalChecking () const {
792
+ if (preconcurrencyContext)
793
+ return false ;
794
+
792
795
if (!conformanceCheck)
793
796
return false ;
794
797
@@ -806,7 +809,7 @@ bool SendableCheckContext::isExplicitSendableConformance() const {
806
809
DiagnosticBehavior SendableCheckContext::defaultDiagnosticBehavior () const {
807
810
// If we're not supposed to diagnose existing data races from this context,
808
811
// ignore the diagnostic entirely.
809
- if (!isExplicitSendableConformance () &&
812
+ if (!warnInMinimalChecking () &&
810
813
!shouldDiagnoseExistingDataRaces (fromDC))
811
814
return DiagnosticBehavior::Ignore;
812
815
@@ -825,9 +828,7 @@ SendableCheckContext::implicitSendableDiagnosticBehavior() const {
825
828
LLVM_FALLTHROUGH;
826
829
827
830
case StrictConcurrency::Minimal:
828
- // Explicit Sendable conformances always diagnose, even when strict
829
- // strict checking is disabled.
830
- if (isExplicitSendableConformance ())
831
+ if (warnInMinimalChecking ())
831
832
return DiagnosticBehavior::Warning;
832
833
833
834
return DiagnosticBehavior::Ignore;
@@ -868,6 +869,13 @@ bool swift::hasExplicitSendableConformance(NominalTypeDecl *nominal,
868
869
// / nominal type.
869
870
DiagnosticBehavior SendableCheckContext::diagnosticBehavior (
870
871
NominalTypeDecl *nominal) const {
872
+ // If we're in a preconcurrency context, don't override the default behavior
873
+ // based on explicit conformances. For example, a @preconcurrency @Sendable
874
+ // closure should not warn about an explicitly unavailable Sendable
875
+ // conformance in minimal checking.
876
+ if (preconcurrencyContext)
877
+ return defaultDiagnosticBehavior ();
878
+
871
879
if (hasExplicitSendableConformance (nominal))
872
880
return DiagnosticBehavior::Warning;
873
881
@@ -2780,11 +2788,16 @@ namespace {
2780
2788
continue ;
2781
2789
2782
2790
auto *closure = localFunc.getAbstractClosureExpr ();
2791
+ auto *explicitClosure = dyn_cast_or_null<ClosureExpr>(closure);
2792
+
2793
+ bool preconcurrency = false ;
2794
+ if (explicitClosure) {
2795
+ preconcurrency = explicitClosure->isIsolatedByPreconcurrency ();
2796
+ }
2783
2797
2784
2798
// Diagnose a `self` capture inside an escaping `sending`
2785
2799
// `@Sendable` closure in a deinit, which almost certainly
2786
2800
// means `self` would escape deinit at runtime.
2787
- auto *explicitClosure = dyn_cast_or_null<ClosureExpr>(closure);
2788
2801
auto *dc = getDeclContext ();
2789
2802
if (explicitClosure && isa<DestructorDecl>(dc) &&
2790
2803
!explicitClosure->getType ()->isNoEscape () &&
@@ -2794,7 +2807,8 @@ namespace {
2794
2807
if (var && var->isSelfParameter ()) {
2795
2808
ctx.Diags .diagnose (explicitClosure->getLoc (),
2796
2809
diag::self_capture_deinit_task)
2797
- .warnUntilSwiftVersion (6 );
2810
+ .limitBehaviorWithPreconcurrency (DiagnosticBehavior::Warning,
2811
+ preconcurrency);
2798
2812
}
2799
2813
}
2800
2814
@@ -2822,6 +2836,9 @@ namespace {
2822
2836
if (type->hasError ())
2823
2837
continue ;
2824
2838
2839
+ SendableCheckContext sendableContext (getDeclContext (),
2840
+ preconcurrency);
2841
+
2825
2842
if (closure && closure->isImplicit ()) {
2826
2843
auto *patternBindingDecl = getTopPatternBindingDecl ();
2827
2844
if (patternBindingDecl && patternBindingDecl->isAsyncLet ()) {
@@ -2843,21 +2860,21 @@ namespace {
2843
2860
} else {
2844
2861
// Fallback to a generic implicit capture missing sendable
2845
2862
// conformance diagnostic.
2846
- diagnoseNonSendableTypes (type, getDeclContext () ,
2863
+ diagnoseNonSendableTypes (type, sendableContext ,
2847
2864
/* inDerivedConformance*/ Type (),
2848
2865
capture.getLoc (),
2849
2866
diag::implicit_non_sendable_capture,
2850
2867
decl->getName ());
2851
2868
}
2852
2869
} else if (fnType->isSendable ()) {
2853
- diagnoseNonSendableTypes (type, getDeclContext () ,
2870
+ diagnoseNonSendableTypes (type, sendableContext ,
2854
2871
/* inDerivedConformance*/ Type (),
2855
2872
capture.getLoc (),
2856
2873
diag::non_sendable_capture,
2857
2874
decl->getName (),
2858
2875
/* closure=*/ closure != nullptr );
2859
2876
} else {
2860
- diagnoseNonSendableTypes (type, getDeclContext () ,
2877
+ diagnoseNonSendableTypes (type, sendableContext ,
2861
2878
/* inDerivedConformance*/ Type (),
2862
2879
capture.getLoc (),
2863
2880
diag::non_sendable_isolated_capture,
@@ -4090,7 +4107,12 @@ namespace {
4090
4107
if (!mayExecuteConcurrentlyWith (dc, findCapturedDeclContext (value)))
4091
4108
return false ;
4092
4109
4093
- SendableCheckContext sendableBehavior (dc);
4110
+ bool preconcurrency = false ;
4111
+ if (auto *closure = dyn_cast<ClosureExpr>(dc)) {
4112
+ preconcurrency = closure->isIsolatedByPreconcurrency ();
4113
+ }
4114
+
4115
+ SendableCheckContext sendableBehavior (dc, preconcurrency);
4094
4116
auto limit = sendableBehavior.defaultDiagnosticBehavior ();
4095
4117
4096
4118
// Check whether this is a local variable, in which case we can
@@ -4120,7 +4142,7 @@ namespace {
4120
4142
ctx.Diags
4121
4143
.diagnose (loc, diag::concurrent_access_of_inout_param,
4122
4144
param->getName ())
4123
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4145
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4124
4146
return true ;
4125
4147
}
4126
4148
}
@@ -4135,7 +4157,7 @@ namespace {
4135
4157
loc, diag::concurrent_access_of_local_capture,
4136
4158
parent.dyn_cast <LoadExpr *>(),
4137
4159
var)
4138
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4160
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4139
4161
return true ;
4140
4162
}
4141
4163
@@ -4145,7 +4167,7 @@ namespace {
4145
4167
4146
4168
func->diagnose (diag::local_function_executed_concurrently, func)
4147
4169
.fixItInsert (func->getAttributeInsertionLoc (false ), " @Sendable " )
4148
- .limitBehaviorUntilSwiftVersion (limit, 6 );
4170
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency );
4149
4171
4150
4172
// Add the @Sendable attribute implicitly, so we don't diagnose
4151
4173
// again.
@@ -4155,7 +4177,8 @@ namespace {
4155
4177
}
4156
4178
4157
4179
// Concurrent access to some other local.
4158
- ctx.Diags .diagnose (loc, diag::concurrent_access_local, value);
4180
+ ctx.Diags .diagnose (loc, diag::concurrent_access_local, value)
4181
+ .limitBehaviorWithPreconcurrency (limit, preconcurrency);
4159
4182
value->diagnose (
4160
4183
diag::kind_declared_here, value->getDescriptiveKind ());
4161
4184
return true ;
@@ -5980,7 +6003,8 @@ bool swift::contextRequiresStrictConcurrencyChecking(
5980
6003
const DeclContext *dc,
5981
6004
llvm::function_ref<Type(const AbstractClosureExpr *)> getType,
5982
6005
llvm::function_ref<bool(const ClosureExpr *)> isolatedByPreconcurrency) {
5983
- switch (dc->getASTContext ().LangOpts .StrictConcurrencyLevel ) {
6006
+ auto concurrencyLevel = dc->getASTContext ().LangOpts .StrictConcurrencyLevel ;
6007
+ switch (concurrencyLevel) {
5984
6008
case StrictConcurrency::Complete:
5985
6009
return true ;
5986
6010
@@ -6000,7 +6024,20 @@ bool swift::contextRequiresStrictConcurrencyChecking(
6000
6024
6001
6025
// Don't take any more cues if this only got its type information by
6002
6026
// being provided to a `@preconcurrency` operation.
6027
+ //
6028
+ // FIXME: contextRequiresStrictConcurrencyChecking is called from
6029
+ // within the constraint system, but closures are only set to be isolated
6030
+ // by preconcurrency in solution application because it's dependent on
6031
+ // overload resolution. The constraint system either needs to check its
6032
+ // own state on the current path, or not make type inference decisions based
6033
+ // on concurrency checking level.
6003
6034
if (isolatedByPreconcurrency (explicitClosure)) {
6035
+ // If we're in minimal checking, preconcurrency always suppresses
6036
+ // diagnostics. Targeted checking will still produce diagnostics if
6037
+ // the outer context has adopted explicit concurrency features.
6038
+ if (concurrencyLevel == StrictConcurrency::Minimal)
6039
+ return false ;
6040
+
6004
6041
dc = dc->getParent ();
6005
6042
continue ;
6006
6043
}
0 commit comments