Accepts a list of function signatures and attempts to combine them together into a new CallableType consisting of the union of all of the given arguments and return types. If there is at least one non-callable type, return Any (this can happen if there is an ambiguity becaus
(self, types: list[ProperType])
| 3234 | del self.type_overrides[expr] |
| 3235 | |
| 3236 | def combine_function_signatures(self, types: list[ProperType]) -> AnyType | CallableType: |
| 3237 | """Accepts a list of function signatures and attempts to combine them together into a |
| 3238 | new CallableType consisting of the union of all of the given arguments and return types. |
| 3239 | |
| 3240 | If there is at least one non-callable type, return Any (this can happen if there is |
| 3241 | an ambiguity because of Any in arguments). |
| 3242 | """ |
| 3243 | assert types, "Trying to merge no callables" |
| 3244 | if not all(isinstance(c, CallableType) for c in types): |
| 3245 | return AnyType(TypeOfAny.special_form) |
| 3246 | callables = cast("list[CallableType]", types) |
| 3247 | if len(callables) == 1: |
| 3248 | return callables[0] |
| 3249 | |
| 3250 | # Note: we are assuming here that if a user uses some TypeVar 'T' in |
| 3251 | # two different functions, they meant for that TypeVar to mean the |
| 3252 | # same thing. |
| 3253 | # |
| 3254 | # This function will make sure that all instances of that TypeVar 'T' |
| 3255 | # refer to the same underlying TypeVarType objects to simplify the union-ing |
| 3256 | # logic below. |
| 3257 | # |
| 3258 | # (If the user did *not* mean for 'T' to be consistently bound to the |
| 3259 | # same type in their overloads, well, their code is probably too |
| 3260 | # confusing and ought to be re-written anyways.) |
| 3261 | callables, variables = merge_typevars_in_callables_by_name(callables) |
| 3262 | |
| 3263 | new_args: list[list[Type]] = [[] for _ in range(len(callables[0].arg_types))] |
| 3264 | new_kinds = list(callables[0].arg_kinds) |
| 3265 | new_returns: list[Type] = [] |
| 3266 | |
| 3267 | too_complex = False |
| 3268 | for target in callables: |
| 3269 | # We fall back to Callable[..., Union[<returns>]] if the functions do not have |
| 3270 | # the exact same signature. The only exception is if one arg is optional and |
| 3271 | # the other is positional: in that case, we continue unioning (and expect a |
| 3272 | # positional arg). |
| 3273 | # TODO: Enhance the merging logic to handle a wider variety of signatures. |
| 3274 | if len(new_kinds) != len(target.arg_kinds): |
| 3275 | too_complex = True |
| 3276 | break |
| 3277 | for i, (new_kind, target_kind) in enumerate(zip(new_kinds, target.arg_kinds)): |
| 3278 | if new_kind == target_kind: |
| 3279 | continue |
| 3280 | elif new_kind.is_positional() and target_kind.is_positional(): |
| 3281 | new_kinds[i] = ARG_POS |
| 3282 | else: |
| 3283 | too_complex = True |
| 3284 | break |
| 3285 | |
| 3286 | if too_complex: |
| 3287 | break # outer loop |
| 3288 | |
| 3289 | for i, arg in enumerate(target.arg_types): |
| 3290 | new_args[i].append(arg) |
| 3291 | new_returns.append(target.ret_type) |
| 3292 | |
| 3293 | union_return = make_simplified_union(new_returns) |
no test coverage detected