mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 22:54:42 +00:00
[red-knot] Add mdtests for global
statement (#17563)
## Summary This is a first step toward `global` support in red-knot (#15385). I went through all the matches for `global` in the `mypy/test-data` directory, but I didn't find anything too interesting that wasn't already covered by @carljm's suggestions on Discord. I still pulled in a couple of cases for a little extra variety. I also included a section from the [PLE0118](https://docs.astral.sh/ruff/rules/load-before-global-declaration/) tests in ruff that will become syntax errors once #17463 is merged and we handle `global` statements. I don't think I figured out how to use `@Todo` properly, so please let me know if I need to fix that. I hope this is a good start to the test suite otherwise. --------- Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
parent
d5410ef9fe
commit
bfc1650198
2 changed files with 177 additions and 11 deletions
|
@ -0,0 +1,177 @@
|
||||||
|
# `global` references
|
||||||
|
|
||||||
|
## Implicit global in function
|
||||||
|
|
||||||
|
A name reference to a never-defined symbol in a function is implicitly a global lookup.
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
reveal_type(x) # revealed: Unknown | Literal[1]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explicit global in function
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
reveal_type(x) # revealed: Unknown | Literal[1]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unassignable type in function
|
||||||
|
|
||||||
|
```py
|
||||||
|
x: int = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
y: int = 1
|
||||||
|
# error: [invalid-assignment] "Object of type `Literal[""]` is not assignable to `int`"
|
||||||
|
y = ""
|
||||||
|
|
||||||
|
global x
|
||||||
|
# TODO: error: [invalid-assignment] "Object of type `Literal[""]` is not assignable to `int`"
|
||||||
|
x = ""
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nested intervening scope
|
||||||
|
|
||||||
|
A `global` statement causes lookup to skip any bindings in intervening scopes:
|
||||||
|
|
||||||
|
```py
|
||||||
|
x: int = 1
|
||||||
|
|
||||||
|
def outer():
|
||||||
|
x: str = ""
|
||||||
|
|
||||||
|
def inner():
|
||||||
|
global x
|
||||||
|
# TODO: revealed: int
|
||||||
|
reveal_type(x) # revealed: str
|
||||||
|
```
|
||||||
|
|
||||||
|
## Narrowing
|
||||||
|
|
||||||
|
An assignment following a `global` statement should narrow the type in the local scope after the
|
||||||
|
assignment.
|
||||||
|
|
||||||
|
```py
|
||||||
|
x: int | None
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
x = 1
|
||||||
|
reveal_type(x) # revealed: Literal[1]
|
||||||
|
```
|
||||||
|
|
||||||
|
## `nonlocal` and `global`
|
||||||
|
|
||||||
|
A binding cannot be both `nonlocal` and `global`. This should emit a semantic syntax error. CPython
|
||||||
|
marks the `nonlocal` line, while `mypy`, `pyright`, and `ruff` (`PLE0115`) mark the `global` line.
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
x = 1
|
||||||
|
def g() -> None:
|
||||||
|
nonlocal x
|
||||||
|
global x # TODO: error: [invalid-syntax] "name 'x' is nonlocal and global"
|
||||||
|
x = None
|
||||||
|
```
|
||||||
|
|
||||||
|
## Global declaration after `global` statement
|
||||||
|
|
||||||
|
```py
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
# TODO this should also not be an error
|
||||||
|
y = x # error: [unresolved-reference] "Name `x` used when not defined"
|
||||||
|
x = 1 # No error.
|
||||||
|
|
||||||
|
x = 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Semantic syntax errors
|
||||||
|
|
||||||
|
Using a name prior to its `global` declaration in the same scope is a syntax error.
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
print(x) # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
print(x) # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
def f():
|
||||||
|
print(x) # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x, y
|
||||||
|
print(x) # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
print(x)
|
||||||
|
|
||||||
|
def f():
|
||||||
|
x = 1 # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
x = 1 # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
def f():
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x, y
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global x, y
|
||||||
|
del x # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x, y
|
||||||
|
del x
|
||||||
|
|
||||||
|
def f():
|
||||||
|
print(f"{x=}") # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
|
||||||
|
# still an error in module scope
|
||||||
|
x = None # TODO: error: [invalid-syntax] name `x` is used prior to global declaration
|
||||||
|
global x
|
||||||
|
```
|
|
@ -43,14 +43,3 @@ def f():
|
||||||
def h():
|
def h():
|
||||||
reveal_type(x) # revealed: Unknown | Literal[1]
|
reveal_type(x) # revealed: Unknown | Literal[1]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Implicit global in function
|
|
||||||
|
|
||||||
A name reference to a never-defined symbol in a function is implicitly a global lookup.
|
|
||||||
|
|
||||||
```py
|
|
||||||
x = 1
|
|
||||||
|
|
||||||
def f():
|
|
||||||
reveal_type(x) # revealed: Unknown | Literal[1]
|
|
||||||
```
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue