Skip to content

RecursionError with recursive type alias and concatenate #21123

@MeGaGiGaGon

Description

@MeGaGiGaGon

Crash Report

While trying to make an infinitely expanding function, I kept getting 500 errors on the playground. Trying it on the CLI, mypy crashed with error: INTERNAL ERROR, with the traceback ending in RecursionError: maximum recursion depth exceeded.

Traceback

Collapsed for readability
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "Scripts\mypy.exe\__main__.py", line 10, in <module>
    sys.exit(console_entry())
  File "Lib\site-packages\mypy\__main__.py", line 15, in console_entry
    main()
  File "Lib\site-packages\mypy\main.py", line 141, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
  File "Lib\site-packages\mypy\main.py", line 225, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "Lib\site-packages\mypy\build.py", line 391, in build
    result = build_inner(
  File "Lib\site-packages\mypy\build.py", line 488, in build_inner
    graph = dispatch(sources, manager, stdout)
  File "Lib\site-packages\mypy\build.py", line 3754, in dispatch
    process_graph(graph, manager)
  File "Lib\site-packages\mypy\build.py", line 4206, in process_graph
    done, still_working, results = manager.wait_for_done(graph)
  File "Lib\site-packages\mypy\build.py", line 1208, in wait_for_done
    process_stale_scc(graph, next_scc, self)
  File "Lib\site-packages\mypy\build.py", line 4371, in process_stale_scc
    mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
  File "Lib\site-packages\mypy\semanal_main.py", line 92, in semantic_analysis_for_scc
    process_functions(graph, scc, patches)
  File "Lib\site-packages\mypy\semanal_main.py", line 275, in process_functions
    process_top_level_function(
  File "Lib\site-packages\mypy\semanal_main.py", line 314, in process_top_level_function
    deferred, incomplete, progress = semantic_analyze_target(
  File "Lib\site-packages\mypy\semanal_main.py", line 380, in semantic_analyze_target
    analyzer.refresh_partial(
  File "Lib\site-packages\mypy\semanal.py", line 704, in refresh_partial
    self.accept(node)
  File "Lib\site-packages\mypy\semanal.py", line 7710, in accept
    node.accept(self)
    ~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\nodes.py", line 1089, in accept
    return visitor.visit_func_def(self)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\semanal.py", line 988, in visit_func_def
    self.analyze_func_def(defn)
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\semanal.py", line 1032, in analyze_func_def
    if self.found_incomplete_ref(tag) or has_placeholder(result):
                                         ~~~~~~~~~~~~~~~^^^^^^^^
  File "Lib\site-packages\mypy\semanal_shared.py", line 377, in has_placeholder
    return typ.accept(HasPlaceholders())
           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "Lib\site-packages\mypy\types.py", line 2324, in accept
    return visitor.visit_callable_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\type_visitor.py", line 554, in visit_callable_type
    args = self.query_types(t.arg_types)
  File "Lib\site-packages\mypy\type_visitor.py", line 605, in query_types
    return any(t.accept(self) for t in types)
           ^^^
  File "Lib\site-packages\mypy\type_visitor.py", line 605, in <genexpr>
    return any(t.accept(self) for t in types)
               ~~~~~~~~^^^^^^


  File "Lib\site-packages\mypy\types.py", line 418, in accept
    return visitor.visit_type_alias_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\type_visitor.py", line 598, in visit_type_alias_type
    return get_proper_type(t).accept(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\types.py", line 2324, in accept
    return visitor.visit_callable_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\type_visitor.py", line 555, in visit_callable_type
    ret = t.ret_type.accept(self)

  ^ Above 4 traceback items repeated 4085 more times (excluded for brevity)


  File "Lib\site-packages\mypy\types.py", line 418, in accept
    return visitor.visit_type_alias_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\type_visitor.py", line 598, in visit_type_alias_type
    return get_proper_type(t).accept(self)
           ~~~~~~~~~~~~~~~^^^
  File "Lib\site-packages\mypy\types.py", line 3649, in get_proper_type
    typ = typ._expand_once()
  File "Lib\site-packages\mypy\types.py", line 382, in _expand_once
    return self.alias.target.accept(InstantiateAliasVisitor(mapping))
           ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "Lib\site-packages\mypy\types.py", line 2324, in accept
    return visitor.visit_callable_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\expandtype.py", line 495, in visit_callable_type
    arg_types = self.expand_types(t.arg_types)
  File "Lib\site-packages\mypy\expandtype.py", line 616, in expand_types
    a.append(t.accept(self))
             ~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\types.py", line 2324, in accept
    return visitor.visit_callable_type(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "Lib\site-packages\mypy\expandtype.py", line 443, in visit_callable_type
    param_spec = t.param_spec()
  File "Lib\site-packages\mypy\types.py", line 2440, in param_spec
    return arg_type.copy_modified(flavor=ParamSpecFlavor.BARE, prefix=prefix)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "Lib\site-packages\mypy\types.py", line 827, in copy_modified
    return ParamSpecType(
        self.name,
    ...<7 lines>...
        prefix=prefix if prefix is not _dummy else self.prefix,
    )
  File "Lib\site-packages\mypy\types.py", line 803, in __init__
    super().__init__(name, fullname, id, upper_bound, default, line=line, column=column)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "Lib\site-packages\mypy\types.py", line 609, in __init__
    super().__init__(line, column)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "Lib\site-packages\mypy\types.py", line 267, in __init__
    super().__init__(line, column)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded

To Reproduce

https://mypy-play.net/?gist=2c6fdf9918139e545067e2d5dd443b8f

from typing import Callable, reveal_type, Concatenate

type A[**P] = Callable[[Callable[P, None]], A[Concatenate[int, P]]]

def foo[**P](x: A[P]):
    reveal_type(x)
Powershell command used
PS ~\Downloads> uvx mypy@https://github.com/python/mypy.git --show-traceback -c @'
from typing import Callable, reveal_type, Concatenate

type A[**P] = Callable[[Callable[P, None]], A[Concatenate[int, P]]]

def foo[**P](x: A[P]):
    reveal_type(x)
'@ > output.txt

Your Environment

  • Mypy version used: Current master
  • Mypy command-line flags: --show-traceback -c "code"
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.14? Whatever uvx does.
  • Operating system and version: Windows 11

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions