Skip to content

[concurrency] Inherit caller isolation inheriting when inferring isolation from a nominal type context for a method on the nominal type. #78665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5950,10 +5950,19 @@ InferredActorIsolation ActorIsolationRequest::evaluate(
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
auto selfTypeIsolation = getInferredActorIsolation(selfTypeDecl);
if (selfTypeIsolation.isolation) {
return {
inferredIsolation(selfTypeIsolation.isolation, onlyGlobal),
selfTypeIsolation.source
};
auto isolation = selfTypeIsolation.isolation;

if (auto *func = dyn_cast<AbstractFunctionDecl>(value);
ctx.LangOpts.hasFeature(
Feature::NonIsolatedAsyncInheritsIsolationFromContext) &&
func && func->hasAsync() &&
func->getModuleContext() == ctx.MainModule &&
isolation.isNonisolated()) {
isolation = ActorIsolation::forCallerIsolationInheriting();
}

return {inferredIsolation(isolation, onlyGlobal),
selfTypeIsolation.source};
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions test/Concurrency/nonisolated_inherits_isolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@

class NonSendableKlass {}

nonisolated class NonIsolatedNonSendableKlass {
func unspecifiedMethod() async {}
nonisolated func nonisolatedMethod() async {}
}

func unspecifiedSyncUse<T>(_ t: T) {}
func unspecifiedAsyncUse<T>(_ t: T) async {}
nonisolated func nonisolatedSyncUse<T>(_ t: T) {}
Expand Down Expand Up @@ -148,3 +153,17 @@ class MainActorKlass {
// expected-enabled-note @-1 {{sending main actor-isolated 'x4' to global actor 'CustomActor'-isolated global function 'sendToCustom' risks causing data races between global actor 'CustomActor'-isolated and main actor-isolated uses}}
}
}

// We should not error on either of these since c is in the main actor's region
// and our nonisolated/unspecified methods are inheriting the main actor
// isolation which is safe since they are type checked as something that cannot
// access any state that is outside of the current actor that c is reachable from.
@MainActor
func validateNonisolatedOnClassMeansCallerIsolationInheritingOnFuncDecl(
c: NonIsolatedNonSendableKlass
) async {
await c.unspecifiedMethod() // expected-disabled-error {{sending 'c' risks causing data races}}
// expected-disabled-note @-1 {{sending main actor-isolated 'c' to nonisolated instance method 'unspecifiedMethod()' risks causing data races between nonisolated and main actor-isolated uses}}
await c.nonisolatedMethod() // expected-disabled-error {{sending 'c' risks causing data races}}
// expected-disabled-note @-1 {{sending main actor-isolated 'c' to nonisolated instance method 'nonisolatedMethod()' risks causing data races between nonisolated and main actor-isolated uses}}
}