diff --git a/mypy/cache.py b/mypy/cache.py index 013a286fae2c..9a9adbb41976 100644 --- a/mypy/cache.py +++ b/mypy/cache.py @@ -72,7 +72,7 @@ from mypy_extensions import u8 # High-level cache layout format -CACHE_VERSION: Final = 11 +CACHE_VERSION: Final = 12 # Type used internally to represent errors: # (path, line, column, end_line, end_column, severity, message, code) diff --git a/mypy/checker.py b/mypy/checker.py index d4ba6c54fb35..d9665abcd5fb 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -246,6 +246,7 @@ def __init__(self) -> None: false_only, fixup_partial_type, function_type, + has_any_type, is_literal_type_like, is_singleton_equality_type, is_singleton_identity_type, @@ -5970,7 +5971,7 @@ def check_untyped_after_decorator(self, typ: Type, func: FuncDef) -> None: if not self.options.disallow_any_decorated or self.is_stub or self.current_node_deferred: return - if mypy.checkexpr.has_any_type(typ): + if has_any_type(typ): self.msg.untyped_decorated_function(typ, func) def check_async_with_item( diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 647116706d32..82251932e92d 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -152,6 +152,7 @@ freeze_all_type_vars, get_all_type_vars, get_type_vars, + has_any_type, is_literal_type_like, make_simplified_union, true_only, @@ -2874,6 +2875,7 @@ def check_overload_call( callable_name, object_type, none_type_var_overlap, + callee.bound_args, context, ) except TooManyUnions: @@ -2902,6 +2904,7 @@ def check_overload_call( arg_names, callable_name, object_type, + callee.bound_args, context, ) # If any of checks succeed, perform deprecation tests and stop early. @@ -2980,7 +2983,7 @@ def plausible_overload_call_targets( arg_kinds: list[ArgKind], arg_names: Sequence[str | None] | None, overload: Overloaded, - ) -> list[CallableType]: + ) -> list[tuple[int, CallableType]]: """Returns all overload call targets that having matching argument counts. If the given args contains a star-arg (*arg or **kwarg argument, except for @@ -2990,7 +2993,10 @@ def plausible_overload_call_targets( The only exception is if the starred argument is something like a Tuple or a NamedTuple, which has a definitive "shape". If so, we don't move the corresponding alternative to the front since we can infer a more precise match using the original - order.""" + order. + + The return also contains the original overload index for each plausible target. + """ def has_shape(typ: Type) -> bool: typ = get_proper_type(typ) @@ -2998,8 +3004,8 @@ def has_shape(typ: Type) -> bool: isinstance(typ, Instance) and typ.type.is_named_tuple ) - matches: list[CallableType] = [] - star_matches: list[CallableType] = [] + matches: list[tuple[int, CallableType]] = [] + star_matches: list[tuple[int, CallableType]] = [] args_have_var_arg = False args_have_kw_arg = False @@ -3009,7 +3015,7 @@ def has_shape(typ: Type) -> bool: if kind == ARG_STAR2 and not has_shape(typ): args_have_kw_arg = True - for typ in overload.items: + for idx, typ in enumerate(overload.items): formal_to_actual = map_actuals_to_formals( arg_kinds, arg_names, typ.arg_kinds, typ.arg_names, lambda i: arg_types[i] ) @@ -3020,28 +3026,29 @@ def has_shape(typ: Type) -> bool: # is safe: it will be filtered out later. # Unlike other var-args signatures, ParamSpec produces essentially # a fixed signature, so there's no need to push them to the top. - matches.append(typ) + matches.append((idx, typ)) elif self.check_argument_count( typ, arg_types, arg_kinds, arg_names, formal_to_actual, None ): if args_have_var_arg and typ.is_var_arg: - star_matches.append(typ) + star_matches.append((idx, typ)) elif args_have_kw_arg and typ.is_kw_arg: - star_matches.append(typ) + star_matches.append((idx, typ)) else: - matches.append(typ) + matches.append((idx, typ)) return star_matches + matches def infer_overload_return_type( self, - plausible_targets: list[CallableType], + plausible_targets: list[tuple[int, CallableType]], args: list[Expression], arg_types: list[Type], arg_kinds: list[ArgKind], arg_names: Sequence[str | None] | None, callable_name: str | None, object_type: Type | None, + bound_args: list[Type] | None, context: Context, ) -> tuple[Type, Type] | None: """Attempts to find the first matching callable from the given list. @@ -3051,16 +3058,17 @@ def infer_overload_return_type( If multiple targets match due to ambiguous Any parameters, returns (AnyType, AnyType). If no targets match, returns None. - Assumes all of the given targets have argument counts compatible with the caller. + Assumes all the given targets have argument counts compatible with the caller. """ - matches: list[CallableType] = [] + matches: list[tuple[int, CallableType]] = [] return_types: list[Type] = [] inferred_types: list[Type] = [] - args_contain_any = any(map(has_any_type, arg_types)) + # bound_arg are recorded only if the original object type contained any. + args_contain_any = any(map(has_any_type, arg_types)) or bound_args is not None type_maps: list[dict[Expression, Type]] = [] - for typ in plausible_targets: + for idx, typ in plausible_targets: assert self.msg is self.chk.msg with self.msg.filter_errors(filter_revealed_type=True) as w: with self.chk.local_type_map as m: @@ -3084,16 +3092,18 @@ def infer_overload_return_type( if isinstance(p_infer_type, CallableType): # Prefer inferred types if possible, this will avoid false triggers for # Any-ambiguity caused by arguments with Any passed to generic overloads. - matches.append(p_infer_type) + matches.append((idx, p_infer_type)) else: - matches.append(typ) + matches.append((idx, typ)) return_types.append(ret_type) inferred_types.append(infer_type) type_maps.append(m) if not matches: return None - elif any_causes_overload_ambiguity(matches, return_types, arg_types, arg_kinds, arg_names): + elif any_causes_overload_ambiguity( + matches, return_types, arg_types, arg_kinds, arg_names, bound_args + ): # An argument of type or containing the type 'Any' caused ambiguity. # We try returning a precise type if we can. If not, we give up and just return 'Any'. if all_same_types(return_types): @@ -3119,7 +3129,7 @@ def infer_overload_return_type( def overload_erased_call_targets( self, - plausible_targets: list[CallableType], + plausible_targets: list[tuple[int, CallableType]], arg_types: list[Type], arg_kinds: list[ArgKind], arg_names: Sequence[str | None] | None, @@ -3131,7 +3141,7 @@ def overload_erased_call_targets( Assumes all of the given targets have argument counts compatible with the caller. """ matches: list[CallableType] = [] - for typ in plausible_targets: + for _, typ in plausible_targets: if self.erased_signature_similarity( arg_types, arg_kinds, arg_names, args, typ, context ): @@ -3139,7 +3149,7 @@ def overload_erased_call_targets( return matches def possible_none_type_var_overlap( - self, arg_types: list[Type], plausible_targets: list[CallableType] + self, arg_types: list[Type], plausible_targets: list[tuple[int, CallableType]] ) -> bool: """Heuristic to determine whether we need to try forcing union math. @@ -3166,19 +3176,20 @@ def foo(x: T) -> list[T]: ... if not has_optional_arg: return False - min_prefix = min(len(c.arg_types) for c in plausible_targets) + min_prefix = min(len(c.arg_types) for _, c in plausible_targets) for i in range(min_prefix): if any( - isinstance(get_proper_type(c.arg_types[i]), NoneType) for c in plausible_targets + isinstance(get_proper_type(c.arg_types[i]), NoneType) for _, c in plausible_targets ) and any( - isinstance(get_proper_type(c.arg_types[i]), TypeVarType) for c in plausible_targets + isinstance(get_proper_type(c.arg_types[i]), TypeVarType) + for _, c in plausible_targets ): return True return False def union_overload_result( self, - plausible_targets: list[CallableType], + plausible_targets: list[tuple[int, CallableType]], args: list[Expression], arg_types: list[Type], arg_kinds: list[ArgKind], @@ -3186,6 +3197,7 @@ def union_overload_result( callable_name: str | None, object_type: Type | None, none_type_var_overlap: bool, + bound_args: list[Type] | None, context: Context, level: int = 0, ) -> list[tuple[Type, Type]] | None: @@ -3195,7 +3207,7 @@ def union_overload_result( Return a list of (, ) if call succeeds for every item of the desctructured union. Returns None if there is no match. """ - # Step 1: If we are already too deep, then stop immediately. Otherwise mypy might + # Step 1: If we are already too deep, then stop immediately. Otherwise, mypy might # hang for long time because of a weird overload call. The caller will get # the exception and generate an appropriate note message, if needed. if level >= MAX_UNIONS: @@ -3217,6 +3229,7 @@ def union_overload_result( arg_names, callable_name, object_type, + bound_args, context, ) if res is not None: @@ -3235,6 +3248,7 @@ def union_overload_result( arg_names, callable_name, object_type, + bound_args, context, ) if direct is not None and not isinstance( @@ -3260,6 +3274,7 @@ def union_overload_result( callable_name, object_type, none_type_var_overlap, + bound_args, context, level + 1, ) @@ -6684,37 +6699,6 @@ def try_parse_as_type_expression(self, maybe_type_expr: Expression) -> Type | No return None -def has_any_type(t: Type, ignore_in_type_obj: bool = False) -> bool: - """Whether t contains an Any type""" - return t.accept(HasAnyType(ignore_in_type_obj)) - - -class HasAnyType(types.BoolTypeQuery): - def __init__(self, ignore_in_type_obj: bool) -> None: - super().__init__(types.ANY_STRATEGY) - self.ignore_in_type_obj = ignore_in_type_obj - - def visit_any(self, t: AnyType) -> bool: - return t.type_of_any != TypeOfAny.special_form # special forms are not real Any types - - def visit_callable_type(self, t: CallableType) -> bool: - if self.ignore_in_type_obj and t.is_type_obj(): - return False - return super().visit_callable_type(t) - - def visit_type_var(self, t: TypeVarType) -> bool: - default = [t.default] if t.has_default() else [] - return self.query_types([t.upper_bound, *default] + t.values) - - def visit_param_spec(self, t: ParamSpecType) -> bool: - default = [t.default] if t.has_default() else [] - return self.query_types([t.upper_bound, *default, t.prefix]) - - def visit_type_var_tuple(self, t: TypeVarTupleType) -> bool: - default = [t.default] if t.has_default() else [] - return self.query_types([t.upper_bound, *default]) - - def has_coroutine_decorator(t: Type) -> bool: """Whether t came from a function decorated with `@coroutine`.""" t = get_proper_type(t) @@ -6902,11 +6886,12 @@ def is_typetype_like(typ: ProperType) -> bool: def any_causes_overload_ambiguity( - items: list[CallableType], + items: list[tuple[int, CallableType]], return_types: list[Type], arg_types: list[Type], arg_kinds: list[ArgKind], arg_names: Sequence[str | None] | None, + bound_args: list[Type] | None, ) -> bool: """May an argument containing 'Any' cause ambiguous result type on call to overloaded function? @@ -6916,9 +6901,11 @@ def any_causes_overload_ambiguity( Args: items: Overload items matching the actual arguments + return_types: Corresponding inferred return type for each item arg_types: Actual argument types arg_kinds: Actual argument kinds arg_names: Actual argument names + bound_args: Full list of self-types bound (if overload is a method) """ if all_same_types(return_types): return False @@ -6927,7 +6914,7 @@ def any_causes_overload_ambiguity( map_formals_to_actuals( arg_kinds, arg_names, item.arg_kinds, item.arg_names, lambda i: arg_types[i] ) - for item in items + for _, item in items ] for arg_idx, arg_type in enumerate(arg_types): @@ -6944,7 +6931,7 @@ def any_causes_overload_ambiguity( matching_returns = [] matching_formals = [] for item_idx, formals in matching_formals_unfiltered: - matched_callable = items[item_idx] + _, matched_callable = items[item_idx] matching_returns.append(matched_callable.ret_type) # Note: if an actual maps to multiple formals of differing types within @@ -6956,6 +6943,12 @@ def any_causes_overload_ambiguity( if not all_same_types(matching_formals) and not all_same_types(matching_returns): # Any maps to multiple different types, and the return types of these items differ. return True + + # If the original object type for methods contained Any, check the self-types as well. + if bound_args is not None: + matching_bound = [bound_args[idx] for idx, _ in items] + if not all_same_types(matching_bound): + return True return False diff --git a/mypy/copytype.py b/mypy/copytype.py index 12dda9d26397..3b283de8cdef 100644 --- a/mypy/copytype.py +++ b/mypy/copytype.py @@ -120,7 +120,7 @@ def visit_union_type(self, t: UnionType) -> ProperType: return self.copy_common(t, UnionType(t.items)) def visit_overloaded(self, t: Overloaded) -> ProperType: - return self.copy_common(t, Overloaded(items=t.items)) + return self.copy_common(t, Overloaded(items=t.items, bound_args=t.bound_args)) def visit_type_type(self, t: TypeType) -> ProperType: # Use cast since the type annotations in TypeType are imprecise. diff --git a/mypy/expandtype.py b/mypy/expandtype.py index fd507216a6be..370e5ca3f583 100644 --- a/mypy/expandtype.py +++ b/mypy/expandtype.py @@ -508,7 +508,7 @@ def visit_overloaded(self, t: Overloaded) -> Type: assert isinstance(new_item, ProperType) assert isinstance(new_item, CallableType) items.append(new_item) - return Overloaded(items) + return Overloaded(items, t.bound_args) def expand_type_list_with_unpack(self, typs: list[Type]) -> list[Type]: """Expands a list of types that has an unpack.""" diff --git a/mypy/suggestions.py b/mypy/suggestions.py index 39a220e34091..c117be1324f3 100644 --- a/mypy/suggestions.py +++ b/mypy/suggestions.py @@ -34,7 +34,6 @@ from mypy.argmap import map_actuals_to_formals from mypy.build import Graph, State -from mypy.checkexpr import has_any_type from mypy.find_sources import InvalidSourceList, SourceFinder from mypy.join import join_type_list from mypy.meet import meet_type_list @@ -60,7 +59,7 @@ from mypy.server.update import FineGrainedBuildManager from mypy.state import state from mypy.traverser import TraverserVisitor -from mypy.typeops import bind_self, make_simplified_union +from mypy.typeops import bind_self, has_any_type, make_simplified_union from mypy.types import ( AnyType, CallableType, diff --git a/mypy/type_visitor.py b/mypy/type_visitor.py index 7052c8011871..6bd756e47eb8 100644 --- a/mypy/type_visitor.py +++ b/mypy/type_visitor.py @@ -332,7 +332,7 @@ def visit_overloaded(self, t: Overloaded, /) -> Type: new = item.accept(self) assert isinstance(new, CallableType) # type: ignore[misc] items.append(new) - return Overloaded(items=items) + return Overloaded(items=items, bound_args=t.bound_args) def visit_type_type(self, t: TypeType, /) -> Type: return TypeType.make_normalized( diff --git a/mypy/typeops.py b/mypy/typeops.py index 8453da4dd31c..a7955c96c9b6 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -34,6 +34,7 @@ Var, ) from mypy.state import state +from mypy.type_visitor import ANY_STRATEGY, BoolTypeQuery from mypy.types import ( ELLIPSIS_TYPE_NAMES, NOT_IMPLEMENTED_TYPE_NAMES, @@ -463,15 +464,57 @@ class B(A): pass """ if isinstance(method, Overloaded): - items = [ - bind_self(c, original_type, is_classmethod, ignore_instances) for c in method.items - ] - return cast(F, Overloaded(items)) + items = [] + # If the original object type has Any, we record the inferred self-types, + if original_type and has_any_type(original_type, ignore_in_type_obj=True): + bound_args: list[Type] | None = [] + else: + bound_args = None + for c in method.items: + bound = bind_self_inner(c, original_type, is_classmethod, ignore_instances) + if bound is None: + items.append(c) + bound_args = None + # If some items can't be bound, we ignore them all for simplicity. + continue + func, variables = bound + res = func.copy_modified( + arg_types=func.arg_types[1:], + arg_kinds=func.arg_kinds[1:], + arg_names=func.arg_names[1:], + variables=variables, + is_bound=True, + ) + items.append(res) + if bound_args is not None: + bound_args.append(func.arg_types[0]) + return cast(F, Overloaded(items, bound_args)) + assert isinstance(method, CallableType) - func: CallableType = method + bound = bind_self_inner(method, original_type, is_classmethod, ignore_instances) + if bound is None: + return method + func, variables = bound + res = func.copy_modified( + arg_types=func.arg_types[1:], + arg_kinds=func.arg_kinds[1:], + arg_names=func.arg_names[1:], + variables=variables, + is_bound=True, + ) + return cast(F, res) + + +def bind_self_inner( + func: CallableType, + original_type: Type | None = None, + is_classmethod: bool = False, + ignore_instances: bool = False, +) -> tuple[CallableType, Sequence[TypeVarLikeType]] | None: + """Implementation of bind_self().""" if not func.arg_types: # Invalid method, return something. - return method + return None if func.arg_kinds[0] in (ARG_STAR, ARG_STAR2): # The signature is of the form 'def foo(*args, ...)'. # In this case we shouldn't drop the first arg, @@ -480,7 +523,8 @@ class B(A): pass # In the case of **kwargs we should probably emit an error, but # for now we simply skip it, to avoid crashes down the line. - return method + return None + self_param_type = get_proper_type(func.arg_types[0]) variables: Sequence[TypeVarLikeType] @@ -527,15 +571,7 @@ class B(A): pass variables = [v for v in func.variables if v not in self_vars] else: variables = func.variables - - res = func.copy_modified( - arg_types=func.arg_types[1:], - arg_kinds=func.arg_kinds[1:], - arg_names=func.arg_names[1:], - variables=variables, - is_bound=True, - ) - return cast(F, res) + return func, variables def erase_to_bound(t: Type) -> Type: @@ -1353,3 +1389,34 @@ def can_have_shared_disjoint_base(instances: list[Instance]) -> bool: else: return False return True + + +def has_any_type(t: Type, ignore_in_type_obj: bool = False) -> bool: + """Whether t contains an Any type""" + return t.accept(HasAnyType(ignore_in_type_obj)) + + +class HasAnyType(BoolTypeQuery): + def __init__(self, ignore_in_type_obj: bool) -> None: + super().__init__(ANY_STRATEGY) + self.ignore_in_type_obj = ignore_in_type_obj + + def visit_any(self, t: AnyType) -> bool: + return t.type_of_any != TypeOfAny.special_form # special forms are not real Any types + + def visit_callable_type(self, t: CallableType) -> bool: + if self.ignore_in_type_obj and t.is_type_obj(): + return False + return super().visit_callable_type(t) + + def visit_type_var(self, t: TypeVarType) -> bool: + default = [t.default] if t.has_default() else [] + return self.query_types([t.upper_bound, *default] + t.values) + + def visit_param_spec(self, t: ParamSpecType) -> bool: + default = [t.default] if t.has_default() else [] + return self.query_types([t.upper_bound, *default, t.prefix]) + + def visit_type_var_tuple(self, t: TypeVarTupleType) -> bool: + default = [t.default] if t.has_default() else [] + return self.query_types([t.upper_bound, *default]) diff --git a/mypy/types.py b/mypy/types.py index 7a1470964d25..c15adf1d6004 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -2746,14 +2746,26 @@ class Overloaded(FunctionLike): implementation. """ - __slots__ = ("_items",) + __slots__ = ("_items", "bound_args") _items: list[CallableType] # Must not be empty - def __init__(self, items: list[CallableType]) -> None: + def __init__(self, items: list[CallableType], bound_args: list[Type] | None = None) -> None: super().__init__(items[0].line, items[0].column) self._items = items self.fallback = items[0].fallback + if bound_args is not None: + assert len(bound_args) == len(items) + # The bound arguments record the original inferred self-types when binding + # an overloaded method. As an optimization, we only do this when we know + # self-types can potentially cause an overload ambiguity, since this is + # the only use case for them. Namely: + # * We ignore them in bind_self_fast(), used when is_trivial_self is True + # on the overloaded function definition. + # * We ignore them if the object type doesn't contain Any tpes. + # Since this is a "technical" attribute, various type queries should skip it, + # and type translators should keep it intact. + self.bound_args = bound_args @property def items(self) -> list[CallableType]: @@ -2776,14 +2788,14 @@ def with_name(self, name: str) -> Overloaded: ni: list[CallableType] = [] for it in self._items: ni.append(it.with_name(name)) - return Overloaded(ni) + return Overloaded(ni, self.bound_args) def get_name(self) -> str | None: return self._items[0].name def with_unpacked_kwargs(self) -> Overloaded: if any(i.unpack_kwargs for i in self.items): - return Overloaded([i.with_unpacked_kwargs() for i in self.items]) + return Overloaded([i.with_unpacked_kwargs() for i in self.items], self.bound_args) return self def accept(self, visitor: TypeVisitor[T]) -> T: @@ -2798,16 +2810,32 @@ def __eq__(self, other: object) -> bool: return self.items == other.items def serialize(self) -> JsonDict: - return {".class": "Overloaded", "items": [t.serialize() for t in self.items]} + return { + ".class": "Overloaded", + "items": [t.serialize() for t in self.items], + "bound_args": ( + [b.serialize() for b in self.bound_args] if self.bound_args is not None else None + ), + } @classmethod def deserialize(cls, data: JsonDict) -> Overloaded: assert data[".class"] == "Overloaded" - return Overloaded([CallableType.deserialize(t) for t in data["items"]]) + items = [CallableType.deserialize(t) for t in data["items"]] + bound_args = ( + [deserialize_type(t) for t in data["bound_args"]] + if data["bound_args"] is not None + else None + ) + return Overloaded(items, bound_args) def write(self, data: WriteBuffer) -> None: write_tag(data, OVERLOADED) write_type_list(data, self.items) + if self.bound_args is None: + write_tag(data, LITERAL_NONE) + else: + write_type_list(data, self.bound_args) write_tag(data, END_TAG) @classmethod @@ -2817,8 +2845,15 @@ def read(cls, data: ReadBuffer) -> Overloaded: for _ in range(read_int_bare(data)): assert read_tag(data) == CALLABLE_TYPE items.append(CallableType.read(data)) + tag = read_tag(data) + if tag == LITERAL_NONE: + bound_args = None + else: + assert tag == LIST_GEN + size = read_int_bare(data) + bound_args = [read_type(data) for _ in range(size)] assert read_tag(data) == END_TAG - return Overloaded(items) + return Overloaded(items, bound_args) class TupleType(ProperType): diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 65e861057a9e..ddd44eeaa06b 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -1906,6 +1906,81 @@ a: Any reveal_type(f(a)) # N: Revealed type is "def (*Any, **Any) -> Any" reveal_type(f(a)(a)) # N: Revealed type is "Any" +[case testOverloadWithOverlappingItemsAndAnyArgumentSelf1] +from typing import Generic, TypeVar, overload, Any + +T = TypeVar("T") + +class Some(Generic[T]): + @overload + def method(self: Some[int]) -> bool: ... + @overload + def method(self: Some[str]) -> float: ... + def method(self): ... + +s: Some[Any] +reveal_type(s.method()) # N: Revealed type is "Any" + +[case testOverloadWithOverlappingItemsAndAnyArgumentSelf2] +from typing import Generic, TypeVar, overload, Any + +T = TypeVar("T") + +class Some(Generic[T]): + @overload + def method(self: Some[int]) -> bool: ... + @overload + def method(self: Some[str]) -> bool: ... + def method(self): ... + +s: Some[Any] +reveal_type(s.method()) # N: Revealed type is "builtins.bool" + +[case testOverloadWithOverlappingItemsAndAnyArgumentSelf3] +from typing import Generic, TypeVar, overload, Any + +T = TypeVar("T") + +class Some(Generic[T]): + @overload + def method(self: Some[int]) -> list[bool]: ... + @overload + def method(self: Some[str]) -> list[float]: ... + def method(self): ... + +s: Some[Any] +reveal_type(s.method()) # N: Revealed type is "builtins.list[Any]" + +[case testOverloadWithOverlappingItemsAndAnyArgumentSelf4] +from typing import Generic, TypeVar, overload, Any + +T = TypeVar("T") + +class Some(Generic[T]): + @overload + def method(self, x: int) -> bool: ... + @overload + def method(self, x: object) -> int: ... + def method(self): ... + +s: Some[Any] +reveal_type(s.method(42)) # N: Revealed type is "builtins.bool" + +[case testOverloadWithOverlappingItemsAndAnyArgumentSelf5] +from typing import Generic, TypeVar, overload, Any + +T = TypeVar("T") + +class Some(Generic[T]): + @overload + def method(self: Some[int], x: int) -> bool: ... + @overload + def method(self: Some[int], x: object) -> int: ... + def method(self): ... + +s: Some[Any] +reveal_type(s.method(42)) # N: Revealed type is "builtins.bool" + [case testOverloadOnOverloadWithType] from typing import Any, Type, TypeVar, overload from mod import MyInt