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 , PromoteExpr ,
22
+ Import , ImportFrom , ImportAll , ImportBase ,
23
+ ARG_POS , ARG_STAR , 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
@@ -875,9 +870,11 @@ def is_trivial_body(self, block: Block) -> bool:
875
870
(isinstance (stmt , ExpressionStmt ) and
876
871
isinstance (stmt .expr , EllipsisExpr )))
877
872
878
- def check_reverse_op_method (self , defn : FuncItem , typ : CallableType ,
879
- method : str , context : Context ) -> None :
873
+ def check_reverse_op_method (self , defn : FuncItem ,
874
+ reverse_type : CallableType , reverse_name : str ,
875
+ context : Context ) -> None :
880
876
"""Check a reverse operator method such as __radd__."""
877
+ # Decides whether it's worth calling check_overlapping_op_methods().
881
878
882
879
# This used to check for some very obscure scenario. It now
883
880
# just decides whether it's worth calling
@@ -890,54 +887,57 @@ def check_reverse_op_method(self, defn: FuncItem, typ: CallableType,
890
887
[None , None ],
891
888
AnyType (TypeOfAny .special_form ),
892
889
self .named_type ('builtins.function' ))
893
- if not is_subtype (typ , method_type ):
894
- self .msg .invalid_signature (typ , context )
890
+ if not is_subtype (reverse_type , method_type ):
891
+ self .msg .invalid_signature (reverse_type , context )
895
892
return
896
893
897
- if method in ('__eq__' , '__ne__' ):
894
+ if reverse_name in ('__eq__' , '__ne__' ):
898
895
# These are defined for all objects => can't cause trouble.
899
896
return
900
897
901
898
# With 'Any' or 'object' return type we are happy, since any possible
902
899
# return value is valid.
903
- ret_type = typ .ret_type
900
+ ret_type = reverse_type .ret_type
904
901
if isinstance (ret_type , AnyType ):
905
902
return
906
903
if isinstance (ret_type , Instance ):
907
904
if ret_type .type .fullname () == 'builtins.object' :
908
905
return
909
-
910
- if len (typ .arg_types ) == 2 :
911
- # TODO check self argument kind
912
-
913
- # Check for the issue described above.
914
- arg_type = typ .arg_types [1 ]
915
- other_method = nodes .normal_from_reverse_op [method ]
916
- if isinstance (arg_type , Instance ):
917
- if not arg_type .type .has_readable_member (other_method ):
918
- return
919
- elif isinstance (arg_type , AnyType ):
920
- return
921
- elif isinstance (arg_type , UnionType ):
922
- if not arg_type .has_readable_member (other_method ):
923
- return
924
- else :
925
- return
926
-
927
- typ2 = self .expr_checker .analyze_external_member_access (
928
- other_method , arg_type , defn )
929
- self .check_overlapping_op_methods (
930
- typ , method , defn .info ,
931
- typ2 , other_method , cast (Instance , arg_type ),
932
- defn )
906
+ if reverse_type .arg_kinds [0 ] == ARG_STAR :
907
+ reverse_type = reverse_type .copy_modified (arg_types = [reverse_type .arg_types [0 ]] * 2 ,
908
+ arg_kinds = [ARG_POS ] * 2 ,
909
+ arg_names = [reverse_type .arg_names [0 ], "_" ])
910
+ assert len (reverse_type .arg_types ) == 2
911
+
912
+ forward_name = nodes .normal_from_reverse_op [reverse_name ]
913
+ forward_inst = reverse_type .arg_types [1 ]
914
+ if isinstance (forward_inst , TypeVarType ):
915
+ forward_inst = forward_inst .upper_bound
916
+ if isinstance (forward_inst , (FunctionLike , TupleType , TypedDictType )):
917
+ forward_inst = forward_inst .fallback
918
+ if isinstance (forward_inst , TypeType ):
919
+ item = forward_inst .item
920
+ if isinstance (item , Instance ):
921
+ opt_meta = item .type .metaclass_type
922
+ if opt_meta is not None :
923
+ forward_inst = opt_meta
924
+ if not (isinstance (forward_inst , (Instance , UnionType ))
925
+ and forward_inst .has_readable_member (forward_name )):
926
+ return
927
+ forward_base = reverse_type .arg_types [1 ]
928
+ forward_type = self .expr_checker .analyze_external_member_access (forward_name , forward_base ,
929
+ context = defn )
930
+ self .check_overlapping_op_methods (reverse_type , reverse_name , defn .info ,
931
+ forward_type , forward_name , forward_base ,
932
+ context = defn )
933
933
934
934
def check_overlapping_op_methods (self ,
935
935
reverse_type : CallableType ,
936
936
reverse_name : str ,
937
937
reverse_class : TypeInfo ,
938
938
forward_type : Type ,
939
939
forward_name : str ,
940
- forward_base : Instance ,
940
+ forward_base : Type ,
941
941
context : Context ) -> None :
942
942
"""Check for overlapping method and reverse method signatures.
943
943
@@ -998,8 +998,8 @@ def check_overlapping_op_methods(self,
998
998
if is_unsafe_overlapping_signatures (forward_tweaked ,
999
999
reverse_tweaked ):
1000
1000
self .msg .operator_method_signatures_overlap (
1001
- reverse_class . name () , reverse_name ,
1002
- forward_base . type . name () , forward_name , context )
1001
+ reverse_class , reverse_name ,
1002
+ forward_base , forward_name , context )
1003
1003
elif isinstance (forward_item , Overloaded ):
1004
1004
for item in forward_item .items ():
1005
1005
self .check_overlapping_op_methods (
0 commit comments