88import mypy .typeops
99from mypy .expandtype import expand_type
1010from mypy .maptype import map_instance_to_supertype
11- from mypy .nodes import CONTRAVARIANT , COVARIANT , INVARIANT , VARIANCE_NOT_READY , TypeInfo
11+ from mypy .nodes import (
12+ ARG_NAMED ,
13+ ARG_POS ,
14+ CONTRAVARIANT ,
15+ COVARIANT ,
16+ INVARIANT ,
17+ VARIANCE_NOT_READY ,
18+ ArgKind ,
19+ TypeInfo ,
20+ )
1221from mypy .state import state
1322from mypy .subtypes import (
1423 SubtypeContext ,
@@ -328,7 +337,7 @@ def visit_unpack_type(self, t: UnpackType) -> UnpackType:
328337
329338 def visit_parameters (self , t : Parameters ) -> ProperType :
330339 if isinstance (self .s , Parameters ):
331- if not is_similar_params (t , self .s ):
340+ if not is_similar_callables (t , self .s ):
332341 # TODO: it would be prudent to return [*object, **object] instead of Any.
333342 return self .default (self .s )
334343 from mypy .meet import meet_types
@@ -337,6 +346,7 @@ def visit_parameters(self, t: Parameters) -> ProperType:
337346 arg_types = [
338347 meet_types (s_a , t_a ) for s_a , t_a in zip (self .s .arg_types , t .arg_types )
339348 ],
349+ arg_kinds = combine_arg_kinds (self .s , t ),
340350 arg_names = combine_arg_names (self .s , t ),
341351 )
342352 else :
@@ -752,24 +762,29 @@ def normalize_callables(s: ProperType, t: ProperType) -> tuple[ProperType, Prope
752762 return s , t
753763
754764
755- def is_similar_callables (t : CallableType , s : CallableType ) -> bool :
756- """Return True if t and s have identical numbers of
757- arguments, default arguments and varargs.
758- """
759- return (
760- len (t .arg_types ) == len (s .arg_types )
761- and t .min_args == s .min_args
762- and t .is_var_arg == s .is_var_arg
763- )
764-
765+ def is_similar_callables (
766+ t : CallableType | Parameters , s : CallableType | Parameters , for_meet : bool = False
767+ ) -> bool :
768+ """Return True if t and s have identical numbers of arguments with similar shape.
765769
766- def is_similar_params (t : Parameters , s : Parameters ) -> bool :
767- # This matches the logic in is_similar_callables() above.
768- return (
769- len (t .arg_types ) == len (s .arg_types )
770- and t .min_args == s .min_args
771- and (t .var_arg () is not None ) == (s .var_arg () is not None )
772- )
770+ If for_meet is True, the argument names must always match.
771+ """
772+ if len (t .variables ) != len (s .variables ):
773+ return False
774+ if len (t .arg_types ) != len (s .arg_types ):
775+ return False
776+ for i , (t_kind , s_kind ) in enumerate (zip (t .arg_kinds , s .arg_kinds )):
777+ if t .arg_names [i ] != s .arg_names [i ]:
778+ if for_meet or t_kind .is_named ():
779+ return False
780+ if t_kind == s_kind :
781+ continue
782+ if t_kind .is_positional () and s_kind .is_positional ():
783+ continue
784+ if t_kind .is_named () and s_kind .is_named ():
785+ continue
786+ return False
787+ return True
773788
774789
775790def update_callable_ids (c : CallableType , ids : list [TypeVarId ]) -> CallableType :
@@ -803,7 +818,12 @@ def join_similar_callables(t: CallableType, s: CallableType) -> CallableType:
803818 t , s = match_generic_callables (t , s )
804819 arg_types : list [Type ] = []
805820 for i in range (len (t .arg_types )):
806- arg_types .append (safe_meet (t .arg_types [i ], s .arg_types [i ]))
821+ if isinstance (get_proper_type (t .arg_types [i ]), AnyType ):
822+ arg_types .append (t .arg_types [i ])
823+ elif isinstance (get_proper_type (s .arg_types [i ]), AnyType ):
824+ arg_types .append (s .arg_types [i ])
825+ else :
826+ arg_types .append (safe_meet (t .arg_types [i ], s .arg_types [i ]))
807827 # TODO in combine_similar_callables also applies here (names and kinds; user metaclasses)
808828 # The fallback type can be either 'function', 'type', or some user-provided metaclass.
809829 # The result should always use 'function' as a fallback if either operands are using it.
@@ -816,6 +836,7 @@ def join_similar_callables(t: CallableType, s: CallableType) -> CallableType:
816836 instance_type = join_types (t .instance_type , s .instance_type )
817837 return t .copy_modified (
818838 arg_types = arg_types ,
839+ arg_kinds = combine_arg_kinds (t , s ),
819840 arg_names = combine_arg_names (t , s ),
820841 ret_type = join_types (t .ret_type , s .ret_type ),
821842 instance_type = instance_type ,
@@ -874,6 +895,7 @@ def combine_similar_callables(t: CallableType, s: CallableType) -> CallableType:
874895 instance_type = join_types (t .instance_type , s .instance_type )
875896 return t .copy_modified (
876897 arg_types = arg_types ,
898+ arg_kinds = combine_arg_kinds (t , s ),
877899 arg_names = combine_arg_names (t , s ),
878900 ret_type = join_types (t .ret_type , s .ret_type ),
879901 instance_type = instance_type ,
@@ -899,20 +921,35 @@ def combine_arg_names(
899921 Note that the third argument's name is omitted and 't' and 's'
900922 are both valid subtypes of this inferred signature.
901923
902- Precondition: is_similar_types (t, s) is true.
924+ Precondition: is_similar_callables (t, s) is true.
903925 """
904- num_args = len (t .arg_types )
905926 new_names = []
906- for i in range (num_args ):
907- t_name = t .arg_names [i ]
908- s_name = s .arg_names [i ]
909- if t_name == s_name or t .arg_kinds [i ].is_named () or s .arg_kinds [i ].is_named ():
927+ for t_name , s_name in zip (t .arg_names , s .arg_names ):
928+ if t_name == s_name :
910929 new_names .append (t_name )
911930 else :
912931 new_names .append (None )
913932 return new_names
914933
915934
935+ def combine_arg_kinds (t : CallableType | Parameters , s : CallableType | Parameters ) -> list [ArgKind ]:
936+ """Produces a list of argument kinds compatible with both callables.
937+
938+ Essentially we make all arguments non-optional (both positional and named).
939+ Precondition: is_similar_callables(t, s) is true.
940+ """
941+ new_kinds = []
942+ for t_kind , s_kind in zip (t .arg_kinds , s .arg_kinds ):
943+ if t_kind == s_kind :
944+ new_kinds .append (t_kind )
945+ elif t_kind .is_positional ():
946+ new_kinds .append (ARG_POS )
947+ else :
948+ assert t_kind .is_named ()
949+ new_kinds .append (ARG_NAMED )
950+ return new_kinds
951+
952+
916953def object_from_instance (instance : Instance ) -> Instance :
917954 """Construct the type 'builtins.object' from an instance type."""
918955 # Use the fact that 'object' is always the last class in the mro.
0 commit comments