@@ -556,20 +556,30 @@ findReference(Expr *expr) {
556556// /
557557// / Note that this must be called after the implicitlyAsync flag has been set,
558558// / or implicitly async calls will not return the correct value.
559- static bool isAsyncCall (const ApplyExpr *call) {
560- if (call->isImplicitlyAsync ())
559+ static bool isAsyncCall (
560+ llvm::PointerUnion<ApplyExpr *, LookupExpr *> call) {
561+
562+ if (auto *apply = call.dyn_cast <ApplyExpr *>()) {
563+ if (apply->isImplicitlyAsync ())
564+ return true ;
565+
566+ // Effectively the same as doing a
567+ // `cast_or_null<FunctionType>(call->getFn()->getType())`, check the
568+ // result of that and then checking `isAsync` if it's defined.
569+ Type funcTypeType = apply->getFn ()->getType ();
570+ if (!funcTypeType)
571+ return false ;
572+ AnyFunctionType *funcType = funcTypeType->getAs <AnyFunctionType>();
573+ if (!funcType)
574+ return false ;
575+ return funcType->isAsync ();
576+ }
577+
578+ auto *lookup = call.get <LookupExpr *>();
579+ if (lookup->isImplicitlyAsync ())
561580 return true ;
562581
563- // Effectively the same as doing a
564- // `cast_or_null<FunctionType>(call->getFn()->getType())`, check the
565- // result of that and then checking `isAsync` if it's defined.
566- Type funcTypeType = call->getFn ()->getType ();
567- if (!funcTypeType)
568- return false ;
569- AnyFunctionType *funcType = funcTypeType->getAs <AnyFunctionType>();
570- if (!funcType)
571- return false ;
572- return funcType->isAsync ();
582+ return isAsyncDecl (lookup->getDecl ());
573583}
574584
575585// / Determine whether we should diagnose data races within the current context.
@@ -1932,7 +1942,7 @@ namespace {
19321942 class ActorIsolationChecker : public ASTWalker {
19331943 ASTContext &ctx;
19341944 SmallVector<const DeclContext *, 4 > contextStack;
1935- SmallVector<ApplyExpr* , 4 > applyStack;
1945+ SmallVector<llvm::PointerUnion< ApplyExpr *, LookupExpr *> , 4 > applyStack;
19361946 SmallVector<std::pair<OpaqueValueExpr *, Expr *>, 4 > opaqueValues;
19371947 SmallVector<const PatternBindingDecl *, 2 > patternBindingStack;
19381948 llvm::function_ref<Type(Expr *)> getType;
@@ -1950,6 +1960,13 @@ namespace {
19501960 using MutableVarParent
19511961 = llvm::PointerUnion<InOutExpr *, LoadExpr *, AssignExpr *>;
19521962
1963+ ApplyExpr *getImmediateApply () const {
1964+ if (applyStack.empty ())
1965+ return nullptr ;
1966+
1967+ return applyStack.back ().dyn_cast <ApplyExpr *>();
1968+ }
1969+
19531970 const PatternBindingDecl *getTopPatternBindingDecl () const {
19541971 return patternBindingStack.empty () ? nullptr : patternBindingStack.back ();
19551972 }
@@ -2207,7 +2224,7 @@ namespace {
22072224
22082225 const auto End = applyStack.rend ();
22092226 for (auto I = applyStack.rbegin (); I != End; ++I)
2210- if (auto call = dyn_cast<CallExpr>(*I )) {
2227+ if (auto call = dyn_cast<CallExpr>(I-> dyn_cast <ApplyExpr *>() )) {
22112228 if (setAsync) {
22122229 call->setImplicitlyAsync (*setAsync);
22132230 }
@@ -2261,6 +2278,11 @@ namespace {
22612278 }
22622279
22632280 PreWalkResult<Expr *> walkToExprPre (Expr *expr) override {
2281+ // Skip expressions that didn't make it to solution application
2282+ // because the constraint system diagnosed an error.
2283+ if (!expr->getType ())
2284+ return Action::SkipChildren (expr);
2285+
22642286 if (auto *openExistential = dyn_cast<OpenExistentialExpr>(expr)) {
22652287 opaqueValues.push_back ({
22662288 openExistential->getOpaqueValue (),
@@ -2295,6 +2317,7 @@ namespace {
22952317 recordMutableVarParent (load, load->getSubExpr ());
22962318
22972319 if (auto lookup = dyn_cast<LookupExpr>(expr)) {
2320+ applyStack.push_back (lookup);
22982321 checkReference (lookup->getBase (), lookup->getMember (), lookup->getLoc (),
22992322 /* partialApply*/ llvm::None, lookup);
23002323 return Action::Continue (expr);
@@ -2337,7 +2360,7 @@ namespace {
23372360 // Self applications are checked as part of the outer call.
23382361 // However, we look for inout issues here.
23392362 if (applyStack.size () >= 2 ) {
2340- ApplyExpr * outerCall = applyStack[applyStack.size () - 2 ];
2363+ auto outerCall = applyStack[applyStack.size () - 2 ];
23412364 if (isAsyncCall (outerCall)) {
23422365 // This call is a partial application within an async call.
23432366 // If the partial application take a value inout, it is bad.
@@ -2391,17 +2414,21 @@ namespace {
23912414 }
23922415
23932416 if (auto *apply = dyn_cast<ApplyExpr>(expr)) {
2394- assert (applyStack.back () == apply);
2417+ assert (applyStack.back (). get <ApplyExpr *>() == apply);
23952418 applyStack.pop_back ();
23962419 }
23972420
23982421 // Clear out the mutable local variable parent map on the way out.
2399- if (auto *declRefExpr = dyn_cast<DeclRefExpr>(expr))
2422+ if (auto *declRefExpr = dyn_cast<DeclRefExpr>(expr)) {
24002423 mutableLocalVarParent.erase (declRefExpr);
2401- else if (auto *lookupExpr = dyn_cast<LookupExpr>(expr))
2424+ } else if (auto *lookupExpr = dyn_cast<LookupExpr>(expr)) {
24022425 mutableLocalVarParent.erase (lookupExpr);
2403- else if (auto *inoutExpr = dyn_cast<InOutExpr>(expr))
2426+
2427+ assert (applyStack.back ().dyn_cast <LookupExpr *>() == lookupExpr);
2428+ applyStack.pop_back ();
2429+ } else if (auto *inoutExpr = dyn_cast<InOutExpr>(expr)) {
24042430 mutableLocalVarParent.erase (inoutExpr);
2431+ }
24052432
24062433 // Remove the tracked capture contexts.
24072434 if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
@@ -2616,28 +2643,31 @@ namespace {
26162643 // / Diagnose an inout argument passed into an async call
26172644 // /
26182645 // / \returns true if we diagnosed the entity, \c false otherwise.
2619- bool diagnoseInOutArg (const ApplyExpr *call, const InOutExpr *arg,
2620- bool isPartialApply) {
2646+ bool diagnoseInOutArg (
2647+ llvm::PointerUnion<ApplyExpr *, LookupExpr *> call,
2648+ const InOutExpr *arg,
2649+ bool isPartialApply) {
26212650 // check that the call is actually async
26222651 if (!isAsyncCall (call))
26232652 return false ;
26242653
26252654 bool result = false ;
2626- auto checkDiagnostic = [this , call, isPartialApply, &result](
2655+ auto diagnoseIsolatedInoutState = [this , call, isPartialApply, &result](
26272656 ConcreteDeclRef declRef, SourceLoc argLoc) {
26282657 auto decl = declRef.getDecl ();
26292658 auto isolation = getActorIsolationForReference (decl, getDeclContext ());
26302659 if (!isolation.isActorIsolated ())
26312660 return ;
26322661
26332662 if (isPartialApply) {
2663+ auto *apply = call.get <ApplyExpr *>();
26342664 // The partially applied InoutArg is a property of actor. This
26352665 // can really only happen when the property is a struct with a
26362666 // mutating async method.
2637- if (auto partialApply = dyn_cast<ApplyExpr>(call ->getFn ())) {
2667+ if (auto partialApply = dyn_cast<ApplyExpr>(apply ->getFn ())) {
26382668 if (auto declRef = dyn_cast<DeclRefExpr>(partialApply->getFn ())) {
26392669 ValueDecl *fnDecl = declRef->getDecl ();
2640- ctx.Diags .diagnose (call ->getLoc (),
2670+ ctx.Diags .diagnose (apply ->getLoc (),
26412671 diag::actor_isolated_mutating_func,
26422672 fnDecl->getName (), decl);
26432673 result = true ;
@@ -2646,29 +2676,36 @@ namespace {
26462676 }
26472677 }
26482678
2679+ bool isImplicitlyAsync;
2680+ if (auto *apply = call.dyn_cast <ApplyExpr *>()) {
2681+ isImplicitlyAsync = apply->isImplicitlyAsync ().has_value ();
2682+ } else {
2683+ auto *lookup = call.get <LookupExpr *>();
2684+ isImplicitlyAsync = lookup->isImplicitlyAsync ().has_value ();
2685+ }
2686+
26492687 ctx.Diags .diagnose (argLoc, diag::actor_isolated_inout_state,
2650- decl, call-> isImplicitlyAsync (). has_value () );
2688+ decl, isImplicitlyAsync);
26512689 decl->diagnose (diag::kind_declared_here, decl->getDescriptiveKind ());
26522690 result = true ;
26532691 return ;
26542692 };
2655- auto expressionWalker = [baseArg = arg->getSubExpr (),
2656- checkDiagnostic](Expr *expr) -> Expr * {
2657- if (isa<InOutExpr>(expr))
2658- return nullptr ; // AST walker will hit this again
2693+
2694+ auto findIsolatedState = [&](Expr *expr) -> Expr * {
26592695 if (LookupExpr *lookup = dyn_cast<LookupExpr>(expr)) {
26602696 if (isa<DeclRefExpr>(lookup->getBase ())) {
2661- checkDiagnostic (lookup->getMember ().getDecl (), baseArg->getLoc ());
2697+ diagnoseIsolatedInoutState (lookup->getMember ().getDecl (),
2698+ expr->getLoc ());
26622699 return nullptr ; // Diagnosed. Don't keep walking
26632700 }
26642701 }
26652702 if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
2666- checkDiagnostic (declRef->getDecl (), baseArg ->getLoc ());
2703+ diagnoseIsolatedInoutState (declRef->getDecl (), expr ->getLoc ());
26672704 return nullptr ; // Diagnosed. Don't keep walking
26682705 }
26692706 return expr;
26702707 };
2671- arg->getSubExpr ()->forEachChildExpr (expressionWalker );
2708+ arg->getSubExpr ()->forEachChildExpr (findIsolatedState );
26722709 return result;
26732710 }
26742711
@@ -3172,9 +3209,9 @@ namespace {
31723209
31733210 // If this declaration is a callee from the enclosing application,
31743211 // it's already been checked via the call.
3175- if (!applyStack. empty ()) {
3212+ if (auto *apply = getImmediateApply ()) {
31763213 auto immediateCallee =
3177- applyStack. back () ->getCalledValue (/* skipFunctionConversions=*/ true );
3214+ apply ->getCalledValue (/* skipFunctionConversions=*/ true );
31783215 if (decl == immediateCallee)
31793216 return false ;
31803217 }
0 commit comments