Skip to content

Commit 214b8d8

Browse files
authored
Merge pull request #81860 from hborla/isolated-capture-fixes
[Concurrency] Fix a false-positive metatype capture diagnostic.
2 parents 31fe75b + f0e77c7 commit 214b8d8

File tree

2 files changed

+23
-24
lines changed

2 files changed

+23
-24
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 10 additions & 24 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,13 +4814,12 @@ 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;
48234822

4824-
bool isolatedStateMayEscape = false;
4825-
48264823
auto useIsolation = getActorIsolationOfContext(
48274824
const_cast<DeclContext *>(useContext), getClosureActorIsolation);
48284825
if (useIsolation.isActorIsolated()) {
@@ -4840,16 +4837,6 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
48404837
if (ctx.LangOpts.hasFeature(Feature::GlobalActorIsolatedTypesUsability) &&
48414838
regionIsolationEnabled && useIsolation.isGlobalActor())
48424839
return false;
4843-
4844-
// If the local function is not Sendable, its isolation differs
4845-
// from that of the context, and both contexts are actor isolated,
4846-
// then capturing non-Sendable values allows the closure to stash
4847-
// those values into actor-isolated state. The original context
4848-
// may also stash those values into isolated state, enabling concurrent
4849-
// access later on.
4850-
isolatedStateMayEscape =
4851-
(!regionIsolationEnabled &&
4852-
useIsolation.isActorIsolated() && defIsolation.isActorIsolated());
48534840
}
48544841

48554842
// Walk the context chain from the use to the definition.
@@ -4859,18 +4846,17 @@ bool ActorIsolationChecker::mayExecuteConcurrentlyWith(
48594846
if (closure->isSendable())
48604847
return true;
48614848

4862-
if (isolatedStateMayEscape)
4863-
return true;
4849+
if (auto *explicitClosure = dyn_cast<ClosureExpr>(closure)) {
4850+
if (includeSending && explicitClosure->isPassedToSendingParameter())
4851+
return true;
4852+
}
48644853
}
48654854

48664855
if (auto func = dyn_cast<FuncDecl>(useContext)) {
48674856
if (func->isLocalCapture()) {
48684857
// If the function is @Sendable... it can be run concurrently.
48694858
if (func->isSendable())
48704859
return true;
4871-
4872-
if (isolatedStateMayEscape)
4873-
return true;
48744860
}
48754861
}
48764862

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)