mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
While 'defer' is implemented as a local function, it doesn't behave as one. In particular, since SILGen runs it after destroying all local bindings that appear after the 'defer' definition, the body of a 'defer' cannot forward reference captured bindings the way that local functions can. Note that I had to remove a SILGen test case for an older, related issue. The new diagnostic in Sema catches these cases earlier. Fixes rdar://problem/75088379.
168 lines
4.7 KiB
Swift
168 lines
4.7 KiB
Swift
// RUN: %target-swift-emit-silgen %s -verify
|
|
|
|
/// We emit an invalid forward capture as an 'undef'; make sure
|
|
/// we cover the various possible cases.
|
|
|
|
public func captureBeforeDefLet(amount: Int) -> () -> Int {
|
|
func getter() -> Int { // expected-error {{closure captures 'modifiedAmount' before it is declared}}
|
|
return modifiedAmount // expected-note {{captured here}}
|
|
}
|
|
let closure = getter
|
|
let modifiedAmount = amount // expected-note{{captured value declared here}}
|
|
return closure
|
|
}
|
|
|
|
public func captureBeforeDefVar(amount: Int) -> () -> Int {
|
|
func incrementor() -> Int { // expected-error {{closure captures 'currentTotal' before it is declared}}
|
|
currentTotal += amount // expected-note {{captured here}}
|
|
return currentTotal
|
|
}
|
|
let closure = incrementor
|
|
var currentTotal = 0 // expected-note{{captured value declared here}}
|
|
currentTotal = 1
|
|
return closure
|
|
}
|
|
|
|
public func captureBeforeDefWeakVar(obj: AnyObject) -> () -> AnyObject? {
|
|
func getter() -> AnyObject? { // expected-error {{closure captures 'weakObj' before it is declared}}
|
|
return weakObj // expected-note {{captured here}}
|
|
}
|
|
let closure = getter
|
|
weak var weakObj: AnyObject? = obj // expected-note{{captured value declared here}}
|
|
return closure
|
|
}
|
|
|
|
public func captureBeforeDefUnownedLet(obj: AnyObject) -> () -> AnyObject? {
|
|
func getter() -> AnyObject? { // expected-error {{closure captures 'unownedObj' before it is declared}}
|
|
return unownedObj // expected-note {{captured here}}
|
|
}
|
|
let closure = getter
|
|
unowned let unownedObj: AnyObject = obj // expected-note{{captured value declared here}}
|
|
return closure
|
|
}
|
|
|
|
public func captureBeforeDefUnownedVar(obj: AnyObject) -> () -> AnyObject? {
|
|
func getter() -> AnyObject? { // expected-error {{closure captures 'unownedObj' before it is declared}}
|
|
return unownedObj // expected-note {{captured here}}
|
|
}
|
|
let closure = getter
|
|
unowned var unownedObj: AnyObject = obj // expected-note{{captured value declared here}}
|
|
// expected-warning@-1 {{variable 'unownedObj' was never mutated; consider changing to 'let' constant}}
|
|
return closure
|
|
}
|
|
|
|
/// Examples of transitive capture
|
|
|
|
func pingpong() {
|
|
func ping() -> Int {
|
|
return pong()
|
|
}
|
|
func pong() -> Int {
|
|
return ping()
|
|
}
|
|
_ = ping()
|
|
}
|
|
|
|
func transitiveForwardCapture() {
|
|
func ping() -> Int { // expected-error {{closure captures 'x' before it is declared}}
|
|
return pong()
|
|
}
|
|
_ = ping()
|
|
var x = 1 // expected-note {{captured value declared here}}
|
|
func pong() -> Int {
|
|
x += 1 // expected-note {{captured here}}
|
|
return ping()
|
|
}
|
|
}
|
|
|
|
func transitiveForwardCapture2() {
|
|
func ping() -> Int { // expected-error {{closure captures 'x' before it is declared}}
|
|
_ = pong()
|
|
}
|
|
_ = ping()
|
|
var x = 1 // expected-note {{captured value declared here}}
|
|
func pong() -> Int {
|
|
_ = pung()
|
|
}
|
|
func pung() -> Int {
|
|
x += 1 // expected-note {{captured here}}
|
|
return ping()
|
|
}
|
|
}
|
|
|
|
func transitiveForwardCapture3() {
|
|
var y = 2
|
|
func ping() -> Int { // expected-error {{closure captures 'x' before it is declared}}
|
|
_ = pong()
|
|
}
|
|
_ = ping()
|
|
var x = 1 // expected-note {{captured value declared here}}
|
|
func pung() -> Int {
|
|
x += 1 // expected-note {{captured here}}
|
|
return ping()
|
|
}
|
|
func pong() -> Int {
|
|
y += 2
|
|
_ = pung()
|
|
}
|
|
}
|
|
|
|
func captureInClosure() {
|
|
let x = { (i: Int) in // expected-error {{closure captures 'currentTotal' before it is declared}}
|
|
currentTotal += i // expected-note {{captured here}}
|
|
}
|
|
|
|
var currentTotal = 0 // expected-note {{captured value declared here}}
|
|
|
|
_ = x
|
|
}
|
|
|
|
/// Regression tests
|
|
|
|
class SR4812 {
|
|
public func foo() {
|
|
let bar = { [weak self] in
|
|
// expected-error@-1 {{closure captures 'bar' before it is declared}}
|
|
// expected-note@-2 {{captured value declared here}}
|
|
// expected-warning@-3 {{variable 'self' was written to, but never read}}
|
|
bar2()
|
|
}
|
|
func bar2() {
|
|
bar() // expected-note {{captured here}}
|
|
}
|
|
bar()
|
|
}
|
|
}
|
|
|
|
func timeout(_ f: @escaping () -> Void) {
|
|
f()
|
|
}
|
|
|
|
func sr10687() {
|
|
timeout { // expected-error {{closure captures 'x' before it is declared}}
|
|
proc()
|
|
}
|
|
|
|
let x = 0 // expected-note {{captured value declared here}}
|
|
|
|
func proc() {
|
|
_ = x // expected-note {{captured here}}
|
|
}
|
|
}
|
|
|
|
class rdar40600800 {
|
|
func foo() {
|
|
let callback = { // expected-error {{closure captures 'callback' before it is declared}}
|
|
// expected-note@-1 {{captured value declared here}}
|
|
innerFunction()
|
|
}
|
|
|
|
func innerFunction() {
|
|
let closure = {
|
|
// expected-warning@-1 {{initialization of immutable value 'closure' was never used; consider replacing with assignment to '_' or removing it}}
|
|
callback() // expected-note {{captured here}}
|
|
}
|
|
}
|
|
}
|
|
}
|