@@ -958,68 +958,69 @@ namespace {
958
958
// / \returns true if we diagnosed the entity, \c false otherwise.
959
959
bool diagnoseInOutArg (const ApplyExpr *call, const InOutExpr *arg,
960
960
bool isPartialApply) {
961
-
962
961
// check that the call is actually async
963
962
if (!isAsyncCall (call))
964
963
return false ;
965
964
966
- Expr *subArg = arg->getSubExpr ();
967
- ValueDecl *valueDecl = nullptr ;
968
- if (auto binding = dyn_cast<BindOptionalExpr>(subArg))
969
- subArg = binding->getSubExpr ();
970
- if (LookupExpr *baseArg = dyn_cast<LookupExpr>(subArg)) {
971
- while (LookupExpr *nextLayer = dyn_cast<LookupExpr>(baseArg->getBase ()))
972
- baseArg = nextLayer;
973
- // subArg: the actual property being passed inout
974
- // baseArg: the property in the actor who's property is being passed
975
- // inout
976
-
977
- valueDecl = baseArg->getMember ().getDecl ();
978
- } else if (DeclRefExpr *declExpr = dyn_cast<DeclRefExpr>(subArg)) {
979
- valueDecl = declExpr->getDecl ();
980
- } else {
981
- llvm_unreachable (" Inout argument is neither a lookup nor decl." );
982
- }
983
- assert (valueDecl != nullptr && " valueDecl was never set!" );
984
- auto isolation = ActorIsolationRestriction::forDeclaration (valueDecl);
985
- switch (isolation) {
986
- case ActorIsolationRestriction::Unrestricted:
987
- case ActorIsolationRestriction::LocalCapture:
988
- case ActorIsolationRestriction::Unsafe:
989
- break ;
990
- case ActorIsolationRestriction::GlobalActor: {
991
- ctx.Diags .diagnose (call->getLoc (),
992
- diag::actor_isolated_inout_state,
993
- valueDecl->getDescriptiveKind (),
994
- valueDecl->getName (),
995
- call->implicitlyAsync ());
996
- valueDecl->diagnose (diag::kind_declared_here,
997
- valueDecl->getDescriptiveKind ());
998
- return true ;
999
- }
1000
- case ActorIsolationRestriction::ActorSelf: {
1001
- if (isPartialApply) {
1002
- // The partially applied InoutArg is a property of actor. This can
1003
- // really only happen when the property is a struct with a mutating
1004
- // async method.
1005
- if (auto partialApply = dyn_cast<ApplyExpr>(call->getFn ())) {
1006
- ValueDecl *fnDecl =
1007
- cast<DeclRefExpr>(partialApply->getFn ())->getDecl ();
1008
- ctx.Diags .diagnose (
1009
- call->getLoc (), diag::actor_isolated_mutating_func,
1010
- fnDecl->getName (), valueDecl->getDescriptiveKind (),
1011
- valueDecl->getName ());
1012
- return true ;
965
+ bool result = false ;
966
+ auto checkDiagnostic = [this , call, isPartialApply,
967
+ &result](ValueDecl *decl, SourceLoc argLoc) {
968
+ auto isolation = ActorIsolationRestriction::forDeclaration (decl);
969
+ switch (isolation) {
970
+ case ActorIsolationRestriction::Unrestricted:
971
+ case ActorIsolationRestriction::LocalCapture:
972
+ case ActorIsolationRestriction::Unsafe:
973
+ break ;
974
+ case ActorIsolationRestriction::GlobalActor: {
975
+ ctx.Diags .diagnose (argLoc, diag::actor_isolated_inout_state,
976
+ decl->getDescriptiveKind (), decl->getName (),
977
+ call->implicitlyAsync ());
978
+ decl->diagnose (diag::kind_declared_here, decl->getDescriptiveKind ());
979
+ result = true ;
980
+ break ;
981
+ }
982
+ case ActorIsolationRestriction::ActorSelf: {
983
+ if (isPartialApply) {
984
+ // The partially applied InoutArg is a property of actor. This
985
+ // can really only happen when the property is a struct with a
986
+ // mutating async method.
987
+ if (auto partialApply = dyn_cast<ApplyExpr>(call->getFn ())) {
988
+ ValueDecl *fnDecl =
989
+ cast<DeclRefExpr>(partialApply->getFn ())->getDecl ();
990
+ ctx.Diags .diagnose (call->getLoc (),
991
+ diag::actor_isolated_mutating_func,
992
+ fnDecl->getName (), decl->getDescriptiveKind (),
993
+ decl->getName ());
994
+ result = true ;
995
+ }
996
+ } else {
997
+ ctx.Diags .diagnose (argLoc, diag::actor_isolated_inout_state,
998
+ decl->getDescriptiveKind (), decl->getName (),
999
+ call->implicitlyAsync ());
1000
+ result = true ;
1013
1001
}
1014
- } else {
1015
- ctx.Diags .diagnose (
1016
- subArg->getLoc (), diag::actor_isolated_inout_state,
1017
- valueDecl->getDescriptiveKind (), valueDecl->getName (), call->implicitlyAsync ());
1018
- return true ;
1002
+ break ;
1019
1003
}
1020
- }
1021
- }
1022
- return false ;
1004
+ }
1005
+ };
1006
+ auto expressionWalker = [baseArg = arg->getSubExpr (),
1007
+ checkDiagnostic](Expr *expr) -> Expr * {
1008
+ if (isa<InOutExpr>(expr))
1009
+ return nullptr ; // AST walker will hit this again
1010
+ if (LookupExpr *lookup = dyn_cast<LookupExpr>(expr)) {
1011
+ if (isa<DeclRefExpr>(lookup->getBase ())) {
1012
+ checkDiagnostic (lookup->getMember ().getDecl (), baseArg->getLoc ());
1013
+ return nullptr ; // Diagnosed. Don't keep walking
1014
+ }
1015
+ }
1016
+ if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
1017
+ checkDiagnostic (declRef->getDecl (), baseArg->getLoc ());
1018
+ return nullptr ; // Diagnosed. Don't keep walking
1019
+ }
1020
+ return expr;
1021
+ };
1022
+ arg->getSubExpr ()->forEachChildExpr (expressionWalker);
1023
+ return result;
1023
1024
}
1024
1025
1025
1026
// / Get the actor isolation of the innermost relevant context.
0 commit comments