Skip to content

Commit d40c37e

Browse files
committed
[Sema/SILGen] Import ObjC async functions as nonisolated(nonsending) by default
These functions already have special code generation that keeps them in the caller's isolation context, so there is no behavior change here. Resolves: rdar://145672343 (cherry picked from commit 07bad98)
1 parent cdc02a4 commit d40c37e

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,8 +1706,12 @@ class DestructureInputs {
17061706

17071707
// If we are an async function that is unspecified or nonisolated, insert an
17081708
// isolated parameter if AsyncCallerExecution is enabled.
1709+
//
1710+
// NOTE: The parameter is not inserted for async functions imported
1711+
// from ObjC because they are handled in a special way that doesn't
1712+
// require it.
17091713
if (IsolationInfo && IsolationInfo->isCallerIsolationInheriting() &&
1710-
extInfoBuilder.isAsync()) {
1714+
extInfoBuilder.isAsync() && !Foreign.async) {
17111715
auto actorProtocol = TC.Context.getProtocol(KnownProtocolKind::Actor);
17121716
auto actorType =
17131717
ExistentialType::get(actorProtocol->getDeclaredInterfaceType());

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5852,6 +5852,18 @@ computeDefaultInferredActorIsolation(ValueDecl *value) {
58525852
// isolation for this decl.
58535853
}
58545854

5855+
// Asynchronous variants for functions imported from ObjC are
5856+
// `nonisolated(nonsending)` by default.
5857+
if (value->hasClangNode()) {
5858+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(value)) {
5859+
if (!isa<ProtocolDecl>(AFD->getDeclContext()) &&
5860+
AFD->getForeignAsyncConvention()) {
5861+
return {
5862+
{ActorIsolation::forCallerIsolationInheriting(), {}}, nullptr, {}};
5863+
}
5864+
}
5865+
}
5866+
58555867
// We did not find anything special, return unspecified.
58565868
return {{ActorIsolation::forUnspecified(), {}}, nullptr, {}};
58575869
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/src)
3+
// RUN: split-file %s %t/src
4+
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \
6+
// RUN: -import-objc-header %t/src/Test.h \
7+
// RUN: -swift-version 6 \
8+
// RUN: -module-name main -I %t -verify
9+
10+
// REQUIRES: objc_interop
11+
12+
//--- Test.h
13+
#define MAIN_ACTOR __attribute__((__swift_attr__("@MainActor")))
14+
15+
#pragma clang assume_nonnull begin
16+
17+
@import Foundation;
18+
19+
@interface Test : NSObject
20+
- (void)loadWithCompletionHandler:(void (^)(void)) completionHandler;
21+
@end
22+
23+
MAIN_ACTOR
24+
@interface TestIsolated : NSObject
25+
- (void)loadWithCompletionHandler:(void (^)(void)) completionHandler;
26+
@end
27+
28+
#pragma clang assume_nonnull end
29+
30+
//--- main.swift
31+
32+
func test(t: Test, i: TestIsolated) async throws {
33+
let fn = t.load // nonisolated(nonsending) () async -> Void
34+
35+
let _: @isolated(any) () async -> Void = fn
36+
// expected-error@-1 {{cannot convert value of type 'nonisolated(nonsending) () async -> Void' to specified type '@isolated(any) () async -> Void'}}
37+
38+
let isolatedFn = i.load
39+
let _: () -> Void = isolatedFn
40+
// expected-error@-1 {{invalid conversion from 'async' function of type '@MainActor @Sendable () async -> Void' to synchronous function type '() -> Void'}}
41+
}

0 commit comments

Comments
 (0)