|
3 | 3 | import itertools
|
4 | 4 | import fnmatch
|
5 | 5 | from contextlib import contextmanager
|
6 |
| -import sys |
7 | 6 |
|
8 | 7 | from typing import (
|
9 | 8 | Dict, Set, List, cast, Tuple, TypeVar, Union, Optional, NamedTuple, Iterator
|
10 | 9 | )
|
11 | 10 |
|
12 | 11 | from mypy.errors import Errors, report_internal_error
|
13 | 12 | from mypy.nodes import (
|
14 |
| - SymbolTable, Statement, MypyFile, Var, Expression, Lvalue, |
| 13 | + SymbolTable, Statement, MypyFile, Var, Expression, Lvalue, Node, |
15 | 14 | OverloadedFuncDef, FuncDef, FuncItem, FuncBase, TypeInfo,
|
16 |
| - ClassDef, GDEF, Block, AssignmentStmt, NameExpr, MemberExpr, IndexExpr, |
| 15 | + ClassDef, Block, AssignmentStmt, NameExpr, MemberExpr, IndexExpr, |
17 | 16 | TupleExpr, ListExpr, ExpressionStmt, ReturnStmt, IfStmt,
|
18 | 17 | WhileStmt, OperatorAssignmentStmt, WithStmt, AssertStmt,
|
19 | 18 | RaiseStmt, TryStmt, ForStmt, DelStmt, CallExpr, IntExpr, StrExpr,
|
20 |
| - BytesExpr, UnicodeExpr, FloatExpr, OpExpr, UnaryExpr, CastExpr, RevealTypeExpr, SuperExpr, |
21 |
| - TypeApplication, DictExpr, SliceExpr, LambdaExpr, TempNode, SymbolTableNode, |
22 |
| - Context, ListComprehension, ConditionalExpr, GeneratorExpr, |
23 |
| - Decorator, SetExpr, TypeVarExpr, NewTypeExpr, PrintStmt, |
24 |
| - LITERAL_TYPE, BreakStmt, PassStmt, ContinueStmt, ComparisonExpr, StarExpr, |
25 |
| - YieldFromExpr, NamedTupleExpr, TypedDictExpr, SetComprehension, |
26 |
| - DictionaryComprehension, ComplexExpr, EllipsisExpr, TypeAliasExpr, |
27 |
| - RefExpr, YieldExpr, BackquoteExpr, Import, ImportFrom, ImportAll, ImportBase, |
28 |
| - AwaitExpr, PromoteExpr, Node, EnumCallExpr, |
29 |
| - ARG_POS, MDEF, |
30 |
| - CONTRAVARIANT, COVARIANT, INVARIANT) |
| 19 | + UnicodeExpr, OpExpr, UnaryExpr, LambdaExpr, TempNode, SymbolTableNode, |
| 20 | + Context, Decorator, PrintStmt, BreakStmt, PassStmt, ContinueStmt, |
| 21 | + ComparisonExpr, StarExpr, EllipsisExpr, RefExpr, |
| 22 | + Import, ImportFrom, ImportAll, ImportBase, |
| 23 | + ARG_POS, LITERAL_TYPE, MDEF, GDEF, |
| 24 | + CONTRAVARIANT, COVARIANT, INVARIANT, |
| 25 | +) |
31 | 26 | from mypy import nodes
|
32 | 27 | from mypy.literals import literal, literal_hash
|
33 | 28 | from mypy.typeanal import has_any_from_unimported_type, check_for_explicit_any
|
34 | 29 | from mypy.types import (
|
35 | 30 | Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType,
|
36 | 31 | Instance, NoneTyp, strip_type, TypeType, TypeOfAny,
|
37 | 32 | UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
|
38 |
| - true_only, false_only, function_type, is_named_instance, union_items |
| 33 | + true_only, false_only, function_type, is_named_instance, union_items, |
39 | 34 | )
|
40 | 35 | from mypy.sametypes import is_same_type, is_same_types
|
41 | 36 | from mypy.messages import MessageBuilder, make_inferred_type_note
|
@@ -811,59 +806,50 @@ def is_trivial_body(self, block: Block) -> bool:
|
811 | 806 | (isinstance(stmt, ExpressionStmt) and
|
812 | 807 | isinstance(stmt.expr, EllipsisExpr)))
|
813 | 808 |
|
814 |
| - def check_reverse_op_method(self, defn: FuncItem, typ: CallableType, |
815 |
| - method: str) -> None: |
| 809 | + def check_reverse_op_method(self, defn: FuncItem, |
| 810 | + reverse_type: CallableType, reverse_name: str) -> None: |
816 | 811 | """Check a reverse operator method such as __radd__."""
|
| 812 | + # Decides whether it's worth calling check_overlapping_op_methods(). |
817 | 813 |
|
818 |
| - # This used to check for some very obscure scenario. It now |
819 |
| - # just decides whether it's worth calling |
820 |
| - # check_overlapping_op_methods(). |
821 |
| - |
822 |
| - if method in ('__eq__', '__ne__'): |
| 814 | + if reverse_name in ('__eq__', '__ne__'): |
823 | 815 | # These are defined for all objects => can't cause trouble.
|
824 | 816 | return
|
825 | 817 |
|
826 | 818 | # With 'Any' or 'object' return type we are happy, since any possible
|
827 | 819 | # return value is valid.
|
828 |
| - ret_type = typ.ret_type |
| 820 | + ret_type = reverse_type.ret_type |
829 | 821 | if isinstance(ret_type, AnyType):
|
830 | 822 | return
|
831 | 823 | if isinstance(ret_type, Instance):
|
832 | 824 | if ret_type.type.fullname() == 'builtins.object':
|
833 | 825 | return
|
| 826 | + |
834 | 827 | # Plausibly the method could have too few arguments, which would result
|
835 | 828 | # in an error elsewhere.
|
836 |
| - if len(typ.arg_types) <= 2: |
837 |
| - # TODO check self argument kind |
838 |
| - |
839 |
| - # Check for the issue described above. |
840 |
| - arg_type = typ.arg_types[1] |
841 |
| - other_method = nodes.normal_from_reverse_op[method] |
842 |
| - if isinstance(arg_type, Instance): |
843 |
| - if not arg_type.type.has_readable_member(other_method): |
844 |
| - return |
845 |
| - elif isinstance(arg_type, AnyType): |
846 |
| - return |
847 |
| - elif isinstance(arg_type, UnionType): |
848 |
| - if not arg_type.has_readable_member(other_method): |
849 |
| - return |
850 |
| - else: |
851 |
| - return |
| 829 | + if len(reverse_type.arg_types) != 2: |
| 830 | + return |
852 | 831 |
|
853 |
| - typ2 = self.expr_checker.analyze_external_member_access( |
854 |
| - other_method, arg_type, defn) |
855 |
| - self.check_overlapping_op_methods( |
856 |
| - typ, method, defn.info, |
857 |
| - typ2, other_method, cast(Instance, arg_type), |
858 |
| - defn) |
| 832 | + forward_name = nodes.normal_from_reverse_op[reverse_name] |
| 833 | + forward_base = reverse_type.arg_types[1] |
| 834 | + if isinstance(forward_base, (FunctionLike, TupleType, TypedDictType)): |
| 835 | + forward_base = forward_base.fallback |
| 836 | + if not (isinstance(forward_base, (Instance, UnionType)) |
| 837 | + and forward_base.has_readable_member(forward_name)): |
| 838 | + return |
| 839 | + |
| 840 | + forward_type = self.expr_checker.analyze_external_member_access(forward_name, forward_base, |
| 841 | + context=defn) |
| 842 | + self.check_overlapping_op_methods(reverse_type, reverse_name, defn.info, |
| 843 | + forward_type, forward_name, forward_base, |
| 844 | + context=defn) |
859 | 845 |
|
860 | 846 | def check_overlapping_op_methods(self,
|
861 | 847 | reverse_type: CallableType,
|
862 | 848 | reverse_name: str,
|
863 | 849 | reverse_class: TypeInfo,
|
864 | 850 | forward_type: Type,
|
865 | 851 | forward_name: str,
|
866 |
| - forward_base: Instance, |
| 852 | + forward_base: Type, |
867 | 853 | context: Context) -> None:
|
868 | 854 | """Check for overlapping method and reverse method signatures.
|
869 | 855 |
|
@@ -924,8 +910,8 @@ def check_overlapping_op_methods(self,
|
924 | 910 | if is_unsafe_overlapping_signatures(forward_tweaked,
|
925 | 911 | reverse_tweaked):
|
926 | 912 | self.msg.operator_method_signatures_overlap(
|
927 |
| - reverse_class.name(), reverse_name, |
928 |
| - forward_base.type.name(), forward_name, context) |
| 913 | + reverse_class, reverse_name, |
| 914 | + forward_base, forward_name, context) |
929 | 915 | elif isinstance(forward_item, Overloaded):
|
930 | 916 | for item in forward_item.items():
|
931 | 917 | self.check_overlapping_op_methods(
|
|
0 commit comments