@@ -1921,39 +1921,6 @@ static FuncDecl *findAnnotatableFunction(DeclContext *dc) {
19211921 return fn;
19221922}
19231923
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-
19571924bool swift::diagnoseApplyArgSendability (ApplyExpr *apply, const DeclContext *declContext) {
19581925 auto isolationCrossing = apply->getIsolationCrossing ();
19591926 if (!isolationCrossing.has_value ())
@@ -2036,6 +2003,16 @@ namespace {
20362003 // / an expression or function.
20372004 llvm::SmallDenseMap<const DeclContext *, ActorIsolation> requiredIsolation;
20382005
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+
20392016 // / Keeps track of the capture context of variables that have been
20402017 // / explicitly captured in closures.
20412018 llvm::SmallDenseMap<VarDecl *, TinyPtrVector<const DeclContext *>>
@@ -2054,6 +2031,99 @@ namespace {
20542031 return applyStack.back ().dyn_cast <ApplyExpr *>();
20552032 }
20562033
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:
20572127 const PatternBindingDecl *getTopPatternBindingDecl () const {
20582128 return patternBindingStack.empty () ? nullptr : patternBindingStack.back ();
20592129 }
@@ -3185,27 +3255,58 @@ namespace {
31853255 // If we need to mark the call as implicitly asynchronous, make sure
31863256 // we're in an asynchronous context.
31873257 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+ }
31983287 } 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 ())
32023302 .warnUntilSwiftVersionIf (getContextIsolation ().preconcurrency (), 6 );
3203- }
3303+ }
32043304
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+ }
32093310 }
32103311
32113312 return true ;
@@ -3574,22 +3675,38 @@ namespace {
35743675 bool preconcurrencyContext =
35753676 result.options .contains (ActorReferenceResult::Flags::Preconcurrency);
35763677
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 ));
35923684
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+ }
35933710 return true ;
35943711 }
35953712 }
@@ -3731,9 +3848,11 @@ void swift::checkFunctionActorIsolation(AbstractFunctionDecl *decl) {
37313848 if (decl->getAttrs ().hasAttribute <LLDBDebuggerFunctionAttr>())
37323849 return ;
37333850
3851+ auto &ctx = decl->getASTContext ();
37343852 ActorIsolationChecker checker (decl);
37353853 if (auto body = decl->getBody ()) {
37363854 body->walk (checker);
3855+ if (ctx.LangOpts .hasFeature (Feature::GroupActorErrors)){ checker.diagnoseIsolationErrors (); }
37373856 }
37383857 if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
37393858 if (auto superInit = ctor->getSuperInitCall ())
0 commit comments