Files
swift-mirror/test/stmt/defer.swift
Freddy Kellison-Linn 45505b87a5 Implement async defer
Use closure for defer body

Revert to main

Rework implementation to keep FuncDecl

Add AST briding

Add test with async let

Add main actor tests

Add additional tests
2026-03-14 17:47:51 -04:00

288 lines
6.3 KiB
Swift

// RUN: %target-typecheck-verify-swift
func voidReturn1() {}
func breakContinue(_: Int) -> Int {}
func testDefer(_ a : Int) {
defer { voidReturn1() }
defer { breakContinue(1)+42 } // expected-warning {{result of operator '+' is unused}}
// Ok:
defer { while false { break } }
// Not ok.
while false { defer { break } } // expected-error {{'break' cannot transfer control out of a defer statement}}
// expected-warning@-1 {{'defer' statement at end of scope always executes immediately}}{{17-22=do}}
defer { return } // expected-error {{'return' cannot transfer control out of a defer statement}}
// expected-warning@-1 {{'defer' statement at end of scope always executes immediately}}{{3-8=do}}
}
class SomeTestClass {
var x = 42
func method() {
defer { x = 97 } // self. not required here!
// expected-warning@-1 {{'defer' statement at end of scope always executes immediately}}{{5-10=do}}
}
}
enum DeferThrowError: Error {
case someError
}
func throwInDefer() {
defer { throw DeferThrowError.someError } // expected-error {{errors cannot be thrown out of a defer body}}
print("Foo")
}
func throwInDeferOK1() {
defer {
do {
throw DeferThrowError.someError
} catch {}
}
print("Bar")
}
func throwInDeferOK2() throws {
defer {
do {
throw DeferThrowError.someError
} catch {}
}
print("Bar")
}
func throwingFuncInDefer1() throws {
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
print("Bar")
}
func throwingFuncInDefer1a() throws {
defer {
do {
try throwingFunctionCalledInDefer()
} catch {}
}
print("Bar")
}
func throwingFuncInDefer2() throws {
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
print("Bar")
}
func throwingFuncInDefer2a() throws {
defer {
do {
throwingFunctionCalledInDefer()
// expected-error@-1 {{call can throw but is not marked with 'try'}}
// expected-note@-2 {{did you mean to use 'try'?}}
// expected-note@-3 {{did you mean to handle error as optional value?}}
// expected-note@-4 {{did you mean to disable error propagation?}}
} catch {}
}
print("Bar")
}
func throwingFuncInDefer3() {
defer { try throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
print("Bar")
}
func throwingFuncInDefer3a() {
defer {
do {
try throwingFunctionCalledInDefer()
} catch {}
}
print("Bar")
}
func throwingFuncInDefer4() {
defer { throwingFunctionCalledInDefer() } // expected-error {{errors cannot be thrown out of a defer body}}
print("Bar")
}
func throwingFuncInDefer4a() {
defer {
do {
throwingFunctionCalledInDefer()
// expected-error@-1 {{call can throw but is not marked with 'try'}}
// expected-note@-2 {{did you mean to use 'try'?}}
// expected-note@-3 {{did you mean to handle error as optional value?}}
// expected-note@-4 {{did you mean to disable error propagation?}}
} catch {}
}
print("Bar")
}
func throwingFunctionCalledInDefer() throws {
throw DeferThrowError.someError
}
class SomeDerivedClass: SomeTestClass {
override init() {
defer {
super.init() // expected-error {{initializer chaining ('super.init') cannot be nested in another expression}}
}
}
}
// rdar://75088379 -- 'defer' should not be able to forward-reference captures
func badForwardReference() {
defer {
_ = x2 // expected-error {{use of local variable 'x2' before its declaration}}
let x1 = 0
let y1 = 0
defer {
_ = x1
_ = x2 // expected-error {{use of local variable 'x2' before its declaration}}
_ = y1
_ = y2 // expected-error {{use of local variable 'y2' before its declaration}}
}
let y2 = 0 // expected-note {{'y2' declared here}}
}
let x2 = 0 // expected-note 2{{'x2' declared here}}
func localFunc() {
defer {
_ = z1 // expected-error {{use of local variable 'z1' before its declaration}}
_ = z2
}
let z1 = 0 // expected-note {{'z1' declared here}}
}
let z2 = 0
}
public func basicAsyncDefer() async {
defer { await asyncFunc() }
voidFunc()
}
func asyncFunc() async {}
func voidFunc() {}
func testClosure() async {
let f = {
defer { await asyncFunc() }
voidFunc()
}
await f()
}
func asyncDeferInSyncFunc() {
defer { await asyncFunc() } // expected-error {{'async' defer must appear within an 'async' context}}
voidFunc()
}
func asyncLetDeferInSyncFunc() {
defer { async let _: () = voidFunc() } // expected-error {{'async' defer must appear within an 'async' context}}
voidFunc()
}
@MainActor
func mainActorFunc() {}
@MainActor
func mainActorAsyncFunc() async {}
func asyncFuncToDeferCallToMainActor() async {
defer {
await mainActorFunc()
await mainActorAsyncFunc()
}
voidFunc()
}
@MainActor
func mainActorAsyncFuncToDeferCallToMainActor() async {
defer {
mainActorFunc()
await mainActorAsyncFunc()
}
voidFunc()
}
actor A {
nonisolated func asyncMethod() async {
defer {
await isolatedMethod()
}
voidFunc()
}
nonisolated func nonisolatedSyncMethod() {
defer { // expected-error {{'async' defer must appear within an 'async' context}}
await isolatedMethod()
}
voidFunc()
}
func isolatedMethod() async {
defer {
await anotherIsolatedMethod()
}
voidFunc()
}
func anotherIsolatedMethod() async {}
func isolatedSyncMethod() {
defer {
anotherIsolatedSyncMethod()
}
voidFunc()
}
func anotherIsolatedSyncMethod() {}
}
func testLocalIsolatedParameter(_ a: isolated A) async {
var x = 0
defer {
await a.isolatedMethod()
await a.asyncMethod()
a.isolatedSyncMethod()
x = 2
}
voidFunc()
x = 1
_ = x
}
func testNestedIsolation(_ a: isolated A) async {
let _: @MainActor () async -> Void = {
func inner(isolated: isolated (any Actor)? = nil) async {
let y: Int = 0
defer {
voidFunc()
_ = y
}
_ = y
}
}
}
func testLocalNonisolatedParameter(_ a: A) async {
var x: Int = 0
defer {
await a.isolatedMethod()
await a.asyncMethod()
await a.isolatedSyncMethod()
x = 2
}
voidFunc()
x = 1
_ = x
}