// 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(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(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(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(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 } } // 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 } }