python/mypy

a pretty bad bug report about a segfault, but at least I can show you the repo

glyph opened this issue · 4 comments

I am at a bit of a loss as to what happened here, because I just noticed my editor's inline type-checking suddenly went away, and then saw a mypy process consuming an entire core for multiple minutes at a time, then crashing. I figured I'd get the report in quickly rather than try to minimize first, but I understand this is a pretty poor-quality bug report. The fact that the repo is open source might make it easy enough to get into a debugger for someone more knowledgeable.

Crash Report

zsh: segmentation fault mypy src

Traceback

it's a segfault so --show-traceback gives me nothing.

To Reproduce

mypy src on
glyph/Pomodouroboros@8a8102c

Your Environment

  • Mypy version used: mypy 1.13.0 (compiled: yes)
  • Mypy command-line flags: none
  • Mypy configuration options from mypy.ini (and other config files): see repo
  • Python version used: 3.12.7
  • Operating system and version:
ProductName:		macOS
ProductVersion:		15.1.1
BuildVersion:		24B91
File "/Users/shantanu/dev/mypy/mypy/types.py", line 2010, in accept
    return visitor.visit_callable_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 710, in visit_callable_type
    return is_callable_compatible(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 1548, in is_callable_compatible
    unified = unify_generic_callable(left, right, ignore_return=ignore_return)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 1881, in unify_generic_callable
    c = mypy.constraints.infer_constraints(
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/constraints.py", line 314, in infer_constraints
    res = _infer_constraints(template, actual, direction, skip_neg_op)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/constraints.py", line 410, in _infer_constraints
    return template.accept(ConstraintBuilderVisitor(actual, direction, skip_neg_op))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/types.py", line 1470, in accept
    return visitor.visit_instance(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/constraints.py", line 938, in visit_instance
    and mypy.subtypes.is_protocol_implementation(erased, instance, skip=["__call__"])
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 1198, in is_protocol_implementation
    is_compat = is_subtype(
                ^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 185, in is_subtype
    return _is_subtype(left, right, subtype_context, proper_subtype=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 350, in _is_subtype
    return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/types.py", line 2010, in accept
    return visitor.visit_callable_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 710, in visit_callable_type
    return is_callable_compatible(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 1548, in is_callable_compatible
    unified = unify_generic_callable(left, right, ignore_return=ignore_return)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/subtypes.py", line 1862, in unify_generic_callable
    if set(type.type_var_ids()) & {v.id for v in mypy.typeops.get_all_type_vars(target)}:
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/typeops.py", line 1050, in get_all_type_vars
    return tp.accept(TypeVarExtractor(include_all=True))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/types.py", line 2010, in accept
    return visitor.visit_callable_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 409, in visit_callable_type
    return self.query_types(t.arg_types + [t.ret_type])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 451, in query_types
    return self.strategy([t.accept(self) for t in types])
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 451, in <listcomp>
    return self.strategy([t.accept(self) for t in types])
                          ^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/types.py", line 1470, in accept
    return visitor.visit_instance(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 405, in visit_instance
    return self.query_types(t.args)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 451, in query_types
    return self.strategy([t.accept(self) for t in types])
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/type_visitor.py", line 451, in <listcomp>
    return self.strategy([t.accept(self) for t in types])
                          ^^^^^^^^^^^^^^
  File "/Users/shantanu/dev/mypy/mypy/types.py", line 1274, in accept
    return visitor.visit_none_type(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded
src/scratch.py:55: : note: use --pdb to drop into pdb

Thanks @hauntsaninja ! What did I do? :)

Nothing you did! By default mypy ships binaries compiled with mypyc (these are 3-4x faster). In mypyc, stack overflows are segfaults, not nice RecursionError's. To get the RecursionError output, I ran pure Python mypy (you can pip install --no-binary or editable install from source)

As for what the code that mypy can't handle is, I haven't looked yet, but src/scratch.py:55 is a promising clue for minimising the repro when I get time.

This commit glyph/Pomodouroboros@28da08a has a bunch of type errors, but mypy happily completes quickly again, and the most salient change is that I removed the use of TypeVarTuple. There's obviously more going on here, but that seems to be at the core of the issue.