diff --git a/mypy/checker.py b/mypy/checker.py index 4e15278bb614..bb25f5b95d25 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -65,6 +65,7 @@ [ ('node', FuncItem), ('context_type_name', Optional[str]), # Name of the surrounding class (for error messages) + ('class_type', Optional[Type]), # And its type (from class_context) ]) @@ -202,13 +203,20 @@ def check_second_pass(self) -> bool: todo = self.deferred_nodes self.deferred_nodes = [] done = set() # type: Set[FuncItem] - for node, type_name in todo: + for node, type_name, class_type in todo: if node in done: continue + # This is useful for debugging: + # print("XXX in pass %d, class %s, function %s" % + # (self.pass_num, type_name, node.fullname() or node.name())) done.add(node) if type_name: self.errors.push_type(type_name) + if class_type: + self.class_context.append(class_type) self.accept(node) + if class_type: + self.class_context.pop() if type_name: self.errors.pop_type() return True @@ -221,7 +229,11 @@ def handle_cannot_determine_type(self, name: str, context: Context) -> None: type_name = self.errors.type_name[-1] else: type_name = None - self.deferred_nodes.append(DeferredNode(node, type_name)) + if self.class_context: + class_context_top = self.class_context[-1] + else: + class_context_top = None + self.deferred_nodes.append(DeferredNode(node, type_name, class_context_top)) # Set a marker so that we won't infer additional types in this # function. Any inferred types could be bogus, because there's at # least one type that we don't know. diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 8aac9840097e..67bb4201d8ab 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -1296,6 +1296,14 @@ def deco(f: Callable[[T], int]) -> Callable[[T], int]: main:1: note: In module imported here: tmp/a.py:6: error: Revealed type is 'def (builtins.str*) -> builtins.int' +[case testDeferredClassContext] +class A: + def f(self) -> str: return 'foo' +class B(A): + def f(self) -> str: return self.x + def initialize(self): self.x = 'bar' +[out] + -- Scripts and __main__