Skip to content

Commit

Permalink
[partially defined] fix false positive with global/nonlocal vars (#14222
Browse files Browse the repository at this point in the history
)

This is a workaround until we implement better handling for variables
undefined in global scope (see #14213).

We treat `global/nonlocal` as a variable declaration. I've included test
cases that should fail in the future once we implement the check
properly.
  • Loading branch information
ilinum authored Nov 29, 2022
1 parent 3a3cf41 commit 98f1b00
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
12 changes: 12 additions & 0 deletions mypy/partially_defined.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
FuncDef,
FuncItem,
GeneratorExpr,
GlobalDecl,
IfStmt,
Import,
ImportFrom,
Expand All @@ -25,6 +26,7 @@
Lvalue,
MatchStmt,
NameExpr,
NonlocalDecl,
RaiseStmt,
RefExpr,
ReturnStmt,
Expand Down Expand Up @@ -279,6 +281,16 @@ def process_definition(self, name: str) -> None:
self.var_used_before_def(name, ref)
self.tracker.record_definition(name)

def visit_global_decl(self, o: GlobalDecl) -> None:
for name in o.names:
self.process_definition(name)
super().visit_global_decl(o)

def visit_nonlocal_decl(self, o: NonlocalDecl) -> None:
for name in o.names:
self.process_definition(name)
super().visit_nonlocal_decl(o)

def process_lvalue(self, lvalue: Lvalue | None) -> None:
if isinstance(lvalue, NameExpr):
self.process_definition(lvalue.name)
Expand Down
43 changes: 43 additions & 0 deletions test-data/unit/check-partially-defined.test
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,49 @@ if int():
y = 3
x = y # E: Name "y" may be undefined

[case testVarDefinedInOuterScopeUpdated]
# flags: --enable-error-code partially-defined --enable-error-code use-before-def
def f0() -> None:
global x
y = x
x = 1 # No error.

x = 2

[case testNonlocalVar]
# flags: --enable-error-code partially-defined --enable-error-code use-before-def
def f0() -> None:
x = 2

def inner() -> None:
nonlocal x
y = x
x = 1 # No error.


[case testGlobalDeclarationAfterUsage]
# flags: --enable-error-code partially-defined --enable-error-code use-before-def
def f0() -> None:
y = x # E: Name "x" is used before definition
global x
x = 1 # No error.

x = 2
[case testVarDefinedInOuterScope]
# flags: --enable-error-code partially-defined --enable-error-code use-before-def
def f0() -> None:
global x
y = x # We do not detect such errors right now.

f0()
x = 1
[case testDefinedInOuterScopeNoError]
# flags: --enable-error-code partially-defined --enable-error-code use-before-def
def foo() -> None:
bar()

def bar() -> None:
foo()
[case testFuncParams]
# flags: --enable-error-code partially-defined
def foo(a: int) -> None:
Expand Down

0 comments on commit 98f1b00

Please sign in to comment.