Skip to content

Commit 70ee798

Browse files
authored
Local forward refs should precede global forward refs (#19000)
Fixes #18988 This should be a minimal change to restore backwards compatibility for an edge case with forward references.
1 parent 7b4f631 commit 70ee798

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

mypy/semanal.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6382,6 +6382,8 @@ class C:
63826382
if node.name not in self.globals:
63836383
return True
63846384
global_node = self.globals[node.name]
6385+
if not self.is_textually_before_class(global_node.node):
6386+
return True
63856387
return not self.is_type_like(global_node.node)
63866388
return False
63876389

@@ -6409,6 +6411,13 @@ def is_textually_before_statement(self, node: SymbolNode) -> bool:
64096411
else:
64106412
return line_diff > 0
64116413

6414+
def is_textually_before_class(self, node: SymbolNode | None) -> bool:
6415+
"""Similar to above, but check if a node is defined before current class."""
6416+
assert self.type is not None
6417+
if node is None:
6418+
return False
6419+
return node.line < self.type.defn.line
6420+
64126421
def is_overloaded_item(self, node: SymbolNode, statement: Statement) -> bool:
64136422
"""Check whether the function belongs to the overloaded variants"""
64146423
if isinstance(node, OverloadedFuncDef) and isinstance(statement, FuncDef):

test-data/unit/check-python312.test

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,15 +2004,18 @@ reveal_type(x.related_resources) # N: Revealed type is "__main__.ResourceRule"
20042004

20052005
[case testPEP695TypeAliasRecursiveOuterClass]
20062006
class A:
2007-
type X = X
2007+
type X = X # E: Cannot resolve name "X" (possible cyclic definition)
20082008
class X: ...
20092009

2010+
class AA:
2011+
XX = XX # OK, we allow this as a special case.
2012+
class XX: ...
2013+
20102014
class Y: ...
20112015
class B:
20122016
type Y = Y
20132017

2014-
x: A.X
2015-
reveal_type(x) # N: Revealed type is "__main__.X"
2018+
reveal_type(AA.XX) # N: Revealed type is "def () -> __main__.XX"
20162019
y: B.Y
20172020
reveal_type(y) # N: Revealed type is "__main__.Y"
20182021
[builtins fixtures/tuple.pyi]
@@ -2042,3 +2045,17 @@ tuple[*tuple[int, ...], *tuple[int, ...]] # E: More than one Unpack in a type i
20422045
b: tuple[*tuple[int, ...], *tuple[int, ...]] # E: More than one Unpack in a type is not allowed
20432046
[builtins fixtures/tuple.pyi]
20442047
[typing fixtures/typing-full.pyi]
2048+
2049+
[case testForwardNestedPrecedesForwardGlobal]
2050+
from typing import NewType
2051+
2052+
class W[T]: pass
2053+
2054+
class R:
2055+
class M(W[Action.V], type):
2056+
FOO = R.Action.V(0)
2057+
class Action(metaclass=M):
2058+
V = NewType('V', int)
2059+
2060+
class Action:
2061+
pass

0 commit comments

Comments
 (0)