|
126 | 126 | find_member, |
127 | 127 | is_same_type, |
128 | 128 | is_subtype, |
| 129 | + merge_typevars_in_callables_by_name, |
129 | 130 | non_method_protocol_members, |
| 131 | + union_function_signatures, |
130 | 132 | ) |
131 | 133 | from mypy.traverser import ( |
132 | 134 | all_name_and_member_expressions, |
@@ -3298,75 +3300,30 @@ def type_overrides_set( |
3298 | 3300 |
|
3299 | 3301 | def combine_function_signatures(self, types: list[ProperType]) -> AnyType | CallableType: |
3300 | 3302 | """Accepts a list of function signatures and attempts to combine them together into a |
3301 | | - new CallableType consisting of the union of all of the given arguments and return types. |
| 3303 | + new CallableType consisting of the union of all the given arguments and return types. |
3302 | 3304 |
|
3303 | 3305 | If there is at least one non-callable type, return Any (this can happen if there is |
3304 | 3306 | an ambiguity because of Any in arguments). |
3305 | 3307 | """ |
3306 | 3308 | assert types, "Trying to merge no callables" |
3307 | 3309 | if not all(isinstance(c, CallableType) for c in types): |
3308 | 3310 | return AnyType(TypeOfAny.special_form) |
3309 | | - |
3310 | 3311 | callables = cast("list[CallableType]", types) |
3311 | | - if len(callables) == 1: |
3312 | | - return callables[0] |
3313 | | - |
3314 | | - # Note: we are assuming here that if a user uses some TypeVar 'T' in |
3315 | | - # two different functions, they meant for that TypeVar to mean the |
3316 | | - # same thing. |
3317 | | - # |
3318 | | - # This function will make sure that all instances of that TypeVar 'T' |
3319 | | - # refer to the same underlying TypeVarType objects to simplify the union-ing |
3320 | | - # logic below. |
3321 | | - # |
3322 | | - # (If the user did *not* mean for 'T' to be consistently bound to the |
3323 | | - # same type in their overloads, well, their code is probably too |
3324 | | - # confusing and ought to be re-written anyways.) |
3325 | | - callables, variables = merge_typevars_in_callables_by_name(callables) |
3326 | 3312 |
|
3327 | | - new_args: list[list[Type]] = [[] for _ in callables[0].arg_types] |
3328 | | - new_kinds = list(callables[0].arg_kinds) |
3329 | | - new_returns: list[Type] = [] |
3330 | | - too_complex = False |
3331 | | - |
3332 | | - for target in callables: |
3333 | | - # We fall back to Callable[..., Union[<returns>]] if the functions do not have |
3334 | | - # the exact same signature. The only exception is if one arg is optional and |
3335 | | - # the other is positional: in that case, we continue unioning (and expect a |
3336 | | - # positional arg). |
3337 | | - # TODO: Enhance the merging logic to handle a wider variety of signatures. |
3338 | | - if len(new_kinds) != len(target.arg_kinds): |
3339 | | - too_complex = True |
3340 | | - break |
3341 | | - for i, (new_kind, target_kind) in enumerate(zip(new_kinds, target.arg_kinds)): |
3342 | | - if new_kind == target_kind: |
3343 | | - continue |
3344 | | - if new_kind.is_positional() and target_kind.is_positional(): |
3345 | | - new_kinds[i] = ARG_POS |
3346 | | - else: |
3347 | | - too_complex = True |
3348 | | - break |
3349 | | - if too_complex: |
3350 | | - break |
3351 | | - for i, arg in enumerate(target.arg_types): |
3352 | | - new_args[i].append(arg) |
3353 | | - new_returns.append(target.ret_type) |
3354 | | - |
3355 | | - union_return = make_simplified_union(new_returns) |
3356 | | - if too_complex: |
3357 | | - any = AnyType(TypeOfAny.special_form) |
3358 | | - return callables[0].copy_modified( |
3359 | | - arg_types=[any, any], |
3360 | | - arg_kinds=[ARG_STAR, ARG_STAR2], |
3361 | | - arg_names=[None, None], |
3362 | | - ret_type=union_return, |
3363 | | - variables=variables, |
3364 | | - implicit=True, |
3365 | | - ) |
| 3313 | + combined = union_function_signatures(callables) |
| 3314 | + if combined is not None: |
| 3315 | + return combined |
3366 | 3316 |
|
| 3317 | + # We fall back to Callable[..., Union[<returns>]] if the functions do not have |
| 3318 | + # the exact same signature. The only exception is if one arg is optional and |
| 3319 | + # the other is positional (and expect a positional arg). |
| 3320 | + callables, variables = merge_typevars_in_callables_by_name(callables) |
| 3321 | + union_return = make_simplified_union([c.ret_type for c in callables]) |
| 3322 | + any = AnyType(TypeOfAny.special_form) |
3367 | 3323 | return callables[0].copy_modified( |
3368 | | - arg_types=[make_simplified_union(args) for args in new_args], |
3369 | | - arg_kinds=new_kinds, |
| 3324 | + arg_types=[any, any], |
| 3325 | + arg_kinds=[ARG_STAR, ARG_STAR2], |
| 3326 | + arg_names=[None, None], |
3370 | 3327 | ret_type=union_return, |
3371 | 3328 | variables=variables, |
3372 | 3329 | implicit=True, |
@@ -6965,51 +6922,6 @@ def all_same_types(types: list[Type]) -> bool: |
6965 | 6922 | return all(is_same_type(t, types[0]) for t in types[1:]) |
6966 | 6923 |
|
6967 | 6924 |
|
6968 | | -def merge_typevars_in_callables_by_name( |
6969 | | - callables: Sequence[CallableType], |
6970 | | -) -> tuple[list[CallableType], list[TypeVarType]]: |
6971 | | - """Takes all the typevars present in the callables and 'combines' the ones with the same name. |
6972 | | -
|
6973 | | - For example, suppose we have two callables with signatures "f(x: T, y: S) -> T" and |
6974 | | - "f(x: List[Tuple[T, S]]) -> Tuple[T, S]". Both callables use typevars named "T" and |
6975 | | - "S", but we treat them as distinct, unrelated typevars. (E.g. they could both have |
6976 | | - distinct ids.) |
6977 | | -
|
6978 | | - If we pass in both callables into this function, it returns a list containing two |
6979 | | - new callables that are identical in signature, but use the same underlying TypeVarType |
6980 | | - for T and S. |
6981 | | -
|
6982 | | - This is useful if we want to take the output lists and "merge" them into one callable |
6983 | | - in some way -- for example, when unioning together overloads. |
6984 | | -
|
6985 | | - Returns both the new list of callables and a list of all distinct TypeVarType objects used. |
6986 | | - """ |
6987 | | - output: list[CallableType] = [] |
6988 | | - unique_typevars: dict[str, TypeVarType] = {} |
6989 | | - variables: list[TypeVarType] = [] |
6990 | | - |
6991 | | - for target in callables: |
6992 | | - if target.is_generic(): |
6993 | | - target = freshen_function_type_vars(target) |
6994 | | - |
6995 | | - rename = {} # Dict[TypeVarId, TypeVar] |
6996 | | - for tv in target.variables: |
6997 | | - name = tv.fullname |
6998 | | - if name not in unique_typevars: |
6999 | | - # TODO: support ParamSpecType and TypeVarTuple. |
7000 | | - if isinstance(tv, (ParamSpecType, TypeVarTupleType)): |
7001 | | - continue |
7002 | | - assert isinstance(tv, TypeVarType) |
7003 | | - unique_typevars[name] = tv |
7004 | | - variables.append(tv) |
7005 | | - rename[tv.id] = unique_typevars[name] |
7006 | | - |
7007 | | - target = expand_type(target, rename) |
7008 | | - output.append(target) |
7009 | | - |
7010 | | - return output, variables |
7011 | | - |
7012 | | - |
7013 | 6925 | def try_getting_literal(typ: Type) -> ProperType: |
7014 | 6926 | """If possible, get a more precise literal type for a given type.""" |
7015 | 6927 | typ = get_proper_type(typ) |
|
0 commit comments