Skip to content

Recursion Error for Protocols with Self #17474

@JasonGrace2282

Description

@JasonGrace2282

Crash Report
I ran mypy on this code and it crashed with an internal error

Traceback

Click here for full traceback
Traceback (most recent call last):
  File "/sbin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File "/usr/lib/python3.12/site-packages/mypy/__main__.py", line 15, in console_entry
    main()
  File "/usr/lib/python3.12/site-packages/mypy/main.py", line 100, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
  File "/usr/lib/python3.12/site-packages/mypy/main.py", line 182, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/usr/lib/python3.12/site-packages/mypy/build.py", line 192, in build

I had to cut a lot of this out because it was too long.

  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 179, in is_subtype
    return _is_subtype(left, right, subtype_context, proper_subtype=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 352, in _is_subtype
    return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/types.py", line 1984, in accept
    return visitor.visit_callable_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 721, in visit_callable_type
    call = find_member("__call__", right, left, is_operator=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 1238, in find_member
    return find_node_type(method, itype, subtype, class_obj=class_obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 1364, in find_node_type
    signature = bind_self(
                ^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/typeops.py", line 292, in bind_self
    F, Overloaded([bind_self(c, original_type, is_classmethod) for c in method.items])
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/typeops.py", line 326, in bind_self
    typeargs = infer_type_arguments(
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/infer.py", line 75, in infer_type_arguments
    return solve_constraints(type_vars, constraints, skip_unsatisfied=skip_unsatisfied)[0]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/solve.py", line 124, in solve_constraints
    res = pre_validate_solutions(res, original_vars, constraints)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/solve.py", line 549, in pre_validate_solutions
    if s is not None and not is_subtype(s, t.upper_bound):
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 179, in is_subtype
    return _is_subtype(left, right, subtype_context, proper_subtype=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 352, in _is_subtype
    return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/types.py", line 1984, in accept
    return visitor.visit_callable_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 721, in visit_callable_type
    call = find_member("__call__", right, left, is_operator=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 1238, in find_member
    return find_node_type(method, itype, subtype, class_obj=class_obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/subtypes.py", line 1364, in find_node_type
    signature = bind_self(
                ^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/typeops.py", line 292, in bind_self
    F, Overloaded([bind_self(c, original_type, is_classmethod) for c in method.items])
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/typeops.py", line 326, in bind_self
    typeargs = infer_type_arguments(
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/infer.py", line 74, in infer_type_arguments
    constraints = infer_constraints(template, actual, SUPERTYPE_OF if is_supertype else SUBTYPE_OF)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/constraints.py", line 304, in infer_constraints
    if has_recursive_types(template) or isinstance(get_proper_type(template), Instance):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/types.py", line 3533, in has_recursive_types
    return typ.accept(_has_recursive_type)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/types.py", line 644, in accept
    return visitor.visit_type_var(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/type_visitor.py", line 482, in visit_type_var
    return self.query_types([t.upper_bound, t.default] + t.values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/type_visitor.py", line 557, in query_types
    return any(t.accept(self) for t in types)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/type_visitor.py", line 557, in <genexpr>
    return any(t.accept(self) for t in types)
               ^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/types.py", line 1444, in accept
    return visitor.visit_instance(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/type_visitor.py", line 500, in visit_instance
    return self.query_types(t.args)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/mypy/type_visitor.py", line 562, in query_types
    return any(t.accept(self) for t in types)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded

To Reproduce

from typing import TYPE_CHECKING, Any, TypeVar, Protocol, overload

if TYPE_CHECKING:
    from typing_extensions import Self

V = TypeVar("V")

class SimpleAttributeFunc(Protocol[V]):
    # getter
    @overload
    def __call__(self, new: None = None, **kwargs: Any) -> V: ...

    # setter
    @overload
    def __call__(self, new: V, **kwargs: Any) -> Self: ...

class TestMe:
    def testsomething(self) -> SimpleAttributeFunc[str]:
        @overload
        def foo(new: None = None, **kwargs: Any) -> str: ...

        @overload
        def foo(new: str, **kwargs: Any) -> Self: ...

        # this function crashes it for whatever reason
        def foo(new: str | None = None, **kwargs):
            if new is None:
                return str(["hi"])
            else:
                print(f"Setting to {new} with {kwargs}")
                return self
        # specifically this
        return foo

Your Environment

  • Mypy version used: Both the one on PyPI and the latest branch
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): No config
  • Python version used: 3.12
  • Operating system and version: Arch Linux
My Goal

While irrelevant to the issue, here was my goal (but working) https://gist.github.com/mypy-play/62fad45174312b2b1ec0c17e555d9ece

Metadata

Metadata

Assignees

No one assigned
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions