Skip to content

Commit ed5a057

Browse files
ilevkivskyiJukkaL
authored andcommitted
Push correct enclosing class while deferring a method (#4073)
Fixes #4069 This pushes the correct enclosing class while deferring a method instead of just the top class.
1 parent bf9dc4c commit ed5a057

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

mypy/checker.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,15 @@ def check_top_level(self, node: MypyFile) -> None:
261261

262262
def handle_cannot_determine_type(self, name: str, context: Context) -> None:
263263
node = self.scope.top_function()
264-
if (self.pass_num < LAST_PASS and node is not None
265-
and isinstance(node, (FuncDef, LambdaExpr))):
264+
if self.pass_num < LAST_PASS and isinstance(node, (FuncDef, LambdaExpr)):
266265
# Don't report an error yet. Just defer.
267266
if self.errors.type_name:
268267
type_name = self.errors.type_name[-1]
269268
else:
270269
type_name = None
271270
# Shouldn't we freeze the entire scope?
272-
active_class = self.scope.active_class()
273-
self.deferred_nodes.append(DeferredNode(node, type_name, active_class))
271+
enclosing_class = self.scope.enclosing_class()
272+
self.deferred_nodes.append(DeferredNode(node, type_name, enclosing_class))
274273
# Set a marker so that we won't infer additional types in this
275274
# function. Any inferred types could be bogus, because there's at
276275
# least one type that we don't know.
@@ -3403,6 +3402,16 @@ def active_class(self) -> Optional[TypeInfo]:
34033402
return self.stack[-1]
34043403
return None
34053404

3405+
def enclosing_class(self) -> Optional[TypeInfo]:
3406+
top = self.top_function()
3407+
assert top, "This method must be called from inside a function"
3408+
index = self.stack.index(top)
3409+
assert index, "Scope stack must always start with a module"
3410+
enclosing = self.stack[index - 1]
3411+
if isinstance(enclosing, TypeInfo):
3412+
return enclosing
3413+
return None
3414+
34063415
def active_self_type(self) -> Optional[Union[Instance, TupleType]]:
34073416
info = self.active_class()
34083417
if info:

test-data/unit/check-classes.test

+35
Original file line numberDiff line numberDiff line change
@@ -3996,6 +3996,41 @@ class F(six.with_metaclass(t.M)): pass
39963996
@six.add_metaclass(t.M)
39973997
class G: pass
39983998

3999+
[case testCorrectEnclosingClassPushedInDeferred]
4000+
class C:
4001+
def __getattr__(self, attr: str) -> int:
4002+
x: F
4003+
return x.f
4004+
4005+
class F:
4006+
def __init__(self, f: int) -> None:
4007+
self.f = f
4008+
[out]
4009+
4010+
[case testCorrectEnclosingClassPushedInDeferred2]
4011+
from typing import TypeVar
4012+
T = TypeVar('T', bound=C)
4013+
class C:
4014+
def m(self: T) -> T:
4015+
class Inner:
4016+
x: F
4017+
f = x.f
4018+
return self
4019+
4020+
class F:
4021+
def __init__(self, f: int) -> None:
4022+
self.f = f
4023+
[out]
4024+
4025+
[case testCorrectEnclosingClassPushedInDeferred3]
4026+
class A:
4027+
def f(self) -> None:
4028+
def g(x: int) -> int:
4029+
return y
4030+
4031+
y = int()
4032+
[out]
4033+
39994034
[case testMetaclassMemberAccessViaType]
40004035
from typing import Type
40014036
class M(type):

0 commit comments

Comments
 (0)