Detect implicit returns in auto-return-types (#8952)

## Summary

Adds detection for branches without a `return` or `raise`, so that we
can properly `Optional` the return types. I'd like to remove this and
replace it with our code graph analysis from the `unreachable.rs` rule,
but it at least fixes the worst offenders.

Closes #8942.
This commit is contained in:
Charlie Marsh 2023-12-01 12:35:01 -05:00 committed by GitHub
parent d66063bb33
commit e5db72459e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 860 additions and 20 deletions

View file

@ -63,3 +63,87 @@ def func(x: int):
return "str"
else:
return None
def func(x: int):
if x:
return 1
def func():
x = 1
def func(x: int):
if x > 0:
return 1
def func(x: int):
match x:
case [1, 2, 3]:
return 1
case 4 as y:
return "foo"
def func(x: int):
for i in range(5):
if i > 0:
return 1
def func(x: int):
for i in range(5):
if i > 0:
return 1
else:
return 4
def func(x: int):
for i in range(5):
if i > 0:
break
else:
return 4
def func(x: int):
try:
pass
except:
return 1
def func(x: int):
try:
pass
except:
return 1
finally:
return 2
def func(x: int):
try:
pass
except:
return 1
else:
return 2
def func(x: int):
try:
return 1
except:
return 2
else:
pass
def func(x: int):
while x > 0:
break
return 1

View file

@ -1,10 +1,9 @@
use itertools::Itertools;
use ruff_diagnostics::Edit;
use rustc_hash::FxHashSet;
use crate::importer::{ImportRequest, Importer};
use ruff_diagnostics::Edit;
use ruff_python_ast::helpers::{
pep_604_union, typing_optional, typing_union, ReturnStatementVisitor,
implicit_return, pep_604_union, typing_optional, typing_union, ReturnStatementVisitor,
};
use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{self as ast, Expr, ExprContext};
@ -13,6 +12,7 @@ use ruff_python_semantic::analyze::visibility;
use ruff_python_semantic::{Definition, SemanticModel};
use ruff_text_size::{TextRange, TextSize};
use crate::importer::{ImportRequest, Importer};
use crate::settings::types::PythonVersion;
/// Return the name of the function, if it's overloaded.
@ -48,14 +48,19 @@ pub(crate) fn auto_return_type(function: &ast::StmtFunctionDef) -> Option<AutoPy
let returns = {
let mut visitor = ReturnStatementVisitor::default();
visitor.visit_body(&function.body);
// Ignore generators.
if visitor.is_generator {
return None;
}
visitor.returns
};
// Determine the return type of the first `return` statement.
let (return_statement, returns) = returns.split_first()?;
let Some((return_statement, returns)) = returns.split_first() else {
return Some(AutoPythonType::Atom(PythonType::None));
};
let mut return_type = return_statement.value.as_deref().map_or(
ResolvedPythonType::Atom(PythonType::None),
ResolvedPythonType::from,
@ -69,6 +74,16 @@ pub(crate) fn auto_return_type(function: &ast::StmtFunctionDef) -> Option<AutoPy
));
}
// If the function has an implicit return, union with `None`, as in:
// ```python
// def func(x: int):
// if x > 0:
// return 1
// ```
if implicit_return(function) {
return_type = return_type.union(ResolvedPythonType::Atom(PythonType::None));
}
match return_type {
ResolvedPythonType::Atom(python_type) => Some(AutoPythonType::Atom(python_type)),
ResolvedPythonType::Union(python_types) => Some(AutoPythonType::Union(python_types)),

View file

@ -200,4 +200,231 @@ auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public f
61 61 | return 1
62 62 | elif x > 5:
auto_return_type.py:68:5: ANN201 [*] Missing return type annotation for public function `func`
|
68 | def func(x: int):
| ^^^^ ANN201
69 | if x:
70 | return 1
|
= help: Add return type annotation: `int | None`
Unsafe fix
65 65 | return None
66 66 |
67 67 |
68 |-def func(x: int):
68 |+def func(x: int) -> int | None:
69 69 | if x:
70 70 | return 1
71 71 |
auto_return_type.py:73:5: ANN201 [*] Missing return type annotation for public function `func`
|
73 | def func():
| ^^^^ ANN201
74 | x = 1
|
= help: Add return type annotation: `None`
Unsafe fix
70 70 | return 1
71 71 |
72 72 |
73 |-def func():
73 |+def func() -> None:
74 74 | x = 1
75 75 |
76 76 |
auto_return_type.py:77:5: ANN201 [*] Missing return type annotation for public function `func`
|
77 | def func(x: int):
| ^^^^ ANN201
78 | if x > 0:
79 | return 1
|
= help: Add return type annotation: `int | None`
Unsafe fix
74 74 | x = 1
75 75 |
76 76 |
77 |-def func(x: int):
77 |+def func(x: int) -> int | None:
78 78 | if x > 0:
79 79 | return 1
80 80 |
auto_return_type.py:82:5: ANN201 [*] Missing return type annotation for public function `func`
|
82 | def func(x: int):
| ^^^^ ANN201
83 | match x:
84 | case [1, 2, 3]:
|
= help: Add return type annotation: `str | int`
Unsafe fix
79 79 | return 1
80 80 |
81 81 |
82 |-def func(x: int):
82 |+def func(x: int) -> str | int:
83 83 | match x:
84 84 | case [1, 2, 3]:
85 85 | return 1
auto_return_type.py:90:5: ANN201 [*] Missing return type annotation for public function `func`
|
90 | def func(x: int):
| ^^^^ ANN201
91 | for i in range(5):
92 | if i > 0:
|
= help: Add return type annotation: `int | None`
Unsafe fix
87 87 | return "foo"
88 88 |
89 89 |
90 |-def func(x: int):
90 |+def func(x: int) -> int | None:
91 91 | for i in range(5):
92 92 | if i > 0:
93 93 | return 1
auto_return_type.py:96:5: ANN201 [*] Missing return type annotation for public function `func`
|
96 | def func(x: int):
| ^^^^ ANN201
97 | for i in range(5):
98 | if i > 0:
|
= help: Add return type annotation: `int`
Unsafe fix
93 93 | return 1
94 94 |
95 95 |
96 |-def func(x: int):
96 |+def func(x: int) -> int:
97 97 | for i in range(5):
98 98 | if i > 0:
99 99 | return 1
auto_return_type.py:104:5: ANN201 [*] Missing return type annotation for public function `func`
|
104 | def func(x: int):
| ^^^^ ANN201
105 | for i in range(5):
106 | if i > 0:
|
= help: Add return type annotation: `int | None`
Unsafe fix
101 101 | return 4
102 102 |
103 103 |
104 |-def func(x: int):
104 |+def func(x: int) -> int | None:
105 105 | for i in range(5):
106 106 | if i > 0:
107 107 | break
auto_return_type.py:112:5: ANN201 [*] Missing return type annotation for public function `func`
|
112 | def func(x: int):
| ^^^^ ANN201
113 | try:
114 | pass
|
= help: Add return type annotation: `int | None`
Unsafe fix
109 109 | return 4
110 110 |
111 111 |
112 |-def func(x: int):
112 |+def func(x: int) -> int | None:
113 113 | try:
114 114 | pass
115 115 | except:
auto_return_type.py:119:5: ANN201 [*] Missing return type annotation for public function `func`
|
119 | def func(x: int):
| ^^^^ ANN201
120 | try:
121 | pass
|
= help: Add return type annotation: `int`
Unsafe fix
116 116 | return 1
117 117 |
118 118 |
119 |-def func(x: int):
119 |+def func(x: int) -> int:
120 120 | try:
121 121 | pass
122 122 | except:
auto_return_type.py:128:5: ANN201 [*] Missing return type annotation for public function `func`
|
128 | def func(x: int):
| ^^^^ ANN201
129 | try:
130 | pass
|
= help: Add return type annotation: `int`
Unsafe fix
125 125 | return 2
126 126 |
127 127 |
128 |-def func(x: int):
128 |+def func(x: int) -> int:
129 129 | try:
130 130 | pass
131 131 | except:
auto_return_type.py:137:5: ANN201 [*] Missing return type annotation for public function `func`
|
137 | def func(x: int):
| ^^^^ ANN201
138 | try:
139 | return 1
|
= help: Add return type annotation: `int`
Unsafe fix
134 134 | return 2
135 135 |
136 136 |
137 |-def func(x: int):
137 |+def func(x: int) -> int:
138 138 | try:
139 139 | return 1
140 140 | except:
auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public function `func`
|
146 | def func(x: int):
| ^^^^ ANN201
147 | while x > 0:
148 | break
|
= help: Add return type annotation: `int | None`
Unsafe fix
143 143 | pass
144 144 |
145 145 |
146 |-def func(x: int):
146 |+def func(x: int) -> int | None:
147 147 | while x > 0:
148 148 | break
149 149 | return 1

View file

@ -220,4 +220,266 @@ auto_return_type.py:59:5: ANN201 [*] Missing return type annotation for public f
61 62 | return 1
62 63 | elif x > 5:
auto_return_type.py:68:5: ANN201 [*] Missing return type annotation for public function `func`
|
68 | def func(x: int):
| ^^^^ ANN201
69 | if x:
70 | return 1
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
65 66 | return None
66 67 |
67 68 |
68 |-def func(x: int):
69 |+def func(x: int) -> Optional[int]:
69 70 | if x:
70 71 | return 1
71 72 |
auto_return_type.py:73:5: ANN201 [*] Missing return type annotation for public function `func`
|
73 | def func():
| ^^^^ ANN201
74 | x = 1
|
= help: Add return type annotation: `None`
Unsafe fix
70 70 | return 1
71 71 |
72 72 |
73 |-def func():
73 |+def func() -> None:
74 74 | x = 1
75 75 |
76 76 |
auto_return_type.py:77:5: ANN201 [*] Missing return type annotation for public function `func`
|
77 | def func(x: int):
| ^^^^ ANN201
78 | if x > 0:
79 | return 1
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
74 75 | x = 1
75 76 |
76 77 |
77 |-def func(x: int):
78 |+def func(x: int) -> Optional[int]:
78 79 | if x > 0:
79 80 | return 1
80 81 |
auto_return_type.py:82:5: ANN201 [*] Missing return type annotation for public function `func`
|
82 | def func(x: int):
| ^^^^ ANN201
83 | match x:
84 | case [1, 2, 3]:
|
= help: Add return type annotation: `Union[str | int]`
Unsafe fix
1 |+from typing import Union
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
79 80 | return 1
80 81 |
81 82 |
82 |-def func(x: int):
83 |+def func(x: int) -> Union[str | int]:
83 84 | match x:
84 85 | case [1, 2, 3]:
85 86 | return 1
auto_return_type.py:90:5: ANN201 [*] Missing return type annotation for public function `func`
|
90 | def func(x: int):
| ^^^^ ANN201
91 | for i in range(5):
92 | if i > 0:
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
87 88 | return "foo"
88 89 |
89 90 |
90 |-def func(x: int):
91 |+def func(x: int) -> Optional[int]:
91 92 | for i in range(5):
92 93 | if i > 0:
93 94 | return 1
auto_return_type.py:96:5: ANN201 [*] Missing return type annotation for public function `func`
|
96 | def func(x: int):
| ^^^^ ANN201
97 | for i in range(5):
98 | if i > 0:
|
= help: Add return type annotation: `int`
Unsafe fix
93 93 | return 1
94 94 |
95 95 |
96 |-def func(x: int):
96 |+def func(x: int) -> int:
97 97 | for i in range(5):
98 98 | if i > 0:
99 99 | return 1
auto_return_type.py:104:5: ANN201 [*] Missing return type annotation for public function `func`
|
104 | def func(x: int):
| ^^^^ ANN201
105 | for i in range(5):
106 | if i > 0:
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
101 102 | return 4
102 103 |
103 104 |
104 |-def func(x: int):
105 |+def func(x: int) -> Optional[int]:
105 106 | for i in range(5):
106 107 | if i > 0:
107 108 | break
auto_return_type.py:112:5: ANN201 [*] Missing return type annotation for public function `func`
|
112 | def func(x: int):
| ^^^^ ANN201
113 | try:
114 | pass
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
109 110 | return 4
110 111 |
111 112 |
112 |-def func(x: int):
113 |+def func(x: int) -> Optional[int]:
113 114 | try:
114 115 | pass
115 116 | except:
auto_return_type.py:119:5: ANN201 [*] Missing return type annotation for public function `func`
|
119 | def func(x: int):
| ^^^^ ANN201
120 | try:
121 | pass
|
= help: Add return type annotation: `int`
Unsafe fix
116 116 | return 1
117 117 |
118 118 |
119 |-def func(x: int):
119 |+def func(x: int) -> int:
120 120 | try:
121 121 | pass
122 122 | except:
auto_return_type.py:128:5: ANN201 [*] Missing return type annotation for public function `func`
|
128 | def func(x: int):
| ^^^^ ANN201
129 | try:
130 | pass
|
= help: Add return type annotation: `int`
Unsafe fix
125 125 | return 2
126 126 |
127 127 |
128 |-def func(x: int):
128 |+def func(x: int) -> int:
129 129 | try:
130 130 | pass
131 131 | except:
auto_return_type.py:137:5: ANN201 [*] Missing return type annotation for public function `func`
|
137 | def func(x: int):
| ^^^^ ANN201
138 | try:
139 | return 1
|
= help: Add return type annotation: `int`
Unsafe fix
134 134 | return 2
135 135 |
136 136 |
137 |-def func(x: int):
137 |+def func(x: int) -> int:
138 138 | try:
139 139 | return 1
140 140 | except:
auto_return_type.py:146:5: ANN201 [*] Missing return type annotation for public function `func`
|
146 | def func(x: int):
| ^^^^ ANN201
147 | while x > 0:
148 | break
|
= help: Add return type annotation: `Optional[int]`
Unsafe fix
1 |+from typing import Optional
1 2 | def func():
2 3 | return 1
3 4 |
--------------------------------------------------------------------------------
143 144 | pass
144 145 |
145 146 |
146 |-def func(x: int):
147 |+def func(x: int) -> Optional[int]:
147 148 | while x > 0:
148 149 | break
149 150 | return 1

View file

@ -1,14 +1,24 @@
---
source: crates/ruff_linter/src/rules/flake8_annotations/mod.rs
---
annotation_presence.py:5:5: ANN201 Missing return type annotation for public function `foo`
annotation_presence.py:5:5: ANN201 [*] Missing return type annotation for public function `foo`
|
4 | # Error
5 | def foo(a, b):
| ^^^ ANN201
6 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
2 2 | from typing_extensions import override
3 3 |
4 4 | # Error
5 |-def foo(a, b):
5 |+def foo(a, b) -> None:
6 6 | pass
7 7 |
8 8 |
annotation_presence.py:5:9: ANN001 Missing type annotation for function argument `a`
|
@ -26,14 +36,24 @@ annotation_presence.py:5:12: ANN001 Missing type annotation for function argumen
6 | pass
|
annotation_presence.py:10:5: ANN201 Missing return type annotation for public function `foo`
annotation_presence.py:10:5: ANN201 [*] Missing return type annotation for public function `foo`
|
9 | # Error
10 | def foo(a: int, b):
| ^^^ ANN201
11 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
7 7 |
8 8 |
9 9 | # Error
10 |-def foo(a: int, b):
10 |+def foo(a: int, b) -> None:
11 11 | pass
12 12 |
13 13 |
annotation_presence.py:10:17: ANN001 Missing type annotation for function argument `b`
|
@ -51,23 +71,43 @@ annotation_presence.py:15:17: ANN001 Missing type annotation for function argume
16 | pass
|
annotation_presence.py:20:5: ANN201 Missing return type annotation for public function `foo`
annotation_presence.py:20:5: ANN201 [*] Missing return type annotation for public function `foo`
|
19 | # Error
20 | def foo(a: int, b: int):
| ^^^ ANN201
21 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
annotation_presence.py:25:5: ANN201 Missing return type annotation for public function `foo`
Unsafe fix
17 17 |
18 18 |
19 19 | # Error
20 |-def foo(a: int, b: int):
20 |+def foo(a: int, b: int) -> None:
21 21 | pass
22 22 |
23 23 |
annotation_presence.py:25:5: ANN201 [*] Missing return type annotation for public function `foo`
|
24 | # Error
25 | def foo():
| ^^^ ANN201
26 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
22 22 |
23 23 |
24 24 | # Error
25 |-def foo():
25 |+def foo() -> None:
26 26 | pass
27 27 |
28 28 |
annotation_presence.py:45:12: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|

View file

@ -1,13 +1,23 @@
---
source: crates/ruff_linter/src/rules/flake8_annotations/mod.rs
---
ignore_fully_untyped.py:24:5: ANN201 Missing return type annotation for public function `error_partially_typed_1`
ignore_fully_untyped.py:24:5: ANN201 [*] Missing return type annotation for public function `error_partially_typed_1`
|
24 | def error_partially_typed_1(a: int, b):
| ^^^^^^^^^^^^^^^^^^^^^^^ ANN201
25 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
21 21 | pass
22 22 |
23 23 |
24 |-def error_partially_typed_1(a: int, b):
24 |+def error_partially_typed_1(a: int, b) -> None:
25 25 | pass
26 26 |
27 27 |
ignore_fully_untyped.py:24:37: ANN001 Missing type annotation for function argument `b`
|
@ -23,15 +33,25 @@ ignore_fully_untyped.py:28:37: ANN001 Missing type annotation for function argum
29 | pass
|
ignore_fully_untyped.py:32:5: ANN201 Missing return type annotation for public function `error_partially_typed_3`
ignore_fully_untyped.py:32:5: ANN201 [*] Missing return type annotation for public function `error_partially_typed_3`
|
32 | def error_partially_typed_3(a: int, b: int):
| ^^^^^^^^^^^^^^^^^^^^^^^ ANN201
33 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
ignore_fully_untyped.py:43:9: ANN201 Missing return type annotation for public function `error_typed_self`
Unsafe fix
29 29 | pass
30 30 |
31 31 |
32 |-def error_partially_typed_3(a: int, b: int):
32 |+def error_partially_typed_3(a: int, b: int) -> None:
33 33 | pass
34 34 |
35 35 |
ignore_fully_untyped.py:43:9: ANN201 [*] Missing return type annotation for public function `error_typed_self`
|
41 | pass
42 |
@ -39,6 +59,14 @@ ignore_fully_untyped.py:43:9: ANN201 Missing return type annotation for public f
| ^^^^^^^^^^^^^^^^ ANN201
44 | pass
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
40 40 | def ok_untyped_method(self):
41 41 | pass
42 42 |
43 |- def error_typed_self(self: X):
43 |+ def error_typed_self(self: X) -> None:
44 44 | pass

View file

@ -41,14 +41,24 @@ mypy_init_return.py:11:9: ANN204 [*] Missing return type annotation for special
13 13 |
14 14 |
mypy_init_return.py:40:5: ANN202 Missing return type annotation for private function `__init__`
mypy_init_return.py:40:5: ANN202 [*] Missing return type annotation for private function `__init__`
|
39 | # Error
40 | def __init__(self, foo: int):
| ^^^^^^^^ ANN202
41 | ...
|
= help: Add return type annotation
= help: Add return type annotation: `None`
Unsafe fix
37 37 |
38 38 |
39 39 | # Error
40 |-def __init__(self, foo: int):
40 |+def __init__(self, foo: int) -> None:
41 41 | ...
42 42 |
43 43 |
mypy_init_return.py:47:9: ANN204 [*] Missing return type annotation for special method `__init__`
|

View file

@ -911,6 +911,180 @@ where
}
}
/// Returns `true` if the function has an implicit return.
pub fn implicit_return(function: &ast::StmtFunctionDef) -> bool {
/// Returns `true` if the body may break via a `break` statement.
fn sometimes_breaks(stmts: &[Stmt]) -> bool {
for stmt in stmts {
match stmt {
Stmt::For(ast::StmtFor { body, orelse, .. }) => {
if returns(body) {
return false;
}
if sometimes_breaks(orelse) {
return true;
}
}
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
if returns(body) {
return false;
}
if sometimes_breaks(orelse) {
return true;
}
}
Stmt::If(ast::StmtIf {
body,
elif_else_clauses,
..
}) => {
if std::iter::once(body)
.chain(elif_else_clauses.iter().map(|clause| &clause.body))
.any(|body| sometimes_breaks(body))
{
return true;
}
}
Stmt::Match(ast::StmtMatch { cases, .. }) => {
if cases.iter().any(|case| sometimes_breaks(&case.body)) {
return true;
}
}
Stmt::Try(ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
}) => {
if sometimes_breaks(body)
|| handlers.iter().any(|handler| {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
body,
..
}) = handler;
sometimes_breaks(body)
})
|| sometimes_breaks(orelse)
|| sometimes_breaks(finalbody)
{
return true;
}
}
Stmt::With(ast::StmtWith { body, .. }) => {
if sometimes_breaks(body) {
return true;
}
}
Stmt::Break(_) => return true,
Stmt::Return(_) => return false,
Stmt::Raise(_) => return false,
_ => {}
}
}
false
}
/// Returns `true` if the body may break via a `break` statement.
fn always_breaks(stmts: &[Stmt]) -> bool {
for stmt in stmts {
match stmt {
Stmt::Break(_) => return true,
Stmt::Return(_) => return false,
Stmt::Raise(_) => return false,
_ => {}
}
}
false
}
/// Returns `true` if the body contains a branch that ends without an explicit `return` or
/// `raise` statement.
fn returns(stmts: &[Stmt]) -> bool {
for stmt in stmts.iter().rev() {
match stmt {
Stmt::For(ast::StmtFor { body, orelse, .. }) => {
if always_breaks(body) {
return false;
}
if returns(body) {
return true;
}
if returns(orelse) && !sometimes_breaks(body) {
return true;
}
}
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
if always_breaks(body) {
return false;
}
if returns(body) {
return true;
}
if returns(orelse) && !sometimes_breaks(body) {
return true;
}
}
Stmt::If(ast::StmtIf {
body,
elif_else_clauses,
..
}) => {
if elif_else_clauses.iter().any(|clause| clause.test.is_none())
&& std::iter::once(body)
.chain(elif_else_clauses.iter().map(|clause| &clause.body))
.all(|body| returns(body))
{
return true;
}
}
Stmt::Match(ast::StmtMatch { cases, .. }) => {
// Note: we assume the `match` is exhaustive.
if cases.iter().all(|case| returns(&case.body)) {
return true;
}
}
Stmt::Try(ast::StmtTry {
body,
handlers,
orelse,
finalbody,
..
}) => {
// If the `finally` block returns, the `try` block must also return.
if returns(finalbody) {
return true;
}
// If the `body` or the `else` block returns, the `try` block must also return.
if (returns(body) || returns(orelse))
&& handlers.iter().all(|handler| {
let ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
body,
..
}) = handler;
returns(body)
})
{
return true;
}
}
Stmt::With(ast::StmtWith { body, .. }) => {
if returns(body) {
return true;
}
}
Stmt::Return(_) => return true,
Stmt::Raise(_) => return true,
_ => {}
}
}
false
}
!returns(&function.body)
}
/// A [`StatementVisitor`] that collects all `raise` statements in a function or method.
#[derive(Default)]
pub struct RaiseStatementVisitor<'a> {