diff --git a/crates/ruff_linter/resources/test/fixtures/semantic_errors/annonated_global.py b/crates/ruff_linter/resources/test/fixtures/semantic_errors/annonated_global.py new file mode 100644 index 0000000000..2614c60e4a --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/semantic_errors/annonated_global.py @@ -0,0 +1,27 @@ +a: int = 1 +def f1(): + global a + a: str = "foo" + +b: int = 1 +def outer(): + def inner(): + global b + b: str = "nested" + +c: int = 1 +def f2(): + global c + c: list[str] = [] + +d: int = 1 +def f3(): + global d + d: str + +e: int = 1 +def f4(): + e: str = "happy" + +global f +f: int = 1 \ No newline at end of file diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index 719d5ac9c5..f19799cdf0 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -982,6 +982,7 @@ mod tests { #[test_case(Path::new("write_to_debug.py"), PythonVersion::PY310)] #[test_case(Path::new("invalid_expression.py"), PythonVersion::PY312)] #[test_case(Path::new("global_parameter.py"), PythonVersion::PY310)] + #[test_case(Path::new("annotated_global.py"), PythonVersion::latest())] fn test_semantic_errors(path: &Path, python_version: PythonVersion) -> Result<()> { let snapshot = format!( "semantic_syntax_error_{}_{}", diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_annonated_global.py_3.14.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_annonated_global.py_3.14.snap new file mode 100644 index 0000000000..cea88632e7 --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_annonated_global.py_3.14.snap @@ -0,0 +1,46 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +invalid-syntax: annotated name `a` can't be global + --> resources/test/fixtures/semantic_errors/annonated_global.py:4:5 + | +2 | def f1(): +3 | global a +4 | a: str = "foo" + | ^ +5 | +6 | b: int = 1 + | + +invalid-syntax: annotated name `b` can't be global + --> resources/test/fixtures/semantic_errors/annonated_global.py:10:9 + | + 8 | def inner(): + 9 | global b +10 | b: str = "nested" + | ^ +11 | +12 | c: int = 1 + | + +invalid-syntax: annotated name `c` can't be global + --> resources/test/fixtures/semantic_errors/annonated_global.py:15:5 + | +13 | def f2(): +14 | global c +15 | c: list[str] = [] + | ^ +16 | +17 | d: int = 1 + | + +invalid-syntax: annotated name `d` can't be global + --> resources/test/fixtures/semantic_errors/annonated_global.py:20:5 + | +18 | def f3(): +19 | global d +20 | d: str + | ^ +21 | +22 | e: int = 1 + | diff --git a/crates/ruff_python_parser/src/semantic_errors.rs b/crates/ruff_python_parser/src/semantic_errors.rs index dd3c4a832f..5fdf41f0c2 100644 --- a/crates/ruff_python_parser/src/semantic_errors.rs +++ b/crates/ruff_python_parser/src/semantic_errors.rs @@ -300,7 +300,7 @@ impl SemanticSyntaxChecker { visitor.visit_expr(annotation); } if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() { - if ctx.global(id.as_str()).is_some() { + if ctx.global(id.as_str()).is_some() && ctx.in_function_scope() { Self::add_error( ctx, SemanticSyntaxErrorKind::AnnotatedGlobal(id.to_string()),