diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 7ce7e69e21d8..7eedab2e399a 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -956,7 +956,7 @@ def expand_and_bind_callable( ) -> Type: if not mx.preserve_type_var_ids: functype = freshen_all_functions_type_vars(functype) - typ = get_proper_type(expand_self_type(var, functype, mx.original_type)) + typ = get_proper_type(expand_self_type(var, functype, mx.self_type)) assert isinstance(typ, FunctionLike) if is_trivial_self: typ = bind_self_fast(typ, mx.self_type) diff --git a/mypy/constraints.py b/mypy/constraints.py index 9eeea3cb2c26..6416791fa74a 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -1110,7 +1110,10 @@ def visit_callable_type(self, template: CallableType) -> list[Constraint]: # like U -> U, should be Callable[..., Any], but if U is a self-type, we can # allow it to leak, to be later bound to self. A bunch of existing code # depends on this old behaviour. - and not any(tv.id.is_self() for tv in cactual.variables) + and not ( + any(tv.id.is_self() for tv in cactual.variables) + and template.is_ellipsis_args + ) ): # If the actual callable is generic, infer constraints in the opposite # direction, and indicate to the solver there are extra type variables diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 79207c9aad56..0f19b404082e 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -4646,3 +4646,17 @@ reveal_type(t.bar) # N: Revealed type is "def () -> builtins.int" tt: Type[P] = C reveal_type(tt.foo) # N: Revealed type is "def (builtins.object) -> builtins.int" reveal_type(tt.bar) # N: Revealed type is "def (builtins.object) -> builtins.int" + +[case testProtocolDecoratedSelfBound] +from abc import abstractmethod +from typing import Protocol, Self + +class Proto(Protocol): + @abstractmethod + def foo(self, x: Self) -> None: ... + +class Impl: + def foo(self, x: Self) -> None: + pass + +x: Proto = Impl()