mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:18 +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
19
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_18.py
vendored
Normal file
19
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_18.py
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
"""Test bindings created within annotations."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
foo = [1, 2, 3, 4, 5]
|
||||
|
||||
|
||||
class Bar:
|
||||
# OK: Allow list comprehensions in annotations (i.e., treat `qux` as a valid
|
||||
# load in the scope of the annotation).
|
||||
baz: Annotated[
|
||||
str,
|
||||
[qux for qux in foo],
|
||||
]
|
||||
|
||||
|
||||
# OK: Allow named expressions in annotations.
|
||||
x: (y := 1)
|
||||
print(y)
|
21
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_19.py
vendored
Normal file
21
crates/ruff_linter/resources/test/fixtures/pyflakes/F821_19.py
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
"""Test bindings created within annotations under `__future__` annotations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
foo = [1, 2, 3, 4, 5]
|
||||
|
||||
|
||||
class Bar:
|
||||
# OK: Allow list comprehensions in annotations (i.e., treat `qux` as a valid
|
||||
# load in the scope of the annotation).
|
||||
baz: Annotated[
|
||||
str,
|
||||
[qux for qux in foo],
|
||||
]
|
||||
|
||||
|
||||
# Error: `y` is not defined.
|
||||
x: (y := 1)
|
||||
print(y)
|
|
@ -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