mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-25 14:24:10 +00:00
Avoid stack overflow for non-BitOr binary types (#5743)
## Summary Closes #5742.
This commit is contained in:
parent
48309cad08
commit
51a313cca4
3 changed files with 44 additions and 72 deletions
|
|
@ -143,6 +143,7 @@ def f(a: Union[str, bytes]) -> None: ...
|
|||
def f(a: Optional[str]) -> None: ...
|
||||
def f(a: Annotated[str, ...]) -> None: ...
|
||||
def f(a: "Union[str, bytes]") -> None: ...
|
||||
def f(a: int + int) -> None: ...
|
||||
|
||||
# ANN401
|
||||
def f(a: Any | int) -> None: ...
|
||||
|
|
|
|||
|
|
@ -186,59 +186,59 @@ annotation_presence.py:134:13: ANN101 Missing type annotation for `self` in meth
|
|||
135 | pass
|
||||
|
|
||||
|
||||
annotation_presence.py:148:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
147 | # ANN401
|
||||
148 | def f(a: Any | int) -> None: ...
|
||||
| ^^^^^^^^^ ANN401
|
||||
149 | def f(a: int | Any) -> None: ...
|
||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:149:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
147 | # ANN401
|
||||
148 | def f(a: Any | int) -> None: ...
|
||||
149 | def f(a: int | Any) -> None: ...
|
||||
148 | # ANN401
|
||||
149 | def f(a: Any | int) -> None: ...
|
||||
| ^^^^^^^^^ ANN401
|
||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
151 | def f(a: Optional[Any]) -> None: ...
|
||||
150 | def f(a: int | Any) -> None: ...
|
||||
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:150:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
148 | def f(a: Any | int) -> None: ...
|
||||
149 | def f(a: int | Any) -> None: ...
|
||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
||||
151 | def f(a: Optional[Any]) -> None: ...
|
||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
148 | # ANN401
|
||||
149 | def f(a: Any | int) -> None: ...
|
||||
150 | def f(a: int | Any) -> None: ...
|
||||
| ^^^^^^^^^ ANN401
|
||||
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
152 | def f(a: Optional[Any]) -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:151:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
149 | def f(a: int | Any) -> None: ...
|
||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
151 | def f(a: Optional[Any]) -> None: ...
|
||||
| ^^^^^^^^^^^^^ ANN401
|
||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
153 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
149 | def f(a: Any | int) -> None: ...
|
||||
150 | def f(a: int | Any) -> None: ...
|
||||
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
||||
152 | def f(a: Optional[Any]) -> None: ...
|
||||
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:152:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
151 | def f(a: Optional[Any]) -> None: ...
|
||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^ ANN401
|
||||
153 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
150 | def f(a: int | Any) -> None: ...
|
||||
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
152 | def f(a: Optional[Any]) -> None: ...
|
||||
| ^^^^^^^^^^^^^ ANN401
|
||||
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:153:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
151 | def f(a: Optional[Any]) -> None: ...
|
||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
153 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||
152 | def f(a: Optional[Any]) -> None: ...
|
||||
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^ ANN401
|
||||
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
|
|
||||
|
||||
annotation_presence.py:154:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||
|
|
||||
152 | def f(a: Optional[Any]) -> None: ...
|
||||
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
||||
|
|
||||
|
||||
|
|
|
|||
|
|
@ -7,40 +7,6 @@ use ruff_python_ast::typing::parse_type_annotation;
|
|||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_stdlib::sys::is_known_standard_library;
|
||||
|
||||
/// Custom iterator to collect all the `|` separated expressions in a PEP 604
|
||||
/// union type.
|
||||
struct PEP604UnionIterator<'a> {
|
||||
stack: Vec<&'a Expr>,
|
||||
}
|
||||
|
||||
impl<'a> PEP604UnionIterator<'a> {
|
||||
fn new(expr: &'a Expr) -> Self {
|
||||
Self { stack: vec![expr] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PEP604UnionIterator<'a> {
|
||||
type Item = &'a Expr;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(expr) = self.stack.pop() {
|
||||
match expr {
|
||||
Expr::BinOp(ast::ExprBinOp {
|
||||
left,
|
||||
op: Operator::BitOr,
|
||||
right,
|
||||
..
|
||||
}) => {
|
||||
self.stack.push(left);
|
||||
self.stack.push(right);
|
||||
}
|
||||
_ => return Some(expr),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given call path is a known type.
|
||||
///
|
||||
/// A known type is either a builtin type, any object from the standard library,
|
||||
|
|
@ -80,7 +46,7 @@ enum TypingTarget<'a> {
|
|||
Union(&'a Expr),
|
||||
|
||||
/// A PEP 604 union type e.g., `int | str`.
|
||||
PEP604Union(&'a Expr),
|
||||
PEP604Union(&'a Expr, &'a Expr),
|
||||
|
||||
/// A `typing.Literal` type e.g., `Literal[1, 2, 3]`.
|
||||
Literal(&'a Expr),
|
||||
|
|
@ -135,7 +101,12 @@ impl<'a> TypingTarget<'a> {
|
|||
)
|
||||
}
|
||||
}
|
||||
Expr::BinOp(..) => Some(TypingTarget::PEP604Union(expr)),
|
||||
Expr::BinOp(ast::ExprBinOp {
|
||||
left,
|
||||
op: Operator::BitOr,
|
||||
right,
|
||||
..
|
||||
}) => Some(TypingTarget::PEP604Union(left, right)),
|
||||
Expr::Constant(ast::ExprConstant {
|
||||
value: Constant::None,
|
||||
..
|
||||
|
|
@ -197,7 +168,7 @@ impl<'a> TypingTarget<'a> {
|
|||
new_target.contains_none(semantic, locator, minor_version)
|
||||
})
|
||||
}),
|
||||
TypingTarget::PEP604Union(expr) => PEP604UnionIterator::new(expr).any(|element| {
|
||||
TypingTarget::PEP604Union(left, right) => [left, right].iter().any(|element| {
|
||||
TypingTarget::try_from_expr(element, semantic, locator, minor_version)
|
||||
.map_or(true, |new_target| {
|
||||
new_target.contains_none(semantic, locator, minor_version)
|
||||
|
|
@ -239,7 +210,7 @@ impl<'a> TypingTarget<'a> {
|
|||
new_target.contains_any(semantic, locator, minor_version)
|
||||
})
|
||||
}),
|
||||
TypingTarget::PEP604Union(expr) => PEP604UnionIterator::new(expr).any(|element| {
|
||||
TypingTarget::PEP604Union(left, right) => [left, right].iter().any(|element| {
|
||||
TypingTarget::try_from_expr(element, semantic, locator, minor_version)
|
||||
.map_or(true, |new_target| {
|
||||
new_target.contains_any(semantic, locator, minor_version)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue