Skip to content

Commit 8e78c8b

Browse files
committed
[CSApply] Propagate 'async' from contextual types to closures, unless the closure
is an argument to a 'reasync' function.
1 parent 50373c5 commit 8e78c8b

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

lib/Sema/CSApply.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ASTVisitor.h"
2626
#include "swift/AST/ASTWalker.h"
2727
#include "swift/AST/ClangModuleLoader.h"
28+
#include "swift/AST/Effects.h"
2829
#include "swift/AST/ExistentialLayout.h"
2930
#include "swift/AST/GenericEnvironment.h"
3031
#include "swift/AST/GenericSignature.h"
@@ -7043,6 +7044,38 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
70437044
}
70447045
}
70457046

7047+
/// Whether the given effect should be propagated to a closure expression.
7048+
auto shouldApplyEffect = [&](EffectKind kind) -> bool {
7049+
auto last = locator.last();
7050+
if (!(last && last->is<LocatorPathElt::ApplyArgToParam>()))
7051+
return true;
7052+
7053+
// The effect should not be applied if the closure is an argument
7054+
// to a function where that effect is polymorphic.
7055+
if (auto *call = getAsExpr<ApplyExpr>(locator.getAnchor())) {
7056+
if (auto *declRef = dyn_cast<DeclRefExpr>(call->getFn())) {
7057+
if (auto *fn = dyn_cast<AbstractFunctionDecl>(declRef->getDecl()))
7058+
return !fn->hasPolymorphicEffect(kind);
7059+
}
7060+
}
7061+
7062+
return true;
7063+
};
7064+
7065+
// If we have a ClosureExpr, we can safely propagate 'async' to the closure.
7066+
fromEI = fromFunc->getExtInfo();
7067+
if (toEI.isAsync() && !fromEI.isAsync() && shouldApplyEffect(EffectKind::Async)) {
7068+
auto newFromFuncType = fromFunc->withExtInfo(fromEI.withAsync());
7069+
if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) {
7070+
fromFunc = newFromFuncType->castTo<FunctionType>();
7071+
7072+
// Propagating 'async' might have satisfied the entire conversion.
7073+
// If so, we're done, otherwise keep converting.
7074+
if (fromFunc->isEqual(toType))
7075+
return expr;
7076+
}
7077+
}
7078+
70467079
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
70477080
// bit to the closure without invalidating prior analysis.
70487081
fromEI = fromFunc->getExtInfo();

test/Concurrency/actor_isolation.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ actor MyActor: MySuperActor { // expected-error{{actor types do not support inhe
7171
class func synchronousClass() { }
7272
static func synchronousStatic() { }
7373

74-
func synchronous() -> String { text.first ?? "nothing" } // expected-note 20{{calls to instance method 'synchronous()' from outside of its actor context are implicitly asynchronous}}
74+
func synchronous() -> String { text.first ?? "nothing" } // expected-note 19{{calls to instance method 'synchronous()' from outside of its actor context are implicitly asynchronous}}
7575
func asynchronous() async -> String {
7676
super.superState += 4
7777
return synchronous()
@@ -807,7 +807,8 @@ func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable
807807
extension MyActor {
808808
func testSendableAndInheriting() {
809809
acceptAsyncSendableClosure {
810-
synchronous() // expected-error{{actor-isolated instance method 'synchronous()' cannot be referenced from a concurrent closure}}
810+
synchronous() // expected-error{{expression is 'async' but is not marked with 'await'}}
811+
// expected-note@-1 {{call is 'async'}}
811812
}
812813

813814
acceptAsyncSendableClosure {

test/Concurrency/global_actor_inference.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ func acceptClosure<T>(_: () -> T) { }
509509
// ----------------------------------------------------------------------
510510
func takesUnsafeMainActor(@_unsafeMainActor fn: () -> Void) { }
511511

512-
@MainActor func onlyOnMainActor() { } // expected-note{{calls to global function 'onlyOnMainActor()' from outside of its actor context are implicitly asynchronous}}
512+
@MainActor func onlyOnMainActor() { }
513513

514514
func useUnsafeMainActor() {
515515
takesUnsafeMainActor {
@@ -525,7 +525,8 @@ func acceptAsyncSendableClosureInheriting<T>(@_inheritActorContext _: @Sendable
525525

526526
@MainActor func testCallFromMainActor() {
527527
acceptAsyncSendableClosure {
528-
onlyOnMainActor() // expected-error{{call to main actor-isolated global function 'onlyOnMainActor()' in a synchronous nonisolated context}}
528+
onlyOnMainActor() // expected-error{{expression is 'async' but is not marked with 'await'}}
529+
// expected-note@-1 {{call is 'async'}}
529530
}
530531

531532
acceptAsyncSendableClosure {

0 commit comments

Comments
 (0)