Skip to content

2.2 Regression with placeholder types in a TypeVar #21640

Description

@delfick

Crash Report

I was testing the mypy 2.2 branch and I came across some errors around placeholder types.

Traceback

There's kinda two errors and I think they're related

AssertionError: Must not defer during final iteration
Please report a bug at https://github.com/python/mypy/issues
version: 2.2.0+dev.5ef090270579013c337a9bcc79e2c58417f09538
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "mypy/semanal.py", line 7732, in accept
File "mypy/nodes.py", line 1165, in accept
File "mypy/semanal.py", line 991, in visit_func_def
File "mypy/semanal.py", line 1036, in analyze_func_def
File "mypy/semanal.py", line 7333, in defer
AssertionError: Must not defer during final iteration

If I use the source directly so I get more of a traceback

More details
version: 2.2.0+dev.5ef090270579013c337a9bcc79e2c58417f09538
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/Users/stephen.moore/Projects/external/mypy/mypy/__main__.py", line 52, in <module>
console_entry()
File "/Users/stephen.moore/Projects/external/mypy/mypy/__main__.py", line 16, in console_entry
main()
File "/Users/stephen.moore/Projects/external/mypy/mypy/main.py", line 154, in main
res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
File "/Users/stephen.moore/Projects/external/mypy/mypy/main.py", line 244, in run_build
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 422, in build
result = build_inner(
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 537, in build_inner
graph = dispatch(sources, manager, stdout, connect_threads)
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 4146, in dispatch
process_graph(graph, manager)
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 4614, in process_graph
done, still_working, results = manager.wait_for_done(graph)
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 1484, in wait_for_done
process_stale_scc(graph, next_scc, self)
File "/Users/stephen.moore/Projects/external/mypy/mypy/build.py", line 4782, in process_stale_scc
mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal_main.py", line 92, in semantic_analysis_for_scc
process_functions(graph, scc, patches)
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal_main.py", line 275, in process_functions
process_top_level_function(
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal_main.py", line 314, in process_top_level_function
deferred, incomplete, progress = semantic_analyze_target(
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal_main.py", line 380, in semantic_analyze_target
analyzer.refresh_partial(
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal.py", line 709, in refresh_partial
self.accept(node)
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal.py", line 7732, in accept
node.accept(self)
~~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/Projects/external/mypy/mypy/nodes.py", line 1165, in accept
return visitor.visit_func_def(self)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal.py", line 991, in visit_func_def
self.analyze_func_def(defn)
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal.py", line 1036, in analyze_func_def
self.defer(defn)
~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/Projects/external/mypy/mypy/semanal.py", line 7333, in defer
assert not self.final_iteration, "Must not defer during final iteration"
^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Must not defer during final iteration

And if I start trying to fill in default values I start to get this happening:

NotImplementedError: Cannot serialize PlaceholderType instance
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/__main__.py", line 52, in <module>
console_entry()
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/__main__.py", line 16, in console_entry
main()
~~~~^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/main.py", line 154, in main
res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/main.py", line 244, in run_build
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 422, in build
result = build_inner(
sources,
...<9 lines>...
metastore,
)
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 537, in build_inner
graph = dispatch(sources, manager, stdout, connect_threads)
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 4146, in dispatch
process_graph(graph, manager)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 4614, in process_graph
done, still_working, results = manager.wait_for_done(graph)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 1484, in wait_for_done
process_stale_scc(graph, next_scc, self)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 4821, in process_stale_scc
meta_tuple = graph[id].write_cache()
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 3604, in write_cache
new_interface_hash, meta_tuple = write_cache(
~~~~~~~~~~~^
self.id,
^^^^^^^^
...<13 lines>...
self.manager,
^^^^^^^^^^^^^
)
^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/build.py", line 2325, in write_cache
tree.write(data_io)
~~~~~~~~~~^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/nodes.py", line 599, in write
self.names.write(data, self._fullname)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/nodes.py", line 5169, in write
value.write(data, fullname, key)
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/nodes.py", line 5074, in write
self.node.write(data)
~~~~~~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/nodes.py", line 4721, in write
self.target.write(data)
~~~~~~~~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/types.py", line 1756, in write
write_type_list(data, self.args)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/types.py", line 4553, in write_type_list
item.write(data)
~~~~~~~~~~^^^^^^
File "/Users/stephen.moore/.virtualenvs/project/lib/python3.13/site-packages/mypy/types.py", line 318, in write
raise NotImplementedError(f"Cannot serialize {self.__class__.__name__} instance")
NotImplementedError: Cannot serialize PlaceholderType instance

To Reproduce

It appears that ultimately this is an interaction with how my mypy plugin works, which complicates it a little.
Essentially I add dependencies with the get_additional_deps hook that contain aliases (I call these virtual dependencies), and then with a get_type_analyze_hook hook I look for a special class that I replace with the target of an appropriate alias from those "virtual dependencies".

I have created an example with a readme that replicates the problem. Seems I can't upload a git bundle to a github issue, so
here is a repo: https://github.com/delfick/mypy-release-2.2-bug-demonstration

It seems there is one change required to fix it

From 84140edcb76aaf4b6bf3a2fd1f6a5ffc80277810 Mon Sep 17 00:00:00 2001
From: Stephen Moore <stephen.moore@kraken.tech>
Date: Wed, 24 Jun 2026 10:13:32 +1000
Subject: [PATCH] WIP: this makes a difference
---
mypy/semanal.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mypy/semanal.py b/mypy/semanal.py
index e010273b0..324910809 100644
--- a/mypy/semanal.py+++ b/mypy/semanal.py@@ -2009,7 +2009,7 @@ class SemanticAnalyzer(
# re-analyze this class. Note we force progress to handle cases like
# class C[T = C], this matches logic in process_typevar_parameters()
# for "old style" type variables.
- self.defer(force_progress=tvar_defs != defn.type_vars)+ self.mark_incomplete(defn.name, defn)
self.analyze_class_keywords(defn)
bases_result = self.analyze_base_classes(defn.name, bases)
-- 
2.50.1 (Apple Git-155)

(undoing a change in #21491)

However when I do this mypy unit tests start to fail. I can't figure out how to fix that, or even how to replicate the errors in a mypy unit test.

Your Environment

  • Mypy version used: release-2.2 branch (5ef0902)
  • Python version used: 3.13.2
  • Operating system and version: MacOS Tahoe 26.5.1

AI Disclosure: None: I actively avoid LLMs

Metadata

Metadata

Assignees

No one assigned

    Labels

    crashtopic-pluginsThe plugin API and ideas for new plugins

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions