Skip to content
Open
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
21 changes: 14 additions & 7 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6513,6 +6513,20 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
}
}

// When `NonisolatedNonsendingByDefault` feature is enabled and the value is
// asynchronous `nonisolated` always means `nonisolated(nonsending)`.
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
inferred.isNonisolated() && value->isAsync()) {
// Either current module or async variant of an ObjC API.
if (value->getModuleContext() == ctx.MainModule ||
(value->hasClangNode() &&
!isa<ProtocolDecl>(value->getDeclContext()))) {
inferred =
ActorIsolation::forCallerIsolationInheriting().withPreconcurrency(
inferred.preconcurrency());
}
}

// Add an implicit attribute to capture the actor isolation that was
// inferred, so that (e.g.) it will be printed and serialized.
switch (inferred) {
Expand Down Expand Up @@ -6724,13 +6738,6 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
if (shouldSelfIsolationOverrideDefault(
ctx, value->getDeclContext(), selfTypeIsolation.isolation)) {
auto isolation = selfTypeIsolation.isolation;

if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
value->isAsync() && value->getModuleContext() == ctx.MainModule &&
isolation.isNonisolated()) {
isolation = ActorIsolation::forCallerIsolationInheriting();
}

return {inferredIsolation(isolation, onlyGlobal),
selfTypeIsolation.source};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ public struct InferenceTest {
public func testAutoclosure(value2 fn: nonisolated(nonsending) @autoclosure () async -> Int) async { await fn() }
}

// CHECK: nonisolated extension A.InferenceTest {
// CHECK: nonisolated(nonsending) public func testInExtension() async
// CHECK: @concurrent public func testConcurrentInExtension() async
// CHECK: }
nonisolated public extension InferenceTest {
func testInExtension() async {}
@concurrent func testConcurrentInExtension() async {}
}

// CHECK: public protocol P {
// CHECK: nonisolated(nonsending) func testWitness() async
// CHECK: }
public protocol P {
func testWitness() async
}

// CHECK: public struct WitnessTest : nonisolated A.P {
// CHECK: nonisolated(nonsending) public func testWitness() async
// CHECK: }
public struct WitnessTest: nonisolated P {
public func testWitness() async {}
}

// CHECK: nonisolated public class NoinsolatedClassTest {
// CHECK: nonisolated(nonsending) public func test() async
// CHECK: }
nonisolated public class NoinsolatedClassTest {
public func test() async {}
}

//--- Client.swift
import A

Expand Down Expand Up @@ -75,13 +105,18 @@ func testWithCallback(t: Test) async {
// CHECK: function_ref @$s1A13InferenceTestV10infersAttryyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> ()
// CHECK: function_ref @$s1A13InferenceTestV10testNested8callbackyyyyYaYbYCXEc_tF : $@convention(method) (@guaranteed @callee_guaranteed (@guaranteed @noescape @Sendable @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> (), @in_guaranteed InferenceTest) -> ()
// CHECK: function_ref @$s1A13InferenceTestV10testNested4dictySDySSyyYaYCcSgG_tF : $@convention(method) (@guaranteed Dictionary<String, Optional<nonisolated(nonsending) () async -> ()>>, @in_guaranteed InferenceTest) -> ()
// CHECK: function_ref @$s1A13InferenceTestV15testInExtensionyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> ()
// CHECK: function_ref @$s1A13InferenceTestV25testConcurrentInExtensionyyYaF : $@convention(method) @async (@in_guaranteed InferenceTest) -> ()
// CHECK: } // end sil function '$s6Client13testInference1ty1A0C4TestV_tYaF'
@MainActor
func testInference(t: InferenceTest) async {
await t.infersAttr()

t.testNested { _ in }
t.testNested(dict: [:])

await t.testInExtension()
await t.testConcurrentInExtension()
}

// CHECK-LABEL: sil hidden @$s6Client15testAutoclosure1ty1A13InferenceTestV_tYaF : $@convention(thin) @async (@in_guaranteed InferenceTest) -> ()
Expand All @@ -92,3 +127,17 @@ func testAutoclosure(t: InferenceTest) async {
await t.testAutoclosure(value1: 42)
await t.testAutoclosure(value2: 42)
}

// CHECK-LABEL: sil hidden @$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF : $@convention(thin) @async (@in_guaranteed WitnessTest) -> ()
// CHECK: function_ref @$s1A11WitnessTestV04testA0yyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed WitnessTest) -> ()
// CHECK: } // end sil function '$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF'
func testWitnessWithNonisolated(t: WitnessTest) async {
await t.testWitness()
}

// CHECK-LABEL: sil hidden @$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF : $@convention(thin) @async (@guaranteed NoinsolatedClassTest) -> ()
// CHECK: class_method {{.*}}, #NoinsolatedClassTest.test : (NoinsolatedClassTest) -> () async -> (), $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed NoinsolatedClassTest) -> ()
// CHECK: } // end sil function '$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF'
func testNonisolatedClass(t: NoinsolatedClassTest) async {
await t.test()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/src)
// RUN: split-file %s %t/src

// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil %t/src/main.swift \
// RUN: -import-objc-header %t/src/Test.h \
// RUN: -swift-version 5 \
// RUN: -strict-concurrency=complete \
// RUN: -enable-upcoming-feature NonisolatedNonsendingByDefault \
// RUN: -module-name main -I %t -verify

// REQUIRES: objc_interop
// REQUIRES: concurrency
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault

//--- Test.h
#define SWIFT_NONISOLATED __attribute__((__swift_attr__("nonisolated")))

#pragma clang assume_nonnull begin

@import Foundation;

SWIFT_NONISOLATED
@interface Doc : NSObject
- (void)saveWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler;
@end

SWIFT_NONISOLATED
@interface Doc(Reset)
- (void)resetWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler;
@end

#pragma clang assume_nonnull end

//--- main.swift

final class Test {
let doc = Doc()

func test() async {
_ = await doc.save() // Ok
_ = await doc.reset() // Ok
}
}