From efc6efc4ed45e17595172018bb3db953db790197 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 21 May 2025 13:48:43 -0700 Subject: [PATCH] [CSApply] Don't inject global actor into closure type if it's marked as `@concurrent` When the attribute is specified explicitly passing a `@concurrent` closure to a global actor-isolated parameter or contextual type should result in a conversion and closure itself should be nonisolated. Resolves: rdar://151797372 --- lib/Sema/CSApply.cpp | 10 ++++++---- .../attr_execution/conversions_silgen.swift | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index d0d04ff1a406a..1e9396ea2f993 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -7731,11 +7731,13 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, } // If we have a ClosureExpr, then we can safely propagate a global actor - // to the closure without invalidating prior analysis. + // to the closure if it's not explicitly marked as `@concurrent` without + // invalidating prior analysis. fromEI = fromFunc->getExtInfo(); - if (toEI.getGlobalActor() && !fromEI.getGlobalActor()) { - auto newFromFuncType = fromFunc->withExtInfo( - fromEI.withGlobalActor(toEI.getGlobalActor())); + if (toEI.getGlobalActor() && !fromEI.getGlobalActor() && + !isClosureMarkedAsConcurrent(expr)) { + auto newFromFuncType = + fromFunc->withExtInfo(fromEI.withGlobalActor(toEI.getGlobalActor())); if (applyTypeToClosureExpr(cs, expr, newFromFuncType)) { fromFunc = newFromFuncType->castTo(); diff --git a/test/Concurrency/attr_execution/conversions_silgen.swift b/test/Concurrency/attr_execution/conversions_silgen.swift index f6389f5ea2451..358ab0eeeb748 100644 --- a/test/Concurrency/attr_execution/conversions_silgen.swift +++ b/test/Concurrency/attr_execution/conversions_silgen.swift @@ -462,3 +462,14 @@ func testNoIsolationTransfer() { // CHECK: hop_to_executor [[GENERIC_EXECUTOR]] testErasure { @concurrent in } } + +func testClosuresDontAssumeGlobalActorWithMarkedAsConcurrent() { + func test(_ fn: @MainActor () async -> Void) {} + + // CHECK-LABEL: sil private [ossa] @$s21attr_execution_silgen55testClosuresDontAssumeGlobalActorWithMarkedAsConcurrentyyFyyYaYbXEfU_ + // CHECK: [[GENERIC_EXECUTOR:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK-NEXT: hop_to_executor [[GENERIC_EXECUTOR]] + // CHECK: } // end sil function '$s21attr_execution_silgen55testClosuresDontAssumeGlobalActorWithMarkedAsConcurrentyyFyyYaYbXEfU_' + test { @Sendable @concurrent in + } +}