mypy
mypy copied to clipboard
Segmentation fault with mypy 1.7.1
Crash Report
mypy crashes with segmentation fault as such:
mypy-segmentation-fault on main is 📦 v0.1.0 via 🐍 v3.11.6 (mypy-segmentation-fault-py3.11)
❯ mypy --version
mypy 1.7.1 (compiled: yes)
mypy-segmentation-fault on main is 📦 v0.1.0 via 🐍 v3.11.6 (mypy-segmentation-fault-py3.11)
❯ mypy -p mypy_segmentation_fault
zsh: segmentation fault mypy -p mypy_segmentation_fault
with mypy_segmentation_fault.py:
from datetime import UTC, datetime
from typing import Protocol, Self
from injector import Binder, Injector, Module
class NowGenerator(Protocol):
def __call__(self: Self) -> datetime:
...
class NowGeneratorImpl:
def __call__(self: Self) -> datetime:
return datetime.now(tz=UTC)
class GeneratorsModule(Module):
def configure(self: Self, binder: Binder) -> None:
binder.bind(
NowGenerator, # type: ignore[type-abstract]
to=NowGeneratorImpl,
)
injector = Injector([GeneratorsModule])
print(injector.get(NowGenerator)()) # type: ignore[type-abstract]
My observation is that if I remove Self type annotation, mypy does not crash and I do realise it is not necessary
(though, it was a good way to avoid hitting ruff's missing-type-self rule, which in theory I could disable).
I don't know if I could reproduce the crash without using python-injector.
Traceback
Unfortunately, nothing useful shows up:
mypy --show-traceback -p mypy_segmentation_fault
zsh: segmentation fault mypy --show-traceback -p mypy_segmentation_fault
To Reproduce
- Minimum reproducable code: https://github.com/ryo-tagami/mypy-segmentation-fault
- Invoking mypy:
mypy -p mypy_segmentation_fault
Your Environment
- Mypy version used: 1.7.1
- Mypy command-line flags:
-p mypy_segmentation_fault - Mypy configuration options from
mypy.ini(and other config files): None - Python version used: 3.11.6
- Operating system and version: macOS Sonoma Version 14.1.2 (23B92) on Apple M2 Pro
As is often the case with mypyc segfaults, it seems this is due to a RecursionError. Here's the last part of the stack trace if you use an uncompiled install of mypy from the master branch:
<many lines>
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 1223, in find_member
return find_node_type(method, itype, subtype, class_obj=class_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 1349, in find_node_type
signature = bind_self(
^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\typeops.py", line 326, in bind_self
typeargs = infer_type_arguments(
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\infer.py", line 75, in infer_type_arguments
return solve_constraints(type_vars, constraints, skip_unsatisfied=skip_unsatisfied)[0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\solve.py", line 124, in solve_constraints
res = pre_validate_solutions(res, original_vars, constraints)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\solve.py", line 549, in pre_validate_solutions
if s is not None and not is_subtype(s, t.upper_bound):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 179, in is_subtype
return _is_subtype(left, right, subtype_context, proper_subtype=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 352, in _is_subtype
return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\types.py", line 1970, in accept
return visitor.visit_callable_type(self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 706, in visit_callable_type
call = find_member("__call__", right, left, is_operator=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 1223, in find_member
return find_node_type(method, itype, subtype, class_obj=class_obj)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\subtypes.py", line 1349, in find_node_type
signature = bind_self(
^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\typeops.py", line 322, in bind_self
self_ids = {tv.id for tv in get_all_type_vars(self_param_type)}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\typeops.py", line 955, in get_all_type_vars
return tp.accept(TypeVarExtractor(include_all=True))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\mypy\mypy\typeops.py", line 960, in __init__
super().__init__(self._merge)
RecursionError: maximum recursion depth exceeded
I created a similar / duplicate issue https://github.com/python/mypy/issues/16877 -- for anyone looking into this, there's a more compact repro and report of my initial investigation.
Afaict this affects version 1.7.0 and up, including the current verison 1.8.0.
Still valid for 1.9.0
Still valid for 1.10.0.
Also, a simpler example that reproduces the crash in my case is
from typing import Protocol, Self
class MyProtocol(Protocol):
__name__: str
def __call__(
self: Self,
) -> None: ...
value: MyProtocol = print
#17314 has a simpler repro case that seems similar though the stack trace is a little different:
from typing import Protocol
from typing import Self
class Printer(Protocol):
def __call__(self: Self): ...
class Version:
def __init__(self, printer: Printer): ...
Version(printer=print)
(Thanks Alex for finding this related issue.)