Skip to content

Commit f0e77c7

Browse files
committed
[Concurrency] Don't diagnose metatype captures in closures that are
isolated to the same actor as the enclosing context.
1 parent c283ce1 commit f0e77c7

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,7 +2543,8 @@ namespace {
25432543
/// Determine whether code in the given use context might execute
25442544
/// concurrently with code in the definition context.
25452545
bool mayExecuteConcurrentlyWith(
2546-
const DeclContext *useContext, const DeclContext *defContext);
2546+
const DeclContext *useContext, const DeclContext *defContext,
2547+
bool includeSending = false);
25472548

25482549
/// If the subexpression is a reference to a mutable local variable from a
25492550
/// different context, record its parent. We'll query this as part of
@@ -3051,12 +3052,9 @@ namespace {
30513052
}
30523053
}
30533054

3054-
// FIXME: When passing to a sending parameter, should this be handled
3055-
// by region isolation? Or should it always be handled by region
3056-
// isolation?
30573055
if (mayExecuteConcurrentlyWith(
3058-
localFunc.getAsDeclContext(), getDeclContext()) ||
3059-
(explicitClosure && explicitClosure->isPassedToSendingParameter())) {
3056+
localFunc.getAsDeclContext(), getDeclContext(),
3057+
/*includeSending*/true)) {
30603058
auto innermostGenericDC = localFunc.getAsDeclContext();
30613059
while (innermostGenericDC && !innermostGenericDC->isGenericContext())
30623060
innermostGenericDC = innermostGenericDC->getParent();
@@ -4816,7 +4814,8 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
48164814
}
48174815

48184816
bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
4819-
const DeclContext *useContext, const DeclContext *defContext) {
4817+
const DeclContext *useContext, const DeclContext *defContext,
4818+
bool includeSending) {
48204819
// Fast path for when the use and definition contexts are the same.
48214820
if (useContext == defContext)
48224821
return false;
@@ -4847,6 +4846,10 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
48474846
if (closure->isSendable())
48484847
return true;
48494848

4849+
if (auto *explicitClosure = dyn_cast<ClosureExpr>(closure)) {
4850+
if (includeSending && explicitClosure->isPassedToSendingParameter())
4851+
return true;
4852+
}
48504853
}
48514854

48524855
if (auto func = dyn_cast<FuncDecl>(useContext)) {

test/Concurrency/sendable_metatype_typecheck.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,16 @@ extension TestUnapplied {
175175
func testUnappliedWithOpetator<T: Comparable>(v: TestUnapplied<T>) {
176176
v<=>(>) // expected-error {{converting non-Sendable function value to '@Sendable (T, T) -> Bool' may introduce data races}}
177177
}
178+
179+
protocol P {}
180+
181+
func acceptClosure(_: () -> Void) {}
182+
183+
@MainActor
184+
func f<T: P>(_: T.Type) {
185+
acceptClosure {
186+
Task {
187+
_ = T.self // okay to capture T.Type in this closure.
188+
}
189+
}
190+
}

0 commit comments

Comments
 (0)