Files
swift-mirror/test/Concurrency/sendable_checking_captures_swift5.swift
Pavel Yaskevich 3ae34e8e68 [Concurrency] Fix @Sendable closures not inferring nonisolated(nonsending)
If there are no explicit concurrency attributes, isolated parameters,
or captures associated with the closure it should infer `nonisolated(nonsending)`
for the parent conversion injected by the solver (this conversion is injected
because the solver cannot check captures to elide it).

The change pushes `isIsolationInferenceBoundaryClosure` check down
with added benefit of getting preconcurrency context from the parent.
2025-09-04 16:51:45 -07:00

97 lines
2.9 KiB
Swift

// RUN: %target-typecheck-verify-swift -swift-version 5
// RUN: %target-typecheck-verify-swift -swift-version 5 -strict-concurrency=complete -verify-additional-prefix complete-
class NonSendable {} // expected-complete-note 3{{class 'NonSendable' does not conform to the 'Sendable' protocol}}
func callee(_: @Sendable () -> NonSendable) {}
var testLocalCaptures: Int {
let ns = NonSendable()
@Sendable func localFunc() -> NonSendable {
return ns // expected-complete-warning {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' local function}}
}
callee { return ns } // expected-complete-warning {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' closure}}
return 3
}
struct Bad {
var c: Int = {
let ns = NonSendable()
callee { return ns } // expected-complete-warning {{capture of 'ns' with non-Sendable type 'NonSendable' in a '@Sendable' closure}}
return 3
}()
}
do {
class Test { // expected-complete-note 2 {{class 'Test' does not conform to the 'Sendable' protocol}}
func update() {}
}
func sendable(_: @Sendable () -> Void) {}
@preconcurrency
func sendable_preconcurrency(_: @Sendable () -> Void) {}
func withMutable(_: (inout Test) -> Void) {}
withMutable { test in
sendable {
test.update()
// expected-complete-warning@-1 {{capture of 'test' with non-Sendable type 'Test' in a '@Sendable' closure}}
// expected-warning@-2 {{mutable capture of 'inout' parameter 'test' is not allowed in concurrently-executing code}}
}
sendable_preconcurrency {
test.update()
// expected-complete-warning@-1 {{capture of 'test' with non-Sendable type 'Test' in a '@Sendable' closure}}
// expected-complete-warning@-2 {{mutable capture of 'inout' parameter 'test' is not allowed in concurrently-executing code}}
}
}
}
class NotSendable {} // expected-complete-note {{class 'NotSendable' does not conform to the 'Sendable' protocol}}
@available(*, unavailable)
extension NotSendable : @unchecked Sendable {}
@preconcurrency func withSendableClosure(_: @Sendable () -> Void) {}
func testPreconcurrencyDowngrade(ns: NotSendable) {
var x = 0
withSendableClosure {
_ = ns
// expected-complete-warning@-1 {{capture of 'ns' with non-Sendable type 'NotSendable' in a '@Sendable' closure}}
x += 1
// expected-complete-warning@-1 {{mutation of captured var 'x' in concurrently-executing code}}
}
}
// rdar://136766795
do {
class Class {
static func test() -> @Sendable () -> Void {
{
// OK, an unbound reference is sendable.
let _ = Class.method
}
}
func method() {}
}
}
do {
class Class {}
// expected-complete-note@-1 {{class 'Class' does not conform to the 'Sendable' protocol}}
func test(_: @autoclosure @Sendable () -> Class) {}
let c: Class
test(c)
// expected-complete-warning@-1:8 {{implicit capture of 'c' requires that 'Class' conforms to 'Sendable'}}
}