Repository: astral-sh/ruff
File: crates/ruff_python_parser/src/semantic_errors.rs (Rust)

Code before:
                if ctx.python_version() > PythonVersion::PY313 {
                    // test_ok valid_annotation_py313
                    // # parse_options: {"target-version": "3.13"}
                    // a: (x := 1)
                    // def outer():
                    //     b: (yield 1)
                    //     c: (yield from 1)
                    // async def outer():
                    //     d: (await 1)

                    // test_err invalid_annotation_py314
                    // # parse_options: {"target-version": "3.14"}
                    // a: (x := 1)
                    // def outer():
                    //     b: (yield 1)
                    //     c: (yield from 1)
                    // async def outer():
                    //     d: (await 1)
                    let mut visitor = InvalidExpressionVisitor {
                        position: InvalidExpressionPosition::TypeAnnotation,
                        ctx,
                    };
                    visitor.visit_expr(annotation);
                }
                if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() {
                    if ctx.global(id.as_str()).is_some() && ctx.in_function_scope() {
                        Self::add_error(
                            ctx,
                            SemanticSyntaxErrorKind::AnnotatedGlobal(id.to_string()),
                            target.range(),
                        );
                    }
                }
            }
            Stmt::FunctionDef(ast::StmtFunctionDef {
                type_params,
                parameters,
                returns,
                ..
            }) => {
                // test_ok valid_annotation_function_py313
                // # parse_options: {"target-version": "3.13"}
                // def f() -> (y := 3): ...
                // def g(arg: (x := 1)): ...
                // def outer():
                //     def i(x: (yield 1)): ...
                //     def k() -> (yield 1): ...
                //     def m(x: (yield from 1)): ...
                //     def o() -> (yield from 1): ...
                // async def outer():
                //     def f() -> (await 1): ...

Review comment (suggestion):
I pushed another test case that should still raise an error in the module scope. This `in_function_scope` check is too restrictive, we still miss the new case I added:

```shell
❯ python <<EOF
g: int = 1
global g
EOF
  File "<stdin>", line 2
SyntaxError: annotated name 'g' can't be global
```

I also noticed that ty actually has a false positive on the `f` case: https://play.ty.dev/d6285858-e5cf-429e-a983-291a243db217.

So we may want to fix that as well, if we can find a nice solution on the Ruff side.

For Ruff, we may be able to compare the range returned by `ctx.global` to the range of the `ExprName`. I think that's what we do for the other `global` error:

https://github.com/astral-sh/ruff/blob/e8540d9b085980bef22cc8e1d4c6e75531cf140c/crates/ruff_python_parser/src/semantic_errors.rs#L858-L860

Code after:
                if ctx.python_version() > PythonVersion::PY313 {
                    // test_ok valid_annotation_py313
                    // # parse_options: {"target-version": "3.13"}
                    // a: (x := 1)
                    // def outer():
                    //     b: (yield 1)
                    //     c: (yield from 1)
                    // async def outer():
                    //     d: (await 1)

                    // test_err invalid_annotation_py314
                    // # parse_options: {"target-version": "3.14"}
                    // a: (x := 1)
                    // def outer():
                    //     b: (yield 1)
                    //     c: (yield from 1)
                    // async def outer():
                    //     d: (await 1)
                    let mut visitor = InvalidExpressionVisitor {
                        position: InvalidExpressionPosition::TypeAnnotation,
                        ctx,
                    };
                    visitor.visit_expr(annotation);
                }
                if let Expr::Name(ast::ExprName { id, .. }) = target.as_ref() {
                    if let Some(global_stmt) = ctx.global(id.as_str()) {
                        let global_start = global_stmt.start();
                        if !ctx.in_module_scope() || target.start() < global_start {
                            Self::add_error(
                                ctx,
                                SemanticSyntaxErrorKind::AnnotatedGlobal(id.to_string()),
                                target.range(),
                            );
                        }
                    }
                }
            }
            Stmt::FunctionDef(ast::StmtFunctionDef {
                type_params,
                parameters,
                returns,
                ..
            }) => {
                // test_ok valid_annotation_function_py313
                // # parse_options: {"target-version": "3.13"}
                // def f() -> (y := 3): ...
                // def g(arg: (x := 1)): ...
                // def outer():
                //     def i(x: (yield 1)): ...
                //     def k() -> (yield 1): ...
                //     def m(x: (yield from 1)): ...