-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
segfault on recursive generic protocols of certain form #17326
Comments
Maybe related to #17319, since I also do tuple unpacking. |
Here's a slightly more minimal repro that doesn't involve from __future__ import annotations
from typing import Protocol, TypeVar, overload
X = TypeVar("X")
Y = TypeVar("Y")
X2 = TypeVar("X2")
Y2 = TypeVar("Y2")
class Transform(Protocol[X, Y]):
def __or__(self, other: Transform[X2, Y2]) -> Transform[tuple[X, X2], tuple[Y, Y2]]: ...
@overload
def chain_encoders(e: Transform[X, Y], simplify: bool) -> Transform[X, Y]: ...
@overload
def chain_encoders(*es: *tuple[*tuple[Transform, ...], Transform[X, object]]) -> Transform[X, Y]: ... The cause is a recursion error; recursion errors cause segfaults if the code has been compiled with mypyc. Here's the last part of the traceback if you use an uncompiled version of mypy from the File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 180, in is_subtype
return _is_subtype(left, right, subtype_context, proper_subtype=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 353, in _is_subtype
return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 1966, in accept
return visitor.visit_callable_type(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 711, in visit_callable_type
return is_callable_compatible(
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 1550, in is_callable_compatible
if not ignore_return and not is_compat_return(left.ret_type, right.ret_type):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 415, in _is_subtype
return is_subtype(left, right, subtype_context=self.subtype_context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 180, in is_subtype
return _is_subtype(left, right, subtype_context, proper_subtype=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 353, in _is_subtype
return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 1422, in accept
return visitor.visit_instance(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 607, in visit_instance
if right.type.is_protocol and is_protocol_implementation(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/subtypes.py", line 1147, in is_protocol_implementation
if l == left and r == right:
^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 1434, in __eq__
and self.args == other.args
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 2406, in __eq__
return self.items == other.items and self.partial_fallback == other.partial_fallback
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 2406, in __eq__
return self.items == other.items and self.partial_fallback == other.partial_fallback
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/alexw/dev/mypy/mypy/types.py", line 2406, in __eq__
return self.items == other.items and self.partial_fallback == other.partial_fallback
^^^^^^^^^^^^^^^^^^^^^^^^^
[Previous line repeated 370 more times]
RecursionError: maximum recursion depth exceeded |
An appropriate issue title might be something like "segfault on recursive protocol used in overloaded function that also uses PEP-646" |
This has actually nothing to do with overloads or tuples. The real problem is diverging recursive protocols. These are very similar to diverging recursive aliases (that are plain prohibited at semanal level), even though they (theoretically) may have real use cases (e.g. an exercise: represent a non-mixed union like Sorry for a detour, the real minimal repro is:
FWIW generic types like TBH I am not sure what to do. We may just prohibit such protocols, and require them to be nominal classes. |
For context, the |
Hm, I think I see the issue, when trying to test from typing import Protocol
class P[T](Protocol):
def meth(self) -> "P[list[T]]": ...
class C:
def meth(self) -> "C":
return self
def as_p[T](x: P[T]) -> P[T]:
return x
reveal_type(as_p(C())) # P[Unknown] |
Well, what do you think export const maxTypeRecursionCount = 20; mean? |
Crash Report
Not sure how to title this, the following example produces a segfault, I simplified it from more complicated code. It seems to be multicausal, removing the
Literal
makes it disappear, so does removing the__or__
operator onTransform
.To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=2409c60fc1d5734569f6ab55344a85f0
The text was updated successfully, but these errors were encountered: