mirror of https://github.com/astral-sh/ruff
Avoid stack overflow for non-BitOr binary types (#5743)
## Summary Closes #5742.
This commit is contained in:
parent
48309cad08
commit
51a313cca4
|
|
@ -143,6 +143,7 @@ def f(a: Union[str, bytes]) -> None: ...
|
||||||
def f(a: Optional[str]) -> None: ...
|
def f(a: Optional[str]) -> None: ...
|
||||||
def f(a: Annotated[str, ...]) -> None: ...
|
def f(a: Annotated[str, ...]) -> None: ...
|
||||||
def f(a: "Union[str, bytes]") -> None: ...
|
def f(a: "Union[str, bytes]") -> None: ...
|
||||||
|
def f(a: int + int) -> None: ...
|
||||||
|
|
||||||
# ANN401
|
# ANN401
|
||||||
def f(a: Any | int) -> None: ...
|
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
|
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`
|
annotation_presence.py:149:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||||
|
|
|
|
||||||
147 | # ANN401
|
148 | # ANN401
|
||||||
148 | def f(a: Any | int) -> None: ...
|
149 | def f(a: Any | int) -> None: ...
|
||||||
149 | def f(a: int | Any) -> None: ...
|
|
||||||
| ^^^^^^^^^ ANN401
|
| ^^^^^^^^^ ANN401
|
||||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
150 | def f(a: int | Any) -> None: ...
|
||||||
151 | def f(a: Optional[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`
|
annotation_presence.py:150:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||||
|
|
|
|
||||||
148 | def f(a: Any | int) -> None: ...
|
148 | # ANN401
|
||||||
149 | def f(a: int | Any) -> None: ...
|
149 | def f(a: Any | int) -> None: ...
|
||||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
150 | def f(a: int | Any) -> None: ...
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
| ^^^^^^^^^ ANN401
|
||||||
151 | def f(a: Optional[Any]) -> None: ...
|
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
152 | def f(a: Optional[Any]) -> None: ...
|
||||||
|
|
|
|
||||||
|
|
||||||
annotation_presence.py:151:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
annotation_presence.py:151:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||||
|
|
|
|
||||||
149 | def f(a: int | Any) -> None: ...
|
149 | def f(a: Any | int) -> None: ...
|
||||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
150 | def f(a: int | Any) -> None: ...
|
||||||
151 | def f(a: Optional[Any]) -> None: ...
|
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||||
| ^^^^^^^^^^^^^ ANN401
|
| ^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
||||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
152 | def f(a: Optional[Any]) -> None: ...
|
||||||
153 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
||||||
|
|
|
|
||||||
|
|
||||||
annotation_presence.py:152:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
annotation_presence.py:152:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||||
|
|
|
|
||||||
150 | def f(a: Union[str, bytes, Any]) -> None: ...
|
150 | def f(a: int | Any) -> None: ...
|
||||||
151 | def f(a: Optional[Any]) -> None: ...
|
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
152 | def f(a: Optional[Any]) -> None: ...
|
||||||
| ^^^^^^^^^^^^^^^^^^^ ANN401
|
| ^^^^^^^^^^^^^ ANN401
|
||||||
153 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
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`
|
annotation_presence.py:153:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
||||||
|
|
|
|
||||||
151 | def f(a: Optional[Any]) -> None: ...
|
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
||||||
152 | def f(a: Annotated[Any, ...]) -> None: ...
|
152 | def f(a: Optional[Any]) -> None: ...
|
||||||
153 | def f(a: "Union[str, bytes, 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
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
||||||
|
|
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,40 +7,6 @@ use ruff_python_ast::typing::parse_type_annotation;
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_python_stdlib::sys::is_known_standard_library;
|
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.
|
/// 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,
|
/// A known type is either a builtin type, any object from the standard library,
|
||||||
|
|
@ -80,7 +46,7 @@ enum TypingTarget<'a> {
|
||||||
Union(&'a Expr),
|
Union(&'a Expr),
|
||||||
|
|
||||||
/// A PEP 604 union type e.g., `int | str`.
|
/// 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]`.
|
/// A `typing.Literal` type e.g., `Literal[1, 2, 3]`.
|
||||||
Literal(&'a Expr),
|
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 {
|
Expr::Constant(ast::ExprConstant {
|
||||||
value: Constant::None,
|
value: Constant::None,
|
||||||
..
|
..
|
||||||
|
|
@ -197,7 +168,7 @@ impl<'a> TypingTarget<'a> {
|
||||||
new_target.contains_none(semantic, locator, minor_version)
|
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)
|
TypingTarget::try_from_expr(element, semantic, locator, minor_version)
|
||||||
.map_or(true, |new_target| {
|
.map_or(true, |new_target| {
|
||||||
new_target.contains_none(semantic, locator, minor_version)
|
new_target.contains_none(semantic, locator, minor_version)
|
||||||
|
|
@ -239,7 +210,7 @@ impl<'a> TypingTarget<'a> {
|
||||||
new_target.contains_any(semantic, locator, minor_version)
|
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)
|
TypingTarget::try_from_expr(element, semantic, locator, minor_version)
|
||||||
.map_or(true, |new_target| {
|
.map_or(true, |new_target| {
|
||||||
new_target.contains_any(semantic, locator, minor_version)
|
new_target.contains_any(semantic, locator, minor_version)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue