Skip to content

Commit ef6f156

Browse files
ilevkivskyiJukkaL
authored andcommitted
Fix crash on access to local classes (#2855)
Fixes #2559 The idea is the same as in PR #2553. The only difference is that mangled names are always stored in globals, otherwise there would be a problem for a method in a nested class that is itself inside a method.
1 parent e1774a7 commit ef6f156

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

mypy/semanal.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,15 @@ def setup_class_def_analysis(self, defn: ClassDef) -> None:
850850
kind = MDEF
851851
if self.is_func_scope():
852852
kind = LDEF
853-
self.add_symbol(defn.name, SymbolTableNode(kind, defn.info), defn)
853+
node = SymbolTableNode(kind, defn.info)
854+
self.add_symbol(defn.name, node, defn)
855+
if kind == LDEF:
856+
# We need to preserve local classes, let's store them
857+
# in globals under mangled unique names
858+
local_name = defn.info._fullname + '@' + str(defn.line)
859+
defn.info._fullname = self.cur_mod_id + '.' + local_name
860+
defn.fullname = defn.info._fullname
861+
self.globals[local_name] = node
854862

855863
def analyze_base_classes(self, defn: ClassDef) -> None:
856864
"""Analyze and set up base classes.

test-data/unit/check-incremental.test

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,53 @@ main:2: error: Revealed type is 'TypedDict(x=builtins.int, _fallback=typing.Mapp
17681768
main:3: error: Revealed type is 'TypedDict(x=builtins.int, _fallback=ntcrash.C.A@4)'
17691769
main:4: error: Revealed type is 'def () -> ntcrash.C.A@4'
17701770

1771+
[case testIncrementalInnerClassAttrInMethod]
1772+
import crash
1773+
nonexisting
1774+
[file crash.py]
1775+
class C:
1776+
def f(self) -> None:
1777+
class A:
1778+
pass
1779+
self.a = A()
1780+
[out1]
1781+
main:2: error: Name 'nonexisting' is not defined
1782+
[out2]
1783+
main:2: error: Name 'nonexisting' is not defined
1784+
1785+
[case testIncrementalInnerClassAttrInMethodReveal]
1786+
import crash
1787+
reveal_type(crash.C().a)
1788+
reveal_type(crash.D().a)
1789+
[file crash.py]
1790+
from typing import TypeVar, Generic
1791+
T = TypeVar('T')
1792+
class C:
1793+
def f(self) -> None:
1794+
class A:
1795+
pass
1796+
self.a = A()
1797+
reveal_type(C().a)
1798+
class D:
1799+
def f(self) -> None:
1800+
class A:
1801+
def g(self) -> None:
1802+
class B(Generic[T]):
1803+
pass
1804+
self.b = B[int]()
1805+
self.a = A().b
1806+
reveal_type(D().a)
1807+
[out1]
1808+
tmp/crash.py:8: error: Revealed type is 'crash.A@5'
1809+
tmp/crash.py:17: error: Revealed type is 'crash.B@13[builtins.int*]'
1810+
main:2: error: Revealed type is 'crash.A@5'
1811+
main:3: error: Revealed type is 'crash.B@13[builtins.int*]'
1812+
[out2]
1813+
tmp/crash.py:8: error: Revealed type is 'crash.A@5'
1814+
tmp/crash.py:17: error: Revealed type is 'crash.B@13[builtins.int*]'
1815+
main:2: error: Revealed type is 'crash.A@5'
1816+
main:3: error: Revealed type is 'crash.B@13[builtins.int*]'
1817+
17711818
[case testGenericMethodRestoreMetaLevel]
17721819
from typing import Dict
17731820

test-data/unit/semanal-classes.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ MypyFile:1(
315315
A
316316
PassStmt:2())
317317
ExpressionStmt:3(
318-
NameExpr(A [l])))))
318+
NameExpr(A [__main__.A@2])))))
319319

320320
[case testReferenceToClassWithinClass]
321321
class A:
@@ -364,7 +364,7 @@ MypyFile:1(
364364
AssignmentStmt:3(
365365
NameExpr(x [l])
366366
NameExpr(None [builtins.None])
367-
A))))
367+
__main__.A@2))))
368368

369369
[case testAccessToLocalInOuterScopeWithinNestedClass]
370370
def f(x):

0 commit comments

Comments
 (0)