Implement 'rethrows' checking in Sema.

Now with amazing new fixes and tests for methods and generics!

Swift SVN r28499
This commit is contained in:
John McCall
2015-05-13 00:03:09 +00:00
parent 9b67c6bf7f
commit 7a5ffeddf4
4 changed files with 1151 additions and 113 deletions

View File

@@ -1798,6 +1798,8 @@ ERROR(isa_pattern_value,sema_tcp,none,
ERROR(try_unhandled,sema,none, ERROR(try_unhandled,sema,none,
"errors thrown from here are not handled", ()) "errors thrown from here are not handled", ())
ERROR(throwing_call_unhandled,sema,none,
"call can throw, but the error is not handled", ())
ERROR(tryless_throwing_call_unhandled,sema,none, ERROR(tryless_throwing_call_unhandled,sema,none,
"call can throw, but it is not marked with 'try' and " "call can throw, but it is not marked with 'try' and "
"the error is not handled", ()) "the error is not handled", ())
@@ -1805,6 +1807,21 @@ ERROR(throw_in_nonthrowing_function,sema,none,
"error is not handled because the enclosing function " "error is not handled because the enclosing function "
"is not declared 'throws'", ()) "is not declared 'throws'", ())
ERROR(throwing_call_in_rethrows_function,sema,none,
"throwing call in 'rethrows' function is not to a parameter "
"function", ())
ERROR(tryless_throwing_call_in_rethrows_function,sema,none,
"throwing call in 'rethrows' function is not to a parameter "
"function and is not marked with 'try'", ())
ERROR(throw_in_rethrows_function,sema,none,
"'rethrows' function may only throw by calling a parameter "
"function", ())
NOTE(because_rethrows_argument_throws,sema,none,
"call is to 'rethrows' function, but argument function can throw", ())
NOTE(because_rethrows_default_argument_throws,sema,none,
"call is to 'rethrows' function, but a defaulted argument function"
" can throw", ())
ERROR(throwing_call_in_nonthrowing_autoclosure,sema,none, ERROR(throwing_call_in_nonthrowing_autoclosure,sema,none,
"call can throw, but it is executed in a non-throwing " "call can throw, but it is executed in a non-throwing "
"autoclosure",()) "autoclosure",())
@@ -1818,11 +1835,11 @@ ERROR(throw_in_nonthrowing_autoclosure,sema,none,
ERROR(try_unhandled_in_nonexhaustive_catch,sema,none, ERROR(try_unhandled_in_nonexhaustive_catch,sema,none,
"errors thrown from here are not handled because the " "errors thrown from here are not handled because the "
"enclosing catch is not exhaustive", ()) "enclosing catch is not exhaustive", ())
ERROR(throwing_call_in_nonexhaustive_catch,sema,none,
"call can throw, but the enclosing catch is not exhaustive", ())
ERROR(tryless_throwing_call_in_nonexhaustive_catch,sema,none, ERROR(tryless_throwing_call_in_nonexhaustive_catch,sema,none,
"call can throw, but it is not marked with 'try' and " "call can throw, but it is not marked with 'try' and "
"the enclosing catch is not exhaustive", ()) "the enclosing catch is not exhaustive", ())
ERROR(throwing_call_in_nonexhaustive_catch,sema,none,
"call can throw, but the enclosing catch is not exhaustive", ())
ERROR(throw_in_nonexhaustive_catch,sema,none, ERROR(throw_in_nonexhaustive_catch,sema,none,
"error is not handled because the enclosing catch is not exhaustive", ()) "error is not handled because the enclosing catch is not exhaustive", ())

File diff suppressed because it is too large Load Diff

View File

@@ -92,3 +92,230 @@ class C3 : Super {
override func nhf(f: () throws -> ()) rethrows {} // expected-error {{cannot override non-throwing method with throwing method}} override func nhf(f: () throws -> ()) rethrows {} // expected-error {{cannot override non-throwing method with throwing method}}
override func rhf(f: () throws -> ()) rethrows {} 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())
}

View File

@@ -70,3 +70,17 @@ struct seven {
} }
} }
} }
protocol ThrowingProto {
func foo() throws
static func bar() throws
}
func testExistential(p : ThrowingProto) throws {
try p.foo()
try p.dynamicType.bar()
}
func testGeneric<P : ThrowingProto>(p : P) throws {
try p.foo()
try P.bar()
}