mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-27 10:26:20 +00:00
Allow bindings to be created and referenced within annotations (#7885)
## Summary
Given:
```python
baz: Annotated[
str,
[qux for qux in foo],
]
```
We treat `baz` as `BindingKind::Annotation`, to ensure that references
to `baz` are marked as unbound. However, we were _also_ treating `qux`
as `BindingKind::Annotation`, which meant that the load in the
comprehension _also_ errored.
Closes https://github.com/astral-sh/ruff/issues/7879.
This commit is contained in:
parent
ec7395ba69
commit
a3e8e77172
6 changed files with 67 additions and 6 deletions
|
|
@ -1168,13 +1168,14 @@ where
|
|||
range: _,
|
||||
}) = slice.as_ref()
|
||||
{
|
||||
if let Some(expr) = elts.first() {
|
||||
let mut iter = elts.iter();
|
||||
if let Some(expr) = iter.next() {
|
||||
self.visit_expr(expr);
|
||||
for expr in elts.iter().skip(1) {
|
||||
self.visit_non_type_definition(expr);
|
||||
}
|
||||
self.visit_expr_context(ctx);
|
||||
}
|
||||
for expr in iter {
|
||||
self.visit_non_type_definition(expr);
|
||||
}
|
||||
self.visit_expr_context(ctx);
|
||||
} else {
|
||||
debug!("Found non-Expr::Tuple argument to PEP 593 Annotation.");
|
||||
}
|
||||
|
|
@ -1618,10 +1619,12 @@ impl<'a> Checker<'a> {
|
|||
fn handle_node_store(&mut self, id: &'a str, expr: &Expr) {
|
||||
let parent = self.semantic.current_statement();
|
||||
|
||||
// Match the left-hand side of an annotated assignment, like `x` in `x: int`.
|
||||
if matches!(
|
||||
parent,
|
||||
Stmt::AnnAssign(ast::StmtAnnAssign { value: None, .. })
|
||||
) {
|
||||
) && !self.semantic.in_annotation()
|
||||
{
|
||||
self.add_binding(
|
||||
id,
|
||||
expr.range(),
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ mod tests {
|
|||
#[test_case(Rule::UndefinedName, Path::new("F821_15.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_16.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_17.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_18.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_19.py"))]
|
||||
#[test_case(Rule::UndefinedExport, Path::new("F822_0.py"))]
|
||||
#[test_case(Rule::UndefinedExport, Path::new("F822_1.py"))]
|
||||
#[test_case(Rule::UndefinedExport, Path::new("F822_2.py"))]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||
---
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||
---
|
||||
F821_19.py:21:7: F821 Undefined name `y`
|
||||
|
|
||||
19 | # Error: `y` is not defined.
|
||||
20 | x: (y := 1)
|
||||
21 | print(y)
|
||||
| ^ F821
|
||||
|
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue