@@ -1921,39 +1921,6 @@ static FuncDecl *findAnnotatableFunction(DeclContext *dc) {
1921
1921
return fn;
1922
1922
}
1923
1923
1924
- // / Note when the enclosing context could be put on a global actor.
1925
- // FIXME: This should handle closures too.
1926
- static void noteGlobalActorOnContext (DeclContext *dc, Type globalActor) {
1927
- // If we are in a synchronous function on the global actor,
1928
- // suggest annotating with the global actor itself.
1929
- if (auto fn = findAnnotatableFunction (dc)) {
1930
- // Suppress this for accessories because you can't change the
1931
- // actor isolation of an individual accessor. Arguably we could
1932
- // add this to the entire storage declaration, though.
1933
- // Suppress this for async functions out of caution; but don't
1934
- // suppress it if we looked through a defer.
1935
- if (!isa<AccessorDecl>(fn) &&
1936
- (!fn->isAsyncContext () || fn != dc)) {
1937
- switch (getActorIsolation (fn)) {
1938
- case ActorIsolation::ActorInstance:
1939
- case ActorIsolation::GlobalActor:
1940
- case ActorIsolation::GlobalActorUnsafe:
1941
- case ActorIsolation::Nonisolated:
1942
- case ActorIsolation::NonisolatedUnsafe:
1943
- return ;
1944
-
1945
- case ActorIsolation::Unspecified:
1946
- fn->diagnose (diag::note_add_globalactor_to_function,
1947
- globalActor->getWithoutParens ().getString (),
1948
- fn, globalActor)
1949
- .fixItInsert (fn->getAttributeInsertionLoc (false ),
1950
- diag::insert_globalactor_attr, globalActor);
1951
- return ;
1952
- }
1953
- }
1954
- }
1955
- }
1956
-
1957
1924
bool swift::diagnoseApplyArgSendability (ApplyExpr *apply, const DeclContext *declContext) {
1958
1925
auto isolationCrossing = apply->getIsolationCrossing ();
1959
1926
if (!isolationCrossing.has_value ())
@@ -2036,6 +2003,16 @@ namespace {
2036
2003
// / an expression or function.
2037
2004
llvm::SmallDenseMap<const DeclContext *, ActorIsolation> requiredIsolation;
2038
2005
2006
+ using ActorRefKindPair = std::pair<ReferencedActor::Kind, ActorIsolation>;
2007
+
2008
+ using IsolationPair = std::pair<ActorIsolation, ActorIsolation>;
2009
+
2010
+ using DiagnosticList = std::vector<IsolationError>;
2011
+
2012
+ llvm::DenseMap<ActorRefKindPair, DiagnosticList> refErrors;
2013
+
2014
+ llvm::DenseMap<IsolationPair, DiagnosticList> applyErrors;
2015
+
2039
2016
// / Keeps track of the capture context of variables that have been
2040
2017
// / explicitly captured in closures.
2041
2018
llvm::SmallDenseMap<VarDecl *, TinyPtrVector<const DeclContext *>>
@@ -2054,6 +2031,99 @@ namespace {
2054
2031
return applyStack.back ().dyn_cast <ApplyExpr *>();
2055
2032
}
2056
2033
2034
+ // / Note when the enclosing context could be put on a global actor.
2035
+ // FIXME: This should handle closures too.
2036
+ static bool missingGlobalActorOnContext (DeclContext *dc, Type globalActor, DiagnosticBehavior behavior) {
2037
+ // If we are in a synchronous function on the global actor,
2038
+ // suggest annotating with the global actor itself.
2039
+ if (auto fn = findAnnotatableFunction (dc)) {
2040
+ // Suppress this for accessors because you can't change the
2041
+ // actor isolation of an individual accessor. Arguably we could
2042
+ // add this to the entire storage declaration, though.
2043
+ // Suppress this for async functions out of caution; but don't
2044
+ // suppress it if we looked through a defer.
2045
+ if (!isa<AccessorDecl>(fn) &&
2046
+ (!fn->isAsyncContext () || fn != dc)) {
2047
+ switch (getActorIsolation (fn)) {
2048
+ case ActorIsolation::ActorInstance:
2049
+ case ActorIsolation::GlobalActor:
2050
+ case ActorIsolation::GlobalActorUnsafe:
2051
+ case ActorIsolation::Nonisolated:
2052
+ case ActorIsolation::NonisolatedUnsafe:
2053
+ return false ;
2054
+
2055
+ case ActorIsolation::Unspecified:
2056
+ fn->diagnose (diag::add_globalactor_to_function,
2057
+ globalActor->getWithoutParens ().getString (),
2058
+ fn, globalActor)
2059
+ .limitBehavior (behavior)
2060
+ .fixItInsert (fn->getAttributeInsertionLoc (false ),
2061
+ diag::insert_globalactor_attr, globalActor);
2062
+ return true ;
2063
+ }
2064
+ }
2065
+ }
2066
+ return false ;
2067
+ }
2068
+
2069
+ public:
2070
+ bool diagnoseIsolationErrors () {
2071
+ bool diagnosedError = false ;
2072
+
2073
+ for (auto list : refErrors) {
2074
+ ActorRefKindPair key = list.getFirst ();
2075
+ DiagnosticList errors = list.getSecond ();
2076
+ ActorIsolation isolation = key.second ;
2077
+
2078
+ auto behavior = DiagnosticBehavior::Error;
2079
+
2080
+ // Add Fix-it for missing @SomeActor annotation
2081
+ if (isolation.isGlobalActor ()) {
2082
+ if (missingGlobalActorOnContext (
2083
+ const_cast <DeclContext *>(getDeclContext ()),
2084
+ isolation.getGlobalActor (), behavior) &&
2085
+ errors.size () > 1 ) {
2086
+ behavior= DiagnosticBehavior::Note;
2087
+ }
2088
+ }
2089
+
2090
+ for (IsolationError error : errors) {
2091
+ // Diagnose actor_isolated_non_self_reference as note
2092
+ // if fix-it provided in missingGlobalActorOnContext
2093
+ ctx.Diags .diagnose (error.loc , error.diag )
2094
+ .limitBehavior (behavior);
2095
+ }
2096
+ }
2097
+
2098
+ for (auto list : applyErrors) {
2099
+ IsolationPair key = list.getFirst ();
2100
+ DiagnosticList errors = list.getSecond ();
2101
+ ActorIsolation isolation = key.first ;
2102
+
2103
+ auto behavior = DiagnosticBehavior::Error;
2104
+
2105
+ // Add Fix-it for missing @SomeActor annotation
2106
+ if (isolation.isGlobalActor ()) {
2107
+ if (missingGlobalActorOnContext (
2108
+ const_cast <DeclContext *>(getDeclContext ()),
2109
+ isolation.getGlobalActor (), behavior) &&
2110
+ errors.size () > 1 ) {
2111
+ behavior= DiagnosticBehavior::Note;
2112
+ }
2113
+ }
2114
+
2115
+ for (IsolationError error : errors) {
2116
+ // Diagnose actor_isolated_call as note if
2117
+ // fix-it provided in missingGlobalActorOnContext
2118
+ ctx.Diags .diagnose (error.loc , error.diag )
2119
+ .limitBehavior (behavior);
2120
+ }
2121
+ }
2122
+
2123
+ return diagnosedError;
2124
+ }
2125
+
2126
+ private:
2057
2127
const PatternBindingDecl *getTopPatternBindingDecl () const {
2058
2128
return patternBindingStack.empty () ? nullptr : patternBindingStack.back ();
2059
2129
}
@@ -3185,27 +3255,58 @@ namespace {
3185
3255
// If we need to mark the call as implicitly asynchronous, make sure
3186
3256
// we're in an asynchronous context.
3187
3257
if (requiresAsync && !getDeclContext ()->isAsyncContext ()) {
3188
- if (calleeDecl) {
3189
- auto preconcurrency = getContextIsolation ().preconcurrency () ||
3190
- calleeDecl->preconcurrency ();
3191
- ctx.Diags .diagnose (
3192
- apply->getLoc (), diag::actor_isolated_call_decl,
3193
- *unsatisfiedIsolation,
3194
- calleeDecl,
3195
- getContextIsolation ())
3196
- .warnUntilSwiftVersionIf (preconcurrency, 6 );
3197
- calleeDecl->diagnose (diag::actor_isolated_sync_func, calleeDecl);
3258
+
3259
+ if (ctx.LangOpts .hasFeature (Feature::GroupActorErrors)) {
3260
+
3261
+ IsolationError mismatch ([calleeDecl, apply, unsatisfiedIsolation, getContextIsolation]() {
3262
+ if (calleeDecl) {
3263
+ return IsolationError (
3264
+ apply->getLoc (),
3265
+ Diagnostic (diag::actor_isolated_call_decl,
3266
+ *unsatisfiedIsolation,
3267
+ calleeDecl,
3268
+ getContextIsolation ()));
3269
+ } else {
3270
+ return IsolationError (
3271
+ apply->getLoc (),
3272
+ Diagnostic (diag::actor_isolated_call,
3273
+ *unsatisfiedIsolation,
3274
+ getContextIsolation ()));
3275
+ }
3276
+ }());
3277
+
3278
+ auto iter = applyErrors.find (std::make_pair (*unsatisfiedIsolation, getContextIsolation ()));
3279
+ if (iter != applyErrors.end ()){
3280
+ iter->second .push_back ((mismatch));
3281
+ } else {
3282
+ DiagnosticList list;
3283
+ list.push_back ((mismatch));
3284
+ auto keyPair = std::make_pair (*unsatisfiedIsolation, getContextIsolation ());
3285
+ applyErrors.insert (std::make_pair (keyPair, list));
3286
+ }
3198
3287
} else {
3199
- ctx.Diags .diagnose (
3200
- apply->getLoc (), diag::actor_isolated_call, *unsatisfiedIsolation,
3201
- getContextIsolation ())
3288
+ if (calleeDecl) {
3289
+ auto preconcurrency = getContextIsolation ().preconcurrency () ||
3290
+ calleeDecl->preconcurrency ();
3291
+ ctx.Diags .diagnose (
3292
+ apply->getLoc (), diag::actor_isolated_call_decl,
3293
+ *unsatisfiedIsolation,
3294
+ calleeDecl,
3295
+ getContextIsolation ())
3296
+ .warnUntilSwiftVersionIf (preconcurrency, 6 );
3297
+ calleeDecl->diagnose (diag::actor_isolated_sync_func, calleeDecl);
3298
+ } else {
3299
+ ctx.Diags .diagnose (
3300
+ apply->getLoc (), diag::actor_isolated_call, *unsatisfiedIsolation,
3301
+ getContextIsolation ())
3202
3302
.warnUntilSwiftVersionIf (getContextIsolation ().preconcurrency (), 6 );
3203
- }
3303
+ }
3204
3304
3205
- if (unsatisfiedIsolation->isGlobalActor ()) {
3206
- noteGlobalActorOnContext (
3207
- const_cast <DeclContext *>(getDeclContext ()),
3208
- unsatisfiedIsolation->getGlobalActor ());
3305
+ if (unsatisfiedIsolation->isGlobalActor ()) {
3306
+ missingGlobalActorOnContext (
3307
+ const_cast <DeclContext *>(getDeclContext ()),
3308
+ unsatisfiedIsolation->getGlobalActor (), DiagnosticBehavior::Note);
3309
+ }
3209
3310
}
3210
3311
3211
3312
return true ;
@@ -3574,22 +3675,38 @@ namespace {
3574
3675
bool preconcurrencyContext =
3575
3676
result.options .contains (ActorReferenceResult::Flags::Preconcurrency);
3576
3677
3577
- ctx.Diags .diagnose (
3578
- loc, diag::actor_isolated_non_self_reference,
3579
- decl,
3580
- useKind,
3581
- refKind + 1 , refGlobalActor,
3582
- result.isolation )
3583
- .warnUntilSwiftVersionIf (preconcurrencyContext, 6 );
3584
-
3585
- noteIsolatedActorMember (decl, context);
3586
-
3587
- if (result.isolation .isGlobalActor ()) {
3588
- noteGlobalActorOnContext (
3589
- const_cast <DeclContext *>(getDeclContext ()),
3590
- result.isolation .getGlobalActor ());
3591
- }
3678
+ if (ctx.LangOpts .hasFeature (Feature::GroupActorErrors)) {
3679
+ IsolationError mismatch = IsolationError (loc, Diagnostic (diag::actor_isolated_non_self_reference,
3680
+ decl,
3681
+ useKind,
3682
+ refKind + 1 , refGlobalActor,
3683
+ result.isolation ));
3592
3684
3685
+ auto iter = refErrors.find (std::make_pair (refKind,result.isolation ));
3686
+ if (iter != refErrors.end ()){
3687
+ iter->second .push_back (mismatch);
3688
+ } else {
3689
+ DiagnosticList list;
3690
+ list.push_back (mismatch);
3691
+ auto keyPair = std::make_pair (refKind,result.isolation );
3692
+ refErrors.insert (std::make_pair (keyPair, list));
3693
+ }
3694
+ } else {
3695
+ ctx.Diags .diagnose (
3696
+ loc, diag::actor_isolated_non_self_reference,
3697
+ decl,
3698
+ useKind,
3699
+ refKind + 1 , refGlobalActor,
3700
+ result.isolation )
3701
+ .warnUntilSwiftVersionIf (preconcurrencyContext, 6 );
3702
+
3703
+ noteIsolatedActorMember (decl, context);
3704
+ if (result.isolation .isGlobalActor ()) {
3705
+ missingGlobalActorOnContext (
3706
+ const_cast <DeclContext *>(getDeclContext ()),
3707
+ result.isolation .getGlobalActor (), DiagnosticBehavior::Note);
3708
+ }
3709
+ }
3593
3710
return true ;
3594
3711
}
3595
3712
}
@@ -3731,9 +3848,11 @@ void swift::checkFunctionActorIsolation(AbstractFunctionDecl *decl) {
3731
3848
if (decl->getAttrs ().hasAttribute <LLDBDebuggerFunctionAttr>())
3732
3849
return ;
3733
3850
3851
+ auto &ctx = decl->getASTContext ();
3734
3852
ActorIsolationChecker checker (decl);
3735
3853
if (auto body = decl->getBody ()) {
3736
3854
body->walk (checker);
3855
+ if (ctx.LangOpts .hasFeature (Feature::GroupActorErrors)){ checker.diagnoseIsolationErrors (); }
3737
3856
}
3738
3857
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
3739
3858
if (auto superInit = ctor->getSuperInitCall ())
0 commit comments