python / python/mypy

`RecursionError` with recursive type alias and concatenate

Aperta
#21,123 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

crash topic-paramspec topic-recursive-types
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Merge medio
1g 18h
PR unite (30g)
54

Descrizione

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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Esegui il riproduttore minimo dell’issue con --show-traceback, quindi esamina mypy/semanal_shared.py, mypy/type_visitor.py, mypy/types.py e mypy/expandtype.py in relazione a has_placeholder, all’espansione dei type-alias e all’attraversamento dei callable. Il lavoro è completato quando l’esempio di alias ricorsivo e Concatenate non va più in crash con RecursionError né segnala un INTERNAL ERROR.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
devtools
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Tranquilla
Chiarezza
Abbastanza chiara
Idoneità per principianti
48/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.