mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
use local funcs to implement `defer`, this also fixes several bugs with that feature, such as it breaking in nonisolated functions when a default isolation is in effect in the source file. Change how we compute isolation of local funcs. The rule here is supposed to be that non-`@Sendable` local funcs are isolated the same as their enclosing context. Unlike closure expressions, this is unconditional: in instance-isolated functions, the isolation does not depend on whether `self` is captured. But the computation was wrong: it didn't translate global actor isolation between contexts, it didn't turn parameter isolation into capture isolation, and it fell through for several other kinds of parent isolation, causing the compiler to try to apply default isolation instead. I've extracted the logic from the closure expression path into a common function and used it for both paths. The capture computation logic was forcing a capture of the enclosing isolation in local funcs, but only for async functions. Presumably this was conditional because async functions need the isolation for actor hops, but sync functions don't really need it. However, this was causing crashes with `-enable-actor-data-race-checks`. (I didn't investigate whether it also failed with the similar assertion we do with preconcurrency.) For now, I've switched this to capture the isolated instance unconditionally. If we need to be more conservative by either only capturing when data-race checks are enabled or disabling the checks when the isolation isn't captured, we can look into that. Fix a bug in capture isolation checking. We were ignoring captures of nonisolated declarations in order to implement the rule that permits `nonisolated(unsafe)` variables to be captured in non-sendable closures. This check needs to only apply to variables! The isolation of a local func has nothing to do with its sendability as a capture. That fix exposed a problem where we were being unnecessarily restrictive with generic local func declarations because we didn't consider them to have sendable type. This was true even if the genericity was purely from being declared in a generic context, but it doesn't matter, they ought to be sendable regardless. Finally, fix a handful of bugs where global actor types were not remapped properly in SILGen.
63 lines
1.9 KiB
Swift
63 lines
1.9 KiB
Swift
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple %s -emit-sil -o - -verify -strict-concurrency=complete -enable-actor-data-race-checks -disable-availability-checking | %FileCheck %s
|
|
|
|
// Issue #80772. This used to crash in SILGen because we gave local functions
|
|
// the isolation of their enclosing context instead of trying to convert
|
|
// parameter isolation to capture isolation.
|
|
actor TestActor {
|
|
// CHECK-LABEL: // nested #1 () in TestActor.testWithoutCapture()
|
|
// CHECK-NEXT: // Isolation: actor_instance. name: 'self'
|
|
func testWithoutCapture() {
|
|
func nested() -> String {
|
|
return "test"
|
|
}
|
|
|
|
print(nested())
|
|
}
|
|
|
|
// CHECK-LABEL: // nested #1 () in TestActor.testWithCapture()
|
|
// CHECK-NEXT: // Isolation: actor_instance. name: 'self'
|
|
// CHECK: [[SELF_EXECUTOR:%.*]] = extract_executor %0
|
|
// CHECK: [[CHECK_FN:%.*]] = function_ref @swift_task_isCurrentExecutor
|
|
// CHECK: apply [[CHECK_FN]]([[SELF_EXECUTOR]])
|
|
func testWithCapture() {
|
|
func nested() -> String {
|
|
_ = self
|
|
return "test"
|
|
}
|
|
|
|
print(nested())
|
|
}
|
|
}
|
|
|
|
@globalActor struct GenericGlobalActor<T> {
|
|
static var shared: TestActor {
|
|
// not a valid implementation
|
|
return TestActor()
|
|
}
|
|
}
|
|
|
|
struct Generic<T> {
|
|
// CHECK-LABEL: // nested #1 <A><A1>(_:) in Generic.testGenericGlobalActor()
|
|
// CHECK-NEXT: // Isolation: global_actor. type: GenericGlobalActor<T>
|
|
@GenericGlobalActor<T> func testGenericGlobalActor() {
|
|
func nested<U>(_ type: U.Type) -> String {
|
|
// CHECK: [[FN:%.*]] = function_ref @$s15local_functions18GenericGlobalActorV6sharedAA04TestE0CvgZ
|
|
// CHECK: apply [[FN]]<T>(
|
|
return "test"
|
|
}
|
|
|
|
print(nested(Int.self))
|
|
}
|
|
}
|
|
|
|
actor MyActor {
|
|
// CHECK-LABEL: // nested #1 () in MyActor.deinit
|
|
// CHECK-NEXT: // Isolation: actor_instance. name: 'self'
|
|
isolated deinit {
|
|
func nested() -> String {
|
|
return "test"
|
|
}
|
|
print(nested())
|
|
}
|
|
}
|