mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
416 lines
20 KiB
Swift
416 lines
20 KiB
Swift
// RUN: %target-parse-verify-swift
|
|
|
|
/** Basics *******************************************************************/
|
|
|
|
// Function types can't be rethrows right now.
|
|
let r1 = {() rethrows -> Int in 0} // expected-error {{only function declarations may be marked 'rethrows'}}
|
|
let r2 : () rethrows -> Int = { 0 } // expected-error {{only function declarations may be marked 'rethrows'}}
|
|
let r3 : Optional<() rethrows -> ()> = nil // expected-error {{only function declarations may be marked 'rethrows'}}
|
|
|
|
func f1(f: () throws -> ()) rethrows { try f() }
|
|
func f2(f: () -> ()) rethrows { f() } // expected-error {{'rethrows' function must take a throwing function argument}}
|
|
func f3(f: UndeclaredFunctionType) rethrows { f() } // expected-error {{use of undeclared type 'UndeclaredFunctionType'}}
|
|
|
|
/** Protocol conformance checking ********************************************/
|
|
|
|
protocol P {
|
|
func tf() throws
|
|
func nf() // expected-note {{protocol requires}}
|
|
|
|
func thf(f: () throws -> ()) throws
|
|
func nhf(f: () throws -> ()) // expected-note 2 {{protocol requires}}
|
|
func rhf(f: () throws -> ()) rethrows // expected-note {{protocol requires}}
|
|
}
|
|
|
|
struct T0 : P { // expected-error {{type 'T0' does not conform to protocol 'P'}}
|
|
func tf() throws {}
|
|
func nf() throws {} // expected-note {{candidate throws, but protocol does not allow it}}
|
|
|
|
func thf(f: () throws -> ()) throws {}
|
|
func nhf(f: () throws -> ()) throws {} // expected-note {{candidate throws, but protocol does not allow it}}
|
|
func rhf(f: () throws -> ()) throws {} // expected-note {{candidate is not 'rethrows', but protocol requires it}}
|
|
}
|
|
|
|
struct T1 : P {
|
|
func tf() {}
|
|
func nf() {}
|
|
|
|
func thf(f: () throws -> ()) {}
|
|
func nhf(f: () throws -> ()) {}
|
|
func rhf(f: () throws -> ()) {}
|
|
}
|
|
|
|
struct T2 : P { // expected-error {{type 'T2' does not conform to protocol 'P'}}
|
|
func tf() {}
|
|
func nf() {}
|
|
|
|
func thf(f: () throws -> ()) rethrows {}
|
|
func nhf(f: () throws -> ()) rethrows {} // expected-note {{candidate throws, but protocol does not allow it}}
|
|
func rhf(f: () throws -> ()) rethrows {}
|
|
}
|
|
|
|
/** Classes ******************************************************************/
|
|
|
|
class Super {
|
|
func tf() throws {}
|
|
func nf() {} // expected-note {{overridden declaration is here}}
|
|
|
|
func thf(f: () throws -> ()) throws {}
|
|
func nhf(f: () throws -> ()) {} // expected-note 2 {{overridden declaration is here}}
|
|
func rhf(f: () throws -> ()) rethrows {} // expected-note {{overridden declaration is here}}
|
|
}
|
|
|
|
class C1 : Super {
|
|
override func tf() {}
|
|
override func nf() {}
|
|
|
|
override func thf(f: () throws -> ()) {}
|
|
override func nhf(f: () throws -> ()) {}
|
|
override func rhf(f: () throws -> ()) {}
|
|
}
|
|
|
|
class C2 : Super {
|
|
override func tf() throws {}
|
|
override func nf() throws {} // expected-error {{cannot override non-throwing method with throwing method}}
|
|
|
|
override func thf(f: () throws -> ()) throws {}
|
|
override func nhf(f: () throws -> ()) throws {} // expected-error {{cannot override non-throwing method with throwing method}}
|
|
override func rhf(f: () throws -> ()) throws {} // expected-error {{override of 'rethrows' method should also be 'rethrows'}}
|
|
}
|
|
|
|
class C3 : Super {
|
|
override func tf() {}
|
|
override func nf() {}
|
|
|
|
override func thf(f: () throws -> ()) rethrows {}
|
|
override func nhf(f: () throws -> ()) rethrows {} // expected-error {{cannot override non-throwing method with throwing method}}
|
|
override func rhf(f: () throws -> ()) rethrows {}
|
|
}
|
|
|
|
/** Semantics ****************************************************************/
|
|
|
|
func call(fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
func callAC(@autoclosure fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
func raise() throws -> Int { return 0 }
|
|
func noraise() -> Int { return 0 }
|
|
|
|
/** Global functions **/
|
|
|
|
func testCallUnhandled() {
|
|
call(noraise)
|
|
try call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testCallHandled() throws {
|
|
call(noraise)
|
|
try call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try call(raise)
|
|
}
|
|
|
|
func testCallACUnhandled() {
|
|
callAC(noraise())
|
|
try callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testCallACHandled() throws {
|
|
callAC(noraise())
|
|
try callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try callAC(raise())
|
|
}
|
|
|
|
func testForward1(fn: () throws -> Int) rethrows {
|
|
try call(fn)
|
|
}
|
|
func testForward2(fn: () throws -> Int) rethrows {
|
|
try call({ try fn() })
|
|
}
|
|
|
|
/** Methods **/
|
|
|
|
struct MyStruct : MyProto {
|
|
func call(fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
func callAC(@autoclosure fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
|
|
static func static_call(fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
static func static_callAC(@autoclosure fn: () throws -> Int) rethrows -> Int { return try fn() }
|
|
}
|
|
|
|
func testMethodCallUnhandled(s: MyStruct) {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
MyStruct.static_call(noraise)
|
|
try MyStruct.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
MyStruct.static_call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try MyStruct.static_call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testMethodCallHandled(s: MyStruct) throws {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise)
|
|
|
|
MyStruct.static_call(noraise)
|
|
try MyStruct.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
MyStruct.static_call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try MyStruct.static_call(raise)
|
|
}
|
|
|
|
func testMethodCallACUnhandled(s: MyStruct) {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
MyStruct.static_callAC(noraise())
|
|
try MyStruct.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
MyStruct.static_callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try MyStruct.static_callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testMethodCallACHandled(s: MyStruct) throws {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise())
|
|
|
|
MyStruct.static_callAC(noraise())
|
|
try MyStruct.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
MyStruct.static_callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try MyStruct.static_callAC(raise())
|
|
}
|
|
|
|
/** Protocol methods **/
|
|
|
|
protocol MyProto {
|
|
func call(fn: () throws -> Int) rethrows -> Int
|
|
func callAC(@autoclosure fn: () throws -> Int) rethrows -> Int
|
|
|
|
static func static_call(fn: () throws -> Int) rethrows -> Int
|
|
static func static_callAC(@autoclosure fn: () throws -> Int) rethrows -> Int
|
|
}
|
|
|
|
/** Existentials **/
|
|
|
|
func testProtoMethodCallUnhandled(s: MyProto) {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
s.dynamicType.static_call(noraise)
|
|
try s.dynamicType.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.dynamicType.static_call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.dynamicType.static_call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testProtoMethodCallHandled(s: MyProto) throws {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise)
|
|
|
|
s.dynamicType.static_call(noraise)
|
|
try s.dynamicType.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.dynamicType.static_call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.dynamicType.static_call(raise)
|
|
}
|
|
|
|
func testProtoMethodCallACUnhandled(s: MyProto) {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
s.dynamicType.static_callAC(noraise())
|
|
try s.dynamicType.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.dynamicType.static_callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.dynamicType.static_callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testProtoMethodCallACHandled(s: MyProto) throws {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise())
|
|
|
|
s.dynamicType.static_callAC(noraise())
|
|
try s.dynamicType.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.dynamicType.static_callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.dynamicType.static_callAC(raise())
|
|
}
|
|
|
|
/** Generics **/
|
|
|
|
func testGenericMethodCallUnhandled<P: MyProto>(s: P) {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
P.static_call(noraise)
|
|
try P.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
P.static_call(raise) // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try P.static_call(raise) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testGenericMethodCallHandled<P: MyProto>(s: P) throws {
|
|
s.call(noraise)
|
|
try s.call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.call(raise)
|
|
|
|
P.static_call(noraise)
|
|
try P.static_call(noraise) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
P.static_call(raise) // expected-error {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try P.static_call(raise)
|
|
}
|
|
|
|
func testGenericMethodCallACUnhandled<P: MyProto>(s: P) {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
|
|
P.static_callAC(noraise())
|
|
try P.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
P.static_callAC(raise()) // expected-error {{call can throw but is not marked with 'try'}} \
|
|
// expected-error {{call can throw, but it is not marked with 'try' and the error is not handled}} \
|
|
// expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try P.static_callAC(raise()) // expected-error {{call can throw, but the error is not handled}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
}
|
|
|
|
func testGenericMethodCallACHandled<P: MyProto>(s: P) throws {
|
|
s.callAC(noraise())
|
|
try s.callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
s.callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try s.callAC(raise())
|
|
|
|
P.static_callAC(noraise())
|
|
try P.static_callAC(noraise()) // expected-warning {{no calls to throwing functions occur within 'try'}}
|
|
P.static_callAC(raise()) // expected-error 2 {{call can throw but is not marked with 'try'}} expected-note {{call is to 'rethrows' function, but argument function can throw}}
|
|
try P.static_callAC(raise())
|
|
}
|
|
|
|
/** Miscellaneous bugs **/
|
|
|
|
// rdar://problem/21967164 - Non-throwing closures are incorrectly marked as throwing in rethrow contexts
|
|
func rt1(@noescape predicate: () throws -> ()) rethrows { }
|
|
rt1 { }
|
|
|
|
func rt2(predicate: () throws -> ()) rethrows { }
|
|
rt2 { }
|
|
|
|
|
|
enum SomeError : ErrorProtocol {
|
|
case Badness
|
|
}
|
|
|
|
func testUnrelatedThrowsInRethrows(fn: () throws -> Void) rethrows {
|
|
try fn() // okay
|
|
try testUnrelatedThrowsInRethrows(fn) // okay
|
|
|
|
raise() // expected-error {{call can throw, but it is not marked with 'try' and the error is not handled; a function declared 'rethrows' may only throw if its parameter does}}
|
|
try raise() // expected-error {{call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does}}
|
|
throw SomeError.Badness // expected-error {{a function declared 'rethrows' may only throw if its parameter does}}
|
|
}
|
|
|
|
func testThrowsInCatchInRethrows(fn: () throws -> Void) rethrows {
|
|
do {
|
|
try fn()
|
|
} catch {
|
|
// this catch can only be entered if our `fn` parameter throws
|
|
throw error // okay
|
|
}
|
|
|
|
do {
|
|
try fn()
|
|
} catch let error as SomeError {
|
|
throw error // okay
|
|
}
|
|
|
|
do {
|
|
try fn()
|
|
try raise()
|
|
} catch {
|
|
// this catch can be entered regardless of whether our `fn` parameter throws
|
|
throw error // expected-error {{a function declared 'rethrows' may only throw if its parameter does}}
|
|
}
|
|
|
|
do {
|
|
throw SomeError.Badness
|
|
} catch {
|
|
// this catch can be entered regardless of whether our `fn` parameter throws
|
|
throw error // expected-error {{a function declared 'rethrows' may only throw if its parameter does}}
|
|
}
|
|
|
|
do {
|
|
try fn()
|
|
try raise() // expected-error {{call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does}}
|
|
} catch is SomeError {}
|
|
|
|
do {
|
|
try raise()
|
|
} catch {
|
|
try fn() // okay
|
|
}
|
|
|
|
do {
|
|
// don't throw anything; equivalent to throwing in an #if
|
|
} catch { // expected-warning {{'catch' block is unreachable because no errors are thrown in 'do' block}}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
// Sanity-check that throwing in catch blocks behaves as expected outside of
|
|
// rethrows functions
|
|
|
|
func testThrowsInCatch(fn: () throws -> Void) {
|
|
do {
|
|
try fn()
|
|
} catch {
|
|
throw error // expected-error {{error is not handled because the enclosing function is not declared 'throws'}}
|
|
}
|
|
}
|
|
|
|
func testThrowsInCatchInThrows() throws {
|
|
do {
|
|
try raise()
|
|
} catch {
|
|
throw error // okay
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/24221830> Bogus "no calls to throwing functions" warning in derived throwing init
|
|
class B24221830 {}
|
|
class r24221830 : B24221830 {
|
|
var B: Int
|
|
|
|
init(A: String) throws {
|
|
self.B = 0
|
|
}
|
|
|
|
}
|
|
|