diff --git a/mypy/checker.py b/mypy/checker.py index 7189b3d96faf..763176a3e6ae 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -3938,8 +3938,21 @@ def visit_print_stmt(self, s: PrintStmt) -> None: if s.target: target_type = get_proper_type(self.expr_checker.accept(s.target)) if not isinstance(target_type, NoneType): - # TODO: Also verify the type of 'write'. - self.expr_checker.analyze_external_member_access('write', target_type, s.target) + write_type = self.expr_checker.analyze_external_member_access( + 'write', target_type, s.target) + required_type = CallableType( + arg_types=[self.named_type('builtins.str')], + arg_kinds=[ARG_POS], + arg_names=[None], + ret_type=AnyType(TypeOfAny.implementation_artifact), + fallback=self.named_type('builtins.function'), + ) + # This has to be hard-coded, since it is a syntax pattern, not a function call. + if not is_subtype(write_type, required_type): + self.fail(message_registry.PYTHON2_PRINT_FILE_TYPE.format( + write_type, + required_type, + ), s.target) def visit_break_stmt(self, s: BreakStmt) -> None: self.binder.handle_break() diff --git a/mypy/message_registry.py b/mypy/message_registry.py index a1f6f651af99..eda3081ae204 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -135,6 +135,9 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage": code=codes.TRUTHY_BOOL, ) NOT_CALLABLE: Final = '{} not callable' +PYTHON2_PRINT_FILE_TYPE: Final = ( + 'Argument "file" to "print" has incompatible type "{}"; expected "{}"' +) # Generic GENERIC_INSTANCE_VAR_CLASS_ACCESS: Final = ( diff --git a/test-data/unit/check-python2.test b/test-data/unit/check-python2.test index f9dd8f96f951..30213ba6a26c 100644 --- a/test-data/unit/check-python2.test +++ b/test-data/unit/check-python2.test @@ -27,10 +27,16 @@ class A: # type: (str) -> None pass +class B: + def write(self): + # type: () -> int + pass + print >>A(), '' print >>None, '' print >>1, '' # E: "int" has no attribute "write" print >>(None + ''), None # E: Unsupported left operand type for + ("None") +print >> B(), '' # E: Argument "file" to "print" has incompatible type "def () -> builtins.int"; expected "def (builtins.str) -> Any" [case testDivision] class A: