瀏覽代碼

d04 добавление компонентов для монитора

SVI 2 年之前
父節點
當前提交
e27de40bb1
共有 100 個文件被更改,包括 33744 次插入0 次删除
  1. 3 0
      requiments.txt
  2. 二進制
      venv/lib/python3.11/site-packages/ced4bbd844d3a34b6fc2__mypyc.cpython-311-x86_64-linux-gnu.so
  3. 1 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/INSTALLER
  4. 229 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/LICENSE
  5. 44 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/METADATA
  6. 1487 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/RECORD
  7. 0 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/REQUESTED
  8. 6 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/WHEEL
  9. 6 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/entry_points.txt
  10. 3 0
      venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/top_level.txt
  11. 二進制
      venv/lib/python3.11/site-packages/mypy/__init__.cpython-311-x86_64-linux-gnu.so
  12. 1 0
      venv/lib/python3.11/site-packages/mypy/__init__.py
  13. 37 0
      venv/lib/python3.11/site-packages/mypy/__main__.py
  14. 二進制
      venv/lib/python3.11/site-packages/mypy/api.cpython-311-x86_64-linux-gnu.so
  15. 94 0
      venv/lib/python3.11/site-packages/mypy/api.py
  16. 二進制
      venv/lib/python3.11/site-packages/mypy/applytype.cpython-311-x86_64-linux-gnu.so
  17. 186 0
      venv/lib/python3.11/site-packages/mypy/applytype.py
  18. 二進制
      venv/lib/python3.11/site-packages/mypy/argmap.cpython-311-x86_64-linux-gnu.so
  19. 247 0
      venv/lib/python3.11/site-packages/mypy/argmap.py
  20. 二進制
      venv/lib/python3.11/site-packages/mypy/binder.cpython-311-x86_64-linux-gnu.so
  21. 463 0
      venv/lib/python3.11/site-packages/mypy/binder.py
  22. 27 0
      venv/lib/python3.11/site-packages/mypy/bogus_type.py
  23. 二進制
      venv/lib/python3.11/site-packages/mypy/build.cpython-311-x86_64-linux-gnu.so
  24. 二進制
      venv/lib/python3.11/site-packages/mypy/checker.cpython-311-x86_64-linux-gnu.so
  25. 7819 0
      venv/lib/python3.11/site-packages/mypy/checker.py
  26. 二進制
      venv/lib/python3.11/site-packages/mypy/checkexpr.cpython-311-x86_64-linux-gnu.so
  27. 5972 0
      venv/lib/python3.11/site-packages/mypy/checkexpr.py
  28. 二進制
      venv/lib/python3.11/site-packages/mypy/checkmember.cpython-311-x86_64-linux-gnu.so
  29. 1316 0
      venv/lib/python3.11/site-packages/mypy/checkmember.py
  30. 二進制
      venv/lib/python3.11/site-packages/mypy/checkpattern.cpython-311-x86_64-linux-gnu.so
  31. 721 0
      venv/lib/python3.11/site-packages/mypy/checkpattern.py
  32. 二進制
      venv/lib/python3.11/site-packages/mypy/checkstrformat.cpython-311-x86_64-linux-gnu.so
  33. 1105 0
      venv/lib/python3.11/site-packages/mypy/checkstrformat.py
  34. 二進制
      venv/lib/python3.11/site-packages/mypy/config_parser.cpython-311-x86_64-linux-gnu.so
  35. 620 0
      venv/lib/python3.11/site-packages/mypy/config_parser.py
  36. 二進制
      venv/lib/python3.11/site-packages/mypy/constant_fold.cpython-311-x86_64-linux-gnu.so
  37. 187 0
      venv/lib/python3.11/site-packages/mypy/constant_fold.py
  38. 二進制
      venv/lib/python3.11/site-packages/mypy/constraints.cpython-311-x86_64-linux-gnu.so
  39. 1262 0
      venv/lib/python3.11/site-packages/mypy/constraints.py
  40. 二進制
      venv/lib/python3.11/site-packages/mypy/copytype.cpython-311-x86_64-linux-gnu.so
  41. 133 0
      venv/lib/python3.11/site-packages/mypy/copytype.py
  42. 二進制
      venv/lib/python3.11/site-packages/mypy/defaults.cpython-311-x86_64-linux-gnu.so
  43. 48 0
      venv/lib/python3.11/site-packages/mypy/defaults.py
  44. 二進制
      venv/lib/python3.11/site-packages/mypy/dmypy/__init__.cpython-311-x86_64-linux-gnu.so
  45. 0 0
      venv/lib/python3.11/site-packages/mypy/dmypy/__init__.py
  46. 6 0
      venv/lib/python3.11/site-packages/mypy/dmypy/__main__.py
  47. 二進制
      venv/lib/python3.11/site-packages/mypy/dmypy/client.cpython-311-x86_64-linux-gnu.so
  48. 744 0
      venv/lib/python3.11/site-packages/mypy/dmypy/client.py
  49. 二進制
      venv/lib/python3.11/site-packages/mypy/dmypy_os.cpython-311-x86_64-linux-gnu.so
  50. 42 0
      venv/lib/python3.11/site-packages/mypy/dmypy_os.py
  51. 二進制
      venv/lib/python3.11/site-packages/mypy/dmypy_server.cpython-311-x86_64-linux-gnu.so
  52. 1063 0
      venv/lib/python3.11/site-packages/mypy/dmypy_server.py
  53. 二進制
      venv/lib/python3.11/site-packages/mypy/dmypy_util.cpython-311-x86_64-linux-gnu.so
  54. 31 0
      venv/lib/python3.11/site-packages/mypy/dmypy_util.py
  55. 二進制
      venv/lib/python3.11/site-packages/mypy/erasetype.cpython-311-x86_64-linux-gnu.so
  56. 233 0
      venv/lib/python3.11/site-packages/mypy/erasetype.py
  57. 二進制
      venv/lib/python3.11/site-packages/mypy/errorcodes.cpython-311-x86_64-linux-gnu.so
  58. 255 0
      venv/lib/python3.11/site-packages/mypy/errorcodes.py
  59. 二進制
      venv/lib/python3.11/site-packages/mypy/errors.cpython-311-x86_64-linux-gnu.so
  60. 1276 0
      venv/lib/python3.11/site-packages/mypy/errors.py
  61. 二進制
      venv/lib/python3.11/site-packages/mypy/evalexpr.cpython-311-x86_64-linux-gnu.so
  62. 204 0
      venv/lib/python3.11/site-packages/mypy/evalexpr.py
  63. 二進制
      venv/lib/python3.11/site-packages/mypy/expandtype.cpython-311-x86_64-linux-gnu.so
  64. 613 0
      venv/lib/python3.11/site-packages/mypy/expandtype.py
  65. 二進制
      venv/lib/python3.11/site-packages/mypy/exprtotype.cpython-311-x86_64-linux-gnu.so
  66. 193 0
      venv/lib/python3.11/site-packages/mypy/exprtotype.py
  67. 二進制
      venv/lib/python3.11/site-packages/mypy/fastparse.cpython-311-x86_64-linux-gnu.so
  68. 2100 0
      venv/lib/python3.11/site-packages/mypy/fastparse.py
  69. 二進制
      venv/lib/python3.11/site-packages/mypy/find_sources.cpython-311-x86_64-linux-gnu.so
  70. 243 0
      venv/lib/python3.11/site-packages/mypy/find_sources.py
  71. 二進制
      venv/lib/python3.11/site-packages/mypy/fixup.cpython-311-x86_64-linux-gnu.so
  72. 410 0
      venv/lib/python3.11/site-packages/mypy/fixup.py
  73. 二進制
      venv/lib/python3.11/site-packages/mypy/freetree.cpython-311-x86_64-linux-gnu.so
  74. 23 0
      venv/lib/python3.11/site-packages/mypy/freetree.py
  75. 二進制
      venv/lib/python3.11/site-packages/mypy/fscache.cpython-311-x86_64-linux-gnu.so
  76. 309 0
      venv/lib/python3.11/site-packages/mypy/fscache.py
  77. 二進制
      venv/lib/python3.11/site-packages/mypy/fswatcher.cpython-311-x86_64-linux-gnu.so
  78. 106 0
      venv/lib/python3.11/site-packages/mypy/fswatcher.py
  79. 二進制
      venv/lib/python3.11/site-packages/mypy/gclogger.cpython-311-x86_64-linux-gnu.so
  80. 47 0
      venv/lib/python3.11/site-packages/mypy/gclogger.py
  81. 二進制
      venv/lib/python3.11/site-packages/mypy/git.cpython-311-x86_64-linux-gnu.so
  82. 34 0
      venv/lib/python3.11/site-packages/mypy/git.py
  83. 二進制
      venv/lib/python3.11/site-packages/mypy/graph_utils.cpython-311-x86_64-linux-gnu.so
  84. 112 0
      venv/lib/python3.11/site-packages/mypy/graph_utils.py
  85. 二進制
      venv/lib/python3.11/site-packages/mypy/indirection.cpython-311-x86_64-linux-gnu.so
  86. 121 0
      venv/lib/python3.11/site-packages/mypy/indirection.py
  87. 二進制
      venv/lib/python3.11/site-packages/mypy/infer.cpython-311-x86_64-linux-gnu.so
  88. 70 0
      venv/lib/python3.11/site-packages/mypy/infer.py
  89. 二進制
      venv/lib/python3.11/site-packages/mypy/inspections.cpython-311-x86_64-linux-gnu.so
  90. 625 0
      venv/lib/python3.11/site-packages/mypy/inspections.py
  91. 二進制
      venv/lib/python3.11/site-packages/mypy/ipc.cpython-311-x86_64-linux-gnu.so
  92. 268 0
      venv/lib/python3.11/site-packages/mypy/ipc.py
  93. 二進制
      venv/lib/python3.11/site-packages/mypy/join.cpython-311-x86_64-linux-gnu.so
  94. 682 0
      venv/lib/python3.11/site-packages/mypy/join.py
  95. 二進制
      venv/lib/python3.11/site-packages/mypy/literals.cpython-311-x86_64-linux-gnu.so
  96. 306 0
      venv/lib/python3.11/site-packages/mypy/literals.py
  97. 二進制
      venv/lib/python3.11/site-packages/mypy/lookup.cpython-311-x86_64-linux-gnu.so
  98. 61 0
      venv/lib/python3.11/site-packages/mypy/lookup.py
  99. 二進制
      venv/lib/python3.11/site-packages/mypy/main.cpython-311-x86_64-linux-gnu.so
  100. 1550 0
      venv/lib/python3.11/site-packages/mypy/main.py

+ 3 - 0
requiments.txt

@@ -9,6 +9,8 @@ idna               3.4
 isort              5.12.0
 lazy-object-proxy  1.9.0
 mccabe             0.7.0
+mypy               1.5.1
+mypy-extensions    1.0.0
 pip                23.2.1
 platformdirs       3.10.0
 pycodestyle        2.11.0
@@ -20,5 +22,6 @@ requests           2.31.0
 setuptools         65.5.0
 snowballstemmer    2.2.0
 tomlkit            0.12.1
+typing_extensions  4.8.0
 urllib3            2.0.5
 wrapt              1.15.0

二進制
venv/lib/python3.11/site-packages/ced4bbd844d3a34b6fc2__mypyc.cpython-311-x86_64-linux-gnu.so


+ 1 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 229 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/LICENSE

@@ -0,0 +1,229 @@
+Mypy (and mypyc) are licensed under the terms of the MIT license, reproduced below.
+
+= = = = =
+
+The MIT License
+
+Copyright (c) 2012-2022 Jukka Lehtosalo and contributors
+Copyright (c) 2015-2022 Dropbox, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+= = = = =
+
+Portions of mypy and mypyc are licensed under different licenses.
+The files
+mypyc/lib-rt/pythonsupport.h, mypyc/lib-rt/getargs.c and
+mypyc/lib-rt/getargsfast.c are licensed under the PSF 2 License, reproduced
+below.
+
+= = = = =
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python
+alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee.  This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions.  Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee.  This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party.  As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee.  Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement.  This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013.  This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee.  This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+        ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands.  All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 44 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/METADATA

@@ -0,0 +1,44 @@
+Metadata-Version: 2.1
+Name: mypy
+Version: 1.5.1
+Summary: Optional static typing for Python
+Home-page: https://www.mypy-lang.org/
+Author: Jukka Lehtosalo
+Author-email: jukka.lehtosalo@iki.fi
+License: MIT License
+Project-URL: News, https://mypy-lang.org/news.html
+Project-URL: Documentation, https://mypy.readthedocs.io/en/stable/index.html
+Project-URL: Repository, https://github.com/python/mypy
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Topic :: Software Development
+Classifier: Typing :: Typed
+Requires-Python: >=3.8
+License-File: LICENSE
+Requires-Dist: typing-extensions >=4.1.0
+Requires-Dist: mypy-extensions >=1.0.0
+Requires-Dist: tomli >=1.1.0 ; python_version < "3.11"
+Provides-Extra: dmypy
+Requires-Dist: psutil >=4.0 ; extra == 'dmypy'
+Provides-Extra: install-types
+Requires-Dist: pip ; extra == 'install-types'
+Provides-Extra: python2
+Provides-Extra: reports
+Requires-Dist: lxml ; extra == 'reports'
+
+Mypy -- Optional Static Typing for Python
+=========================================
+
+Add type annotations to your Python programs, and use mypy to type
+check them.  Mypy is essentially a Python linter on steroids, and it
+can catch many programming errors by analyzing your program, without
+actually having to run it.  Mypy has a powerful type system with
+features such as type inference, gradual typing, generics and union
+types.

+ 1487 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/RECORD

@@ -0,0 +1,1487 @@
+../../../bin/dmypy,sha256=BZAu1FaO-Xqr2djndvF1UQUDzONVwbsLbPhkFTVixsA,290
+../../../bin/mypy,sha256=DqrCxacBxY5KFqE-m8RpMFQ4jVhdeG_BOm_AuDb0v1g,286
+../../../bin/mypyc,sha256=ydZq_Hm-M7kze7OGq7gp02jA_oloYSkWMNdU8P1FFh4,269
+../../../bin/stubgen,sha256=UYPGk9F8AW6ZIWcHDPaVdR_DXvRlCuFvyy3Ii_AmmbA,267
+../../../bin/stubtest,sha256=Blk68D2Gk-OGMFrsNGFKesQxVEhLk4vMi4Qdpy2MOwo,268
+ced4bbd844d3a34b6fc2__mypyc.cpython-311-x86_64-linux-gnu.so,sha256=kEJToChoep1XgVIUpvQV7Hp2PTQXbJgbEFPvToQlJkw,28525896
+mypy-1.5.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+mypy-1.5.1.dist-info/LICENSE,sha256=-Y7dgWkG6YbHCZIiHjcRxzzGja0J4AuHR-E2b22zP5s,11328
+mypy-1.5.1.dist-info/METADATA,sha256=OqlSn_uyMAsMTfhJaDZLsg0YUvnSvxgpARHui1NqEIk,1746
+mypy-1.5.1.dist-info/RECORD,,
+mypy-1.5.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy-1.5.1.dist-info/WHEEL,sha256=_LZBqZ35DCu3uv8ATZIVr5ONm4B0sfkj2MEukraC5JM,152
+mypy-1.5.1.dist-info/entry_points.txt,sha256=DKRnGYlnjnz9_6jxYhHskdeZLwNC69R-ZPVxv3b9dpc,179
+mypy-1.5.1.dist-info/top_level.txt,sha256=vfNpUwXx5m9MRv4c74jPm30rhnpdiU-geJQ-2dTrKiY,39
+mypy/__init__.cpython-311-x86_64-linux-gnu.so,sha256=lAZPNSC8YSeq16HEkMgITxZE6wogE59LY7mDNLl_x00,8008
+mypy/__init__.py,sha256=4yp43qNAZZ0ViBpVn56Bc7MA4H2UMXe0WTVPdkODP6k,37
+mypy/__main__.py,sha256=OYmAgQIvrZCCYYZc1L4ZM_ZebZ5ZkcxqNeWkJG4Zg70,1061
+mypy/__pycache__/__init__.cpython-311.pyc,,
+mypy/__pycache__/__main__.cpython-311.pyc,,
+mypy/__pycache__/api.cpython-311.pyc,,
+mypy/__pycache__/applytype.cpython-311.pyc,,
+mypy/__pycache__/argmap.cpython-311.pyc,,
+mypy/__pycache__/binder.cpython-311.pyc,,
+mypy/__pycache__/bogus_type.cpython-311.pyc,,
+mypy/__pycache__/build.cpython-311.pyc,,
+mypy/__pycache__/checker.cpython-311.pyc,,
+mypy/__pycache__/checkexpr.cpython-311.pyc,,
+mypy/__pycache__/checkmember.cpython-311.pyc,,
+mypy/__pycache__/checkpattern.cpython-311.pyc,,
+mypy/__pycache__/checkstrformat.cpython-311.pyc,,
+mypy/__pycache__/config_parser.cpython-311.pyc,,
+mypy/__pycache__/constant_fold.cpython-311.pyc,,
+mypy/__pycache__/constraints.cpython-311.pyc,,
+mypy/__pycache__/copytype.cpython-311.pyc,,
+mypy/__pycache__/defaults.cpython-311.pyc,,
+mypy/__pycache__/dmypy_os.cpython-311.pyc,,
+mypy/__pycache__/dmypy_server.cpython-311.pyc,,
+mypy/__pycache__/dmypy_util.cpython-311.pyc,,
+mypy/__pycache__/erasetype.cpython-311.pyc,,
+mypy/__pycache__/errorcodes.cpython-311.pyc,,
+mypy/__pycache__/errors.cpython-311.pyc,,
+mypy/__pycache__/evalexpr.cpython-311.pyc,,
+mypy/__pycache__/expandtype.cpython-311.pyc,,
+mypy/__pycache__/exprtotype.cpython-311.pyc,,
+mypy/__pycache__/fastparse.cpython-311.pyc,,
+mypy/__pycache__/find_sources.cpython-311.pyc,,
+mypy/__pycache__/fixup.cpython-311.pyc,,
+mypy/__pycache__/freetree.cpython-311.pyc,,
+mypy/__pycache__/fscache.cpython-311.pyc,,
+mypy/__pycache__/fswatcher.cpython-311.pyc,,
+mypy/__pycache__/gclogger.cpython-311.pyc,,
+mypy/__pycache__/git.cpython-311.pyc,,
+mypy/__pycache__/graph_utils.cpython-311.pyc,,
+mypy/__pycache__/indirection.cpython-311.pyc,,
+mypy/__pycache__/infer.cpython-311.pyc,,
+mypy/__pycache__/inspections.cpython-311.pyc,,
+mypy/__pycache__/ipc.cpython-311.pyc,,
+mypy/__pycache__/join.cpython-311.pyc,,
+mypy/__pycache__/literals.cpython-311.pyc,,
+mypy/__pycache__/lookup.cpython-311.pyc,,
+mypy/__pycache__/main.cpython-311.pyc,,
+mypy/__pycache__/maptype.cpython-311.pyc,,
+mypy/__pycache__/meet.cpython-311.pyc,,
+mypy/__pycache__/memprofile.cpython-311.pyc,,
+mypy/__pycache__/message_registry.cpython-311.pyc,,
+mypy/__pycache__/messages.cpython-311.pyc,,
+mypy/__pycache__/metastore.cpython-311.pyc,,
+mypy/__pycache__/mixedtraverser.cpython-311.pyc,,
+mypy/__pycache__/modulefinder.cpython-311.pyc,,
+mypy/__pycache__/moduleinspect.cpython-311.pyc,,
+mypy/__pycache__/mro.cpython-311.pyc,,
+mypy/__pycache__/nodes.cpython-311.pyc,,
+mypy/__pycache__/operators.cpython-311.pyc,,
+mypy/__pycache__/options.cpython-311.pyc,,
+mypy/__pycache__/parse.cpython-311.pyc,,
+mypy/__pycache__/partially_defined.cpython-311.pyc,,
+mypy/__pycache__/patterns.cpython-311.pyc,,
+mypy/__pycache__/plugin.cpython-311.pyc,,
+mypy/__pycache__/pyinfo.cpython-311.pyc,,
+mypy/__pycache__/reachability.cpython-311.pyc,,
+mypy/__pycache__/refinfo.cpython-311.pyc,,
+mypy/__pycache__/renaming.cpython-311.pyc,,
+mypy/__pycache__/report.cpython-311.pyc,,
+mypy/__pycache__/scope.cpython-311.pyc,,
+mypy/__pycache__/semanal.cpython-311.pyc,,
+mypy/__pycache__/semanal_classprop.cpython-311.pyc,,
+mypy/__pycache__/semanal_enum.cpython-311.pyc,,
+mypy/__pycache__/semanal_infer.cpython-311.pyc,,
+mypy/__pycache__/semanal_main.cpython-311.pyc,,
+mypy/__pycache__/semanal_namedtuple.cpython-311.pyc,,
+mypy/__pycache__/semanal_newtype.cpython-311.pyc,,
+mypy/__pycache__/semanal_pass1.cpython-311.pyc,,
+mypy/__pycache__/semanal_shared.cpython-311.pyc,,
+mypy/__pycache__/semanal_typeargs.cpython-311.pyc,,
+mypy/__pycache__/semanal_typeddict.cpython-311.pyc,,
+mypy/__pycache__/sharedparse.cpython-311.pyc,,
+mypy/__pycache__/solve.cpython-311.pyc,,
+mypy/__pycache__/split_namespace.cpython-311.pyc,,
+mypy/__pycache__/state.cpython-311.pyc,,
+mypy/__pycache__/stats.cpython-311.pyc,,
+mypy/__pycache__/strconv.cpython-311.pyc,,
+mypy/__pycache__/stubdoc.cpython-311.pyc,,
+mypy/__pycache__/stubgen.cpython-311.pyc,,
+mypy/__pycache__/stubgenc.cpython-311.pyc,,
+mypy/__pycache__/stubinfo.cpython-311.pyc,,
+mypy/__pycache__/stubtest.cpython-311.pyc,,
+mypy/__pycache__/stubutil.cpython-311.pyc,,
+mypy/__pycache__/subtypes.cpython-311.pyc,,
+mypy/__pycache__/suggestions.cpython-311.pyc,,
+mypy/__pycache__/traverser.cpython-311.pyc,,
+mypy/__pycache__/treetransform.cpython-311.pyc,,
+mypy/__pycache__/tvar_scope.cpython-311.pyc,,
+mypy/__pycache__/type_visitor.cpython-311.pyc,,
+mypy/__pycache__/typeanal.cpython-311.pyc,,
+mypy/__pycache__/typeops.cpython-311.pyc,,
+mypy/__pycache__/types.cpython-311.pyc,,
+mypy/__pycache__/types_utils.cpython-311.pyc,,
+mypy/__pycache__/typestate.cpython-311.pyc,,
+mypy/__pycache__/typetraverser.cpython-311.pyc,,
+mypy/__pycache__/typevars.cpython-311.pyc,,
+mypy/__pycache__/typevartuples.cpython-311.pyc,,
+mypy/__pycache__/util.cpython-311.pyc,,
+mypy/__pycache__/version.cpython-311.pyc,,
+mypy/__pycache__/visitor.cpython-311.pyc,,
+mypy/api.cpython-311-x86_64-linux-gnu.so,sha256=D9drnLm2OgesvnNQyzU-WW60pp1Sy5Yl5HdQJWz5DAk,8008
+mypy/api.py,sha256=z1YRAJA2Tk5dvAspKo4yCkan0fB6OSBtQq-qKQEMEBM,2922
+mypy/applytype.cpython-311-x86_64-linux-gnu.so,sha256=jANS7v5-fHVbeYc7dn1DXOPTv79MGHxm_hs9Q1NYleM,8024
+mypy/applytype.py,sha256=yyJ-k_d8i5eYeC1suyMugaIqITmJi30ziuvdzq1R1IA,7149
+mypy/argmap.cpython-311-x86_64-linux-gnu.so,sha256=HdjLD3BHeP1mISDjoslklLTk_6rynHf2CwbC6Nf5Jak,8016
+mypy/argmap.py,sha256=9-1UG9F1s5Q4FL-LbViYwFHfNQTkuPLvwnDp9z8YkSw,10207
+mypy/binder.cpython-311-x86_64-linux-gnu.so,sha256=38xvoCTthnikiuGW8lfDNmAffHASlrLXbVT526w5SlQ,8016
+mypy/binder.py,sha256=vUjcTq3dOxLb4T14bUy6v0twgE3Y9UM9USA-VqJVXoI,17975
+mypy/bogus_type.py,sha256=w3GrsWoj5FKbfEUsc87OVFO812HC9BvnWnSaV2T4u1c,816
+mypy/build.cpython-311-x86_64-linux-gnu.so,sha256=4xkLpywZzxWL2paDEK75cMUUaKtyVRGjWge9PkDKnZk,8016
+mypy/build.py,sha256=d7UO2oVK-tLL6miP0fxuU7TSoBPBOOfKsl19T47glYY,144182
+mypy/checker.cpython-311-x86_64-linux-gnu.so,sha256=033tDmX3UAKKuhy2EVIzu29NKaDhSBQOZ6xq0V4AtiQ,8016
+mypy/checker.py,sha256=w61qvkFADlIj4Fy3rYwTCdjrQFXaRXV1n3NXdOl-ZkQ,348573
+mypy/checkexpr.cpython-311-x86_64-linux-gnu.so,sha256=GkqXWvXd2j3VQ4B2CsUqeENzjQPAhBN5Aib09HV5UfA,8024
+mypy/checkexpr.py,sha256=D5opW6gm-yLF8qTwigUTTCGzQlK7d1mKA9FOrdJJUME,257342
+mypy/checkmember.cpython-311-x86_64-linux-gnu.so,sha256=OPJFTHY1Uu6AMFtudIpewYueVhBxlxOlmSj0sBRfO8Y,8024
+mypy/checkmember.py,sha256=ZESYJMhB-PGX05sKe05Mdgf2t8T9XCGvUDDnKvquXCE,51652
+mypy/checkpattern.cpython-311-x86_64-linux-gnu.so,sha256=k9pwH6syTnL_ptJsVLjhJ6NWaU_CRc9RIIGDSALERJo,8024
+mypy/checkpattern.py,sha256=6DQWoJIKRtmM0RrRu8VKX5jCbf-fuW8t_eTRJKdzyl0,28648
+mypy/checkstrformat.cpython-311-x86_64-linux-gnu.so,sha256=IM6v7vAlpRiQOYAvsXqQdPT0iCoZuzLrpddnK7gBckQ,8032
+mypy/checkstrformat.py,sha256=A_udye824EjyuvMH_yKcDFPC9yiCfb2wWUcuTu33MTI,45859
+mypy/config_parser.cpython-311-x86_64-linux-gnu.so,sha256=RCl6NEwkSM-oFvSiKSTbeU6UocwACl2-NrSNWsgFJi4,8032
+mypy/config_parser.py,sha256=h8T4zLf2Cy2b2PYWFvNakNF4-HqUIE1XCbVLYmZ9z-c,21669
+mypy/constant_fold.cpython-311-x86_64-linux-gnu.so,sha256=0TFnq55nf_kPWud1X-F-1BCktn5Qk39GrsrthQ2kTuw,8032
+mypy/constant_fold.py,sha256=tAkvl9svLCOKMRZQnnUKdMUhU5bEBZmtBK89dtrPKmo,6071
+mypy/constraints.cpython-311-x86_64-linux-gnu.so,sha256=g6nH2HmHyeO_ykWeFIPT09bfjZdAx6NO68E1n0hF-4A,8024
+mypy/constraints.py,sha256=HpARwqGV_p534zdrYBR_uFsA2nfSgVqzz_4pGVuxgNU,55851
+mypy/copytype.cpython-311-x86_64-linux-gnu.so,sha256=7LVvaaswtrKyqW0wsBA-tsWYIlm9VmeuioswH6jlUCE,8016
+mypy/copytype.py,sha256=uD1VnR8yP40osAbJZa0aAKGBp5YzJriyUV7gXE0xux4,4425
+mypy/defaults.cpython-311-x86_64-linux-gnu.so,sha256=BhDZTFwMiwt8Cr1c7dxX2SEnOX0BjkfGsknnkqRGci4,8016
+mypy/defaults.py,sha256=PX4EN2kAHAA7dqL8BA3qcRav584mEFEcSff8Tl5PxKM,1544
+mypy/dmypy/__init__.cpython-311-x86_64-linux-gnu.so,sha256=GOjFNVLp4lZQvkUz-eJAD3aZZ5REu71h_Ixh3v1bLBo,8016
+mypy/dmypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/dmypy/__main__.py,sha256=u6ZYw52bfIJ11Oo88mzx7p4WD2WUo1-H9PRsT45eswU,128
+mypy/dmypy/__pycache__/__init__.cpython-311.pyc,,
+mypy/dmypy/__pycache__/__main__.cpython-311.pyc,,
+mypy/dmypy/__pycache__/client.cpython-311.pyc,,
+mypy/dmypy/client.cpython-311-x86_64-linux-gnu.so,sha256=lm3ABkVCP_fyBdsNEZK-vFXH-TDk_1zT7v_Akbw_2ug,8016
+mypy/dmypy/client.py,sha256=B5xoRr9yRe40QVD0bNhdnrWnOagt5LCbM9FaQw5yKUw,24162
+mypy/dmypy_os.cpython-311-x86_64-linux-gnu.so,sha256=96zx_AAP3ghQ3-RpYM4tMTpSIkApB80Gq6rj-5C5jrA,8016
+mypy/dmypy_os.py,sha256=nmfi-HdtYmmEa06t2516asBL-ozX048daR1OxaxFU9w,1154
+mypy/dmypy_server.cpython-311-x86_64-linux-gnu.so,sha256=rcAblrAiWfq7yWc8s9E1YP1M_Jh1L5yJSYazhaWZJ-0,8024
+mypy/dmypy_server.py,sha256=LpsEui2kK20LR1saRhRjmlRPIsdAIL1oyZcJUHelDfA,42835
+mypy/dmypy_util.cpython-311-x86_64-linux-gnu.so,sha256=mG6cGRgcE1TGrheU2QPJxkWaaCAAR2Y5u9WOlzObWA8,8024
+mypy/dmypy_util.py,sha256=4noiuknq06s4sv992uuyMNjhHtcNPXUuN7MjIzI5pFY,846
+mypy/erasetype.cpython-311-x86_64-linux-gnu.so,sha256=Ldw8BZVP_Sfbbd585OL5THq5AsRjXAXf4yZBiU57X_E,8024
+mypy/erasetype.py,sha256=fuUAoaqWVybi5nfxRet5nHrKK_sD9C-h4rhqJN_JeoA,8035
+mypy/errorcodes.cpython-311-x86_64-linux-gnu.so,sha256=iv_CaKRjRGYayuUp75KR66X-oQkcCcq3nXkz-NdpquM,8024
+mypy/errorcodes.py,sha256=HDILJ0Q2CUUtIkXO8OtfdBIYhHRIjrbhqLuWN_NJnpw,9462
+mypy/errors.cpython-311-x86_64-linux-gnu.so,sha256=IhHH3kDhXjjOYaDgQcu1znA61UWpOoAOpBxYH0T-tfM,8016
+mypy/errors.py,sha256=SZ6Ljg4ikXoOoY1OnnHexGuYpBwT26K2NI0l62RlwC4,47620
+mypy/evalexpr.cpython-311-x86_64-linux-gnu.so,sha256=UKOC_I9pQlBbaEGJ4olhSakjhWyxV6dgqoGpVWOrcaU,8016
+mypy/evalexpr.py,sha256=viRAzjVZ411NRdE0Jy7gJpUUuW-FrzGWtvDQxlvRtPs,6561
+mypy/expandtype.cpython-311-x86_64-linux-gnu.so,sha256=bMugfbV3mS5TmCVpZiVgerKsSSKgJGCiNwPa-s1fjBA,8024
+mypy/expandtype.py,sha256=O3Q2aliR3kttlfb4bMEtt_QEA67tK_oi-ks27SQDJWw,24921
+mypy/exprtotype.cpython-311-x86_64-linux-gnu.so,sha256=K53Uu5I4eggwGTjmbs9nr3UnNSMXkIwBkd3jQluBNT8,8024
+mypy/exprtotype.py,sha256=YY8MI5L28XDWiU91nRMOhFoLIQkVxHTgkCq057Ltq-U,7182
+mypy/fastparse.cpython-311-x86_64-linux-gnu.so,sha256=twmcuEofFWodoCYrrkQnfpGRRXzGPWTjj--gBVFfnoc,8024
+mypy/fastparse.py,sha256=uFu5FWk5yUud_PfzlsyEMSybcfnJHEpxn_DwrbZnUPQ,80839
+mypy/find_sources.cpython-311-x86_64-linux-gnu.so,sha256=IVgBuueZ0PYRGFIiTV2_OaSIMb27Q7INMnARqMXdwA4,8024
+mypy/find_sources.py,sha256=LtHK4iJKl05aXO3oheb2Re2FkKoyFfeO68BjFwU-jTs,9362
+mypy/fixup.cpython-311-x86_64-linux-gnu.so,sha256=GImuuaqZ15rm30mkzrD_8QuXzz034u9ofagUL8vj62Y,8016
+mypy/fixup.py,sha256=kgAMZq-FklDXawlfiUFh_syhAry80w9wIDIa1YS2WBg,14638
+mypy/freetree.cpython-311-x86_64-linux-gnu.so,sha256=BzcJyzsE0xWiwFndd_-4WhMQk5PsqFSVVzfTLhFw0CE,8016
+mypy/freetree.py,sha256=yz4_ZUq8Ja89176nbDEAiBk-Et2nP74_KXyCcaW4inA,617
+mypy/fscache.cpython-311-x86_64-linux-gnu.so,sha256=F768MjlWm5o7JSse6snaW68LPwbgzOFzcyyEpoTkKjY,8016
+mypy/fscache.py,sha256=WvM25Tew6sIpSIXggPgSUS9sK0kl5pWdruDwetGx0z0,11328
+mypy/fswatcher.cpython-311-x86_64-linux-gnu.so,sha256=Z3nhqZcIwJUGcvz_v1PzNJ_0w-0JU4uEiDKNwVkUL0Y,8024
+mypy/fswatcher.py,sha256=l4klHOpQLSPPeH1_B8OAeIVTFDXhzFM6BOpjRBbYHVI,3969
+mypy/gclogger.cpython-311-x86_64-linux-gnu.so,sha256=v2l0XQtCnvuVqwoHO1GqH9H1xKuuEfDgrVGxaXDRxkw,8016
+mypy/gclogger.py,sha256=8-Af1sazzjueP0xkOFixPHsN77H7pbGaoIccZSCqLNo,1641
+mypy/git.cpython-311-x86_64-linux-gnu.so,sha256=E7b6YHuW7Fxn2SHwVJG3RinQd3vgUWDMhzDUrGpavH0,8008
+mypy/git.py,sha256=FYdMg-3fTtikKjUwfFPXbWiNmpOIMG4rNgMAWIPBsLM,980
+mypy/graph_utils.cpython-311-x86_64-linux-gnu.so,sha256=EvgHK9-ejxknjEsDncmUC1qQBuIQ56GF3mRr4yC49-o,8024
+mypy/graph_utils.py,sha256=HD2zzPpq80hbBJPj759W1RmTm6eDtHBirQt5ih0o_Gg,3343
+mypy/indirection.cpython-311-x86_64-linux-gnu.so,sha256=dcQKsUa-5HH0jx9i7TkYIk5f9SbhepTzf63ky4YcV5E,8024
+mypy/indirection.py,sha256=H3VHroI-TE4ZVTJhBr-93VuZwazedexbwlJPKo-uy-U,4595
+mypy/infer.cpython-311-x86_64-linux-gnu.so,sha256=6thZBVD3PmeiRuBWOARx3HH8gqmBdo_cOgUroJSEjGE,8016
+mypy/infer.py,sha256=XOcSyCoNMNlkpkO2XjCZLiOILOU3PS2EQipTuj8lREc,2334
+mypy/inspections.cpython-311-x86_64-linux-gnu.so,sha256=mBGDydRqX4xCYMp516i7VUfoth5dFSSJXhoiSd-pM-g,8024
+mypy/inspections.py,sha256=p_qDf9_pDTg22jpwgLK4ZVIUnmVJNPrCkRlt_vnGUpg,23663
+mypy/ipc.cpython-311-x86_64-linux-gnu.so,sha256=BbjAH6oGTSB-gXwxEsgx2McPHYlSjJ44NfNUEtLx8KE,8008
+mypy/ipc.py,sha256=tGBz58bPOUc4Wu3V4fOgmvdjU6zgRS_Mds-1kSyeXBg,9877
+mypy/join.cpython-311-x86_64-linux-gnu.so,sha256=BAcajyApj8ChF7iGUFMfT0o3zT4_QrafH1paaG0WGys,8008
+mypy/join.py,sha256=hveC2MjP4Z1MIalR4vKWrstMhMXzr2YVGCf6XR97k14,26580
+mypy/literals.cpython-311-x86_64-linux-gnu.so,sha256=E_16AgrPPleOUKCFCXpKrj6oAJDCzICZYQYYiTkuLd8,8016
+mypy/literals.py,sha256=mhy-7_Gq4C9U4hyCZv1TKs3pJEOITJpq6S97IQzQCs8,8749
+mypy/lookup.cpython-311-x86_64-linux-gnu.so,sha256=4yghKKNFjHrIzGz4xcQK2CNeNxLt4Pupmc4YsonuQn4,8016
+mypy/lookup.py,sha256=azRWZ_lXiK6ZN_bxslUBjAkFcqywGO0dlQgjpWaBtSg,2054
+mypy/main.cpython-311-x86_64-linux-gnu.so,sha256=uTZYYbE6XBpBzJUq-aHNZF62vzRBKL_nUcN5YGN9zeg,8008
+mypy/main.py,sha256=2nHbHLi3y-61iKOJuLWuwlBfPIkiEss3lC2Wt5_0ja0,57526
+mypy/maptype.cpython-311-x86_64-linux-gnu.so,sha256=VRm77lRh7tqoUuC5IMS8HoyqqyNjRKrUoOCUd7wfUok,8016
+mypy/maptype.py,sha256=dnbblcwy6ZXvFoHO-uvtDZmiSTR4on6L6JKTmqXQw9A,4836
+mypy/meet.cpython-311-x86_64-linux-gnu.so,sha256=D-DPo7kSy8OT0nyMLeknwS3jsv2ZckFpKAQQb6g5IGg,8008
+mypy/meet.py,sha256=VcqWYWf6IAW7HuFmebVY6BKT6WTf465u1V8Osi-kpQo,40534
+mypy/memprofile.cpython-311-x86_64-linux-gnu.so,sha256=EkNYf4L1ZupU_uxOPm4tWdP99YUc_W8oeTwyS6qaVmA,8024
+mypy/memprofile.py,sha256=5_FQvTONgPFZInsMhvKUHhZ979IdMZCY1nQ2303F1Mo,4153
+mypy/message_registry.cpython-311-x86_64-linux-gnu.so,sha256=YZ_RT08BzWvKk3InVI-IjEFlAh_BsQ-y_-F9IOilhcE,8032
+mypy/message_registry.py,sha256=9bKgreQutO6nZy0f3a2tyL_yn6JCMfnt0xtt9iEkCME,15039
+mypy/messages.cpython-311-x86_64-linux-gnu.so,sha256=CxZ0HZJTr_EGWaQ3VftDivi8KSmAdU5c6ojaMfGq0k4,8016
+mypy/messages.py,sha256=nx8C-_umeejrWfvwzX3Xpgu7F31HszmYBfuSnP3fg3g,123276
+mypy/metastore.cpython-311-x86_64-linux-gnu.so,sha256=_gdE7bRY5S9EdTUGwK-sFo367dYV7GoJGXGAThYYqYc,8024
+mypy/metastore.py,sha256=oen-1iJsl0IUTNYuFrVyV6EgmqL3GaL5n4oJLfgIZ0I,6717
+mypy/mixedtraverser.cpython-311-x86_64-linux-gnu.so,sha256=iPcgXAuQFBuKskuW4z3bKajIYoYbFxrViQIJh4FW_tU,8032
+mypy/mixedtraverser.py,sha256=FMVLlo0kwOZwtbB0OWSP_vK0zhKF8XA53zrA5HTQlMI,3198
+mypy/modulefinder.cpython-311-x86_64-linux-gnu.so,sha256=GuubeLW2kqYjGv9QETrLotzxTnj9hYosNxS79V98zVw,8024
+mypy/modulefinder.py,sha256=E4vzkrKelsRRpt0QwTLXYyBYXP5rsnnzJIOa_Gj_UW8,38812
+mypy/moduleinspect.cpython-311-x86_64-linux-gnu.so,sha256=uNIGPcyhUf-kJOCIhXr4e7Ty65bywECW8W2lx1fHWUk,8032
+mypy/moduleinspect.py,sha256=srtb0EXK2ekqLHjC6YXDdN5ZoGpt9gW35rS7jknlHvQ,6050
+mypy/mro.cpython-311-x86_64-linux-gnu.so,sha256=iGrYOWKxos-CBqmnxdGnKxK300peQweoGx855r8R7x8,8008
+mypy/mro.py,sha256=Mj_6Ke6W-s2ordeoLWS-LAya3-LUNTv-p2iHFcyxF1A,1993
+mypy/nodes.cpython-311-x86_64-linux-gnu.so,sha256=tX3ZtHsXb9uFHCc4OHq0yATm9LDYnSy_CIXw5qu9Hlc,8016
+mypy/nodes.py,sha256=OhtSlwOWnyW5xQwfqhTKL1FripINLVAKkl1q16cFzIM,133905
+mypy/operators.cpython-311-x86_64-linux-gnu.so,sha256=8VNYwFjaHywDhE9-Cf9SIo5FUdbQeMf1j2-2mF_fGpw,8024
+mypy/operators.py,sha256=UHBxRVc47T4trm0vCDt4ZbvyYt57M5ZoRIelwRkzwp4,2440
+mypy/options.cpython-311-x86_64-linux-gnu.so,sha256=aq6rPYYoCGNLOUK6ywsZIhU6jCuXLA17RoxjPLGRT7I,8016
+mypy/options.py,sha256=vJWZGteTkYvRKncnGSaBOfqsKGv1l7132IoVyOE27Kw,22070
+mypy/parse.cpython-311-x86_64-linux-gnu.so,sha256=WYKO61q4thVmW6Q5GtPghmADs8l36z6uNGkR34PgFyI,8016
+mypy/parse.py,sha256=V5E_zv7IsdBcSKZCirOzvTPBepQJf6Froxqtk7e9WXA,778
+mypy/partially_defined.cpython-311-x86_64-linux-gnu.so,sha256=CbNOyYg4hQRzb1oSoU53pdmqdwDXXR9p10yX2gDIJEM,8040
+mypy/partially_defined.py,sha256=XcslzVgo0y_ptYOZlS7iUGL7UgdmFxO6RtDvhlssoIY,25354
+mypy/patterns.cpython-311-x86_64-linux-gnu.so,sha256=njMHUg4dXotCi9LjPotwqfEESvJDjQlqlbjeEqDfp9I,8016
+mypy/patterns.py,sha256=lLy0h7ALe15iR1J18zM61ViPJ9lzLBwB7Ml5QOrENk8,3974
+mypy/plugin.cpython-311-x86_64-linux-gnu.so,sha256=9VIPzkln7EBoEJ_M0GI-21u7mT6HuuNqDYHJx1w-SqU,8016
+mypy/plugin.py,sha256=jpWmM8vzH1OvU72TlWAQYHFxJIHoC6WdK-AZaAvV27c,35435
+mypy/plugins/__init__.cpython-311-x86_64-linux-gnu.so,sha256=htAfBuzDyr2ls_yyc-reRW4TmIrpXklum11qI2K-8bM,8016
+mypy/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/plugins/__pycache__/__init__.cpython-311.pyc,,
+mypy/plugins/__pycache__/attrs.cpython-311.pyc,,
+mypy/plugins/__pycache__/common.cpython-311.pyc,,
+mypy/plugins/__pycache__/ctypes.cpython-311.pyc,,
+mypy/plugins/__pycache__/dataclasses.cpython-311.pyc,,
+mypy/plugins/__pycache__/default.cpython-311.pyc,,
+mypy/plugins/__pycache__/enums.cpython-311.pyc,,
+mypy/plugins/__pycache__/functools.cpython-311.pyc,,
+mypy/plugins/__pycache__/singledispatch.cpython-311.pyc,,
+mypy/plugins/attrs.cpython-311-x86_64-linux-gnu.so,sha256=7HVBo-Udfs0JEl2XTzOgBgg_8i8Qkmjfyiv9EvDqysk,8016
+mypy/plugins/attrs.py,sha256=lVt2xxushdLIEYB_bm2-QsBmB_aBJ0uhZd_65XfghU0,42386
+mypy/plugins/common.cpython-311-x86_64-linux-gnu.so,sha256=JaihCGNmdaoUIVyLsSgovD5IRLZeVfhe86_pGug37vA,8016
+mypy/plugins/common.py,sha256=aF8x9BLOLF83-iiMAHQTL-ZXg1-Tu0u0mmjdq1iz_Nk,11213
+mypy/plugins/ctypes.cpython-311-x86_64-linux-gnu.so,sha256=B4dhFc9JAizdDxf_R_b5RIrKMqWQYcVDHML7COZQBuk,8016
+mypy/plugins/ctypes.py,sha256=uB84xNCEzCVfeKjC7FHy7dFF5o55V3L-Rve9OD3YoxM,10675
+mypy/plugins/dataclasses.cpython-311-x86_64-linux-gnu.so,sha256=XxS02tgjz7NekEztsyEN9DopR_nU_IZSf3cKA6n9F88,8024
+mypy/plugins/dataclasses.py,sha256=XITUNACqwqrX2-8Vjf_clQJNVNamxxD-AxnHbKTqzJg,46259
+mypy/plugins/default.cpython-311-x86_64-linux-gnu.so,sha256=4yTrpS7qPeDDNXQRcVPM45flioa1JHztUZxqG2pdHZI,8016
+mypy/plugins/default.py,sha256=OL2tu3PNt7IM2JpVtX5Oj7lUqggNotfPInmwDmeDzYU,20182
+mypy/plugins/enums.cpython-311-x86_64-linux-gnu.so,sha256=mznbOQyt547S-KckCCfeV4BRLsjlZBWDm89nemXisJY,8016
+mypy/plugins/enums.py,sha256=-oOxzTkK8-yMb1YpxQP_53Bk5fR3hh6dFlFiiqpXfQs,10444
+mypy/plugins/functools.cpython-311-x86_64-linux-gnu.so,sha256=F08jc8z70xZPMLpFzRF5UaSPq3o3CAUSufVf3BsP3ek,8024
+mypy/plugins/functools.py,sha256=9C3y2_LDunzjkMiMyWi-IBAlJ0F4ZESKGbW3sP_9YPM,4003
+mypy/plugins/singledispatch.cpython-311-x86_64-linux-gnu.so,sha256=6hoMROJcmvytN8z2a9BzXNZqxhY7I0knKmL-d8Z1SW0,8032
+mypy/plugins/singledispatch.py,sha256=KfHOjVVwVtCn53C35sdbr8Lh20mamYUWlJQTPOlUsQw,8446
+mypy/py.typed,sha256=zlBhTdAQBRfJxeJXD-QnlXiZYsiAJYYkr3mbEsmwSac,64
+mypy/pyinfo.py,sha256=Ehwg91OYfin7ItkRZGBITakcEPONGkerMiGnmIw2Eqw,2941
+mypy/reachability.cpython-311-x86_64-linux-gnu.so,sha256=Nv19pP0nbalfYs1qZAcxUMbl2d2R0S5XvPdXSn7GrCk,8024
+mypy/reachability.py,sha256=OGbKiojvAArwJA7-UpyYyFWE9H4zcrW8gYaF5pWHVSk,12690
+mypy/refinfo.cpython-311-x86_64-linux-gnu.so,sha256=6zOiSP5iqpgJPyNTj3aknPkWDjR6gqdosj_jYl8S7dY,8016
+mypy/refinfo.py,sha256=qaWKWtkgdlYQVxNucU3KG-4U2OsOBCSG8K8lqupc2S8,2784
+mypy/renaming.cpython-311-x86_64-linux-gnu.so,sha256=_SD5AiiF_GZNB_ak4xqmExBVRDI95-fleXcPd9bzhnM,8016
+mypy/renaming.py,sha256=tlgsqrz9qhQwnLuJs2AGO0kfGeIX8k02sgM8dZNaL7c,19915
+mypy/report.cpython-311-x86_64-linux-gnu.so,sha256=n7ebv6DO-BUWNoemDryq7wUhgiKyOsT1f7vMsJvXusU,8016
+mypy/report.py,sha256=5-wYCtRP80aCBnx-XuqEmVHBeYJMmIw4OstzUAnEOxM,34136
+mypy/scope.cpython-311-x86_64-linux-gnu.so,sha256=BHN1l8kYGizgI5mcv86rs-XAtd7HILhn0oCpdagMc-g,8016
+mypy/scope.py,sha256=eryiNXSPPgPj8E5miH8aVOa0uPKa-J8wUbQS_M_65I4,4258
+mypy/semanal.cpython-311-x86_64-linux-gnu.so,sha256=U_cGk7-jyLNutup6ErSUEZA6lutW9HeNHQ7r1cX2KQo,8016
+mypy/semanal.py,sha256=JlVb8BgUr8z2cya6pFjAtnxiMfeoDotUq1BqDdZesTc,296677
+mypy/semanal_classprop.cpython-311-x86_64-linux-gnu.so,sha256=1WV-r3-6pKa_MQ_TPGNR3r7BmkH6D8c0V2ubVi27krs,8040
+mypy/semanal_classprop.py,sha256=1ONhN38A46tPtM-99LLuycSknq4RP957onYJQNMxRQw,7663
+mypy/semanal_enum.cpython-311-x86_64-linux-gnu.so,sha256=6xKuOZTT1aDuXfcblCoeGw_HQwzztXRerIsX_voT_7w,8024
+mypy/semanal_enum.py,sha256=q2OeCQNFyWzpV-WBEP-Dy4yqx7MyXgtWwDs-CjZpWpM,9310
+mypy/semanal_infer.cpython-311-x86_64-linux-gnu.so,sha256=9SeaN7-nexWHZ-0y4sqpNWT2QhhiNGGljsgf8Q4_MpU,8032
+mypy/semanal_infer.py,sha256=05i_H20jwVcECXtFXXoWAVmBAqXN5Ce2c5mdjCny01A,5180
+mypy/semanal_main.cpython-311-x86_64-linux-gnu.so,sha256=R79KUrkUPkSRIrX7n9elukoMCFqtE3H63iI_MGTJV-w,8024
+mypy/semanal_main.py,sha256=2-k6wpQkwdhnqBhVs7Clj7pqFT7l2d_p03iCRMl3s_Y,20353
+mypy/semanal_namedtuple.cpython-311-x86_64-linux-gnu.so,sha256=hYpxzf-_Tl4EOqMUAD5WmWbNDGkejT-sR-4PofmJQzM,8040
+mypy/semanal_namedtuple.py,sha256=pBCDjwTlzrl1YI8O2kmlK5crD9MScfCq0Z2hvcXiVJM,28632
+mypy/semanal_newtype.cpython-311-x86_64-linux-gnu.so,sha256=C_Dj8iF82TF1rwWI803imSqn0PV_7PRZk4UDdB6Vioc,8032
+mypy/semanal_newtype.py,sha256=RhYoxPVXu4dWiV0DKfuLcg7s6rRi8eLF8sAe4WCC0vM,10607
+mypy/semanal_pass1.cpython-311-x86_64-linux-gnu.so,sha256=dri3PJSX1QzhT6VNdtouFOKY_TKxQsqYn8Ch1-Gj8ds,8032
+mypy/semanal_pass1.py,sha256=3WuVBB8tyR33CxR-BBp_RfaS4Ef6eob3apR8yFD_vE0,5455
+mypy/semanal_shared.cpython-311-x86_64-linux-gnu.so,sha256=LtF3Z5KpUp5OJw-hzqr5jOOqpWffVHaC5BPRgOu0XGU,8032
+mypy/semanal_shared.py,sha256=dBXRq4WphZ2l-OT3-qKUpM3hql8q8neVAJ7NaI_q1ig,14826
+mypy/semanal_typeargs.cpython-311-x86_64-linux-gnu.so,sha256=jN7plygmqSxHdkzbvm0ihp43Nk5fVzISGXT0eqMri9I,8032
+mypy/semanal_typeargs.py,sha256=gPEXsVolQLFau4p3p-ABPgFpWRlyCASmhopi_Mn8uTY,11105
+mypy/semanal_typeddict.cpython-311-x86_64-linux-gnu.so,sha256=sryPpZWxj13rMIV8tuciPWfOyXRyx9vCRVxkWZVQ_bE,8040
+mypy/semanal_typeddict.py,sha256=wSi1_pP-LYL9l-cr3GWYcaxuuwAfCOeXbbs0G6v92JY,22917
+mypy/server/__init__.cpython-311-x86_64-linux-gnu.so,sha256=TQ3gO5O-AQoSZRjTEwK5hPBpRaWY9dFtrUlhaLYIZ5E,8016
+mypy/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/server/__pycache__/__init__.cpython-311.pyc,,
+mypy/server/__pycache__/astdiff.cpython-311.pyc,,
+mypy/server/__pycache__/astmerge.cpython-311.pyc,,
+mypy/server/__pycache__/aststrip.cpython-311.pyc,,
+mypy/server/__pycache__/deps.cpython-311.pyc,,
+mypy/server/__pycache__/mergecheck.cpython-311.pyc,,
+mypy/server/__pycache__/objgraph.cpython-311.pyc,,
+mypy/server/__pycache__/subexpr.cpython-311.pyc,,
+mypy/server/__pycache__/target.cpython-311.pyc,,
+mypy/server/__pycache__/trigger.cpython-311.pyc,,
+mypy/server/__pycache__/update.cpython-311.pyc,,
+mypy/server/astdiff.cpython-311-x86_64-linux-gnu.so,sha256=gKCa-EGjPPtw3rskkHT_uHGgp65XrH9ngbP3yegWOCE,8016
+mypy/server/astdiff.py,sha256=L2AYR18dH_5xFD3oSVJ6jOsffpOUIVOwI8LpAj_zPPk,19864
+mypy/server/astmerge.cpython-311-x86_64-linux-gnu.so,sha256=h_zgBTAcJNpZbORgGs4GpGiSj7gHMfrNxZIf352Rtpc,8016
+mypy/server/astmerge.py,sha256=-B7q3xE6RJRWMdj1kVF-VXRqr7Cp9Nq9l3vYGf8TeaA,20752
+mypy/server/aststrip.cpython-311-x86_64-linux-gnu.so,sha256=m4jXXxp2yIel_fpcAGQZD8CdJK0LrK5ftubwkexZoi8,8016
+mypy/server/aststrip.py,sha256=SwFkSq_L2YwBEZ5GYfPBtR0PNQkEF8HVoKT8n58fwD4,11293
+mypy/server/deps.cpython-311-x86_64-linux-gnu.so,sha256=4Uk0wODsjX8Ap1ibac8lyaFH33bxgELRmUg7h8gVOQo,8008
+mypy/server/deps.py,sha256=sD1mL66ZxG0YEfBoE4S4yJHs5UJahsEZSM7j_TdlebQ,49729
+mypy/server/mergecheck.cpython-311-x86_64-linux-gnu.so,sha256=VxyJG0MIJ1I4xVFcwubbo_I-K5dCxZHwzLPNrbAip84,8024
+mypy/server/mergecheck.py,sha256=02e2JIC5sZQSGUkfOerHpH6s5mxbN5au1HB9Wx4ALj4,2760
+mypy/server/objgraph.cpython-311-x86_64-linux-gnu.so,sha256=IQ0OV5KcbNtWZ88qCIpa3vTAAppUCrDqtD1ekRTjDjE,8016
+mypy/server/objgraph.py,sha256=Z5-jBSuoaCaV9SsOK1SmNkKv1jc1_vTA5XktJjIxwiY,3230
+mypy/server/subexpr.cpython-311-x86_64-linux-gnu.so,sha256=beAkkZhrJx7JJfkB0q3TOmUF_Xh707lJrZPA8yYmWts,8016
+mypy/server/subexpr.py,sha256=_PJb8UNcTesThq1ZYaUtSb2o9wQSh8rBufAD7VZNG4s,5202
+mypy/server/target.cpython-311-x86_64-linux-gnu.so,sha256=syEM1IFpGVcKViQKkeTgEvd2KTl0AylRlAcO-_h1Zt8,8016
+mypy/server/target.py,sha256=IbuK2qqtMvEPAof83BdgYJv6AGW2q_o4CQxC5TnB-Bg,273
+mypy/server/trigger.cpython-311-x86_64-linux-gnu.so,sha256=pDK4txkNioIvTSvp96QjVHRdxG76Vx-q0zF5XS9a-EU,8016
+mypy/server/trigger.py,sha256=qvo4tCLyrhI48oPTfDO_nWOVZfjMcYjoMdGgWsocEKg,793
+mypy/server/update.cpython-311-x86_64-linux-gnu.so,sha256=Gt_so6soEzOpIgkHZPit0zUaQj36xlFvH9iQxqGBTvo,8016
+mypy/server/update.py,sha256=2qxk3REfFoar15hfrNNeXjyrATyldlOFXTIZaq0u2jE,53000
+mypy/sharedparse.cpython-311-x86_64-linux-gnu.so,sha256=9XkY5GmcJAxv3TU8L-1jbZT7eqtH0uo2vRYDeWrh96c,8024
+mypy/sharedparse.py,sha256=fDaWJyO37T5v6VPR8u_Hw-1sFGofK1eUx9R17MoDsoU,2102
+mypy/solve.cpython-311-x86_64-linux-gnu.so,sha256=lhT8Jq_kroyHgiFgasYp4XIImiiv6bl4u-qpIYW2D_M,8016
+mypy/solve.py,sha256=gIV1cPf9LFVQvas8RZuk4epp40MWm1vjMe8IN_lx6nI,15346
+mypy/split_namespace.py,sha256=P67HianSrsMSZoeuS6F9swM5eK-B2fEBU3XJ6RFtYo0,1289
+mypy/state.cpython-311-x86_64-linux-gnu.so,sha256=h-KaX6li1xyU_EyK3qcHG5Nh7DERAt8YNgRVVbJw3d8,8016
+mypy/state.py,sha256=okCVIeCimJ6ikTCHTg9gL2I4HIvg43YI21Upq8ZKBDA,824
+mypy/stats.cpython-311-x86_64-linux-gnu.so,sha256=79XTACUifBeLzG-TuHE_LDU6H0k4rHiSonaIGOwO_Mc,8016
+mypy/stats.py,sha256=eidwWKXy8eiuAG_pHe8Rp3LPjuEWVPOUG05s9npF4d8,16662
+mypy/strconv.cpython-311-x86_64-linux-gnu.so,sha256=XC43a6fgg2-sGdet2H7k1ChYaCCM9ZxPGdtMBx9ZDYs,8016
+mypy/strconv.py,sha256=3rLUG2NZT3kpRUoDmgewudZaF7Gegguou5FrCavfjuU,23387
+mypy/stubdoc.py,sha256=b0HQ2N0x5Tx6AMiXZISYqY41rJA5wYxZAYUCMWTq9JI,13938
+mypy/stubgen.cpython-311-x86_64-linux-gnu.so,sha256=56CTDTqoVBtHIUsBvBgee5jvew4FXJUy1nJRYNVuVV8,8016
+mypy/stubgen.py,sha256=MKHlkVMcPSxYaVYXDFduzkLllWb23IdmyGiij2wqFT8,75538
+mypy/stubgenc.py,sha256=FDiGgReUx8HHsiqXkMpmbo274YHq3Hd5vpaqMDBU2D0,24848
+mypy/stubinfo.cpython-311-x86_64-linux-gnu.so,sha256=J2jOnZwZHfjI8LTf5AzNw7B7eZZZqD_PqKiSxBFjomc,8016
+mypy/stubinfo.py,sha256=MLEzcUvhQg1iqowVKYkxCPxljytvmJHGAW-KbW_bFlY,6617
+mypy/stubtest.py,sha256=ZvUBLZnhm9H0ArApjGMIh0LWEVybQoBEuCf1iBMZaW8,75013
+mypy/stubutil.py,sha256=0yv_S7p3AYHDF3KiBbyM6orPmhQwH7RigFta1M-ooQo,6386
+mypy/subtypes.cpython-311-x86_64-linux-gnu.so,sha256=bbCrffb_GqQ7TdnbgkGosavtEYjg__ups2BD7Wc_8YA,8016
+mypy/subtypes.py,sha256=w8CJp2aMtf21WscKjbJkgemzj1DRfkmcUzmMMdvSdXE,78742
+mypy/suggestions.cpython-311-x86_64-linux-gnu.so,sha256=Ktpxf7_l3PAkSaSd1W0YbR2xImhaHmKs-sRZgp1bVq4,8024
+mypy/suggestions.py,sha256=XAtCVZGD51Ae0UfCkyPNZtxCVxs9sw4OkWrQR13AppE,38046
+mypy/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/test/__pycache__/__init__.cpython-311.pyc,,
+mypy/test/__pycache__/config.cpython-311.pyc,,
+mypy/test/__pycache__/data.cpython-311.pyc,,
+mypy/test/__pycache__/helpers.cpython-311.pyc,,
+mypy/test/__pycache__/test_find_sources.cpython-311.pyc,,
+mypy/test/__pycache__/test_ref_info.cpython-311.pyc,,
+mypy/test/__pycache__/testapi.cpython-311.pyc,,
+mypy/test/__pycache__/testargs.cpython-311.pyc,,
+mypy/test/__pycache__/testcheck.cpython-311.pyc,,
+mypy/test/__pycache__/testcmdline.cpython-311.pyc,,
+mypy/test/__pycache__/testconstraints.cpython-311.pyc,,
+mypy/test/__pycache__/testdaemon.cpython-311.pyc,,
+mypy/test/__pycache__/testdeps.cpython-311.pyc,,
+mypy/test/__pycache__/testdiff.cpython-311.pyc,,
+mypy/test/__pycache__/testerrorstream.cpython-311.pyc,,
+mypy/test/__pycache__/testfinegrained.cpython-311.pyc,,
+mypy/test/__pycache__/testfinegrainedcache.cpython-311.pyc,,
+mypy/test/__pycache__/testformatter.cpython-311.pyc,,
+mypy/test/__pycache__/testfscache.cpython-311.pyc,,
+mypy/test/__pycache__/testgraph.cpython-311.pyc,,
+mypy/test/__pycache__/testinfer.cpython-311.pyc,,
+mypy/test/__pycache__/testipc.cpython-311.pyc,,
+mypy/test/__pycache__/testmerge.cpython-311.pyc,,
+mypy/test/__pycache__/testmodulefinder.cpython-311.pyc,,
+mypy/test/__pycache__/testmypyc.cpython-311.pyc,,
+mypy/test/__pycache__/testparse.cpython-311.pyc,,
+mypy/test/__pycache__/testpep561.cpython-311.pyc,,
+mypy/test/__pycache__/testpythoneval.cpython-311.pyc,,
+mypy/test/__pycache__/testreports.cpython-311.pyc,,
+mypy/test/__pycache__/testsemanal.cpython-311.pyc,,
+mypy/test/__pycache__/testsolve.cpython-311.pyc,,
+mypy/test/__pycache__/teststubgen.cpython-311.pyc,,
+mypy/test/__pycache__/teststubinfo.cpython-311.pyc,,
+mypy/test/__pycache__/teststubtest.cpython-311.pyc,,
+mypy/test/__pycache__/testsubtypes.cpython-311.pyc,,
+mypy/test/__pycache__/testtransform.cpython-311.pyc,,
+mypy/test/__pycache__/testtypegen.cpython-311.pyc,,
+mypy/test/__pycache__/testtypes.cpython-311.pyc,,
+mypy/test/__pycache__/testutil.cpython-311.pyc,,
+mypy/test/__pycache__/typefixture.cpython-311.pyc,,
+mypy/test/__pycache__/update_data.cpython-311.pyc,,
+mypy/test/__pycache__/visitors.cpython-311.pyc,,
+mypy/test/config.py,sha256=MreYObGnynJA3wO-4Yeu88PMnFwuEHKFgbkp5-9O3MA,1160
+mypy/test/data.py,sha256=h0SYRz0iyaJd_s9xDMZ3QNnlVMj5Udgk4QHJTr0A_fE,29920
+mypy/test/helpers.py,sha256=bMulqdjvGCGan2pDAFHDyX24W5t5gGFi02F-VedfsHQ,15936
+mypy/test/meta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/test/meta/__pycache__/__init__.cpython-311.pyc,,
+mypy/test/meta/__pycache__/test_parse_data.cpython-311.pyc,,
+mypy/test/meta/__pycache__/test_update_data.cpython-311.pyc,,
+mypy/test/meta/test_parse_data.py,sha256=nRRiOyNBFO-DDXCVSoA3uhdf9cwvEAKq4mlTX_M2usE,2744
+mypy/test/meta/test_update_data.py,sha256=jkGbA4YsIQ4mw7CGz4GBGsuEoI-EGWDJ2PvERah-FkM,5619
+mypy/test/test_find_sources.py,sha256=-ilBplbRWcIY5NUc6GysV5hk1VWCR7gjyEsrKl0R3z4,13684
+mypy/test/test_ref_info.py,sha256=hz0P6MOqKTppSCyUXWvGamUDX433v15IpfVIHKgqFJw,1432
+mypy/test/testapi.py,sha256=Xinte9ICqFeoe9AUweIEKiHvjbgD8H_Xv6Leck_sUoA,1447
+mypy/test/testargs.py,sha256=rBfuUIyyHESbfiqOYokY6_AVKhyu_AtFVx-QONibmm0,3212
+mypy/test/testcheck.py,sha256=PH6RTv4eqgR8tA63Fo9eLOIYF60-Rk8zjkM3TiyfHs4,13681
+mypy/test/testcmdline.py,sha256=O98d9t0T_7wjhB8BL4np7dkwWoXWxLYcDWtcWTxkTnw,5074
+mypy/test/testconstraints.py,sha256=5VJFK420k7MCoeqb8efZghtyHLoHEHb9NV85EyRePiA,5796
+mypy/test/testdaemon.py,sha256=9OACkimdIGIsqx7x7yhl78Zqwz-xpD860kCh0JcfbI0,4511
+mypy/test/testdeps.py,sha256=TzP2p8p1kxpLPFLP8TOYPC9TQSd1TpEVAaxh1HUJ1mw,3087
+mypy/test/testdiff.py,sha256=HBKemEOWdfjG6B7JFx1FX6UZlhBLW44XBcIGt_sNgts,2452
+mypy/test/testerrorstream.py,sha256=ZKNOBoAWVjyRJJnHIH4-dfRkgUAaSV6uKdnQ09SV0Bc,1418
+mypy/test/testfinegrained.py,sha256=ZyibRcH7WDDovgMZeQB8djBBR1M1s9s_E8Yl1397XtU,17700
+mypy/test/testfinegrainedcache.py,sha256=AocgzZWRs8dlNcaaKzwY3QSBwxbbdwi3xwq5qcH9XTI,580
+mypy/test/testformatter.py,sha256=-0l59KcEx65YySrlHK5DiAoaGvhuSoWQSPiWXimemfU,2645
+mypy/test/testfscache.py,sha256=oXDObYVJmKRL1IiedVkbIkhxbwce3Duy_XTN2sOobjs,4456
+mypy/test/testgraph.py,sha256=Ix9xaT6zhjyJqkpWUGxYfKYbvS2Z2iWQkLpHoUTuIVA,3084
+mypy/test/testinfer.py,sha256=kaiTrv5nTMnnSCacRPDK_qs7tt-IMVxKVQiKa33ORg0,13856
+mypy/test/testipc.py,sha256=n54MoCHb4um75HTiE0aaXwj5AvuOBhewzJxjaQ9qCCE,2275
+mypy/test/testmerge.py,sha256=rJKBmsvFFzmK6UNr5bSW98QYrD-pphG732J1GsBS21Q,8661
+mypy/test/testmodulefinder.py,sha256=38Ae7t19_k5E_AiKK5qR_4ae2FAFfsv9g2URMw45DfE,13177
+mypy/test/testmypyc.py,sha256=gaQS_ZFFXh8D8eCi_IPwKPvcIQvlhnxcgX5OwrXBySM,397
+mypy/test/testparse.py,sha256=Pw3CEdZMw0TnKIsIHortg5Frc8sIA7I7Ik0FF7ek_Gk,3109
+mypy/test/testpep561.py,sha256=pLObdKGOUwVgSGzmUJzIYrIZIWduhqX_vJVKmXju6o0,8092
+mypy/test/testpythoneval.py,sha256=up7D5qCYDylSAW5bX_dZYLxFmugXG1Tb3SP9sG-fu98,4583
+mypy/test/testreports.py,sha256=UR5hNxOajvtEYB-n5yTbaMk1IBKlYiAk7ASq2lGSALs,1756
+mypy/test/testsemanal.py,sha256=yJHfSyk3XD6bB0bZVSys3b-QTyDi4gGl8aWlrYFTnCc,6800
+mypy/test/testsolve.py,sha256=mrU2t9C1_NyFKsCDwJR5nw1xH2MOpd9zkWQsY5KCCFA,5284
+mypy/test/teststubgen.py,sha256=Cq6Nq0TVi1Guvwu6kgINXbQvrXW7yDHSklCWAxjya7g,53233
+mypy/test/teststubinfo.py,sha256=OMMxhXJ999NX0RXjni4SFIgLpGwJ7WA_AdNMJvlhRMg,368
+mypy/test/teststubtest.py,sha256=DBjeU4k8xPNFxbL9_l89e54sGrIUt3JgbdxlWurHynQ,64452
+mypy/test/testsubtypes.py,sha256=STzcfTUoXmPGBLzWnC4obJkks9mLa_tSIR36eR72GR8,14820
+mypy/test/testtransform.py,sha256=sBsLd_HeGIR-2JLZrYI0tOlgbHwed3oy1AQB6NGUiws,2316
+mypy/test/testtypegen.py,sha256=NKxbG4ZVzOVdKf848GKqbyoqWWj2ifCP3i3iAKCVQ5I,3153
+mypy/test/testtypes.py,sha256=NNAzXBZt4mLfDPOW8kqk9ObSlI2kyCTbI1OHnJjUknY,58237
+mypy/test/testutil.py,sha256=Ci60em4yJKe8rxFh2XqyRRDsxzdV2WzFA60xk08MWzw,629
+mypy/test/typefixture.py,sha256=KHghULAGiIqGIk46KYhcJEmPGEy13qZ4W6e7PBCwhmg,15401
+mypy/test/update_data.py,sha256=EEHotU9p5rij90Tvf0z4nXe3PDnHH01djlA6PKqDFX4,3676
+mypy/test/visitors.cpython-311-x86_64-linux-gnu.so,sha256=qW_2iX7x146majONsF53Z8HGLBcnPL7nuP-TNjbUc2A,8016
+mypy/test/visitors.py,sha256=cfsPawFO9J2UnoeZGzkYbAbZcuZ8HRDc1FKGd9SV1E0,2089
+mypy/traverser.cpython-311-x86_64-linux-gnu.so,sha256=IKc_xq03AHhwvK-JrxdbRJh1nf1I5nUPufUDpQQS9GE,8024
+mypy/traverser.py,sha256=Nyi59M7EbAHaginvcl5PsELd_d6lJz1UChChe2wUzOs,26849
+mypy/treetransform.cpython-311-x86_64-linux-gnu.so,sha256=EXyYqoYnfQpDBF5SEJYQXGNqy7H6LPiAmL9FFvBWyNA,8032
+mypy/treetransform.py,sha256=O5O9ikjl8WRWScxUEZnsGjOHJhN8HxduvToOBxpYi_E,28486
+mypy/tvar_scope.cpython-311-x86_64-linux-gnu.so,sha256=7c0TF2PZ7oyy5rkRUkr-QzN2hTATWuiwH41ylzWrDhM,8024
+mypy/tvar_scope.py,sha256=g-PrV-qvv8BPIni3S-VxRrH_nFoWhnMbTHjiqtxC7IE,5099
+mypy/type_visitor.cpython-311-x86_64-linux-gnu.so,sha256=xg-lJ27SX74wpCUC8HzgifUqrzUdZYPyHVPRXip8U0M,8024
+mypy/type_visitor.py,sha256=F2LfsDkSw8nwgTPfDQRBjri9t6Vecr3j5NsIk5nHDQA,18082
+mypy/typeanal.cpython-311-x86_64-linux-gnu.so,sha256=rFSzrSO1BQ10aH1jl4i0dM7psc2WWie0W8k8vRp3jKY,8016
+mypy/typeanal.py,sha256=TBff9tPRbgUduruonV_LdZZa3rYG73lxmg96LkhFRsA,88214
+mypy/typeops.cpython-311-x86_64-linux-gnu.so,sha256=9Eo6eQoEHg4YDtaEFIZYlbuTTWAY2LPLj6SbOJQXZmk,8016
+mypy/typeops.py,sha256=4Jb0ubetiBkPKK1gvepaWn72xK7mpRvQqbK3TKt9K9A,39890
+mypy/types.cpython-311-x86_64-linux-gnu.so,sha256=n40cGUMjhR_ZGLErbTLuENJUslI_VFk0D18AS5B38_M,8016
+mypy/types.py,sha256=qGBACrPl_PdLR9hqQYxSqQlim7xr6gPVKkL4TlWLyH8,123962
+mypy/types_utils.cpython-311-x86_64-linux-gnu.so,sha256=RPRwLnjbN3gL7u5v5vbcmnvBadtgbb_3NU7xH9I7BwM,8024
+mypy/types_utils.py,sha256=n89PKk9WOD2n2pStFMjR-xOwV1cso4nXacOINkpgjVA,5321
+mypy/typeshed/LICENSE,sha256=KV-FOMlK5cMEMwHPfP8chS2ranhqjd7kceBhtA1eyr4,12657
+mypy/typeshed/stdlib/VERSIONS,sha256=OUMkkkoMNtFYtgu7gzeGRmAO85xyt-OTVtFqPraq3bo,5254
+mypy/typeshed/stdlib/__future__.pyi,sha256=qIwWDmjaw3XCiulKYoKBQB_eJjLxweesUKwBdpkgQkU,915
+mypy/typeshed/stdlib/__main__.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63
+mypy/typeshed/stdlib/_ast.pyi,sha256=UkO9sK-xuEZ2vbQOh-5X8dTel68jm5KhdIZ_b5jOsKo,16037
+mypy/typeshed/stdlib/_bisect.pyi,sha256=FbUBdcUSPSGrnXSN89eA0gqCBVWMm8NlpxHKz6guO8Y,2651
+mypy/typeshed/stdlib/_bootlocale.pyi,sha256=vSVnoBvURsNzi7MPLR1b_wpuh-yySKzPValAwQ3OVT8,64
+mypy/typeshed/stdlib/_codecs.pyi,sha256=cOPe_Bh1vQjCTL6GnZwUKAQB3ItZFjfbCRqtanFoTh0,7280
+mypy/typeshed/stdlib/_collections_abc.pyi,sha256=I02Ck2dKVEiIVBcS1zHObCybRYEFnTy4qWhv7CI6gPg,2424
+mypy/typeshed/stdlib/_compat_pickle.pyi,sha256=sjo4_LT7N6KZgL68z0ojpak04NRsMN44bePUG2xDG9A,356
+mypy/typeshed/stdlib/_compression.pyi,sha256=hO1Jre9kkSh8zrie_PYuETpbGgJa4toWK7xbWWqVZSY,814
+mypy/typeshed/stdlib/_csv.pyi,sha256=EhO1CFf_BOCg21DGmbPb_5svCrGhTnr0nHHHN1oh3Cg,2499
+mypy/typeshed/stdlib/_ctypes.pyi,sha256=aN5SKHIuJ7RA1cWDxZrh6tUOo_zbmskRr23uS6j7Gkg,7494
+mypy/typeshed/stdlib/_curses.pyi,sha256=c_nTmCbxpfiRs7F6Q3CvjvfPDufBLeEim6bRJyZVt6I,17328
+mypy/typeshed/stdlib/_decimal.pyi,sha256=SPje3ceejvT7ff0EVtHeA9fNeU7EdznupLIczvkQl2w,13741
+mypy/typeshed/stdlib/_dummy_thread.pyi,sha256=Y4Ys6KdPlBoQ6n84SJjpRXhVE8_eqvFARVhP1dWls64,1046
+mypy/typeshed/stdlib/_dummy_threading.pyi,sha256=fp5j7Z6E5FYNvf3hlmEixnqFK8RfquAP27w8LM39BSg,5215
+mypy/typeshed/stdlib/_heapq.pyi,sha256=NvwWd6-ExFetJeTLKqMRUoxtfLoRtYbN4NnTo09pEqI,367
+mypy/typeshed/stdlib/_imp.pyi,sha256=arj7IyHTju0_cDEj-MNDTORMlwjCExmwxOyZlb-XjoU,1114
+mypy/typeshed/stdlib/_json.pyi,sha256=Bs258jyFiWHGFm0x6ydUm3fuxIVbTyufmAMkbAppHjs,1481
+mypy/typeshed/stdlib/_markupbase.pyi,sha256=WGSjv5DRDrdgbB7rtDQoeW2g3ZASHBUSZfF5l6PEx-Y,722
+mypy/typeshed/stdlib/_msi.pyi,sha256=xJElfKaJaWALQ7-GNJHadsDIYBvfTzbnjdew97AkULM,3225
+mypy/typeshed/stdlib/_operator.pyi,sha256=avbN1FurJvBb1mjmqa33VZXKqHy_tTGvmt204N0YY2o,6585
+mypy/typeshed/stdlib/_osx_support.pyi,sha256=FBwXcEZ0RiSBcJSnx4PcFDOZGtjTHR0fVtLbwqYMens,1996
+mypy/typeshed/stdlib/_posixsubprocess.pyi,sha256=2IvkhVM05N7TpXjrMa3ieaCovlqUc4UTOEsillGjHps,1009
+mypy/typeshed/stdlib/_py_abc.pyi,sha256=R0z0SRyolByTpUzBnKYU3R-Y9HgZsfYEiWGRdv0rFaY,402
+mypy/typeshed/stdlib/_pydecimal.pyi,sha256=ryisw8Pi3ne96GxJMFW5ViAgMqmc4PF4uJE53WP-f0M,895
+mypy/typeshed/stdlib/_random.pyi,sha256=_c80ak9c8eWe0WKY0aRBFPGD0WQeZ1U6Umkbor0Xx4g,405
+mypy/typeshed/stdlib/_sitebuiltins.pyi,sha256=r3FOOxK3-kK3OB8RHCdBRn8snHq-NqcZ7QazSqJ8nSw,547
+mypy/typeshed/stdlib/_socket.pyi,sha256=R9LTSG9QExmyb5OsWmJ_gOKH8hi-MHmTpmeziC1pAzg,19294
+mypy/typeshed/stdlib/_stat.pyi,sha256=RUXZ9AEbvpHbNj2VN-XYUre6HXu3O3vam1QBIqfKyVg,2944
+mypy/typeshed/stdlib/_thread.pyi,sha256=xGkM_K9C4YixwwrF-UBkD87ZJSVpCRgcAqHhnFEwUFM,1725
+mypy/typeshed/stdlib/_threading_local.pyi,sha256=ZThgVxdPOLAua_HHMoReeI3flStJ0qCnFaHYcEZyyBQ,516
+mypy/typeshed/stdlib/_tkinter.pyi,sha256=7DbOOjNoBxL1PbfxBbVFjL8BtrOm-JO94zh3BlR1UvQ,4382
+mypy/typeshed/stdlib/_tracemalloc.pyi,sha256=n3ZG2Dp8lSKm_pYV2vcx_rgal-izk1nSKhoBGky8J1A,546
+mypy/typeshed/stdlib/_typeshed/__init__.pyi,sha256=ORCajY7UFMF2oColRESbqD7rdDyNwkryuvOb2TQUYCk,10083
+mypy/typeshed/stdlib/_typeshed/dbapi.pyi,sha256=DeU6U1Pthzsff0fR8Edji3tY68uVwxtVFeP2cV2pfM4,1638
+mypy/typeshed/stdlib/_typeshed/wsgi.pyi,sha256=fN8hZBoc5Mh9K1AP7C2XbTGwk6ZI1mLjtJOy_s9BGoo,1633
+mypy/typeshed/stdlib/_typeshed/xml.pyi,sha256=ZsCZUHRN6hswgU32qOaxG4ODenZHxWSacH-4c_n2qI4,490
+mypy/typeshed/stdlib/_warnings.pyi,sha256=Esoyeo22Si1KfOPkjeyJZAmBs028j2SF94iZ9r12Jbw,1026
+mypy/typeshed/stdlib/_weakref.pyi,sha256=vEQNVQHp7eas3UurUURHXsmD9u7NYuPcn3GwwpUGoC4,1238
+mypy/typeshed/stdlib/_weakrefset.pyi,sha256=qV_rcSqhrQRAqhw_8IEym4p6l2v5dsfNzTmxxdIn6lc,2383
+mypy/typeshed/stdlib/_winapi.pyi,sha256=lojLoM-ldpmvv39M9JVG7gQsEzKEv1ViiKU7vLFG5Jg,9713
+mypy/typeshed/stdlib/abc.pyi,sha256=zq2uP3LvwhQ3NJmwc6AacCbC--yFLEiDJ-xLrVyyO2c,1773
+mypy/typeshed/stdlib/aifc.pyi,sha256=zFQeQmq0e5W02ZabrEqhX1wQJnwgUAs1igMQBA0nKWc,3354
+mypy/typeshed/stdlib/antigravity.pyi,sha256=AT_uMXdsZR3AL8NfPU7aH05CAQaYpiM7yv2pBm7F78k,123
+mypy/typeshed/stdlib/argparse.pyi,sha256=bW2w0EqqP9bLjh58ed0nf-1METj5NJ7qBrUbxbS1USg,21263
+mypy/typeshed/stdlib/array.pyi,sha256=NtKjh29IHQK5ZI_c81ACvymNB_qruhL7mDZEL6KzP-c,3843
+mypy/typeshed/stdlib/ast.pyi,sha256=dBSz38KsXrt1TOcc8mVXtFMbaWa7nbkPyzG268IJzqI,12061
+mypy/typeshed/stdlib/asynchat.pyi,sha256=jFTiOSXClcmhNvWXQc9JdRD44AT5o9Cq7xSC2fbVC2k,787
+mypy/typeshed/stdlib/asyncio/__init__.pyi,sha256=ZB6DIp0K2gi7TPowY-C6Ft5gfYQPJamVdSKU0AB3quM,1217
+mypy/typeshed/stdlib/asyncio/base_events.pyi,sha256=jfAglfLKzVbbRax4pTkeAmDcZ8sYOQ3K6DSrnfgOVCs,17307
+mypy/typeshed/stdlib/asyncio/base_futures.pyi,sha256=5D2qWnRrHaDRgvlRYZbjHp0vJeyIys7B7aWdi5cFkVo,748
+mypy/typeshed/stdlib/asyncio/base_subprocess.pyi,sha256=eAtCQYLCEDzV9YQ9nLzREGeiXNwVTzyHs4VSioJFpI4,2645
+mypy/typeshed/stdlib/asyncio/base_tasks.pyi,sha256=1qMENIsXTar5-dVXn33qy8hpWzOtFOs_I-kf5I92dsI,404
+mypy/typeshed/stdlib/asyncio/constants.pyi,sha256=Nh41DNlDLjA5bIOJo1nd717qr69XVctsfk2Ouqy0c8U,509
+mypy/typeshed/stdlib/asyncio/coroutines.pyi,sha256=27ayJdF53unjE6G1IYdqyQWHcomVQOr7Vo2ZcLkBeUU,1092
+mypy/typeshed/stdlib/asyncio/events.pyi,sha256=cEFhyf4H-u2MkSkqLO2YTs1nqGF8u8w92Kn4ivjpd2Y,23108
+mypy/typeshed/stdlib/asyncio/exceptions.pyi,sha256=bQiiiV49ZInjR0fIXInLq3J3mcIdt4huqVGWQZXZ-0I,1001
+mypy/typeshed/stdlib/asyncio/format_helpers.pyi,sha256=pqidJZJBMxN17PB9i3WKeAiZ7vbrfW-7b94xk53es28,887
+mypy/typeshed/stdlib/asyncio/futures.pyi,sha256=BbfbmNKNcEDLaL7Sv6x_ZV_UhFUiYeiFqcn9GIjmaxg,2644
+mypy/typeshed/stdlib/asyncio/locks.pyi,sha256=ZOIyhz6_JUWfWSdGVN9o2wPESFcqgSUIke_G2NztNXo,4072
+mypy/typeshed/stdlib/asyncio/log.pyi,sha256=Ql97njxNKmNn76c8-vomSAM7P-V14o-17SOIgG47V-U,39
+mypy/typeshed/stdlib/asyncio/mixins.pyi,sha256=YqQRvFzqgxJ0BvStd6F56A4DaIEM3KvD4fDELKCYhco,215
+mypy/typeshed/stdlib/asyncio/proactor_events.pyi,sha256=3KbenyD40hMRKWEb14IKEbVeI1TPabNY--dYG7GtEhE,2935
+mypy/typeshed/stdlib/asyncio/protocols.pyi,sha256=7ec4bMbkO0Xd05dsLFooOCp5rMwg8mNu2ePuvu3wiVk,1631
+mypy/typeshed/stdlib/asyncio/queues.pyi,sha256=kLR78xfdH_vpDLQ2VA_lyQYRMXxGVFafDAXIXkhA8Go,1270
+mypy/typeshed/stdlib/asyncio/runners.pyi,sha256=4JFKKIMuC-MVezGAj_Rhlr3ulQT2ko3CLGrylT8nDLU,1253
+mypy/typeshed/stdlib/asyncio/selector_events.pyi,sha256=V2A71DnovAWTNDBxU4kUlB6m2i4GvN7ZzzvTLOCIuXo,223
+mypy/typeshed/stdlib/asyncio/sslproto.pyi,sha256=3gzemOQMMRy93PQb1iUa8AC5OhSbT4G4b1c5BuxmNfY,6250
+mypy/typeshed/stdlib/asyncio/staggered.pyi,sha256=vtlD5Xfya4AEfvkwJmIL9zXXgRlsI8MmGOFitDK9h7g,341
+mypy/typeshed/stdlib/asyncio/streams.pyi,sha256=r4Qu1TN5l0TqdhnSYbYruYmhBUerD_ZxX4jU0GrQ42c,6258
+mypy/typeshed/stdlib/asyncio/subprocess.pyi,sha256=dy6b33TqSilxV9YVe6S-wvvizUb_6mOM5PF8zc6672o,9322
+mypy/typeshed/stdlib/asyncio/taskgroups.pyi,sha256=1x0xnS_Nks_2-7C6LEghD0IDCMvuX8dYMHfAU0kErww,588
+mypy/typeshed/stdlib/asyncio/tasks.pyi,sha256=q12YazFwW12ezuXo99Zpl0fRp8cnjYwpD0_P9ufsXOQ,13426
+mypy/typeshed/stdlib/asyncio/threads.pyi,sha256=f_9nq2fb0eZ8uUWY82DgtdBnEGeQStvQu0xXgp0TQ44,265
+mypy/typeshed/stdlib/asyncio/timeouts.pyi,sha256=4v2d55B807McvC3sClLAxH_3ckhI_I6YfFQ-yQjTXuQ,635
+mypy/typeshed/stdlib/asyncio/transports.pyi,sha256=8kLgFY7IK3nNPdq4eCaB61mVKui7juFEh2o47k2moXI,2040
+mypy/typeshed/stdlib/asyncio/trsock.pyi,sha256=pLt4Vb1eAcMb_-ZEAkjPxU4xWKrWqHjkqYYcbxKpKO4,4703
+mypy/typeshed/stdlib/asyncio/unix_events.pyi,sha256=MfSifWOxgYCV2r8laW4TD5Vvc91GzkUSDnngs6WyBL0,5720
+mypy/typeshed/stdlib/asyncio/windows_events.pyi,sha256=ltq1x9bnJvdR1s6tDAm65MekVo6c-XMaSbm-rJigBCE,3535
+mypy/typeshed/stdlib/asyncio/windows_utils.pyi,sha256=yvfgULt6CA8EAdsqL729VCpNvNKcufDYgGKPDCfMVY8,2273
+mypy/typeshed/stdlib/asyncore.pyi,sha256=CQ9U-vJyEFrR5-lCOstjFJQ62-tNUIzTc49mHr-ZIkY,3631
+mypy/typeshed/stdlib/atexit.pyi,sha256=WucU9TxdhsTUhdv4OarVmMtMikCo87HAjGiPCGiLZTY,392
+mypy/typeshed/stdlib/audioop.pyi,sha256=JJT_ftnNM_7YLIeILh1amX9N6kZLdf-BZyiSTl2K-TA,2141
+mypy/typeshed/stdlib/base64.pyi,sha256=tLy_2P5-_DIE25O_6fvHGwDx30iYwCVC5GvkVJ1cDws,2167
+mypy/typeshed/stdlib/bdb.pyi,sha256=-9DFKMIMH7sQXECANntIWsidN0rjeo6gpxHCziQAJCY,4610
+mypy/typeshed/stdlib/binascii.pyi,sha256=uvR4Sh6iymvu6B0A4xg7xx0KSAU6gI6xMHvipy4t-G0,1739
+mypy/typeshed/stdlib/binhex.pyi,sha256=l2tnH6FCXMiJrcwVrs6CiaaSa7IKG3MgHM1_YVevX7U,1279
+mypy/typeshed/stdlib/bisect.pyi,sha256=sQn9UUS0Cw5XZMEGcEj8Ka5VKPVobL43Pex_SagjXg8,67
+mypy/typeshed/stdlib/builtins.pyi,sha256=fs0nRaQJrtmtxfO1Rr9Bxc0_O8nbtMw0JQa63jC05hI,83882
+mypy/typeshed/stdlib/bz2.pyi,sha256=QBvgpFNVordw5CMD7owfjKXzW90Jl8YSRs9Ta7xgtrg,4870
+mypy/typeshed/stdlib/cProfile.pyi,sha256=5nIaAgaIqmedBRrfuEyen-mueYur_8W02bvQgHH9u1M,1538
+mypy/typeshed/stdlib/calendar.pyi,sha256=za-HIKKPGPWsVv5wm8aIv7H8LjYBAgQ9zQUwcSjJS-g,7323
+mypy/typeshed/stdlib/cgi.pyi,sha256=5BuEH5RV0EGQpWS7U6UtsXp3sz5aazYn7d6xDQs_UaI,4127
+mypy/typeshed/stdlib/cgitb.pyi,sha256=Yt0CBL6-EFUPMZuSq9xQV6d7GNrRPvyenS-sCDqfEzE,1423
+mypy/typeshed/stdlib/chunk.pyi,sha256=691YVfWjwx20ngjDSBGS5Pjs7IrLViQinuTBg8ddmX4,614
+mypy/typeshed/stdlib/cmath.pyi,sha256=wXsGj-URtKQALMlwtxC0Re9NZfjLvf3-I8rdsaO1Jmg,1326
+mypy/typeshed/stdlib/cmd.pyi,sha256=q2USCtjmDTP1gx-mwW96rQQNceWKB5y9wJV7gs_BEI0,1754
+mypy/typeshed/stdlib/code.pyi,sha256=bCi9Kmcv189tCNmJ0jawDbQKY34WAAC4zBdeghyRxlM,1481
+mypy/typeshed/stdlib/codecs.pyi,sha256=HEjBp9P2RJayV4KaOSjn-BJk1t_5qENKZsteE_-CyTc,12012
+mypy/typeshed/stdlib/codeop.pyi,sha256=BshEWu9RnM658m5FO9jt4flB20HIf80Ykr3sZrKxhT0,466
+mypy/typeshed/stdlib/collections/__init__.pyi,sha256=OAkjiCNcp4VliTWbAb9Y1aDCZw5DiEeM88HsuhL7k-s,20998
+mypy/typeshed/stdlib/collections/abc.pyi,sha256=kBiZAN0VPf8qpkInbjqKZRRe0PXrZ7jxNmCGs4o5UOc,79
+mypy/typeshed/stdlib/colorsys.pyi,sha256=o1mphr041ViW0Iw-diYI36c3wTP2D8x3KZ9oi2_SPoA,648
+mypy/typeshed/stdlib/compileall.pyi,sha256=lAWm30z1mTQLgJNGz6wEvAOFCVMZXN0ndey1sVt5elE,3438
+mypy/typeshed/stdlib/concurrent/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/concurrent/futures/__init__.pyi,sha256=8OswZuD6b09cWrtdIYRXwg-Gnr-2dx_4pdomGfNmBLQ,880
+mypy/typeshed/stdlib/concurrent/futures/_base.pyi,sha256=1XRrFcrM5wruEehiXR8S-_O2qUJqtPiHuf3lwnxHesQ,3614
+mypy/typeshed/stdlib/concurrent/futures/process.pyi,sha256=9xGIh9--Zpjb1uT9HmqCiTCcewunkIZ-1tXApJ1LlB8,6617
+mypy/typeshed/stdlib/concurrent/futures/thread.pyi,sha256=0SarSjF2vA3yqiS41VVbw4OGQzd_6zxVxuO-W-IeMjY,1749
+mypy/typeshed/stdlib/configparser.pyi,sha256=MvGrvzmJdRvLWpxW2DHbBV4z-rFNtD5iLVUzmopFiH4,11805
+mypy/typeshed/stdlib/contextlib.pyi,sha256=xGVqsLhVw67ZCwkDYiMzavLSjOj3sAKILAzUlx11hRE,8986
+mypy/typeshed/stdlib/contextvars.pyi,sha256=xzC9d8x2yrx_ZBhKM5DyYq8CF6ac3hCB7dtqmdKswsE,2044
+mypy/typeshed/stdlib/copy.pyi,sha256=iR27xJZfwjPi8T4sj3lynCv86Eo_b4Qfd6tD79Z17n0,350
+mypy/typeshed/stdlib/copyreg.pyi,sha256=59YPSECQJ5ppsEmYJxcvb1NOac6UTAu5CqP3SMd6VL4,983
+mypy/typeshed/stdlib/crypt.pyi,sha256=hIS4DwxYD1ocrl3s6uFffA5A2xX63YL73oHg8NH4NUg,383
+mypy/typeshed/stdlib/csv.pyi,sha256=N_sLlKIK5cqtNtkCbEVCgE3za5WDF3FwlZonNh8Kjmw,4577
+mypy/typeshed/stdlib/ctypes/__init__.pyi,sha256=yWWMIxC4zVx0O3shrE9FNU-JKqsjnkfouQLeAkGCRm0,6392
+mypy/typeshed/stdlib/ctypes/util.pyi,sha256=Lf_nOeoLmPYs5DJ00UmxbAlTex7Z8bwByM3bSg4wg1w,129
+mypy/typeshed/stdlib/ctypes/wintypes.pyi,sha256=3v7rBzxDxjRd6yKo0l34GYFEXEdU_r3O7P_88q1JRDU,5284
+mypy/typeshed/stdlib/curses/__init__.pyi,sha256=w2qNwsrgzVou78UsaLJGQKuQyQqb7oCtkMmmBvcLQNQ,573
+mypy/typeshed/stdlib/curses/ascii.pyi,sha256=6QYkjrJkj0h_zuFWKViJRxv5pAZ7sKR_Sd3EMLOuqEY,1393
+mypy/typeshed/stdlib/curses/has_key.pyi,sha256=1cQk4unAogRYYX0g6_1Q6Kbincq8V30kACec7zHeUZc,84
+mypy/typeshed/stdlib/curses/panel.pyi,sha256=YhKmDC4vSBMdHzpjKcWD_Hw7sDIqLr2Z5R_MA_egFyo,931
+mypy/typeshed/stdlib/curses/textpad.pyi,sha256=fUs_A09jazJOAta4pzdzwHY88mhxMoasV4uYkQaRa1M,514
+mypy/typeshed/stdlib/dataclasses.pyi,sha256=PGCqYmqCPs_99oqOGFZQa4691MBzz_BjZLT2GeSJtak,9397
+mypy/typeshed/stdlib/datetime.pyi,sha256=DGD0ODGx99Crz7RTv0_MLULcejetj_4Nc0TwR6bsuH4,11534
+mypy/typeshed/stdlib/dbm/__init__.pyi,sha256=OUefuueS01fdL_zcGVEoxWPlESkcgtHfxK5RUIeOby4,1762
+mypy/typeshed/stdlib/dbm/dumb.pyi,sha256=Jl40HJzDQL90nBJX5Gt-_RXqzqqsAUBrDf8FKq-aSPY,1287
+mypy/typeshed/stdlib/dbm/gnu.pyi,sha256=kh-w9ny1KS0Tj1DSNkiQv2pk-tcVYLf3UsXDwQu562o,1665
+mypy/typeshed/stdlib/dbm/ndbm.pyi,sha256=oMAr_PcWWvCWhc73DER9-DXyxBQqm0zCmDhIcEzXdC8,1451
+mypy/typeshed/stdlib/decimal.pyi,sha256=Ovcm6bcpLZyxOWrrmdnZkdYVVB4DRZzyJlKYVDyynmk,117
+mypy/typeshed/stdlib/difflib.pyi,sha256=XZ6VGIbRP6A2C2a0fJ7L6XqkLSRueVMB-ZJqvzRLwwU,4504
+mypy/typeshed/stdlib/dis.pyi,sha256=U4240SQsLz2T6G-EKUmDbxxR1p5UsZgZbbpKJG9-T20,4494
+mypy/typeshed/stdlib/distutils/__init__.pyi,sha256=o-D0LAC_8LmRTahqNjjRUXycRSMyJ537NHeFaduZKVc,351
+mypy/typeshed/stdlib/distutils/archive_util.pyi,sha256=MaH28V7MYRGIRO-t1fuXeqVfl9zeM-du9AiRUdDvMZQ,545
+mypy/typeshed/stdlib/distutils/bcppcompiler.pyi,sha256=fge2cMbG4jp--o0I2zNcwykh24tJWZtk6leQgAH2NJw,78
+mypy/typeshed/stdlib/distutils/ccompiler.pyi,sha256=PHtfphiyCzg-Rmn_2YV8Q3cX9x-Sgo-ameRm06Su4lA,6340
+mypy/typeshed/stdlib/distutils/cmd.pyi,sha256=crtZybjdq_hjrprEiPeTem_Co-ZvimnIdwUpknQ-0jE,2896
+mypy/typeshed/stdlib/distutils/command/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/distutils/command/bdist.pyi,sha256=AdLrhg0m_8Mj6qknF1ygbDdOUHC3EN5-yVdBsvK0iVk,540
+mypy/typeshed/stdlib/distutils/command/bdist_dumb.pyi,sha256=8QnGTsOKkYvgBHnflEcmI4VD-CTLUZD68d-ZvZM-vMc,450
+mypy/typeshed/stdlib/distutils/command/bdist_msi.pyi,sha256=-D04M4rDkMeVFhjtaOBqsISagr2GLzyNgv1IrFAvj8Q,1494
+mypy/typeshed/stdlib/distutils/command/bdist_packager.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/distutils/command/bdist_rpm.pyi,sha256=FddCkOBAFRN42HORJjs6QYs-TbECyhtmI1nIwbm58mM,1104
+mypy/typeshed/stdlib/distutils/command/bdist_wininst.pyi,sha256=Juj3Vb3fhsEVtNppLp4xmfGYgIP5VL23CP9UGziT8Sg,639
+mypy/typeshed/stdlib/distutils/command/build.pyi,sha256=BBENKWeYOUx87wVwVreSFz_7pAE2PRDuxQApH7GyxP4,711
+mypy/typeshed/stdlib/distutils/command/build_clib.pyi,sha256=SU1h7-fsfz_tsQMhvQh7ahYlfpq3tHhSmNjLO3Cuefg,668
+mypy/typeshed/stdlib/distutils/command/build_ext.pyi,sha256=JqiTAAQWy_th3ZGRpsf5zwVmvN4mnGx4hxHHpdtMIFM,1293
+mypy/typeshed/stdlib/distutils/command/build_py.pyi,sha256=VvmnDGrXs-iUxiFMFJhFz0hSvlZtjQZqGiRjIuehFOg,1442
+mypy/typeshed/stdlib/distutils/command/build_scripts.pyi,sha256=tG65N9cNLUcejDyGrpqbazEXgRnv3LPkSnJp10rlvCk,574
+mypy/typeshed/stdlib/distutils/command/check.pyi,sha256=4tsIp-xVK-HiMpcPYLUAMJju0RL1A6JTEVIZpQsv5qY,1092
+mypy/typeshed/stdlib/distutils/command/clean.pyi,sha256=voT57WZHfvCRRrAoZWwS8_RYcmBejf7HMIiE0omvDjo,377
+mypy/typeshed/stdlib/distutils/command/config.pyi,sha256=dxBf56elIwn4IyQW1Pth6hF6oKAyx5WhKIbwUzEqaWc,2679
+mypy/typeshed/stdlib/distutils/command/install.pyi,sha256=uEOlKn1k5mrci3Cn2TUjCGtPSq1qlAdlAaK2XnmSkVM,1689
+mypy/typeshed/stdlib/distutils/command/install_data.pyi,sha256=7icf2pxCX6WjLoXqQAzo0In50qVzQWhRmBUeVo4N6xM,436
+mypy/typeshed/stdlib/distutils/command/install_egg_info.pyi,sha256=BfFJ1Su5HgAXYwpvq8_1cPWO2gkiLho12YzNSmLRnAA,490
+mypy/typeshed/stdlib/distutils/command/install_headers.pyi,sha256=rT-1sQqlc8J2nqs_gf9RKmNBOorb5EAhC6qs8nUpfis,387
+mypy/typeshed/stdlib/distutils/command/install_lib.pyi,sha256=tHZ-f7Ulj7Z-K6tolL4Mtpa4jD9OmeG7-Kv5UU8QDq4,598
+mypy/typeshed/stdlib/distutils/command/install_scripts.pyi,sha256=okwcG_xRAomZj1zWLUHMhHoJpycTEMmgaI0ibbfNOeI,426
+mypy/typeshed/stdlib/distutils/command/register.pyi,sha256=KG_UraoJa6x0_iGya4WGQ3InY0RuuiqvQ1Sz5c5tW7E,570
+mypy/typeshed/stdlib/distutils/command/sdist.pyi,sha256=tJkV01XU2RKeqVvBWOtHk6d4kwPPFtoObcAX9Q0QHng,1118
+mypy/typeshed/stdlib/distutils/command/upload.pyi,sha256=TsjsCOSOxh4S4M_SonwMai2DG68WTyPeuymzmqtszeY,462
+mypy/typeshed/stdlib/distutils/config.pyi,sha256=Bmpm5-txSuUYd92XnDnfpAevSl9bk5YfXO-I_wXC2QI,497
+mypy/typeshed/stdlib/distutils/core.pyi,sha256=Pm-PZ9owP8e7Sr1d7xcRE0jUmHMGI8UmTgRmSENVgHE,1841
+mypy/typeshed/stdlib/distutils/cygwinccompiler.pyi,sha256=HylOkCpcmW32AHArKYyHMtW-KeEZQxSacYXbNFmUpak,545
+mypy/typeshed/stdlib/distutils/debug.pyi,sha256=MPYhYD0EJVkAAiL_6t7_Xfd2ctbMia2QEsy0D-HhLDY,19
+mypy/typeshed/stdlib/distutils/dep_util.pyi,sha256=TAeLwrEamwS67ykJBm8kV6fGy2a0FiY5RHnBqJOfYS4,224
+mypy/typeshed/stdlib/distutils/dir_util.pyi,sha256=gWjFQqveLrdnLvdd593ZEwZNhQdy8IaU4J8hG71BeZQ,510
+mypy/typeshed/stdlib/distutils/dist.pyi,sha256=MfmIPU7fERFXX8l0eKdp1xm2azC15EuYjrMgtORqwr0,5879
+mypy/typeshed/stdlib/distutils/errors.pyi,sha256=l1W_FgoP9L-D-hEPFA2BzZuybjN0lV4WBXl0VJ-k7J8,852
+mypy/typeshed/stdlib/distutils/extension.pyi,sha256=KosWjLSvvyfdQTtOCu3fibblHyiFIXm8iHHWrWk916E,1236
+mypy/typeshed/stdlib/distutils/fancy_getopt.pyi,sha256=XtlTxwRpJcDPvHrmyFH0_XFbty7r_NSc_4gdA71Oj_8,1162
+mypy/typeshed/stdlib/distutils/file_util.pyi,sha256=l7rfxgTQXO64_jYXB_uAtPHPd1DXzPpqChAq0Z5LeiI,429
+mypy/typeshed/stdlib/distutils/filelist.pyi,sha256=fQMPMvxrR3iolf9WvUJ8DpjI5oRCOo8Ka0RWO3mG-UI,2204
+mypy/typeshed/stdlib/distutils/log.pyi,sha256=SV3wrT_9-Emn66QuN6htDFVeEoc4hEaljLOPgIQp_G4,843
+mypy/typeshed/stdlib/distutils/msvccompiler.pyi,sha256=qQLr26msfhjz-omJutWcRHik3shLh1CIt7CDI3jBd3I,78
+mypy/typeshed/stdlib/distutils/spawn.pyi,sha256=oaH_dzZkyOOHR6a3EHZBFj9RxX540tNpMltTAI4ME3w,187
+mypy/typeshed/stdlib/distutils/sysconfig.pyi,sha256=XnioDAEApQhL01IeAc4upSe4w6DFmy-Xj-e4Fhl2cXU,791
+mypy/typeshed/stdlib/distutils/text_file.pyi,sha256=bWqk509MdjmhUI6QPk9mVpZ0QFBFPMdWEW62d5fMozs,682
+mypy/typeshed/stdlib/distutils/unixccompiler.pyi,sha256=R3VKldSfFPIPPIhygeq0KEphtTp0gxUzLoOHd0QoWW8,79
+mypy/typeshed/stdlib/distutils/util.pyi,sha256=AYZ0jqplKuhv-HajMLvcxzFmbw0t9TuGoGfb2wgN4gI,1626
+mypy/typeshed/stdlib/distutils/version.pyi,sha256=yIGp2uvie77qTBWlT2ffBGNXIKJmPfJLPzaE2zua1fc,1308
+mypy/typeshed/stdlib/doctest.pyi,sha256=BXWgrbqPB0yrRLHW0Pg9cyLFFBl0w-Fi4h1QivK2f6A,7290
+mypy/typeshed/stdlib/dummy_threading.pyi,sha256=ZI04ySfGgI8qdlogWtA8USUTFGfzm32t2ZxL5Ps53O8,79
+mypy/typeshed/stdlib/email/__init__.pyi,sha256=a--ccM_KLv044YhJ9UdgPBV4BDqr-m6axEsBnp4sMjs,1054
+mypy/typeshed/stdlib/email/_header_value_parser.pyi,sha256=6NhWVY3OMpvJE2_fuK1KuS0ZrebNzTT3DemEyYg4BOQ,11297
+mypy/typeshed/stdlib/email/base64mime.pyi,sha256=g98A7lvsErIaif8dVjP_LyoVFSXd6lNuJ_pOiTHudqs,559
+mypy/typeshed/stdlib/email/charset.pyi,sha256=frlG5m-R1INwR5fPy-VgM1H9VVy3ZVoOVETmU_zUkdc,1077
+mypy/typeshed/stdlib/email/contentmanager.pyi,sha256=UwmeUcRuRTCDHXVEDzDASBN4lEtVG1A9BonNaMmv0b8,480
+mypy/typeshed/stdlib/email/encoders.pyi,sha256=dJc5t6R6TtZGffzRC_ji2O2KNj9n_fJHzkAnKWTbfcQ,293
+mypy/typeshed/stdlib/email/errors.pyi,sha256=ynSYv-EvzwFIpxnJv6n0D_A33bbhMI9hAdM4qLmoWbk,1533
+mypy/typeshed/stdlib/email/feedparser.pyi,sha256=LZOzHbmFtOu_30OKdLks4IjpKapCqrx3d5uuMzTeYEM,965
+mypy/typeshed/stdlib/email/generator.pyi,sha256=m37jgKtezrebkOME2GhUtmQaX5rFXL7A8YGU8Vfrjtk,1175
+mypy/typeshed/stdlib/email/header.pyi,sha256=2Y72KRnu5SyQK6Vy_lcvw6VGIqXmMFMs8Jqn8SN0Vi0,1264
+mypy/typeshed/stdlib/email/headerregistry.pyi,sha256=8l_KnUirCw48LVSQOJodf9jLN9LlYz9ZWXm2-LLX1no,6228
+mypy/typeshed/stdlib/email/iterators.pyi,sha256=Vou7LSsfU52ckW-lKx4i49KGi0rd54LctjXHimRblrc,648
+mypy/typeshed/stdlib/email/message.pyi,sha256=di4WbQnhOZYaQCuhOoqquwxcvQEK981vViFQ2Gs9b08,6116
+mypy/typeshed/stdlib/email/mime/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/email/mime/application.pyi,sha256=PkqCQXJMdIRSXBV14unvCnpQTuNcEQO23W8CJ8hhtAc,498
+mypy/typeshed/stdlib/email/mime/audio.pyi,sha256=hsnNC5xAaI2pvS7DYMr58Y46U-hv4MjAKUF0wXWnDfs,482
+mypy/typeshed/stdlib/email/mime/base.pyi,sha256=zMUOzyzRFw00inwMFYk-GG8ap-SM9dtp1GRTxjfAiWU,271
+mypy/typeshed/stdlib/email/mime/image.pyi,sha256=E3zejA7f_g0NY09tvTj8y1jzGQ0IPrhsKDAofd6ZObA,482
+mypy/typeshed/stdlib/email/mime/message.pyi,sha256=obSuhQRP3v-8BeLonA8MWIuomlk7ywUcLEu5mVl6OMU,294
+mypy/typeshed/stdlib/email/mime/multipart.pyi,sha256=xeTg6yNg93HdN3OOIQk85d-nw8Rr-RW-kVH5kdwtDak,485
+mypy/typeshed/stdlib/email/mime/nonmultipart.pyi,sha256=YW7_zxIBEwStGGAuw7nQEYYS7Yz_TMuTW4-ZIFpIpM4,108
+mypy/typeshed/stdlib/email/mime/text.pyi,sha256=YQOSm74Bk8ngTj4y8PaucRTyxkREUT89UnBmVyyV6Z0,293
+mypy/typeshed/stdlib/email/parser.pyi,sha256=FWcbxX0V408Zabk1EPsJ2utlcbOcV-AGEUtPsdX9aj4,1328
+mypy/typeshed/stdlib/email/policy.pyi,sha256=nRRRJvFLfkVEVfuF_ilz8aXs0gWI4P0Unq15gyEe2nU,3088
+mypy/typeshed/stdlib/email/quoprimime.pyi,sha256=bSFnFlSadE1pXHmqDzvAEnWwNyeWSLm-i21Kczwrt6A,835
+mypy/typeshed/stdlib/email/utils.pyi,sha256=ffSYfN13dXu3i8mTSF7k9jR5HVRoSYj_s07w5OTPIqA,2312
+mypy/typeshed/stdlib/encodings/__init__.pyi,sha256=mjHeGjmXCdZHm-KK-XvpvSIf5rY8DOCyKZ_Ot-BJT30,309
+mypy/typeshed/stdlib/encodings/utf_8.pyi,sha256=pP3w9phIJOSOw_8I6o2BttSVIiuk8snVD3983_ZpJmE,904
+mypy/typeshed/stdlib/encodings/utf_8_sig.pyi,sha256=CAvKrplGLrXKmpdEW4-PjihiA5UICRtcD8YaJX5dhiM,1059
+mypy/typeshed/stdlib/ensurepip/__init__.pyi,sha256=8tmoDM1Cy7ojGznNaYzp_-zzoTYP_FunKhPvKpsVU4I,264
+mypy/typeshed/stdlib/enum.pyi,sha256=pXweoXrBDJIaxm7Ec_7601w9lEaCFQSM6lEPJRTbIv8,10833
+mypy/typeshed/stdlib/errno.pyi,sha256=vQQB9ZjEpks2rsFIMBj-XVlepslb3q2D3F512wklonw,3911
+mypy/typeshed/stdlib/faulthandler.pyi,sha256=jn6gMdF0GEZljfFTc1splgef8zIo99X1H44qgWxU8sE,644
+mypy/typeshed/stdlib/fcntl.pyi,sha256=rd6Ni82C7Y6JWDLayu0e6OtsXVUMiHnhNGFwQA6DRH0,3780
+mypy/typeshed/stdlib/filecmp.pyi,sha256=TuGPwCEY_P9IbAqJou_C3nDEUjyeY1uD6Mn3rMdvc84,1965
+mypy/typeshed/stdlib/fileinput.pyi,sha256=PDLWh7pnyb3NHAWu4k2Bpf1P8WBcXrWVq-67F54SaLU,11114
+mypy/typeshed/stdlib/fnmatch.pyi,sha256=BdxrklLHztHBzg2Ob26Q0axULmgd-Z82xRNvY9hh_5Y,339
+mypy/typeshed/stdlib/formatter.pyi,sha256=PoCFa7jJ7efz-ZO-IJU73MK_O9t7mjbYwjxBaSppqpU,3711
+mypy/typeshed/stdlib/fractions.pyi,sha256=xlRbpQ1KH1kGp3CX9ZDeUWd_YCpdKlHq_f2OOHBwGag,5592
+mypy/typeshed/stdlib/ftplib.pyi,sha256=Fh9Hnm70VfMWUMtOCL_j8QvJiAlPcIt8xpyLseAhcNk,6484
+mypy/typeshed/stdlib/functools.pyi,sha256=KQFoCundZqP7F3YXTrvlzxrI94iseN09-ECElq0c31A,7816
+mypy/typeshed/stdlib/gc.pyi,sha256=tTSNtCeCKrD7mmE_zSCsrOJw94MwcTuzd1Z6jzg73pw,1281
+mypy/typeshed/stdlib/genericpath.pyi,sha256=UNRas_1vatwqaaAK5IheDBI-nnc-49M2Z2jpm55uj70,1756
+mypy/typeshed/stdlib/getopt.pyi,sha256=-4KTGgePwlf-_mHrgy5uxrJb0l8UxM0zBNCfrHqz_70,439
+mypy/typeshed/stdlib/getpass.pyi,sha256=HHVTCLX2MOEjVm1Hhf8l1SHi0S3kAUBWcT0dHy27wZ8,227
+mypy/typeshed/stdlib/gettext.pyi,sha256=Bbz7_j5bo-FlYKaf-uugLh47gQ54UyvQjMRGFzBvxXk,6274
+mypy/typeshed/stdlib/glob.pyi,sha256=sjh3z3zHQ-yG9qh7RJpMwakq1y5XOhnHoXqCw_w1B6I,1421
+mypy/typeshed/stdlib/graphlib.pyi,sha256=pAiBbKU2aBWlIpq53Fksc9FISuDjn80fZUqn_C37J-U,914
+mypy/typeshed/stdlib/grp.pyi,sha256=zHteSa6HGgfqdSEmSDpu3dIR3PoM8_XAeI-FJd-rHF8,730
+mypy/typeshed/stdlib/gzip.pyi,sha256=ipwZrl88c9D-33hcEys4KZNYrX0UZ98wYl9bsNqdkIg,5068
+mypy/typeshed/stdlib/hashlib.pyi,sha256=-pXm5zweb3zYsxAZtzkYmleuRSaVHVfO6yKCF8w4CfU,5551
+mypy/typeshed/stdlib/heapq.pyi,sha256=Gwenj3-2NvVdRP_SvN65F1AJItQ4tKRY1h3wZQdIoos,788
+mypy/typeshed/stdlib/hmac.pyi,sha256=ZyB9PlM7ECKYQlxicC6pzy7YDPxtwE15ByGyOMbhgeM,1747
+mypy/typeshed/stdlib/html/__init__.pyi,sha256=TKNt2K9D-oAvCTmt9_EtgRndcpb--8rawxYFMPHTSC0,157
+mypy/typeshed/stdlib/html/entities.pyi,sha256=h-6Ku1fpOhkthtjVMXLTkVwKmc-yZwY4hZN3GkaLaMg,182
+mypy/typeshed/stdlib/html/parser.pyi,sha256=DpUIH4HLOZc9J3VyIrHf8JDwoN11H7lFpbaJZdboeaQ,1714
+mypy/typeshed/stdlib/http/__init__.pyi,sha256=gXJf8CiYayBaKwPBiy7J_MwJs7dCNL8B-CBIQjBKOPo,2724
+mypy/typeshed/stdlib/http/client.pyi,sha256=lwJ9r-CClACqoKK_qD-KNMnxw0hseDFoX28E40llNrg,6988
+mypy/typeshed/stdlib/http/cookiejar.pyi,sha256=MLr8jbOYo6luufRHy9Js07t7nPtGGZniIiyvYiTTB44,7628
+mypy/typeshed/stdlib/http/cookies.pyi,sha256=p_Z4HI5SkgS4__gdFS7GmC-e9Fx3Q92jKRlgqCP-KJQ,2301
+mypy/typeshed/stdlib/http/server.pyi,sha256=n0oVq9-9cU2lMZTs09tle0-4i7VSF7LpiW9L5fyFIn0,3450
+mypy/typeshed/stdlib/imaplib.pyi,sha256=qJ7bHJOwJZI7g3QrVqqnkUMP0wYdU5lj9pMBMD5kwCE,7609
+mypy/typeshed/stdlib/imghdr.pyi,sha256=zKdymGE7sXhMhNoes35IgaOiDRmDvYcmpv7rAIoIPdg,501
+mypy/typeshed/stdlib/imp.pyi,sha256=2jpRVeGOQyYOD_vD4qhkWSJ6pNkJyIya9OGdETLxPgA,2380
+mypy/typeshed/stdlib/importlib/__init__.pyi,sha256=k-6tW7wJF4HqK0xDFELd6d6NX2aOFLDSd57VvXoeGRQ,801
+mypy/typeshed/stdlib/importlib/abc.pyi,sha256=LvPnzU9X13MO9GJQK2gICVcqSeshuVVXhKV0SrTnDD8,7380
+mypy/typeshed/stdlib/importlib/machinery.pyi,sha256=2NZcNnqwt5TEHBAeIgDkFx0NFH36SThb6RzdlY22_B0,5621
+mypy/typeshed/stdlib/importlib/metadata/__init__.pyi,sha256=rkIq-B7_A9wD7fLvX4VOMsabayPrttdBXhFlEhBBpUA,6736
+mypy/typeshed/stdlib/importlib/metadata/_meta.pyi,sha256=K-a2f2ioc65l14fT9pj9r3hxhggoJDpebXR9EwXF_6Q,842
+mypy/typeshed/stdlib/importlib/resources/__init__.pyi,sha256=EnOIG5c5szMg0-QlLeLP9Rt_5Y_gkZqeWPhTpE-3-pM,1515
+mypy/typeshed/stdlib/importlib/resources/abc.pyi,sha256=uLq0IrUI45F5H19i5EhQvTQV34jW-ffft_W5_cJ_iTM,476
+mypy/typeshed/stdlib/importlib/util.pyi,sha256=imUe5o1FYHnEVtvdjasg62NPo6VPMBocBAgeQGvZr_s,1769
+mypy/typeshed/stdlib/inspect.pyi,sha256=f6sjYomDIAjg5iEnS-a7gvwk3dfDe0nQcdy23L01dhk,21322
+mypy/typeshed/stdlib/io.pyi,sha256=C0GtJPqkmsIODIwNC_Ij_33ozo6kT-AeOkossfNjBU0,7875
+mypy/typeshed/stdlib/ipaddress.pyi,sha256=5R_io7ROd8CJ-AQTsCr9CAHEDhxURyaERGqU6diT4HE,7052
+mypy/typeshed/stdlib/itertools.pyi,sha256=_Jqfl_fuQicY0eiCAKlFzC1FLIDSVeZFzFj29aMK8dc,10920
+mypy/typeshed/stdlib/json/__init__.pyi,sha256=stSGpZp2CXo0E3iPmVdjpzvFdKPlNj3kWhc2hrFrdwM,2374
+mypy/typeshed/stdlib/json/decoder.pyi,sha256=XdU0nhYShlWZbSXpxGdsgurtM3S_l0C9mDYCV9Tfaik,1117
+mypy/typeshed/stdlib/json/encoder.pyi,sha256=DFPWZRLUTpXXmBpD712DgBqeEsaqplsFo1B0_sse8H8,1073
+mypy/typeshed/stdlib/json/tool.pyi,sha256=d4f22QGwpb1ZtDk-1Sn72ftvo4incC5E2JAikmjzfJI,24
+mypy/typeshed/stdlib/keyword.pyi,sha256=tMj4zQZ8F6WE8NyF1oJXtSofryQGDX-BAm-gnXBTGn0,576
+mypy/typeshed/stdlib/lib2to3/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/lib2to3/btm_matcher.pyi,sha256=zWMSDahNavhi40hkU1rK-3lPsSgvlsDJtwhQfqAlmSU,860
+mypy/typeshed/stdlib/lib2to3/fixer_base.pyi,sha256=LeWkZHLIWJdjampO-OjBzs-tjM8tFTmzirpb9BQ3B6w,1722
+mypy/typeshed/stdlib/lib2to3/fixes/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/lib2to3/fixes/fix_apply.pyi,sha256=fMwyUW7M8pNtX5jsjxOBXuh4gCCOQwrYH2fNFaQK7Fw,244
+mypy/typeshed/stdlib/lib2to3/fixes/fix_asserts.pyi,sha256=E8PjT1AHkF_vKPPdAFtvgO3dclTC8YjbqnV9P7plCN4,274
+mypy/typeshed/stdlib/lib2to3/fixes/fix_basestring.pyi,sha256=sHleX1PbQPoMim8CNtnqcea4eiVGIhRUmNGZZ7r5epw,269
+mypy/typeshed/stdlib/lib2to3/fixes/fix_buffer.pyi,sha256=K80GV8ziMMziiuuuFUBQDHu5Yas7Wd2WoXTRg62PNuY,253
+mypy/typeshed/stdlib/lib2to3/fixes/fix_dict.pyi,sha256=Qrd1EoXh5UhfzdXgB1Wds-57qV24Ahh5Gpz9nSp1m40,453
+mypy/typeshed/stdlib/lib2to3/fixes/fix_except.pyi,sha256=waLonSperau9qZnZXk3WdudZkCl9_Nu_AnAoWYtZu8Q,444
+mypy/typeshed/stdlib/lib2to3/fixes/fix_exec.pyi,sha256=fvSzFTx0oelJQfWkz92JI3ch0aawMHbBhrQIZvWntOU,243
+mypy/typeshed/stdlib/lib2to3/fixes/fix_execfile.pyi,sha256=WLLKgPe3DLdf3_iyeixCnEzwua4GidrBf92EtPCRyNg,247
+mypy/typeshed/stdlib/lib2to3/fixes/fix_exitfunc.pyi,sha256=T94Ss9lrrJhKL7OJQe3y6zC_T9FhyqCdKnCBE7rNPaw,474
+mypy/typeshed/stdlib/lib2to3/fixes/fix_filter.pyi,sha256=cUIaI8lXGcaRr7M2TxMvuNPjV0yLWh1Rd_CRp71RNsQ,309
+mypy/typeshed/stdlib/lib2to3/fixes/fix_funcattrs.pyi,sha256=wpNVS7qiCfOa-ntH1Xn_vmdtKREQxFdtMc3lwPyJw2E,256
+mypy/typeshed/stdlib/lib2to3/fixes/fix_future.pyi,sha256=VzKv4eBNNA9yHxMpUmXy1enJhhWfsiZDzCEDtTnJocw,245
+mypy/typeshed/stdlib/lib2to3/fixes/fix_getcwdu.pyi,sha256=s8r0T5SH32FFLeFqKhLROljaM0tTe5WqWkhNCJg7SjY,254
+mypy/typeshed/stdlib/lib2to3/fixes/fix_has_key.pyi,sha256=U89OcromnfM6Xznu53mowROUNG0WhgYaQcj8Yk399C4,245
+mypy/typeshed/stdlib/lib2to3/fixes/fix_idioms.pyi,sha256=9Km3gsJ2egZ_V1wUnxyA15BVyCN1ngNrAfRY93YQlvI,467
+mypy/typeshed/stdlib/lib2to3/fixes/fix_import.pyi,sha256=v4kcca0ESMyQTWq_t3zVzJ2nT1EwQ6DSQUJAeyb29Kc,536
+mypy/typeshed/stdlib/lib2to3/fixes/fix_imports.pyi,sha256=Zs69-jLRHCH93Hp2MyuPDuZk-p4q8NoFfUk3aZbWFS0,668
+mypy/typeshed/stdlib/lib2to3/fixes/fix_imports2.pyi,sha256=pzGySeACcI5dKnjkxYjQniR1_b2tb9Scnim3p4xZaxY,117
+mypy/typeshed/stdlib/lib2to3/fixes/fix_input.pyi,sha256=tHVWYMRwlfKTZJF42KLHZ7GCi5N1-UFShIcjPeW_xvc,298
+mypy/typeshed/stdlib/lib2to3/fixes/fix_intern.pyi,sha256=VRTpFS__Y1ATU6FW71Iy6Tzc7XVz9D4rFnmSjXYGYsY,281
+mypy/typeshed/stdlib/lib2to3/fixes/fix_isinstance.pyi,sha256=__drE1gI79IudseaaKLhYyxS_hdVHAJWEZGJepvnqHk,257
+mypy/typeshed/stdlib/lib2to3/fixes/fix_itertools.pyi,sha256=VgbVFWHLCWvtuvd4gk1dVwcl_8q-6UV-Q97_Z26xbNE,274
+mypy/typeshed/stdlib/lib2to3/fixes/fix_itertools_imports.pyi,sha256=aTParR-cgGVHB8E6Ls3S-FwjMjvr9fqJkhgJ9PEYkIY,259
+mypy/typeshed/stdlib/lib2to3/fixes/fix_long.pyi,sha256=hwk6vJ3ATD3bEULIiHR9SrfBg3Ymz1zS50EICcdGxQw,269
+mypy/typeshed/stdlib/lib2to3/fixes/fix_map.pyi,sha256=b26jZyZrMl8PY1PUjyWl85Ea-Kg85g0xmGhR65VNOpk,303
+mypy/typeshed/stdlib/lib2to3/fixes/fix_metaclass.pyi,sha256=Ux8QCZdYcYyXaWYMNF58LsGIkROO0nHx4f2G1nex2yo,616
+mypy/typeshed/stdlib/lib2to3/fixes/fix_methodattrs.pyi,sha256=iNl6xU9hwP_IUi8FZAEdVH9pmjeT3r9L0u8wsMX6orc,279
+mypy/typeshed/stdlib/lib2to3/fixes/fix_ne.pyi,sha256=5BdSijTtOciULlXEr0ifqQslbaJQA6aQSlOhIajvwQM,246
+mypy/typeshed/stdlib/lib2to3/fixes/fix_next.pyi,sha256=mSMyIwsro09GMIgLjQfG4Wa-g_ZIU7sC3U0_v1e1Pdg,547
+mypy/typeshed/stdlib/lib2to3/fixes/fix_nonzero.pyi,sha256=gOYlqMr3QVHiFnZWmP2sMJfOLsAYkPiYhwF8afXC1l8,254
+mypy/typeshed/stdlib/lib2to3/fixes/fix_numliterals.pyi,sha256=XVmq4JjqU6ECsqEtC-pzb3YzYReb3iA5gKZIDsas-Kc,255
+mypy/typeshed/stdlib/lib2to3/fixes/fix_operator.pyi,sha256=RafNpVfcOuMmJ0aMLWRaep3HTFlKsC_LFRhfta-gdq4,341
+mypy/typeshed/stdlib/lib2to3/fixes/fix_paren.pyi,sha256=FwfM-6nRRnuVjY_Cp4JC5o6YhFzpDCZMEINylw6Xz6I,252
+mypy/typeshed/stdlib/lib2to3/fixes/fix_print.pyi,sha256=tBgB1zWSdovU4q3zYSQmUhnouaaY5O1WbzmP3sAwVSk,363
+mypy/typeshed/stdlib/lib2to3/fixes/fix_raise.pyi,sha256=MTDB5qFflcqSNrsG5ZJRA7ZneGYeuVDWZtLxnBIT2VU,244
+mypy/typeshed/stdlib/lib2to3/fixes/fix_raw_input.pyi,sha256=pVVF8YEBD9W0YBJ8Awm4-WPbmGRjM5AHoHl0VMmfrPk,255
+mypy/typeshed/stdlib/lib2to3/fixes/fix_reduce.pyi,sha256=9ek2-PH8ImOmdewvFdyPfS5YlEpLQ7AxA96Q39Ae13o,293
+mypy/typeshed/stdlib/lib2to3/fixes/fix_reload.pyi,sha256=EDwHdKE_r8jYesybzPCpR5N_zdfiiuZ-YKg0yTCCW-s,281
+mypy/typeshed/stdlib/lib2to3/fixes/fix_renames.pyi,sha256=X23XjhnLgYSDdSYJLVc-4dL7xVBsu7uRkMlTpiOjivM,515
+mypy/typeshed/stdlib/lib2to3/fixes/fix_repr.pyi,sha256=PArHIegabn3u3_RS9TKMwIc2AKLWiZXGKDDhWcdqk80,243
+mypy/typeshed/stdlib/lib2to3/fixes/fix_set_literal.pyi,sha256=HPkiRIj6NDVqb7h0MBBsEJnoH1hYN5C0rSWKmP51ysc,253
+mypy/typeshed/stdlib/lib2to3/fixes/fix_standarderror.pyi,sha256=HCaqBbCEhaOjE-mYjpglgjxzbQS2-Y0DkdVO6O3MhfU,252
+mypy/typeshed/stdlib/lib2to3/fixes/fix_sys_exc.pyi,sha256=VErzcgJ2H9APFKsJ3YdPZN8wmDjlZgjPfsPwXizf_L8,279
+mypy/typeshed/stdlib/lib2to3/fixes/fix_throw.pyi,sha256=bch-j5etGJ_CoibmQdAGzeXPBp0MUN3m3bQna6vjK7A,252
+mypy/typeshed/stdlib/lib2to3/fixes/fix_tuple_params.pyi,sha256=uKdcVzeKZwildQvhp4oUIG_VVKoiU8oXHrBeGY6V9No,534
+mypy/typeshed/stdlib/lib2to3/fixes/fix_types.pyi,sha256=dnZVek0XD6uZHI-mYLftaBaQPm26aMI2DF72wh4429Y,244
+mypy/typeshed/stdlib/lib2to3/fixes/fix_unicode.pyi,sha256=9k0MhheVdShwzv3Eyv07MZw9RgPAwQBNxYs6gXeu2sc,497
+mypy/typeshed/stdlib/lib2to3/fixes/fix_urllib.pyi,sha256=sV7M68z03O3vvwuqSUPLx1NKMpt4E78nBmltA83gif8,553
+mypy/typeshed/stdlib/lib2to3/fixes/fix_ws_comma.pyi,sha256=wsFjaaDkheetk0lJN2QDJ-ZyFF4durul2Wd8g4-6wCQ,333
+mypy/typeshed/stdlib/lib2to3/fixes/fix_xrange.pyi,sha256=8vXa2s9ME7wQ831LwX-4n1OJV1l_0P7yq4oOsO5n-jg,755
+mypy/typeshed/stdlib/lib2to3/fixes/fix_xreadlines.pyi,sha256=MWrTb-ZbLcISSHGVU__wg3g64K6PkHcoKJoeDKQi-XM,257
+mypy/typeshed/stdlib/lib2to3/fixes/fix_zip.pyi,sha256=Box7R_l6R_V3WBi2G-YVSc1LViMxiXStJRRoiVzuRUc,303
+mypy/typeshed/stdlib/lib2to3/main.pyi,sha256=iuGAaZ5uQe5lmVOQ3L6kFlEcb7VPSE0KuCA7dD5QmVc,1561
+mypy/typeshed/stdlib/lib2to3/pgen2/__init__.pyi,sha256=J1r7O6-RC55RX9XuIU4QcT8sm-7ySY0eowiibNJz0kE,287
+mypy/typeshed/stdlib/lib2to3/pgen2/driver.pyi,sha256=PNvewWFDcgWCmmEwYEKtBrKrHkukMZqkryr6WauQZ1w,1067
+mypy/typeshed/stdlib/lib2to3/pgen2/grammar.pyi,sha256=dG17yFsbtkiDsvKCyWRZvc0zmaCLF83m_naTZzUziRU,682
+mypy/typeshed/stdlib/lib2to3/pgen2/literals.pyi,sha256=TtrXnXJiXUTSBXIP_3hJUoKM2h_rSNg5aTqQcL5tZIc,151
+mypy/typeshed/stdlib/lib2to3/pgen2/parse.pyi,sha256=dSjInOriPq4H6YhXCvsW0lUeCZKMV81mYmYc9ZbEh4Y,1133
+mypy/typeshed/stdlib/lib2to3/pgen2/pgen.pyi,sha256=YwRE2n1QaIFGzAxDqUnI_83kLPg8rNZ1VRP87IINFXc,2206
+mypy/typeshed/stdlib/lib2to3/pgen2/token.pyi,sha256=k1QtetXMmv43tbZLjQ_sYeIQ49aqe7yL4dC_mI_HRkw,958
+mypy/typeshed/stdlib/lib2to3/pgen2/tokenize.pyi,sha256=mdjbHoIgTIFWGaGKpky1FqxpY6Ugih514SvAlNUT-8k,1972
+mypy/typeshed/stdlib/lib2to3/pygram.pyi,sha256=3BvaX2_4NJpKlneYuai6Q9KSavCUVpCRY7yCgfhDkG4,2300
+mypy/typeshed/stdlib/lib2to3/pytree.pyi,sha256=pmZAhOwiYJ0TavdEUB1cFdfmaaDIoPfcq3gk97dLLww,4100
+mypy/typeshed/stdlib/lib2to3/refactor.pyi,sha256=Ycijp2PcLpoUPLQtePFKgzSy64-A9vdO9KUm6G8iO_U,3975
+mypy/typeshed/stdlib/linecache.pyi,sha256=H3c8IE4fcSOi88r-ydi7PPQ0eSdLIlhD9VZmfhkIvKE,945
+mypy/typeshed/stdlib/locale.pyi,sha256=Zwj6M5_lHO2C-1SOO4Bdv6z1olKPVTKR0cSztbYU2Xk,3819
+mypy/typeshed/stdlib/logging/__init__.pyi,sha256=eVmMFQUcRl9TqJaJSeHabykK4t5b1wgKL_Zwk6XWLtQ,27009
+mypy/typeshed/stdlib/logging/config.pyi,sha256=s438xN7uHUvkjCbyiGoM3-hwHmn5QPqOFVNQjIGZbNc,6063
+mypy/typeshed/stdlib/logging/handlers.pyi,sha256=PVzD_jXDS79YT4jh85Pdce_CmQ38PGT0gl4BpzXyXts,9534
+mypy/typeshed/stdlib/lzma.pyi,sha256=0gH1o9lG0Vup2EN0V7Hr9bUn43cZjHC5LIC-lSmpI9U,5323
+mypy/typeshed/stdlib/macpath.pyi,sha256=T1F0CQemy12Qp0VR-ffx23KKc0tUnZSaTa7glIHMmM0,2405
+mypy/typeshed/stdlib/mailbox.pyi,sha256=6OxWyPRlCIouPkW_f-0rCiDvS3Bpt51engIGFV1DL0I,10459
+mypy/typeshed/stdlib/mailcap.pyi,sha256=h3wCqy9SD2DA8-aB5k7vW17ShyhlL-AZV6iYKpRTyP4,388
+mypy/typeshed/stdlib/marshal.pyi,sha256=vhtCdF0NOC0aFkBtigcLPfFQfutGsm7_n367POUooz4,841
+mypy/typeshed/stdlib/math.pyi,sha256=E7yJZAhnJFBRn6SRdlZLmNmz0bYxmPp9SExtAt_k0aU,5295
+mypy/typeshed/stdlib/mimetypes.pyi,sha256=5zlCIfTn4q5telJgsb4wTceOtiP9SyD8ZYEVW8xBXzM,1998
+mypy/typeshed/stdlib/mmap.pyi,sha256=iaz2-GAPO6p5ZKwV3Ugm-wzd_eRetPti5VfnLf6SGe4,4135
+mypy/typeshed/stdlib/modulefinder.pyi,sha256=y58n3BJ8sPSB4j4R5XWfElNav27UJcf4ry4zvnSe2dA,3604
+mypy/typeshed/stdlib/msilib/__init__.pyi,sha256=kM9w94mBqf1zFRjVy0dQWovjSHvUdG5916uhZKVbpFA,5881
+mypy/typeshed/stdlib/msilib/schema.pyi,sha256=hRHjm9DavaKkp9xDvvtbMaYjuRkOaPouAiUp9YGvPHU,2141
+mypy/typeshed/stdlib/msilib/sequence.pyi,sha256=Kr3fzhLlB_ejF3yzrW6G0U709ejvr7g1B2IwBZgtczE,362
+mypy/typeshed/stdlib/msilib/text.pyi,sha256=gj20tE12dECwfdxJt4gqIsfSJcc6VY_BVuDesFqUxOE,154
+mypy/typeshed/stdlib/msvcrt.pyi,sha256=1Kdi3IfdtyhtoKvbOZ3sBO-4KhlXmk7xGvYhhR2ntZg,995
+mypy/typeshed/stdlib/multiprocessing/__init__.pyi,sha256=kbXttawGSBDTJzrovepJLfHZYKfm4siac-c-kjPMf5U,3241
+mypy/typeshed/stdlib/multiprocessing/connection.pyi,sha256=WFMXLGxGqsrsUhdHGHZwgpSXTB4FImH9y3cNwF_jgi0,2934
+mypy/typeshed/stdlib/multiprocessing/context.pyi,sha256=-KX1nm2HA0BM9-ZGGD3qvC7H0QHd3YsB8McG83O-NTA,7970
+mypy/typeshed/stdlib/multiprocessing/dummy/__init__.pyi,sha256=zIF0EveYbA3TfaqugU39MWFZbcBiikyM-Uqg_I78oko,1964
+mypy/typeshed/stdlib/multiprocessing/dummy/connection.pyi,sha256=WNsr78HeHz67VG14qLrc6xUkFNQkKt18jw95amhFBQg,1282
+mypy/typeshed/stdlib/multiprocessing/forkserver.pyi,sha256=S_67nMlJq7QCV2XLHPoqy6k4C_OAdcxpa_Z9JKPm-nw,1058
+mypy/typeshed/stdlib/multiprocessing/heap.pyi,sha256=UdBz1JsRfJdZMGAi5fdcWy1LUhCNLKJhC5EddcKI1cc,1046
+mypy/typeshed/stdlib/multiprocessing/managers.pyi,sha256=bxI0XtL88ovb91wzqFC71f1q7RMpjHjEWJRAx3bBmuU,8859
+mypy/typeshed/stdlib/multiprocessing/pool.pyi,sha256=B0f6vdrtjMP7uGfPnq8H87l33AGhcHDiWk2_RksCmG0,4751
+mypy/typeshed/stdlib/multiprocessing/popen_fork.pyi,sha256=mheawsbB0-LZ2gJmYvsMhCt06yXWCtg8tClPJJNKJ0Y,724
+mypy/typeshed/stdlib/multiprocessing/popen_forkserver.pyi,sha256=-f851cHQEbM_L9oXaw6PrUHI6bKAVasRR17OirOSd60,353
+mypy/typeshed/stdlib/multiprocessing/popen_spawn_posix.pyi,sha256=kuKZmJxw4id8R5dTTp-B7E-5qDWTSexAOkCqStEMoKo,524
+mypy/typeshed/stdlib/multiprocessing/popen_spawn_win32.pyi,sha256=t-0UShNiEUqeKfLEEt7tRM8eF1iRaxdaFKP_c0TXDNc,738
+mypy/typeshed/stdlib/multiprocessing/process.pyi,sha256=Oi25pZLuhmaOVdTjOxbBWl4uZdUFwLvMiirkFcuam34,1333
+mypy/typeshed/stdlib/multiprocessing/queues.pyi,sha256=59kIwC-rl7eL8GoaqwGhMgXJFSM2k3SomZ0Y0TD3H-w,1486
+mypy/typeshed/stdlib/multiprocessing/reduction.pyi,sha256=P_DhZp89BFfQi0nKm-7XHQANKCMEiElNAZ32YsMIAzY,3330
+mypy/typeshed/stdlib/multiprocessing/resource_sharer.pyi,sha256=d9OjiE5L4aC3-u2-WC7csArCtkqs_IMOhhOVMEi6UjY,420
+mypy/typeshed/stdlib/multiprocessing/resource_tracker.pyi,sha256=w2BBEY5ehBV36E_tZ2gOOcmpdCVYn3W3iNLjsf047dg,635
+mypy/typeshed/stdlib/multiprocessing/shared_memory.pyi,sha256=1qcmGOD2rKo6L2cwpD5GjfQG6Ve216XQQrupVeXcIyg,1354
+mypy/typeshed/stdlib/multiprocessing/sharedctypes.pyi,sha256=wWZWXWSJjmlr77ljgBKeYV-Bd1iq3dCWGX1mKNMkpAA,4048
+mypy/typeshed/stdlib/multiprocessing/spawn.pyi,sha256=qyGvnY6Byy0tHwPsz86lF1wAAL02B_vb6wu64vCsgNk,861
+mypy/typeshed/stdlib/multiprocessing/synchronize.pyi,sha256=g7ruX6xPaJs5DAxRYhGwpjvcu1wNAO-P4wFNBhwbcc4,2128
+mypy/typeshed/stdlib/multiprocessing/util.pyi,sha256=MrGcQ3DTwm3ZUJTvWbMRJNA4WdADyebKJ22eeSadxlw,2427
+mypy/typeshed/stdlib/netrc.pyi,sha256=tvfrFw9uqNzt6Xt_fJVlbF2uXIoJy7YXEAOzveB8AEo,745
+mypy/typeshed/stdlib/nis.pyi,sha256=jnKh2Xj3mroOTpZpm-C7BYPVe5M18UAIVeh66AFGyw0,293
+mypy/typeshed/stdlib/nntplib.pyi,sha256=NzKy303qNUX47T9Rxfasi6mdDLMmLx2l9UMZR-6W_SQ,4490
+mypy/typeshed/stdlib/ntpath.pyi,sha256=Vj-Qpb3dqa43cjUtO_SQFABIf7_iAV3KhnWCb4ZHOhs,2687
+mypy/typeshed/stdlib/nturl2path.pyi,sha256=E4_g6cF1KbaY3WxuH-K0-fdoY_Awea4D2Q0hQCFf3pQ,76
+mypy/typeshed/stdlib/numbers.pyi,sha256=qinqUryHx19YkhH6OClOLMG8c1yX9PozHrr_KOXyy4Q,3914
+mypy/typeshed/stdlib/opcode.pyi,sha256=9FFbIQByV3VdwYO_mNBNUskDjasfGsWhM3qW5OLeWEQ,1402
+mypy/typeshed/stdlib/operator.pyi,sha256=tYdNrYQHPWJRxg8tpq3tBoPIzxjXNp4_YGzReH04NiU,1644
+mypy/typeshed/stdlib/optparse.pyi,sha256=1VTQ2_uVELLVWuCp5GamcjLgYGOGrn1YyDrzh22YNWc,10286
+mypy/typeshed/stdlib/os/__init__.pyi,sha256=Q_CryJNsVz3-_QSuGF50pvyOrBvmWg2qrzJzA9jcSG4,36995
+mypy/typeshed/stdlib/os/path.pyi,sha256=G76tJbvlG1_kzFd8gnCqS4Mht3gPzlC1ihIBqzurxDM,186
+mypy/typeshed/stdlib/ossaudiodev.pyi,sha256=KlSY0YMwJ4GhwRykTgJLA1X3l9uvezLYSA7GoEQG1zY,3618
+mypy/typeshed/stdlib/parser.pyi,sha256=niYW6rP8Ec_LPEwkT0R172ylS56mYdsoo1OzoIJ8OcI,1046
+mypy/typeshed/stdlib/pathlib.pyi,sha256=cttMTj6EbBh_N6oplIBsPNM-ctGWay7llU9jzomUuIM,8857
+mypy/typeshed/stdlib/pdb.pyi,sha256=Yz2xTexiBJSdiBesLiOEiBOFM7kfIHRiq0jK8ie2ybs,7415
+mypy/typeshed/stdlib/pickle.pyi,sha256=lECwhkVkIrAPDIB-QisRc9ZVSv-YvzGevA6cM-C74Vw,6898
+mypy/typeshed/stdlib/pickletools.pyi,sha256=hfV2HoaGStXhWZ9jta9NAqCJDa6ws9YeAU34k3Fz9-s,3813
+mypy/typeshed/stdlib/pipes.pyi,sha256=FvE1GTA5YU-JHBIO-mCAIfrAARL7g2Ck0HmgJ765gNc,502
+mypy/typeshed/stdlib/pkgutil.pyi,sha256=wQO0412Zh54qP6X6sY0YOqU3f-NMdtDcg141H9v571k,1699
+mypy/typeshed/stdlib/platform.pyi,sha256=IOmVCfbnZeVv6o6_k3XhVpXxI_3Ar5nKUOMj79F-vEQ,2375
+mypy/typeshed/stdlib/plistlib.pyi,sha256=PNso6sFX3yIFsbSUZQFQ51efd467GXO1EFaTWGKXoP0,3104
+mypy/typeshed/stdlib/poplib.pyi,sha256=DHIoO9sIXcFCuRbPSA0_2XCVlw-rkrSYYmFDHUoy9p8,2171
+mypy/typeshed/stdlib/posix.pyi,sha256=_S2z1Et-0bSF3YKc3yBq51LxJnJDMz6Xg9r4LdMagGs,10549
+mypy/typeshed/stdlib/posixpath.pyi,sha256=4prwuNkHrRT7ahvo_5UTd9gOzKLxTDnxPn2bC1cn5TA,4270
+mypy/typeshed/stdlib/pprint.pyi,sha256=eKR-SVXORiPTH6u-T25vDdlZhUeTU66kb_LDBU82Kk8,3857
+mypy/typeshed/stdlib/profile.pyi,sha256=VpPS5rX-U-fcd_c6RqY61jExGMMUtzY_QKV_Et0er6o,1400
+mypy/typeshed/stdlib/pstats.pyi,sha256=qx3KiOBJPKy__dWfqJHMdf4djvUZs-LY4G5bglSZCC8,2809
+mypy/typeshed/stdlib/pty.pyi,sha256=pz6Mkf2jC_-4VAg5Xjl8StYz7AsmVFH-u5rOQe8mroc,679
+mypy/typeshed/stdlib/pwd.pyi,sha256=KBcXx1wI9FnT3_Pxgpc_pWCO4RwOnXzw8BoWHFW6_vs,931
+mypy/typeshed/stdlib/py_compile.pyi,sha256=PIqaC0dYXtXkn2P4bNjlGmnTbKWxah-gY2NFxDZCVeg,1234
+mypy/typeshed/stdlib/pyclbr.pyi,sha256=9zqUEWOZfm2eRKsOfdrze6IgBYHcOFOSeDxo2si463U,1839
+mypy/typeshed/stdlib/pydoc.pyi,sha256=GC7vDN3ImpgM8CKaVjct5s94VQcKpB0j9DoydMcWjFI,10809
+mypy/typeshed/stdlib/pydoc_data/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/pydoc_data/topics.pyi,sha256=e6t5ek6ktCuHqVHsBY_gFm5Lzj4BupyBch13u0t2JVc,23
+mypy/typeshed/stdlib/pyexpat/__init__.pyi,sha256=2tNGsAw-Owb0Kq9fT3XdCxWlGODZ9YTXavZBVsfIek4,3396
+mypy/typeshed/stdlib/pyexpat/errors.pyi,sha256=X8RDjOTN_gpDtmIZMIkMump2fA-wBWRLQ9PCWAN43Ac,1477
+mypy/typeshed/stdlib/pyexpat/model.pyi,sha256=LlBMaLvt3TBD1JQSAQTYUrHKAfKNEeQYaDw5GsJA--g,205
+mypy/typeshed/stdlib/queue.pyi,sha256=Uvl7OyniSZunXc-pGwZcgI2oC9_gl9j36WtnM06jEXw,2042
+mypy/typeshed/stdlib/quopri.pyi,sha256=dS5VRBZNFkbcr7iEbgkiZzaVMBikOVqqerPCYxtunjY,635
+mypy/typeshed/stdlib/random.pyi,sha256=tk5Zfqr5Ls02BvHPFsE7HjvDNqr3rcRc9ddR99apCpI,5012
+mypy/typeshed/stdlib/re.pyi,sha256=ZiigKHJjoKkbJ0rqfc4yg2G1V_YklFTI-S95r1ZQD74,11135
+mypy/typeshed/stdlib/readline.pyi,sha256=IZlPSsDps5e06s_ScKfJxSaepjwpKPydrsETGOS78wQ,1862
+mypy/typeshed/stdlib/reprlib.pyi,sha256=usKrUhRcCNeOVdYy3S6I8njRORXIQ9rXrGme00uGJd4,1986
+mypy/typeshed/stdlib/resource.pyi,sha256=VK5hfm2DzqEm5AEOpdEtn93-0dXf_-JXK6y9_L5QRBA,2763
+mypy/typeshed/stdlib/rlcompleter.pyi,sha256=FtTt0Z1sNrWz6EMCyowIRAq8tzAeTpee6rUVJ5b-Tsw,322
+mypy/typeshed/stdlib/runpy.pyi,sha256=hrHtuhkdU-vJb7E6trWXD-ITI33AOQT_HH5CEsURVdQ,811
+mypy/typeshed/stdlib/sched.pyi,sha256=B8FhorZyvm0qvFqQ0kXb1kDQq4IhUFwDCqV3Q5Hinnk,1333
+mypy/typeshed/stdlib/secrets.pyi,sha256=GTDHK_EMcCaMZ9h-8OploY5SQiAaqTDRbh3ROug0M4I,624
+mypy/typeshed/stdlib/select.pyi,sha256=Ljdjkz2zJVFvgErZf46vv9Ta55cQxTaFrzrCKMFNNew,4523
+mypy/typeshed/stdlib/selectors.pyi,sha256=0kj3kq1KTVfcDUYzvbJFkw6Di6Qa5u6k_lP-kzUh7mU,3729
+mypy/typeshed/stdlib/shelve.pyi,sha256=r7AlnyCRzUETyAagweOwWdiJeNeWUXH6oi55t284ji8,1741
+mypy/typeshed/stdlib/shlex.pyi,sha256=tgaHCMRHxb5cq1XmsNnqYoQk6slIZGWIF-r_X2Wc6RQ,1502
+mypy/typeshed/stdlib/shutil.pyi,sha256=tHW6wzBNrYvtrovIDaf-sZF-yetpSw8yKkcssiv-PQI,7634
+mypy/typeshed/stdlib/signal.pyi,sha256=5eaDUBa5fUjO1OVckME6j3ui5KNCWG7xZaTtNHyJYO8,5346
+mypy/typeshed/stdlib/site.pyi,sha256=VLUjy224HMBMxypap1nqsUxzApffnonquUkMXDEvmwE,1358
+mypy/typeshed/stdlib/smtpd.pyi,sha256=ce_-rXeXmh2tgsxOR_tJJOPFQWLiQYqsnSggBP69huQ,2998
+mypy/typeshed/stdlib/smtplib.pyi,sha256=IHHzP3zVn_1zHZArcnDfuO1AymUVlEZ_Z0w9XCpgHHU,6156
+mypy/typeshed/stdlib/sndhdr.pyi,sha256=4boTiWWf2o3VW6QhITP8JNEePP734AlxyMeU1cn74CM,353
+mypy/typeshed/stdlib/socket.pyi,sha256=ka8C4aCM14f5NUPZFlwDS4iR3BSz3Qypyej05n3RHgM,29507
+mypy/typeshed/stdlib/socketserver.pyi,sha256=4Xn5icyBtZXOgRUx8q28PUTvb193W6KpQHFkEKc3GSk,6734
+mypy/typeshed/stdlib/spwd.pyi,sha256=ns6VO7ch2oLddqPkxl7WWZuMmI_B3SZKYGqAQhotgpk,1180
+mypy/typeshed/stdlib/sqlite3/__init__.pyi,sha256=gceY1jvHvHiZ45SMdArnWeyTcRGArLc2PK28jNbtbXU,29
+mypy/typeshed/stdlib/sqlite3/dbapi2.pyi,sha256=jx5XwmbT1QbDJBmeUGYsLMY5sW3sC16rF4TCS52oDJ0,16736
+mypy/typeshed/stdlib/sre_compile.pyi,sha256=yc1nsmNzAJbfAUFaKTMoik99gA4TgPwx92ux45r2VEA,332
+mypy/typeshed/stdlib/sre_constants.pyi,sha256=z7gyetbR-CCQlJZlAnER6fT1TD4dwLW67As3eEVZClw,3986
+mypy/typeshed/stdlib/sre_parse.pyi,sha256=OLaoGeVEtYTscbcEApP65qd_JEf8FOm8cOdS7CN8gCI,4069
+mypy/typeshed/stdlib/ssl.pyi,sha256=u7wQp1LzlFTZXeLSsYjMFS3J_NbUA24KxYJn9KUGB2A,18327
+mypy/typeshed/stdlib/stat.pyi,sha256=H9gX7m5DJt9cT5h4xk3JwIDAVDdzSt_cHfoeVG_B2Ko,20
+mypy/typeshed/stdlib/statistics.pyi,sha256=VljvkYS_tpLl0FYRCPWnFRHgmTQvBl4Fx15HPP8-u1E,5105
+mypy/typeshed/stdlib/string.pyi,sha256=zES75mTdIJQiklC5SZEXuyWHQPFU9y0EoI0y7bVK1kY,3097
+mypy/typeshed/stdlib/stringprep.pyi,sha256=Zcj538_tsMh7ijQYUgxe01Qhdu0YUzWtYk2Hl9cT-tw,910
+mypy/typeshed/stdlib/struct.pyi,sha256=VHGwv1FizhOZu9fTSpnMwTceXkTCrdEudLzoibejGas,1271
+mypy/typeshed/stdlib/subprocess.pyi,sha256=1LoNJfcyFTyAA8ZQ4SFV-AMybtD6xCgbJ9hx9WpQzTQ,91091
+mypy/typeshed/stdlib/sunau.pyi,sha256=sH5NN1qSPh-NnDTPzRDEmJ6XSELdwaKa7X4W8k_sqNY,2867
+mypy/typeshed/stdlib/symbol.pyi,sha256=lyGzaMWeP5QnH3ktpjdbX149vWbryIGvA4Z-i_v3gnI,1531
+mypy/typeshed/stdlib/symtable.pyi,sha256=NWXnsX_VGAxivxJIKVKr_zWIZhSzvJwpLc0O_LJwNWA,2359
+mypy/typeshed/stdlib/sys.pyi,sha256=NWgrDkwT5A51JmGsG84diDpeU4ujlkMEZ2F6yom8xgM,12507
+mypy/typeshed/stdlib/sysconfig.pyi,sha256=a5EQEJRM3dXboAWOFVwcArzJvt3kVTsfBKmlTkb__Wg,1399
+mypy/typeshed/stdlib/syslog.pyi,sha256=TDpOA4Ie8T_05WKIt2n2WOMcPSj_eycPDvT1_pi9LN0,1357
+mypy/typeshed/stdlib/tabnanny.pyi,sha256=qBHW9MY44U92xKdFbYgrSXljglOVtAY0GYTa41BHwbE,514
+mypy/typeshed/stdlib/tarfile.pyi,sha256=kdLUt9ptYURXqIjHWtD4hyEro0u3XOLeG85Mic-ebAI,14977
+mypy/typeshed/stdlib/telnetlib.pyi,sha256=yZydgLEan7JJJV33MT_5bqe_PE4QRjCeeCvh4EvTWRU,2827
+mypy/typeshed/stdlib/tempfile.pyi,sha256=s7CSn4vX9DDsWVNUMlZk7cxHA6PeAQaC2QKw2chEU3w,22824
+mypy/typeshed/stdlib/termios.pyi,sha256=Lw8IhEyQOyqnhtBKikiCQsIbWRL1cLXbgQ5a_H7Cm6k,5095
+mypy/typeshed/stdlib/textwrap.pyi,sha256=6eEGWUkmDRU_-fA-aOIWWse9-1GIq8T89S4Vaf9aJ7Y,3233
+mypy/typeshed/stdlib/this.pyi,sha256=qeiwAiqbPK8iEcH4W--jUM_ickhZFNnx8cEvTqVPvCY,25
+mypy/typeshed/stdlib/threading.pyi,sha256=9rdROg_2ppRFEY-_yr8geqLJoJknNrnW2IUBR_ZwDRs,6297
+mypy/typeshed/stdlib/time.pyi,sha256=ge4eUsmMwc0m16aqbVqcI9EAtOFM3XJbQFpyAYfkH4w,3663
+mypy/typeshed/stdlib/timeit.pyi,sha256=4yMgBR4T5Ame22l3SkRnXrq134Jivk3bJIclXNsp6lo,1240
+mypy/typeshed/stdlib/tkinter/__init__.pyi,sha256=WXiq2p6rrGrh80X8q8r94csQbOoq51M7axJt5fA68pI,134288
+mypy/typeshed/stdlib/tkinter/colorchooser.pyi,sha256=XEQaC9ihB5nJr6yGUmxGMZYct_9Vn0mXTncq59rtKOk,654
+mypy/typeshed/stdlib/tkinter/commondialog.pyi,sha256=AEiY_bOF0XKQNltMTeEao6OzvOkU2HRrBnJYwEw7gA8,436
+mypy/typeshed/stdlib/tkinter/constants.pyi,sha256=WfBSeKTB52NfPVFdsdaRrnsmDOvT3FoP8j4QK1T3yxU,1886
+mypy/typeshed/stdlib/tkinter/dialog.pyi,sha256=Zx4Lp6NNRdSdmQeu_rTE8RBmfyVmD8HIXrNmHoFxkuA,413
+mypy/typeshed/stdlib/tkinter/dnd.pyi,sha256=hTMdgJxSAmnjhJX_DzIq96Od6efr3nuuKStfQ6jzWvA,748
+mypy/typeshed/stdlib/tkinter/filedialog.pyi,sha256=mYX_j-6CLUKBrLFF_rGUE8latcOgphKLAd1yDiAaOAw,5232
+mypy/typeshed/stdlib/tkinter/font.pyi,sha256=122mjZBpmDxWHWtZuOmB5eibxZsVyOshO0xycsxkZpk,4056
+mypy/typeshed/stdlib/tkinter/messagebox.pyi,sha256=v-AB9-m9M1yTzZAV__Y_wDjNIbb2z_OS06STV0j5lsQ,1321
+mypy/typeshed/stdlib/tkinter/scrolledtext.pyi,sha256=hx0HadZ4WRUK6Vf4vh4kRnWJIAtgo3GO8EmfeSsHWcg,347
+mypy/typeshed/stdlib/tkinter/simpledialog.pyi,sha256=ZZxYKT7uNQ7t1FJ4RqlXX5BCJg9Zcs93e3uFRqt-bSU,1596
+mypy/typeshed/stdlib/tkinter/tix.pyi,sha256=UEYf32dC2wwFbnRkWNeTf43ySGQQGjDgDHPF2fAtVnk,14434
+mypy/typeshed/stdlib/tkinter/ttk.pyi,sha256=h6bx-EVBrsYQyDbwHFB7RavRaHNhO6fBZsJIXtitwMg,44712
+mypy/typeshed/stdlib/token.pyi,sha256=9Eb65Fw8MX2uji_EXg3DuWtRTX7x393EDxaMrKtJ3po,2608
+mypy/typeshed/stdlib/tokenize.pyi,sha256=z-5IGr-pNh47Hv3otvejDhu-C6W9GVzoSXF8iQrOnLw,4372
+mypy/typeshed/stdlib/tomllib.pyi,sha256=8PrxthyKN9Ki3Bz9XP0hCXwrXfvNInW_iwJQB6lKVvE,374
+mypy/typeshed/stdlib/trace.pyi,sha256=Q-J24b-CQ7V4gs0CW10BT2G88t7Rd21Xf5TB8JqreSU,2703
+mypy/typeshed/stdlib/traceback.pyi,sha256=JJcgjmuiEJk194EYTgFhZgYFB4lmus4Hd13RfAPkYqo,8906
+mypy/typeshed/stdlib/tracemalloc.pyi,sha256=bxyPBpWNisLSzzh1BNZ1YWM36JpeEBldP9s0SozLMGE,4400
+mypy/typeshed/stdlib/tty.pyi,sha256=k-rdL0AQuOWV9_SvTvxpi9bXqP5XG_rX6QB4-P2vJvg,430
+mypy/typeshed/stdlib/turtle.pyi,sha256=c5Wp_gQWyBXNPaDNpxJq02BUTBkMF6Tv4XlOhi9n6fY,22163
+mypy/typeshed/stdlib/types.pyi,sha256=P-oirLNKM_hvtOYhAGgu-oAZIvx7t8jkCBROUgHZhGQ,21290
+mypy/typeshed/stdlib/typing.pyi,sha256=bWbZZUadyUDrhQQSdcFuqPsHd7g7x5M0ucB5nsbdyow,33387
+mypy/typeshed/stdlib/typing_extensions.pyi,sha256=UTVoNMz8CqpipYypA4pH0RGs9ctAqIvYY0VF6ocwB9s,14374
+mypy/typeshed/stdlib/unicodedata.pyi,sha256=vHejnVd-GSPq9cXVbOebw51BXY1ccOS1m8onx3sbzdA,2511
+mypy/typeshed/stdlib/unittest/__init__.pyi,sha256=26L4TsNk8c_5DYr8jEHAtoFbRR8uFpfIK2HGvXWUC3U,1871
+mypy/typeshed/stdlib/unittest/_log.pyi,sha256=KXpRo2YT_82EvO93LD8N0P21ehqazFRKcoQEaGR9low,892
+mypy/typeshed/stdlib/unittest/async_case.pyi,sha256=7yqlBVkBDTEk6fAAPBf5zYuVn0xz2BV_5AqwujwhiAg,663
+mypy/typeshed/stdlib/unittest/case.pyi,sha256=LolrEJMMC9iEmj5rTFhOfrqSZfhe_v-guiSi5zKolns,13905
+mypy/typeshed/stdlib/unittest/loader.pyi,sha256=_sA0l3OilNSuQ6R2eGLUEF6W6I1xQ-HvBVEGz0l3AUU,1990
+mypy/typeshed/stdlib/unittest/main.pyi,sha256=8VDvlDjlkePWKfDu_XsyNsGFKNjgoQPtFXdLFWtVQwI,1544
+mypy/typeshed/stdlib/unittest/mock.pyi,sha256=Qvms8nzBSF1OLopdkVqAdcAamUsgKMoVyFuB_0-YH4A,15234
+mypy/typeshed/stdlib/unittest/result.pyi,sha256=w8hNFXqyBM07ALP69NZMyFrVD9YiFFqAMs3iN40x52c,1721
+mypy/typeshed/stdlib/unittest/runner.pyi,sha256=ODV9p4ULZoYnUD1XTLDlVFpEn0YL-7no1jJfOCDgru8,1353
+mypy/typeshed/stdlib/unittest/signals.pyi,sha256=6rqsVHXOvSPHSkeF_vYPf5sUaLgqqFSmFihkaDqPhSw,488
+mypy/typeshed/stdlib/unittest/suite.pyi,sha256=gu8_zNvsjXQSRvMSC7prG0RZCymHJMQx096BIPN91U4,983
+mypy/typeshed/stdlib/unittest/util.pyi,sha256=KpMwCEXOSHtZ7nIilXkPe5D7KdEiDqgHWUGpHlZsYGI,978
+mypy/typeshed/stdlib/urllib/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/urllib/error.pyi,sha256=I-uhiBMZN9tuYrjeZWczbBT5Mwe7X-Eupqf74_4eXgo,816
+mypy/typeshed/stdlib/urllib/parse.pyi,sha256=koen8iL7qLwmh5E_OZAaE8LqXwBjgVj48gOXIncCt9E,6532
+mypy/typeshed/stdlib/urllib/request.pyi,sha256=g_9PErn_aTeMgW5KwrcO_Pz3tbJsDiAgeNBBOA22YCk,17570
+mypy/typeshed/stdlib/urllib/response.pyi,sha256=K_lbdNdeEsOfeThsidKvJ9A0EQAoh-dURwPcC6zrHgE,2302
+mypy/typeshed/stdlib/urllib/robotparser.pyi,sha256=xuV1t5bvnO8ogw1v4TDiFP3VLfRMdN4ISkJdGhqwscM,733
+mypy/typeshed/stdlib/uu.pyi,sha256=yMt5ZRAepWSra-qWti133ZGibCtrJXkMZg5kKJe-MdM,431
+mypy/typeshed/stdlib/uuid.pyi,sha256=-ShHEwqhgu3eCACN2nHcZhNUb91y-X0k_Hc96tT2MsA,2619
+mypy/typeshed/stdlib/venv/__init__.pyi,sha256=aKgJDxdGYcVUVH-VkdZhcKW21JVBYL_6Rgal_6PN2qs,2665
+mypy/typeshed/stdlib/warnings.pyi,sha256=mpkdpsfLVQ9F79hzhewi9hpFxpURqzryWUttHOBIc0M,3682
+mypy/typeshed/stdlib/wave.pyi,sha256=fRzyqfDoP39s1vkXf4rHeT6IzXTsgZG3fB-ZSuVAaBs,2758
+mypy/typeshed/stdlib/weakref.pyi,sha256=vWkIaJcFPfOn2z9TI59L3EF-WHfIMNR8tnQwRlKjyGM,6014
+mypy/typeshed/stdlib/webbrowser.pyi,sha256=Nk8mSmJaK0z83HeXcNwo0YwzSvqS7EQvaXKB_iF9xwc,2574
+mypy/typeshed/stdlib/winreg.pyi,sha256=1-y9o9Nx2eYXm69l-59XC6F14k73poJLuYTWHbSYhng,4345
+mypy/typeshed/stdlib/winsound.pyi,sha256=XF1e0kTWVsK8Qky02khQJWIdMX2dj_XFfx6Vcwagacs,951
+mypy/typeshed/stdlib/wsgiref/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/wsgiref/handlers.pyi,sha256=d4qMJ3ZNLNAnDk1I___l8nIUK9uxDol-bXsjtc9BsX0,3068
+mypy/typeshed/stdlib/wsgiref/headers.pyi,sha256=rw-QVHeN939ReRhzZTvPABuQQo4L5k35EYsBS2uU2yE,1036
+mypy/typeshed/stdlib/wsgiref/simple_server.pyi,sha256=-nQD3wVKCs_VDpTeehZ8CdKILXm0Hec0ZeGRdCSZJjs,1398
+mypy/typeshed/stdlib/wsgiref/types.pyi,sha256=OXMbejbY89BqvXfn1yTqD7iBLERExvXclEi5v0a5xU0,1258
+mypy/typeshed/stdlib/wsgiref/util.pyi,sha256=OaPZRbiITLo8QbXqiW5tRJtzXNM5fQbaRyyUPOCxZaQ,995
+mypy/typeshed/stdlib/wsgiref/validate.pyi,sha256=NCpbRPP9fTt21peGNlXLgegq6U1yZaeAxFO-SUfBlng,1737
+mypy/typeshed/stdlib/xdrlib.pyi,sha256=wxJVHCfO5rju29ihBF96XgK3dj5b-LbsVGeotGgp15k,2368
+mypy/typeshed/stdlib/xml/__init__.pyi,sha256=1v5PXkWd1I909FrHSGV42z-AW-79lZBHfSIrbB3DeW8,35
+mypy/typeshed/stdlib/xml/dom/NodeFilter.pyi,sha256=bi0L5SEOxk4FyEhf18oU-I8Msf9S9o_tJt-mVc93f28,457
+mypy/typeshed/stdlib/xml/dom/__init__.pyi,sha256=p3WpjR2_q3xdrf0_xp5vsEdiZkhXQRAB9Mw_wad4OYk,1889
+mypy/typeshed/stdlib/xml/dom/domreg.pyi,sha256=LNRgIl78O0eH3m7E5GFqG0BKQ0JSsHxTBnwr5KznZvI,418
+mypy/typeshed/stdlib/xml/dom/expatbuilder.pyi,sha256=vJRZwYGT5ufRjNqAqi7VvhjU1Hewx1bL1eQjVoAUN5I,4847
+mypy/typeshed/stdlib/xml/dom/minicompat.pyi,sha256=wZCjy4-kA-uW5ym2T_S9fnF2XhXIOtbGdUAO6MJrbeI,707
+mypy/typeshed/stdlib/xml/dom/minidom.pyi,sha256=Y18h7WpzX8-KSQGmestkcnZcPK1-qrCw6JTC2UmhEjs,15038
+mypy/typeshed/stdlib/xml/dom/pulldom.pyi,sha256=GXJ865exnLgs7JFlPr_1zB0RkIh3alhNuT01X-VS9Ho,3435
+mypy/typeshed/stdlib/xml/dom/xmlbuilder.pyi,sha256=c07EzVhYJIxBL23IZz9nbrV7sHJnIazDeKxC2iafjso,4206
+mypy/typeshed/stdlib/xml/etree/ElementInclude.pyi,sha256=j-auBTW6n_Ady1Ikya3Epum8Uq3AvJ3gejRakI2jd2g,983
+mypy/typeshed/stdlib/xml/etree/ElementPath.pyi,sha256=lcIxOcA8hTuptcicWV6vDioMDPK0fG3AryHTitElC34,1636
+mypy/typeshed/stdlib/xml/etree/ElementTree.pyi,sha256=ZguADuSuJzVdb5mFS-dCp91TllTmSuSaYgkoLjp4aE0,14360
+mypy/typeshed/stdlib/xml/etree/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/xml/etree/cElementTree.pyi,sha256=iYR7ebpdB3g9zfBvICnV1VzvQktMya-Dh6lX4C9u4Uo,36
+mypy/typeshed/stdlib/xml/parsers/__init__.pyi,sha256=PS75lzF6CFuo_xdO83zK-IOQrnoJQ3FkUoMSOMdwWJM,39
+mypy/typeshed/stdlib/xml/parsers/expat/__init__.pyi,sha256=qmz8tuPGbZ2rBfRrfYANxDZNxn9BTQXdd9AugF5wDW0,22
+mypy/typeshed/stdlib/xml/parsers/expat/errors.pyi,sha256=mH9YRZuV4quzksDMLEmxiisAFgNhMOhl8p07ZzlS2XE,29
+mypy/typeshed/stdlib/xml/parsers/expat/model.pyi,sha256=M7GVdd-AxOh6oGw6zfONEATLMsxAIYW2y9kROXnn-Zg,28
+mypy/typeshed/stdlib/xml/sax/__init__.pyi,sha256=3STINoHubXI0MlWJL-0695gRDV8IhPfMCVETwaNE7VM,1844
+mypy/typeshed/stdlib/xml/sax/handler.pyi,sha256=PJ-wNvSIlXWbpRhISKp6Pfcc7RcGfjfOCm3DyAX0UcM,1799
+mypy/typeshed/stdlib/xml/sax/saxutils.pyi,sha256=8GyLUYCIsDRexN0G27iXfZoVUC7nX8zKZxnmwDbnI9E,2505
+mypy/typeshed/stdlib/xml/sax/xmlreader.pyi,sha256=1aHmtd2kGF1-PM0FVysnTr5-DRJA9XLYLLYSueBsw_I,2408
+mypy/typeshed/stdlib/xmlrpc/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypy/typeshed/stdlib/xmlrpc/client.pyi,sha256=m-BYsvGMDm2o_SvpU5r-VpSn10eCsNEedVQjcaZRf68,12644
+mypy/typeshed/stdlib/xmlrpc/server.pyi,sha256=-EeIIcQM0Vho-4uKelSAr3pTdn8LJdoXy2xKpvPxdEI,6073
+mypy/typeshed/stdlib/xxlimited.pyi,sha256=lJRSdSHHY2wiZol2efBzvrCUCknkEaSB8hmyF-ccQps,338
+mypy/typeshed/stdlib/zipapp.pyi,sha256=gOkFhcdfGpy6PIboXe45wODMw-94YtC1ypUTCxBxTfU,553
+mypy/typeshed/stdlib/zipfile.pyi,sha256=lNitRlOhHPfLCYvhokShCVZbPP-CH3hI-Or3cjh-T5U,9406
+mypy/typeshed/stdlib/zipimport.pyi,sha256=cTfr4m5AjreaU2JchaB9NLDmdYQ-igXTD5QC0qRP_kk,1384
+mypy/typeshed/stdlib/zlib.pyi,sha256=XPqtuDyY-6_HsW9061pqiOMq05EtG52Jp4iYPtPmqOM,1787
+mypy/typeshed/stdlib/zoneinfo/__init__.pyi,sha256=x2bw7ohsupcJs7XMiVmzzHGi-u6N3Oo6ANbaqLe5X0k,1513
+mypy/typeshed/stubs/mypy-extensions/mypy_extensions.pyi,sha256=M00bMpf1XZOilHhHPjPrdRK7a9qw35DqOWh0PeT8aj4,8892
+mypy/typestate.cpython-311-x86_64-linux-gnu.so,sha256=sUlip3G5bUefajKkaHNzxJ9YgMDGLCZm7wUDfUy7kaA,8024
+mypy/typestate.py,sha256=ozFH6U1ZtDSwoPQPLQjR_eQ4jW30ovimSikI-MyL2r0,15744
+mypy/typetraverser.cpython-311-x86_64-linux-gnu.so,sha256=-C4sbHNcyp9S4N4YubLFkHSe9WXFTracvzZB_a_8I_s,8032
+mypy/typetraverser.py,sha256=Xop8Bz5c24h0TQyELACQaM36rMxzGf6qiQ2D4J8nAYw,3724
+mypy/typevars.cpython-311-x86_64-linux-gnu.so,sha256=1EiYv-MiH-kgPp8d_NqEvwTv3gZ7Se3UQOdxYyskHjY,8016
+mypy/typevars.py,sha256=QnTkilTsz6KHprkJ0YQOYpvpefQLGm-DGaVRQ5KGmok,2670
+mypy/typevartuples.cpython-311-x86_64-linux-gnu.so,sha256=9oWvlRQmYqjPsWxMAOAn7VnqG4vwUEP7C73t_XzxHkE,8032
+mypy/typevartuples.py,sha256=VbMsW2W9PN5ZP24wT2JcZonxSy8toj4PkYcD6LBKez8,5646
+mypy/util.cpython-311-x86_64-linux-gnu.so,sha256=MU1LTqMWUoawy4VbjwQGEFu-rIXhlyGErWeqDf94-8I,8008
+mypy/util.py,sha256=tSLGQq_3LoHwtHDR_9BlRWX8cuTv8R0Nc-CR9H3Twyw,28892
+mypy/version.py,sha256=8rmxh34XkVT7yu5zgYupipfDrKs2hgGCjOMEIK3E4oI,22
+mypy/visitor.cpython-311-x86_64-linux-gnu.so,sha256=p3o9hZr-WZBdz_RKmZ_5nOc7sGP8FQLyUttCb37qR-c,8016
+mypy/visitor.py,sha256=FTsBCo74V8F_Q_uId10wvORCQ8rexQjuQuUWhK21XdU,15882
+mypy/xml/mypy-html.css,sha256=-e3IQLmSIuw_RVP8BzyIIsgGg-eOsefWawOg2b3H2KY,1409
+mypy/xml/mypy-html.xslt,sha256=19QUoO3-8HArENuzA1n5sgTiIuUHQEl1YuFy9pJCd3M,3824
+mypy/xml/mypy-txt.xslt,sha256=r94I7UBJQRb-QVytQdPlpRVi4R1AZ49vgf1HN-DPp4k,4686
+mypy/xml/mypy.xsd,sha256=RQw6a6mG9eTaXDT5p2xxLX8rRhfDUyCMCeyDrmLIhdE,2173
+mypyc/README.md,sha256=w3R9pi9pyvr407c4sONjsXzfdwDOBco0ERuEawL90PU,4131
+mypyc/__init__.cpython-311-x86_64-linux-gnu.so,sha256=MYr2JH_-yn_EXH2NYN04g8K1QB0HEqWzz12aSqD_6KE,8016
+mypyc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/__main__.py,sha256=RJyB6omzvsoctyMV5M0ATIYCH6lNqfVvkSdnl4VBbIk,1503
+mypyc/__pycache__/__init__.cpython-311.pyc,,
+mypyc/__pycache__/__main__.cpython-311.pyc,,
+mypyc/__pycache__/build.cpython-311.pyc,,
+mypyc/__pycache__/common.cpython-311.pyc,,
+mypyc/__pycache__/crash.cpython-311.pyc,,
+mypyc/__pycache__/errors.cpython-311.pyc,,
+mypyc/__pycache__/namegen.cpython-311.pyc,,
+mypyc/__pycache__/options.cpython-311.pyc,,
+mypyc/__pycache__/rt_subtype.cpython-311.pyc,,
+mypyc/__pycache__/sametype.cpython-311.pyc,,
+mypyc/__pycache__/subtype.cpython-311.pyc,,
+mypyc/analysis/__init__.cpython-311-x86_64-linux-gnu.so,sha256=EPqO00Pquyow3ZSyyxdkLrremWb848-IKHWM9-g4Xic,8016
+mypyc/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/analysis/__pycache__/__init__.cpython-311.pyc,,
+mypyc/analysis/__pycache__/attrdefined.cpython-311.pyc,,
+mypyc/analysis/__pycache__/blockfreq.cpython-311.pyc,,
+mypyc/analysis/__pycache__/dataflow.cpython-311.pyc,,
+mypyc/analysis/__pycache__/ircheck.cpython-311.pyc,,
+mypyc/analysis/__pycache__/selfleaks.cpython-311.pyc,,
+mypyc/analysis/attrdefined.cpython-311-x86_64-linux-gnu.so,sha256=_XsoByk9xj8QwdPdBarzVVZTYQ2LnThpF7Ld25anY7o,8024
+mypyc/analysis/attrdefined.py,sha256=LGN9MzcAz-WYyrl6lhzKoX0_LxaupBcfZ1Ch8Ew_-O4,15369
+mypyc/analysis/blockfreq.cpython-311-x86_64-linux-gnu.so,sha256=hvPCq2LgEa6yN1QiiryYPxTPFdqFd7UI2d5g_BMJvCU,8024
+mypyc/analysis/blockfreq.py,sha256=CjdVRFXgRdsuksk6e11cqbsFdj4e1z_8GHvvnY_Pgb8,1004
+mypyc/analysis/dataflow.cpython-311-x86_64-linux-gnu.so,sha256=sMbQT6yX8OZXIpot6Qq59hj7jjUy4M2kdHKHKPLmFdc,8016
+mypyc/analysis/dataflow.py,sha256=olyxdQuhaetdeDJsP_0sE-zFX6_xFQwJKx8mCPnd00I,19512
+mypyc/analysis/ircheck.cpython-311-x86_64-linux-gnu.so,sha256=GT6erFXSeFTRBp0pvG9pCwBtMMVUcTX_sri__uASY5g,8016
+mypyc/analysis/ircheck.py,sha256=FAmhmtGpfmL9bLdNJfsuDnmBji3U09DrsRwsAsmVZDg,13367
+mypyc/analysis/selfleaks.cpython-311-x86_64-linux-gnu.so,sha256=_AcnqQ5hD0vO4AuTbxDDpzsYQ5aGrIJvABPB_qS3zlE,8024
+mypyc/analysis/selfleaks.py,sha256=JG_GxBAdwNHIufo2OkH2lQgopz8mt6OZgOKlHwylacs,5536
+mypyc/build.cpython-311-x86_64-linux-gnu.so,sha256=lqSfpUPJwuY1pXH0EyZYyj4USAtZXw0-O-fH9KgpPi8,8016
+mypyc/build.py,sha256=MogjyuueVnYK5LZMW13mk-9NzZSyij13ByflNnoMHVM,22155
+mypyc/codegen/__init__.cpython-311-x86_64-linux-gnu.so,sha256=52i7DDBCF87386QqXV9xPgZiHHhL374UsRO1-sLa2_4,8016
+mypyc/codegen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/codegen/__pycache__/__init__.cpython-311.pyc,,
+mypyc/codegen/__pycache__/cstring.cpython-311.pyc,,
+mypyc/codegen/__pycache__/emit.cpython-311.pyc,,
+mypyc/codegen/__pycache__/emitclass.cpython-311.pyc,,
+mypyc/codegen/__pycache__/emitfunc.cpython-311.pyc,,
+mypyc/codegen/__pycache__/emitmodule.cpython-311.pyc,,
+mypyc/codegen/__pycache__/emitwrapper.cpython-311.pyc,,
+mypyc/codegen/__pycache__/literals.cpython-311.pyc,,
+mypyc/codegen/cstring.cpython-311-x86_64-linux-gnu.so,sha256=4GpWgXcklC2BtATLysdOp5bL8fBykQhhRMveece4Mcs,8016
+mypyc/codegen/cstring.py,sha256=yB_SJmahDpTC7Xq3vlCstPZhhyLpRzEy9yHBwdqdIa4,2004
+mypyc/codegen/emit.cpython-311-x86_64-linux-gnu.so,sha256=mR13QQCrVZUK-sFFhkvCEFysw8iKsWbBMi9cUDsH7WI,8008
+mypyc/codegen/emit.py,sha256=aMqmt_hgHJNzswkCFmza7dZjca6_3Wn66LkOxl0Sq9w,47292
+mypyc/codegen/emitclass.cpython-311-x86_64-linux-gnu.so,sha256=R7P8raYjB0340gCKKjo0Wr6U4k5fB7IEu7ms44ILkP4,8024
+mypyc/codegen/emitclass.py,sha256=Bh3KG65sZQ9ht5nnGw8IgTOx30Pb3uFahmu1yHhG6bw,42135
+mypyc/codegen/emitfunc.cpython-311-x86_64-linux-gnu.so,sha256=GhDrdNUgQT1sUT-9UOrxWwqGYIqfyDZ0tiM-r2RGLsA,8016
+mypyc/codegen/emitfunc.py,sha256=DFGzqJBe6D7hKyGj4K-ePr_0p9KwPy04_J8EKAxQnec,32072
+mypyc/codegen/emitmodule.cpython-311-x86_64-linux-gnu.so,sha256=FBDezF50oRX_E3wK0ndjG4YSUC3ZYGqIU2pMnzB_BLY,8024
+mypyc/codegen/emitmodule.py,sha256=WoJ5UE6zBK1Bes_2IaNbxgJrTHsSUY-Ns9J_uURr2RQ,45491
+mypyc/codegen/emitwrapper.cpython-311-x86_64-linux-gnu.so,sha256=2Agply9RwaakyTpZaoJWVmeFw306lDrHVrCYrqM9Djc,8024
+mypyc/codegen/emitwrapper.py,sha256=TKX-QdD72GAl5EEZarsDS4txJ_q-Yv43rtd0_G2DsIc,37928
+mypyc/codegen/literals.cpython-311-x86_64-linux-gnu.so,sha256=AdD6Sm60vQZDEMdmwfxDl-pWP12omR18MvSTY-jmzRo,8016
+mypyc/codegen/literals.py,sha256=q9tpKsilOaZE2oa34tRp1hpVgQvSPzTnLJZLVMKxtrI,10629
+mypyc/common.cpython-311-x86_64-linux-gnu.so,sha256=I8tHYP7ep_HQE_oi503YyAl6hXsDH5pYK_ANBmooJ2g,8016
+mypyc/common.py,sha256=d-xzzd_062wKr4MrzDOK5hxCQAhdk1kue5ZCjjqNN2s,4402
+mypyc/crash.cpython-311-x86_64-linux-gnu.so,sha256=WIPk9B1sXf5Ngu_O0l5kOzIlcDwLZTSACMkwKO5Htic,8016
+mypyc/crash.py,sha256=ofNC_TLq7VaBMj0bPIcAMlFQ-xQY_1IERFke0pAxD6E,926
+mypyc/doc/Makefile,sha256=i2WHuFlgfyAPEW4ssEP8NY4cOibDJrVjvzSEU8_Ggwc,634
+mypyc/doc/__pycache__/conf.cpython-311.pyc,,
+mypyc/doc/bool_operations.rst,sha256=wJPFzR26eSaqxtPopRiGw9f_zC-q1-RIE8W2u36b9Ro,373
+mypyc/doc/compilation_units.rst,sha256=TXycr64XYsR8fCkDo5EI0wugy_UA8bQieM_Mh8dhdKw,826
+mypyc/doc/conf.py,sha256=BTuVcVJR1WASjuVwjnbsgeE9oYxMhFlwPEtX6OVBuSg,2196
+mypyc/doc/cpython-timings.md,sha256=XX2UCU8eITd8NbQ6hPaw5WyOMiIfugZFCIUYtOKhHrM,830
+mypyc/doc/dev-intro.md,sha256=V9o4MG7G1Gctyc36Pomaz3UkV6RplPT2vApRZGDtonY,22695
+mypyc/doc/dict_operations.rst,sha256=Zit3bGFlkfbdqOfp15JPcXN5npbIQUwBN8u6guHM7Ew,870
+mypyc/doc/differences_from_python.rst,sha256=y4PLIE1Tk4I-ITOwDPYqmGs_mEnR0UrZ4REZf8xAHhw,10060
+mypyc/doc/float_operations.rst,sha256=lNdL0aoSUePhGNomoA69qYL3ZAgQDgzzDQFufBrpMmk,1066
+mypyc/doc/future.md,sha256=b7HAYGmE6hoLMUG_sGZK7EvNAZa-yG2NYSCdFAO4ekw,1431
+mypyc/doc/getting_started.rst,sha256=lN1Zb19oglT8rNiAEIdF52Lpo9ovG1Qx_Th-Gy1mOkg,6722
+mypyc/doc/index.rst,sha256=_TIxEFzf5BYkQVggf9CQPhpxeWl0UCqEGu2PJdtCQ-U,1213
+mypyc/doc/int_operations.rst,sha256=bzn2KuIWCgL0SNW52i5HQAzReHxJd-jOZuzF2jV4xkc,4589
+mypyc/doc/introduction.rst,sha256=sRnOzHtT4Kw9b7YxAEc6oMB04S1Jkr4HMaUMu8OcUds,5821
+mypyc/doc/list_operations.rst,sha256=e1kZyc2y0UZ-oZot9QBJc5C6krJB1vKpWfgyIAs7DMY,1029
+mypyc/doc/make.bat,sha256=xxfN3a_rN9HJSTHJDfhwV9HRJ2I0Mg3cyhj28ZqU4fk,800
+mypyc/doc/native_classes.rst,sha256=a2XSjRgirZuuZl5tri4sS00eBc8kAJR6eRKufZ22F3Y,5436
+mypyc/doc/native_operations.rst,sha256=nfN8LLywQ7uUaagHfSUTawv7d0MD5HwLO3dJyO1i42o,1190
+mypyc/doc/performance_tips_and_tricks.rst,sha256=a_aTWrSyHhlWgc91hhi7aEapCXLEx9KH32f7AgOTrOM,8262
+mypyc/doc/set_operations.rst,sha256=u5mposJ9vbUi6uyv1lrK-86O4MUEUVybUNzcTWny_4o,672
+mypyc/doc/str_operations.rst,sha256=N6xjFRMuet6GEadaJNRaF6Kd4IfZ_XHQSOUBiu0jv9Q,738
+mypyc/doc/tuple_operations.rst,sha256=UA1ry-YZQDoXGxVmzRYehyvVs_HMHZfjIKMXhq5vQLA,732
+mypyc/doc/using_type_annotations.rst,sha256=1U7GeujG46so5sQj1QpQmaM1TM_iTwfthfSB2ULJO7A,14274
+mypyc/errors.cpython-311-x86_64-linux-gnu.so,sha256=kIdy9CtC-wL38rjh4LrwRBcY-TdO-TazY0HvlsXP0Hc,8016
+mypyc/errors.py,sha256=0peshMAH657cILI2cTPGCMrGZIbfy9DchbDdmqVjtWU,945
+mypyc/external/googletest/LICENSE,sha256=lwLefkEXqOKyDa-rEf_aWMGYrt4GZAZJa-9nDUCiITg,1475
+mypyc/external/googletest/README.md,sha256=U653TFRb1xzoRcOl0nc8aQsaa9MOKNq3eeUg-MG-3VA,10524
+mypyc/external/googletest/include/gtest/gtest-death-test.h,sha256=oEAXpmp8n6BNppNEOdWJ5SFx6TsTHx9Ooilzu6pvd7A,11523
+mypyc/external/googletest/include/gtest/gtest-message.h,sha256=ZinCUfHjDlLyLei-DRUMLEO3v2x1iO6Dse8IaRvcIQo,9186
+mypyc/external/googletest/include/gtest/gtest-param-test.h,sha256=qfY-n6X0BZJmdAgfgtEl2e89jco1EKIeNCZ4SFxLOlI,77062
+mypyc/external/googletest/include/gtest/gtest-param-test.h.pump,sha256=NpyIfKfS1aiReGrDVwF0g1kZfb7H46dnOx2V1LL6OzQ,20042
+mypyc/external/googletest/include/gtest/gtest-printers.h,sha256=4xoLRppoMmDFco3penSRrfIfeniw8rwNrUbEKd4nF1k,36806
+mypyc/external/googletest/include/gtest/gtest-spi.h,sha256=URXVqM7TaiC4zsA0gS97DSrCDVEaFH-b7qmw7yfZS1Y,9952
+mypyc/external/googletest/include/gtest/gtest-test-part.h,sha256=UbiqNBwPxmdu8nwpcwv9ist_EVH_6z1iWdwC-E4m1lc,6509
+mypyc/external/googletest/include/gtest/gtest-typed-test.h,sha256=Z86zBBVbIko-TQUfa3UTwrPFUEqBfdSbUbyCFZ3PXyA,10459
+mypyc/external/googletest/include/gtest/gtest.h,sha256=YR-JIlT5RmQ_sfoFo4LZMgPrbcnQTS8RZmHY9bprHfc,85459
+mypyc/external/googletest/include/gtest/gtest_pred_impl.h,sha256=O4O-7-rsRr_-QPxziHCzEKhlF_9DahV-TH5dzVGUrWU,15145
+mypyc/external/googletest/include/gtest/gtest_prod.h,sha256=Spmj2YakW01tmzr1SAnwFcVKqYJ0eTpK4XP1AQ0K0zw,2324
+mypyc/external/googletest/include/gtest/internal/custom/gtest-port.h,sha256=bxpA0nM8YLVd-LFDycgUfpSw88hFonF-tFxCnY-VizI,3143
+mypyc/external/googletest/include/gtest/internal/custom/gtest-printers.h,sha256=UhZH8767CA5tdvbOuXaTdySmVroCsqSR6ga4drHSk7w,2099
+mypyc/external/googletest/include/gtest/internal/custom/gtest.h,sha256=d9pZKYTaGQGi8ZrlaG8z8j5_5ma27M7WyQYH9CsfV9k,1995
+mypyc/external/googletest/include/gtest/internal/gtest-death-test-internal.h,sha256=pH-Yt0nFOuGSo9UOMpouliTV_jLfQt9pISjxeiNz_qs,13429
+mypyc/external/googletest/include/gtest/internal/gtest-filepath.h,sha256=ITSxHGDTFSN-jrr5WsTsR6X8SK41zCG-I4v3XmTdUSM,9603
+mypyc/external/googletest/include/gtest/internal/gtest-internal.h,sha256=k3o-3UCdXmdGL6iR6BnultJQSm8q-y9ynBkCBdh2f_I,47284
+mypyc/external/googletest/include/gtest/internal/gtest-linked_ptr.h,sha256=E1eNfe1J3hQOvx15nt5TXy7Xr7DDxhUcHepURGNjE6w,8424
+mypyc/external/googletest/include/gtest/internal/gtest-param-util-generated.h,sha256=M080D-k0YIwk0URIfMIuVmNX4wl24cks6FoARFPdr-k,192177
+mypyc/external/googletest/include/gtest/internal/gtest-param-util-generated.h.pump,sha256=1vBEXfV8A9hDH8UZGz7O0OIC4c_tOkW7xHjMBip_gX4,9107
+mypyc/external/googletest/include/gtest/internal/gtest-param-util.h,sha256=s2epfRNAs6GAYFD44u0YEjMEFTCj0vL3LguF_gB4dLg,27892
+mypyc/external/googletest/include/gtest/internal/gtest-port-arch.h,sha256=0w_3w9C720YzqfrUfRKHLFV9e_40sgYTM8gzDM7ceiE,3471
+mypyc/external/googletest/include/gtest/internal/gtest-port.h,sha256=UzvP2W4v_SY3iKh56J_tICcS7xWdxvPwOpTfJdzSK3c,90022
+mypyc/external/googletest/include/gtest/internal/gtest-string.h,sha256=b3V_AjXC4N96oGvKZNDQWlsoJsHFzHT5ApjUaN9QtEQ,6968
+mypyc/external/googletest/include/gtest/internal/gtest-tuple.h,sha256=tWJY6_-meMw_DO-_yLRK7OBuCZw-mfaZQBHzvMLWFOw,28617
+mypyc/external/googletest/include/gtest/internal/gtest-tuple.h.pump,sha256=dRNxezLu4o3s-ImlghK6aHwlH5Lw1eyNDwsLRvRId6g,9620
+mypyc/external/googletest/include/gtest/internal/gtest-type-util.h,sha256=fCjK3R_2eofApDo6BtW-2YGaegpfKQIvtpK5iRDs4fM,185666
+mypyc/external/googletest/include/gtest/internal/gtest-type-util.h.pump,sha256=hnSm--oNlLE4imhstBWvnV1NwaSc8pLhRXefDCFO-f0,9317
+mypyc/external/googletest/make/Makefile,sha256=uEze2Zn577H-Noy4YpRoBUKk0MUWRaEvioyWKyp95f4,2045
+mypyc/external/googletest/src/gtest-all.cc,sha256=VorBGfXmQY8fvPvfGF1yRlfX81ObR4ItoimsXQFWJrI,2161
+mypyc/external/googletest/src/gtest-death-test.cc,sha256=dMzpg4yQnBrtozU4BLDHPLXS-cvedFhLT_vCGmw1rQo,50942
+mypyc/external/googletest/src/gtest-filepath.cc,sha256=05oi5GoRLWlzPzaB5j4YmOkBneI5sctPTGGtesLotYA,14553
+mypyc/external/googletest/src/gtest-internal-inl.h,sha256=CZx7w7raKAVq1INo4ziPFuZSvurmXTbq5ppdim7D4Qc,45475
+mypyc/external/googletest/src/gtest-port.cc,sha256=zGE4VEMYbGEqFw0YfZdtnq2qJ7RigoOWwHWyNsEdQKk,42985
+mypyc/external/googletest/src/gtest-printers.cc,sha256=TisATnhXjqHwvy05beB8qTuRYuF0h8etw09mslZLwN0,12625
+mypyc/external/googletest/src/gtest-test-part.cc,sha256=CIP7dtg-ULF6U-ylbW3n5l_MHTmB_Lc24Sm59dAyfAk,4163
+mypyc/external/googletest/src/gtest-typed-test.cc,sha256=vzF19TTkXlZeegs7mur5dLCnLRqDwoChUKAfvGV39AI,3960
+mypyc/external/googletest/src/gtest.cc,sha256=paFL0Z5CjSmSTB-FqAR5zi7AcVShmdLpL7_rTS0Fz-8,195751
+mypyc/external/googletest/src/gtest_main.cc,sha256=oTO8TSAEXgIZqqJEFhoAJuN0h0pVsRZ6JZGYjr-_x18,1765
+mypyc/ir/__init__.cpython-311-x86_64-linux-gnu.so,sha256=nDpBWdJlxDQoE8ATSTP_I-4Ab-5mgT1aZ_fuLpV_5Kc,8008
+mypyc/ir/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/ir/__pycache__/__init__.cpython-311.pyc,,
+mypyc/ir/__pycache__/class_ir.cpython-311.pyc,,
+mypyc/ir/__pycache__/func_ir.cpython-311.pyc,,
+mypyc/ir/__pycache__/module_ir.cpython-311.pyc,,
+mypyc/ir/__pycache__/ops.cpython-311.pyc,,
+mypyc/ir/__pycache__/pprint.cpython-311.pyc,,
+mypyc/ir/__pycache__/rtypes.cpython-311.pyc,,
+mypyc/ir/class_ir.cpython-311-x86_64-linux-gnu.so,sha256=B5KNl6wPrPQfiYCGVoaeO_qFjGjjUExTLdbfb83a5EA,8016
+mypyc/ir/class_ir.py,sha256=Lqpv0xF1Hc63d2PHQ-UWrLejpHR74RFHVYPN5KwEOUo,21398
+mypyc/ir/func_ir.cpython-311-x86_64-linux-gnu.so,sha256=deAdKVgQNXIiE-jvfjHnfslCDi9L6CfXVcoiY0vji0c,8016
+mypyc/ir/func_ir.py,sha256=Rjv1WDFjvqkofDiQJiaGCZdhQUT5fm-T0Dgnlw7kQv4,11705
+mypyc/ir/module_ir.cpython-311-x86_64-linux-gnu.so,sha256=bWGBhvko8NVAVvmYTimdVMfO5Xe7E1XlV9iCoYW2LmQ,8024
+mypyc/ir/module_ir.py,sha256=SihVUwh0OcDQpAgCzY3SRaHltCV5YZTZBLdYz6YHjxM,3222
+mypyc/ir/ops.cpython-311-x86_64-linux-gnu.so,sha256=i2UeMbeZdbn6i-dH1owHJZ1SHlXOZTLyKPmRXcUDK44,8008
+mypyc/ir/ops.py,sha256=9JkTbXU5XD6BwyCaKi2YTxwei92VxHgRgYJ9e7OUhNQ,45951
+mypyc/ir/pprint.cpython-311-x86_64-linux-gnu.so,sha256=kOu6cSnWQSH9VVj7qwE6X5YfKNplxeOEcfm8hYmRlyA,8016
+mypyc/ir/pprint.py,sha256=fNFWdkZI0qU61-jdub5Ds90rUY8NsFFizh5NcxFm8-8,17146
+mypyc/ir/rtypes.cpython-311-x86_64-linux-gnu.so,sha256=EcZjl1ImPba1LNBBO7dGUlX74qVGdEIg75zyeP6eNmc,8016
+mypyc/ir/rtypes.py,sha256=zrdtdBbyiFwGbFbZ-kxDZqK0d8b5EfOQpN8AgrQ2-Q0,33428
+mypyc/irbuild/__init__.cpython-311-x86_64-linux-gnu.so,sha256=mmSflipj9Mt8hI1pyHDex0_jycp-cbVwB_Dxc7VYr5U,8016
+mypyc/irbuild/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/irbuild/__pycache__/__init__.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/ast_helpers.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/builder.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/callable_class.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/classdef.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/constant_fold.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/context.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/env_class.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/expression.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/for_helpers.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/format_str_tokenizer.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/function.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/generator.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/ll_builder.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/main.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/mapper.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/match.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/nonlocalcontrol.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/prebuildvisitor.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/prepare.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/specialize.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/statement.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/targets.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/util.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/visitor.cpython-311.pyc,,
+mypyc/irbuild/__pycache__/vtable.cpython-311.pyc,,
+mypyc/irbuild/ast_helpers.cpython-311-x86_64-linux-gnu.so,sha256=nvtWnmsaPHu6a-OM6O8hEedegVGmZ0WznY24g6cVXFA,8024
+mypyc/irbuild/ast_helpers.py,sha256=wlIJOXi3fOPfX3_kXXYvMcw7qQZECqZ3PwyHhIAtpnY,4239
+mypyc/irbuild/builder.cpython-311-x86_64-linux-gnu.so,sha256=Dy5C-G1pWtlrOOUxr6O-_s03T1OdKrKLX1SlHAFFJhI,8016
+mypyc/irbuild/builder.py,sha256=J13FkQeGwh0jHfpAwgPVkbG1jwnUXTPp-l7Jjbs30jU,55790
+mypyc/irbuild/callable_class.cpython-311-x86_64-linux-gnu.so,sha256=MbD6XGAUtGZvQowtImiDBUZZVkpNhsMzGJpV6q7ZHlA,8032
+mypyc/irbuild/callable_class.py,sha256=xXaBjVUwZ504xaKRie8ECjRoVoTjIxZsfUfueCkPI2o,7319
+mypyc/irbuild/classdef.cpython-311-x86_64-linux-gnu.so,sha256=-iXs8hK16DO5K28nI6EffPakZ14wDv6nsEFEr5Tuz6U,8016
+mypyc/irbuild/classdef.py,sha256=Qa9nq8O8LBWpGrfUJXUSrihQhWpMD57LVcOHjuSzYQQ,34040
+mypyc/irbuild/constant_fold.cpython-311-x86_64-linux-gnu.so,sha256=nlQTsDTAMlBdNoxSdkGGJzC-HQ3X3AUiSoHu0GeiqQM,8032
+mypyc/irbuild/constant_fold.py,sha256=uvrLBOm4rhZGkIADlGQA-BTGUNFbBMMaEG8yiz8fwpo,3307
+mypyc/irbuild/context.cpython-311-x86_64-linux-gnu.so,sha256=pHtyWNp_4HSnyc59w4wLJsJ5jR8HEJ7Dg4oNpcPhBQ0,8016
+mypyc/irbuild/context.py,sha256=cXVImSH1tzkDGjFsWdus3nLgXb6tW3ajoakkQFqjHYk,6643
+mypyc/irbuild/env_class.cpython-311-x86_64-linux-gnu.so,sha256=XP7aj1Zd6Yrlpk2Ibsg0a1utZgtj7XNZpX2_Huple9g,8024
+mypyc/irbuild/env_class.py,sha256=0lG8menRA5k0Ho3HZyq320ujK2buiQKkdBWEmEtJwjI,9107
+mypyc/irbuild/expression.cpython-311-x86_64-linux-gnu.so,sha256=yvinqdBZbd4fYaZJV5f0z2o1dFp9AEpAIQXksVq2BFs,8024
+mypyc/irbuild/expression.py,sha256=8lxgJ5YOuP1pQ2Ev65VkfPtxWO6FcF5GTi5DChQsfmw,38669
+mypyc/irbuild/for_helpers.cpython-311-x86_64-linux-gnu.so,sha256=UNS9KNVYXeHh2_Zv7Vbx9iTwKoEJJLIVmTxkmYZD0z4,8024
+mypyc/irbuild/for_helpers.py,sha256=BcFF7kMyY-lk7FF90Xrg3KPKCLXpluWrQSV9vFInTBg,39520
+mypyc/irbuild/format_str_tokenizer.cpython-311-x86_64-linux-gnu.so,sha256=e3fpmNSHKl65If4m-rV-aLO_-OGXniL1jEt2D__xDtE,8040
+mypyc/irbuild/format_str_tokenizer.py,sha256=d0mH9h6zkSVZzp0KBvFZYyh2E20i5Rfgz2iZtc6Cb5Q,8740
+mypyc/irbuild/function.cpython-311-x86_64-linux-gnu.so,sha256=fAJPYRBS0oynRP8ILijh5Cw9BRCkFrEOJofXTpNztyM,8016
+mypyc/irbuild/function.py,sha256=31eZlLoOjPUfUSpTjEja_Q5VCOiJDRL3qilDd3K6Fn4,41812
+mypyc/irbuild/generator.cpython-311-x86_64-linux-gnu.so,sha256=CEaQeZsd0UxxjXLXLO7lAdgxn2G1QQtDZ8uZ2Tqm0DE,8024
+mypyc/irbuild/generator.py,sha256=0dS-pPuIDxJglr3Y34mOvRjj5GgaRQ4sL2Rw_lOeGys,13595
+mypyc/irbuild/ll_builder.cpython-311-x86_64-linux-gnu.so,sha256=zpgYtaTqzjfxwuHyRJsWbiaigeAlOx7hLip4_5XB3NM,8024
+mypyc/irbuild/ll_builder.py,sha256=0Bf90UjOLBsMmSHqsqUpDnqpKdeP8Co85BK1Wtjp7fM,100339
+mypyc/irbuild/main.cpython-311-x86_64-linux-gnu.so,sha256=LZrQU3eGk8dOkY_HY1wzKiBlrFNbE5uPwvoJ1lrBJ_8,8008
+mypyc/irbuild/main.py,sha256=tW41NsTmuxX7E2kBzYLL1KpvsSGQiA_wOsKSGISnVcU,4687
+mypyc/irbuild/mapper.cpython-311-x86_64-linux-gnu.so,sha256=VVU61gvmlInn00rJONf0c0svq2Nag38OuDbLFfG6F-M,8016
+mypyc/irbuild/mapper.py,sha256=R5TOg3TbCohnoGlArf_8VHBACkrZY9F9_29B2z10Z8s,8550
+mypyc/irbuild/match.cpython-311-x86_64-linux-gnu.so,sha256=6LoPjlaZAnzznE-ynRJiqPTmr0jpylTry6kF5kXhgqY,8016
+mypyc/irbuild/match.py,sha256=dRnM95b5JFFAO3GxD-3OhvbsN0dM3oOBOPJaxFiuvvU,11977
+mypyc/irbuild/nonlocalcontrol.cpython-311-x86_64-linux-gnu.so,sha256=bEBlzxEA_hjEz2kTbB0Ehcxkghcn_G8ru4WbLh888Xo,8032
+mypyc/irbuild/nonlocalcontrol.py,sha256=7AN24AR7_sm9SESO5HkxMLGHxQk31citmcL2lJIjvIA,7224
+mypyc/irbuild/prebuildvisitor.cpython-311-x86_64-linux-gnu.so,sha256=3WsD0LrwWcqtFaITAq1Q6aGBHH7PGp6x8tD-BjIWQ2M,8032
+mypyc/irbuild/prebuildvisitor.py,sha256=7dkJztN22BsYXkivYfzrzVonACtKBZBMo0adli_iqqA,8042
+mypyc/irbuild/prepare.cpython-311-x86_64-linux-gnu.so,sha256=MdkKPouqqQEQLQ7zZMW-mYJYpfn6VTSsbGikIjWMj9k,8016
+mypyc/irbuild/prepare.py,sha256=x32mqx_ZC6E7I2hReJ8odhlf5jgjoEQ2CzVbPS8ja7c,24771
+mypyc/irbuild/specialize.cpython-311-x86_64-linux-gnu.so,sha256=kvMzVjinODOd3RUcveXaXWYUy1gtYmvS7A3NXW63V_k,8024
+mypyc/irbuild/specialize.py,sha256=h0Uc1_MjF0qjGwVQr1_XF9g5puWzhNgNoHoo7rnil8s,29249
+mypyc/irbuild/statement.cpython-311-x86_64-linux-gnu.so,sha256=2ozBP0bN8C30Pw8cGLkm2c50Wg0T8Xu4b_Gz1xBIgRU,8024
+mypyc/irbuild/statement.py,sha256=MTnyt9mxXwkSBedE4npuqsD427d_5nEhR0OcvGrfQsI,35303
+mypyc/irbuild/targets.cpython-311-x86_64-linux-gnu.so,sha256=36oc8D9haWIUKFIAnnQwR4JLrk-xvca9xyqhxwcKzGs,8016
+mypyc/irbuild/targets.py,sha256=QmIjNRbZVgWFXlN8N-_9UgWxzP2w1ba2aIBa8dg73Ro,1825
+mypyc/irbuild/util.cpython-311-x86_64-linux-gnu.so,sha256=t0OVPMT5jCdBhjIQadS8pz4Nv_JF5_spMJFInMv8hLI,8008
+mypyc/irbuild/util.py,sha256=wCEeShIvXNlIOV8X66JmT4bQN1sv_e31UbMUD_jscVw,5722
+mypyc/irbuild/visitor.cpython-311-x86_64-linux-gnu.so,sha256=ZiOkpoWPwRmwnm_gJxuRQDx32qYNieargVW157bDvOU,8016
+mypyc/irbuild/visitor.py,sha256=tx5wdNmLPYFsSUwc3N_u_d49GKZJ-SPdZtuyZgNGeo8,12626
+mypyc/irbuild/vtable.cpython-311-x86_64-linux-gnu.so,sha256=D6HEsk6IkG36nbn0HffKNmj0c5eNcYVBPXfNRdgF2M0,8016
+mypyc/irbuild/vtable.py,sha256=nuibAGp_OVSxX1Mpwq4qRPV92k1d5TrczwGNzkNMQk8,3304
+mypyc/lib-rt/CPy.h,sha256=ZFAI0hoHJqBgPN_3jQaKbZgX1TEEr6688D6-xsn4ugg,24051
+mypyc/lib-rt/__pycache__/setup.cpython-311.pyc,,
+mypyc/lib-rt/bytes_ops.c,sha256=CJLRRdkStkYlYfs4K_l_3Bh40fM5w6qcU-4RuE6deVM,4914
+mypyc/lib-rt/dict_ops.c,sha256=gGsa_sTqhTvBVesCGr9OVcljaU6gKWxb_FQdXdF6q7g,12681
+mypyc/lib-rt/exc_ops.c,sha256=thwzyDvdb_jg3UdVlL0rqGSPIau-p1p_9P2aSuEkW1U,8283
+mypyc/lib-rt/float_ops.c,sha256=37WK_fIsnPqm2W16BJiWlX3JZlZHJNGvS5LKWJz-A7s,5017
+mypyc/lib-rt/generic_ops.c,sha256=rMTlTphKs6parq9DFylBOG5V8M5F_ZjFI2z0iwBY6J8,1844
+mypyc/lib-rt/getargs.c,sha256=AQTvAS7LNn7ajr4ZwcZrhKHu9sD_gu2B2aC0cjY8Jis,15739
+mypyc/lib-rt/getargsfast.c,sha256=UQ-45NrXyAJzmB4UNSumRogyLLUANNTS3dqZrJsupt4,18812
+mypyc/lib-rt/init.c,sha256=yeF-Uoop1jMX1-ntOOO8-YQiW_7evfdAjyVkWAw-Ap8,473
+mypyc/lib-rt/int_ops.c,sha256=URcI1LVjcDXLy8bA6Lnx9CR_BG418Zq__ov54O1scaI,24673
+mypyc/lib-rt/list_ops.c,sha256=avqCw7AuKkoCfgFe4FvgHaA9liSEzwDLxf_87PSMXcQ,10049
+mypyc/lib-rt/misc_ops.c,sha256=9GT0HVeUbVoAhFILEEIVXoayWTf7yjLObWbUHrXN4Qc,29536
+mypyc/lib-rt/module_shim.tmpl,sha256=jOXsy3GTuo7uA4hBCNWWAZrwSz03Gc6EHiJR--t7PkA,522
+mypyc/lib-rt/mypyc_util.h,sha256=xfvyVqKXRlBuqeh02lDqV1e5HPGlJ8jT449GoYVv_XI,3692
+mypyc/lib-rt/pythoncapi_compat.h,sha256=spH18KGaQTg6CP-VbEgmfQ_R2Q7xGFRclzyl676rTMA,13662
+mypyc/lib-rt/pythonsupport.h,sha256=U_F6x172Sm85Eoh0BzuN4sK4L9P9PWU6tQH3O7arwmA,15167
+mypyc/lib-rt/set_ops.c,sha256=-fImDML6Aobq7-NCbb28O19g6C2YyHkGJ6NF1gueHJM,351
+mypyc/lib-rt/setup.py,sha256=JSmjV4gQe_wObsoBRLN4LajdzpydWi44YbfYbzKWH_I,1133
+mypyc/lib-rt/str_ops.c,sha256=jUdLnZVrMhEWVDbqQdWYIewEi7LLEtEvcMPUaW0NTxo,8074
+mypyc/lib-rt/test_capi.cc,sha256=m9BcwiGWaegosfT5WOIhnvAlv0tMMTAIxCTUNDRMRd0,19484
+mypyc/lib-rt/tuple_ops.c,sha256=xodLF2mCIIknpFZy-KHoL2eEVdKUh5m8rmTl0V2hQnE,1985
+mypyc/namegen.cpython-311-x86_64-linux-gnu.so,sha256=K9Pt_P4gv3I_MZ2XG50oMLsQvSJM1hNY6-CFytUmaVY,8016
+mypyc/namegen.py,sha256=lzE0Ayjs74N4xU9ObiVyZBJ1QnNrdE9sMHapbJHKKyY,4372
+mypyc/options.cpython-311-x86_64-linux-gnu.so,sha256=VyNU7picxxVqPxCgwjX9H-Jq8y_Rj3LT1zMwYcgvyz8,8016
+mypyc/options.py,sha256=6eXorVbf8VMSPO92mcP3nHGPFN2hwiGpo12DRGmSqJs,1158
+mypyc/primitives/__init__.cpython-311-x86_64-linux-gnu.so,sha256=TR3yVIIKvJWN3MJayrlXpYDptKO3dYo1L9HcFQWUckE,8024
+mypyc/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/primitives/__pycache__/__init__.cpython-311.pyc,,
+mypyc/primitives/__pycache__/bytes_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/dict_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/exc_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/float_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/generic_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/int_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/list_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/misc_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/registry.cpython-311.pyc,,
+mypyc/primitives/__pycache__/set_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/str_ops.cpython-311.pyc,,
+mypyc/primitives/__pycache__/tuple_ops.cpython-311.pyc,,
+mypyc/primitives/bytes_ops.cpython-311-x86_64-linux-gnu.so,sha256=zUwAWe-NE5I8qI25D75iZkSoA_qsmebKxzE3It5MvR4,8024
+mypyc/primitives/bytes_ops.py,sha256=KDUPvnYS1DTY0DQ3sVux5vvykpi1C2sSZTNdXqx2ITk,2425
+mypyc/primitives/dict_ops.cpython-311-x86_64-linux-gnu.so,sha256=EOOmdzC1riyY45sCFd1puYvac5GoA57UaDk-LS7SSsQ,8016
+mypyc/primitives/dict_ops.py,sha256=RtyIrLIR0hRjZa9eZhyLO2H8T0iQVR8XZad5DPXuNnQ,8220
+mypyc/primitives/exc_ops.cpython-311-x86_64-linux-gnu.so,sha256=vH4Wc9FZj2tOvhEpbi6LvhtbkLREqEZ_or-V2LxRNg0,8016
+mypyc/primitives/exc_ops.py,sha256=9CRKfNJ3BlezzE3VnWxCvY-SyG4YFRr007GYMDHk9ag,3284
+mypyc/primitives/float_ops.cpython-311-x86_64-linux-gnu.so,sha256=e79Dz9-Yfu9bu80GM7ZMrSdOijbudFYrlUSM_DbgrVY,8024
+mypyc/primitives/float_ops.py,sha256=3q30iwOlSKchTu2ak77lvy9W5EIPoLjm_qTjOmQB_6g,3838
+mypyc/primitives/generic_ops.cpython-311-x86_64-linux-gnu.so,sha256=EGGeyzRoxtsBlIRxvzNjq_Ilbq8M28RgQ3IWlAqXT1I,8024
+mypyc/primitives/generic_ops.py,sha256=o2hgmZ0GXsfvn-tEbdbDF-LTw3PK_Ja-znymGE6lGnc,10523
+mypyc/primitives/int_ops.cpython-311-x86_64-linux-gnu.so,sha256=8_E-_zmdmnayP0R5NkIKH0lezRprs7588lmdtuYmvcw,8016
+mypyc/primitives/int_ops.py,sha256=ARoNvliSE1vy22qZi0EKtGn6zBOldgkS7x1_hZEkbbI,9279
+mypyc/primitives/list_ops.cpython-311-x86_64-linux-gnu.so,sha256=vGAll-2SMNHs2sQpsGV68Xr_W1NX5ukvefInJoiZlpA,8016
+mypyc/primitives/list_ops.py,sha256=CRJnx2T-LSJZ-5d_5M7NHolCjERJ0J6dcnIsZDwLnCs,7491
+mypyc/primitives/misc_ops.cpython-311-x86_64-linux-gnu.so,sha256=6pOsLRvqj58PjdnxIHOf0oQjQW8XQJPZSjA5QsStUZw,8016
+mypyc/primitives/misc_ops.py,sha256=AOE6HgMIYtR7bcok67b1MF8Ryl03AWpmVNPYQ8qZv-E,7576
+mypyc/primitives/registry.cpython-311-x86_64-linux-gnu.so,sha256=B0S4RgsgINiE3ZTZzddjbKTxAgd9CcV9R5Lrg38rnz4,8016
+mypyc/primitives/registry.py,sha256=OnFfFN4XvbOc6ZMWJC9_NGvw8oJRCnuxnEHEdVqP-C0,9649
+mypyc/primitives/set_ops.cpython-311-x86_64-linux-gnu.so,sha256=9EPXXpjlYT0xQ9nAN9Yrv88SIGLAQrT0sGUbWqXy6lI,8016
+mypyc/primitives/set_ops.py,sha256=V2VFyHZHz0oMxfm0uGRhaJdBLycE-i0vA6FzyQvfryY,2774
+mypyc/primitives/str_ops.cpython-311-x86_64-linux-gnu.so,sha256=HahiE_9ajo8MYNrvpjHxpXfLYqLkq0n_VfkO9no5cyg,8016
+mypyc/primitives/str_ops.py,sha256=R3iQ9DVTYzjLQE4hf_hgNMMqnWyaIU0JwXMka_oOKb4,5723
+mypyc/primitives/tuple_ops.cpython-311-x86_64-linux-gnu.so,sha256=d9xF1grW7ZiD-wewb9lENlLZf9WSAj70FMTb71FUz2A,8024
+mypyc/primitives/tuple_ops.py,sha256=8eFeTLcWJOemeFGezgt0LlgKeXCHyLhUXG1uX3r_XtU,2375
+mypyc/rt_subtype.cpython-311-x86_64-linux-gnu.so,sha256=2Ofq2WMH51ae7q7IDdIUx5bBRcWYc4l8ScBix7f9sR8,8024
+mypyc/rt_subtype.py,sha256=rAoZ_IRp7MFVmd_xtbgL6wTeU9h0pxjlYjhldfgZEc4,2448
+mypyc/sametype.cpython-311-x86_64-linux-gnu.so,sha256=VUzLO1F2OxPdKreFmUkVGEYmj5vNf8vWmkSlBnKkxjc,8016
+mypyc/sametype.py,sha256=T3wXw8XjNk-W2W2CW9giAjYtFYdrh2HBjsam9-jwvmU,2464
+mypyc/subtype.cpython-311-x86_64-linux-gnu.so,sha256=Nheu7Y2tMASEQY5tFl9ma59ejSN1K8G0okDMwfLq3iY,8016
+mypyc/subtype.py,sha256=Tg3pYSXWBiDRMHKnfgDKPFiFyPYHiShnnA1vOhkECbg,2757
+mypyc/test-data/alwaysdefined.test,sha256=_HZG3I9dg-SDwexC812QiEXTere50UjwK160Pij0X8I,15266
+mypyc/test-data/analysis.test,sha256=1t-1MxefLi3XHzan_hF-tFbW0sp3K4YjCZH6lCTiFpA,13799
+mypyc/test-data/commandline.test,sha256=Z-in5HZ4yZrEcMRzOZnqEi-XEONQtUWuPPfBMBWhB0k,5517
+mypyc/test-data/driver/__pycache__/driver.cpython-311.pyc,,
+mypyc/test-data/driver/driver.py,sha256=AVo8AqvNNvYmuAhKULgwpVa9wq4VyWzSXUhU5MerJrs,1405
+mypyc/test-data/exceptions-freq.test,sha256=rJoHRfL3-OxL5K5hPssN98CSAVvy2zOyqupu-jUcfGg,2135
+mypyc/test-data/exceptions.test,sha256=X9-8rnzT7G2RcR2YqW-GjutrHdsj5QLEKSuqgp2_b5g,13123
+mypyc/test-data/fixtures/__pycache__/ir.cpython-311.pyc,,
+mypyc/test-data/fixtures/__pycache__/testutil.cpython-311.pyc,,
+mypyc/test-data/fixtures/ir.py,sha256=UjnkDyVHGNoDnY0LKDDp77KS5nHQG0WsE1Ryn653aNE,13995
+mypyc/test-data/fixtures/testutil.py,sha256=alt2YuCvuOrRJIwspAm8-z2CPbVZVZFgHTzi296AhNM,3022
+mypyc/test-data/fixtures/typing-full.pyi,sha256=lpMSYyc7pqwTdXaYj_17aMlQbBSJ3m7XA4vQRy4R0oI,4969
+mypyc/test-data/irbuild-any.test,sha256=ArqXUkLB9-ifGbAyT5oj1Btko7Mr5lbnV-0O2iZrh3o,4357
+mypyc/test-data/irbuild-basic.test,sha256=-X_9nHpJhO968_2PG1za4xL0UcJR9S0FrZMx7LOrH_A,70628
+mypyc/test-data/irbuild-bool.test,sha256=44q00ARXkzIEKXQP4jq8Gm29vZqaIrMnQRN-pFphFiI,8403
+mypyc/test-data/irbuild-bytes.test,sha256=wWqmkJh9vFQrcvGBWBUDy8Hhay8DoF1HE2Cwr8NTsvQ,3669
+mypyc/test-data/irbuild-classes.test,sha256=RId-qq2pe_rJnVmpQP5UUie7OEoHM8kurFOhGP6nXnE,25611
+mypyc/test-data/irbuild-constant-fold.test,sha256=t6EHwrg2KF7mV7J5TubiJInmp-VZ8LoxlJOoSiQ9J1Y,9765
+mypyc/test-data/irbuild-dict.test,sha256=BpD5YmavBSjlv8wtCmAoxX_vYjLgS-YUPi_EydG9bUo,11152
+mypyc/test-data/irbuild-dunders.test,sha256=9H689nlQXn7WGeBx5pLWMy_jWOKtXutQ_Ukp8Gk8wH8,3682
+mypyc/test-data/irbuild-float.test,sha256=cXUP_fDKbu8f82bhYNkJgH_Wb20-m9FO3YjtTirjU2Q,9321
+mypyc/test-data/irbuild-generics.test,sha256=oTCglW1n0t-ER4-xZGG6ipxFbVL4gECcTySYaNYD4Z0,2676
+mypyc/test-data/irbuild-glue-methods.test,sha256=saSWPCS7N9nwCm0wln37e7dsJHSlXEcD92s0PHFsdts,9679
+mypyc/test-data/irbuild-i16.test,sha256=FjFrtPo-NZEAg8HqZt356uczfxaESWvDcFXzsELn6pY,9145
+mypyc/test-data/irbuild-i32.test,sha256=h2sqKgkw8bHXLFnY6LWMuug0_OEc2j4K4D3gMmndXis,10256
+mypyc/test-data/irbuild-i64.test,sha256=_cJdLZwvtF5RwsznXVcNSODfKxYQBAaSCmT0zTJIP-8,35838
+mypyc/test-data/irbuild-int.test,sha256=dxi0hdKwfnYjbAGc_RMQbS5ySp5_a3rmQinRrNBOmSU,3634
+mypyc/test-data/irbuild-isinstance.test,sha256=iXTsqLqTIA8UHmFfUWfgW8MS2OBTOJDDRAiomRubmQE,2281
+mypyc/test-data/irbuild-lists.test,sha256=Yv4r2Wvm_XF5fs8Aw7CH0fE1KJv5a3LhE7xiTvBZpwk,10559
+mypyc/test-data/irbuild-match.test,sha256=HM3VC9UEZn0GJZF0WkPX6B6h6pWeV6fcb96YqCRLTvk,34938
+mypyc/test-data/irbuild-math.test,sha256=fYR0xPO4XjLoE1MHIvcSq_jwgCZ0pNFKxtsFFCdpHNA,855
+mypyc/test-data/irbuild-nested.test,sha256=-CZkKvz3UFINotaJ8519Myu8cfzGxjE67tjUCPjy4bM,20164
+mypyc/test-data/irbuild-optional.test,sha256=YTluUUnzMstk_ySeiQI1R1HQjtL_2J5BggphmcgPIkI,9166
+mypyc/test-data/irbuild-set.test,sha256=jU-Tq1ydjBhjvVYSc90FI4c50e6VoHOAa7oMKg40Sxo,15826
+mypyc/test-data/irbuild-singledispatch.test,sha256=oQlvEbGqrkDqUAmEDC8vjcRZQXsI9hEu8GQ6IbJm5j4,5700
+mypyc/test-data/irbuild-statements.test,sha256=hSZ0oyXxPCxTsCA4xfUUT6o7M3k4yqNmURczaslS6dQ,20236
+mypyc/test-data/irbuild-str.test,sha256=TV2JqXJRA84r6RgSlwOM0ESRj_PrJq-QdQnbw1otawQ,6779
+mypyc/test-data/irbuild-strip-asserts.test,sha256=-00qr21AtEcp1-PWanXoWLevyvuUjo498s5G9ChnF0Y,152
+mypyc/test-data/irbuild-try.test,sha256=D2gDS2vNcKqm1Jgl7-1W2M-2XCERlMkZPJtx_U-Ac9w,10638
+mypyc/test-data/irbuild-tuple.test,sha256=G4q0E_QQLT8pv0_5pXu_J4oAintlENZWLTtmQP6rDGo,8613
+mypyc/test-data/irbuild-u8.test,sha256=GE95fm8se7wcKVGKNOBxHv0lq8PgCw_gzPeVjO4-fPA,9272
+mypyc/test-data/irbuild-unreachable.test,sha256=fgEfat_WYWFYgIQ6DYt0I4PD-lv0kf_H0NqkkYMpt-8,2112
+mypyc/test-data/irbuild-vectorcall.test,sha256=qI1hHq_07SsI3kkUFYxYvhzNODC1oiMJQqlw0nXwLoQ,3193
+mypyc/test-data/refcount.test,sha256=gTQpEmOP5umszGA40eeGhFu3t6yohbP-eQlKjZAWCVE,24759
+mypyc/test-data/run-async.test,sha256=Xx0hbeQl1TMhcjUT2zmq07TpZWAbsXfwsRhT8WXmzqk,3360
+mypyc/test-data/run-attrs.test,sha256=FmF5xIdOOOPBgLy1EZjkuLzz3O_xhU5ysnUwW8OfRdk,7472
+mypyc/test-data/run-bench.test,sha256=dCKvWAGTVQrMCYG8cHzGtum05nTBTK6IcFHpDVHP0u0,5633
+mypyc/test-data/run-bools.test,sha256=HyU61eDOIg3BzuBKZGG9dxtg3LG_lys7hd6sLiM5dyw,5360
+mypyc/test-data/run-bytes.test,sha256=FqS1Q64h1KxZ7QzEV9RvRTeYCY2Mf9et5wnJQnAovv4,8619
+mypyc/test-data/run-classes.test,sha256=3KpFZ9Rp3mqk9NRU7-emPfiPo24sPhJZcedjP_WwmQs,49291
+mypyc/test-data/run-dicts.test,sha256=JRXJLCNLhM3Ho1Zcm5QYvOUoV45hxFejm0Jjv3KsU2c,7793
+mypyc/test-data/run-dunders.test,sha256=TtVjK9mC4L0sNPFdQoeA2SJ0v81bdS-4bMQ0mjOtrw0,21000
+mypyc/test-data/run-exceptions.test,sha256=7QzUa1VjaR1xgTNevaUNNaw443rxjoKawSlFT41rQiw,8038
+mypyc/test-data/run-floats.test,sha256=GfpYrgHiAimumP_71zEnzmvRdbkUTmKR1qc8y20gaso,13551
+mypyc/test-data/run-functions.test,sha256=hCXMaZk6eAmMNUCy6IQQZ4IHeUxEPuKyR1dD5uICpic,30039
+mypyc/test-data/run-generators.test,sha256=AjV-s6eCfInyxzGEbzEaxKJzPvrOjHCH3cWJLOiWifk,15644
+mypyc/test-data/run-i16.test,sha256=-ULlpY1hIGqdIsm4WVYNZ4EM_gcFKt-mRV8GeX4C_jw,9306
+mypyc/test-data/run-i32.test,sha256=iP1Rllu3mRfPwH2uc_r-nAF3K-w2Uqx7rGwWW_ca1aI,9301
+mypyc/test-data/run-i64.test,sha256=gcrMCUxvdCmyz5uvySpcqxzc5AUMPHVGCFifM2wkooE,35857
+mypyc/test-data/run-imports.test,sha256=g447WTJ7ifXMLS4WZUep3BO96VTax4mIeGJ_uJs9a14,5294
+mypyc/test-data/run-integers.test,sha256=GuQx7OQ2SGLT4PQa5XV_kfy1TdqLJwlTGWDhXhbxP2s,14839
+mypyc/test-data/run-lists.test,sha256=zYjoa46IorIF0B6LHsZKDTbLRmx8Fl12-5vXGRKHuPs,9119
+mypyc/test-data/run-loops.test,sha256=wxKsZ5bnVvejxoWOOJyGJ25KuEIUkO4Y1Du1ns_Fbv4,9311
+mypyc/test-data/run-match.test,sha256=6fOoGLqRykNO1tqAIlvVNKqy2zx5ketH3i8Ce22-Azc,5103
+mypyc/test-data/run-math.test,sha256=ZWxtzOmMvMbAAYc_X3_E0lQyzCELcs5NdBycbGshrjk,3606
+mypyc/test-data/run-misc.test,sha256=mwtxbYg7jFp8fK443KsZLptSE5FOMnBGar3I7SKLFBc,24844
+mypyc/test-data/run-multimodule.test,sha256=r_V5Nl71zoL5MqlX1UEwWfhpNHf20HQY2kTozX2pqRU,14723
+mypyc/test-data/run-mypy-sim.test,sha256=gEFbly0ydcW6ks-ZlIIRdLrszt1UTH1bqpYiXX5611o,3984
+mypyc/test-data/run-primitives.test,sha256=bmhNzK4hCC3CVg8-bLao3Mbnt55y3RZdStSUOWj9Qwc,8028
+mypyc/test-data/run-python37.test,sha256=s20VHaTRwcQveafl_WJFE4OVOpbee6JG69pUQQF2RxQ,3874
+mypyc/test-data/run-python38.test,sha256=80qSVb1outZVHu1ekex9Ugem_k0mpbY1VAiehbuyl3Y,1970
+mypyc/test-data/run-sets.test,sha256=aYZ4EOBO1c0YuHa36UkCzf-Nn9dPz2w8Rb6EdrGZQjQ,3288
+mypyc/test-data/run-singledispatch.test,sha256=BMMFI5qw566gqCb8y0r_OCYFkJvCogUC9hzhhNx-Avc,14527
+mypyc/test-data/run-strings.test,sha256=utRTZLLE92qUv2p5e3xmSCL_nmm9kcyURKPOkX6wBc4,24090
+mypyc/test-data/run-traits.test,sha256=35wAgnsnDI6rxnF2UYrhW46igBFtJpAdHGKkEcWOsJc,5989
+mypyc/test-data/run-tuples.test,sha256=78bSkpeciu-aKEkmkbLfVSHGn9K0r0rOtkZF_acK_sY,5918
+mypyc/test-data/run-u8.test,sha256=7ltTAz2puFYThjQ9eYbqWe43FSMj2HdozylM06qLvDU,7496
+mypyc/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/test/__pycache__/__init__.cpython-311.pyc,,
+mypyc/test/__pycache__/config.cpython-311.pyc,,
+mypyc/test/__pycache__/test_alwaysdefined.cpython-311.pyc,,
+mypyc/test/__pycache__/test_analysis.cpython-311.pyc,,
+mypyc/test/__pycache__/test_cheader.cpython-311.pyc,,
+mypyc/test/__pycache__/test_commandline.cpython-311.pyc,,
+mypyc/test/__pycache__/test_emit.cpython-311.pyc,,
+mypyc/test/__pycache__/test_emitclass.cpython-311.pyc,,
+mypyc/test/__pycache__/test_emitfunc.cpython-311.pyc,,
+mypyc/test/__pycache__/test_emitwrapper.cpython-311.pyc,,
+mypyc/test/__pycache__/test_exceptions.cpython-311.pyc,,
+mypyc/test/__pycache__/test_external.cpython-311.pyc,,
+mypyc/test/__pycache__/test_irbuild.cpython-311.pyc,,
+mypyc/test/__pycache__/test_ircheck.cpython-311.pyc,,
+mypyc/test/__pycache__/test_literals.cpython-311.pyc,,
+mypyc/test/__pycache__/test_namegen.cpython-311.pyc,,
+mypyc/test/__pycache__/test_pprint.cpython-311.pyc,,
+mypyc/test/__pycache__/test_rarray.cpython-311.pyc,,
+mypyc/test/__pycache__/test_refcount.cpython-311.pyc,,
+mypyc/test/__pycache__/test_run.cpython-311.pyc,,
+mypyc/test/__pycache__/test_serialization.cpython-311.pyc,,
+mypyc/test/__pycache__/test_struct.cpython-311.pyc,,
+mypyc/test/__pycache__/test_tuplename.cpython-311.pyc,,
+mypyc/test/__pycache__/test_typeops.cpython-311.pyc,,
+mypyc/test/__pycache__/testutil.cpython-311.pyc,,
+mypyc/test/config.py,sha256=ZnruYrojiT_ZG4RrYzoESoNTiZY1bWuk0SQ2CFZHTQA,406
+mypyc/test/test_alwaysdefined.py,sha256=r1ar0OGCoZZKBiBY-2GjIyw-5BJz4II2ANziN4SYY6s,1525
+mypyc/test/test_analysis.py,sha256=XOCAxn-pn5a5N_gb02HAtZsLh_eXZDVlkHjVXWOFHWE,3259
+mypyc/test/test_cheader.py,sha256=lAKvmxQadjR3f6yyinrmCe1d_e3tJCf5gb8ew_l8zaE,1630
+mypyc/test/test_commandline.py,sha256=ULYaN9gmgBXwnGUVYIui_x8Ybny3Wy5KKHpuJaeXxFs,2823
+mypyc/test/test_emit.py,sha256=10ApluEgCshILz_EK6xqS2AcEE4mUP3OEGzrKPQZkGc,2840
+mypyc/test/test_emitclass.py,sha256=DE9sG9K-05LjbDvT6CWidDJB-onab7O0t8l2GVhjYlM,1228
+mypyc/test/test_emitfunc.py,sha256=1NVwBqBEPRaOv7NUb9nAO7vn33IJC-YZ-WDRptYcUfU,32815
+mypyc/test/test_emitwrapper.py,sha256=yl-uO-yZLeYf44LzMzltCSnIASbZjAWLVlY5kOjbx3w,2213
+mypyc/test/test_exceptions.py,sha256=CvvGhQybOJxcxzH2lwWJPaxAbthE9aJcROpl22bZ5LE,2133
+mypyc/test/test_external.py,sha256=voULWHFEoqU0W_NgDgtacLqNIjjzci2t5PvK1PNcM_E,1862
+mypyc/test/test_irbuild.py,sha256=AY19Ycj81AtepFslZy3H8R28bHGAN0NcTllCKVtB0pA,2618
+mypyc/test/test_ircheck.py,sha256=OxY-wNKtyD9CMvSRuzPLBrboKPlCOUXI1Ai41e1Jutc,6868
+mypyc/test/test_literals.py,sha256=VospqX81-sNRhInwnnwC81Kzk9z1hr7UsnIDjC1NXhs,3325
+mypyc/test/test_namegen.py,sha256=j0A_uauQ6QkBK-g0zwMVONuQ2Zm-3xTMrxVk6vhd5DE,1805
+mypyc/test/test_pprint.py,sha256=6kfSLDyEvNXPGmdbvDojM4wEdWFoi-6Oh23AHOjx-v4,1281
+mypyc/test/test_rarray.py,sha256=eVIfBeR2t6F-16QXznpycEN5DkRGYAvR-hNbkIkaRPw,1488
+mypyc/test/test_refcount.py,sha256=dZbntAtDE5TAv2wxRRRVaUVaR--8PoHQeDjQooDSPEc,2052
+mypyc/test/test_run.py,sha256=rBKKLzhU5pMYHsBWlZoHvhQwf5G0MnrM5vCZ-ul-Jr8,15322
+mypyc/test/test_serialization.py,sha256=RcY1tx44PKApqinIQGnju3jvbZbYzqqBei68JqbiYEY,4059
+mypyc/test/test_struct.py,sha256=EEfu868uSm1wJmwowq1S_g1wInUaURX8tIhoPqGzs8w,3903
+mypyc/test/test_tuplename.py,sha256=P03_NcIw1n-g4vFOig_aKX5RgLqoBkO3xh7M2Zzerkg,1044
+mypyc/test/test_typeops.py,sha256=FQvUfsjTKL_eIPbBxcchG6zrsVJvgWpb5U316NrvFCw,3935
+mypyc/test/testutil.py,sha256=rd1CR9zeKlc7PQrCUV7xlE6fuhzNzxTSJifOW-YVYpQ,9415
+mypyc/transform/__init__.cpython-311-x86_64-linux-gnu.so,sha256=q2nZgiAyRxVg-fM3n70jlt_u4QBAC5cf_6qzNbCdsIs,8024
+mypyc/transform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+mypyc/transform/__pycache__/__init__.cpython-311.pyc,,
+mypyc/transform/__pycache__/exceptions.cpython-311.pyc,,
+mypyc/transform/__pycache__/refcount.cpython-311.pyc,,
+mypyc/transform/__pycache__/uninit.cpython-311.pyc,,
+mypyc/transform/exceptions.cpython-311-x86_64-linux-gnu.so,sha256=_HWAABabhY7pxwtrd08bAAWLFhtXuif6C_yEDf9NtYI,8024
+mypyc/transform/exceptions.py,sha256=K2z1piHIamVECHwNNgJLKyVpYZMSjEUDn6vStbR8JUk,6414
+mypyc/transform/refcount.cpython-311-x86_64-linux-gnu.so,sha256=V3quHu44tQW7ez0yqapw4EKY3q7PF3YIzHM-BaaUiU0,8016
+mypyc/transform/refcount.py,sha256=K6dPkNxp0m30aKAwSp5CdLktdH6SyQ09_ZkNktlTh54,10013
+mypyc/transform/uninit.cpython-311-x86_64-linux-gnu.so,sha256=cATdymVH5ssCULlMuW9ZWhQIWqcVGML2QPB4KPkzD6E,8016
+mypyc/transform/uninit.py,sha256=YKc6sCp2IB7xPsR8w6r5XJpkHa49V7fxTctb9pvt9tI,6819

+ 0 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/REQUESTED


+ 6 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/WHEEL

@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.41.1)
+Root-Is-Purelib: false
+Tag: cp311-cp311-manylinux_2_17_x86_64
+Tag: cp311-cp311-manylinux2014_x86_64
+

+ 6 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/entry_points.txt

@@ -0,0 +1,6 @@
+[console_scripts]
+dmypy = mypy.dmypy.client:console_entry
+mypy = mypy.__main__:console_entry
+mypyc = mypyc.__main__:main
+stubgen = mypy.stubgen:main
+stubtest = mypy.stubtest:main

+ 3 - 0
venv/lib/python3.11/site-packages/mypy-1.5.1.dist-info/top_level.txt

@@ -0,0 +1,3 @@
+ced4bbd844d3a34b6fc2__mypyc
+mypy
+mypyc

二進制
venv/lib/python3.11/site-packages/mypy/__init__.cpython-311-x86_64-linux-gnu.so


+ 1 - 0
venv/lib/python3.11/site-packages/mypy/__init__.py

@@ -0,0 +1 @@
+# This page intentionally left blank

+ 37 - 0
venv/lib/python3.11/site-packages/mypy/__main__.py

@@ -0,0 +1,37 @@
+"""Mypy type checker command line tool."""
+
+from __future__ import annotations
+
+import os
+import sys
+import traceback
+
+from mypy.main import main, process_options
+from mypy.util import FancyFormatter
+
+
+def console_entry() -> None:
+    try:
+        main()
+        sys.stdout.flush()
+        sys.stderr.flush()
+    except BrokenPipeError:
+        # Python flushes standard streams on exit; redirect remaining output
+        # to devnull to avoid another BrokenPipeError at shutdown
+        devnull = os.open(os.devnull, os.O_WRONLY)
+        os.dup2(devnull, sys.stdout.fileno())
+        sys.exit(2)
+    except KeyboardInterrupt:
+        _, options = process_options(args=sys.argv[1:])
+        if options.show_traceback:
+            sys.stdout.write(traceback.format_exc())
+        formatter = FancyFormatter(sys.stdout, sys.stderr, False)
+        msg = "Interrupted\n"
+        sys.stdout.write(formatter.style(msg, color="red", bold=True))
+        sys.stdout.flush()
+        sys.stderr.flush()
+        sys.exit(2)
+
+
+if __name__ == "__main__":
+    console_entry()

二進制
venv/lib/python3.11/site-packages/mypy/api.cpython-311-x86_64-linux-gnu.so


+ 94 - 0
venv/lib/python3.11/site-packages/mypy/api.py

@@ -0,0 +1,94 @@
+"""This module makes it possible to use mypy as part of a Python application.
+
+Since mypy still changes, the API was kept utterly simple and non-intrusive.
+It just mimics command line activation without starting a new interpreter.
+So the normal docs about the mypy command line apply.
+Changes in the command line version of mypy will be immediately usable.
+
+Just import this module and then call the 'run' function with a parameter of
+type List[str], containing what normally would have been the command line
+arguments to mypy.
+
+Function 'run' returns a Tuple[str, str, int], namely
+(<normal_report>, <error_report>, <exit_status>),
+in which <normal_report> is what mypy normally writes to sys.stdout,
+<error_report> is what mypy normally writes to sys.stderr and exit_status is
+the exit status mypy normally returns to the operating system.
+
+Any pretty formatting is left to the caller.
+
+The 'run_dmypy' function is similar, but instead mimics invocation of
+dmypy. Note that run_dmypy is not thread-safe and modifies sys.stdout
+and sys.stderr during its invocation.
+
+Note that these APIs don't support incremental generation of error
+messages.
+
+Trivial example of code using this module:
+
+import sys
+from mypy import api
+
+result = api.run(sys.argv[1:])
+
+if result[0]:
+    print('\nType checking report:\n')
+    print(result[0])  # stdout
+
+if result[1]:
+    print('\nError report:\n')
+    print(result[1])  # stderr
+
+print('\nExit status:', result[2])
+
+"""
+
+from __future__ import annotations
+
+import sys
+from io import StringIO
+from typing import Callable, TextIO
+
+
+def _run(main_wrapper: Callable[[TextIO, TextIO], None]) -> tuple[str, str, int]:
+    stdout = StringIO()
+    stderr = StringIO()
+
+    try:
+        main_wrapper(stdout, stderr)
+        exit_status = 0
+    except SystemExit as system_exit:
+        assert isinstance(system_exit.code, int)
+        exit_status = system_exit.code
+
+    return stdout.getvalue(), stderr.getvalue(), exit_status
+
+
+def run(args: list[str]) -> tuple[str, str, int]:
+    # Lazy import to avoid needing to import all of mypy to call run_dmypy
+    from mypy.main import main
+
+    return _run(
+        lambda stdout, stderr: main(args=args, stdout=stdout, stderr=stderr, clean_exit=True)
+    )
+
+
+def run_dmypy(args: list[str]) -> tuple[str, str, int]:
+    from mypy.dmypy.client import main
+
+    # A bunch of effort has been put into threading stdout and stderr
+    # through the main API to avoid the threadsafety problems of
+    # modifying sys.stdout/sys.stderr, but that hasn't been done for
+    # the dmypy client, so we just do the non-threadsafe thing.
+    def f(stdout: TextIO, stderr: TextIO) -> None:
+        old_stdout = sys.stdout
+        old_stderr = sys.stderr
+        try:
+            sys.stdout = stdout
+            sys.stderr = stderr
+            main(args)
+        finally:
+            sys.stdout = old_stdout
+            sys.stderr = old_stderr
+
+    return _run(f)

二進制
venv/lib/python3.11/site-packages/mypy/applytype.cpython-311-x86_64-linux-gnu.so


+ 186 - 0
venv/lib/python3.11/site-packages/mypy/applytype.py

@@ -0,0 +1,186 @@
+from __future__ import annotations
+
+from typing import Callable, Sequence
+
+import mypy.subtypes
+from mypy.expandtype import expand_type, expand_unpack_with_variables
+from mypy.nodes import ARG_STAR, Context
+from mypy.types import (
+    AnyType,
+    CallableType,
+    Instance,
+    Parameters,
+    ParamSpecType,
+    PartialType,
+    TupleType,
+    Type,
+    TypeVarId,
+    TypeVarLikeType,
+    TypeVarTupleType,
+    TypeVarType,
+    UnpackType,
+    get_proper_type,
+)
+from mypy.typevartuples import find_unpack_in_list, replace_starargs
+
+
+def get_target_type(
+    tvar: TypeVarLikeType,
+    type: Type,
+    callable: CallableType,
+    report_incompatible_typevar_value: Callable[[CallableType, Type, str, Context], None],
+    context: Context,
+    skip_unsatisfied: bool,
+) -> Type | None:
+    if isinstance(tvar, ParamSpecType):
+        return type
+    if isinstance(tvar, TypeVarTupleType):
+        return type
+    assert isinstance(tvar, TypeVarType)
+    values = tvar.values
+    p_type = get_proper_type(type)
+    if values:
+        if isinstance(p_type, AnyType):
+            return type
+        if isinstance(p_type, TypeVarType) and p_type.values:
+            # Allow substituting T1 for T if every allowed value of T1
+            # is also a legal value of T.
+            if all(any(mypy.subtypes.is_same_type(v, v1) for v in values) for v1 in p_type.values):
+                return type
+        matching = []
+        for value in values:
+            if mypy.subtypes.is_subtype(type, value):
+                matching.append(value)
+        if matching:
+            best = matching[0]
+            # If there are more than one matching value, we select the narrowest
+            for match in matching[1:]:
+                if mypy.subtypes.is_subtype(match, best):
+                    best = match
+            return best
+        if skip_unsatisfied:
+            return None
+        report_incompatible_typevar_value(callable, type, tvar.name, context)
+    else:
+        upper_bound = tvar.upper_bound
+        if not mypy.subtypes.is_subtype(type, upper_bound):
+            if skip_unsatisfied:
+                return None
+            report_incompatible_typevar_value(callable, type, tvar.name, context)
+    return type
+
+
+def apply_generic_arguments(
+    callable: CallableType,
+    orig_types: Sequence[Type | None],
+    report_incompatible_typevar_value: Callable[[CallableType, Type, str, Context], None],
+    context: Context,
+    skip_unsatisfied: bool = False,
+) -> CallableType:
+    """Apply generic type arguments to a callable type.
+
+    For example, applying [int] to 'def [T] (T) -> T' results in
+    'def (int) -> int'.
+
+    Note that each type can be None; in this case, it will not be applied.
+
+    If `skip_unsatisfied` is True, then just skip the types that don't satisfy type variable
+    bound or constraints, instead of giving an error.
+    """
+    tvars = callable.variables
+    assert len(tvars) == len(orig_types)
+    # Check that inferred type variable values are compatible with allowed
+    # values and bounds.  Also, promote subtype values to allowed values.
+    # Create a map from type variable id to target type.
+    id_to_type: dict[TypeVarId, Type] = {}
+
+    for tvar, type in zip(tvars, orig_types):
+        assert not isinstance(type, PartialType), "Internal error: must never apply partial type"
+        if type is None:
+            continue
+
+        target_type = get_target_type(
+            tvar, type, callable, report_incompatible_typevar_value, context, skip_unsatisfied
+        )
+        if target_type is not None:
+            id_to_type[tvar.id] = target_type
+
+    param_spec = callable.param_spec()
+    if param_spec is not None:
+        nt = id_to_type.get(param_spec.id)
+        if nt is not None:
+            nt = get_proper_type(nt)
+            if isinstance(nt, (CallableType, Parameters)):
+                callable = callable.expand_param_spec(nt)
+
+    # Apply arguments to argument types.
+    var_arg = callable.var_arg()
+    if var_arg is not None and isinstance(var_arg.typ, UnpackType):
+        star_index = callable.arg_kinds.index(ARG_STAR)
+        callable = callable.copy_modified(
+            arg_types=(
+                [expand_type(at, id_to_type) for at in callable.arg_types[:star_index]]
+                + [callable.arg_types[star_index]]
+                + [expand_type(at, id_to_type) for at in callable.arg_types[star_index + 1 :]]
+            )
+        )
+
+        unpacked_type = get_proper_type(var_arg.typ.type)
+        if isinstance(unpacked_type, TupleType):
+            # Assuming for now that because we convert prefixes to positional arguments,
+            # the first argument is always an unpack.
+            expanded_tuple = expand_type(unpacked_type, id_to_type)
+            if isinstance(expanded_tuple, TupleType):
+                # TODO: handle the case where the tuple has an unpack. This will
+                # hit an assert below.
+                expanded_unpack = find_unpack_in_list(expanded_tuple.items)
+                if expanded_unpack is not None:
+                    callable = callable.copy_modified(
+                        arg_types=(
+                            callable.arg_types[:star_index]
+                            + [expanded_tuple]
+                            + callable.arg_types[star_index + 1 :]
+                        )
+                    )
+                else:
+                    callable = replace_starargs(callable, expanded_tuple.items)
+            else:
+                # TODO: handle the case for if we get a variable length tuple.
+                assert False, f"mypy bug: unimplemented case, {expanded_tuple}"
+        elif isinstance(unpacked_type, TypeVarTupleType):
+            expanded_tvt = expand_unpack_with_variables(var_arg.typ, id_to_type)
+            if isinstance(expanded_tvt, list):
+                for t in expanded_tvt:
+                    assert not isinstance(t, UnpackType)
+                callable = replace_starargs(callable, expanded_tvt)
+            else:
+                assert isinstance(expanded_tvt, Instance)
+                assert expanded_tvt.type.fullname == "builtins.tuple"
+                callable = callable.copy_modified(
+                    arg_types=(
+                        callable.arg_types[:star_index]
+                        + [expanded_tvt.args[0]]
+                        + callable.arg_types[star_index + 1 :]
+                    )
+                )
+        else:
+            assert False, "mypy bug: unhandled case applying unpack"
+    else:
+        callable = callable.copy_modified(
+            arg_types=[expand_type(at, id_to_type) for at in callable.arg_types]
+        )
+
+    # Apply arguments to TypeGuard if any.
+    if callable.type_guard is not None:
+        type_guard = expand_type(callable.type_guard, id_to_type)
+    else:
+        type_guard = None
+
+    # The callable may retain some type vars if only some were applied.
+    remaining_tvars = [tv for tv in tvars if tv.id not in id_to_type]
+
+    return callable.copy_modified(
+        ret_type=expand_type(callable.ret_type, id_to_type),
+        variables=remaining_tvars,
+        type_guard=type_guard,
+    )

二進制
venv/lib/python3.11/site-packages/mypy/argmap.cpython-311-x86_64-linux-gnu.so


+ 247 - 0
venv/lib/python3.11/site-packages/mypy/argmap.py

@@ -0,0 +1,247 @@
+"""Utilities for mapping between actual and formal arguments (and their types)."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Callable, Sequence
+
+from mypy import nodes
+from mypy.maptype import map_instance_to_supertype
+from mypy.types import (
+    AnyType,
+    Instance,
+    ParamSpecType,
+    TupleType,
+    Type,
+    TypedDictType,
+    TypeOfAny,
+    get_proper_type,
+)
+
+if TYPE_CHECKING:
+    from mypy.infer import ArgumentInferContext
+
+
+def map_actuals_to_formals(
+    actual_kinds: list[nodes.ArgKind],
+    actual_names: Sequence[str | None] | None,
+    formal_kinds: list[nodes.ArgKind],
+    formal_names: Sequence[str | None],
+    actual_arg_type: Callable[[int], Type],
+) -> list[list[int]]:
+    """Calculate mapping between actual (caller) args and formals.
+
+    The result contains a list of caller argument indexes mapping to each
+    callee argument index, indexed by callee index.
+
+    The caller_arg_type argument should evaluate to the type of the actual
+    argument type with the given index.
+    """
+    nformals = len(formal_kinds)
+    formal_to_actual: list[list[int]] = [[] for i in range(nformals)]
+    ambiguous_actual_kwargs: list[int] = []
+    fi = 0
+    for ai, actual_kind in enumerate(actual_kinds):
+        if actual_kind == nodes.ARG_POS:
+            if fi < nformals:
+                if not formal_kinds[fi].is_star():
+                    formal_to_actual[fi].append(ai)
+                    fi += 1
+                elif formal_kinds[fi] == nodes.ARG_STAR:
+                    formal_to_actual[fi].append(ai)
+        elif actual_kind == nodes.ARG_STAR:
+            # We need to know the actual type to map varargs.
+            actualt = get_proper_type(actual_arg_type(ai))
+            if isinstance(actualt, TupleType):
+                # A tuple actual maps to a fixed number of formals.
+                for _ in range(len(actualt.items)):
+                    if fi < nformals:
+                        if formal_kinds[fi] != nodes.ARG_STAR2:
+                            formal_to_actual[fi].append(ai)
+                        else:
+                            break
+                        if formal_kinds[fi] != nodes.ARG_STAR:
+                            fi += 1
+            else:
+                # Assume that it is an iterable (if it isn't, there will be
+                # an error later).
+                while fi < nformals:
+                    if formal_kinds[fi].is_named(star=True):
+                        break
+                    else:
+                        formal_to_actual[fi].append(ai)
+                    if formal_kinds[fi] == nodes.ARG_STAR:
+                        break
+                    fi += 1
+        elif actual_kind.is_named():
+            assert actual_names is not None, "Internal error: named kinds without names given"
+            name = actual_names[ai]
+            if name in formal_names:
+                formal_to_actual[formal_names.index(name)].append(ai)
+            elif nodes.ARG_STAR2 in formal_kinds:
+                formal_to_actual[formal_kinds.index(nodes.ARG_STAR2)].append(ai)
+        else:
+            assert actual_kind == nodes.ARG_STAR2
+            actualt = get_proper_type(actual_arg_type(ai))
+            if isinstance(actualt, TypedDictType):
+                for name in actualt.items:
+                    if name in formal_names:
+                        formal_to_actual[formal_names.index(name)].append(ai)
+                    elif nodes.ARG_STAR2 in formal_kinds:
+                        formal_to_actual[formal_kinds.index(nodes.ARG_STAR2)].append(ai)
+            else:
+                # We don't exactly know which **kwargs are provided by the
+                # caller, so we'll defer until all the other unambiguous
+                # actuals have been processed
+                ambiguous_actual_kwargs.append(ai)
+
+    if ambiguous_actual_kwargs:
+        # Assume the ambiguous kwargs will fill the remaining arguments.
+        #
+        # TODO: If there are also tuple varargs, we might be missing some potential
+        #       matches if the tuple was short enough to not match everything.
+        unmatched_formals = [
+            fi
+            for fi in range(nformals)
+            if (
+                formal_names[fi]
+                and (
+                    not formal_to_actual[fi]
+                    or actual_kinds[formal_to_actual[fi][0]] == nodes.ARG_STAR
+                )
+                and formal_kinds[fi] != nodes.ARG_STAR
+            )
+            or formal_kinds[fi] == nodes.ARG_STAR2
+        ]
+        for ai in ambiguous_actual_kwargs:
+            for fi in unmatched_formals:
+                formal_to_actual[fi].append(ai)
+
+    return formal_to_actual
+
+
+def map_formals_to_actuals(
+    actual_kinds: list[nodes.ArgKind],
+    actual_names: Sequence[str | None] | None,
+    formal_kinds: list[nodes.ArgKind],
+    formal_names: list[str | None],
+    actual_arg_type: Callable[[int], Type],
+) -> list[list[int]]:
+    """Calculate the reverse mapping of map_actuals_to_formals."""
+    formal_to_actual = map_actuals_to_formals(
+        actual_kinds, actual_names, formal_kinds, formal_names, actual_arg_type
+    )
+    # Now reverse the mapping.
+    actual_to_formal: list[list[int]] = [[] for _ in actual_kinds]
+    for formal, actuals in enumerate(formal_to_actual):
+        for actual in actuals:
+            actual_to_formal[actual].append(formal)
+    return actual_to_formal
+
+
+class ArgTypeExpander:
+    """Utility class for mapping actual argument types to formal arguments.
+
+    One of the main responsibilities is to expand caller tuple *args and TypedDict
+    **kwargs, and to keep track of which tuple/TypedDict items have already been
+    consumed.
+
+    Example:
+
+       def f(x: int, *args: str) -> None: ...
+       f(*(1, 'x', 1.1))
+
+    We'd call expand_actual_type three times:
+
+      1. The first call would provide 'int' as the actual type of 'x' (from '1').
+      2. The second call would provide 'str' as one of the actual types for '*args'.
+      2. The third call would provide 'float' as one of the actual types for '*args'.
+
+    A single instance can process all the arguments for a single call. Each call
+    needs a separate instance since instances have per-call state.
+    """
+
+    def __init__(self, context: ArgumentInferContext) -> None:
+        # Next tuple *args index to use.
+        self.tuple_index = 0
+        # Keyword arguments in TypedDict **kwargs used.
+        self.kwargs_used: set[str] = set()
+        # Type context for `*` and `**` arg kinds.
+        self.context = context
+
+    def expand_actual_type(
+        self,
+        actual_type: Type,
+        actual_kind: nodes.ArgKind,
+        formal_name: str | None,
+        formal_kind: nodes.ArgKind,
+    ) -> Type:
+        """Return the actual (caller) type(s) of a formal argument with the given kinds.
+
+        If the actual argument is a tuple *args, return the next individual tuple item that
+        maps to the formal arg.
+
+        If the actual argument is a TypedDict **kwargs, return the next matching typed dict
+        value type based on formal argument name and kind.
+
+        This is supposed to be called for each formal, in order. Call multiple times per
+        formal if multiple actuals map to a formal.
+        """
+        original_actual = actual_type
+        actual_type = get_proper_type(actual_type)
+        if actual_kind == nodes.ARG_STAR:
+            if isinstance(actual_type, Instance) and actual_type.args:
+                from mypy.subtypes import is_subtype
+
+                if is_subtype(actual_type, self.context.iterable_type):
+                    return map_instance_to_supertype(
+                        actual_type, self.context.iterable_type.type
+                    ).args[0]
+                else:
+                    # We cannot properly unpack anything other
+                    # than `Iterable` type with `*`.
+                    # Just return `Any`, other parts of code would raise
+                    # a different error for improper use.
+                    return AnyType(TypeOfAny.from_error)
+            elif isinstance(actual_type, TupleType):
+                # Get the next tuple item of a tuple *arg.
+                if self.tuple_index >= len(actual_type.items):
+                    # Exhausted a tuple -- continue to the next *args.
+                    self.tuple_index = 1
+                else:
+                    self.tuple_index += 1
+                return actual_type.items[self.tuple_index - 1]
+            elif isinstance(actual_type, ParamSpecType):
+                # ParamSpec is valid in *args but it can't be unpacked.
+                return actual_type
+            else:
+                return AnyType(TypeOfAny.from_error)
+        elif actual_kind == nodes.ARG_STAR2:
+            from mypy.subtypes import is_subtype
+
+            if isinstance(actual_type, TypedDictType):
+                if formal_kind != nodes.ARG_STAR2 and formal_name in actual_type.items:
+                    # Lookup type based on keyword argument name.
+                    assert formal_name is not None
+                else:
+                    # Pick an arbitrary item if no specified keyword is expected.
+                    formal_name = (set(actual_type.items.keys()) - self.kwargs_used).pop()
+                self.kwargs_used.add(formal_name)
+                return actual_type.items[formal_name]
+            elif (
+                isinstance(actual_type, Instance)
+                and len(actual_type.args) > 1
+                and is_subtype(actual_type, self.context.mapping_type)
+            ):
+                # Only `Mapping` type can be unpacked with `**`.
+                # Other types will produce an error somewhere else.
+                return map_instance_to_supertype(actual_type, self.context.mapping_type.type).args[
+                    1
+                ]
+            elif isinstance(actual_type, ParamSpecType):
+                # ParamSpec is valid in **kwargs but it can't be unpacked.
+                return actual_type
+            else:
+                return AnyType(TypeOfAny.from_error)
+        else:
+            # No translation for other kinds -- 1:1 mapping.
+            return original_actual

二進制
venv/lib/python3.11/site-packages/mypy/binder.cpython-311-x86_64-linux-gnu.so


+ 463 - 0
venv/lib/python3.11/site-packages/mypy/binder.py

@@ -0,0 +1,463 @@
+from __future__ import annotations
+
+from collections import defaultdict
+from contextlib import contextmanager
+from typing import DefaultDict, Iterator, List, Optional, Tuple, Union, cast
+from typing_extensions import TypeAlias as _TypeAlias
+
+from mypy.erasetype import remove_instance_last_known_values
+from mypy.join import join_simple
+from mypy.literals import Key, literal, literal_hash, subkeys
+from mypy.nodes import Expression, IndexExpr, MemberExpr, NameExpr, RefExpr, TypeInfo, Var
+from mypy.subtypes import is_same_type, is_subtype
+from mypy.types import (
+    AnyType,
+    NoneType,
+    PartialType,
+    Type,
+    TypeOfAny,
+    TypeType,
+    UnionType,
+    get_proper_type,
+)
+from mypy.typevars import fill_typevars_with_any
+
+BindableExpression: _TypeAlias = Union[IndexExpr, MemberExpr, NameExpr]
+
+
+class Frame:
+    """A Frame represents a specific point in the execution of a program.
+    It carries information about the current types of expressions at
+    that point, arising either from assignments to those expressions
+    or the result of isinstance checks. It also records whether it is
+    possible to reach that point at all.
+
+    This information is not copied into a new Frame when it is pushed
+    onto the stack, so a given Frame only has information about types
+    that were assigned in that frame.
+    """
+
+    def __init__(self, id: int, conditional_frame: bool = False) -> None:
+        self.id = id
+        self.types: dict[Key, Type] = {}
+        self.unreachable = False
+        self.conditional_frame = conditional_frame
+
+        # Should be set only if we're entering a frame where it's not
+        # possible to accurately determine whether or not contained
+        # statements will be unreachable or not.
+        #
+        # Long-term, we should improve mypy to the point where we no longer
+        # need this field.
+        self.suppress_unreachable_warnings = False
+
+    def __repr__(self) -> str:
+        return f"Frame({self.id}, {self.types}, {self.unreachable}, {self.conditional_frame})"
+
+
+Assigns = DefaultDict[Expression, List[Tuple[Type, Optional[Type]]]]
+
+
+class ConditionalTypeBinder:
+    """Keep track of conditional types of variables.
+
+    NB: Variables are tracked by literal expression, so it is possible
+    to confuse the binder; for example,
+
+    ```
+    class A:
+        a: Union[int, str] = None
+    x = A()
+    lst = [x]
+    reveal_type(x.a)      # Union[int, str]
+    x.a = 1
+    reveal_type(x.a)      # int
+    reveal_type(lst[0].a) # Union[int, str]
+    lst[0].a = 'a'
+    reveal_type(x.a)      # int
+    reveal_type(lst[0].a) # str
+    ```
+    """
+
+    # Stored assignments for situations with tuple/list lvalue and rvalue of union type.
+    # This maps an expression to a list of bound types for every item in the union type.
+    type_assignments: Assigns | None = None
+
+    def __init__(self) -> None:
+        self.next_id = 1
+
+        # The stack of frames currently used.  These map
+        # literal_hash(expr) -- literals like 'foo.bar' --
+        # to types. The last element of this list is the
+        # top-most, current frame. Each earlier element
+        # records the state as of when that frame was last
+        # on top of the stack.
+        self.frames = [Frame(self._get_id())]
+
+        # For frames higher in the stack, we record the set of
+        # Frames that can escape there, either by falling off
+        # the end of the frame or by a loop control construct
+        # or raised exception. The last element of self.frames
+        # has no corresponding element in this list.
+        self.options_on_return: list[list[Frame]] = []
+
+        # Maps literal_hash(expr) to get_declaration(expr)
+        # for every expr stored in the binder
+        self.declarations: dict[Key, Type | None] = {}
+        # Set of other keys to invalidate if a key is changed, e.g. x -> {x.a, x[0]}
+        # Whenever a new key (e.g. x.a.b) is added, we update this
+        self.dependencies: dict[Key, set[Key]] = {}
+
+        # Whether the last pop changed the newly top frame on exit
+        self.last_pop_changed = False
+
+        self.try_frames: set[int] = set()
+        self.break_frames: list[int] = []
+        self.continue_frames: list[int] = []
+
+    def _get_id(self) -> int:
+        self.next_id += 1
+        return self.next_id
+
+    def _add_dependencies(self, key: Key, value: Key | None = None) -> None:
+        if value is None:
+            value = key
+        else:
+            self.dependencies.setdefault(key, set()).add(value)
+        for elt in subkeys(key):
+            self._add_dependencies(elt, value)
+
+    def push_frame(self, conditional_frame: bool = False) -> Frame:
+        """Push a new frame into the binder."""
+        f = Frame(self._get_id(), conditional_frame)
+        self.frames.append(f)
+        self.options_on_return.append([])
+        return f
+
+    def _put(self, key: Key, type: Type, index: int = -1) -> None:
+        self.frames[index].types[key] = type
+
+    def _get(self, key: Key, index: int = -1) -> Type | None:
+        if index < 0:
+            index += len(self.frames)
+        for i in range(index, -1, -1):
+            if key in self.frames[i].types:
+                return self.frames[i].types[key]
+        return None
+
+    def put(self, expr: Expression, typ: Type) -> None:
+        if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)):
+            return
+        if not literal(expr):
+            return
+        key = literal_hash(expr)
+        assert key is not None, "Internal error: binder tried to put non-literal"
+        if key not in self.declarations:
+            self.declarations[key] = get_declaration(expr)
+            self._add_dependencies(key)
+        self._put(key, typ)
+
+    def unreachable(self) -> None:
+        self.frames[-1].unreachable = True
+
+    def suppress_unreachable_warnings(self) -> None:
+        self.frames[-1].suppress_unreachable_warnings = True
+
+    def get(self, expr: Expression) -> Type | None:
+        key = literal_hash(expr)
+        assert key is not None, "Internal error: binder tried to get non-literal"
+        return self._get(key)
+
+    def is_unreachable(self) -> bool:
+        # TODO: Copy the value of unreachable into new frames to avoid
+        # this traversal on every statement?
+        return any(f.unreachable for f in self.frames)
+
+    def is_unreachable_warning_suppressed(self) -> bool:
+        # TODO: See todo in 'is_unreachable'
+        return any(f.suppress_unreachable_warnings for f in self.frames)
+
+    def cleanse(self, expr: Expression) -> None:
+        """Remove all references to a Node from the binder."""
+        key = literal_hash(expr)
+        assert key is not None, "Internal error: binder tried cleanse non-literal"
+        self._cleanse_key(key)
+
+    def _cleanse_key(self, key: Key) -> None:
+        """Remove all references to a key from the binder."""
+        for frame in self.frames:
+            if key in frame.types:
+                del frame.types[key]
+
+    def update_from_options(self, frames: list[Frame]) -> bool:
+        """Update the frame to reflect that each key will be updated
+        as in one of the frames.  Return whether any item changes.
+
+        If a key is declared as AnyType, only update it if all the
+        options are the same.
+        """
+
+        frames = [f for f in frames if not f.unreachable]
+        changed = False
+        keys = {key for f in frames for key in f.types}
+
+        for key in keys:
+            current_value = self._get(key)
+            resulting_values = [f.types.get(key, current_value) for f in frames]
+            if any(x is None for x in resulting_values):
+                # We didn't know anything about key before
+                # (current_value must be None), and we still don't
+                # know anything about key in at least one possible frame.
+                continue
+
+            type = resulting_values[0]
+            assert type is not None
+            declaration_type = get_proper_type(self.declarations.get(key))
+            if isinstance(declaration_type, AnyType):
+                # At this point resulting values can't contain None, see continue above
+                if not all(is_same_type(type, cast(Type, t)) for t in resulting_values[1:]):
+                    type = AnyType(TypeOfAny.from_another_any, source_any=declaration_type)
+            else:
+                for other in resulting_values[1:]:
+                    assert other is not None
+                    type = join_simple(self.declarations[key], type, other)
+            if current_value is None or not is_same_type(type, current_value):
+                self._put(key, type)
+                changed = True
+
+        self.frames[-1].unreachable = not frames
+
+        return changed
+
+    def pop_frame(self, can_skip: bool, fall_through: int) -> Frame:
+        """Pop a frame and return it.
+
+        See frame_context() for documentation of fall_through.
+        """
+
+        if fall_through > 0:
+            self.allow_jump(-fall_through)
+
+        result = self.frames.pop()
+        options = self.options_on_return.pop()
+
+        if can_skip:
+            options.insert(0, self.frames[-1])
+
+        self.last_pop_changed = self.update_from_options(options)
+
+        return result
+
+    @contextmanager
+    def accumulate_type_assignments(self) -> Iterator[Assigns]:
+        """Push a new map to collect assigned types in multiassign from union.
+
+        If this map is not None, actual binding is deferred until all items in
+        the union are processed (a union of collected items is later bound
+        manually by the caller).
+        """
+        old_assignments = None
+        if self.type_assignments is not None:
+            old_assignments = self.type_assignments
+        self.type_assignments = defaultdict(list)
+        yield self.type_assignments
+        self.type_assignments = old_assignments
+
+    def assign_type(
+        self, expr: Expression, type: Type, declared_type: Type | None, restrict_any: bool = False
+    ) -> None:
+        # We should erase last known value in binder, because if we are using it,
+        # it means that the target is not final, and therefore can't hold a literal.
+        type = remove_instance_last_known_values(type)
+
+        if self.type_assignments is not None:
+            # We are in a multiassign from union, defer the actual binding,
+            # just collect the types.
+            self.type_assignments[expr].append((type, declared_type))
+            return
+        if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)):
+            return None
+        if not literal(expr):
+            return
+        self.invalidate_dependencies(expr)
+
+        if declared_type is None:
+            # Not sure why this happens.  It seems to mainly happen in
+            # member initialization.
+            return
+        if not is_subtype(type, declared_type):
+            # Pretty sure this is only happens when there's a type error.
+
+            # Ideally this function wouldn't be called if the
+            # expression has a type error, though -- do other kinds of
+            # errors cause this function to get called at invalid
+            # times?
+            return
+
+        p_declared = get_proper_type(declared_type)
+        p_type = get_proper_type(type)
+        enclosing_type = get_proper_type(self.most_recent_enclosing_type(expr, type))
+        if isinstance(enclosing_type, AnyType) and not restrict_any:
+            # If x is Any and y is int, after x = y we do not infer that x is int.
+            # This could be changed.
+            # Instead, since we narrowed type from Any in a recent frame (probably an
+            # isinstance check), but now it is reassigned, we broaden back
+            # to Any (which is the most recent enclosing type)
+            self.put(expr, enclosing_type)
+        # As a special case, when assigning Any to a variable with a
+        # declared Optional type that has been narrowed to None,
+        # replace all the Nones in the declared Union type with Any.
+        # This overrides the normal behavior of ignoring Any assignments to variables
+        # in order to prevent false positives.
+        # (See discussion in #3526)
+        elif (
+            isinstance(p_type, AnyType)
+            and isinstance(p_declared, UnionType)
+            and any(isinstance(get_proper_type(item), NoneType) for item in p_declared.items)
+            and isinstance(
+                get_proper_type(self.most_recent_enclosing_type(expr, NoneType())), NoneType
+            )
+        ):
+            # Replace any Nones in the union type with Any
+            new_items = [
+                type if isinstance(get_proper_type(item), NoneType) else item
+                for item in p_declared.items
+            ]
+            self.put(expr, UnionType(new_items))
+        elif isinstance(p_type, AnyType) and not (
+            isinstance(p_declared, UnionType)
+            and any(isinstance(get_proper_type(item), AnyType) for item in p_declared.items)
+        ):
+            # Assigning an Any value doesn't affect the type to avoid false negatives, unless
+            # there is an Any item in a declared union type.
+            self.put(expr, declared_type)
+        else:
+            self.put(expr, type)
+
+        for i in self.try_frames:
+            # XXX This should probably not copy the entire frame, but
+            # just copy this variable into a single stored frame.
+            self.allow_jump(i)
+
+    def invalidate_dependencies(self, expr: BindableExpression) -> None:
+        """Invalidate knowledge of types that include expr, but not expr itself.
+
+        For example, when expr is foo.bar, invalidate foo.bar.baz.
+
+        It is overly conservative: it invalidates globally, including
+        in code paths unreachable from here.
+        """
+        key = literal_hash(expr)
+        assert key is not None
+        for dep in self.dependencies.get(key, set()):
+            self._cleanse_key(dep)
+
+    def most_recent_enclosing_type(self, expr: BindableExpression, type: Type) -> Type | None:
+        type = get_proper_type(type)
+        if isinstance(type, AnyType):
+            return get_declaration(expr)
+        key = literal_hash(expr)
+        assert key is not None
+        enclosers = [get_declaration(expr)] + [
+            f.types[key] for f in self.frames if key in f.types and is_subtype(type, f.types[key])
+        ]
+        return enclosers[-1]
+
+    def allow_jump(self, index: int) -> None:
+        # self.frames and self.options_on_return have different lengths
+        # so make sure the index is positive
+        if index < 0:
+            index += len(self.options_on_return)
+        frame = Frame(self._get_id())
+        for f in self.frames[index + 1 :]:
+            frame.types.update(f.types)
+            if f.unreachable:
+                frame.unreachable = True
+        self.options_on_return[index].append(frame)
+
+    def handle_break(self) -> None:
+        self.allow_jump(self.break_frames[-1])
+        self.unreachable()
+
+    def handle_continue(self) -> None:
+        self.allow_jump(self.continue_frames[-1])
+        self.unreachable()
+
+    @contextmanager
+    def frame_context(
+        self,
+        *,
+        can_skip: bool,
+        fall_through: int = 1,
+        break_frame: int = 0,
+        continue_frame: int = 0,
+        conditional_frame: bool = False,
+        try_frame: bool = False,
+    ) -> Iterator[Frame]:
+        """Return a context manager that pushes/pops frames on enter/exit.
+
+        If can_skip is True, control flow is allowed to bypass the
+        newly-created frame.
+
+        If fall_through > 0, then it will allow control flow that
+        falls off the end of the frame to escape to its ancestor
+        `fall_through` levels higher. Otherwise control flow ends
+        at the end of the frame.
+
+        If break_frame > 0, then 'break' statements within this frame
+        will jump out to the frame break_frame levels higher than the
+        frame created by this call to frame_context. Similarly for
+        continue_frame and 'continue' statements.
+
+        If try_frame is true, then execution is allowed to jump at any
+        point within the newly created frame (or its descendants) to
+        its parent (i.e., to the frame that was on top before this
+        call to frame_context).
+
+        After the context manager exits, self.last_pop_changed indicates
+        whether any types changed in the newly-topmost frame as a result
+        of popping this frame.
+        """
+        assert len(self.frames) > 1
+
+        if break_frame:
+            self.break_frames.append(len(self.frames) - break_frame)
+        if continue_frame:
+            self.continue_frames.append(len(self.frames) - continue_frame)
+        if try_frame:
+            self.try_frames.add(len(self.frames) - 1)
+
+        new_frame = self.push_frame(conditional_frame)
+        if try_frame:
+            # An exception may occur immediately
+            self.allow_jump(-1)
+        yield new_frame
+        self.pop_frame(can_skip, fall_through)
+
+        if break_frame:
+            self.break_frames.pop()
+        if continue_frame:
+            self.continue_frames.pop()
+        if try_frame:
+            self.try_frames.remove(len(self.frames) - 1)
+
+    @contextmanager
+    def top_frame_context(self) -> Iterator[Frame]:
+        """A variant of frame_context for use at the top level of
+        a namespace (module, function, or class).
+        """
+        assert len(self.frames) == 1
+        yield self.push_frame()
+        self.pop_frame(True, 0)
+        assert len(self.frames) == 1
+
+
+def get_declaration(expr: BindableExpression) -> Type | None:
+    if isinstance(expr, RefExpr):
+        if isinstance(expr.node, Var):
+            type = expr.node.type
+            if not isinstance(get_proper_type(type), PartialType):
+                return type
+        elif isinstance(expr.node, TypeInfo):
+            return TypeType(fill_typevars_with_any(expr.node))
+    return None

+ 27 - 0
venv/lib/python3.11/site-packages/mypy/bogus_type.py

@@ -0,0 +1,27 @@
+"""A Bogus[T] type alias for marking when we subvert the type system
+
+We need this for compiling with mypyc, which inserts runtime
+typechecks that cause problems when we subvert the type system. So
+when compiling with mypyc, we turn those places into Any, while
+keeping the types around for normal typechecks.
+
+Since this causes the runtime types to be Any, this is best used
+in places where efficient access to properties is not important.
+For those cases some other technique should be used.
+"""
+
+from __future__ import annotations
+
+from typing import Any, TypeVar
+
+from mypy_extensions import FlexibleAlias
+
+T = TypeVar("T")
+
+# This won't ever be true at runtime, but we consider it true during
+# mypyc compilations.
+MYPYC = False
+if MYPYC:
+    Bogus = FlexibleAlias[T, Any]
+else:
+    Bogus = FlexibleAlias[T, T]

二進制
venv/lib/python3.11/site-packages/mypy/build.cpython-311-x86_64-linux-gnu.so


二進制
venv/lib/python3.11/site-packages/mypy/checker.cpython-311-x86_64-linux-gnu.so


+ 7819 - 0
venv/lib/python3.11/site-packages/mypy/checker.py

@@ -0,0 +1,7819 @@
+"""Mypy type checker."""
+
+from __future__ import annotations
+
+import itertools
+from collections import defaultdict
+from contextlib import contextmanager, nullcontext
+from typing import (
+    AbstractSet,
+    Callable,
+    Dict,
+    Final,
+    Generic,
+    Iterable,
+    Iterator,
+    Mapping,
+    NamedTuple,
+    Optional,
+    Sequence,
+    Tuple,
+    TypeVar,
+    Union,
+    cast,
+    overload,
+)
+from typing_extensions import TypeAlias as _TypeAlias
+
+import mypy.checkexpr
+from mypy import errorcodes as codes, message_registry, nodes, operators
+from mypy.binder import ConditionalTypeBinder, Frame, get_declaration
+from mypy.checkmember import (
+    MemberContext,
+    analyze_decorator_or_funcbase_access,
+    analyze_descriptor_access,
+    analyze_member_access,
+    type_object_type,
+)
+from mypy.checkpattern import PatternChecker
+from mypy.constraints import SUPERTYPE_OF
+from mypy.erasetype import erase_type, erase_typevars, remove_instance_last_known_values
+from mypy.errorcodes import TYPE_VAR, UNUSED_AWAITABLE, UNUSED_COROUTINE, ErrorCode
+from mypy.errors import Errors, ErrorWatcher, report_internal_error
+from mypy.expandtype import expand_self_type, expand_type, expand_type_by_instance
+from mypy.join import join_types
+from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash
+from mypy.maptype import map_instance_to_supertype
+from mypy.meet import is_overlapping_erased_types, is_overlapping_types
+from mypy.message_registry import ErrorMessage
+from mypy.messages import (
+    SUGGESTED_TEST_FIXTURES,
+    MessageBuilder,
+    append_invariance_notes,
+    format_type,
+    format_type_bare,
+    format_type_distinctly,
+    make_inferred_type_note,
+    pretty_seq,
+)
+from mypy.mro import MroError, calculate_mro
+from mypy.nodes import (
+    ARG_NAMED,
+    ARG_POS,
+    ARG_STAR,
+    CONTRAVARIANT,
+    COVARIANT,
+    FUNC_NO_INFO,
+    GDEF,
+    IMPLICITLY_ABSTRACT,
+    INVARIANT,
+    IS_ABSTRACT,
+    LDEF,
+    LITERAL_TYPE,
+    MDEF,
+    NOT_ABSTRACT,
+    AssertStmt,
+    AssignmentExpr,
+    AssignmentStmt,
+    Block,
+    BreakStmt,
+    BytesExpr,
+    CallExpr,
+    ClassDef,
+    ComparisonExpr,
+    Context,
+    ContinueStmt,
+    Decorator,
+    DelStmt,
+    EllipsisExpr,
+    Expression,
+    ExpressionStmt,
+    FloatExpr,
+    ForStmt,
+    FuncBase,
+    FuncDef,
+    FuncItem,
+    IfStmt,
+    Import,
+    ImportAll,
+    ImportBase,
+    ImportFrom,
+    IndexExpr,
+    IntExpr,
+    LambdaExpr,
+    ListExpr,
+    Lvalue,
+    MatchStmt,
+    MemberExpr,
+    MypyFile,
+    NameExpr,
+    Node,
+    OperatorAssignmentStmt,
+    OpExpr,
+    OverloadedFuncDef,
+    PassStmt,
+    PromoteExpr,
+    RaiseStmt,
+    RefExpr,
+    ReturnStmt,
+    StarExpr,
+    Statement,
+    StrExpr,
+    SymbolNode,
+    SymbolTable,
+    SymbolTableNode,
+    TempNode,
+    TryStmt,
+    TupleExpr,
+    TypeAlias,
+    TypeInfo,
+    TypeVarExpr,
+    UnaryExpr,
+    Var,
+    WhileStmt,
+    WithStmt,
+    is_final_node,
+)
+from mypy.options import Options
+from mypy.patterns import AsPattern, StarredPattern
+from mypy.plugin import CheckerPluginInterface, Plugin
+from mypy.plugins import dataclasses as dataclasses_plugin
+from mypy.scope import Scope
+from mypy.semanal import is_trivial_body, refers_to_fullname, set_callable_name
+from mypy.semanal_enum import ENUM_BASES, ENUM_SPECIAL_PROPS
+from mypy.sharedparse import BINARY_MAGIC_METHODS
+from mypy.state import state
+from mypy.subtypes import (
+    find_member,
+    is_callable_compatible,
+    is_equivalent,
+    is_more_precise,
+    is_proper_subtype,
+    is_same_type,
+    is_subtype,
+    restrict_subtype_away,
+    unify_generic_callable,
+)
+from mypy.traverser import TraverserVisitor, all_return_statements, has_return_statement
+from mypy.treetransform import TransformVisitor
+from mypy.typeanal import check_for_explicit_any, has_any_from_unimported_type, make_optional_type
+from mypy.typeops import (
+    bind_self,
+    coerce_to_literal,
+    custom_special_method,
+    erase_def_to_union_or_bound,
+    erase_to_bound,
+    erase_to_union_or_bound,
+    false_only,
+    fixup_partial_type,
+    function_type,
+    get_type_vars,
+    is_literal_type_like,
+    is_singleton_type,
+    make_simplified_union,
+    map_type_from_supertype,
+    true_only,
+    try_expanding_sum_type_to_union,
+    try_getting_int_literals_from_type,
+    try_getting_str_literals,
+    try_getting_str_literals_from_type,
+    tuple_fallback,
+)
+from mypy.types import (
+    ANY_STRATEGY,
+    MYPYC_NATIVE_INT_NAMES,
+    OVERLOAD_NAMES,
+    AnyType,
+    BoolTypeQuery,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    FunctionLike,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeGuardedType,
+    TypeOfAny,
+    TypeTranslator,
+    TypeType,
+    TypeVarId,
+    TypeVarLikeType,
+    TypeVarType,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    flatten_nested_unions,
+    get_proper_type,
+    get_proper_types,
+    is_literal_type,
+    is_named_instance,
+)
+from mypy.types_utils import is_optional, remove_optional, store_argument_type, strip_type
+from mypy.typetraverser import TypeTraverserVisitor
+from mypy.typevars import fill_typevars, fill_typevars_with_any, has_no_typevars
+from mypy.util import is_dunder, is_sunder, is_typeshed_file
+from mypy.visitor import NodeVisitor
+
+T = TypeVar("T")
+
+DEFAULT_LAST_PASS: Final = 1  # Pass numbers start at 0
+
+DeferredNodeType: _TypeAlias = Union[FuncDef, LambdaExpr, OverloadedFuncDef, Decorator]
+FineGrainedDeferredNodeType: _TypeAlias = Union[FuncDef, MypyFile, OverloadedFuncDef]
+
+
+# A node which is postponed to be processed during the next pass.
+# In normal mode one can defer functions and methods (also decorated and/or overloaded)
+# and lambda expressions. Nested functions can't be deferred -- only top-level functions
+# and methods of classes not defined within a function can be deferred.
+class DeferredNode(NamedTuple):
+    node: DeferredNodeType
+    # And its TypeInfo (for semantic analysis self type handling
+    active_typeinfo: TypeInfo | None
+
+
+# Same as above, but for fine-grained mode targets. Only top-level functions/methods
+# and module top levels are allowed as such.
+class FineGrainedDeferredNode(NamedTuple):
+    node: FineGrainedDeferredNodeType
+    active_typeinfo: TypeInfo | None
+
+
+# Data structure returned by find_isinstance_check representing
+# information learned from the truth or falsehood of a condition.  The
+# dict maps nodes representing expressions like 'a[0].x' to their
+# refined types under the assumption that the condition has a
+# particular truth value. A value of None means that the condition can
+# never have that truth value.
+
+# NB: The keys of this dict are nodes in the original source program,
+# which are compared by reference equality--effectively, being *the
+# same* expression of the program, not just two identical expressions
+# (such as two references to the same variable). TODO: it would
+# probably be better to have the dict keyed by the nodes' literal_hash
+# field instead.
+TypeMap: _TypeAlias = Optional[Dict[Expression, Type]]
+
+
+# An object that represents either a precise type or a type with an upper bound;
+# it is important for correct type inference with isinstance.
+class TypeRange(NamedTuple):
+    item: Type
+    is_upper_bound: bool  # False => precise type
+
+
+# Keeps track of partial types in a single scope. In fine-grained incremental
+# mode partial types initially defined at the top level cannot be completed in
+# a function, and we use the 'is_function' attribute to enforce this.
+class PartialTypeScope(NamedTuple):
+    map: dict[Var, Context]
+    is_function: bool
+    is_local: bool
+
+
+class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
+    """Mypy type checker.
+
+    Type check mypy source files that have been semantically analyzed.
+
+    You must create a separate instance for each source file.
+    """
+
+    # Are we type checking a stub?
+    is_stub = False
+    # Error message reporter
+    errors: Errors
+    # Utility for generating messages
+    msg: MessageBuilder
+    # Types of type checked nodes. The first item is the "master" type
+    # map that will store the final, exported types. Additional items
+    # are temporary type maps used during type inference, and these
+    # will be eventually popped and either discarded or merged into
+    # the master type map.
+    #
+    # Avoid accessing this directly, but prefer the lookup_type(),
+    # has_type() etc. helpers instead.
+    _type_maps: list[dict[Expression, Type]]
+
+    # Helper for managing conditional types
+    binder: ConditionalTypeBinder
+    # Helper for type checking expressions
+    expr_checker: mypy.checkexpr.ExpressionChecker
+
+    pattern_checker: PatternChecker
+
+    tscope: Scope
+    scope: CheckerScope
+    # Stack of function return types
+    return_types: list[Type]
+    # Flags; true for dynamically typed functions
+    dynamic_funcs: list[bool]
+    # Stack of collections of variables with partial types
+    partial_types: list[PartialTypeScope]
+    # Vars for which partial type errors are already reported
+    # (to avoid logically duplicate errors with different error context).
+    partial_reported: set[Var]
+    globals: SymbolTable
+    modules: dict[str, MypyFile]
+    # Nodes that couldn't be checked because some types weren't available. We'll run
+    # another pass and try these again.
+    deferred_nodes: list[DeferredNode]
+    # Type checking pass number (0 = first pass)
+    pass_num = 0
+    # Last pass number to take
+    last_pass = DEFAULT_LAST_PASS
+    # Have we deferred the current function? If yes, don't infer additional
+    # types during this pass within the function.
+    current_node_deferred = False
+    # Is this file a typeshed stub?
+    is_typeshed_stub = False
+    options: Options
+    # Used for collecting inferred attribute types so that they can be checked
+    # for consistency.
+    inferred_attribute_types: dict[Var, Type] | None = None
+    # Don't infer partial None types if we are processing assignment from Union
+    no_partial_types: bool = False
+
+    # The set of all dependencies (suppressed or not) that this module accesses, either
+    # directly or indirectly.
+    module_refs: set[str]
+
+    # A map from variable nodes to a snapshot of the frame ids of the
+    # frames that were active when the variable was declared. This can
+    # be used to determine nearest common ancestor frame of a variable's
+    # declaration and the current frame, which lets us determine if it
+    # was declared in a different branch of the same `if` statement
+    # (if that frame is a conditional_frame).
+    var_decl_frames: dict[Var, set[int]]
+
+    # Plugin that provides special type checking rules for specific library
+    # functions such as open(), etc.
+    plugin: Plugin
+
+    def __init__(
+        self,
+        errors: Errors,
+        modules: dict[str, MypyFile],
+        options: Options,
+        tree: MypyFile,
+        path: str,
+        plugin: Plugin,
+        per_line_checking_time_ns: dict[int, int],
+    ) -> None:
+        """Construct a type checker.
+
+        Use errors to report type check errors.
+        """
+        self.errors = errors
+        self.modules = modules
+        self.options = options
+        self.tree = tree
+        self.path = path
+        self.msg = MessageBuilder(errors, modules)
+        self.plugin = plugin
+        self.tscope = Scope()
+        self.scope = CheckerScope(tree)
+        self.binder = ConditionalTypeBinder()
+        self.globals = tree.names
+        self.return_types = []
+        self.dynamic_funcs = []
+        self.partial_types = []
+        self.partial_reported = set()
+        self.var_decl_frames = {}
+        self.deferred_nodes = []
+        self._type_maps = [{}]
+        self.module_refs = set()
+        self.pass_num = 0
+        self.current_node_deferred = False
+        self.is_stub = tree.is_stub
+        self.is_typeshed_stub = is_typeshed_file(options.abs_custom_typeshed_dir, path)
+        self.inferred_attribute_types = None
+
+        # If True, process function definitions. If False, don't. This is used
+        # for processing module top levels in fine-grained incremental mode.
+        self.recurse_into_functions = True
+        # This internal flag is used to track whether we a currently type-checking
+        # a final declaration (assignment), so that some errors should be suppressed.
+        # Should not be set manually, use get_final_context/enter_final_context instead.
+        # NOTE: we use the context manager to avoid "threading" an additional `is_final_def`
+        # argument through various `checker` and `checkmember` functions.
+        self._is_final_def = False
+
+        # This flag is set when we run type-check or attribute access check for the purpose
+        # of giving a note on possibly missing "await". It is used to avoid infinite recursion.
+        self.checking_missing_await = False
+
+        # While this is True, allow passing an abstract class where Type[T] is expected.
+        # although this is technically unsafe, this is desirable in some context, for
+        # example when type-checking class decorators.
+        self.allow_abstract_call = False
+
+        # Child checker objects for specific AST node types
+        self.expr_checker = mypy.checkexpr.ExpressionChecker(
+            self, self.msg, self.plugin, per_line_checking_time_ns
+        )
+        self.pattern_checker = PatternChecker(self, self.msg, self.plugin, options)
+
+    @property
+    def type_context(self) -> list[Type | None]:
+        return self.expr_checker.type_context
+
+    def reset(self) -> None:
+        """Cleanup stale state that might be left over from a typechecking run.
+
+        This allows us to reuse TypeChecker objects in fine-grained
+        incremental mode.
+        """
+        # TODO: verify this is still actually worth it over creating new checkers
+        self.partial_reported.clear()
+        self.module_refs.clear()
+        self.binder = ConditionalTypeBinder()
+        self._type_maps[1:] = []
+        self._type_maps[0].clear()
+        self.temp_type_map = None
+        self.expr_checker.reset()
+
+        assert self.inferred_attribute_types is None
+        assert self.partial_types == []
+        assert self.deferred_nodes == []
+        assert len(self.scope.stack) == 1
+        assert self.partial_types == []
+
+    def check_first_pass(self) -> None:
+        """Type check the entire file, but defer functions with unresolved references.
+
+        Unresolved references are forward references to variables
+        whose types haven't been inferred yet.  They may occur later
+        in the same file or in a different file that's being processed
+        later (usually due to an import cycle).
+
+        Deferred functions will be processed by check_second_pass().
+        """
+        self.recurse_into_functions = True
+        with state.strict_optional_set(self.options.strict_optional):
+            self.errors.set_file(
+                self.path, self.tree.fullname, scope=self.tscope, options=self.options
+            )
+            with self.tscope.module_scope(self.tree.fullname):
+                with self.enter_partial_types(), self.binder.top_frame_context():
+                    for d in self.tree.defs:
+                        if self.binder.is_unreachable():
+                            if not self.should_report_unreachable_issues():
+                                break
+                            if not self.is_noop_for_reachability(d):
+                                self.msg.unreachable_statement(d)
+                                break
+                        else:
+                            self.accept(d)
+
+                assert not self.current_node_deferred
+
+                all_ = self.globals.get("__all__")
+                if all_ is not None and all_.type is not None:
+                    all_node = all_.node
+                    assert all_node is not None
+                    seq_str = self.named_generic_type(
+                        "typing.Sequence", [self.named_type("builtins.str")]
+                    )
+                    if not is_subtype(all_.type, seq_str):
+                        str_seq_s, all_s = format_type_distinctly(
+                            seq_str, all_.type, options=self.options
+                        )
+                        self.fail(
+                            message_registry.ALL_MUST_BE_SEQ_STR.format(str_seq_s, all_s), all_node
+                        )
+
+    def check_second_pass(
+        self, todo: Sequence[DeferredNode | FineGrainedDeferredNode] | None = None
+    ) -> bool:
+        """Run second or following pass of type checking.
+
+        This goes through deferred nodes, returning True if there were any.
+        """
+        self.recurse_into_functions = True
+        with state.strict_optional_set(self.options.strict_optional):
+            if not todo and not self.deferred_nodes:
+                return False
+            self.errors.set_file(
+                self.path, self.tree.fullname, scope=self.tscope, options=self.options
+            )
+            with self.tscope.module_scope(self.tree.fullname):
+                self.pass_num += 1
+                if not todo:
+                    todo = self.deferred_nodes
+                else:
+                    assert not self.deferred_nodes
+                self.deferred_nodes = []
+                done: set[DeferredNodeType | FineGrainedDeferredNodeType] = set()
+                for node, active_typeinfo in todo:
+                    if node in done:
+                        continue
+                    # This is useful for debugging:
+                    # print("XXX in pass %d, class %s, function %s" %
+                    #       (self.pass_num, type_name, node.fullname or node.name))
+                    done.add(node)
+                    with self.tscope.class_scope(
+                        active_typeinfo
+                    ) if active_typeinfo else nullcontext():
+                        with self.scope.push_class(
+                            active_typeinfo
+                        ) if active_typeinfo else nullcontext():
+                            self.check_partial(node)
+            return True
+
+    def check_partial(self, node: DeferredNodeType | FineGrainedDeferredNodeType) -> None:
+        if isinstance(node, MypyFile):
+            self.check_top_level(node)
+        else:
+            self.recurse_into_functions = True
+            if isinstance(node, LambdaExpr):
+                self.expr_checker.accept(node)
+            else:
+                self.accept(node)
+
+    def check_top_level(self, node: MypyFile) -> None:
+        """Check only the top-level of a module, skipping function definitions."""
+        self.recurse_into_functions = False
+        with self.enter_partial_types():
+            with self.binder.top_frame_context():
+                for d in node.defs:
+                    d.accept(self)
+
+        assert not self.current_node_deferred
+        # TODO: Handle __all__
+
+    def defer_node(self, node: DeferredNodeType, enclosing_class: TypeInfo | None) -> None:
+        """Defer a node for processing during next type-checking pass.
+
+        Args:
+            node: function/method being deferred
+            enclosing_class: for methods, the class where the method is defined
+        NOTE: this can't handle nested functions/methods.
+        """
+        # We don't freeze the entire scope since only top-level functions and methods
+        # can be deferred. Only module/class level scope information is needed.
+        # Module-level scope information is preserved in the TypeChecker instance.
+        self.deferred_nodes.append(DeferredNode(node, enclosing_class))
+
+    def handle_cannot_determine_type(self, name: str, context: Context) -> None:
+        node = self.scope.top_non_lambda_function()
+        if self.pass_num < self.last_pass and isinstance(node, FuncDef):
+            # Don't report an error yet. Just defer. Note that we don't defer
+            # lambdas because they are coupled to the surrounding function
+            # through the binder and the inferred type of the lambda, so it
+            # would get messy.
+            enclosing_class = self.scope.enclosing_class()
+            self.defer_node(node, enclosing_class)
+            # Set a marker so that we won't infer additional types in this
+            # function. Any inferred types could be bogus, because there's at
+            # least one type that we don't know.
+            self.current_node_deferred = True
+        else:
+            self.msg.cannot_determine_type(name, context)
+
+    def accept(self, stmt: Statement) -> None:
+        """Type check a node in the given type context."""
+        try:
+            stmt.accept(self)
+        except Exception as err:
+            report_internal_error(err, self.errors.file, stmt.line, self.errors, self.options)
+
+    def accept_loop(
+        self,
+        body: Statement,
+        else_body: Statement | None = None,
+        *,
+        exit_condition: Expression | None = None,
+    ) -> None:
+        """Repeatedly type check a loop body until the frame doesn't change.
+        If exit_condition is set, assume it must be False on exit from the loop.
+
+        Then check the else_body.
+        """
+        # The outer frame accumulates the results of all iterations
+        with self.binder.frame_context(can_skip=False, conditional_frame=True):
+            while True:
+                with self.binder.frame_context(can_skip=True, break_frame=2, continue_frame=1):
+                    self.accept(body)
+                if not self.binder.last_pop_changed:
+                    break
+            if exit_condition:
+                _, else_map = self.find_isinstance_check(exit_condition)
+                self.push_type_map(else_map)
+            if else_body:
+                self.accept(else_body)
+
+    #
+    # Definitions
+    #
+
+    def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
+        if not self.recurse_into_functions:
+            return
+        with self.tscope.function_scope(defn):
+            self._visit_overloaded_func_def(defn)
+
+    def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
+        num_abstract = 0
+        if not defn.items:
+            # In this case we have already complained about none of these being
+            # valid overloads.
+            return None
+        if len(defn.items) == 1:
+            self.fail(message_registry.MULTIPLE_OVERLOADS_REQUIRED, defn)
+
+        if defn.is_property:
+            # HACK: Infer the type of the property.
+            assert isinstance(defn.items[0], Decorator)
+            self.visit_decorator(defn.items[0])
+        for fdef in defn.items:
+            assert isinstance(fdef, Decorator)
+            self.check_func_item(fdef.func, name=fdef.func.name, allow_empty=True)
+            if fdef.func.abstract_status in (IS_ABSTRACT, IMPLICITLY_ABSTRACT):
+                num_abstract += 1
+        if num_abstract not in (0, len(defn.items)):
+            self.fail(message_registry.INCONSISTENT_ABSTRACT_OVERLOAD, defn)
+        if defn.impl:
+            defn.impl.accept(self)
+        if defn.info:
+            found_method_base_classes = self.check_method_override(defn)
+            if (
+                defn.is_explicit_override
+                and not found_method_base_classes
+                and found_method_base_classes is not None
+            ):
+                self.msg.no_overridable_method(defn.name, defn)
+            self.check_explicit_override_decorator(defn, found_method_base_classes, defn.impl)
+            self.check_inplace_operator_method(defn)
+        if not defn.is_property:
+            self.check_overlapping_overloads(defn)
+        return None
+
+    def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None:
+        # At this point we should have set the impl already, and all remaining
+        # items are decorators
+
+        if self.msg.errors.file in self.msg.errors.ignored_files:
+            # This is a little hacky, however, the quadratic check here is really expensive, this
+            # method has no side effects, so we should skip it if we aren't going to report
+            # anything. In some other places we swallow errors in stubs, but this error is very
+            # useful for stubs!
+            return
+
+        # Compute some info about the implementation (if it exists) for use below
+        impl_type: CallableType | None = None
+        if defn.impl:
+            if isinstance(defn.impl, FuncDef):
+                inner_type: Type | None = defn.impl.type
+            elif isinstance(defn.impl, Decorator):
+                inner_type = defn.impl.var.type
+            else:
+                assert False, "Impl isn't the right type"
+
+            # This can happen if we've got an overload with a different
+            # decorator or if the implementation is untyped -- we gave up on the types.
+            inner_type = get_proper_type(inner_type)
+            if inner_type is not None and not isinstance(inner_type, AnyType):
+                if isinstance(inner_type, CallableType):
+                    impl_type = inner_type
+                elif isinstance(inner_type, Instance):
+                    inner_call = get_proper_type(
+                        analyze_member_access(
+                            name="__call__",
+                            typ=inner_type,
+                            context=defn.impl,
+                            is_lvalue=False,
+                            is_super=False,
+                            is_operator=True,
+                            msg=self.msg,
+                            original_type=inner_type,
+                            chk=self,
+                        )
+                    )
+                    if isinstance(inner_call, CallableType):
+                        impl_type = inner_call
+                if impl_type is None:
+                    self.msg.not_callable(inner_type, defn.impl)
+
+        is_descriptor_get = defn.info and defn.name == "__get__"
+        for i, item in enumerate(defn.items):
+            # TODO overloads involving decorators
+            assert isinstance(item, Decorator)
+            sig1 = self.function_type(item.func)
+            assert isinstance(sig1, CallableType)
+
+            for j, item2 in enumerate(defn.items[i + 1 :]):
+                assert isinstance(item2, Decorator)
+                sig2 = self.function_type(item2.func)
+                assert isinstance(sig2, CallableType)
+
+                if not are_argument_counts_overlapping(sig1, sig2):
+                    continue
+
+                if overload_can_never_match(sig1, sig2):
+                    self.msg.overloaded_signature_will_never_match(i + 1, i + j + 2, item2.func)
+                elif not is_descriptor_get:
+                    # Note: we force mypy to check overload signatures in strict-optional mode
+                    # so we don't incorrectly report errors when a user tries typing an overload
+                    # that happens to have a 'if the argument is None' fallback.
+                    #
+                    # For example, the following is fine in strict-optional mode but would throw
+                    # the unsafe overlap error when strict-optional is disabled:
+                    #
+                    #     @overload
+                    #     def foo(x: None) -> int: ...
+                    #     @overload
+                    #     def foo(x: str) -> str: ...
+                    #
+                    # See Python 2's map function for a concrete example of this kind of overload.
+                    with state.strict_optional_set(True):
+                        if is_unsafe_overlapping_overload_signatures(sig1, sig2):
+                            self.msg.overloaded_signatures_overlap(i + 1, i + j + 2, item.func)
+
+            if impl_type is not None:
+                assert defn.impl is not None
+
+                # We perform a unification step that's very similar to what
+                # 'is_callable_compatible' would have done if we had set
+                # 'unify_generics' to True -- the only difference is that
+                # we check and see if the impl_type's return value is a
+                # *supertype* of the overload alternative, not a *subtype*.
+                #
+                # This is to match the direction the implementation's return
+                # needs to be compatible in.
+                if impl_type.variables:
+                    impl: CallableType | None = unify_generic_callable(
+                        # Normalize both before unifying
+                        impl_type.with_unpacked_kwargs(),
+                        sig1.with_unpacked_kwargs(),
+                        ignore_return=False,
+                        return_constraint_direction=SUPERTYPE_OF,
+                    )
+                    if impl is None:
+                        self.msg.overloaded_signatures_typevar_specific(i + 1, defn.impl)
+                        continue
+                else:
+                    impl = impl_type
+
+                # Prevent extra noise from inconsistent use of @classmethod by copying
+                # the first arg from the method being checked against.
+                if sig1.arg_types and defn.info:
+                    impl = impl.copy_modified(arg_types=[sig1.arg_types[0]] + impl.arg_types[1:])
+
+                # Is the overload alternative's arguments subtypes of the implementation's?
+                if not is_callable_compatible(
+                    impl, sig1, is_compat=is_subtype, ignore_return=True
+                ):
+                    self.msg.overloaded_signatures_arg_specific(i + 1, defn.impl)
+
+                # Is the overload alternative's return type a subtype of the implementation's?
+                if not (
+                    is_subtype(sig1.ret_type, impl.ret_type)
+                    or is_subtype(impl.ret_type, sig1.ret_type)
+                ):
+                    self.msg.overloaded_signatures_ret_specific(i + 1, defn.impl)
+
+    # Here's the scoop about generators and coroutines.
+    #
+    # There are two kinds of generators: classic generators (functions
+    # with `yield` or `yield from` in the body) and coroutines
+    # (functions declared with `async def`).  The latter are specified
+    # in PEP 492 and only available in Python >= 3.5.
+    #
+    # Classic generators can be parameterized with three types:
+    # - ty is the Yield type (the type of y in `yield y`)
+    # - tc is the type reCeived by yield (the type of c in `c = yield`).
+    # - tr is the Return type (the type of r in `return r`)
+    #
+    # A classic generator must define a return type that's either
+    # `Generator[ty, tc, tr]`, Iterator[ty], or Iterable[ty] (or
+    # object or Any).  If tc/tr are not given, both are None.
+    #
+    # A coroutine must define a return type corresponding to tr; the
+    # other two are unconstrained.  The "external" return type (seen
+    # by the caller) is Awaitable[tr].
+    #
+    # In addition, there's the synthetic type AwaitableGenerator: it
+    # inherits from both Awaitable and Generator and can be used both
+    # in `yield from` and in `await`.  This type is set automatically
+    # for functions decorated with `@types.coroutine` or
+    # `@asyncio.coroutine`.  Its single parameter corresponds to tr.
+    #
+    # PEP 525 adds a new type, the asynchronous generator, which was
+    # first released in Python 3.6. Async generators are `async def`
+    # functions that can also `yield` values. They can be parameterized
+    # with two types, ty and tc, because they cannot return a value.
+    #
+    # There are several useful methods, each taking a type t and a
+    # flag c indicating whether it's for a generator or coroutine:
+    #
+    # - is_generator_return_type(t, c) returns whether t is a Generator,
+    #   Iterator, Iterable (if not c), or Awaitable (if c), or
+    #   AwaitableGenerator (regardless of c).
+    # - is_async_generator_return_type(t) returns whether t is an
+    #   AsyncGenerator.
+    # - get_generator_yield_type(t, c) returns ty.
+    # - get_generator_receive_type(t, c) returns tc.
+    # - get_generator_return_type(t, c) returns tr.
+
+    def is_generator_return_type(self, typ: Type, is_coroutine: bool) -> bool:
+        """Is `typ` a valid type for a generator/coroutine?
+
+        True if `typ` is a *supertype* of Generator or Awaitable.
+        Also true it it's *exactly* AwaitableGenerator (modulo type parameters).
+        """
+        typ = get_proper_type(typ)
+        if is_coroutine:
+            # This means we're in Python 3.5 or later.
+            at = self.named_generic_type("typing.Awaitable", [AnyType(TypeOfAny.special_form)])
+            if is_subtype(at, typ):
+                return True
+        else:
+            any_type = AnyType(TypeOfAny.special_form)
+            gt = self.named_generic_type("typing.Generator", [any_type, any_type, any_type])
+            if is_subtype(gt, typ):
+                return True
+        return isinstance(typ, Instance) and typ.type.fullname == "typing.AwaitableGenerator"
+
+    def is_async_generator_return_type(self, typ: Type) -> bool:
+        """Is `typ` a valid type for an async generator?
+
+        True if `typ` is a supertype of AsyncGenerator.
+        """
+        try:
+            any_type = AnyType(TypeOfAny.special_form)
+            agt = self.named_generic_type("typing.AsyncGenerator", [any_type, any_type])
+        except KeyError:
+            # we're running on a version of typing that doesn't have AsyncGenerator yet
+            return False
+        return is_subtype(agt, typ)
+
+    def get_generator_yield_type(self, return_type: Type, is_coroutine: bool) -> Type:
+        """Given the declared return type of a generator (t), return the type it yields (ty)."""
+        return_type = get_proper_type(return_type)
+
+        if isinstance(return_type, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=return_type)
+        elif isinstance(return_type, UnionType):
+            return make_simplified_union(
+                [self.get_generator_yield_type(item, is_coroutine) for item in return_type.items]
+            )
+        elif not self.is_generator_return_type(
+            return_type, is_coroutine
+        ) and not self.is_async_generator_return_type(return_type):
+            # If the function doesn't have a proper Generator (or
+            # Awaitable) return type, anything is permissible.
+            return AnyType(TypeOfAny.from_error)
+        elif not isinstance(return_type, Instance):
+            # Same as above, but written as a separate branch so the typechecker can understand.
+            return AnyType(TypeOfAny.from_error)
+        elif return_type.type.fullname == "typing.Awaitable":
+            # Awaitable: ty is Any.
+            return AnyType(TypeOfAny.special_form)
+        elif return_type.args:
+            # AwaitableGenerator, Generator, AsyncGenerator, Iterator, or Iterable; ty is args[0].
+            ret_type = return_type.args[0]
+            # TODO not best fix, better have dedicated yield token
+            return ret_type
+        else:
+            # If the function's declared supertype of Generator has no type
+            # parameters (i.e. is `object`), then the yielded values can't
+            # be accessed so any type is acceptable.  IOW, ty is Any.
+            # (However, see https://github.com/python/mypy/issues/1933)
+            return AnyType(TypeOfAny.special_form)
+
+    def get_generator_receive_type(self, return_type: Type, is_coroutine: bool) -> Type:
+        """Given a declared generator return type (t), return the type its yield receives (tc)."""
+        return_type = get_proper_type(return_type)
+
+        if isinstance(return_type, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=return_type)
+        elif isinstance(return_type, UnionType):
+            return make_simplified_union(
+                [self.get_generator_receive_type(item, is_coroutine) for item in return_type.items]
+            )
+        elif not self.is_generator_return_type(
+            return_type, is_coroutine
+        ) and not self.is_async_generator_return_type(return_type):
+            # If the function doesn't have a proper Generator (or
+            # Awaitable) return type, anything is permissible.
+            return AnyType(TypeOfAny.from_error)
+        elif not isinstance(return_type, Instance):
+            # Same as above, but written as a separate branch so the typechecker can understand.
+            return AnyType(TypeOfAny.from_error)
+        elif return_type.type.fullname == "typing.Awaitable":
+            # Awaitable, AwaitableGenerator: tc is Any.
+            return AnyType(TypeOfAny.special_form)
+        elif (
+            return_type.type.fullname in ("typing.Generator", "typing.AwaitableGenerator")
+            and len(return_type.args) >= 3
+        ):
+            # Generator: tc is args[1].
+            return return_type.args[1]
+        elif return_type.type.fullname == "typing.AsyncGenerator" and len(return_type.args) >= 2:
+            return return_type.args[1]
+        else:
+            # `return_type` is a supertype of Generator, so callers won't be able to send it
+            # values.  IOW, tc is None.
+            return NoneType()
+
+    def get_coroutine_return_type(self, return_type: Type) -> Type:
+        return_type = get_proper_type(return_type)
+        if isinstance(return_type, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=return_type)
+        assert isinstance(return_type, Instance), "Should only be called on coroutine functions."
+        # Note: return type is the 3rd type parameter of Coroutine.
+        return return_type.args[2]
+
+    def get_generator_return_type(self, return_type: Type, is_coroutine: bool) -> Type:
+        """Given the declared return type of a generator (t), return the type it returns (tr)."""
+        return_type = get_proper_type(return_type)
+
+        if isinstance(return_type, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=return_type)
+        elif isinstance(return_type, UnionType):
+            return make_simplified_union(
+                [self.get_generator_return_type(item, is_coroutine) for item in return_type.items]
+            )
+        elif not self.is_generator_return_type(return_type, is_coroutine):
+            # If the function doesn't have a proper Generator (or
+            # Awaitable) return type, anything is permissible.
+            return AnyType(TypeOfAny.from_error)
+        elif not isinstance(return_type, Instance):
+            # Same as above, but written as a separate branch so the typechecker can understand.
+            return AnyType(TypeOfAny.from_error)
+        elif return_type.type.fullname == "typing.Awaitable" and len(return_type.args) == 1:
+            # Awaitable: tr is args[0].
+            return return_type.args[0]
+        elif (
+            return_type.type.fullname in ("typing.Generator", "typing.AwaitableGenerator")
+            and len(return_type.args) >= 3
+        ):
+            # AwaitableGenerator, Generator: tr is args[2].
+            return return_type.args[2]
+        else:
+            # Supertype of Generator (Iterator, Iterable, object): tr is any.
+            return AnyType(TypeOfAny.special_form)
+
+    def visit_func_def(self, defn: FuncDef) -> None:
+        if not self.recurse_into_functions:
+            return
+        with self.tscope.function_scope(defn):
+            self._visit_func_def(defn)
+
+    def _visit_func_def(self, defn: FuncDef) -> None:
+        """Type check a function definition."""
+        self.check_func_item(defn, name=defn.name)
+        if defn.info:
+            if not defn.is_dynamic() and not defn.is_overload and not defn.is_decorated:
+                # If the definition is the implementation for an
+                # overload, the legality of the override has already
+                # been typechecked, and decorated methods will be
+                # checked when the decorator is.
+                found_method_base_classes = self.check_method_override(defn)
+                self.check_explicit_override_decorator(defn, found_method_base_classes)
+            self.check_inplace_operator_method(defn)
+        if defn.original_def:
+            # Override previous definition.
+            new_type = self.function_type(defn)
+            if isinstance(defn.original_def, FuncDef):
+                # Function definition overrides function definition.
+                old_type = self.function_type(defn.original_def)
+                if not is_same_type(new_type, old_type):
+                    self.msg.incompatible_conditional_function_def(defn, old_type, new_type)
+            else:
+                # Function definition overrides a variable initialized via assignment or a
+                # decorated function.
+                orig_type = defn.original_def.type
+                if orig_type is None:
+                    # If other branch is unreachable, we don't type check it and so we might
+                    # not have a type for the original definition
+                    return
+                if isinstance(orig_type, PartialType):
+                    if orig_type.type is None:
+                        # Ah this is a partial type. Give it the type of the function.
+                        orig_def = defn.original_def
+                        if isinstance(orig_def, Decorator):
+                            var = orig_def.var
+                        else:
+                            var = orig_def
+                        partial_types = self.find_partial_types(var)
+                        if partial_types is not None:
+                            var.type = new_type
+                            del partial_types[var]
+                    else:
+                        # Trying to redefine something like partial empty list as function.
+                        self.fail(message_registry.INCOMPATIBLE_REDEFINITION, defn)
+                else:
+                    name_expr = NameExpr(defn.name)
+                    name_expr.node = defn.original_def
+                    self.binder.assign_type(name_expr, new_type, orig_type)
+                    self.check_subtype(
+                        new_type,
+                        orig_type,
+                        defn,
+                        message_registry.INCOMPATIBLE_REDEFINITION,
+                        "redefinition with type",
+                        "original type",
+                    )
+
+    def check_func_item(
+        self,
+        defn: FuncItem,
+        type_override: CallableType | None = None,
+        name: str | None = None,
+        allow_empty: bool = False,
+    ) -> None:
+        """Type check a function.
+
+        If type_override is provided, use it as the function type.
+        """
+        self.dynamic_funcs.append(defn.is_dynamic() and not type_override)
+
+        with self.enter_partial_types(is_function=True):
+            typ = self.function_type(defn)
+            if type_override:
+                typ = type_override.copy_modified(line=typ.line, column=typ.column)
+            if isinstance(typ, CallableType):
+                with self.enter_attribute_inference_context():
+                    self.check_func_def(defn, typ, name, allow_empty)
+            else:
+                raise RuntimeError("Not supported")
+
+        self.dynamic_funcs.pop()
+        self.current_node_deferred = False
+
+        if name == "__exit__":
+            self.check__exit__return_type(defn)
+        if name == "__post_init__":
+            if dataclasses_plugin.is_processed_dataclass(defn.info):
+                dataclasses_plugin.check_post_init(self, defn, defn.info)
+
+    @contextmanager
+    def enter_attribute_inference_context(self) -> Iterator[None]:
+        old_types = self.inferred_attribute_types
+        self.inferred_attribute_types = {}
+        yield None
+        self.inferred_attribute_types = old_types
+
+    def check_func_def(
+        self, defn: FuncItem, typ: CallableType, name: str | None, allow_empty: bool = False
+    ) -> None:
+        """Type check a function definition."""
+        # Expand type variables with value restrictions to ordinary types.
+        expanded = self.expand_typevars(defn, typ)
+        for item, typ in expanded:
+            old_binder = self.binder
+            self.binder = ConditionalTypeBinder()
+            with self.binder.top_frame_context():
+                defn.expanded.append(item)
+
+                # We may be checking a function definition or an anonymous
+                # function. In the first case, set up another reference with the
+                # precise type.
+                if isinstance(item, FuncDef):
+                    fdef = item
+                    # Check if __init__ has an invalid return type.
+                    if (
+                        fdef.info
+                        and fdef.name in ("__init__", "__init_subclass__")
+                        and not isinstance(
+                            get_proper_type(typ.ret_type), (NoneType, UninhabitedType)
+                        )
+                        and not self.dynamic_funcs[-1]
+                    ):
+                        self.fail(
+                            message_registry.MUST_HAVE_NONE_RETURN_TYPE.format(fdef.name), item
+                        )
+
+                    # Check validity of __new__ signature
+                    if fdef.info and fdef.name == "__new__":
+                        self.check___new___signature(fdef, typ)
+
+                    self.check_for_missing_annotations(fdef)
+                    if self.options.disallow_any_unimported:
+                        if fdef.type and isinstance(fdef.type, CallableType):
+                            ret_type = fdef.type.ret_type
+                            if has_any_from_unimported_type(ret_type):
+                                self.msg.unimported_type_becomes_any("Return type", ret_type, fdef)
+                            for idx, arg_type in enumerate(fdef.type.arg_types):
+                                if has_any_from_unimported_type(arg_type):
+                                    prefix = f'Argument {idx + 1} to "{fdef.name}"'
+                                    self.msg.unimported_type_becomes_any(prefix, arg_type, fdef)
+                    check_for_explicit_any(
+                        fdef.type, self.options, self.is_typeshed_stub, self.msg, context=fdef
+                    )
+
+                if name:  # Special method names
+                    if defn.info and self.is_reverse_op_method(name):
+                        self.check_reverse_op_method(item, typ, name, defn)
+                    elif name in ("__getattr__", "__getattribute__"):
+                        self.check_getattr_method(typ, defn, name)
+                    elif name == "__setattr__":
+                        self.check_setattr_method(typ, defn)
+
+                # Refuse contravariant return type variable
+                if isinstance(typ.ret_type, TypeVarType):
+                    if typ.ret_type.variance == CONTRAVARIANT:
+                        self.fail(
+                            message_registry.RETURN_TYPE_CANNOT_BE_CONTRAVARIANT, typ.ret_type
+                        )
+                    self.check_unbound_return_typevar(typ)
+
+                # Check that Generator functions have the appropriate return type.
+                if defn.is_generator:
+                    if defn.is_async_generator:
+                        if not self.is_async_generator_return_type(typ.ret_type):
+                            self.fail(
+                                message_registry.INVALID_RETURN_TYPE_FOR_ASYNC_GENERATOR, typ
+                            )
+                    else:
+                        if not self.is_generator_return_type(typ.ret_type, defn.is_coroutine):
+                            self.fail(message_registry.INVALID_RETURN_TYPE_FOR_GENERATOR, typ)
+
+                # Fix the type if decorated with `@types.coroutine` or `@asyncio.coroutine`.
+                if defn.is_awaitable_coroutine:
+                    # Update the return type to AwaitableGenerator.
+                    # (This doesn't exist in typing.py, only in typing.pyi.)
+                    t = typ.ret_type
+                    c = defn.is_coroutine
+                    ty = self.get_generator_yield_type(t, c)
+                    tc = self.get_generator_receive_type(t, c)
+                    if c:
+                        tr = self.get_coroutine_return_type(t)
+                    else:
+                        tr = self.get_generator_return_type(t, c)
+                    ret_type = self.named_generic_type(
+                        "typing.AwaitableGenerator", [ty, tc, tr, t]
+                    )
+                    typ = typ.copy_modified(ret_type=ret_type)
+                    defn.type = typ
+
+                # Push return type.
+                self.return_types.append(typ.ret_type)
+
+                # Store argument types.
+                for i in range(len(typ.arg_types)):
+                    arg_type = typ.arg_types[i]
+                    with self.scope.push_function(defn):
+                        # We temporary push the definition to get the self type as
+                        # visible from *inside* of this function/method.
+                        ref_type: Type | None = self.scope.active_self_type()
+                    if (
+                        isinstance(defn, FuncDef)
+                        and ref_type is not None
+                        and i == 0
+                        and (not defn.is_static or defn.name == "__new__")
+                        and typ.arg_kinds[0] not in [nodes.ARG_STAR, nodes.ARG_STAR2]
+                    ):
+                        if defn.is_class or defn.name == "__new__":
+                            ref_type = mypy.types.TypeType.make_normalized(ref_type)
+                        erased = get_proper_type(erase_to_bound(arg_type))
+                        if not is_subtype(ref_type, erased, ignore_type_params=True):
+                            if (
+                                isinstance(erased, Instance)
+                                and erased.type.is_protocol
+                                or isinstance(erased, TypeType)
+                                and isinstance(erased.item, Instance)
+                                and erased.item.type.is_protocol
+                            ):
+                                # We allow the explicit self-type to be not a supertype of
+                                # the current class if it is a protocol. For such cases
+                                # the consistency check will be performed at call sites.
+                                msg = None
+                            elif typ.arg_names[i] in {"self", "cls"}:
+                                msg = message_registry.ERASED_SELF_TYPE_NOT_SUPERTYPE.format(
+                                    erased.str_with_options(self.options),
+                                    ref_type.str_with_options(self.options),
+                                )
+                            else:
+                                msg = message_registry.MISSING_OR_INVALID_SELF_TYPE
+                            if msg:
+                                self.fail(msg, defn)
+                    elif isinstance(arg_type, TypeVarType):
+                        # Refuse covariant parameter type variables
+                        # TODO: check recursively for inner type variables
+                        if (
+                            arg_type.variance == COVARIANT
+                            and defn.name not in ("__init__", "__new__", "__post_init__")
+                            and not is_private(defn.name)  # private methods are not inherited
+                        ):
+                            ctx: Context = arg_type
+                            if ctx.line < 0:
+                                ctx = typ
+                            self.fail(message_registry.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, ctx)
+                    # Need to store arguments again for the expanded item.
+                    store_argument_type(item, i, typ, self.named_generic_type)
+
+                # Type check initialization expressions.
+                body_is_trivial = is_trivial_body(defn.body)
+                self.check_default_args(item, body_is_trivial)
+
+            # Type check body in a new scope.
+            with self.binder.top_frame_context():
+                # Copy some type narrowings from an outer function when it seems safe enough
+                # (i.e. we can't find an assignment that might change the type of the
+                # variable afterwards).
+                new_frame: Frame | None = None
+                for frame in old_binder.frames:
+                    for key, narrowed_type in frame.types.items():
+                        key_var = extract_var_from_literal_hash(key)
+                        if key_var is not None and not self.is_var_redefined_in_outer_context(
+                            key_var, defn.line
+                        ):
+                            # It seems safe to propagate the type narrowing to a nested scope.
+                            if new_frame is None:
+                                new_frame = self.binder.push_frame()
+                            new_frame.types[key] = narrowed_type
+                            self.binder.declarations[key] = old_binder.declarations[key]
+                with self.scope.push_function(defn):
+                    # We suppress reachability warnings when we use TypeVars with value
+                    # restrictions: we only want to report a warning if a certain statement is
+                    # marked as being suppressed in *all* of the expansions, but we currently
+                    # have no good way of doing this.
+                    #
+                    # TODO: Find a way of working around this limitation
+                    if len(expanded) >= 2:
+                        self.binder.suppress_unreachable_warnings()
+                    self.accept(item.body)
+                unreachable = self.binder.is_unreachable()
+                if new_frame is not None:
+                    self.binder.pop_frame(True, 0)
+
+            if not unreachable:
+                if defn.is_generator or is_named_instance(
+                    self.return_types[-1], "typing.AwaitableGenerator"
+                ):
+                    return_type = self.get_generator_return_type(
+                        self.return_types[-1], defn.is_coroutine
+                    )
+                elif defn.is_coroutine:
+                    return_type = self.get_coroutine_return_type(self.return_types[-1])
+                else:
+                    return_type = self.return_types[-1]
+                return_type = get_proper_type(return_type)
+
+                allow_empty = allow_empty or self.options.allow_empty_bodies
+
+                show_error = (
+                    not body_is_trivial
+                    or
+                    # Allow empty bodies for abstract methods, overloads, in tests and stubs.
+                    (
+                        not allow_empty
+                        and not (
+                            isinstance(defn, FuncDef) and defn.abstract_status != NOT_ABSTRACT
+                        )
+                        and not self.is_stub
+                    )
+                )
+
+                # Ignore plugin generated methods, these usually don't need any bodies.
+                if defn.info is not FUNC_NO_INFO and (
+                    defn.name not in defn.info.names or defn.info.names[defn.name].plugin_generated
+                ):
+                    show_error = False
+
+                # Ignore also definitions that appear in `if TYPE_CHECKING: ...` blocks.
+                # These can't be called at runtime anyway (similar to plugin-generated).
+                if isinstance(defn, FuncDef) and defn.is_mypy_only:
+                    show_error = False
+
+                # We want to minimize the fallout from checking empty bodies
+                # that was absent in many mypy versions.
+                if body_is_trivial and is_subtype(NoneType(), return_type):
+                    show_error = False
+
+                may_be_abstract = (
+                    body_is_trivial
+                    and defn.info is not FUNC_NO_INFO
+                    and defn.info.metaclass_type is not None
+                    and defn.info.metaclass_type.type.has_base("abc.ABCMeta")
+                )
+
+                if self.options.warn_no_return:
+                    if (
+                        not self.current_node_deferred
+                        and not isinstance(return_type, (NoneType, AnyType))
+                        and show_error
+                    ):
+                        # Control flow fell off the end of a function that was
+                        # declared to return a non-None type.
+                        if isinstance(return_type, UninhabitedType):
+                            # This is a NoReturn function
+                            msg = message_registry.INVALID_IMPLICIT_RETURN
+                        else:
+                            msg = message_registry.MISSING_RETURN_STATEMENT
+                        if body_is_trivial:
+                            msg = msg._replace(code=codes.EMPTY_BODY)
+                        self.fail(msg, defn)
+                        if may_be_abstract:
+                            self.note(message_registry.EMPTY_BODY_ABSTRACT, defn)
+                elif show_error:
+                    msg = message_registry.INCOMPATIBLE_RETURN_VALUE_TYPE
+                    if body_is_trivial:
+                        msg = msg._replace(code=codes.EMPTY_BODY)
+                    # similar to code in check_return_stmt
+                    if (
+                        not self.check_subtype(
+                            subtype_label="implicitly returns",
+                            subtype=NoneType(),
+                            supertype_label="expected",
+                            supertype=return_type,
+                            context=defn,
+                            msg=msg,
+                        )
+                        and may_be_abstract
+                    ):
+                        self.note(message_registry.EMPTY_BODY_ABSTRACT, defn)
+
+            self.return_types.pop()
+
+            self.binder = old_binder
+
+    def is_var_redefined_in_outer_context(self, v: Var, after_line: int) -> bool:
+        """Can the variable be assigned to at module top level or outer function?
+
+        Note that this doesn't do a full CFG analysis but uses a line number based
+        heuristic that isn't correct in some (rare) cases.
+        """
+        outers = self.tscope.outer_functions()
+        if not outers:
+            # Top-level function -- outer context is top level, and we can't reason about
+            # globals
+            return True
+        for outer in outers:
+            if isinstance(outer, FuncDef):
+                if find_last_var_assignment_line(outer.body, v) >= after_line:
+                    return True
+        return False
+
+    def check_unbound_return_typevar(self, typ: CallableType) -> None:
+        """Fails when the return typevar is not defined in arguments."""
+        if isinstance(typ.ret_type, TypeVarType) and typ.ret_type in typ.variables:
+            arg_type_visitor = CollectArgTypeVarTypes()
+            for argtype in typ.arg_types:
+                argtype.accept(arg_type_visitor)
+
+            if typ.ret_type not in arg_type_visitor.arg_types:
+                self.fail(message_registry.UNBOUND_TYPEVAR, typ.ret_type, code=TYPE_VAR)
+                upper_bound = get_proper_type(typ.ret_type.upper_bound)
+                if not (
+                    isinstance(upper_bound, Instance)
+                    and upper_bound.type.fullname == "builtins.object"
+                ):
+                    self.note(
+                        "Consider using the upper bound "
+                        f"{format_type(typ.ret_type.upper_bound, self.options)} instead",
+                        context=typ.ret_type,
+                    )
+
+    def check_default_args(self, item: FuncItem, body_is_trivial: bool) -> None:
+        for arg in item.arguments:
+            if arg.initializer is None:
+                continue
+            if body_is_trivial and isinstance(arg.initializer, EllipsisExpr):
+                continue
+            name = arg.variable.name
+            msg = "Incompatible default for "
+            if name.startswith("__tuple_arg_"):
+                msg += f"tuple argument {name[12:]}"
+            else:
+                msg += f'argument "{name}"'
+            if (
+                not self.options.implicit_optional
+                and isinstance(arg.initializer, NameExpr)
+                and arg.initializer.fullname == "builtins.None"
+            ):
+                notes = [
+                    "PEP 484 prohibits implicit Optional. "
+                    "Accordingly, mypy has changed its default to no_implicit_optional=True",
+                    "Use https://github.com/hauntsaninja/no_implicit_optional to automatically "
+                    "upgrade your codebase",
+                ]
+            else:
+                notes = None
+            self.check_simple_assignment(
+                arg.variable.type,
+                arg.initializer,
+                context=arg.initializer,
+                msg=ErrorMessage(msg, code=codes.ASSIGNMENT),
+                lvalue_name="argument",
+                rvalue_name="default",
+                notes=notes,
+            )
+
+    def is_forward_op_method(self, method_name: str) -> bool:
+        return method_name in operators.reverse_op_methods
+
+    def is_reverse_op_method(self, method_name: str) -> bool:
+        return method_name in operators.reverse_op_method_set
+
+    def check_for_missing_annotations(self, fdef: FuncItem) -> None:
+        # Check for functions with unspecified/not fully specified types.
+        def is_unannotated_any(t: Type) -> bool:
+            if not isinstance(t, ProperType):
+                return False
+            return isinstance(t, AnyType) and t.type_of_any == TypeOfAny.unannotated
+
+        has_explicit_annotation = isinstance(fdef.type, CallableType) and any(
+            not is_unannotated_any(t) for t in fdef.type.arg_types + [fdef.type.ret_type]
+        )
+
+        show_untyped = not self.is_typeshed_stub or self.options.warn_incomplete_stub
+        check_incomplete_defs = self.options.disallow_incomplete_defs and has_explicit_annotation
+        if show_untyped and (self.options.disallow_untyped_defs or check_incomplete_defs):
+            if fdef.type is None and self.options.disallow_untyped_defs:
+                if not fdef.arguments or (
+                    len(fdef.arguments) == 1
+                    and (fdef.arg_names[0] == "self" or fdef.arg_names[0] == "cls")
+                ):
+                    self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef)
+                    if not has_return_statement(fdef) and not fdef.is_generator:
+                        self.note(
+                            'Use "-> None" if function does not return a value',
+                            fdef,
+                            code=codes.NO_UNTYPED_DEF,
+                        )
+                else:
+                    self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef)
+            elif isinstance(fdef.type, CallableType):
+                ret_type = get_proper_type(fdef.type.ret_type)
+                if is_unannotated_any(ret_type):
+                    self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef)
+                elif fdef.is_generator:
+                    if is_unannotated_any(
+                        self.get_generator_return_type(ret_type, fdef.is_coroutine)
+                    ):
+                        self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef)
+                elif fdef.is_coroutine and isinstance(ret_type, Instance):
+                    if is_unannotated_any(self.get_coroutine_return_type(ret_type)):
+                        self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef)
+                if any(is_unannotated_any(t) for t in fdef.type.arg_types):
+                    self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef)
+
+    def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None:
+        self_type = fill_typevars_with_any(fdef.info)
+        bound_type = bind_self(typ, self_type, is_classmethod=True)
+        # Check that __new__ (after binding cls) returns an instance
+        # type (or any).
+        if fdef.info.is_metaclass():
+            # This is a metaclass, so it must return a new unrelated type.
+            self.check_subtype(
+                bound_type.ret_type,
+                self.type_type(),
+                fdef,
+                message_registry.INVALID_NEW_TYPE,
+                "returns",
+                "but must return a subtype of",
+            )
+        elif not isinstance(
+            get_proper_type(bound_type.ret_type), (AnyType, Instance, TupleType, UninhabitedType)
+        ):
+            self.fail(
+                message_registry.NON_INSTANCE_NEW_TYPE.format(
+                    format_type(bound_type.ret_type, self.options)
+                ),
+                fdef,
+            )
+        else:
+            # And that it returns a subtype of the class
+            self.check_subtype(
+                bound_type.ret_type,
+                self_type,
+                fdef,
+                message_registry.INVALID_NEW_TYPE,
+                "returns",
+                "but must return a subtype of",
+            )
+
+    def check_reverse_op_method(
+        self, defn: FuncItem, reverse_type: CallableType, reverse_name: str, context: Context
+    ) -> None:
+        """Check a reverse operator method such as __radd__."""
+        # Decides whether it's worth calling check_overlapping_op_methods().
+
+        # This used to check for some very obscure scenario.  It now
+        # just decides whether it's worth calling
+        # check_overlapping_op_methods().
+
+        assert defn.info
+
+        # First check for a valid signature
+        method_type = CallableType(
+            [AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)],
+            [nodes.ARG_POS, nodes.ARG_POS],
+            [None, None],
+            AnyType(TypeOfAny.special_form),
+            self.named_type("builtins.function"),
+        )
+        if not is_subtype(reverse_type, method_type):
+            self.msg.invalid_signature(reverse_type, context)
+            return
+
+        if reverse_name in ("__eq__", "__ne__"):
+            # These are defined for all objects => can't cause trouble.
+            return
+
+        # With 'Any' or 'object' return type we are happy, since any possible
+        # return value is valid.
+        ret_type = get_proper_type(reverse_type.ret_type)
+        if isinstance(ret_type, AnyType):
+            return
+        if isinstance(ret_type, Instance):
+            if ret_type.type.fullname == "builtins.object":
+                return
+        if reverse_type.arg_kinds[0] == ARG_STAR:
+            reverse_type = reverse_type.copy_modified(
+                arg_types=[reverse_type.arg_types[0]] * 2,
+                arg_kinds=[ARG_POS] * 2,
+                arg_names=[reverse_type.arg_names[0], "_"],
+            )
+        assert len(reverse_type.arg_types) >= 2
+
+        forward_name = operators.normal_from_reverse_op[reverse_name]
+        forward_inst = get_proper_type(reverse_type.arg_types[1])
+        if isinstance(forward_inst, TypeVarType):
+            forward_inst = get_proper_type(forward_inst.upper_bound)
+        elif isinstance(forward_inst, TupleType):
+            forward_inst = tuple_fallback(forward_inst)
+        elif isinstance(forward_inst, (FunctionLike, TypedDictType, LiteralType)):
+            forward_inst = forward_inst.fallback
+        if isinstance(forward_inst, TypeType):
+            item = forward_inst.item
+            if isinstance(item, Instance):
+                opt_meta = item.type.metaclass_type
+                if opt_meta is not None:
+                    forward_inst = opt_meta
+
+        def has_readable_member(typ: UnionType | Instance, name: str) -> bool:
+            # TODO: Deal with attributes of TupleType etc.
+            if isinstance(typ, Instance):
+                return typ.type.has_readable_member(name)
+            return all(
+                (isinstance(x, UnionType) and has_readable_member(x, name))
+                or (isinstance(x, Instance) and x.type.has_readable_member(name))
+                for x in get_proper_types(typ.relevant_items())
+            )
+
+        if not (
+            isinstance(forward_inst, (Instance, UnionType))
+            and has_readable_member(forward_inst, forward_name)
+        ):
+            return
+        forward_base = reverse_type.arg_types[1]
+        forward_type = self.expr_checker.analyze_external_member_access(
+            forward_name, forward_base, context=defn
+        )
+        self.check_overlapping_op_methods(
+            reverse_type,
+            reverse_name,
+            defn.info,
+            forward_type,
+            forward_name,
+            forward_base,
+            context=defn,
+        )
+
+    def check_overlapping_op_methods(
+        self,
+        reverse_type: CallableType,
+        reverse_name: str,
+        reverse_class: TypeInfo,
+        forward_type: Type,
+        forward_name: str,
+        forward_base: Type,
+        context: Context,
+    ) -> None:
+        """Check for overlapping method and reverse method signatures.
+
+        This function assumes that:
+
+        -   The reverse method has valid argument count and kinds.
+        -   If the reverse operator method accepts some argument of type
+            X, the forward operator method also belong to class X.
+
+            For example, if we have the reverse operator `A.__radd__(B)`, then the
+            corresponding forward operator must have the type `B.__add__(...)`.
+        """
+
+        # Note: Suppose we have two operator methods "A.__rOP__(B) -> R1" and
+        # "B.__OP__(C) -> R2". We check if these two methods are unsafely overlapping
+        # by using the following algorithm:
+        #
+        # 1. Rewrite "B.__OP__(C) -> R1"  to "temp1(B, C) -> R1"
+        #
+        # 2. Rewrite "A.__rOP__(B) -> R2" to "temp2(B, A) -> R2"
+        #
+        # 3. Treat temp1 and temp2 as if they were both variants in the same
+        #    overloaded function. (This mirrors how the Python runtime calls
+        #    operator methods: we first try __OP__, then __rOP__.)
+        #
+        #    If the first signature is unsafely overlapping with the second,
+        #    report an error.
+        #
+        # 4. However, if temp1 shadows temp2 (e.g. the __rOP__ method can never
+        #    be called), do NOT report an error.
+        #
+        #    This behavior deviates from how we handle overloads -- many of the
+        #    modules in typeshed seem to define __OP__ methods that shadow the
+        #    corresponding __rOP__ method.
+        #
+        # Note: we do not attempt to handle unsafe overlaps related to multiple
+        # inheritance. (This is consistent with how we handle overloads: we also
+        # do not try checking unsafe overlaps due to multiple inheritance there.)
+
+        for forward_item in flatten_nested_unions([forward_type]):
+            forward_item = get_proper_type(forward_item)
+            if isinstance(forward_item, CallableType):
+                if self.is_unsafe_overlapping_op(forward_item, forward_base, reverse_type):
+                    self.msg.operator_method_signatures_overlap(
+                        reverse_class, reverse_name, forward_base, forward_name, context
+                    )
+            elif isinstance(forward_item, Overloaded):
+                for item in forward_item.items:
+                    if self.is_unsafe_overlapping_op(item, forward_base, reverse_type):
+                        self.msg.operator_method_signatures_overlap(
+                            reverse_class, reverse_name, forward_base, forward_name, context
+                        )
+            elif not isinstance(forward_item, AnyType):
+                self.msg.forward_operator_not_callable(forward_name, context)
+
+    def is_unsafe_overlapping_op(
+        self, forward_item: CallableType, forward_base: Type, reverse_type: CallableType
+    ) -> bool:
+        # TODO: check argument kinds?
+        if len(forward_item.arg_types) < 1:
+            # Not a valid operator method -- can't succeed anyway.
+            return False
+
+        # Erase the type if necessary to make sure we don't have a single
+        # TypeVar in forward_tweaked. (Having a function signature containing
+        # just a single TypeVar can lead to unpredictable behavior.)
+        forward_base_erased = forward_base
+        if isinstance(forward_base, TypeVarType):
+            forward_base_erased = erase_to_bound(forward_base)
+
+        # Construct normalized function signatures corresponding to the
+        # operator methods. The first argument is the left operand and the
+        # second operand is the right argument -- we switch the order of
+        # the arguments of the reverse method.
+
+        forward_tweaked = forward_item.copy_modified(
+            arg_types=[forward_base_erased, forward_item.arg_types[0]],
+            arg_kinds=[nodes.ARG_POS] * 2,
+            arg_names=[None] * 2,
+        )
+        reverse_tweaked = reverse_type.copy_modified(
+            arg_types=[reverse_type.arg_types[1], reverse_type.arg_types[0]],
+            arg_kinds=[nodes.ARG_POS] * 2,
+            arg_names=[None] * 2,
+        )
+
+        reverse_base_erased = reverse_type.arg_types[0]
+        if isinstance(reverse_base_erased, TypeVarType):
+            reverse_base_erased = erase_to_bound(reverse_base_erased)
+
+        if is_same_type(reverse_base_erased, forward_base_erased):
+            return False
+        elif is_subtype(reverse_base_erased, forward_base_erased):
+            first = reverse_tweaked
+            second = forward_tweaked
+        else:
+            first = forward_tweaked
+            second = reverse_tweaked
+
+        return is_unsafe_overlapping_overload_signatures(first, second)
+
+    def check_inplace_operator_method(self, defn: FuncBase) -> None:
+        """Check an inplace operator method such as __iadd__.
+
+        They cannot arbitrarily overlap with __add__.
+        """
+        method = defn.name
+        if method not in operators.inplace_operator_methods:
+            return
+        typ = bind_self(self.function_type(defn))
+        cls = defn.info
+        other_method = "__" + method[3:]
+        if cls.has_readable_member(other_method):
+            instance = fill_typevars(cls)
+            typ2 = get_proper_type(
+                self.expr_checker.analyze_external_member_access(other_method, instance, defn)
+            )
+            fail = False
+            if isinstance(typ2, FunctionLike):
+                if not is_more_general_arg_prefix(typ, typ2):
+                    fail = True
+            else:
+                # TODO overloads
+                fail = True
+            if fail:
+                self.msg.signatures_incompatible(method, other_method, defn)
+
+    def check_getattr_method(self, typ: Type, context: Context, name: str) -> None:
+        if len(self.scope.stack) == 1:
+            # module scope
+            if name == "__getattribute__":
+                self.fail(message_registry.MODULE_LEVEL_GETATTRIBUTE, context)
+                return
+            # __getattr__ is fine at the module level as of Python 3.7 (PEP 562). We could
+            # show an error for Python < 3.7, but that would be annoying in code that supports
+            # both 3.7 and older versions.
+            method_type = CallableType(
+                [self.named_type("builtins.str")],
+                [nodes.ARG_POS],
+                [None],
+                AnyType(TypeOfAny.special_form),
+                self.named_type("builtins.function"),
+            )
+        elif self.scope.active_class():
+            method_type = CallableType(
+                [AnyType(TypeOfAny.special_form), self.named_type("builtins.str")],
+                [nodes.ARG_POS, nodes.ARG_POS],
+                [None, None],
+                AnyType(TypeOfAny.special_form),
+                self.named_type("builtins.function"),
+            )
+        else:
+            return
+        if not is_subtype(typ, method_type):
+            self.msg.invalid_signature_for_special_method(typ, context, name)
+
+    def check_setattr_method(self, typ: Type, context: Context) -> None:
+        if not self.scope.active_class():
+            return
+        method_type = CallableType(
+            [
+                AnyType(TypeOfAny.special_form),
+                self.named_type("builtins.str"),
+                AnyType(TypeOfAny.special_form),
+            ],
+            [nodes.ARG_POS, nodes.ARG_POS, nodes.ARG_POS],
+            [None, None, None],
+            NoneType(),
+            self.named_type("builtins.function"),
+        )
+        if not is_subtype(typ, method_type):
+            self.msg.invalid_signature_for_special_method(typ, context, "__setattr__")
+
+    def check_slots_definition(self, typ: Type, context: Context) -> None:
+        """Check the type of __slots__."""
+        str_type = self.named_type("builtins.str")
+        expected_type = UnionType(
+            [str_type, self.named_generic_type("typing.Iterable", [str_type])]
+        )
+        self.check_subtype(
+            typ,
+            expected_type,
+            context,
+            message_registry.INVALID_TYPE_FOR_SLOTS,
+            "actual type",
+            "expected type",
+            code=codes.ASSIGNMENT,
+        )
+
+    def check_match_args(self, var: Var, typ: Type, context: Context) -> None:
+        """Check that __match_args__ contains literal strings"""
+        if not self.scope.active_class():
+            return
+        typ = get_proper_type(typ)
+        if not isinstance(typ, TupleType) or not all(
+            [is_string_literal(item) for item in typ.items]
+        ):
+            self.msg.note(
+                "__match_args__ must be a tuple containing string literals for checking "
+                "of match statements to work",
+                context,
+                code=codes.LITERAL_REQ,
+            )
+
+    def expand_typevars(
+        self, defn: FuncItem, typ: CallableType
+    ) -> list[tuple[FuncItem, CallableType]]:
+        # TODO use generator
+        subst: list[list[tuple[TypeVarId, Type]]] = []
+        tvars = list(typ.variables) or []
+        if defn.info:
+            # Class type variables
+            tvars += defn.info.defn.type_vars or []
+        # TODO(PEP612): audit for paramspec
+        for tvar in tvars:
+            if isinstance(tvar, TypeVarType) and tvar.values:
+                subst.append([(tvar.id, value) for value in tvar.values])
+        # Make a copy of the function to check for each combination of
+        # value restricted type variables. (Except when running mypyc,
+        # where we need one canonical version of the function.)
+        if subst and not (self.options.mypyc or self.options.inspections):
+            result: list[tuple[FuncItem, CallableType]] = []
+            for substitutions in itertools.product(*subst):
+                mapping = dict(substitutions)
+                result.append((expand_func(defn, mapping), expand_type(typ, mapping)))
+            return result
+        else:
+            return [(defn, typ)]
+
+    def check_explicit_override_decorator(
+        self,
+        defn: FuncDef | OverloadedFuncDef,
+        found_method_base_classes: list[TypeInfo] | None,
+        context: Context | None = None,
+    ) -> None:
+        if (
+            found_method_base_classes
+            and not defn.is_explicit_override
+            and defn.name not in ("__init__", "__new__")
+        ):
+            self.msg.explicit_override_decorator_missing(
+                defn.name, found_method_base_classes[0].fullname, context or defn
+            )
+
+    def check_method_override(
+        self, defn: FuncDef | OverloadedFuncDef | Decorator
+    ) -> list[TypeInfo] | None:
+        """Check if function definition is compatible with base classes.
+
+        This may defer the method if a signature is not available in at least one base class.
+        Return ``None`` if that happens.
+
+        Return a list of base classes which contain an attribute with the method name.
+        """
+        # Check against definitions in base classes.
+        found_method_base_classes: list[TypeInfo] = []
+        for base in defn.info.mro[1:]:
+            result = self.check_method_or_accessor_override_for_base(defn, base)
+            if result is None:
+                # Node was deferred, we will have another attempt later.
+                return None
+            if result:
+                found_method_base_classes.append(base)
+        return found_method_base_classes
+
+    def check_method_or_accessor_override_for_base(
+        self, defn: FuncDef | OverloadedFuncDef | Decorator, base: TypeInfo
+    ) -> bool | None:
+        """Check if method definition is compatible with a base class.
+
+        Return ``None`` if the node was deferred because one of the corresponding
+        superclass nodes is not ready.
+
+        Return ``True`` if an attribute with the method name was found in the base class.
+        """
+        found_base_method = False
+        if base:
+            name = defn.name
+            base_attr = base.names.get(name)
+            if base_attr:
+                # First, check if we override a final (always an error, even with Any types).
+                if is_final_node(base_attr.node):
+                    self.msg.cant_override_final(name, base.name, defn)
+                # Second, final can't override anything writeable independently of types.
+                if defn.is_final:
+                    self.check_if_final_var_override_writable(name, base_attr.node, defn)
+                found_base_method = True
+
+            # Check the type of override.
+            if name not in ("__init__", "__new__", "__init_subclass__", "__post_init__"):
+                # Check method override
+                # (__init__, __new__, __init_subclass__ are special).
+                if self.check_method_override_for_base_with_name(defn, name, base):
+                    return None
+                if name in operators.inplace_operator_methods:
+                    # Figure out the name of the corresponding operator method.
+                    method = "__" + name[3:]
+                    # An inplace operator method such as __iadd__ might not be
+                    # always introduced safely if a base class defined __add__.
+                    # TODO can't come up with an example where this is
+                    #      necessary; now it's "just in case"
+                    if self.check_method_override_for_base_with_name(defn, method, base):
+                        return None
+        return found_base_method
+
+    def check_method_override_for_base_with_name(
+        self, defn: FuncDef | OverloadedFuncDef | Decorator, name: str, base: TypeInfo
+    ) -> bool:
+        """Check if overriding an attribute `name` of `base` with `defn` is valid.
+
+        Return True if the supertype node was not analysed yet, and `defn` was deferred.
+        """
+        base_attr = base.names.get(name)
+        if base_attr:
+            # The name of the method is defined in the base class.
+
+            # Point errors at the 'def' line (important for backward compatibility
+            # of type ignores).
+            if not isinstance(defn, Decorator):
+                context = defn
+            else:
+                context = defn.func
+
+            # Construct the type of the overriding method.
+            # TODO: this logic is much less complete than similar one in checkmember.py
+            if isinstance(defn, (FuncDef, OverloadedFuncDef)):
+                typ: Type = self.function_type(defn)
+                override_class_or_static = defn.is_class or defn.is_static
+                override_class = defn.is_class
+            else:
+                assert defn.var.is_ready
+                assert defn.var.type is not None
+                typ = defn.var.type
+                override_class_or_static = defn.func.is_class or defn.func.is_static
+                override_class = defn.func.is_class
+            typ = get_proper_type(typ)
+            if isinstance(typ, FunctionLike) and not is_static(context):
+                typ = bind_self(typ, self.scope.active_self_type(), is_classmethod=override_class)
+            # Map the overridden method type to subtype context so that
+            # it can be checked for compatibility.
+            original_type = get_proper_type(base_attr.type)
+            original_node = base_attr.node
+            # `original_type` can be partial if (e.g.) it is originally an
+            # instance variable from an `__init__` block that becomes deferred.
+            if original_type is None or isinstance(original_type, PartialType):
+                if self.pass_num < self.last_pass:
+                    # If there are passes left, defer this node until next pass,
+                    # otherwise try reconstructing the method type from available information.
+                    self.defer_node(defn, defn.info)
+                    return True
+                elif isinstance(original_node, (FuncDef, OverloadedFuncDef)):
+                    original_type = self.function_type(original_node)
+                elif isinstance(original_node, Decorator):
+                    original_type = self.function_type(original_node.func)
+                elif isinstance(original_node, Var):
+                    # Super type can define method as an attribute.
+                    # See https://github.com/python/mypy/issues/10134
+
+                    # We also check that sometimes `original_node.type` is None.
+                    # This is the case when we use something like `__hash__ = None`.
+                    if original_node.type is not None:
+                        original_type = get_proper_type(original_node.type)
+                    else:
+                        original_type = NoneType()
+                else:
+                    # Will always fail to typecheck below, since we know the node is a method
+                    original_type = NoneType()
+            if isinstance(original_node, (FuncDef, OverloadedFuncDef)):
+                original_class_or_static = original_node.is_class or original_node.is_static
+            elif isinstance(original_node, Decorator):
+                fdef = original_node.func
+                original_class_or_static = fdef.is_class or fdef.is_static
+            else:
+                original_class_or_static = False  # a variable can't be class or static
+
+            if isinstance(original_type, FunctionLike):
+                original_type = self.bind_and_map_method(base_attr, original_type, defn.info, base)
+                if original_node and is_property(original_node):
+                    original_type = get_property_type(original_type)
+
+            if isinstance(typ, FunctionLike) and is_property(defn):
+                typ = get_property_type(typ)
+                if (
+                    isinstance(original_node, Var)
+                    and not original_node.is_final
+                    and (not original_node.is_property or original_node.is_settable_property)
+                    and isinstance(defn, Decorator)
+                ):
+                    # We only give an error where no other similar errors will be given.
+                    if not isinstance(original_type, AnyType):
+                        self.msg.fail(
+                            "Cannot override writeable attribute with read-only property",
+                            # Give an error on function line to match old behaviour.
+                            defn.func,
+                            code=codes.OVERRIDE,
+                        )
+
+            if isinstance(original_type, AnyType) or isinstance(typ, AnyType):
+                pass
+            elif isinstance(original_type, FunctionLike) and isinstance(typ, FunctionLike):
+                # Check that the types are compatible.
+                # TODO overloaded signatures
+                self.check_override(
+                    typ,
+                    original_type,
+                    defn.name,
+                    name,
+                    base.name,
+                    original_class_or_static,
+                    override_class_or_static,
+                    context,
+                )
+            elif is_equivalent(original_type, typ):
+                # Assume invariance for a non-callable attribute here. Note
+                # that this doesn't affect read-only properties which can have
+                # covariant overrides.
+                #
+                pass
+            elif (
+                original_node
+                and not self.is_writable_attribute(original_node)
+                and is_subtype(typ, original_type)
+            ):
+                # If the attribute is read-only, allow covariance
+                pass
+            else:
+                self.msg.signature_incompatible_with_supertype(
+                    defn.name, name, base.name, context, original=original_type, override=typ
+                )
+        return False
+
+    def bind_and_map_method(
+        self, sym: SymbolTableNode, typ: FunctionLike, sub_info: TypeInfo, super_info: TypeInfo
+    ) -> FunctionLike:
+        """Bind self-type and map type variables for a method.
+
+        Arguments:
+            sym: a symbol that points to method definition
+            typ: method type on the definition
+            sub_info: class where the method is used
+            super_info: class where the method was defined
+        """
+        if isinstance(sym.node, (FuncDef, OverloadedFuncDef, Decorator)) and not is_static(
+            sym.node
+        ):
+            if isinstance(sym.node, Decorator):
+                is_class_method = sym.node.func.is_class
+            else:
+                is_class_method = sym.node.is_class
+
+            mapped_typ = cast(FunctionLike, map_type_from_supertype(typ, sub_info, super_info))
+            active_self_type = self.scope.active_self_type()
+            if isinstance(mapped_typ, Overloaded) and active_self_type:
+                # If we have an overload, filter to overloads that match the self type.
+                # This avoids false positives for concrete subclasses of generic classes,
+                # see testSelfTypeOverrideCompatibility for an example.
+                filtered_items = []
+                for item in mapped_typ.items:
+                    if not item.arg_types:
+                        filtered_items.append(item)
+                    item_arg = item.arg_types[0]
+                    if isinstance(item_arg, TypeVarType):
+                        item_arg = item_arg.upper_bound
+                    if is_subtype(active_self_type, item_arg):
+                        filtered_items.append(item)
+                # If we don't have any filtered_items, maybe it's always a valid override
+                # of the superclass? However if you get to that point you're in murky type
+                # territory anyway, so we just preserve the type and have the behaviour match
+                # that of older versions of mypy.
+                if filtered_items:
+                    mapped_typ = Overloaded(filtered_items)
+
+            return bind_self(mapped_typ, active_self_type, is_class_method)
+        else:
+            return cast(FunctionLike, map_type_from_supertype(typ, sub_info, super_info))
+
+    def get_op_other_domain(self, tp: FunctionLike) -> Type | None:
+        if isinstance(tp, CallableType):
+            if tp.arg_kinds and tp.arg_kinds[0] == ARG_POS:
+                return tp.arg_types[0]
+            return None
+        elif isinstance(tp, Overloaded):
+            raw_items = [self.get_op_other_domain(it) for it in tp.items]
+            items = [it for it in raw_items if it]
+            if items:
+                return make_simplified_union(items)
+            return None
+        else:
+            assert False, "Need to check all FunctionLike subtypes here"
+
+    def check_override(
+        self,
+        override: FunctionLike,
+        original: FunctionLike,
+        name: str,
+        name_in_super: str,
+        supertype: str,
+        original_class_or_static: bool,
+        override_class_or_static: bool,
+        node: Context,
+    ) -> None:
+        """Check a method override with given signatures.
+
+        Arguments:
+          override:  The signature of the overriding method.
+          original:  The signature of the original supertype method.
+          name:      The name of the subtype. This and the next argument are
+                     only used for generating error messages.
+          supertype: The name of the supertype.
+        """
+        # Use boolean variable to clarify code.
+        fail = False
+        op_method_wider_note = False
+        if not is_subtype(override, original, ignore_pos_arg_names=True):
+            fail = True
+        elif isinstance(override, Overloaded) and self.is_forward_op_method(name):
+            # Operator method overrides cannot extend the domain, as
+            # this could be unsafe with reverse operator methods.
+            original_domain = self.get_op_other_domain(original)
+            override_domain = self.get_op_other_domain(override)
+            if (
+                original_domain
+                and override_domain
+                and not is_subtype(override_domain, original_domain)
+            ):
+                fail = True
+                op_method_wider_note = True
+        if isinstance(override, FunctionLike):
+            if original_class_or_static and not override_class_or_static:
+                fail = True
+            elif isinstance(original, CallableType) and isinstance(override, CallableType):
+                if original.type_guard is not None and override.type_guard is None:
+                    fail = True
+
+        if is_private(name):
+            fail = False
+
+        if fail:
+            emitted_msg = False
+
+            # Normalize signatures, so we get better diagnostics.
+            if isinstance(override, (CallableType, Overloaded)):
+                override = override.with_unpacked_kwargs()
+            if isinstance(original, (CallableType, Overloaded)):
+                original = original.with_unpacked_kwargs()
+
+            if (
+                isinstance(override, CallableType)
+                and isinstance(original, CallableType)
+                and len(override.arg_types) == len(original.arg_types)
+                and override.min_args == original.min_args
+            ):
+                # Give more detailed messages for the common case of both
+                # signatures having the same number of arguments and no
+                # overloads.
+
+                # override might have its own generic function type
+                # variables. If an argument or return type of override
+                # does not have the correct subtyping relationship
+                # with the original type even after these variables
+                # are erased, then it is definitely an incompatibility.
+
+                override_ids = override.type_var_ids()
+                type_name = None
+                if isinstance(override.definition, FuncDef):
+                    type_name = override.definition.info.name
+
+                def erase_override(t: Type) -> Type:
+                    return erase_typevars(t, ids_to_erase=override_ids)
+
+                for i in range(len(override.arg_types)):
+                    if not is_subtype(
+                        original.arg_types[i], erase_override(override.arg_types[i])
+                    ):
+                        arg_type_in_super = original.arg_types[i]
+
+                        if isinstance(node, FuncDef):
+                            context: Context = node.arguments[i + len(override.bound_args)]
+                        else:
+                            context = node
+                        self.msg.argument_incompatible_with_supertype(
+                            i + 1,
+                            name,
+                            type_name,
+                            name_in_super,
+                            arg_type_in_super,
+                            supertype,
+                            context,
+                            secondary_context=node,
+                        )
+                        emitted_msg = True
+
+                if not is_subtype(erase_override(override.ret_type), original.ret_type):
+                    self.msg.return_type_incompatible_with_supertype(
+                        name, name_in_super, supertype, original.ret_type, override.ret_type, node
+                    )
+                    emitted_msg = True
+            elif isinstance(override, Overloaded) and isinstance(original, Overloaded):
+                # Give a more detailed message in the case where the user is trying to
+                # override an overload, and the subclass's overload is plausible, except
+                # that the order of the variants are wrong.
+                #
+                # For example, if the parent defines the overload f(int) -> int and f(str) -> str
+                # (in that order), and if the child swaps the two and does f(str) -> str and
+                # f(int) -> int
+                order = []
+                for child_variant in override.items:
+                    for i, parent_variant in enumerate(original.items):
+                        if is_subtype(child_variant, parent_variant):
+                            order.append(i)
+                            break
+
+                if len(order) == len(original.items) and order != sorted(order):
+                    self.msg.overload_signature_incompatible_with_supertype(
+                        name, name_in_super, supertype, node
+                    )
+                    emitted_msg = True
+
+            if not emitted_msg:
+                # Fall back to generic incompatibility message.
+                self.msg.signature_incompatible_with_supertype(
+                    name, name_in_super, supertype, node, original=original, override=override
+                )
+            if op_method_wider_note:
+                self.note(
+                    "Overloaded operator methods can't have wider argument types in overrides",
+                    node,
+                    code=codes.OVERRIDE,
+                )
+
+    def check__exit__return_type(self, defn: FuncItem) -> None:
+        """Generate error if the return type of __exit__ is problematic.
+
+        If __exit__ always returns False but the return type is declared
+        as bool, mypy thinks that a with statement may "swallow"
+        exceptions even though this is not the case, resulting in
+        invalid reachability inference.
+        """
+        if not defn.type or not isinstance(defn.type, CallableType):
+            return
+
+        ret_type = get_proper_type(defn.type.ret_type)
+        if not has_bool_item(ret_type):
+            return
+
+        returns = all_return_statements(defn)
+        if not returns:
+            return
+
+        if all(
+            isinstance(ret.expr, NameExpr) and ret.expr.fullname == "builtins.False"
+            for ret in returns
+        ):
+            self.msg.incorrect__exit__return(defn)
+
+    def visit_class_def(self, defn: ClassDef) -> None:
+        """Type check a class definition."""
+        typ = defn.info
+        for base in typ.mro[1:]:
+            if base.is_final:
+                self.fail(message_registry.CANNOT_INHERIT_FROM_FINAL.format(base.name), defn)
+        with self.tscope.class_scope(defn.info), self.enter_partial_types(is_class=True):
+            old_binder = self.binder
+            self.binder = ConditionalTypeBinder()
+            with self.binder.top_frame_context():
+                with self.scope.push_class(defn.info):
+                    self.accept(defn.defs)
+            self.binder = old_binder
+            if not (defn.info.typeddict_type or defn.info.tuple_type or defn.info.is_enum):
+                # If it is not a normal class (not a special form) check class keywords.
+                self.check_init_subclass(defn)
+            if not defn.has_incompatible_baseclass:
+                # Otherwise we've already found errors; more errors are not useful
+                self.check_multiple_inheritance(typ)
+            self.check_metaclass_compatibility(typ)
+            self.check_final_deletable(typ)
+
+            if defn.decorators:
+                sig: Type = type_object_type(defn.info, self.named_type)
+                # Decorators are applied in reverse order.
+                for decorator in reversed(defn.decorators):
+                    if isinstance(decorator, CallExpr) and isinstance(
+                        decorator.analyzed, PromoteExpr
+                    ):
+                        # _promote is a special type checking related construct.
+                        continue
+
+                    dec = self.expr_checker.accept(decorator)
+                    temp = self.temp_node(sig, context=decorator)
+                    fullname = None
+                    if isinstance(decorator, RefExpr):
+                        fullname = decorator.fullname or None
+
+                    # TODO: Figure out how to have clearer error messages.
+                    # (e.g. "class decorator must be a function that accepts a type."
+                    old_allow_abstract_call = self.allow_abstract_call
+                    self.allow_abstract_call = True
+                    sig, _ = self.expr_checker.check_call(
+                        dec, [temp], [nodes.ARG_POS], defn, callable_name=fullname
+                    )
+                    self.allow_abstract_call = old_allow_abstract_call
+                # TODO: Apply the sig to the actual TypeInfo so we can handle decorators
+                # that completely swap out the type.  (e.g. Callable[[Type[A]], Type[B]])
+        if typ.defn.type_vars:
+            for base_inst in typ.bases:
+                for base_tvar, base_decl_tvar in zip(
+                    base_inst.args, base_inst.type.defn.type_vars
+                ):
+                    if (
+                        isinstance(base_tvar, TypeVarType)
+                        and base_tvar.variance != INVARIANT
+                        and isinstance(base_decl_tvar, TypeVarType)
+                        and base_decl_tvar.variance != base_tvar.variance
+                    ):
+                        self.fail(
+                            f'Variance of TypeVar "{base_tvar.name}" incompatible '
+                            "with variance in parent type",
+                            context=defn,
+                            code=codes.TYPE_VAR,
+                        )
+
+        if typ.is_protocol and typ.defn.type_vars:
+            self.check_protocol_variance(defn)
+        if not defn.has_incompatible_baseclass and defn.info.is_enum:
+            self.check_enum(defn)
+
+    def check_final_deletable(self, typ: TypeInfo) -> None:
+        # These checks are only for mypyc. Only perform some checks that are easier
+        # to implement here than in mypyc.
+        for attr in typ.deletable_attributes:
+            node = typ.names.get(attr)
+            if node and isinstance(node.node, Var) and node.node.is_final:
+                self.fail(message_registry.CANNOT_MAKE_DELETABLE_FINAL, node.node)
+
+    def check_init_subclass(self, defn: ClassDef) -> None:
+        """Check that keywords in a class definition are valid arguments for __init_subclass__().
+
+        In this example:
+            1   class Base:
+            2       def __init_subclass__(cls, thing: int):
+            3           pass
+            4   class Child(Base, thing=5):
+            5       def __init_subclass__(cls):
+            6           pass
+            7   Child()
+
+        Base.__init_subclass__(thing=5) is called at line 4. This is what we simulate here.
+        Child.__init_subclass__ is never called.
+        """
+        if defn.info.metaclass_type and defn.info.metaclass_type.type.fullname not in (
+            "builtins.type",
+            "abc.ABCMeta",
+        ):
+            # We can't safely check situations when both __init_subclass__ and a custom
+            # metaclass are present.
+            return
+        # At runtime, only Base.__init_subclass__ will be called, so
+        # we skip the current class itself.
+        for base in defn.info.mro[1:]:
+            if "__init_subclass__" not in base.names:
+                continue
+            name_expr = NameExpr(defn.name)
+            name_expr.node = base
+            callee = MemberExpr(name_expr, "__init_subclass__")
+            args = list(defn.keywords.values())
+            arg_names: list[str | None] = list(defn.keywords.keys())
+            # 'metaclass' keyword is consumed by the rest of the type machinery,
+            # and is never passed to __init_subclass__ implementations
+            if "metaclass" in arg_names:
+                idx = arg_names.index("metaclass")
+                arg_names.pop(idx)
+                args.pop(idx)
+            arg_kinds = [ARG_NAMED] * len(args)
+            call_expr = CallExpr(callee, args, arg_kinds, arg_names)
+            call_expr.line = defn.line
+            call_expr.column = defn.column
+            call_expr.end_line = defn.end_line
+            self.expr_checker.accept(call_expr, allow_none_return=True, always_allow_any=True)
+            # We are only interested in the first Base having __init_subclass__,
+            # all other bases have already been checked.
+            break
+
+    def check_enum(self, defn: ClassDef) -> None:
+        assert defn.info.is_enum
+        if defn.info.fullname not in ENUM_BASES:
+            for sym in defn.info.names.values():
+                if (
+                    isinstance(sym.node, Var)
+                    and sym.node.has_explicit_value
+                    and sym.node.name == "__members__"
+                ):
+                    # `__members__` will always be overwritten by `Enum` and is considered
+                    # read-only so we disallow assigning a value to it
+                    self.fail(message_registry.ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN, sym.node)
+        for base in defn.info.mro[1:-1]:  # we don't need self and `object`
+            if base.is_enum and base.fullname not in ENUM_BASES:
+                self.check_final_enum(defn, base)
+
+        self.check_enum_bases(defn)
+        self.check_enum_new(defn)
+
+    def check_final_enum(self, defn: ClassDef, base: TypeInfo) -> None:
+        for sym in base.names.values():
+            if self.is_final_enum_value(sym):
+                self.fail(f'Cannot extend enum with existing members: "{base.name}"', defn)
+                break
+
+    def is_final_enum_value(self, sym: SymbolTableNode) -> bool:
+        if isinstance(sym.node, (FuncBase, Decorator)):
+            return False  # A method is fine
+        if not isinstance(sym.node, Var):
+            return True  # Can be a class or anything else
+
+        # Now, only `Var` is left, we need to check:
+        # 1. Private name like in `__prop = 1`
+        # 2. Dunder name like `__hash__ = some_hasher`
+        # 3. Sunder name like `_order_ = 'a, b, c'`
+        # 4. If it is a method / descriptor like in `method = classmethod(func)`
+        if (
+            is_private(sym.node.name)
+            or is_dunder(sym.node.name)
+            or is_sunder(sym.node.name)
+            # TODO: make sure that `x = @class/staticmethod(func)`
+            # and `x = property(prop)` both work correctly.
+            # Now they are incorrectly counted as enum members.
+            or isinstance(get_proper_type(sym.node.type), FunctionLike)
+        ):
+            return False
+
+        return self.is_stub or sym.node.has_explicit_value
+
+    def check_enum_bases(self, defn: ClassDef) -> None:
+        """
+        Non-enum mixins cannot appear after enum bases; this is disallowed at runtime:
+
+            class Foo: ...
+            class Bar(enum.Enum, Foo): ...
+
+        But any number of enum mixins can appear in a class definition
+        (even if multiple enum bases define __new__). So this is fine:
+
+            class Foo(enum.Enum):
+                def __new__(cls, val): ...
+            class Bar(enum.Enum):
+                def __new__(cls, val): ...
+            class Baz(int, Foo, Bar, enum.Flag): ...
+        """
+        enum_base: Instance | None = None
+        for base in defn.info.bases:
+            if enum_base is None and base.type.is_enum:
+                enum_base = base
+                continue
+            elif enum_base is not None and not base.type.is_enum:
+                self.fail(
+                    f'No non-enum mixin classes are allowed after "{enum_base.str_with_options(self.options)}"',
+                    defn,
+                )
+                break
+
+    def check_enum_new(self, defn: ClassDef) -> None:
+        def has_new_method(info: TypeInfo) -> bool:
+            new_method = info.get("__new__")
+            return bool(
+                new_method
+                and new_method.node
+                and new_method.node.fullname != "builtins.object.__new__"
+            )
+
+        has_new = False
+        for base in defn.info.bases:
+            candidate = False
+
+            if base.type.is_enum:
+                # If we have an `Enum`, then we need to check all its bases.
+                candidate = any(not b.is_enum and has_new_method(b) for b in base.type.mro[1:-1])
+            else:
+                candidate = has_new_method(base.type)
+
+            if candidate and has_new:
+                self.fail(
+                    "Only a single data type mixin is allowed for Enum subtypes, "
+                    'found extra "{}"'.format(base.str_with_options(self.options)),
+                    defn,
+                )
+            elif candidate:
+                has_new = True
+
+    def check_protocol_variance(self, defn: ClassDef) -> None:
+        """Check that protocol definition is compatible with declared
+        variances of type variables.
+
+        Note that we also prohibit declaring protocol classes as invariant
+        if they are actually covariant/contravariant, since this may break
+        transitivity of subtyping, see PEP 544.
+        """
+        info = defn.info
+        object_type = Instance(info.mro[-1], [])
+        tvars = info.defn.type_vars
+        for i, tvar in enumerate(tvars):
+            up_args: list[Type] = [
+                object_type if i == j else AnyType(TypeOfAny.special_form)
+                for j, _ in enumerate(tvars)
+            ]
+            down_args: list[Type] = [
+                UninhabitedType() if i == j else AnyType(TypeOfAny.special_form)
+                for j, _ in enumerate(tvars)
+            ]
+            up, down = Instance(info, up_args), Instance(info, down_args)
+            # TODO: add advanced variance checks for recursive protocols
+            if is_subtype(down, up, ignore_declared_variance=True):
+                expected = COVARIANT
+            elif is_subtype(up, down, ignore_declared_variance=True):
+                expected = CONTRAVARIANT
+            else:
+                expected = INVARIANT
+            if isinstance(tvar, TypeVarType) and expected != tvar.variance:
+                self.msg.bad_proto_variance(tvar.variance, tvar.name, expected, defn)
+
+    def check_multiple_inheritance(self, typ: TypeInfo) -> None:
+        """Check for multiple inheritance related errors."""
+        if len(typ.bases) <= 1:
+            # No multiple inheritance.
+            return
+        # Verify that inherited attributes are compatible.
+        mro = typ.mro[1:]
+        for i, base in enumerate(mro):
+            # Attributes defined in both the type and base are skipped.
+            # Normal checks for attribute compatibility should catch any problems elsewhere.
+            non_overridden_attrs = base.names.keys() - typ.names.keys()
+            for name in non_overridden_attrs:
+                if is_private(name):
+                    continue
+                for base2 in mro[i + 1 :]:
+                    # We only need to check compatibility of attributes from classes not
+                    # in a subclass relationship. For subclasses, normal (single inheritance)
+                    # checks suffice (these are implemented elsewhere).
+                    if name in base2.names and base2 not in base.mro:
+                        self.check_compatibility(name, base, base2, typ)
+
+    def determine_type_of_member(self, sym: SymbolTableNode) -> Type | None:
+        if sym.type is not None:
+            return sym.type
+        if isinstance(sym.node, FuncBase):
+            return self.function_type(sym.node)
+        if isinstance(sym.node, TypeInfo):
+            if sym.node.typeddict_type:
+                # We special-case TypedDict, because they don't define any constructor.
+                return self.expr_checker.typeddict_callable(sym.node)
+            else:
+                return type_object_type(sym.node, self.named_type)
+        if isinstance(sym.node, TypeVarExpr):
+            # Use of TypeVars is rejected in an expression/runtime context, so
+            # we don't need to check supertype compatibility for them.
+            return AnyType(TypeOfAny.special_form)
+        if isinstance(sym.node, TypeAlias):
+            with self.msg.filter_errors():
+                # Suppress any errors, they will be given when analyzing the corresponding node.
+                # Here we may have incorrect options and location context.
+                return self.expr_checker.alias_type_in_runtime_context(sym.node, ctx=sym.node)
+        # TODO: handle more node kinds here.
+        return None
+
+    def check_compatibility(
+        self, name: str, base1: TypeInfo, base2: TypeInfo, ctx: TypeInfo
+    ) -> None:
+        """Check if attribute name in base1 is compatible with base2 in multiple inheritance.
+
+        Assume base1 comes before base2 in the MRO, and that base1 and base2 don't have
+        a direct subclass relationship (i.e., the compatibility requirement only derives from
+        multiple inheritance).
+
+        This check verifies that a definition taken from base1 (and mapped to the current
+        class ctx), is type compatible with the definition taken from base2 (also mapped), so
+        that unsafe subclassing like this can be detected:
+            class A(Generic[T]):
+                def foo(self, x: T) -> None: ...
+
+            class B:
+                def foo(self, x: str) -> None: ...
+
+            class C(B, A[int]): ...  # this is unsafe because...
+
+            x: A[int] = C()
+            x.foo  # ...runtime type is (str) -> None, while static type is (int) -> None
+        """
+        if name in ("__init__", "__new__", "__init_subclass__"):
+            # __init__ and friends can be incompatible -- it's a special case.
+            return
+        first = base1.names[name]
+        second = base2.names[name]
+        first_type = get_proper_type(self.determine_type_of_member(first))
+        second_type = get_proper_type(self.determine_type_of_member(second))
+
+        # start with the special case that Instance can be a subtype of FunctionLike
+        call = None
+        if isinstance(first_type, Instance):
+            call = find_member("__call__", first_type, first_type, is_operator=True)
+        if call and isinstance(second_type, FunctionLike):
+            second_sig = self.bind_and_map_method(second, second_type, ctx, base2)
+            ok = is_subtype(call, second_sig, ignore_pos_arg_names=True)
+        elif isinstance(first_type, FunctionLike) and isinstance(second_type, FunctionLike):
+            if first_type.is_type_obj() and second_type.is_type_obj():
+                # For class objects only check the subtype relationship of the classes,
+                # since we allow incompatible overrides of '__init__'/'__new__'
+                ok = is_subtype(
+                    left=fill_typevars_with_any(first_type.type_object()),
+                    right=fill_typevars_with_any(second_type.type_object()),
+                )
+            else:
+                # First bind/map method types when necessary.
+                first_sig = self.bind_and_map_method(first, first_type, ctx, base1)
+                second_sig = self.bind_and_map_method(second, second_type, ctx, base2)
+                ok = is_subtype(first_sig, second_sig, ignore_pos_arg_names=True)
+        elif first_type and second_type:
+            if isinstance(first.node, Var):
+                first_type = expand_self_type(first.node, first_type, fill_typevars(ctx))
+            if isinstance(second.node, Var):
+                second_type = expand_self_type(second.node, second_type, fill_typevars(ctx))
+            ok = is_equivalent(first_type, second_type)
+            if not ok:
+                second_node = base2[name].node
+                if (
+                    isinstance(second_type, FunctionLike)
+                    and second_node is not None
+                    and is_property(second_node)
+                ):
+                    second_type = get_property_type(second_type)
+                    ok = is_subtype(first_type, second_type)
+        else:
+            if first_type is None:
+                self.msg.cannot_determine_type_in_base(name, base1.name, ctx)
+            if second_type is None:
+                self.msg.cannot_determine_type_in_base(name, base2.name, ctx)
+            ok = True
+        # Final attributes can never be overridden, but can override
+        # non-final read-only attributes.
+        if is_final_node(second.node):
+            self.msg.cant_override_final(name, base2.name, ctx)
+        if is_final_node(first.node):
+            self.check_if_final_var_override_writable(name, second.node, ctx)
+        # Some attributes like __slots__ and __deletable__ are special, and the type can
+        # vary across class hierarchy.
+        if isinstance(second.node, Var) and second.node.allow_incompatible_override:
+            ok = True
+        if not ok:
+            self.msg.base_class_definitions_incompatible(name, base1, base2, ctx)
+
+    def check_metaclass_compatibility(self, typ: TypeInfo) -> None:
+        """Ensures that metaclasses of all parent types are compatible."""
+        if (
+            typ.is_metaclass()
+            or typ.is_protocol
+            or typ.is_named_tuple
+            or typ.is_enum
+            or typ.typeddict_type is not None
+        ):
+            return  # Reasonable exceptions from this check
+
+        metaclasses = [
+            entry.metaclass_type
+            for entry in typ.mro[1:-1]
+            if entry.metaclass_type
+            and not is_named_instance(entry.metaclass_type, "builtins.type")
+        ]
+        if not metaclasses:
+            return
+        if typ.metaclass_type is not None and all(
+            is_subtype(typ.metaclass_type, meta) for meta in metaclasses
+        ):
+            return
+        self.fail(
+            "Metaclass conflict: the metaclass of a derived class must be "
+            "a (non-strict) subclass of the metaclasses of all its bases",
+            typ,
+        )
+
+    def visit_import_from(self, node: ImportFrom) -> None:
+        self.check_import(node)
+
+    def visit_import_all(self, node: ImportAll) -> None:
+        self.check_import(node)
+
+    def visit_import(self, node: Import) -> None:
+        self.check_import(node)
+
+    def check_import(self, node: ImportBase) -> None:
+        for assign in node.assignments:
+            lvalue = assign.lvalues[0]
+            lvalue_type, _, __ = self.check_lvalue(lvalue)
+            if lvalue_type is None:
+                # TODO: This is broken.
+                lvalue_type = AnyType(TypeOfAny.special_form)
+            assert isinstance(assign.rvalue, NameExpr)
+            message = message_registry.INCOMPATIBLE_IMPORT_OF.format(assign.rvalue.name)
+            self.check_simple_assignment(
+                lvalue_type,
+                assign.rvalue,
+                node,
+                msg=message,
+                lvalue_name="local name",
+                rvalue_name="imported name",
+            )
+
+    #
+    # Statements
+    #
+
+    def visit_block(self, b: Block) -> None:
+        if b.is_unreachable:
+            # This block was marked as being unreachable during semantic analysis.
+            # It turns out any blocks marked in this way are *intentionally* marked
+            # as unreachable -- so we don't display an error.
+            self.binder.unreachable()
+            return
+        for s in b.body:
+            if self.binder.is_unreachable():
+                if not self.should_report_unreachable_issues():
+                    break
+                if not self.is_noop_for_reachability(s):
+                    self.msg.unreachable_statement(s)
+                    break
+            else:
+                self.accept(s)
+
+    def should_report_unreachable_issues(self) -> bool:
+        return (
+            self.in_checked_function()
+            and self.options.warn_unreachable
+            and not self.current_node_deferred
+            and not self.binder.is_unreachable_warning_suppressed()
+        )
+
+    def is_noop_for_reachability(self, s: Statement) -> bool:
+        """Returns 'true' if the given statement either throws an error of some kind
+        or is a no-op.
+
+        We use this function while handling the '--warn-unreachable' flag. When
+        that flag is present, we normally report an error on any unreachable statement.
+        But if that statement is just something like a 'pass' or a just-in-case 'assert False',
+        reporting an error would be annoying.
+        """
+        if isinstance(s, AssertStmt) and is_false_literal(s.expr):
+            return True
+        elif isinstance(s, (RaiseStmt, PassStmt)):
+            return True
+        elif isinstance(s, ExpressionStmt):
+            if isinstance(s.expr, EllipsisExpr):
+                return True
+            elif isinstance(s.expr, CallExpr):
+                with self.expr_checker.msg.filter_errors():
+                    typ = get_proper_type(
+                        self.expr_checker.accept(
+                            s.expr, allow_none_return=True, always_allow_any=True
+                        )
+                    )
+
+                if isinstance(typ, UninhabitedType):
+                    return True
+        return False
+
+    def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
+        """Type check an assignment statement.
+
+        Handle all kinds of assignment statements (simple, indexed, multiple).
+        """
+        # Avoid type checking type aliases in stubs to avoid false
+        # positives about modern type syntax available in stubs such
+        # as X | Y.
+        if not (s.is_alias_def and self.is_stub):
+            with self.enter_final_context(s.is_final_def):
+                self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax)
+
+        if s.is_alias_def:
+            self.check_type_alias_rvalue(s)
+
+        if (
+            s.type is not None
+            and self.options.disallow_any_unimported
+            and has_any_from_unimported_type(s.type)
+        ):
+            if isinstance(s.lvalues[-1], TupleExpr):
+                # This is a multiple assignment. Instead of figuring out which type is problematic,
+                # give a generic error message.
+                self.msg.unimported_type_becomes_any(
+                    "A type on this line", AnyType(TypeOfAny.special_form), s
+                )
+            else:
+                self.msg.unimported_type_becomes_any("Type of variable", s.type, s)
+        check_for_explicit_any(s.type, self.options, self.is_typeshed_stub, self.msg, context=s)
+
+        if len(s.lvalues) > 1:
+            # Chained assignment (e.g. x = y = ...).
+            # Make sure that rvalue type will not be reinferred.
+            if not self.has_type(s.rvalue):
+                self.expr_checker.accept(s.rvalue)
+            rvalue = self.temp_node(self.lookup_type(s.rvalue), s)
+            for lv in s.lvalues[:-1]:
+                with self.enter_final_context(s.is_final_def):
+                    self.check_assignment(lv, rvalue, s.type is None)
+
+        self.check_final(s)
+        if (
+            s.is_final_def
+            and s.type
+            and not has_no_typevars(s.type)
+            and self.scope.active_class() is not None
+        ):
+            self.fail(message_registry.DEPENDENT_FINAL_IN_CLASS_BODY, s)
+
+        if s.unanalyzed_type and not self.in_checked_function():
+            self.msg.annotation_in_unchecked_function(context=s)
+
+    def check_type_alias_rvalue(self, s: AssignmentStmt) -> None:
+        alias_type = self.expr_checker.accept(s.rvalue)
+        self.store_type(s.lvalues[-1], alias_type)
+
+    def check_assignment(
+        self,
+        lvalue: Lvalue,
+        rvalue: Expression,
+        infer_lvalue_type: bool = True,
+        new_syntax: bool = False,
+    ) -> None:
+        """Type check a single assignment: lvalue = rvalue."""
+        if isinstance(lvalue, (TupleExpr, ListExpr)):
+            self.check_assignment_to_multiple_lvalues(
+                lvalue.items, rvalue, rvalue, infer_lvalue_type
+            )
+        else:
+            self.try_infer_partial_generic_type_from_assignment(lvalue, rvalue, "=")
+            lvalue_type, index_lvalue, inferred = self.check_lvalue(lvalue)
+            # If we're assigning to __getattr__ or similar methods, check that the signature is
+            # valid.
+            if isinstance(lvalue, NameExpr) and lvalue.node:
+                name = lvalue.node.name
+                if name in ("__setattr__", "__getattribute__", "__getattr__"):
+                    # If an explicit type is given, use that.
+                    if lvalue_type:
+                        signature = lvalue_type
+                    else:
+                        signature = self.expr_checker.accept(rvalue)
+                    if signature:
+                        if name == "__setattr__":
+                            self.check_setattr_method(signature, lvalue)
+                        else:
+                            self.check_getattr_method(signature, lvalue, name)
+
+                if name == "__slots__":
+                    typ = lvalue_type or self.expr_checker.accept(rvalue)
+                    self.check_slots_definition(typ, lvalue)
+                if name == "__match_args__" and inferred is not None:
+                    typ = self.expr_checker.accept(rvalue)
+                    self.check_match_args(inferred, typ, lvalue)
+                if name == "__post_init__":
+                    if dataclasses_plugin.is_processed_dataclass(self.scope.active_class()):
+                        self.fail(message_registry.DATACLASS_POST_INIT_MUST_BE_A_FUNCTION, rvalue)
+
+            # Defer PartialType's super type checking.
+            if (
+                isinstance(lvalue, RefExpr)
+                and not (isinstance(lvalue_type, PartialType) and lvalue_type.type is None)
+                and not (isinstance(lvalue, NameExpr) and lvalue.name == "__match_args__")
+            ):
+                if self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue):
+                    # We hit an error on this line; don't check for any others
+                    return
+
+            if isinstance(lvalue, MemberExpr) and lvalue.name == "__match_args__":
+                self.fail(message_registry.CANNOT_MODIFY_MATCH_ARGS, lvalue)
+
+            if lvalue_type:
+                if isinstance(lvalue_type, PartialType) and lvalue_type.type is None:
+                    # Try to infer a proper type for a variable with a partial None type.
+                    rvalue_type = self.expr_checker.accept(rvalue)
+                    if isinstance(get_proper_type(rvalue_type), NoneType):
+                        # This doesn't actually provide any additional information -- multiple
+                        # None initializers preserve the partial None type.
+                        return
+
+                    var = lvalue_type.var
+                    if is_valid_inferred_type(rvalue_type, is_lvalue_final=var.is_final):
+                        partial_types = self.find_partial_types(var)
+                        if partial_types is not None:
+                            if not self.current_node_deferred:
+                                # Partial type can't be final, so strip any literal values.
+                                rvalue_type = remove_instance_last_known_values(rvalue_type)
+                                inferred_type = make_simplified_union([rvalue_type, NoneType()])
+                                self.set_inferred_type(var, lvalue, inferred_type)
+                            else:
+                                var.type = None
+                            del partial_types[var]
+                            lvalue_type = var.type
+                    else:
+                        # Try to infer a partial type. No need to check the return value, as
+                        # an error will be reported elsewhere.
+                        self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type)
+                    # Handle None PartialType's super type checking here, after it's resolved.
+                    if isinstance(lvalue, RefExpr) and self.check_compatibility_all_supers(
+                        lvalue, lvalue_type, rvalue
+                    ):
+                        # We hit an error on this line; don't check for any others
+                        return
+                elif (
+                    is_literal_none(rvalue)
+                    and isinstance(lvalue, NameExpr)
+                    and isinstance(lvalue.node, Var)
+                    and lvalue.node.is_initialized_in_class
+                    and not new_syntax
+                ):
+                    # Allow None's to be assigned to class variables with non-Optional types.
+                    rvalue_type = lvalue_type
+                elif (
+                    isinstance(lvalue, MemberExpr) and lvalue.kind is None
+                ):  # Ignore member access to modules
+                    instance_type = self.expr_checker.accept(lvalue.expr)
+                    rvalue_type, lvalue_type, infer_lvalue_type = self.check_member_assignment(
+                        instance_type, lvalue_type, rvalue, context=rvalue
+                    )
+                else:
+                    # Hacky special case for assigning a literal None
+                    # to a variable defined in a previous if
+                    # branch. When we detect this, we'll go back and
+                    # make the type optional. This is somewhat
+                    # unpleasant, and a generalization of this would
+                    # be an improvement!
+                    if (
+                        is_literal_none(rvalue)
+                        and isinstance(lvalue, NameExpr)
+                        and lvalue.kind == LDEF
+                        and isinstance(lvalue.node, Var)
+                        and lvalue.node.type
+                        and lvalue.node in self.var_decl_frames
+                        and not isinstance(get_proper_type(lvalue_type), AnyType)
+                    ):
+                        decl_frame_map = self.var_decl_frames[lvalue.node]
+                        # Check if the nearest common ancestor frame for the definition site
+                        # and the current site is the enclosing frame of an if/elif/else block.
+                        has_if_ancestor = False
+                        for frame in reversed(self.binder.frames):
+                            if frame.id in decl_frame_map:
+                                has_if_ancestor = frame.conditional_frame
+                                break
+                        if has_if_ancestor:
+                            lvalue_type = make_optional_type(lvalue_type)
+                            self.set_inferred_type(lvalue.node, lvalue, lvalue_type)
+
+                    rvalue_type = self.check_simple_assignment(lvalue_type, rvalue, context=rvalue)
+
+                # Special case: only non-abstract non-protocol classes can be assigned to
+                # variables with explicit type Type[A], where A is protocol or abstract.
+                p_rvalue_type = get_proper_type(rvalue_type)
+                p_lvalue_type = get_proper_type(lvalue_type)
+                if (
+                    isinstance(p_rvalue_type, CallableType)
+                    and p_rvalue_type.is_type_obj()
+                    and (
+                        p_rvalue_type.type_object().is_abstract
+                        or p_rvalue_type.type_object().is_protocol
+                    )
+                    and isinstance(p_lvalue_type, TypeType)
+                    and isinstance(p_lvalue_type.item, Instance)
+                    and (
+                        p_lvalue_type.item.type.is_abstract or p_lvalue_type.item.type.is_protocol
+                    )
+                ):
+                    self.msg.concrete_only_assign(p_lvalue_type, rvalue)
+                    return
+                if rvalue_type and infer_lvalue_type and not isinstance(lvalue_type, PartialType):
+                    # Don't use type binder for definitions of special forms, like named tuples.
+                    if not (isinstance(lvalue, NameExpr) and lvalue.is_special_form):
+                        self.binder.assign_type(lvalue, rvalue_type, lvalue_type, False)
+
+            elif index_lvalue:
+                self.check_indexed_assignment(index_lvalue, rvalue, lvalue)
+
+            if inferred:
+                type_context = self.get_variable_type_context(inferred)
+                rvalue_type = self.expr_checker.accept(rvalue, type_context=type_context)
+                if not (
+                    inferred.is_final
+                    or (isinstance(lvalue, NameExpr) and lvalue.name == "__match_args__")
+                ):
+                    rvalue_type = remove_instance_last_known_values(rvalue_type)
+                self.infer_variable_type(inferred, lvalue, rvalue_type, rvalue)
+            self.check_assignment_to_slots(lvalue)
+
+    # (type, operator) tuples for augmented assignments supported with partial types
+    partial_type_augmented_ops: Final = {("builtins.list", "+"), ("builtins.set", "|")}
+
+    def get_variable_type_context(self, inferred: Var) -> Type | None:
+        type_contexts = []
+        if inferred.info:
+            for base in inferred.info.mro[1:]:
+                base_type, base_node = self.lvalue_type_from_base(inferred, base)
+                if (
+                    base_type
+                    and not (isinstance(base_node, Var) and base_node.invalid_partial_type)
+                    and not isinstance(base_type, PartialType)
+                ):
+                    type_contexts.append(base_type)
+        # Use most derived supertype as type context if available.
+        if not type_contexts:
+            return None
+        candidate = type_contexts[0]
+        for other in type_contexts:
+            if is_proper_subtype(other, candidate):
+                candidate = other
+            elif not is_subtype(candidate, other):
+                # Multiple incompatible candidates, cannot use any of them as context.
+                return None
+        return candidate
+
+    def try_infer_partial_generic_type_from_assignment(
+        self, lvalue: Lvalue, rvalue: Expression, op: str
+    ) -> None:
+        """Try to infer a precise type for partial generic type from assignment.
+
+        'op' is '=' for normal assignment and a binary operator ('+', ...) for
+        augmented assignment.
+
+        Example where this happens:
+
+            x = []
+            if foo():
+                x = [1]  # Infer List[int] as type of 'x'
+        """
+        var = None
+        if (
+            isinstance(lvalue, NameExpr)
+            and isinstance(lvalue.node, Var)
+            and isinstance(lvalue.node.type, PartialType)
+        ):
+            var = lvalue.node
+        elif isinstance(lvalue, MemberExpr):
+            var = self.expr_checker.get_partial_self_var(lvalue)
+        if var is not None:
+            typ = var.type
+            assert isinstance(typ, PartialType)
+            if typ.type is None:
+                return
+            # Return if this is an unsupported augmented assignment.
+            if op != "=" and (typ.type.fullname, op) not in self.partial_type_augmented_ops:
+                return
+            # TODO: some logic here duplicates the None partial type counterpart
+            #       inlined in check_assignment(), see #8043.
+            partial_types = self.find_partial_types(var)
+            if partial_types is None:
+                return
+            rvalue_type = self.expr_checker.accept(rvalue)
+            rvalue_type = get_proper_type(rvalue_type)
+            if isinstance(rvalue_type, Instance):
+                if rvalue_type.type == typ.type and is_valid_inferred_type(rvalue_type):
+                    var.type = rvalue_type
+                    del partial_types[var]
+            elif isinstance(rvalue_type, AnyType):
+                var.type = fill_typevars_with_any(typ.type)
+                del partial_types[var]
+
+    def check_compatibility_all_supers(
+        self, lvalue: RefExpr, lvalue_type: Type | None, rvalue: Expression
+    ) -> bool:
+        lvalue_node = lvalue.node
+        # Check if we are a class variable with at least one base class
+        if (
+            isinstance(lvalue_node, Var)
+            and lvalue.kind in (MDEF, None)
+            and len(lvalue_node.info.bases) > 0  # None for Vars defined via self
+        ):
+            for base in lvalue_node.info.mro[1:]:
+                tnode = base.names.get(lvalue_node.name)
+                if tnode is not None:
+                    if not self.check_compatibility_classvar_super(lvalue_node, base, tnode.node):
+                        # Show only one error per variable
+                        break
+
+                    if not self.check_compatibility_final_super(lvalue_node, base, tnode.node):
+                        # Show only one error per variable
+                        break
+
+            direct_bases = lvalue_node.info.direct_base_classes()
+            last_immediate_base = direct_bases[-1] if direct_bases else None
+
+            for base in lvalue_node.info.mro[1:]:
+                # The type of "__slots__" and some other attributes usually doesn't need to
+                # be compatible with a base class. We'll still check the type of "__slots__"
+                # against "object" as an exception.
+                if lvalue_node.allow_incompatible_override and not (
+                    lvalue_node.name == "__slots__" and base.fullname == "builtins.object"
+                ):
+                    continue
+
+                if is_private(lvalue_node.name):
+                    continue
+
+                base_type, base_node = self.lvalue_type_from_base(lvalue_node, base)
+                if isinstance(base_type, PartialType):
+                    base_type = None
+
+                if base_type:
+                    assert base_node is not None
+                    if not self.check_compatibility_super(
+                        lvalue, lvalue_type, rvalue, base, base_type, base_node
+                    ):
+                        # Only show one error per variable; even if other
+                        # base classes are also incompatible
+                        return True
+                    if base is last_immediate_base:
+                        # At this point, the attribute was found to be compatible with all
+                        # immediate parents.
+                        break
+        return False
+
+    def check_compatibility_super(
+        self,
+        lvalue: RefExpr,
+        lvalue_type: Type | None,
+        rvalue: Expression,
+        base: TypeInfo,
+        base_type: Type,
+        base_node: Node,
+    ) -> bool:
+        lvalue_node = lvalue.node
+        assert isinstance(lvalue_node, Var)
+
+        # Do not check whether the rvalue is compatible if the
+        # lvalue had a type defined; this is handled by other
+        # parts, and all we have to worry about in that case is
+        # that lvalue is compatible with the base class.
+        compare_node = None
+        if lvalue_type:
+            compare_type = lvalue_type
+            compare_node = lvalue.node
+        else:
+            compare_type = self.expr_checker.accept(rvalue, base_type)
+            if isinstance(rvalue, NameExpr):
+                compare_node = rvalue.node
+                if isinstance(compare_node, Decorator):
+                    compare_node = compare_node.func
+
+        base_type = get_proper_type(base_type)
+        compare_type = get_proper_type(compare_type)
+        if compare_type:
+            if isinstance(base_type, CallableType) and isinstance(compare_type, CallableType):
+                base_static = is_node_static(base_node)
+                compare_static = is_node_static(compare_node)
+
+                # In case compare_static is unknown, also check
+                # if 'definition' is set. The most common case for
+                # this is with TempNode(), where we lose all
+                # information about the real rvalue node (but only get
+                # the rvalue type)
+                if compare_static is None and compare_type.definition:
+                    compare_static = is_node_static(compare_type.definition)
+
+                # Compare against False, as is_node_static can return None
+                if base_static is False and compare_static is False:
+                    # Class-level function objects and classmethods become bound
+                    # methods: the former to the instance, the latter to the
+                    # class
+                    base_type = bind_self(base_type, self.scope.active_self_type())
+                    compare_type = bind_self(compare_type, self.scope.active_self_type())
+
+                # If we are a static method, ensure to also tell the
+                # lvalue it now contains a static method
+                if base_static and compare_static:
+                    lvalue_node.is_staticmethod = True
+
+            return self.check_subtype(
+                compare_type,
+                base_type,
+                rvalue,
+                message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
+                "expression has type",
+                f'base class "{base.name}" defined the type as',
+            )
+        return True
+
+    def lvalue_type_from_base(
+        self, expr_node: Var, base: TypeInfo
+    ) -> tuple[Type | None, Node | None]:
+        """For a NameExpr that is part of a class, walk all base classes and try
+        to find the first class that defines a Type for the same name."""
+        expr_name = expr_node.name
+        base_var = base.names.get(expr_name)
+
+        if base_var:
+            base_node = base_var.node
+            base_type = base_var.type
+            if isinstance(base_node, Var) and base_type is not None:
+                base_type = expand_self_type(base_node, base_type, fill_typevars(expr_node.info))
+            if isinstance(base_node, Decorator):
+                base_node = base_node.func
+                base_type = base_node.type
+
+            if base_type:
+                if not has_no_typevars(base_type):
+                    self_type = self.scope.active_self_type()
+                    assert self_type is not None, "Internal error: base lookup outside class"
+                    if isinstance(self_type, TupleType):
+                        instance = tuple_fallback(self_type)
+                    else:
+                        instance = self_type
+                    itype = map_instance_to_supertype(instance, base)
+                    base_type = expand_type_by_instance(base_type, itype)
+
+                base_type = get_proper_type(base_type)
+                if isinstance(base_type, CallableType) and isinstance(base_node, FuncDef):
+                    # If we are a property, return the Type of the return
+                    # value, not the Callable
+                    if base_node.is_property:
+                        base_type = get_proper_type(base_type.ret_type)
+                if isinstance(base_type, FunctionLike) and isinstance(
+                    base_node, OverloadedFuncDef
+                ):
+                    # Same for properties with setter
+                    if base_node.is_property:
+                        base_type = base_type.items[0].ret_type
+
+                return base_type, base_node
+
+        return None, None
+
+    def check_compatibility_classvar_super(
+        self, node: Var, base: TypeInfo, base_node: Node | None
+    ) -> bool:
+        if not isinstance(base_node, Var):
+            return True
+        if node.is_classvar and not base_node.is_classvar:
+            self.fail(message_registry.CANNOT_OVERRIDE_INSTANCE_VAR.format(base.name), node)
+            return False
+        elif not node.is_classvar and base_node.is_classvar:
+            self.fail(message_registry.CANNOT_OVERRIDE_CLASS_VAR.format(base.name), node)
+            return False
+        return True
+
+    def check_compatibility_final_super(
+        self, node: Var, base: TypeInfo, base_node: Node | None
+    ) -> bool:
+        """Check if an assignment overrides a final attribute in a base class.
+
+        This only checks situations where either a node in base class is not a variable
+        but a final method, or where override is explicitly declared as final.
+        In these cases we give a more detailed error message. In addition, we check that
+        a final variable doesn't override writeable attribute, which is not safe.
+
+        Other situations are checked in `check_final()`.
+        """
+        if not isinstance(base_node, (Var, FuncBase, Decorator)):
+            return True
+        if base_node.is_final and (node.is_final or not isinstance(base_node, Var)):
+            # Give this error only for explicit override attempt with `Final`, or
+            # if we are overriding a final method with variable.
+            # Other override attempts will be flagged as assignment to constant
+            # in `check_final()`.
+            self.msg.cant_override_final(node.name, base.name, node)
+            return False
+        if node.is_final:
+            if base.fullname in ENUM_BASES or node.name in ENUM_SPECIAL_PROPS:
+                return True
+            self.check_if_final_var_override_writable(node.name, base_node, node)
+        return True
+
+    def check_if_final_var_override_writable(
+        self, name: str, base_node: Node | None, ctx: Context
+    ) -> None:
+        """Check that a final variable doesn't override writeable attribute.
+
+        This is done to prevent situations like this:
+            class C:
+                attr = 1
+            class D(C):
+                attr: Final = 2
+
+            x: C = D()
+            x.attr = 3  # Oops!
+        """
+        writable = True
+        if base_node:
+            writable = self.is_writable_attribute(base_node)
+        if writable:
+            self.msg.final_cant_override_writable(name, ctx)
+
+    def get_final_context(self) -> bool:
+        """Check whether we a currently checking a final declaration."""
+        return self._is_final_def
+
+    @contextmanager
+    def enter_final_context(self, is_final_def: bool) -> Iterator[None]:
+        """Store whether the current checked assignment is a final declaration."""
+        old_ctx = self._is_final_def
+        self._is_final_def = is_final_def
+        try:
+            yield
+        finally:
+            self._is_final_def = old_ctx
+
+    def check_final(self, s: AssignmentStmt | OperatorAssignmentStmt | AssignmentExpr) -> None:
+        """Check if this assignment does not assign to a final attribute.
+
+        This function performs the check only for name assignments at module
+        and class scope. The assignments to `obj.attr` and `Cls.attr` are checked
+        in checkmember.py.
+        """
+        if isinstance(s, AssignmentStmt):
+            lvs = self.flatten_lvalues(s.lvalues)
+        elif isinstance(s, AssignmentExpr):
+            lvs = [s.target]
+        else:
+            lvs = [s.lvalue]
+        is_final_decl = s.is_final_def if isinstance(s, AssignmentStmt) else False
+        if is_final_decl and self.scope.active_class():
+            lv = lvs[0]
+            assert isinstance(lv, RefExpr)
+            if lv.node is not None:
+                assert isinstance(lv.node, Var)
+                if (
+                    lv.node.final_unset_in_class
+                    and not lv.node.final_set_in_init
+                    and not self.is_stub
+                    and  # It is OK to skip initializer in stub files.
+                    # Avoid extra error messages, if there is no type in Final[...],
+                    # then we already reported the error about missing r.h.s.
+                    isinstance(s, AssignmentStmt)
+                    and s.type is not None
+                ):
+                    self.msg.final_without_value(s)
+        for lv in lvs:
+            if isinstance(lv, RefExpr) and isinstance(lv.node, Var):
+                name = lv.node.name
+                cls = self.scope.active_class()
+                if cls is not None:
+                    # These additional checks exist to give more error messages
+                    # even if the final attribute was overridden with a new symbol
+                    # (which is itself an error)...
+                    for base in cls.mro[1:]:
+                        sym = base.names.get(name)
+                        # We only give this error if base node is variable,
+                        # overriding final method will be caught in
+                        # `check_compatibility_final_super()`.
+                        if sym and isinstance(sym.node, Var):
+                            if sym.node.is_final and not is_final_decl:
+                                self.msg.cant_assign_to_final(name, sym.node.info is None, s)
+                                # ...but only once
+                                break
+                if lv.node.is_final and not is_final_decl:
+                    self.msg.cant_assign_to_final(name, lv.node.info is None, s)
+
+    def check_assignment_to_slots(self, lvalue: Lvalue) -> None:
+        if not isinstance(lvalue, MemberExpr):
+            return
+
+        inst = get_proper_type(self.expr_checker.accept(lvalue.expr))
+        if not isinstance(inst, Instance):
+            return
+        if inst.type.slots is None:
+            return  # Slots do not exist, we can allow any assignment
+        if lvalue.name in inst.type.slots:
+            return  # We are assigning to an existing slot
+        for base_info in inst.type.mro[:-1]:
+            if base_info.names.get("__setattr__") is not None:
+                # When type has `__setattr__` defined,
+                # we can assign any dynamic value.
+                # We exclude object, because it always has `__setattr__`.
+                return
+
+        definition = inst.type.get(lvalue.name)
+        if definition is None:
+            # We don't want to duplicate
+            # `"SomeType" has no attribute "some_attr"`
+            # error twice.
+            return
+        if self.is_assignable_slot(lvalue, definition.type):
+            return
+
+        self.fail(
+            message_registry.NAME_NOT_IN_SLOTS.format(lvalue.name, inst.type.fullname), lvalue
+        )
+
+    def is_assignable_slot(self, lvalue: Lvalue, typ: Type | None) -> bool:
+        if getattr(lvalue, "node", None):
+            return False  # This is a definition
+
+        typ = get_proper_type(typ)
+        if typ is None or isinstance(typ, AnyType):
+            return True  # Any can be literally anything, like `@propery`
+        if isinstance(typ, Instance):
+            # When working with instances, we need to know if they contain
+            # `__set__` special method. Like `@property` does.
+            # This makes assigning to properties possible,
+            # even without extra slot spec.
+            return typ.type.get("__set__") is not None
+        if isinstance(typ, FunctionLike):
+            return True  # Can be a property, or some other magic
+        if isinstance(typ, UnionType):
+            return all(self.is_assignable_slot(lvalue, u) for u in typ.items)
+        return False
+
+    def check_assignment_to_multiple_lvalues(
+        self,
+        lvalues: list[Lvalue],
+        rvalue: Expression,
+        context: Context,
+        infer_lvalue_type: bool = True,
+    ) -> None:
+        if isinstance(rvalue, (TupleExpr, ListExpr)):
+            # Recursively go into Tuple or List expression rhs instead of
+            # using the type of rhs, because this allowed more fine grained
+            # control in cases like: a, b = [int, str] where rhs would get
+            # type List[object]
+            rvalues: list[Expression] = []
+            iterable_type: Type | None = None
+            last_idx: int | None = None
+            for idx_rval, rval in enumerate(rvalue.items):
+                if isinstance(rval, StarExpr):
+                    typs = get_proper_type(self.expr_checker.accept(rval.expr))
+                    if isinstance(typs, TupleType):
+                        rvalues.extend([TempNode(typ) for typ in typs.items])
+                    elif self.type_is_iterable(typs) and isinstance(typs, Instance):
+                        if iterable_type is not None and iterable_type != self.iterable_item_type(
+                            typs, rvalue
+                        ):
+                            self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context)
+                        else:
+                            if last_idx is None or last_idx + 1 == idx_rval:
+                                rvalues.append(rval)
+                                last_idx = idx_rval
+                                iterable_type = self.iterable_item_type(typs, rvalue)
+                            else:
+                                self.fail(message_registry.CONTIGUOUS_ITERABLE_EXPECTED, context)
+                    else:
+                        self.fail(message_registry.ITERABLE_TYPE_EXPECTED.format(typs), context)
+                else:
+                    rvalues.append(rval)
+            iterable_start: int | None = None
+            iterable_end: int | None = None
+            for i, rval in enumerate(rvalues):
+                if isinstance(rval, StarExpr):
+                    typs = get_proper_type(self.expr_checker.accept(rval.expr))
+                    if self.type_is_iterable(typs) and isinstance(typs, Instance):
+                        if iterable_start is None:
+                            iterable_start = i
+                        iterable_end = i
+            if (
+                iterable_start is not None
+                and iterable_end is not None
+                and iterable_type is not None
+            ):
+                iterable_num = iterable_end - iterable_start + 1
+                rvalue_needed = len(lvalues) - (len(rvalues) - iterable_num)
+                if rvalue_needed > 0:
+                    rvalues = (
+                        rvalues[0:iterable_start]
+                        + [TempNode(iterable_type) for i in range(rvalue_needed)]
+                        + rvalues[iterable_end + 1 :]
+                    )
+
+            if self.check_rvalue_count_in_assignment(lvalues, len(rvalues), context):
+                star_index = next(
+                    (i for i, lv in enumerate(lvalues) if isinstance(lv, StarExpr)), len(lvalues)
+                )
+
+                left_lvs = lvalues[:star_index]
+                star_lv = (
+                    cast(StarExpr, lvalues[star_index]) if star_index != len(lvalues) else None
+                )
+                right_lvs = lvalues[star_index + 1 :]
+
+                left_rvs, star_rvs, right_rvs = self.split_around_star(
+                    rvalues, star_index, len(lvalues)
+                )
+
+                lr_pairs = list(zip(left_lvs, left_rvs))
+                if star_lv:
+                    rv_list = ListExpr(star_rvs)
+                    rv_list.set_line(rvalue)
+                    lr_pairs.append((star_lv.expr, rv_list))
+                lr_pairs.extend(zip(right_lvs, right_rvs))
+
+                for lv, rv in lr_pairs:
+                    self.check_assignment(lv, rv, infer_lvalue_type)
+        else:
+            self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type)
+
+    def check_rvalue_count_in_assignment(
+        self, lvalues: list[Lvalue], rvalue_count: int, context: Context
+    ) -> bool:
+        if any(isinstance(lvalue, StarExpr) for lvalue in lvalues):
+            if len(lvalues) - 1 > rvalue_count:
+                self.msg.wrong_number_values_to_unpack(rvalue_count, len(lvalues) - 1, context)
+                return False
+        elif rvalue_count != len(lvalues):
+            self.msg.wrong_number_values_to_unpack(rvalue_count, len(lvalues), context)
+            return False
+        return True
+
+    def check_multi_assignment(
+        self,
+        lvalues: list[Lvalue],
+        rvalue: Expression,
+        context: Context,
+        infer_lvalue_type: bool = True,
+        rv_type: Type | None = None,
+        undefined_rvalue: bool = False,
+    ) -> None:
+        """Check the assignment of one rvalue to a number of lvalues."""
+
+        # Infer the type of an ordinary rvalue expression.
+        # TODO: maybe elsewhere; redundant.
+        rvalue_type = get_proper_type(rv_type or self.expr_checker.accept(rvalue))
+
+        if isinstance(rvalue_type, TypeVarLikeType):
+            rvalue_type = get_proper_type(rvalue_type.upper_bound)
+
+        if isinstance(rvalue_type, UnionType):
+            # If this is an Optional type in non-strict Optional code, unwrap it.
+            relevant_items = rvalue_type.relevant_items()
+            if len(relevant_items) == 1:
+                rvalue_type = get_proper_type(relevant_items[0])
+
+        if isinstance(rvalue_type, AnyType):
+            for lv in lvalues:
+                if isinstance(lv, StarExpr):
+                    lv = lv.expr
+                temp_node = self.temp_node(
+                    AnyType(TypeOfAny.from_another_any, source_any=rvalue_type), context
+                )
+                self.check_assignment(lv, temp_node, infer_lvalue_type)
+        elif isinstance(rvalue_type, TupleType):
+            self.check_multi_assignment_from_tuple(
+                lvalues, rvalue, rvalue_type, context, undefined_rvalue, infer_lvalue_type
+            )
+        elif isinstance(rvalue_type, UnionType):
+            self.check_multi_assignment_from_union(
+                lvalues, rvalue, rvalue_type, context, infer_lvalue_type
+            )
+        elif isinstance(rvalue_type, Instance) and rvalue_type.type.fullname == "builtins.str":
+            self.msg.unpacking_strings_disallowed(context)
+        else:
+            self.check_multi_assignment_from_iterable(
+                lvalues, rvalue_type, context, infer_lvalue_type
+            )
+
+    def check_multi_assignment_from_union(
+        self,
+        lvalues: list[Expression],
+        rvalue: Expression,
+        rvalue_type: UnionType,
+        context: Context,
+        infer_lvalue_type: bool,
+    ) -> None:
+        """Check assignment to multiple lvalue targets when rvalue type is a Union[...].
+        For example:
+
+            t: Union[Tuple[int, int], Tuple[str, str]]
+            x, y = t
+            reveal_type(x)  # Union[int, str]
+
+        The idea in this case is to process the assignment for every item of the union.
+        Important note: the types are collected in two places, 'union_types' contains
+        inferred types for first assignments, 'assignments' contains the narrowed types
+        for binder.
+        """
+        self.no_partial_types = True
+        transposed: tuple[list[Type], ...] = tuple([] for _ in self.flatten_lvalues(lvalues))
+        # Notify binder that we want to defer bindings and instead collect types.
+        with self.binder.accumulate_type_assignments() as assignments:
+            for item in rvalue_type.items:
+                # Type check the assignment separately for each union item and collect
+                # the inferred lvalue types for each union item.
+                self.check_multi_assignment(
+                    lvalues,
+                    rvalue,
+                    context,
+                    infer_lvalue_type=infer_lvalue_type,
+                    rv_type=item,
+                    undefined_rvalue=True,
+                )
+                for t, lv in zip(transposed, self.flatten_lvalues(lvalues)):
+                    # We can access _type_maps directly since temporary type maps are
+                    # only created within expressions.
+                    t.append(self._type_maps[0].pop(lv, AnyType(TypeOfAny.special_form)))
+        union_types = tuple(make_simplified_union(col) for col in transposed)
+        for expr, items in assignments.items():
+            # Bind a union of types collected in 'assignments' to every expression.
+            if isinstance(expr, StarExpr):
+                expr = expr.expr
+
+            # TODO: See todo in binder.py, ConditionalTypeBinder.assign_type
+            # It's unclear why the 'declared_type' param is sometimes 'None'
+            clean_items: list[tuple[Type, Type]] = []
+            for type, declared_type in items:
+                assert declared_type is not None
+                clean_items.append((type, declared_type))
+
+            types, declared_types = zip(*clean_items)
+            self.binder.assign_type(
+                expr,
+                make_simplified_union(list(types)),
+                make_simplified_union(list(declared_types)),
+                False,
+            )
+        for union, lv in zip(union_types, self.flatten_lvalues(lvalues)):
+            # Properly store the inferred types.
+            _1, _2, inferred = self.check_lvalue(lv)
+            if inferred:
+                self.set_inferred_type(inferred, lv, union)
+            else:
+                self.store_type(lv, union)
+        self.no_partial_types = False
+
+    def flatten_lvalues(self, lvalues: list[Expression]) -> list[Expression]:
+        res: list[Expression] = []
+        for lv in lvalues:
+            if isinstance(lv, (TupleExpr, ListExpr)):
+                res.extend(self.flatten_lvalues(lv.items))
+            if isinstance(lv, StarExpr):
+                # Unwrap StarExpr, since it is unwrapped by other helpers.
+                lv = lv.expr
+            res.append(lv)
+        return res
+
+    def check_multi_assignment_from_tuple(
+        self,
+        lvalues: list[Lvalue],
+        rvalue: Expression,
+        rvalue_type: TupleType,
+        context: Context,
+        undefined_rvalue: bool,
+        infer_lvalue_type: bool = True,
+    ) -> None:
+        if self.check_rvalue_count_in_assignment(lvalues, len(rvalue_type.items), context):
+            star_index = next(
+                (i for i, lv in enumerate(lvalues) if isinstance(lv, StarExpr)), len(lvalues)
+            )
+
+            left_lvs = lvalues[:star_index]
+            star_lv = cast(StarExpr, lvalues[star_index]) if star_index != len(lvalues) else None
+            right_lvs = lvalues[star_index + 1 :]
+
+            if not undefined_rvalue:
+                # Infer rvalue again, now in the correct type context.
+                lvalue_type = self.lvalue_type_for_inference(lvalues, rvalue_type)
+                reinferred_rvalue_type = get_proper_type(
+                    self.expr_checker.accept(rvalue, lvalue_type)
+                )
+
+                if isinstance(reinferred_rvalue_type, UnionType):
+                    # If this is an Optional type in non-strict Optional code, unwrap it.
+                    relevant_items = reinferred_rvalue_type.relevant_items()
+                    if len(relevant_items) == 1:
+                        reinferred_rvalue_type = get_proper_type(relevant_items[0])
+                if isinstance(reinferred_rvalue_type, UnionType):
+                    self.check_multi_assignment_from_union(
+                        lvalues, rvalue, reinferred_rvalue_type, context, infer_lvalue_type
+                    )
+                    return
+                if isinstance(reinferred_rvalue_type, AnyType):
+                    # We can get Any if the current node is
+                    # deferred. Doing more inference in deferred nodes
+                    # is hard, so give up for now.  We can also get
+                    # here if reinferring types above changes the
+                    # inferred return type for an overloaded function
+                    # to be ambiguous.
+                    return
+                assert isinstance(reinferred_rvalue_type, TupleType)
+                rvalue_type = reinferred_rvalue_type
+
+            left_rv_types, star_rv_types, right_rv_types = self.split_around_star(
+                rvalue_type.items, star_index, len(lvalues)
+            )
+
+            for lv, rv_type in zip(left_lvs, left_rv_types):
+                self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type)
+            if star_lv:
+                list_expr = ListExpr(
+                    [self.temp_node(rv_type, context) for rv_type in star_rv_types]
+                )
+                list_expr.set_line(context)
+                self.check_assignment(star_lv.expr, list_expr, infer_lvalue_type)
+            for lv, rv_type in zip(right_lvs, right_rv_types):
+                self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type)
+
+    def lvalue_type_for_inference(self, lvalues: list[Lvalue], rvalue_type: TupleType) -> Type:
+        star_index = next(
+            (i for i, lv in enumerate(lvalues) if isinstance(lv, StarExpr)), len(lvalues)
+        )
+        left_lvs = lvalues[:star_index]
+        star_lv = cast(StarExpr, lvalues[star_index]) if star_index != len(lvalues) else None
+        right_lvs = lvalues[star_index + 1 :]
+        left_rv_types, star_rv_types, right_rv_types = self.split_around_star(
+            rvalue_type.items, star_index, len(lvalues)
+        )
+
+        type_parameters: list[Type] = []
+
+        def append_types_for_inference(lvs: list[Expression], rv_types: list[Type]) -> None:
+            for lv, rv_type in zip(lvs, rv_types):
+                sub_lvalue_type, index_expr, inferred = self.check_lvalue(lv)
+                if sub_lvalue_type and not isinstance(sub_lvalue_type, PartialType):
+                    type_parameters.append(sub_lvalue_type)
+                else:  # index lvalue
+                    # TODO Figure out more precise type context, probably
+                    #      based on the type signature of the _set method.
+                    type_parameters.append(rv_type)
+
+        append_types_for_inference(left_lvs, left_rv_types)
+
+        if star_lv:
+            sub_lvalue_type, index_expr, inferred = self.check_lvalue(star_lv.expr)
+            if sub_lvalue_type and not isinstance(sub_lvalue_type, PartialType):
+                type_parameters.extend([sub_lvalue_type] * len(star_rv_types))
+            else:  # index lvalue
+                # TODO Figure out more precise type context, probably
+                #      based on the type signature of the _set method.
+                type_parameters.extend(star_rv_types)
+
+        append_types_for_inference(right_lvs, right_rv_types)
+
+        return TupleType(type_parameters, self.named_type("builtins.tuple"))
+
+    def split_around_star(
+        self, items: list[T], star_index: int, length: int
+    ) -> tuple[list[T], list[T], list[T]]:
+        """Splits a list of items in three to match another list of length 'length'
+        that contains a starred expression at 'star_index' in the following way:
+
+        star_index = 2, length = 5 (i.e., [a,b,*,c,d]), items = [1,2,3,4,5,6,7]
+        returns in: ([1,2], [3,4,5], [6,7])
+        """
+        nr_right_of_star = length - star_index - 1
+        right_index = -nr_right_of_star if nr_right_of_star != 0 else len(items)
+        left = items[:star_index]
+        star = items[star_index:right_index]
+        right = items[right_index:]
+        return left, star, right
+
+    def type_is_iterable(self, type: Type) -> bool:
+        type = get_proper_type(type)
+        if isinstance(type, CallableType) and type.is_type_obj():
+            type = type.fallback
+        return is_subtype(
+            type, self.named_generic_type("typing.Iterable", [AnyType(TypeOfAny.special_form)])
+        )
+
+    def check_multi_assignment_from_iterable(
+        self,
+        lvalues: list[Lvalue],
+        rvalue_type: Type,
+        context: Context,
+        infer_lvalue_type: bool = True,
+    ) -> None:
+        rvalue_type = get_proper_type(rvalue_type)
+        if self.type_is_iterable(rvalue_type) and isinstance(
+            rvalue_type, (Instance, CallableType, TypeType, Overloaded)
+        ):
+            item_type = self.iterable_item_type(rvalue_type, context)
+            for lv in lvalues:
+                if isinstance(lv, StarExpr):
+                    items_type = self.named_generic_type("builtins.list", [item_type])
+                    self.check_assignment(
+                        lv.expr, self.temp_node(items_type, context), infer_lvalue_type
+                    )
+                else:
+                    self.check_assignment(
+                        lv, self.temp_node(item_type, context), infer_lvalue_type
+                    )
+        else:
+            self.msg.type_not_iterable(rvalue_type, context)
+
+    def check_lvalue(self, lvalue: Lvalue) -> tuple[Type | None, IndexExpr | None, Var | None]:
+        lvalue_type = None
+        index_lvalue = None
+        inferred = None
+
+        if self.is_definition(lvalue) and (
+            not isinstance(lvalue, NameExpr) or isinstance(lvalue.node, Var)
+        ):
+            if isinstance(lvalue, NameExpr):
+                assert isinstance(lvalue.node, Var)
+                inferred = lvalue.node
+            else:
+                assert isinstance(lvalue, MemberExpr)
+                self.expr_checker.accept(lvalue.expr)
+                inferred = lvalue.def_var
+        elif isinstance(lvalue, IndexExpr):
+            index_lvalue = lvalue
+        elif isinstance(lvalue, MemberExpr):
+            lvalue_type = self.expr_checker.analyze_ordinary_member_access(lvalue, True)
+            self.store_type(lvalue, lvalue_type)
+        elif isinstance(lvalue, NameExpr):
+            lvalue_type = self.expr_checker.analyze_ref_expr(lvalue, lvalue=True)
+            self.store_type(lvalue, lvalue_type)
+        elif isinstance(lvalue, (TupleExpr, ListExpr)):
+            types = [
+                self.check_lvalue(sub_expr)[0] or
+                # This type will be used as a context for further inference of rvalue,
+                # we put Uninhabited if there is no information available from lvalue.
+                UninhabitedType()
+                for sub_expr in lvalue.items
+            ]
+            lvalue_type = TupleType(types, self.named_type("builtins.tuple"))
+        elif isinstance(lvalue, StarExpr):
+            lvalue_type, _, _ = self.check_lvalue(lvalue.expr)
+        else:
+            lvalue_type = self.expr_checker.accept(lvalue)
+
+        return lvalue_type, index_lvalue, inferred
+
+    def is_definition(self, s: Lvalue) -> bool:
+        if isinstance(s, NameExpr):
+            if s.is_inferred_def:
+                return True
+            # If the node type is not defined, this must the first assignment
+            # that we process => this is a definition, even though the semantic
+            # analyzer did not recognize this as such. This can arise in code
+            # that uses isinstance checks, if type checking of the primary
+            # definition is skipped due to an always False type check.
+            node = s.node
+            if isinstance(node, Var):
+                return node.type is None
+        elif isinstance(s, MemberExpr):
+            return s.is_inferred_def
+        return False
+
+    def infer_variable_type(
+        self, name: Var, lvalue: Lvalue, init_type: Type, context: Context
+    ) -> None:
+        """Infer the type of initialized variables from initializer type."""
+        if isinstance(init_type, DeletedType):
+            self.msg.deleted_as_rvalue(init_type, context)
+        elif (
+            not is_valid_inferred_type(init_type, is_lvalue_final=name.is_final)
+            and not self.no_partial_types
+        ):
+            # We cannot use the type of the initialization expression for full type
+            # inference (it's not specific enough), but we might be able to give
+            # partial type which will be made more specific later. A partial type
+            # gets generated in assignment like 'x = []' where item type is not known.
+            if not self.infer_partial_type(name, lvalue, init_type):
+                self.msg.need_annotation_for_var(name, context, self.options.python_version)
+                self.set_inference_error_fallback_type(name, lvalue, init_type)
+        elif (
+            isinstance(lvalue, MemberExpr)
+            and self.inferred_attribute_types is not None
+            and lvalue.def_var
+            and lvalue.def_var in self.inferred_attribute_types
+            and not is_same_type(self.inferred_attribute_types[lvalue.def_var], init_type)
+        ):
+            # Multiple, inconsistent types inferred for an attribute.
+            self.msg.need_annotation_for_var(name, context, self.options.python_version)
+            name.type = AnyType(TypeOfAny.from_error)
+        else:
+            # Infer type of the target.
+
+            # Make the type more general (strip away function names etc.).
+            init_type = strip_type(init_type)
+
+            self.set_inferred_type(name, lvalue, init_type)
+
+    def infer_partial_type(self, name: Var, lvalue: Lvalue, init_type: Type) -> bool:
+        init_type = get_proper_type(init_type)
+        if isinstance(init_type, NoneType):
+            partial_type = PartialType(None, name)
+        elif isinstance(init_type, Instance):
+            fullname = init_type.type.fullname
+            is_ref = isinstance(lvalue, RefExpr)
+            if (
+                is_ref
+                and (
+                    fullname == "builtins.list"
+                    or fullname == "builtins.set"
+                    or fullname == "builtins.dict"
+                    or fullname == "collections.OrderedDict"
+                )
+                and all(
+                    isinstance(t, (NoneType, UninhabitedType))
+                    for t in get_proper_types(init_type.args)
+                )
+            ):
+                partial_type = PartialType(init_type.type, name)
+            elif is_ref and fullname == "collections.defaultdict":
+                arg0 = get_proper_type(init_type.args[0])
+                arg1 = get_proper_type(init_type.args[1])
+                if isinstance(
+                    arg0, (NoneType, UninhabitedType)
+                ) and self.is_valid_defaultdict_partial_value_type(arg1):
+                    arg1 = erase_type(arg1)
+                    assert isinstance(arg1, Instance)
+                    partial_type = PartialType(init_type.type, name, arg1)
+                else:
+                    return False
+            else:
+                return False
+        else:
+            return False
+        self.set_inferred_type(name, lvalue, partial_type)
+        self.partial_types[-1].map[name] = lvalue
+        return True
+
+    def is_valid_defaultdict_partial_value_type(self, t: ProperType) -> bool:
+        """Check if t can be used as the basis for a partial defaultdict value type.
+
+        Examples:
+
+          * t is 'int' --> True
+          * t is 'list[<nothing>]' --> True
+          * t is 'dict[...]' --> False (only generic types with a single type
+            argument supported)
+        """
+        if not isinstance(t, Instance):
+            return False
+        if len(t.args) == 0:
+            return True
+        if len(t.args) == 1:
+            arg = get_proper_type(t.args[0])
+            # TODO: This is too permissive -- we only allow TypeVarType since
+            #       they leak in cases like defaultdict(list) due to a bug.
+            #       This can result in incorrect types being inferred, but only
+            #       in rare cases.
+            if isinstance(arg, (TypeVarType, UninhabitedType, NoneType)):
+                return True
+        return False
+
+    def set_inferred_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
+        """Store inferred variable type.
+
+        Store the type to both the variable node and the expression node that
+        refers to the variable (lvalue). If var is None, do nothing.
+        """
+        if var and not self.current_node_deferred:
+            var.type = type
+            var.is_inferred = True
+            if var not in self.var_decl_frames:
+                # Used for the hack to improve optional type inference in conditionals
+                self.var_decl_frames[var] = {frame.id for frame in self.binder.frames}
+            if isinstance(lvalue, MemberExpr) and self.inferred_attribute_types is not None:
+                # Store inferred attribute type so that we can check consistency afterwards.
+                if lvalue.def_var is not None:
+                    self.inferred_attribute_types[lvalue.def_var] = type
+            self.store_type(lvalue, type)
+
+    def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
+        """Store best known type for variable if type inference failed.
+
+        If a program ignores error on type inference error, the variable should get some
+        inferred type so that if can used later on in the program. Example:
+
+          x = []  # type: ignore
+          x.append(1)   # Should be ok!
+
+        We implement this here by giving x a valid type (replacing inferred <nothing> with Any).
+        """
+        fallback = self.inference_error_fallback_type(type)
+        self.set_inferred_type(var, lvalue, fallback)
+
+    def inference_error_fallback_type(self, type: Type) -> Type:
+        fallback = type.accept(SetNothingToAny())
+        # Type variables may leak from inference, see https://github.com/python/mypy/issues/5738,
+        # we therefore need to erase them.
+        return erase_typevars(fallback)
+
+    def simple_rvalue(self, rvalue: Expression) -> bool:
+        """Returns True for expressions for which inferred type should not depend on context.
+
+        Note that this function can still return False for some expressions where inferred type
+        does not depend on context. It only exists for performance optimizations.
+        """
+        if isinstance(rvalue, (IntExpr, StrExpr, BytesExpr, FloatExpr, RefExpr)):
+            return True
+        if isinstance(rvalue, CallExpr):
+            if isinstance(rvalue.callee, RefExpr) and isinstance(rvalue.callee.node, FuncBase):
+                typ = rvalue.callee.node.type
+                if isinstance(typ, CallableType):
+                    return not typ.variables
+                elif isinstance(typ, Overloaded):
+                    return not any(item.variables for item in typ.items)
+        return False
+
+    def check_simple_assignment(
+        self,
+        lvalue_type: Type | None,
+        rvalue: Expression,
+        context: Context,
+        msg: ErrorMessage = message_registry.INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
+        lvalue_name: str = "variable",
+        rvalue_name: str = "expression",
+        *,
+        notes: list[str] | None = None,
+    ) -> Type:
+        if self.is_stub and isinstance(rvalue, EllipsisExpr):
+            # '...' is always a valid initializer in a stub.
+            return AnyType(TypeOfAny.special_form)
+        else:
+            always_allow_any = lvalue_type is not None and not isinstance(
+                get_proper_type(lvalue_type), AnyType
+            )
+            rvalue_type = self.expr_checker.accept(
+                rvalue, lvalue_type, always_allow_any=always_allow_any
+            )
+            if (
+                isinstance(get_proper_type(lvalue_type), UnionType)
+                # Skip literal types, as they have special logic (for better errors).
+                and not isinstance(get_proper_type(rvalue_type), LiteralType)
+                and not self.simple_rvalue(rvalue)
+            ):
+                # Try re-inferring r.h.s. in empty context, and use that if it
+                # results in a narrower type. We don't do this always because this
+                # may cause some perf impact, plus we want to partially preserve
+                # the old behavior. This helps with various practical examples, see
+                # e.g. testOptionalTypeNarrowedByGenericCall.
+                with self.msg.filter_errors() as local_errors, self.local_type_map() as type_map:
+                    alt_rvalue_type = self.expr_checker.accept(
+                        rvalue, None, always_allow_any=always_allow_any
+                    )
+                if (
+                    not local_errors.has_new_errors()
+                    # Skip Any type, since it is special cased in binder.
+                    and not isinstance(get_proper_type(alt_rvalue_type), AnyType)
+                    and is_valid_inferred_type(alt_rvalue_type)
+                    and is_proper_subtype(alt_rvalue_type, rvalue_type)
+                ):
+                    rvalue_type = alt_rvalue_type
+                    self.store_types(type_map)
+            if isinstance(rvalue_type, DeletedType):
+                self.msg.deleted_as_rvalue(rvalue_type, context)
+            if isinstance(lvalue_type, DeletedType):
+                self.msg.deleted_as_lvalue(lvalue_type, context)
+            elif lvalue_type:
+                self.check_subtype(
+                    # Preserve original aliases for error messages when possible.
+                    rvalue_type,
+                    lvalue_type,
+                    context,
+                    msg,
+                    f"{rvalue_name} has type",
+                    f"{lvalue_name} has type",
+                    notes=notes,
+                )
+            return rvalue_type
+
+    def check_member_assignment(
+        self, instance_type: Type, attribute_type: Type, rvalue: Expression, context: Context
+    ) -> tuple[Type, Type, bool]:
+        """Type member assignment.
+
+        This defers to check_simple_assignment, unless the member expression
+        is a descriptor, in which case this checks descriptor semantics as well.
+
+        Return the inferred rvalue_type, inferred lvalue_type, and whether to use the binder
+        for this assignment.
+
+        Note: this method exists here and not in checkmember.py, because we need to take
+        care about interaction between binder and __set__().
+        """
+        instance_type = get_proper_type(instance_type)
+        attribute_type = get_proper_type(attribute_type)
+        # Descriptors don't participate in class-attribute access
+        if (isinstance(instance_type, FunctionLike) and instance_type.is_type_obj()) or isinstance(
+            instance_type, TypeType
+        ):
+            rvalue_type = self.check_simple_assignment(attribute_type, rvalue, context)
+            return rvalue_type, attribute_type, True
+
+        if not isinstance(attribute_type, Instance):
+            # TODO: support __set__() for union types.
+            rvalue_type = self.check_simple_assignment(attribute_type, rvalue, context)
+            return rvalue_type, attribute_type, True
+
+        mx = MemberContext(
+            is_lvalue=False,
+            is_super=False,
+            is_operator=False,
+            original_type=instance_type,
+            context=context,
+            self_type=None,
+            msg=self.msg,
+            chk=self,
+        )
+        get_type = analyze_descriptor_access(attribute_type, mx)
+        if not attribute_type.type.has_readable_member("__set__"):
+            # If there is no __set__, we type-check that the assigned value matches
+            # the return type of __get__. This doesn't match the python semantics,
+            # (which allow you to override the descriptor with any value), but preserves
+            # the type of accessing the attribute (even after the override).
+            rvalue_type = self.check_simple_assignment(get_type, rvalue, context)
+            return rvalue_type, get_type, True
+
+        dunder_set = attribute_type.type.get_method("__set__")
+        if dunder_set is None:
+            self.fail(
+                message_registry.DESCRIPTOR_SET_NOT_CALLABLE.format(
+                    attribute_type.str_with_options(self.options)
+                ),
+                context,
+            )
+            return AnyType(TypeOfAny.from_error), get_type, False
+
+        bound_method = analyze_decorator_or_funcbase_access(
+            defn=dunder_set,
+            itype=attribute_type,
+            info=attribute_type.type,
+            self_type=attribute_type,
+            name="__set__",
+            mx=mx,
+        )
+        typ = map_instance_to_supertype(attribute_type, dunder_set.info)
+        dunder_set_type = expand_type_by_instance(bound_method, typ)
+
+        callable_name = self.expr_checker.method_fullname(attribute_type, "__set__")
+        dunder_set_type = self.expr_checker.transform_callee_type(
+            callable_name,
+            dunder_set_type,
+            [TempNode(instance_type, context=context), rvalue],
+            [nodes.ARG_POS, nodes.ARG_POS],
+            context,
+            object_type=attribute_type,
+        )
+
+        # For non-overloaded setters, the result should be type-checked like a regular assignment.
+        # Hence, we first only try to infer the type by using the rvalue as type context.
+        type_context = rvalue
+        with self.msg.filter_errors():
+            _, inferred_dunder_set_type = self.expr_checker.check_call(
+                dunder_set_type,
+                [TempNode(instance_type, context=context), type_context],
+                [nodes.ARG_POS, nodes.ARG_POS],
+                context,
+                object_type=attribute_type,
+                callable_name=callable_name,
+            )
+
+        # And now we in fact type check the call, to show errors related to wrong arguments
+        # count, etc., replacing the type context for non-overloaded setters only.
+        inferred_dunder_set_type = get_proper_type(inferred_dunder_set_type)
+        if isinstance(inferred_dunder_set_type, CallableType):
+            type_context = TempNode(AnyType(TypeOfAny.special_form), context=context)
+        self.expr_checker.check_call(
+            dunder_set_type,
+            [TempNode(instance_type, context=context), type_context],
+            [nodes.ARG_POS, nodes.ARG_POS],
+            context,
+            object_type=attribute_type,
+            callable_name=callable_name,
+        )
+
+        # In the following cases, a message already will have been recorded in check_call.
+        if (not isinstance(inferred_dunder_set_type, CallableType)) or (
+            len(inferred_dunder_set_type.arg_types) < 2
+        ):
+            return AnyType(TypeOfAny.from_error), get_type, False
+
+        set_type = inferred_dunder_set_type.arg_types[1]
+        # Special case: if the rvalue_type is a subtype of both '__get__' and '__set__' types,
+        # and '__get__' type is narrower than '__set__', then we invoke the binder to narrow type
+        # by this assignment. Technically, this is not safe, but in practice this is
+        # what a user expects.
+        rvalue_type = self.check_simple_assignment(set_type, rvalue, context)
+        infer = is_subtype(rvalue_type, get_type) and is_subtype(get_type, set_type)
+        return rvalue_type if infer else set_type, get_type, infer
+
+    def check_indexed_assignment(
+        self, lvalue: IndexExpr, rvalue: Expression, context: Context
+    ) -> None:
+        """Type check indexed assignment base[index] = rvalue.
+
+        The lvalue argument is the base[index] expression.
+        """
+        self.try_infer_partial_type_from_indexed_assignment(lvalue, rvalue)
+        basetype = get_proper_type(self.expr_checker.accept(lvalue.base))
+        method_type = self.expr_checker.analyze_external_member_access(
+            "__setitem__", basetype, lvalue
+        )
+
+        lvalue.method_type = method_type
+        res_type, _ = self.expr_checker.check_method_call(
+            "__setitem__",
+            basetype,
+            method_type,
+            [lvalue.index, rvalue],
+            [nodes.ARG_POS, nodes.ARG_POS],
+            context,
+        )
+        res_type = get_proper_type(res_type)
+        if isinstance(res_type, UninhabitedType) and not res_type.ambiguous:
+            self.binder.unreachable()
+
+    def try_infer_partial_type_from_indexed_assignment(
+        self, lvalue: IndexExpr, rvalue: Expression
+    ) -> None:
+        # TODO: Should we share some of this with try_infer_partial_type?
+        var = None
+        if isinstance(lvalue.base, RefExpr) and isinstance(lvalue.base.node, Var):
+            var = lvalue.base.node
+        elif isinstance(lvalue.base, MemberExpr):
+            var = self.expr_checker.get_partial_self_var(lvalue.base)
+        if isinstance(var, Var):
+            if isinstance(var.type, PartialType):
+                type_type = var.type.type
+                if type_type is None:
+                    return  # The partial type is None.
+                partial_types = self.find_partial_types(var)
+                if partial_types is None:
+                    return
+                typename = type_type.fullname
+                if (
+                    typename == "builtins.dict"
+                    or typename == "collections.OrderedDict"
+                    or typename == "collections.defaultdict"
+                ):
+                    # TODO: Don't infer things twice.
+                    key_type = self.expr_checker.accept(lvalue.index)
+                    value_type = self.expr_checker.accept(rvalue)
+                    if (
+                        is_valid_inferred_type(key_type)
+                        and is_valid_inferred_type(value_type)
+                        and not self.current_node_deferred
+                        and not (
+                            typename == "collections.defaultdict"
+                            and var.type.value_type is not None
+                            and not is_equivalent(value_type, var.type.value_type)
+                        )
+                    ):
+                        var.type = self.named_generic_type(typename, [key_type, value_type])
+                        del partial_types[var]
+
+    def type_requires_usage(self, typ: Type) -> tuple[str, ErrorCode] | None:
+        """Some types require usage in all cases. The classic example is
+        an unused coroutine.
+
+        In the case that it does require usage, returns a note to attach
+        to the error message.
+        """
+        proper_type = get_proper_type(typ)
+        if isinstance(proper_type, Instance):
+            # We use different error codes for generic awaitable vs coroutine.
+            # Coroutines are on by default, whereas generic awaitables are not.
+            if proper_type.type.fullname == "typing.Coroutine":
+                return ("Are you missing an await?", UNUSED_COROUTINE)
+            if proper_type.type.get("__await__") is not None:
+                return ("Are you missing an await?", UNUSED_AWAITABLE)
+        return None
+
+    def visit_expression_stmt(self, s: ExpressionStmt) -> None:
+        expr_type = self.expr_checker.accept(s.expr, allow_none_return=True, always_allow_any=True)
+        error_note_and_code = self.type_requires_usage(expr_type)
+        if error_note_and_code:
+            error_note, code = error_note_and_code
+            self.fail(
+                message_registry.TYPE_MUST_BE_USED.format(format_type(expr_type, self.options)),
+                s,
+                code=code,
+            )
+            self.note(error_note, s, code=code)
+
+    def visit_return_stmt(self, s: ReturnStmt) -> None:
+        """Type check a return statement."""
+        self.check_return_stmt(s)
+        self.binder.unreachable()
+
+    def check_return_stmt(self, s: ReturnStmt) -> None:
+        defn = self.scope.top_function()
+        if defn is not None:
+            if defn.is_generator:
+                return_type = self.get_generator_return_type(
+                    self.return_types[-1], defn.is_coroutine
+                )
+            elif defn.is_coroutine:
+                return_type = self.get_coroutine_return_type(self.return_types[-1])
+            else:
+                return_type = self.return_types[-1]
+            return_type = get_proper_type(return_type)
+
+            if isinstance(return_type, UninhabitedType):
+                self.fail(message_registry.NO_RETURN_EXPECTED, s)
+                return
+
+            if s.expr:
+                is_lambda = isinstance(self.scope.top_function(), LambdaExpr)
+                declared_none_return = isinstance(return_type, NoneType)
+                declared_any_return = isinstance(return_type, AnyType)
+
+                # This controls whether or not we allow a function call that
+                # returns None as the expression of this return statement.
+                # E.g. `return f()` for some `f` that returns None.  We allow
+                # this only if we're in a lambda or in a function that returns
+                # `None` or `Any`.
+                allow_none_func_call = is_lambda or declared_none_return or declared_any_return
+
+                # Return with a value.
+                typ = get_proper_type(
+                    self.expr_checker.accept(
+                        s.expr, return_type, allow_none_return=allow_none_func_call
+                    )
+                )
+
+                if defn.is_async_generator:
+                    self.fail(message_registry.RETURN_IN_ASYNC_GENERATOR, s)
+                    return
+                # Returning a value of type Any is always fine.
+                if isinstance(typ, AnyType):
+                    # (Unless you asked to be warned in that case, and the
+                    # function is not declared to return Any)
+                    if (
+                        self.options.warn_return_any
+                        and not self.current_node_deferred
+                        and not is_proper_subtype(AnyType(TypeOfAny.special_form), return_type)
+                        and not (
+                            defn.name in BINARY_MAGIC_METHODS
+                            and is_literal_not_implemented(s.expr)
+                        )
+                        and not (
+                            isinstance(return_type, Instance)
+                            and return_type.type.fullname == "builtins.object"
+                        )
+                        and not is_lambda
+                    ):
+                        self.msg.incorrectly_returning_any(return_type, s)
+                    return
+
+                # Disallow return expressions in functions declared to return
+                # None, subject to two exceptions below.
+                if declared_none_return:
+                    # Lambdas are allowed to have None returns.
+                    # Functions returning a value of type None are allowed to have a None return.
+                    if is_lambda or isinstance(typ, NoneType):
+                        return
+                    self.fail(message_registry.NO_RETURN_VALUE_EXPECTED, s)
+                else:
+                    self.check_subtype(
+                        subtype_label="got",
+                        subtype=typ,
+                        supertype_label="expected",
+                        supertype=return_type,
+                        context=s.expr,
+                        outer_context=s,
+                        msg=message_registry.INCOMPATIBLE_RETURN_VALUE_TYPE,
+                    )
+            else:
+                # Empty returns are valid in Generators with Any typed returns, but not in
+                # coroutines.
+                if (
+                    defn.is_generator
+                    and not defn.is_coroutine
+                    and isinstance(return_type, AnyType)
+                ):
+                    return
+
+                if isinstance(return_type, (NoneType, AnyType)):
+                    return
+
+                if self.in_checked_function():
+                    self.fail(message_registry.RETURN_VALUE_EXPECTED, s)
+
+    def visit_if_stmt(self, s: IfStmt) -> None:
+        """Type check an if statement."""
+        # This frame records the knowledge from previous if/elif clauses not being taken.
+        # Fall-through to the original frame is handled explicitly in each block.
+        with self.binder.frame_context(can_skip=False, conditional_frame=True, fall_through=0):
+            for e, b in zip(s.expr, s.body):
+                t = get_proper_type(self.expr_checker.accept(e))
+
+                if isinstance(t, DeletedType):
+                    self.msg.deleted_as_rvalue(t, s)
+
+                if_map, else_map = self.find_isinstance_check(e)
+
+                # XXX Issue a warning if condition is always False?
+                with self.binder.frame_context(can_skip=True, fall_through=2):
+                    self.push_type_map(if_map)
+                    self.accept(b)
+
+                # XXX Issue a warning if condition is always True?
+                self.push_type_map(else_map)
+
+            with self.binder.frame_context(can_skip=False, fall_through=2):
+                if s.else_body:
+                    self.accept(s.else_body)
+
+    def visit_while_stmt(self, s: WhileStmt) -> None:
+        """Type check a while statement."""
+        if_stmt = IfStmt([s.expr], [s.body], None)
+        if_stmt.set_line(s)
+        self.accept_loop(if_stmt, s.else_body, exit_condition=s.expr)
+
+    def visit_operator_assignment_stmt(self, s: OperatorAssignmentStmt) -> None:
+        """Type check an operator assignment statement, e.g. x += 1."""
+        self.try_infer_partial_generic_type_from_assignment(s.lvalue, s.rvalue, s.op)
+        if isinstance(s.lvalue, MemberExpr):
+            # Special case, some additional errors may be given for
+            # assignments to read-only or final attributes.
+            lvalue_type = self.expr_checker.visit_member_expr(s.lvalue, True)
+        else:
+            lvalue_type = self.expr_checker.accept(s.lvalue)
+        inplace, method = infer_operator_assignment_method(lvalue_type, s.op)
+        if inplace:
+            # There is __ifoo__, treat as x = x.__ifoo__(y)
+            rvalue_type, method_type = self.expr_checker.check_op(method, lvalue_type, s.rvalue, s)
+            if not is_subtype(rvalue_type, lvalue_type):
+                self.msg.incompatible_operator_assignment(s.op, s)
+        else:
+            # There is no __ifoo__, treat as x = x <foo> y
+            expr = OpExpr(s.op, s.lvalue, s.rvalue)
+            expr.set_line(s)
+            self.check_assignment(
+                lvalue=s.lvalue, rvalue=expr, infer_lvalue_type=True, new_syntax=False
+            )
+        self.check_final(s)
+
+    def visit_assert_stmt(self, s: AssertStmt) -> None:
+        self.expr_checker.accept(s.expr)
+
+        if isinstance(s.expr, TupleExpr) and len(s.expr.items) > 0:
+            self.fail(message_registry.MALFORMED_ASSERT, s)
+
+        # If this is asserting some isinstance check, bind that type in the following code
+        true_map, else_map = self.find_isinstance_check(s.expr)
+        if s.msg is not None:
+            self.expr_checker.analyze_cond_branch(else_map, s.msg, None)
+        self.push_type_map(true_map)
+
+    def visit_raise_stmt(self, s: RaiseStmt) -> None:
+        """Type check a raise statement."""
+        if s.expr:
+            self.type_check_raise(s.expr, s)
+        if s.from_expr:
+            self.type_check_raise(s.from_expr, s, optional=True)
+        self.binder.unreachable()
+
+    def type_check_raise(self, e: Expression, s: RaiseStmt, optional: bool = False) -> None:
+        typ = get_proper_type(self.expr_checker.accept(e))
+        if isinstance(typ, DeletedType):
+            self.msg.deleted_as_rvalue(typ, e)
+            return
+
+        exc_type = self.named_type("builtins.BaseException")
+        expected_type_items = [exc_type, TypeType(exc_type)]
+        if optional:
+            # This is used for `x` part in a case like `raise e from x`,
+            # where we allow `raise e from None`.
+            expected_type_items.append(NoneType())
+
+        self.check_subtype(
+            typ, UnionType.make_union(expected_type_items), s, message_registry.INVALID_EXCEPTION
+        )
+
+        if isinstance(typ, FunctionLike):
+            # https://github.com/python/mypy/issues/11089
+            self.expr_checker.check_call(typ, [], [], e)
+
+    def visit_try_stmt(self, s: TryStmt) -> None:
+        """Type check a try statement."""
+        # Our enclosing frame will get the result if the try/except falls through.
+        # This one gets all possible states after the try block exited abnormally
+        # (by exception, return, break, etc.)
+        with self.binder.frame_context(can_skip=False, fall_through=0):
+            # Not only might the body of the try statement exit
+            # abnormally, but so might an exception handler or else
+            # clause. The finally clause runs in *all* cases, so we
+            # need an outer try frame to catch all intermediate states
+            # in case an exception is raised during an except or else
+            # clause. As an optimization, only create the outer try
+            # frame when there actually is a finally clause.
+            self.visit_try_without_finally(s, try_frame=bool(s.finally_body))
+            if s.finally_body:
+                # First we check finally_body is type safe on all abnormal exit paths
+                self.accept(s.finally_body)
+
+        if s.finally_body:
+            # Then we try again for the more restricted set of options
+            # that can fall through. (Why do we need to check the
+            # finally clause twice? Depending on whether the finally
+            # clause was reached by the try clause falling off the end
+            # or exiting abnormally, after completing the finally clause
+            # either flow will continue to after the entire try statement
+            # or the exception/return/etc. will be processed and control
+            # flow will escape. We need to check that the finally clause
+            # type checks in both contexts, but only the resulting types
+            # from the latter context affect the type state in the code
+            # that follows the try statement.)
+            if not self.binder.is_unreachable():
+                self.accept(s.finally_body)
+
+    def visit_try_without_finally(self, s: TryStmt, try_frame: bool) -> None:
+        """Type check a try statement, ignoring the finally block.
+
+        On entry, the top frame should receive all flow that exits the
+        try block abnormally (i.e., such that the else block does not
+        execute), and its parent should receive all flow that exits
+        the try block normally.
+        """
+        # This frame will run the else block if the try fell through.
+        # In that case, control flow continues to the parent of what
+        # was the top frame on entry.
+        with self.binder.frame_context(can_skip=False, fall_through=2, try_frame=try_frame):
+            # This frame receives exit via exception, and runs exception handlers
+            with self.binder.frame_context(can_skip=False, conditional_frame=True, fall_through=2):
+                # Finally, the body of the try statement
+                with self.binder.frame_context(can_skip=False, fall_through=2, try_frame=True):
+                    self.accept(s.body)
+                for i in range(len(s.handlers)):
+                    with self.binder.frame_context(can_skip=True, fall_through=4):
+                        typ = s.types[i]
+                        if typ:
+                            t = self.check_except_handler_test(typ, s.is_star)
+                            var = s.vars[i]
+                            if var:
+                                # To support local variables, we make this a definition line,
+                                # causing assignment to set the variable's type.
+                                var.is_inferred_def = True
+                                self.check_assignment(var, self.temp_node(t, var))
+                        self.accept(s.handlers[i])
+                        var = s.vars[i]
+                        if var:
+                            # Exception variables are deleted.
+                            # Unfortunately, this doesn't let us detect usage before the
+                            # try/except block.
+                            source = var.name
+                            if isinstance(var.node, Var):
+                                var.node.type = DeletedType(source=source)
+                            self.binder.cleanse(var)
+            if s.else_body:
+                self.accept(s.else_body)
+
+    def check_except_handler_test(self, n: Expression, is_star: bool) -> Type:
+        """Type check an exception handler test clause."""
+        typ = self.expr_checker.accept(n)
+
+        all_types: list[Type] = []
+        test_types = self.get_types_from_except_handler(typ, n)
+
+        for ttype in get_proper_types(test_types):
+            if isinstance(ttype, AnyType):
+                all_types.append(ttype)
+                continue
+
+            if isinstance(ttype, FunctionLike):
+                item = ttype.items[0]
+                if not item.is_type_obj():
+                    self.fail(message_registry.INVALID_EXCEPTION_TYPE, n)
+                    return self.default_exception_type(is_star)
+                exc_type = erase_typevars(item.ret_type)
+            elif isinstance(ttype, TypeType):
+                exc_type = ttype.item
+            else:
+                self.fail(message_registry.INVALID_EXCEPTION_TYPE, n)
+                return self.default_exception_type(is_star)
+
+            if not is_subtype(exc_type, self.named_type("builtins.BaseException")):
+                self.fail(message_registry.INVALID_EXCEPTION_TYPE, n)
+                return self.default_exception_type(is_star)
+
+            all_types.append(exc_type)
+
+        if is_star:
+            new_all_types: list[Type] = []
+            for typ in all_types:
+                if is_proper_subtype(typ, self.named_type("builtins.BaseExceptionGroup")):
+                    self.fail(message_registry.INVALID_EXCEPTION_GROUP, n)
+                    new_all_types.append(AnyType(TypeOfAny.from_error))
+                else:
+                    new_all_types.append(typ)
+            return self.wrap_exception_group(new_all_types)
+        return make_simplified_union(all_types)
+
+    def default_exception_type(self, is_star: bool) -> Type:
+        """Exception type to return in case of a previous type error."""
+        any_type = AnyType(TypeOfAny.from_error)
+        if is_star:
+            return self.named_generic_type("builtins.ExceptionGroup", [any_type])
+        return any_type
+
+    def wrap_exception_group(self, types: Sequence[Type]) -> Type:
+        """Transform except* variable type into an appropriate exception group."""
+        arg = make_simplified_union(types)
+        if is_subtype(arg, self.named_type("builtins.Exception")):
+            base = "builtins.ExceptionGroup"
+        else:
+            base = "builtins.BaseExceptionGroup"
+        return self.named_generic_type(base, [arg])
+
+    def get_types_from_except_handler(self, typ: Type, n: Expression) -> list[Type]:
+        """Helper for check_except_handler_test to retrieve handler types."""
+        typ = get_proper_type(typ)
+        if isinstance(typ, TupleType):
+            return typ.items
+        elif isinstance(typ, UnionType):
+            return [
+                union_typ
+                for item in typ.relevant_items()
+                for union_typ in self.get_types_from_except_handler(item, n)
+            ]
+        elif is_named_instance(typ, "builtins.tuple"):
+            # variadic tuple
+            return [typ.args[0]]
+        else:
+            return [typ]
+
+    def visit_for_stmt(self, s: ForStmt) -> None:
+        """Type check a for statement."""
+        if s.is_async:
+            iterator_type, item_type = self.analyze_async_iterable_item_type(s.expr)
+        else:
+            iterator_type, item_type = self.analyze_iterable_item_type(s.expr)
+        s.inferred_item_type = item_type
+        s.inferred_iterator_type = iterator_type
+        self.analyze_index_variables(s.index, item_type, s.index_type is None, s)
+        self.accept_loop(s.body, s.else_body)
+
+    def analyze_async_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]:
+        """Analyse async iterable expression and return iterator and iterator item types."""
+        echk = self.expr_checker
+        iterable = echk.accept(expr)
+        iterator = echk.check_method_call_by_name("__aiter__", iterable, [], [], expr)[0]
+        awaitable = echk.check_method_call_by_name("__anext__", iterator, [], [], expr)[0]
+        item_type = echk.check_awaitable_expr(
+            awaitable, expr, message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_FOR
+        )
+        return iterator, item_type
+
+    def analyze_iterable_item_type(self, expr: Expression) -> tuple[Type, Type]:
+        """Analyse iterable expression and return iterator and iterator item types."""
+        echk = self.expr_checker
+        iterable = get_proper_type(echk.accept(expr))
+        iterator = echk.check_method_call_by_name("__iter__", iterable, [], [], expr)[0]
+
+        int_type = self.analyze_range_native_int_type(expr)
+        if int_type:
+            return iterator, int_type
+
+        if isinstance(iterable, TupleType):
+            joined: Type = UninhabitedType()
+            for item in iterable.items:
+                joined = join_types(joined, item)
+            return iterator, joined
+        else:
+            # Non-tuple iterable.
+            return iterator, echk.check_method_call_by_name("__next__", iterator, [], [], expr)[0]
+
+    def analyze_iterable_item_type_without_expression(
+        self, type: Type, context: Context
+    ) -> tuple[Type, Type]:
+        """Analyse iterable type and return iterator and iterator item types."""
+        echk = self.expr_checker
+        iterable = get_proper_type(type)
+        iterator = echk.check_method_call_by_name("__iter__", iterable, [], [], context)[0]
+
+        if isinstance(iterable, TupleType):
+            joined: Type = UninhabitedType()
+            for item in iterable.items:
+                joined = join_types(joined, item)
+            return iterator, joined
+        else:
+            # Non-tuple iterable.
+            return (
+                iterator,
+                echk.check_method_call_by_name("__next__", iterator, [], [], context)[0],
+            )
+
+    def analyze_range_native_int_type(self, expr: Expression) -> Type | None:
+        """Try to infer native int item type from arguments to range(...).
+
+        For example, return i64 if the expression is "range(0, i64(n))".
+
+        Return None if unsuccessful.
+        """
+        if (
+            isinstance(expr, CallExpr)
+            and isinstance(expr.callee, RefExpr)
+            and expr.callee.fullname == "builtins.range"
+            and 1 <= len(expr.args) <= 3
+            and all(kind == ARG_POS for kind in expr.arg_kinds)
+        ):
+            native_int: Type | None = None
+            ok = True
+            for arg in expr.args:
+                argt = get_proper_type(self.lookup_type(arg))
+                if isinstance(argt, Instance) and argt.type.fullname in MYPYC_NATIVE_INT_NAMES:
+                    if native_int is None:
+                        native_int = argt
+                    elif argt != native_int:
+                        ok = False
+            if ok and native_int:
+                return native_int
+        return None
+
+    def analyze_container_item_type(self, typ: Type) -> Type | None:
+        """Check if a type is a nominal container of a union of such.
+
+        Return the corresponding container item type.
+        """
+        typ = get_proper_type(typ)
+        if isinstance(typ, UnionType):
+            types: list[Type] = []
+            for item in typ.items:
+                c_type = self.analyze_container_item_type(item)
+                if c_type:
+                    types.append(c_type)
+            return UnionType.make_union(types)
+        if isinstance(typ, Instance) and typ.type.has_base("typing.Container"):
+            supertype = self.named_type("typing.Container").type
+            super_instance = map_instance_to_supertype(typ, supertype)
+            assert len(super_instance.args) == 1
+            return super_instance.args[0]
+        if isinstance(typ, TupleType):
+            return self.analyze_container_item_type(tuple_fallback(typ))
+        return None
+
+    def analyze_index_variables(
+        self, index: Expression, item_type: Type, infer_lvalue_type: bool, context: Context
+    ) -> None:
+        """Type check or infer for loop or list comprehension index vars."""
+        self.check_assignment(index, self.temp_node(item_type, context), infer_lvalue_type)
+
+    def visit_del_stmt(self, s: DelStmt) -> None:
+        if isinstance(s.expr, IndexExpr):
+            e = s.expr
+            m = MemberExpr(e.base, "__delitem__")
+            m.line = s.line
+            m.column = s.column
+            c = CallExpr(m, [e.index], [nodes.ARG_POS], [None])
+            c.line = s.line
+            c.column = s.column
+            self.expr_checker.accept(c, allow_none_return=True)
+        else:
+            s.expr.accept(self.expr_checker)
+            for elt in flatten(s.expr):
+                if isinstance(elt, NameExpr):
+                    self.binder.assign_type(
+                        elt, DeletedType(source=elt.name), get_declaration(elt), False
+                    )
+
+    def visit_decorator(self, e: Decorator) -> None:
+        for d in e.decorators:
+            if isinstance(d, RefExpr):
+                if d.fullname == "typing.no_type_check":
+                    e.var.type = AnyType(TypeOfAny.special_form)
+                    e.var.is_ready = True
+                    return
+
+        if self.recurse_into_functions:
+            with self.tscope.function_scope(e.func):
+                self.check_func_item(e.func, name=e.func.name)
+
+        # Process decorators from the inside out to determine decorated signature, which
+        # may be different from the declared signature.
+        sig: Type = self.function_type(e.func)
+        for d in reversed(e.decorators):
+            if refers_to_fullname(d, OVERLOAD_NAMES):
+                self.fail(message_registry.MULTIPLE_OVERLOADS_REQUIRED, e)
+                continue
+            dec = self.expr_checker.accept(d)
+            temp = self.temp_node(sig, context=e)
+            fullname = None
+            if isinstance(d, RefExpr):
+                fullname = d.fullname or None
+            # if this is a expression like @b.a where b is an object, get the type of b
+            # so we can pass it the method hook in the plugins
+            object_type: Type | None = None
+            if fullname is None and isinstance(d, MemberExpr) and self.has_type(d.expr):
+                object_type = self.lookup_type(d.expr)
+                fullname = self.expr_checker.method_fullname(object_type, d.name)
+            self.check_for_untyped_decorator(e.func, dec, d)
+            sig, t2 = self.expr_checker.check_call(
+                dec, [temp], [nodes.ARG_POS], e, callable_name=fullname, object_type=object_type
+            )
+        self.check_untyped_after_decorator(sig, e.func)
+        sig = set_callable_name(sig, e.func)
+        e.var.type = sig
+        e.var.is_ready = True
+        if e.func.is_property:
+            if isinstance(sig, CallableType):
+                if len([k for k in sig.arg_kinds if k.is_required()]) > 1:
+                    self.msg.fail("Too many arguments for property", e)
+            self.check_incompatible_property_override(e)
+        # For overloaded functions we already checked override for overload as a whole.
+        if e.func.info and not e.func.is_dynamic() and not e.is_overload:
+            found_method_base_classes = self.check_method_override(e)
+            if (
+                e.func.is_explicit_override
+                and not found_method_base_classes
+                and found_method_base_classes is not None
+            ):
+                self.msg.no_overridable_method(e.func.name, e.func)
+            self.check_explicit_override_decorator(e.func, found_method_base_classes)
+
+        if e.func.info and e.func.name in ("__init__", "__new__"):
+            if e.type and not isinstance(get_proper_type(e.type), (FunctionLike, AnyType)):
+                self.fail(message_registry.BAD_CONSTRUCTOR_TYPE, e)
+
+    def check_for_untyped_decorator(
+        self, func: FuncDef, dec_type: Type, dec_expr: Expression
+    ) -> None:
+        if (
+            self.options.disallow_untyped_decorators
+            and is_typed_callable(func.type)
+            and is_untyped_decorator(dec_type)
+        ):
+            self.msg.typed_function_untyped_decorator(func.name, dec_expr)
+
+    def check_incompatible_property_override(self, e: Decorator) -> None:
+        if not e.var.is_settable_property and e.func.info:
+            name = e.func.name
+            for base in e.func.info.mro[1:]:
+                base_attr = base.names.get(name)
+                if not base_attr:
+                    continue
+                if (
+                    isinstance(base_attr.node, OverloadedFuncDef)
+                    and base_attr.node.is_property
+                    and cast(Decorator, base_attr.node.items[0]).var.is_settable_property
+                ):
+                    self.fail(message_registry.READ_ONLY_PROPERTY_OVERRIDES_READ_WRITE, e)
+
+    def visit_with_stmt(self, s: WithStmt) -> None:
+        exceptions_maybe_suppressed = False
+        for expr, target in zip(s.expr, s.target):
+            if s.is_async:
+                exit_ret_type = self.check_async_with_item(expr, target, s.unanalyzed_type is None)
+            else:
+                exit_ret_type = self.check_with_item(expr, target, s.unanalyzed_type is None)
+
+            # Based on the return type, determine if this context manager 'swallows'
+            # exceptions or not. We determine this using a heuristic based on the
+            # return type of the __exit__ method -- see the discussion in
+            # https://github.com/python/mypy/issues/7214 and the section about context managers
+            # in https://github.com/python/typeshed/blob/main/CONTRIBUTING.md#conventions
+            # for more details.
+
+            exit_ret_type = get_proper_type(exit_ret_type)
+            if is_literal_type(exit_ret_type, "builtins.bool", False):
+                continue
+
+            if is_literal_type(exit_ret_type, "builtins.bool", True) or (
+                isinstance(exit_ret_type, Instance)
+                and exit_ret_type.type.fullname == "builtins.bool"
+                and state.strict_optional
+            ):
+                # Note: if strict-optional is disabled, this bool instance
+                # could actually be an Optional[bool].
+                exceptions_maybe_suppressed = True
+
+        if exceptions_maybe_suppressed:
+            # Treat this 'with' block in the same way we'd treat a 'try: BODY; except: pass'
+            # block. This means control flow can continue after the 'with' even if the 'with'
+            # block immediately returns.
+            with self.binder.frame_context(can_skip=True, try_frame=True):
+                self.accept(s.body)
+        else:
+            self.accept(s.body)
+
+    def check_untyped_after_decorator(self, typ: Type, func: FuncDef) -> None:
+        if not self.options.disallow_any_decorated or self.is_stub:
+            return
+
+        if mypy.checkexpr.has_any_type(typ):
+            self.msg.untyped_decorated_function(typ, func)
+
+    def check_async_with_item(
+        self, expr: Expression, target: Expression | None, infer_lvalue_type: bool
+    ) -> Type:
+        echk = self.expr_checker
+        ctx = echk.accept(expr)
+        obj = echk.check_method_call_by_name("__aenter__", ctx, [], [], expr)[0]
+        obj = echk.check_awaitable_expr(
+            obj, expr, message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AENTER
+        )
+        if target:
+            self.check_assignment(target, self.temp_node(obj, expr), infer_lvalue_type)
+        arg = self.temp_node(AnyType(TypeOfAny.special_form), expr)
+        res, _ = echk.check_method_call_by_name(
+            "__aexit__", ctx, [arg] * 3, [nodes.ARG_POS] * 3, expr
+        )
+        return echk.check_awaitable_expr(
+            res, expr, message_registry.INCOMPATIBLE_TYPES_IN_ASYNC_WITH_AEXIT
+        )
+
+    def check_with_item(
+        self, expr: Expression, target: Expression | None, infer_lvalue_type: bool
+    ) -> Type:
+        echk = self.expr_checker
+        ctx = echk.accept(expr)
+        obj = echk.check_method_call_by_name("__enter__", ctx, [], [], expr)[0]
+        if target:
+            self.check_assignment(target, self.temp_node(obj, expr), infer_lvalue_type)
+        arg = self.temp_node(AnyType(TypeOfAny.special_form), expr)
+        res, _ = echk.check_method_call_by_name(
+            "__exit__", ctx, [arg] * 3, [nodes.ARG_POS] * 3, expr
+        )
+        return res
+
+    def visit_break_stmt(self, s: BreakStmt) -> None:
+        self.binder.handle_break()
+
+    def visit_continue_stmt(self, s: ContinueStmt) -> None:
+        self.binder.handle_continue()
+        return None
+
+    def visit_match_stmt(self, s: MatchStmt) -> None:
+        with self.binder.frame_context(can_skip=False, fall_through=0):
+            subject_type = get_proper_type(self.expr_checker.accept(s.subject))
+
+            if isinstance(subject_type, DeletedType):
+                self.msg.deleted_as_rvalue(subject_type, s)
+
+            # We infer types of patterns twice. The first pass is used
+            # to infer the types of capture variables. The type of a
+            # capture variable may depend on multiple patterns (it
+            # will be a union of all capture types). This pass ignores
+            # guard expressions.
+            pattern_types = [self.pattern_checker.accept(p, subject_type) for p in s.patterns]
+            type_maps: list[TypeMap] = [t.captures for t in pattern_types]
+            inferred_types = self.infer_variable_types_from_type_maps(type_maps)
+
+            # The second pass narrows down the types and type checks bodies.
+            for p, g, b in zip(s.patterns, s.guards, s.bodies):
+                current_subject_type = self.expr_checker.narrow_type_from_binder(
+                    s.subject, subject_type
+                )
+                pattern_type = self.pattern_checker.accept(p, current_subject_type)
+                with self.binder.frame_context(can_skip=True, fall_through=2):
+                    if b.is_unreachable or isinstance(
+                        get_proper_type(pattern_type.type), UninhabitedType
+                    ):
+                        self.push_type_map(None)
+                        else_map: TypeMap = {}
+                    else:
+                        pattern_map, else_map = conditional_types_to_typemaps(
+                            s.subject, pattern_type.type, pattern_type.rest_type
+                        )
+                        self.remove_capture_conflicts(pattern_type.captures, inferred_types)
+                        self.push_type_map(pattern_map)
+                        self.push_type_map(pattern_type.captures)
+                    if g is not None:
+                        with self.binder.frame_context(can_skip=True, fall_through=3):
+                            gt = get_proper_type(self.expr_checker.accept(g))
+
+                            if isinstance(gt, DeletedType):
+                                self.msg.deleted_as_rvalue(gt, s)
+
+                            guard_map, guard_else_map = self.find_isinstance_check(g)
+                            else_map = or_conditional_maps(else_map, guard_else_map)
+
+                            self.push_type_map(guard_map)
+                            self.accept(b)
+                    else:
+                        self.accept(b)
+                self.push_type_map(else_map)
+
+            # This is needed due to a quirk in frame_context. Without it types will stay narrowed
+            # after the match.
+            with self.binder.frame_context(can_skip=False, fall_through=2):
+                pass
+
+    def infer_variable_types_from_type_maps(self, type_maps: list[TypeMap]) -> dict[Var, Type]:
+        all_captures: dict[Var, list[tuple[NameExpr, Type]]] = defaultdict(list)
+        for tm in type_maps:
+            if tm is not None:
+                for expr, typ in tm.items():
+                    if isinstance(expr, NameExpr):
+                        node = expr.node
+                        assert isinstance(node, Var)
+                        all_captures[node].append((expr, typ))
+
+        inferred_types: dict[Var, Type] = {}
+        for var, captures in all_captures.items():
+            already_exists = False
+            types: list[Type] = []
+            for expr, typ in captures:
+                types.append(typ)
+
+                previous_type, _, _ = self.check_lvalue(expr)
+                if previous_type is not None:
+                    already_exists = True
+                    if self.check_subtype(
+                        typ,
+                        previous_type,
+                        expr,
+                        msg=message_registry.INCOMPATIBLE_TYPES_IN_CAPTURE,
+                        subtype_label="pattern captures type",
+                        supertype_label="variable has type",
+                    ):
+                        inferred_types[var] = previous_type
+
+            if not already_exists:
+                new_type = UnionType.make_union(types)
+                # Infer the union type at the first occurrence
+                first_occurrence, _ = captures[0]
+                inferred_types[var] = new_type
+                self.infer_variable_type(var, first_occurrence, new_type, first_occurrence)
+        return inferred_types
+
+    def remove_capture_conflicts(self, type_map: TypeMap, inferred_types: dict[Var, Type]) -> None:
+        if type_map:
+            for expr, typ in list(type_map.items()):
+                if isinstance(expr, NameExpr):
+                    node = expr.node
+                    assert isinstance(node, Var)
+                    if node not in inferred_types or not is_subtype(typ, inferred_types[node]):
+                        del type_map[expr]
+
+    def make_fake_typeinfo(
+        self,
+        curr_module_fullname: str,
+        class_gen_name: str,
+        class_short_name: str,
+        bases: list[Instance],
+    ) -> tuple[ClassDef, TypeInfo]:
+        # Build the fake ClassDef and TypeInfo together.
+        # The ClassDef is full of lies and doesn't actually contain a body.
+        # Use format_bare to generate a nice name for error messages.
+        # We skip fully filling out a handful of TypeInfo fields because they
+        # should be irrelevant for a generated type like this:
+        # is_protocol, protocol_members, is_abstract
+        cdef = ClassDef(class_short_name, Block([]))
+        cdef.fullname = curr_module_fullname + "." + class_gen_name
+        info = TypeInfo(SymbolTable(), cdef, curr_module_fullname)
+        cdef.info = info
+        info.bases = bases
+        calculate_mro(info)
+        info.metaclass_type = info.calculate_metaclass_type()
+        return cdef, info
+
+    def intersect_instances(
+        self, instances: tuple[Instance, Instance], errors: list[tuple[str, str]]
+    ) -> Instance | None:
+        """Try creating an ad-hoc intersection of the given instances.
+
+        Note that this function does *not* try and create a full-fledged
+        intersection type. Instead, it returns an instance of a new ad-hoc
+        subclass of the given instances.
+
+        This is mainly useful when you need a way of representing some
+        theoretical subclass of the instances the user may be trying to use
+        the generated intersection can serve as a placeholder.
+
+        This function will create a fresh subclass every time you call it,
+        even if you pass in the exact same arguments. So this means calling
+        `self.intersect_intersection([inst_1, inst_2], ctx)` twice will result
+        in instances of two distinct subclasses of inst_1 and inst_2.
+
+        This is by design: we want each ad-hoc intersection to be unique since
+        they're supposed represent some other unknown subclass.
+
+        Returns None if creating the subclass is impossible (e.g. due to
+        MRO errors or incompatible signatures). If we do successfully create
+        a subclass, its TypeInfo will automatically be added to the global scope.
+        """
+        curr_module = self.scope.stack[0]
+        assert isinstance(curr_module, MypyFile)
+
+        # First, retry narrowing while allowing promotions (they are disabled by default
+        # for isinstance() checks, etc). This way we will still type-check branches like
+        # x: complex = 1
+        # if isinstance(x, int):
+        #     ...
+        left, right = instances
+        if is_proper_subtype(left, right, ignore_promotions=False):
+            return left
+        if is_proper_subtype(right, left, ignore_promotions=False):
+            return right
+
+        def _get_base_classes(instances_: tuple[Instance, Instance]) -> list[Instance]:
+            base_classes_ = []
+            for inst in instances_:
+                if inst.type.is_intersection:
+                    expanded = inst.type.bases
+                else:
+                    expanded = [inst]
+
+                for expanded_inst in expanded:
+                    base_classes_.append(expanded_inst)
+            return base_classes_
+
+        def _make_fake_typeinfo_and_full_name(
+            base_classes_: list[Instance], curr_module_: MypyFile
+        ) -> tuple[TypeInfo, str]:
+            names_list = pretty_seq([x.type.name for x in base_classes_], "and")
+            short_name = f"<subclass of {names_list}>"
+            full_name_ = gen_unique_name(short_name, curr_module_.names)
+            cdef, info_ = self.make_fake_typeinfo(
+                curr_module_.fullname, full_name_, short_name, base_classes_
+            )
+            return info_, full_name_
+
+        base_classes = _get_base_classes(instances)
+        # We use the pretty_names_list for error messages but can't
+        # use it for the real name that goes into the symbol table
+        # because it can have dots in it.
+        pretty_names_list = pretty_seq(
+            format_type_distinctly(*base_classes, options=self.options, bare=True), "and"
+        )
+        try:
+            info, full_name = _make_fake_typeinfo_and_full_name(base_classes, curr_module)
+            with self.msg.filter_errors() as local_errors:
+                self.check_multiple_inheritance(info)
+            if local_errors.has_new_errors():
+                # "class A(B, C)" unsafe, now check "class A(C, B)":
+                base_classes = _get_base_classes(instances[::-1])
+                info, full_name = _make_fake_typeinfo_and_full_name(base_classes, curr_module)
+                with self.msg.filter_errors() as local_errors:
+                    self.check_multiple_inheritance(info)
+            info.is_intersection = True
+        except MroError:
+            errors.append((pretty_names_list, "inconsistent method resolution order"))
+            return None
+        if local_errors.has_new_errors():
+            errors.append((pretty_names_list, "incompatible method signatures"))
+            return None
+
+        curr_module.names[full_name] = SymbolTableNode(GDEF, info)
+        return Instance(info, [], extra_attrs=instances[0].extra_attrs or instances[1].extra_attrs)
+
+    def intersect_instance_callable(self, typ: Instance, callable_type: CallableType) -> Instance:
+        """Creates a fake type that represents the intersection of an Instance and a CallableType.
+
+        It operates by creating a bare-minimum dummy TypeInfo that
+        subclasses type and adds a __call__ method matching callable_type.
+        """
+
+        # In order for this to work in incremental mode, the type we generate needs to
+        # have a valid fullname and a corresponding entry in a symbol table. We generate
+        # a unique name inside the symbol table of the current module.
+        cur_module = self.scope.stack[0]
+        assert isinstance(cur_module, MypyFile)
+        gen_name = gen_unique_name(f"<callable subtype of {typ.type.name}>", cur_module.names)
+
+        # Synthesize a fake TypeInfo
+        short_name = format_type_bare(typ, self.options)
+        cdef, info = self.make_fake_typeinfo(cur_module.fullname, gen_name, short_name, [typ])
+
+        # Build up a fake FuncDef so we can populate the symbol table.
+        func_def = FuncDef("__call__", [], Block([]), callable_type)
+        func_def._fullname = cdef.fullname + ".__call__"
+        func_def.info = info
+        info.names["__call__"] = SymbolTableNode(MDEF, func_def)
+
+        cur_module.names[gen_name] = SymbolTableNode(GDEF, info)
+
+        return Instance(info, [], extra_attrs=typ.extra_attrs)
+
+    def make_fake_callable(self, typ: Instance) -> Instance:
+        """Produce a new type that makes type Callable with a generic callable type."""
+
+        fallback = self.named_type("builtins.function")
+        callable_type = CallableType(
+            [AnyType(TypeOfAny.explicit), AnyType(TypeOfAny.explicit)],
+            [nodes.ARG_STAR, nodes.ARG_STAR2],
+            [None, None],
+            ret_type=AnyType(TypeOfAny.explicit),
+            fallback=fallback,
+            is_ellipsis_args=True,
+        )
+
+        return self.intersect_instance_callable(typ, callable_type)
+
+    def partition_by_callable(
+        self, typ: Type, unsound_partition: bool
+    ) -> tuple[list[Type], list[Type]]:
+        """Partitions a type into callable subtypes and uncallable subtypes.
+
+        Thus, given:
+        `callables, uncallables = partition_by_callable(type)`
+
+        If we assert `callable(type)` then `type` has type Union[*callables], and
+        If we assert `not callable(type)` then `type` has type Union[*uncallables]
+
+        If unsound_partition is set, assume that anything that is not
+        clearly callable is in fact not callable. Otherwise we generate a
+        new subtype that *is* callable.
+
+        Guaranteed to not return [], [].
+        """
+        typ = get_proper_type(typ)
+
+        if isinstance(typ, (FunctionLike, TypeType)):
+            return [typ], []
+
+        if isinstance(typ, AnyType):
+            return [typ], [typ]
+
+        if isinstance(typ, NoneType):
+            return [], [typ]
+
+        if isinstance(typ, UnionType):
+            callables = []
+            uncallables = []
+            for subtype in typ.items:
+                # Use unsound_partition when handling unions in order to
+                # allow the expected type discrimination.
+                subcallables, subuncallables = self.partition_by_callable(
+                    subtype, unsound_partition=True
+                )
+                callables.extend(subcallables)
+                uncallables.extend(subuncallables)
+            return callables, uncallables
+
+        if isinstance(typ, TypeVarType):
+            # We could do better probably?
+            # Refine the the type variable's bound as our type in the case that
+            # callable() is true. This unfortunately loses the information that
+            # the type is a type variable in that branch.
+            # This matches what is done for isinstance, but it may be possible to
+            # do better.
+            # If it is possible for the false branch to execute, return the original
+            # type to avoid losing type information.
+            callables, uncallables = self.partition_by_callable(
+                erase_to_union_or_bound(typ), unsound_partition
+            )
+            uncallables = [typ] if uncallables else []
+            return callables, uncallables
+
+        # A TupleType is callable if its fallback is, but needs special handling
+        # when we dummy up a new type.
+        ityp = typ
+        if isinstance(typ, TupleType):
+            ityp = tuple_fallback(typ)
+
+        if isinstance(ityp, Instance):
+            method = ityp.type.get_method("__call__")
+            if method and method.type:
+                callables, uncallables = self.partition_by_callable(
+                    method.type, unsound_partition=False
+                )
+                if callables and not uncallables:
+                    # Only consider the type callable if its __call__ method is
+                    # definitely callable.
+                    return [typ], []
+
+            if not unsound_partition:
+                fake = self.make_fake_callable(ityp)
+                if isinstance(typ, TupleType):
+                    fake.type.tuple_type = TupleType(typ.items, fake)
+                    return [fake.type.tuple_type], [typ]
+                return [fake], [typ]
+
+        if unsound_partition:
+            return [], [typ]
+        else:
+            # We don't know how properly make the type callable.
+            return [typ], [typ]
+
+    def conditional_callable_type_map(
+        self, expr: Expression, current_type: Type | None
+    ) -> tuple[TypeMap, TypeMap]:
+        """Takes in an expression and the current type of the expression.
+
+        Returns a 2-tuple: The first element is a map from the expression to
+        the restricted type if it were callable. The second element is a
+        map from the expression to the type it would hold if it weren't
+        callable.
+        """
+        if not current_type:
+            return {}, {}
+
+        if isinstance(get_proper_type(current_type), AnyType):
+            return {}, {}
+
+        callables, uncallables = self.partition_by_callable(current_type, unsound_partition=False)
+
+        if callables and uncallables:
+            callable_map = {expr: UnionType.make_union(callables)} if callables else None
+            uncallable_map = {expr: UnionType.make_union(uncallables)} if uncallables else None
+            return callable_map, uncallable_map
+
+        elif callables:
+            return {}, None
+
+        return None, {}
+
+    def conditional_types_for_iterable(
+        self, item_type: Type, iterable_type: Type
+    ) -> tuple[Type | None, Type | None]:
+        """
+        Narrows the type of `iterable_type` based on the type of `item_type`.
+        For now, we only support narrowing unions of TypedDicts based on left operand being literal string(s).
+        """
+        if_types: list[Type] = []
+        else_types: list[Type] = []
+
+        iterable_type = get_proper_type(iterable_type)
+        if isinstance(iterable_type, UnionType):
+            possible_iterable_types = get_proper_types(iterable_type.relevant_items())
+        else:
+            possible_iterable_types = [iterable_type]
+
+        item_str_literals = try_getting_str_literals_from_type(item_type)
+
+        for possible_iterable_type in possible_iterable_types:
+            if item_str_literals and isinstance(possible_iterable_type, TypedDictType):
+                for key in item_str_literals:
+                    if key in possible_iterable_type.required_keys:
+                        if_types.append(possible_iterable_type)
+                    elif (
+                        key in possible_iterable_type.items or not possible_iterable_type.is_final
+                    ):
+                        if_types.append(possible_iterable_type)
+                        else_types.append(possible_iterable_type)
+                    else:
+                        else_types.append(possible_iterable_type)
+            else:
+                if_types.append(possible_iterable_type)
+                else_types.append(possible_iterable_type)
+
+        return (
+            UnionType.make_union(if_types) if if_types else None,
+            UnionType.make_union(else_types) if else_types else None,
+        )
+
+    def _is_truthy_type(self, t: ProperType) -> bool:
+        return (
+            (
+                isinstance(t, Instance)
+                and bool(t.type)
+                and not t.type.has_readable_member("__bool__")
+                and not t.type.has_readable_member("__len__")
+                and t.type.fullname != "builtins.object"
+            )
+            or isinstance(t, FunctionLike)
+            or (
+                isinstance(t, UnionType)
+                and all(self._is_truthy_type(t) for t in get_proper_types(t.items))
+            )
+        )
+
+    def _check_for_truthy_type(self, t: Type, expr: Expression) -> None:
+        if not state.strict_optional:
+            return  # if everything can be None, all bets are off
+
+        t = get_proper_type(t)
+        if not self._is_truthy_type(t):
+            return
+
+        def format_expr_type() -> str:
+            typ = format_type(t, self.options)
+            if isinstance(expr, MemberExpr):
+                return f'Member "{expr.name}" has type {typ}'
+            elif isinstance(expr, RefExpr) and expr.fullname:
+                return f'"{expr.fullname}" has type {typ}'
+            elif isinstance(expr, CallExpr):
+                if isinstance(expr.callee, MemberExpr):
+                    return f'"{expr.callee.name}" returns {typ}'
+                elif isinstance(expr.callee, RefExpr) and expr.callee.fullname:
+                    return f'"{expr.callee.fullname}" returns {typ}'
+                return f"Call returns {typ}"
+            else:
+                return f"Expression has type {typ}"
+
+        def get_expr_name() -> str:
+            if isinstance(expr, (NameExpr, MemberExpr)):
+                return f'"{expr.name}"'
+            else:
+                # return type if expr has no name
+                return format_type(t, self.options)
+
+        if isinstance(t, FunctionLike):
+            self.fail(message_registry.FUNCTION_ALWAYS_TRUE.format(get_expr_name()), expr)
+        elif isinstance(t, UnionType):
+            self.fail(message_registry.TYPE_ALWAYS_TRUE_UNIONTYPE.format(format_expr_type()), expr)
+        elif isinstance(t, Instance) and t.type.fullname == "typing.Iterable":
+            _, info = self.make_fake_typeinfo("typing", "Collection", "Collection", [])
+            self.fail(
+                message_registry.ITERABLE_ALWAYS_TRUE.format(
+                    format_expr_type(), format_type(Instance(info, t.args), self.options)
+                ),
+                expr,
+            )
+        else:
+            self.fail(message_registry.TYPE_ALWAYS_TRUE.format(format_expr_type()), expr)
+
+    def find_type_equals_check(
+        self, node: ComparisonExpr, expr_indices: list[int]
+    ) -> tuple[TypeMap, TypeMap]:
+        """Narrow types based on any checks of the type ``type(x) == T``
+
+        Args:
+            node: The node that might contain the comparison
+            expr_indices: The list of indices of expressions in ``node`` that are being
+                compared
+        """
+
+        def is_type_call(expr: CallExpr) -> bool:
+            """Is expr a call to type with one argument?"""
+            return refers_to_fullname(expr.callee, "builtins.type") and len(expr.args) == 1
+
+        # exprs that are being passed into type
+        exprs_in_type_calls: list[Expression] = []
+        # type that is being compared to type(expr)
+        type_being_compared: list[TypeRange] | None = None
+        # whether the type being compared to is final
+        is_final = False
+
+        for index in expr_indices:
+            expr = node.operands[index]
+
+            if isinstance(expr, CallExpr) and is_type_call(expr):
+                exprs_in_type_calls.append(expr.args[0])
+            else:
+                current_type = self.get_isinstance_type(expr)
+                if current_type is None:
+                    continue
+                if type_being_compared is not None:
+                    # It doesn't really make sense to have several types being
+                    # compared to the output of type (like type(x) == int == str)
+                    # because whether that's true is solely dependent on what the
+                    # types being compared are, so we don't try to narrow types any
+                    # further because we can't really get any information about the
+                    # type of x from that check
+                    return {}, {}
+                else:
+                    if isinstance(expr, RefExpr) and isinstance(expr.node, TypeInfo):
+                        is_final = expr.node.is_final
+                    type_being_compared = current_type
+
+        if not exprs_in_type_calls:
+            return {}, {}
+
+        if_maps: list[TypeMap] = []
+        else_maps: list[TypeMap] = []
+        for expr in exprs_in_type_calls:
+            current_if_type, current_else_type = self.conditional_types_with_intersection(
+                self.lookup_type(expr), type_being_compared, expr
+            )
+            current_if_map, current_else_map = conditional_types_to_typemaps(
+                expr, current_if_type, current_else_type
+            )
+            if_maps.append(current_if_map)
+            else_maps.append(current_else_map)
+
+        def combine_maps(list_maps: list[TypeMap]) -> TypeMap:
+            """Combine all typemaps in list_maps into one typemap"""
+            result_map = {}
+            for d in list_maps:
+                if d is not None:
+                    result_map.update(d)
+            return result_map
+
+        if_map = combine_maps(if_maps)
+        # type(x) == T is only true when x has the same type as T, meaning
+        # that it can be false if x is an instance of a subclass of T. That means
+        # we can't do any narrowing in the else case unless T is final, in which
+        # case T can't be subclassed
+        if is_final:
+            else_map = combine_maps(else_maps)
+        else:
+            else_map = {}
+        return if_map, else_map
+
+    def find_isinstance_check(self, node: Expression) -> tuple[TypeMap, TypeMap]:
+        """Find any isinstance checks (within a chain of ands).  Includes
+        implicit and explicit checks for None and calls to callable.
+        Also includes TypeGuard functions.
+
+        Return value is a map of variables to their types if the condition
+        is true and a map of variables to their types if the condition is false.
+
+        If either of the values in the tuple is None, then that particular
+        branch can never occur.
+
+        May return {}, {}.
+        Can return None, None in situations involving NoReturn.
+        """
+        if_map, else_map = self.find_isinstance_check_helper(node)
+        new_if_map = self.propagate_up_typemap_info(if_map)
+        new_else_map = self.propagate_up_typemap_info(else_map)
+        return new_if_map, new_else_map
+
+    def find_isinstance_check_helper(self, node: Expression) -> tuple[TypeMap, TypeMap]:
+        if is_true_literal(node):
+            return {}, None
+        if is_false_literal(node):
+            return None, {}
+
+        if isinstance(node, CallExpr) and len(node.args) != 0:
+            expr = collapse_walrus(node.args[0])
+            if refers_to_fullname(node.callee, "builtins.isinstance"):
+                if len(node.args) != 2:  # the error will be reported elsewhere
+                    return {}, {}
+                if literal(expr) == LITERAL_TYPE:
+                    return conditional_types_to_typemaps(
+                        expr,
+                        *self.conditional_types_with_intersection(
+                            self.lookup_type(expr), self.get_isinstance_type(node.args[1]), expr
+                        ),
+                    )
+            elif refers_to_fullname(node.callee, "builtins.issubclass"):
+                if len(node.args) != 2:  # the error will be reported elsewhere
+                    return {}, {}
+                if literal(expr) == LITERAL_TYPE:
+                    return self.infer_issubclass_maps(node, expr)
+            elif refers_to_fullname(node.callee, "builtins.callable"):
+                if len(node.args) != 1:  # the error will be reported elsewhere
+                    return {}, {}
+                if literal(expr) == LITERAL_TYPE:
+                    vartype = self.lookup_type(expr)
+                    return self.conditional_callable_type_map(expr, vartype)
+            elif refers_to_fullname(node.callee, "builtins.hasattr"):
+                if len(node.args) != 2:  # the error will be reported elsewhere
+                    return {}, {}
+                attr = try_getting_str_literals(node.args[1], self.lookup_type(node.args[1]))
+                if literal(expr) == LITERAL_TYPE and attr and len(attr) == 1:
+                    return self.hasattr_type_maps(expr, self.lookup_type(expr), attr[0])
+            elif isinstance(node.callee, RefExpr):
+                if node.callee.type_guard is not None:
+                    # TODO: Follow *args, **kwargs
+                    if node.arg_kinds[0] != nodes.ARG_POS:
+                        # the first argument might be used as a kwarg
+                        called_type = get_proper_type(self.lookup_type(node.callee))
+                        assert isinstance(called_type, (CallableType, Overloaded))
+
+                        # *assuming* the overloaded function is correct, there's a couple cases:
+                        #  1) The first argument has different names, but is pos-only. We don't
+                        #     care about this case, the argument must be passed positionally.
+                        #  2) The first argument allows keyword reference, therefore must be the
+                        #     same between overloads.
+                        name = called_type.items[0].arg_names[0]
+
+                        if name in node.arg_names:
+                            idx = node.arg_names.index(name)
+                            # we want the idx-th variable to be narrowed
+                            expr = collapse_walrus(node.args[idx])
+                        else:
+                            self.fail(message_registry.TYPE_GUARD_POS_ARG_REQUIRED, node)
+                            return {}, {}
+                    if literal(expr) == LITERAL_TYPE:
+                        # Note: we wrap the target type, so that we can special case later.
+                        # Namely, for isinstance() we use a normal meet, while TypeGuard is
+                        # considered "always right" (i.e. even if the types are not overlapping).
+                        # Also note that a care must be taken to unwrap this back at read places
+                        # where we use this to narrow down declared type.
+                        return {expr: TypeGuardedType(node.callee.type_guard)}, {}
+        elif isinstance(node, ComparisonExpr):
+            # Step 1: Obtain the types of each operand and whether or not we can
+            # narrow their types. (For example, we shouldn't try narrowing the
+            # types of literal string or enum expressions).
+
+            operands = [collapse_walrus(x) for x in node.operands]
+            operand_types = []
+            narrowable_operand_index_to_hash = {}
+            for i, expr in enumerate(operands):
+                if not self.has_type(expr):
+                    return {}, {}
+                expr_type = self.lookup_type(expr)
+                operand_types.append(expr_type)
+
+                if (
+                    literal(expr) == LITERAL_TYPE
+                    and not is_literal_none(expr)
+                    and not self.is_literal_enum(expr)
+                ):
+                    h = literal_hash(expr)
+                    if h is not None:
+                        narrowable_operand_index_to_hash[i] = h
+
+            # Step 2: Group operands chained by either the 'is' or '==' operands
+            # together. For all other operands, we keep them in groups of size 2.
+            # So the expression:
+            #
+            #   x0 == x1 == x2 < x3 < x4 is x5 is x6 is not x7 is not x8
+            #
+            # ...is converted into the simplified operator list:
+            #
+            #  [("==", [0, 1, 2]), ("<", [2, 3]), ("<", [3, 4]),
+            #   ("is", [4, 5, 6]), ("is not", [6, 7]), ("is not", [7, 8])]
+            #
+            # We group identity/equality expressions so we can propagate information
+            # we discover about one operand across the entire chain. We don't bother
+            # handling 'is not' and '!=' chains in a special way: those are very rare
+            # in practice.
+
+            simplified_operator_list = group_comparison_operands(
+                node.pairwise(), narrowable_operand_index_to_hash, {"==", "is"}
+            )
+
+            # Step 3: Analyze each group and infer more precise type maps for each
+            # assignable operand, if possible. We combine these type maps together
+            # in the final step.
+
+            partial_type_maps = []
+            for operator, expr_indices in simplified_operator_list:
+                if operator in {"is", "is not", "==", "!="}:
+                    # is_valid_target:
+                    #   Controls which types we're allowed to narrow exprs to. Note that
+                    #   we cannot use 'is_literal_type_like' in both cases since doing
+                    #   'x = 10000 + 1; x is 10001' is not always True in all Python
+                    #   implementations.
+                    #
+                    # coerce_only_in_literal_context:
+                    #   If true, coerce types into literal types only if one or more of
+                    #   the provided exprs contains an explicit Literal type. This could
+                    #   technically be set to any arbitrary value, but it seems being liberal
+                    #   with narrowing when using 'is' and conservative when using '==' seems
+                    #   to break the least amount of real-world code.
+                    #
+                    # should_narrow_by_identity:
+                    #   Set to 'false' only if the user defines custom __eq__ or __ne__ methods
+                    #   that could cause identity-based narrowing to produce invalid results.
+                    if operator in {"is", "is not"}:
+                        is_valid_target: Callable[[Type], bool] = is_singleton_type
+                        coerce_only_in_literal_context = False
+                        should_narrow_by_identity = True
+                    else:
+
+                        def is_exactly_literal_type(t: Type) -> bool:
+                            return isinstance(get_proper_type(t), LiteralType)
+
+                        def has_no_custom_eq_checks(t: Type) -> bool:
+                            return not custom_special_method(
+                                t, "__eq__", check_all=False
+                            ) and not custom_special_method(t, "__ne__", check_all=False)
+
+                        is_valid_target = is_exactly_literal_type
+                        coerce_only_in_literal_context = True
+
+                        expr_types = [operand_types[i] for i in expr_indices]
+                        should_narrow_by_identity = all(map(has_no_custom_eq_checks, expr_types))
+
+                    if_map: TypeMap = {}
+                    else_map: TypeMap = {}
+                    if should_narrow_by_identity:
+                        if_map, else_map = self.refine_identity_comparison_expression(
+                            operands,
+                            operand_types,
+                            expr_indices,
+                            narrowable_operand_index_to_hash.keys(),
+                            is_valid_target,
+                            coerce_only_in_literal_context,
+                        )
+
+                    # Strictly speaking, we should also skip this check if the objects in the expr
+                    # chain have custom __eq__ or __ne__ methods. But we (maybe optimistically)
+                    # assume nobody would actually create a custom objects that considers itself
+                    # equal to None.
+                    if if_map == {} and else_map == {}:
+                        if_map, else_map = self.refine_away_none_in_comparison(
+                            operands,
+                            operand_types,
+                            expr_indices,
+                            narrowable_operand_index_to_hash.keys(),
+                        )
+
+                    # If we haven't been able to narrow types yet, we might be dealing with a
+                    # explicit type(x) == some_type check
+                    if if_map == {} and else_map == {}:
+                        if_map, else_map = self.find_type_equals_check(node, expr_indices)
+                elif operator in {"in", "not in"}:
+                    assert len(expr_indices) == 2
+                    left_index, right_index = expr_indices
+                    item_type = operand_types[left_index]
+                    iterable_type = operand_types[right_index]
+
+                    if_map, else_map = {}, {}
+
+                    if left_index in narrowable_operand_index_to_hash:
+                        # We only try and narrow away 'None' for now
+                        if is_optional(item_type):
+                            collection_item_type = get_proper_type(
+                                builtin_item_type(iterable_type)
+                            )
+                            if (
+                                collection_item_type is not None
+                                and not is_optional(collection_item_type)
+                                and not (
+                                    isinstance(collection_item_type, Instance)
+                                    and collection_item_type.type.fullname == "builtins.object"
+                                )
+                                and is_overlapping_erased_types(item_type, collection_item_type)
+                            ):
+                                if_map[operands[left_index]] = remove_optional(item_type)
+
+                    if right_index in narrowable_operand_index_to_hash:
+                        if_type, else_type = self.conditional_types_for_iterable(
+                            item_type, iterable_type
+                        )
+                        expr = operands[right_index]
+                        if if_type is None:
+                            if_map = None
+                        else:
+                            if_map[expr] = if_type
+                        if else_type is None:
+                            else_map = None
+                        else:
+                            else_map[expr] = else_type
+
+                else:
+                    if_map = {}
+                    else_map = {}
+
+                if operator in {"is not", "!=", "not in"}:
+                    if_map, else_map = else_map, if_map
+
+                partial_type_maps.append((if_map, else_map))
+
+            return reduce_conditional_maps(partial_type_maps)
+        elif isinstance(node, AssignmentExpr):
+            if_map = {}
+            else_map = {}
+
+            if_assignment_map, else_assignment_map = self.find_isinstance_check(node.target)
+
+            if if_assignment_map is not None:
+                if_map.update(if_assignment_map)
+            if else_assignment_map is not None:
+                else_map.update(else_assignment_map)
+
+            if_condition_map, else_condition_map = self.find_isinstance_check(node.value)
+
+            if if_condition_map is not None:
+                if_map.update(if_condition_map)
+            if else_condition_map is not None:
+                else_map.update(else_condition_map)
+
+            return (
+                (None if if_assignment_map is None or if_condition_map is None else if_map),
+                (None if else_assignment_map is None or else_condition_map is None else else_map),
+            )
+        elif isinstance(node, OpExpr) and node.op == "and":
+            left_if_vars, left_else_vars = self.find_isinstance_check(node.left)
+            right_if_vars, right_else_vars = self.find_isinstance_check(node.right)
+
+            # (e1 and e2) is true if both e1 and e2 are true,
+            # and false if at least one of e1 and e2 is false.
+            return (
+                and_conditional_maps(left_if_vars, right_if_vars),
+                or_conditional_maps(left_else_vars, right_else_vars),
+            )
+        elif isinstance(node, OpExpr) and node.op == "or":
+            left_if_vars, left_else_vars = self.find_isinstance_check(node.left)
+            right_if_vars, right_else_vars = self.find_isinstance_check(node.right)
+
+            # (e1 or e2) is true if at least one of e1 or e2 is true,
+            # and false if both e1 and e2 are false.
+            return (
+                or_conditional_maps(left_if_vars, right_if_vars),
+                and_conditional_maps(left_else_vars, right_else_vars),
+            )
+        elif isinstance(node, UnaryExpr) and node.op == "not":
+            left, right = self.find_isinstance_check(node.expr)
+            return right, left
+
+        # Restrict the type of the variable to True-ish/False-ish in the if and else branches
+        # respectively
+        original_vartype = self.lookup_type(node)
+        self._check_for_truthy_type(original_vartype, node)
+        vartype = try_expanding_sum_type_to_union(original_vartype, "builtins.bool")
+
+        if_type = true_only(vartype)
+        else_type = false_only(vartype)
+        if_map = {node: if_type} if not isinstance(if_type, UninhabitedType) else None
+        else_map = {node: else_type} if not isinstance(else_type, UninhabitedType) else None
+        return if_map, else_map
+
+    def propagate_up_typemap_info(self, new_types: TypeMap) -> TypeMap:
+        """Attempts refining parent expressions of any MemberExpr or IndexExprs in new_types.
+
+        Specifically, this function accepts two mappings of expression to original types:
+        the original mapping (existing_types), and a new mapping (new_types) intended to
+        update the original.
+
+        This function iterates through new_types and attempts to use the information to try
+        refining any parent types that happen to be unions.
+
+        For example, suppose there are two types "A = Tuple[int, int]" and "B = Tuple[str, str]".
+        Next, suppose that 'new_types' specifies the expression 'foo[0]' has a refined type
+        of 'int' and that 'foo' was previously deduced to be of type Union[A, B].
+
+        Then, this function will observe that since A[0] is an int and B[0] is not, the type of
+        'foo' can be further refined from Union[A, B] into just B.
+
+        We perform this kind of "parent narrowing" for member lookup expressions and indexing
+        expressions into tuples, namedtuples, and typeddicts. We repeat this narrowing
+        recursively if the parent is also a "lookup expression". So for example, if we have
+        the expression "foo['bar'].baz[0]", we'd potentially end up refining types for the
+        expressions "foo", "foo['bar']", and "foo['bar'].baz".
+
+        We return the newly refined map. This map is guaranteed to be a superset of 'new_types'.
+        """
+        if new_types is None:
+            return None
+        output_map = {}
+        for expr, expr_type in new_types.items():
+            # The original inferred type should always be present in the output map, of course
+            output_map[expr] = expr_type
+
+            # Next, try using this information to refine the parent types, if applicable.
+            new_mapping = self.refine_parent_types(expr, expr_type)
+            for parent_expr, proposed_parent_type in new_mapping.items():
+                # We don't try inferring anything if we've already inferred something for
+                # the parent expression.
+                # TODO: Consider picking the narrower type instead of always discarding this?
+                if parent_expr in new_types:
+                    continue
+                output_map[parent_expr] = proposed_parent_type
+        return output_map
+
+    def refine_parent_types(self, expr: Expression, expr_type: Type) -> Mapping[Expression, Type]:
+        """Checks if the given expr is a 'lookup operation' into a union and iteratively refines
+        the parent types based on the 'expr_type'.
+
+        For example, if 'expr' is an expression like 'a.b.c.d', we'll potentially return refined
+        types for expressions 'a', 'a.b', and 'a.b.c'.
+
+        For more details about what a 'lookup operation' is and how we use the expr_type to refine
+        the parent types of lookup_expr, see the docstring in 'propagate_up_typemap_info'.
+        """
+        output: dict[Expression, Type] = {}
+
+        # Note: parent_expr and parent_type are progressively refined as we crawl up the
+        # parent lookup chain.
+        while True:
+            # First, check if this expression is one that's attempting to
+            # "lookup" some key in the parent type. If so, save the parent type
+            # and create function that will try replaying the same lookup
+            # operation against arbitrary types.
+            if isinstance(expr, MemberExpr):
+                parent_expr = collapse_walrus(expr.expr)
+                parent_type = self.lookup_type_or_none(parent_expr)
+                member_name = expr.name
+
+                def replay_lookup(new_parent_type: ProperType) -> Type | None:
+                    with self.msg.filter_errors() as w:
+                        member_type = analyze_member_access(
+                            name=member_name,
+                            typ=new_parent_type,
+                            context=parent_expr,
+                            is_lvalue=False,
+                            is_super=False,
+                            is_operator=False,
+                            msg=self.msg,
+                            original_type=new_parent_type,
+                            chk=self,
+                            in_literal_context=False,
+                        )
+                    if w.has_new_errors():
+                        return None
+                    else:
+                        return member_type
+
+            elif isinstance(expr, IndexExpr):
+                parent_expr = collapse_walrus(expr.base)
+                parent_type = self.lookup_type_or_none(parent_expr)
+
+                index_type = self.lookup_type_or_none(expr.index)
+                if index_type is None:
+                    return output
+
+                str_literals = try_getting_str_literals_from_type(index_type)
+                if str_literals is not None:
+                    # Refactoring these two indexing replay functions is surprisingly
+                    # tricky -- see https://github.com/python/mypy/pull/7917, which
+                    # was blocked by https://github.com/mypyc/mypyc/issues/586
+                    def replay_lookup(new_parent_type: ProperType) -> Type | None:
+                        if not isinstance(new_parent_type, TypedDictType):
+                            return None
+                        try:
+                            assert str_literals is not None
+                            member_types = [new_parent_type.items[key] for key in str_literals]
+                        except KeyError:
+                            return None
+                        return make_simplified_union(member_types)
+
+                else:
+                    int_literals = try_getting_int_literals_from_type(index_type)
+                    if int_literals is not None:
+
+                        def replay_lookup(new_parent_type: ProperType) -> Type | None:
+                            if not isinstance(new_parent_type, TupleType):
+                                return None
+                            try:
+                                assert int_literals is not None
+                                member_types = [new_parent_type.items[key] for key in int_literals]
+                            except IndexError:
+                                return None
+                            return make_simplified_union(member_types)
+
+                    else:
+                        return output
+            else:
+                return output
+
+            # If we somehow didn't previously derive the parent type, abort completely
+            # with what we have so far: something went wrong at an earlier stage.
+            if parent_type is None:
+                return output
+
+            # We currently only try refining the parent type if it's a Union.
+            # If not, there's no point in trying to refine any further parents
+            # since we have no further information we can use to refine the lookup
+            # chain, so we end early as an optimization.
+            parent_type = get_proper_type(parent_type)
+            if not isinstance(parent_type, UnionType):
+                return output
+
+            # Take each element in the parent union and replay the original lookup procedure
+            # to figure out which parents are compatible.
+            new_parent_types = []
+            for item in flatten_nested_unions(parent_type.items):
+                member_type = replay_lookup(get_proper_type(item))
+                if member_type is None:
+                    # We were unable to obtain the member type. So, we give up on refining this
+                    # parent type entirely and abort.
+                    return output
+
+                if is_overlapping_types(member_type, expr_type):
+                    new_parent_types.append(item)
+
+            # If none of the parent types overlap (if we derived an empty union), something
+            # went wrong. We should never hit this case, but deriving the uninhabited type or
+            # reporting an error both seem unhelpful. So we abort.
+            if not new_parent_types:
+                return output
+
+            expr = parent_expr
+            expr_type = output[parent_expr] = make_simplified_union(new_parent_types)
+
+    def refine_identity_comparison_expression(
+        self,
+        operands: list[Expression],
+        operand_types: list[Type],
+        chain_indices: list[int],
+        narrowable_operand_indices: AbstractSet[int],
+        is_valid_target: Callable[[ProperType], bool],
+        coerce_only_in_literal_context: bool,
+    ) -> tuple[TypeMap, TypeMap]:
+        """Produce conditional type maps refining expressions by an identity/equality comparison.
+
+        The 'operands' and 'operand_types' lists should be the full list of operands used
+        in the overall comparison expression. The 'chain_indices' list is the list of indices
+        actually used within this identity comparison chain.
+
+        So if we have the expression:
+
+            a <= b is c is d <= e
+
+        ...then 'operands' and 'operand_types' would be lists of length 5 and 'chain_indices'
+        would be the list [1, 2, 3].
+
+        The 'narrowable_operand_indices' parameter is the set of all indices we are allowed
+        to refine the types of: that is, all operands that will potentially be a part of
+        the output TypeMaps.
+
+        Although this function could theoretically try setting the types of the operands
+        in the chains to the meet, doing that causes too many issues in real-world code.
+        Instead, we use 'is_valid_target' to identify which of the given chain types
+        we could plausibly use as the refined type for the expressions in the chain.
+
+        Similarly, 'coerce_only_in_literal_context' controls whether we should try coercing
+        expressions in the chain to a Literal type. Performing this coercion is sometimes
+        too aggressive of a narrowing, depending on context.
+        """
+        should_coerce = True
+        if coerce_only_in_literal_context:
+
+            def should_coerce_inner(typ: Type) -> bool:
+                typ = get_proper_type(typ)
+                return is_literal_type_like(typ) or (
+                    isinstance(typ, Instance) and typ.type.is_enum
+                )
+
+            should_coerce = any(should_coerce_inner(operand_types[i]) for i in chain_indices)
+
+        target: Type | None = None
+        possible_target_indices = []
+        for i in chain_indices:
+            expr_type = operand_types[i]
+            if should_coerce:
+                expr_type = coerce_to_literal(expr_type)
+            if not is_valid_target(get_proper_type(expr_type)):
+                continue
+            if target and not is_same_type(target, expr_type):
+                # We have multiple disjoint target types. So the 'if' branch
+                # must be unreachable.
+                return None, {}
+            target = expr_type
+            possible_target_indices.append(i)
+
+        # There's nothing we can currently infer if none of the operands are valid targets,
+        # so we end early and infer nothing.
+        if target is None:
+            return {}, {}
+
+        # If possible, use an unassignable expression as the target.
+        # We skip refining the type of the target below, so ideally we'd
+        # want to pick an expression we were going to skip anyways.
+        singleton_index = -1
+        for i in possible_target_indices:
+            if i not in narrowable_operand_indices:
+                singleton_index = i
+
+        # But if none of the possible singletons are unassignable ones, we give up
+        # and arbitrarily pick the last item, mostly because other parts of the
+        # type narrowing logic bias towards picking the rightmost item and it'd be
+        # nice to stay consistent.
+        #
+        # That said, it shouldn't matter which index we pick. For example, suppose we
+        # have this if statement, where 'x' and 'y' both have singleton types:
+        #
+        #     if x is y:
+        #         reveal_type(x)
+        #         reveal_type(y)
+        #     else:
+        #         reveal_type(x)
+        #         reveal_type(y)
+        #
+        # At this point, 'x' and 'y' *must* have the same singleton type: we would have
+        # ended early in the first for-loop in this function if they weren't.
+        #
+        # So, we should always get the same result in the 'if' case no matter which
+        # index we pick. And while we do end up getting different results in the 'else'
+        # case depending on the index (e.g. if we pick 'y', then its type stays the same
+        # while 'x' is narrowed to '<uninhabited>'), this distinction is also moot: mypy
+        # currently will just mark the whole branch as unreachable if either operand is
+        # narrowed to <uninhabited>.
+        if singleton_index == -1:
+            singleton_index = possible_target_indices[-1]
+
+        sum_type_name = None
+        target = get_proper_type(target)
+        if isinstance(target, LiteralType) and (
+            target.is_enum_literal() or isinstance(target.value, bool)
+        ):
+            sum_type_name = target.fallback.type.fullname
+
+        target_type = [TypeRange(target, is_upper_bound=False)]
+
+        partial_type_maps = []
+        for i in chain_indices:
+            # If we try refining a type against itself, conditional_type_map
+            # will end up assuming that the 'else' branch is unreachable. This is
+            # typically not what we want: generally the user will intend for the
+            # target type to be some fixed 'sentinel' value and will want to refine
+            # the other exprs against this one instead.
+            if i == singleton_index:
+                continue
+
+            # Naturally, we can't refine operands which are not permitted to be refined.
+            if i not in narrowable_operand_indices:
+                continue
+
+            expr = operands[i]
+            expr_type = coerce_to_literal(operand_types[i])
+
+            if sum_type_name is not None:
+                expr_type = try_expanding_sum_type_to_union(expr_type, sum_type_name)
+
+            # We intentionally use 'conditional_types' directly here instead of
+            # 'self.conditional_types_with_intersection': we only compute ad-hoc
+            # intersections when working with pure instances.
+            types = conditional_types(expr_type, target_type)
+            partial_type_maps.append(conditional_types_to_typemaps(expr, *types))
+
+        return reduce_conditional_maps(partial_type_maps)
+
+    def refine_away_none_in_comparison(
+        self,
+        operands: list[Expression],
+        operand_types: list[Type],
+        chain_indices: list[int],
+        narrowable_operand_indices: AbstractSet[int],
+    ) -> tuple[TypeMap, TypeMap]:
+        """Produces conditional type maps refining away None in an identity/equality chain.
+
+        For more details about what the different arguments mean, see the
+        docstring of 'refine_identity_comparison_expression' up above.
+        """
+        non_optional_types = []
+        for i in chain_indices:
+            typ = operand_types[i]
+            if not is_optional(typ):
+                non_optional_types.append(typ)
+
+        # Make sure we have a mixture of optional and non-optional types.
+        if len(non_optional_types) == 0 or len(non_optional_types) == len(chain_indices):
+            return {}, {}
+
+        if_map = {}
+        for i in narrowable_operand_indices:
+            expr_type = operand_types[i]
+            if not is_optional(expr_type):
+                continue
+            if any(is_overlapping_erased_types(expr_type, t) for t in non_optional_types):
+                if_map[operands[i]] = remove_optional(expr_type)
+
+        return if_map, {}
+
+    #
+    # Helpers
+    #
+    @overload
+    def check_subtype(
+        self,
+        subtype: Type,
+        supertype: Type,
+        context: Context,
+        msg: str,
+        subtype_label: str | None = None,
+        supertype_label: str | None = None,
+        *,
+        notes: list[str] | None = None,
+        code: ErrorCode | None = None,
+        outer_context: Context | None = None,
+    ) -> bool:
+        ...
+
+    @overload
+    def check_subtype(
+        self,
+        subtype: Type,
+        supertype: Type,
+        context: Context,
+        msg: ErrorMessage,
+        subtype_label: str | None = None,
+        supertype_label: str | None = None,
+        *,
+        notes: list[str] | None = None,
+        outer_context: Context | None = None,
+    ) -> bool:
+        ...
+
+    def check_subtype(
+        self,
+        subtype: Type,
+        supertype: Type,
+        context: Context,
+        msg: str | ErrorMessage,
+        subtype_label: str | None = None,
+        supertype_label: str | None = None,
+        *,
+        notes: list[str] | None = None,
+        code: ErrorCode | None = None,
+        outer_context: Context | None = None,
+    ) -> bool:
+        """Generate an error if the subtype is not compatible with supertype."""
+        if is_subtype(subtype, supertype, options=self.options):
+            return True
+
+        if isinstance(msg, str):
+            msg = ErrorMessage(msg, code=code)
+
+        if self.msg.prefer_simple_messages():
+            self.fail(msg, context)  # Fast path -- skip all fancy logic
+            return False
+
+        orig_subtype = subtype
+        subtype = get_proper_type(subtype)
+        orig_supertype = supertype
+        supertype = get_proper_type(supertype)
+        if self.msg.try_report_long_tuple_assignment_error(
+            subtype, supertype, context, msg, subtype_label, supertype_label
+        ):
+            return False
+        extra_info: list[str] = []
+        note_msg = ""
+        notes = notes or []
+        if subtype_label is not None or supertype_label is not None:
+            subtype_str, supertype_str = format_type_distinctly(
+                orig_subtype, orig_supertype, options=self.options
+            )
+            if subtype_label is not None:
+                extra_info.append(subtype_label + " " + subtype_str)
+            if supertype_label is not None:
+                extra_info.append(supertype_label + " " + supertype_str)
+            note_msg = make_inferred_type_note(
+                outer_context or context, subtype, supertype, supertype_str
+            )
+            if isinstance(subtype, Instance) and isinstance(supertype, Instance):
+                notes = append_invariance_notes(notes, subtype, supertype)
+        if extra_info:
+            msg = msg.with_additional_msg(" (" + ", ".join(extra_info) + ")")
+
+        self.fail(msg, context)
+        for note in notes:
+            self.msg.note(note, context, code=msg.code)
+        if note_msg:
+            self.note(note_msg, context, code=msg.code)
+        self.msg.maybe_note_concatenate_pos_args(subtype, supertype, context, code=msg.code)
+        if (
+            isinstance(supertype, Instance)
+            and supertype.type.is_protocol
+            and isinstance(subtype, (CallableType, Instance, TupleType, TypedDictType))
+        ):
+            self.msg.report_protocol_problems(subtype, supertype, context, code=msg.code)
+        if isinstance(supertype, CallableType) and isinstance(subtype, Instance):
+            call = find_member("__call__", subtype, subtype, is_operator=True)
+            if call:
+                self.msg.note_call(subtype, call, context, code=msg.code)
+        if isinstance(subtype, (CallableType, Overloaded)) and isinstance(supertype, Instance):
+            if supertype.type.is_protocol and "__call__" in supertype.type.protocol_members:
+                call = find_member("__call__", supertype, subtype, is_operator=True)
+                assert call is not None
+                if not is_subtype(subtype, call, options=self.options):
+                    self.msg.note_call(supertype, call, context, code=msg.code)
+        self.check_possible_missing_await(subtype, supertype, context)
+        return False
+
+    def get_precise_awaitable_type(self, typ: Type, local_errors: ErrorWatcher) -> Type | None:
+        """If type implements Awaitable[X] with non-Any X, return X.
+
+        In all other cases return None. This method must be called in context
+        of local_errors.
+        """
+        if isinstance(get_proper_type(typ), PartialType):
+            # Partial types are special, ignore them here.
+            return None
+        try:
+            aw_type = self.expr_checker.check_awaitable_expr(
+                typ, Context(), "", ignore_binder=True
+            )
+        except KeyError:
+            # This is a hack to speed up tests by not including Awaitable in all typing stubs.
+            return None
+        if local_errors.has_new_errors():
+            return None
+        if isinstance(get_proper_type(aw_type), (AnyType, UnboundType)):
+            return None
+        return aw_type
+
+    @contextmanager
+    def checking_await_set(self) -> Iterator[None]:
+        self.checking_missing_await = True
+        try:
+            yield
+        finally:
+            self.checking_missing_await = False
+
+    def check_possible_missing_await(
+        self, subtype: Type, supertype: Type, context: Context
+    ) -> None:
+        """Check if the given type becomes a subtype when awaited."""
+        if self.checking_missing_await:
+            # Avoid infinite recursion.
+            return
+        with self.checking_await_set(), self.msg.filter_errors() as local_errors:
+            aw_type = self.get_precise_awaitable_type(subtype, local_errors)
+            if aw_type is None:
+                return
+            if not self.check_subtype(
+                aw_type, supertype, context, msg=message_registry.INCOMPATIBLE_TYPES
+            ):
+                return
+        self.msg.possible_missing_await(context)
+
+    def contains_none(self, t: Type) -> bool:
+        t = get_proper_type(t)
+        return (
+            isinstance(t, NoneType)
+            or (isinstance(t, UnionType) and any(self.contains_none(ut) for ut in t.items))
+            or (isinstance(t, TupleType) and any(self.contains_none(tt) for tt in t.items))
+            or (
+                isinstance(t, Instance)
+                and bool(t.args)
+                and any(self.contains_none(it) for it in t.args)
+            )
+        )
+
+    def named_type(self, name: str) -> Instance:
+        """Return an instance type with given name and implicit Any type args.
+
+        For example, named_type('builtins.object') produces the 'object' type.
+        """
+        # Assume that the name refers to a type.
+        sym = self.lookup_qualified(name)
+        node = sym.node
+        if isinstance(node, TypeAlias):
+            assert isinstance(node.target, Instance)  # type: ignore[misc]
+            node = node.target.type
+        assert isinstance(node, TypeInfo)
+        any_type = AnyType(TypeOfAny.from_omitted_generics)
+        return Instance(node, [any_type] * len(node.defn.type_vars))
+
+    def named_generic_type(self, name: str, args: list[Type]) -> Instance:
+        """Return an instance with the given name and type arguments.
+
+        Assume that the number of arguments is correct.  Assume that
+        the name refers to a compatible generic type.
+        """
+        info = self.lookup_typeinfo(name)
+        args = [remove_instance_last_known_values(arg) for arg in args]
+        # TODO: assert len(args) == len(info.defn.type_vars)
+        return Instance(info, args)
+
+    def lookup_typeinfo(self, fullname: str) -> TypeInfo:
+        # Assume that the name refers to a class.
+        sym = self.lookup_qualified(fullname)
+        node = sym.node
+        assert isinstance(node, TypeInfo)
+        return node
+
+    def type_type(self) -> Instance:
+        """Return instance type 'type'."""
+        return self.named_type("builtins.type")
+
+    def str_type(self) -> Instance:
+        """Return instance type 'str'."""
+        return self.named_type("builtins.str")
+
+    def store_type(self, node: Expression, typ: Type) -> None:
+        """Store the type of a node in the type map."""
+        self._type_maps[-1][node] = typ
+
+    def has_type(self, node: Expression) -> bool:
+        return any(node in m for m in reversed(self._type_maps))
+
+    def lookup_type_or_none(self, node: Expression) -> Type | None:
+        for m in reversed(self._type_maps):
+            if node in m:
+                return m[node]
+        return None
+
+    def lookup_type(self, node: Expression) -> Type:
+        for m in reversed(self._type_maps):
+            t = m.get(node)
+            if t is not None:
+                return t
+        raise KeyError(node)
+
+    def store_types(self, d: dict[Expression, Type]) -> None:
+        self._type_maps[-1].update(d)
+
+    @contextmanager
+    def local_type_map(self) -> Iterator[dict[Expression, Type]]:
+        """Store inferred types into a temporary type map (returned).
+
+        This can be used to perform type checking "experiments" without
+        affecting exported types (which are used by mypyc).
+        """
+        temp_type_map: dict[Expression, Type] = {}
+        self._type_maps.append(temp_type_map)
+        yield temp_type_map
+        self._type_maps.pop()
+
+    def in_checked_function(self) -> bool:
+        """Should we type-check the current function?
+
+        - Yes if --check-untyped-defs is set.
+        - Yes outside functions.
+        - Yes in annotated functions.
+        - No otherwise.
+        """
+        return (
+            self.options.check_untyped_defs or not self.dynamic_funcs or not self.dynamic_funcs[-1]
+        )
+
+    def lookup(self, name: str) -> SymbolTableNode:
+        """Look up a definition from the symbol table with the given name."""
+        if name in self.globals:
+            return self.globals[name]
+        else:
+            b = self.globals.get("__builtins__", None)
+            if b:
+                assert isinstance(b.node, MypyFile)
+                table = b.node.names
+                if name in table:
+                    return table[name]
+            raise KeyError(f"Failed lookup: {name}")
+
+    def lookup_qualified(self, name: str) -> SymbolTableNode:
+        if "." not in name:
+            return self.lookup(name)
+        else:
+            parts = name.split(".")
+            n = self.modules[parts[0]]
+            for i in range(1, len(parts) - 1):
+                sym = n.names.get(parts[i])
+                assert sym is not None, "Internal error: attempted lookup of unknown name"
+                assert isinstance(sym.node, MypyFile)
+                n = sym.node
+            last = parts[-1]
+            if last in n.names:
+                return n.names[last]
+            elif len(parts) == 2 and parts[0] in ("builtins", "typing"):
+                fullname = ".".join(parts)
+                if fullname in SUGGESTED_TEST_FIXTURES:
+                    suggestion = ", e.g. add '[{} fixtures/{}]' to your test".format(
+                        parts[0], SUGGESTED_TEST_FIXTURES[fullname]
+                    )
+                else:
+                    suggestion = ""
+                raise KeyError(
+                    "Could not find builtin symbol '{}' (If you are running a "
+                    "test case, use a fixture that "
+                    "defines this symbol{})".format(last, suggestion)
+                )
+            else:
+                msg = "Failed qualified lookup: '{}' (fullname = '{}')."
+                raise KeyError(msg.format(last, name))
+
+    @contextmanager
+    def enter_partial_types(
+        self, *, is_function: bool = False, is_class: bool = False
+    ) -> Iterator[None]:
+        """Enter a new scope for collecting partial types.
+
+        Also report errors for (some) variables which still have partial
+        types, i.e. we couldn't infer a complete type.
+        """
+        is_local = (self.partial_types and self.partial_types[-1].is_local) or is_function
+        self.partial_types.append(PartialTypeScope({}, is_function, is_local))
+        yield
+
+        # Don't complain about not being able to infer partials if it is
+        # at the toplevel (with allow_untyped_globals) or if it is in an
+        # untyped function being checked with check_untyped_defs.
+        permissive = (self.options.allow_untyped_globals and not is_local) or (
+            self.options.check_untyped_defs and self.dynamic_funcs and self.dynamic_funcs[-1]
+        )
+
+        partial_types, _, _ = self.partial_types.pop()
+        if not self.current_node_deferred:
+            for var, context in partial_types.items():
+                # If we require local partial types, there are a few exceptions where
+                # we fall back to inferring just "None" as the type from a None initializer:
+                #
+                # 1. If all happens within a single function this is acceptable, since only
+                #    the topmost function is a separate target in fine-grained incremental mode.
+                #    We primarily want to avoid "splitting" partial types across targets.
+                #
+                # 2. A None initializer in the class body if the attribute is defined in a base
+                #    class is fine, since the attribute is already defined and it's currently okay
+                #    to vary the type of an attribute covariantly. The None type will still be
+                #    checked for compatibility with base classes elsewhere. Without this exception
+                #    mypy could require an annotation for an attribute that already has been
+                #    declared in a base class, which would be bad.
+                allow_none = (
+                    not self.options.local_partial_types
+                    or is_function
+                    or (is_class and self.is_defined_in_base_class(var))
+                )
+                if (
+                    allow_none
+                    and isinstance(var.type, PartialType)
+                    and var.type.type is None
+                    and not permissive
+                ):
+                    var.type = NoneType()
+                else:
+                    if var not in self.partial_reported and not permissive:
+                        self.msg.need_annotation_for_var(var, context, self.options.python_version)
+                        self.partial_reported.add(var)
+                    if var.type:
+                        fixed = fixup_partial_type(var.type)
+                        var.invalid_partial_type = fixed != var.type
+                        var.type = fixed
+
+    def handle_partial_var_type(
+        self, typ: PartialType, is_lvalue: bool, node: Var, context: Context
+    ) -> Type:
+        """Handle a reference to a partial type through a var.
+
+        (Used by checkexpr and checkmember.)
+        """
+        in_scope, is_local, partial_types = self.find_partial_types_in_all_scopes(node)
+        if typ.type is None and in_scope:
+            # 'None' partial type. It has a well-defined type. In an lvalue context
+            # we want to preserve the knowledge of it being a partial type.
+            if not is_lvalue:
+                return NoneType()
+            else:
+                return typ
+        else:
+            if partial_types is not None and not self.current_node_deferred:
+                if in_scope:
+                    context = partial_types[node]
+                    if is_local or not self.options.allow_untyped_globals:
+                        self.msg.need_annotation_for_var(
+                            node, context, self.options.python_version
+                        )
+                        self.partial_reported.add(node)
+                else:
+                    # Defer the node -- we might get a better type in the outer scope
+                    self.handle_cannot_determine_type(node.name, context)
+            return fixup_partial_type(typ)
+
+    def is_defined_in_base_class(self, var: Var) -> bool:
+        if not var.info:
+            return False
+        return var.info.fallback_to_any or any(
+            base.get(var.name) is not None for base in var.info.mro[1:]
+        )
+
+    def find_partial_types(self, var: Var) -> dict[Var, Context] | None:
+        """Look for an active partial type scope containing variable.
+
+        A scope is active if assignments in the current context can refine a partial
+        type originally defined in the scope. This is affected by the local_partial_types
+        configuration option.
+        """
+        in_scope, _, partial_types = self.find_partial_types_in_all_scopes(var)
+        if in_scope:
+            return partial_types
+        return None
+
+    def find_partial_types_in_all_scopes(
+        self, var: Var
+    ) -> tuple[bool, bool, dict[Var, Context] | None]:
+        """Look for partial type scope containing variable.
+
+        Return tuple (is the scope active, is the scope a local scope, scope).
+        """
+        for scope in reversed(self.partial_types):
+            if var in scope.map:
+                # All scopes within the outermost function are active. Scopes out of
+                # the outermost function are inactive to allow local reasoning (important
+                # for fine-grained incremental mode).
+                disallow_other_scopes = self.options.local_partial_types
+
+                if isinstance(var.type, PartialType) and var.type.type is not None and var.info:
+                    # This is an ugly hack to make partial generic self attributes behave
+                    # as if --local-partial-types is always on (because it used to be like this).
+                    disallow_other_scopes = True
+
+                scope_active = (
+                    not disallow_other_scopes or scope.is_local == self.partial_types[-1].is_local
+                )
+                return scope_active, scope.is_local, scope.map
+        return False, False, None
+
+    def temp_node(self, t: Type, context: Context | None = None) -> TempNode:
+        """Create a temporary node with the given, fixed type."""
+        return TempNode(t, context=context)
+
+    def fail(
+        self, msg: str | ErrorMessage, context: Context, *, code: ErrorCode | None = None
+    ) -> None:
+        """Produce an error message."""
+        if isinstance(msg, ErrorMessage):
+            self.msg.fail(msg.value, context, code=msg.code)
+            return
+        self.msg.fail(msg, context, code=code)
+
+    def note(
+        self,
+        msg: str | ErrorMessage,
+        context: Context,
+        offset: int = 0,
+        *,
+        code: ErrorCode | None = None,
+    ) -> None:
+        """Produce a note."""
+        if isinstance(msg, ErrorMessage):
+            self.msg.note(msg.value, context, code=msg.code)
+            return
+        self.msg.note(msg, context, offset=offset, code=code)
+
+    def iterable_item_type(
+        self, it: Instance | CallableType | TypeType | Overloaded, context: Context
+    ) -> Type:
+        if isinstance(it, Instance):
+            iterable = map_instance_to_supertype(it, self.lookup_typeinfo("typing.Iterable"))
+            item_type = iterable.args[0]
+            if not isinstance(get_proper_type(item_type), AnyType):
+                # This relies on 'map_instance_to_supertype' returning 'Iterable[Any]'
+                # in case there is no explicit base class.
+                return item_type
+        # Try also structural typing.
+        return self.analyze_iterable_item_type_without_expression(it, context)[1]
+
+    def function_type(self, func: FuncBase) -> FunctionLike:
+        return function_type(func, self.named_type("builtins.function"))
+
+    def push_type_map(self, type_map: TypeMap) -> None:
+        if type_map is None:
+            self.binder.unreachable()
+        else:
+            for expr, type in type_map.items():
+                self.binder.put(expr, type)
+
+    def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeMap, TypeMap]:
+        """Infer type restrictions for an expression in issubclass call."""
+        vartype = self.lookup_type(expr)
+        type = self.get_isinstance_type(node.args[1])
+        if isinstance(vartype, TypeVarType):
+            vartype = vartype.upper_bound
+        vartype = get_proper_type(vartype)
+        if isinstance(vartype, UnionType):
+            union_list = []
+            for t in get_proper_types(vartype.items):
+                if isinstance(t, TypeType):
+                    union_list.append(t.item)
+                else:
+                    # This is an error that should be reported earlier
+                    # if we reach here, we refuse to do any type inference.
+                    return {}, {}
+            vartype = UnionType(union_list)
+        elif isinstance(vartype, TypeType):
+            vartype = vartype.item
+        elif isinstance(vartype, Instance) and vartype.type.is_metaclass():
+            vartype = self.named_type("builtins.object")
+        else:
+            # Any other object whose type we don't know precisely
+            # for example, Any or a custom metaclass.
+            return {}, {}  # unknown type
+        yes_type, no_type = self.conditional_types_with_intersection(vartype, type, expr)
+        yes_map, no_map = conditional_types_to_typemaps(expr, yes_type, no_type)
+        yes_map, no_map = map(convert_to_typetype, (yes_map, no_map))
+        return yes_map, no_map
+
+    @overload
+    def conditional_types_with_intersection(
+        self,
+        expr_type: Type,
+        type_ranges: list[TypeRange] | None,
+        ctx: Context,
+        default: None = None,
+    ) -> tuple[Type | None, Type | None]:
+        ...
+
+    @overload
+    def conditional_types_with_intersection(
+        self, expr_type: Type, type_ranges: list[TypeRange] | None, ctx: Context, default: Type
+    ) -> tuple[Type, Type]:
+        ...
+
+    def conditional_types_with_intersection(
+        self,
+        expr_type: Type,
+        type_ranges: list[TypeRange] | None,
+        ctx: Context,
+        default: Type | None = None,
+    ) -> tuple[Type | None, Type | None]:
+        initial_types = conditional_types(expr_type, type_ranges, default)
+        # For some reason, doing "yes_map, no_map = conditional_types_to_typemaps(...)"
+        # doesn't work: mypyc will decide that 'yes_map' is of type None if we try.
+        yes_type: Type | None = initial_types[0]
+        no_type: Type | None = initial_types[1]
+
+        if not isinstance(get_proper_type(yes_type), UninhabitedType) or type_ranges is None:
+            return yes_type, no_type
+
+        # If conditional_types was unable to successfully narrow the expr_type
+        # using the type_ranges and concluded if-branch is unreachable, we try
+        # computing it again using a different algorithm that tries to generate
+        # an ad-hoc intersection between the expr_type and the type_ranges.
+        proper_type = get_proper_type(expr_type)
+        if isinstance(proper_type, UnionType):
+            possible_expr_types = get_proper_types(proper_type.relevant_items())
+        else:
+            possible_expr_types = [proper_type]
+
+        possible_target_types = []
+        for tr in type_ranges:
+            item = get_proper_type(tr.item)
+            if not isinstance(item, Instance) or tr.is_upper_bound:
+                return yes_type, no_type
+            possible_target_types.append(item)
+
+        out = []
+        errors: list[tuple[str, str]] = []
+        for v in possible_expr_types:
+            if not isinstance(v, Instance):
+                return yes_type, no_type
+            for t in possible_target_types:
+                intersection = self.intersect_instances((v, t), errors)
+                if intersection is None:
+                    continue
+                out.append(intersection)
+        if not out:
+            # Only report errors if no element in the union worked.
+            if self.should_report_unreachable_issues():
+                for types, reason in errors:
+                    self.msg.impossible_intersection(types, reason, ctx)
+            return UninhabitedType(), expr_type
+        new_yes_type = make_simplified_union(out)
+        return new_yes_type, expr_type
+
+    def is_writable_attribute(self, node: Node) -> bool:
+        """Check if an attribute is writable"""
+        if isinstance(node, Var):
+            if node.is_property and not node.is_settable_property:
+                return False
+            return True
+        elif isinstance(node, OverloadedFuncDef) and node.is_property:
+            first_item = node.items[0]
+            assert isinstance(first_item, Decorator)
+            return first_item.var.is_settable_property
+        return False
+
+    def get_isinstance_type(self, expr: Expression) -> list[TypeRange] | None:
+        if isinstance(expr, OpExpr) and expr.op == "|":
+            left = self.get_isinstance_type(expr.left)
+            right = self.get_isinstance_type(expr.right)
+            if left is None or right is None:
+                return None
+            return left + right
+        all_types = get_proper_types(flatten_types(self.lookup_type(expr)))
+        types: list[TypeRange] = []
+        for typ in all_types:
+            if isinstance(typ, FunctionLike) and typ.is_type_obj():
+                # Type variables may be present -- erase them, which is the best
+                # we can do (outside disallowing them here).
+                erased_type = erase_typevars(typ.items[0].ret_type)
+                types.append(TypeRange(erased_type, is_upper_bound=False))
+            elif isinstance(typ, TypeType):
+                # Type[A] means "any type that is a subtype of A" rather than "precisely type A"
+                # we indicate this by setting is_upper_bound flag
+                types.append(TypeRange(typ.item, is_upper_bound=True))
+            elif isinstance(typ, Instance) and typ.type.fullname == "builtins.type":
+                object_type = Instance(typ.type.mro[-1], [])
+                types.append(TypeRange(object_type, is_upper_bound=True))
+            elif isinstance(typ, AnyType):
+                types.append(TypeRange(typ, is_upper_bound=False))
+            else:  # we didn't see an actual type, but rather a variable with unknown value
+                return None
+        if not types:
+            # this can happen if someone has empty tuple as 2nd argument to isinstance
+            # strictly speaking, we should return UninhabitedType but for simplicity we will simply
+            # refuse to do any type inference for now
+            return None
+        return types
+
+    def is_literal_enum(self, n: Expression) -> bool:
+        """Returns true if this expression (with the given type context) is an Enum literal.
+
+        For example, if we had an enum:
+
+            class Foo(Enum):
+                A = 1
+                B = 2
+
+        ...and if the expression 'Foo' referred to that enum within the current type context,
+        then the expression 'Foo.A' would be a literal enum. However, if we did 'a = Foo.A',
+        then the variable 'a' would *not* be a literal enum.
+
+        We occasionally special-case expressions like 'Foo.A' and treat them as a single primitive
+        unit for the same reasons we sometimes treat 'True', 'False', or 'None' as a single
+        primitive unit.
+        """
+        if not isinstance(n, MemberExpr) or not isinstance(n.expr, NameExpr):
+            return False
+
+        parent_type = self.lookup_type_or_none(n.expr)
+        member_type = self.lookup_type_or_none(n)
+        if member_type is None or parent_type is None:
+            return False
+
+        parent_type = get_proper_type(parent_type)
+        member_type = get_proper_type(coerce_to_literal(member_type))
+        if not isinstance(parent_type, FunctionLike) or not isinstance(member_type, LiteralType):
+            return False
+
+        if not parent_type.is_type_obj():
+            return False
+
+        return (
+            member_type.is_enum_literal()
+            and member_type.fallback.type == parent_type.type_object()
+        )
+
+    def add_any_attribute_to_type(self, typ: Type, name: str) -> Type:
+        """Inject an extra attribute with Any type using fallbacks."""
+        orig_typ = typ
+        typ = get_proper_type(typ)
+        any_type = AnyType(TypeOfAny.unannotated)
+        if isinstance(typ, Instance):
+            result = typ.copy_with_extra_attr(name, any_type)
+            # For instances, we erase the possible module name, so that restrictions
+            # become anonymous types.ModuleType instances, allowing hasattr() to
+            # have effect on modules.
+            assert result.extra_attrs is not None
+            result.extra_attrs.mod_name = None
+            return result
+        if isinstance(typ, TupleType):
+            fallback = typ.partial_fallback.copy_with_extra_attr(name, any_type)
+            return typ.copy_modified(fallback=fallback)
+        if isinstance(typ, CallableType):
+            fallback = typ.fallback.copy_with_extra_attr(name, any_type)
+            return typ.copy_modified(fallback=fallback)
+        if isinstance(typ, TypeType) and isinstance(typ.item, Instance):
+            return TypeType.make_normalized(self.add_any_attribute_to_type(typ.item, name))
+        if isinstance(typ, TypeVarType):
+            return typ.copy_modified(
+                upper_bound=self.add_any_attribute_to_type(typ.upper_bound, name),
+                values=[self.add_any_attribute_to_type(v, name) for v in typ.values],
+            )
+        if isinstance(typ, UnionType):
+            with_attr, without_attr = self.partition_union_by_attr(typ, name)
+            return make_simplified_union(
+                with_attr + [self.add_any_attribute_to_type(typ, name) for typ in without_attr]
+            )
+        return orig_typ
+
+    def hasattr_type_maps(
+        self, expr: Expression, source_type: Type, name: str
+    ) -> tuple[TypeMap, TypeMap]:
+        """Simple support for hasattr() checks.
+
+        Essentially the logic is following:
+            * In the if branch, keep types that already has a valid attribute as is,
+              for other inject an attribute with `Any` type.
+            * In the else branch, remove types that already have a valid attribute,
+              while keeping the rest.
+        """
+        if self.has_valid_attribute(source_type, name):
+            return {expr: source_type}, {}
+
+        source_type = get_proper_type(source_type)
+        if isinstance(source_type, UnionType):
+            _, without_attr = self.partition_union_by_attr(source_type, name)
+            yes_map = {expr: self.add_any_attribute_to_type(source_type, name)}
+            return yes_map, {expr: make_simplified_union(without_attr)}
+
+        type_with_attr = self.add_any_attribute_to_type(source_type, name)
+        if type_with_attr != source_type:
+            return {expr: type_with_attr}, {}
+        return {}, {}
+
+    def partition_union_by_attr(
+        self, source_type: UnionType, name: str
+    ) -> tuple[list[Type], list[Type]]:
+        with_attr = []
+        without_attr = []
+        for item in source_type.items:
+            if self.has_valid_attribute(item, name):
+                with_attr.append(item)
+            else:
+                without_attr.append(item)
+        return with_attr, without_attr
+
+    def has_valid_attribute(self, typ: Type, name: str) -> bool:
+        p_typ = get_proper_type(typ)
+        if isinstance(p_typ, AnyType):
+            return False
+        if isinstance(p_typ, Instance) and p_typ.extra_attrs and p_typ.extra_attrs.mod_name:
+            # Presence of module_symbol_table means this check will skip ModuleType.__getattr__
+            module_symbol_table = p_typ.type.names
+        else:
+            module_symbol_table = None
+        with self.msg.filter_errors() as watcher:
+            analyze_member_access(
+                name,
+                typ,
+                TempNode(AnyType(TypeOfAny.special_form)),
+                False,
+                False,
+                False,
+                self.msg,
+                original_type=typ,
+                chk=self,
+                # This is not a real attribute lookup so don't mess with deferring nodes.
+                no_deferral=True,
+                module_symbol_table=module_symbol_table,
+            )
+        return not watcher.has_new_errors()
+
+    def get_expression_type(self, node: Expression, type_context: Type | None = None) -> Type:
+        return self.expr_checker.accept(node, type_context=type_context)
+
+
+class CollectArgTypeVarTypes(TypeTraverserVisitor):
+    """Collects the non-nested argument types in a set."""
+
+    def __init__(self) -> None:
+        self.arg_types: set[TypeVarType] = set()
+
+    def visit_type_var(self, t: TypeVarType) -> None:
+        self.arg_types.add(t)
+
+
+@overload
+def conditional_types(
+    current_type: Type, proposed_type_ranges: list[TypeRange] | None, default: None = None
+) -> tuple[Type | None, Type | None]:
+    ...
+
+
+@overload
+def conditional_types(
+    current_type: Type, proposed_type_ranges: list[TypeRange] | None, default: Type
+) -> tuple[Type, Type]:
+    ...
+
+
+def conditional_types(
+    current_type: Type, proposed_type_ranges: list[TypeRange] | None, default: Type | None = None
+) -> tuple[Type | None, Type | None]:
+    """Takes in the current type and a proposed type of an expression.
+
+    Returns a 2-tuple: The first element is the proposed type, if the expression
+    can be the proposed type. The second element is the type it would hold
+    if it was not the proposed type, if any. UninhabitedType means unreachable.
+    None means no new information can be inferred. If default is set it is returned
+    instead."""
+    if proposed_type_ranges:
+        if len(proposed_type_ranges) == 1:
+            target = proposed_type_ranges[0].item
+            target = get_proper_type(target)
+            if isinstance(target, LiteralType) and (
+                target.is_enum_literal() or isinstance(target.value, bool)
+            ):
+                enum_name = target.fallback.type.fullname
+                current_type = try_expanding_sum_type_to_union(current_type, enum_name)
+        proposed_items = [type_range.item for type_range in proposed_type_ranges]
+        proposed_type = make_simplified_union(proposed_items)
+        if isinstance(proposed_type, AnyType):
+            # We don't really know much about the proposed type, so we shouldn't
+            # attempt to narrow anything. Instead, we broaden the expr to Any to
+            # avoid false positives
+            return proposed_type, default
+        elif not any(
+            type_range.is_upper_bound for type_range in proposed_type_ranges
+        ) and is_proper_subtype(current_type, proposed_type, ignore_promotions=True):
+            # Expression is always of one of the types in proposed_type_ranges
+            return default, UninhabitedType()
+        elif not is_overlapping_types(
+            current_type, proposed_type, prohibit_none_typevar_overlap=True, ignore_promotions=True
+        ):
+            # Expression is never of any type in proposed_type_ranges
+            return UninhabitedType(), default
+        else:
+            # we can only restrict when the type is precise, not bounded
+            proposed_precise_type = UnionType.make_union(
+                [
+                    type_range.item
+                    for type_range in proposed_type_ranges
+                    if not type_range.is_upper_bound
+                ]
+            )
+            remaining_type = restrict_subtype_away(current_type, proposed_precise_type)
+            return proposed_type, remaining_type
+    else:
+        # An isinstance check, but we don't understand the type
+        return current_type, default
+
+
+def conditional_types_to_typemaps(
+    expr: Expression, yes_type: Type | None, no_type: Type | None
+) -> tuple[TypeMap, TypeMap]:
+    expr = collapse_walrus(expr)
+    maps: list[TypeMap] = []
+    for typ in (yes_type, no_type):
+        proper_type = get_proper_type(typ)
+        if isinstance(proper_type, UninhabitedType):
+            maps.append(None)
+        elif proper_type is None:
+            maps.append({})
+        else:
+            assert typ is not None
+            maps.append({expr: typ})
+
+    return cast(Tuple[TypeMap, TypeMap], tuple(maps))
+
+
+def gen_unique_name(base: str, table: SymbolTable) -> str:
+    """Generate a name that does not appear in table by appending numbers to base."""
+    if base not in table:
+        return base
+    i = 1
+    while base + str(i) in table:
+        i += 1
+    return base + str(i)
+
+
+def is_true_literal(n: Expression) -> bool:
+    """Returns true if this expression is the 'True' literal/keyword."""
+    return refers_to_fullname(n, "builtins.True") or isinstance(n, IntExpr) and n.value != 0
+
+
+def is_false_literal(n: Expression) -> bool:
+    """Returns true if this expression is the 'False' literal/keyword."""
+    return refers_to_fullname(n, "builtins.False") or isinstance(n, IntExpr) and n.value == 0
+
+
+def is_literal_none(n: Expression) -> bool:
+    """Returns true if this expression is the 'None' literal/keyword."""
+    return isinstance(n, NameExpr) and n.fullname == "builtins.None"
+
+
+def is_literal_not_implemented(n: Expression) -> bool:
+    return isinstance(n, NameExpr) and n.fullname == "builtins.NotImplemented"
+
+
+def builtin_item_type(tp: Type) -> Type | None:
+    """Get the item type of a builtin container.
+
+    If 'tp' is not one of the built containers (these includes NamedTuple and TypedDict)
+    or if the container is not parameterized (like List or List[Any])
+    return None. This function is used to narrow optional types in situations like this:
+
+        x: Optional[int]
+        if x in (1, 2, 3):
+            x + 42  # OK
+
+    Note: this is only OK for built-in containers, where we know the behavior
+    of __contains__.
+    """
+    tp = get_proper_type(tp)
+
+    if isinstance(tp, Instance):
+        if tp.type.fullname in [
+            "builtins.list",
+            "builtins.tuple",
+            "builtins.dict",
+            "builtins.set",
+            "builtins.frozenset",
+            "_collections_abc.dict_keys",
+            "typing.KeysView",
+        ]:
+            if not tp.args:
+                # TODO: fix tuple in lib-stub/builtins.pyi (it should be generic).
+                return None
+            if not isinstance(get_proper_type(tp.args[0]), AnyType):
+                return tp.args[0]
+    elif isinstance(tp, TupleType) and all(
+        not isinstance(it, AnyType) for it in get_proper_types(tp.items)
+    ):
+        return make_simplified_union(tp.items)  # this type is not externally visible
+    elif isinstance(tp, TypedDictType):
+        # TypedDict always has non-optional string keys. Find the key type from the Mapping
+        # base class.
+        for base in tp.fallback.type.mro:
+            if base.fullname == "typing.Mapping":
+                return map_instance_to_supertype(tp.fallback, base).args[0]
+        assert False, "No Mapping base class found for TypedDict fallback"
+    return None
+
+
+def and_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
+    """Calculate what information we can learn from the truth of (e1 and e2)
+    in terms of the information that we can learn from the truth of e1 and
+    the truth of e2.
+    """
+
+    if m1 is None or m2 is None:
+        # One of the conditions can never be true.
+        return None
+    # Both conditions can be true; combine the information. Anything
+    # we learn from either conditions's truth is valid. If the same
+    # expression's type is refined by both conditions, we somewhat
+    # arbitrarily give precedence to m2. (In the future, we could use
+    # an intersection type.)
+    result = m2.copy()
+    m2_keys = {literal_hash(n2) for n2 in m2}
+    for n1 in m1:
+        if literal_hash(n1) not in m2_keys:
+            result[n1] = m1[n1]
+    return result
+
+
+def or_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
+    """Calculate what information we can learn from the truth of (e1 or e2)
+    in terms of the information that we can learn from the truth of e1 and
+    the truth of e2.
+    """
+
+    if m1 is None:
+        return m2
+    if m2 is None:
+        return m1
+    # Both conditions can be true. Combine information about
+    # expressions whose type is refined by both conditions. (We do not
+    # learn anything about expressions whose type is refined by only
+    # one condition.)
+    result: dict[Expression, Type] = {}
+    for n1 in m1:
+        for n2 in m2:
+            if literal_hash(n1) == literal_hash(n2):
+                result[n1] = make_simplified_union([m1[n1], m2[n2]])
+    return result
+
+
+def reduce_conditional_maps(type_maps: list[tuple[TypeMap, TypeMap]]) -> tuple[TypeMap, TypeMap]:
+    """Reduces a list containing pairs of if/else TypeMaps into a single pair.
+
+    We "and" together all of the if TypeMaps and "or" together the else TypeMaps. So
+    for example, if we had the input:
+
+        [
+            ({x: TypeIfX, shared: TypeIfShared1}, {x: TypeElseX, shared: TypeElseShared1}),
+            ({y: TypeIfY, shared: TypeIfShared2}, {y: TypeElseY, shared: TypeElseShared2}),
+        ]
+
+    ...we'd return the output:
+
+        (
+            {x: TypeIfX,   y: TypeIfY,   shared: PseudoIntersection[TypeIfShared1, TypeIfShared2]},
+            {shared: Union[TypeElseShared1, TypeElseShared2]},
+        )
+
+    ...where "PseudoIntersection[X, Y] == Y" because mypy actually doesn't understand intersections
+    yet, so we settle for just arbitrarily picking the right expr's type.
+
+    We only retain the shared expression in the 'else' case because we don't actually know
+    whether x was refined or y was refined -- only just that one of the two was refined.
+    """
+    if len(type_maps) == 0:
+        return {}, {}
+    elif len(type_maps) == 1:
+        return type_maps[0]
+    else:
+        final_if_map, final_else_map = type_maps[0]
+        for if_map, else_map in type_maps[1:]:
+            final_if_map = and_conditional_maps(final_if_map, if_map)
+            final_else_map = or_conditional_maps(final_else_map, else_map)
+
+        return final_if_map, final_else_map
+
+
+def convert_to_typetype(type_map: TypeMap) -> TypeMap:
+    converted_type_map: dict[Expression, Type] = {}
+    if type_map is None:
+        return None
+    for expr, typ in type_map.items():
+        t = typ
+        if isinstance(t, TypeVarType):
+            t = t.upper_bound
+        # TODO: should we only allow unions of instances as per PEP 484?
+        if not isinstance(get_proper_type(t), (UnionType, Instance)):
+            # unknown type; error was likely reported earlier
+            return {}
+        converted_type_map[expr] = TypeType.make_normalized(typ)
+    return converted_type_map
+
+
+def flatten(t: Expression) -> list[Expression]:
+    """Flatten a nested sequence of tuples/lists into one list of nodes."""
+    if isinstance(t, (TupleExpr, ListExpr)):
+        return [b for a in t.items for b in flatten(a)]
+    elif isinstance(t, StarExpr):
+        return flatten(t.expr)
+    else:
+        return [t]
+
+
+def flatten_types(t: Type) -> list[Type]:
+    """Flatten a nested sequence of tuples into one list of nodes."""
+    t = get_proper_type(t)
+    if isinstance(t, TupleType):
+        return [b for a in t.items for b in flatten_types(a)]
+    else:
+        return [t]
+
+
+def expand_func(defn: FuncItem, map: dict[TypeVarId, Type]) -> FuncItem:
+    visitor = TypeTransformVisitor(map)
+    ret = visitor.node(defn)
+    assert isinstance(ret, FuncItem)
+    return ret
+
+
+class TypeTransformVisitor(TransformVisitor):
+    def __init__(self, map: dict[TypeVarId, Type]) -> None:
+        super().__init__()
+        self.map = map
+
+    def type(self, type: Type) -> Type:
+        return expand_type(type, self.map)
+
+
+def are_argument_counts_overlapping(t: CallableType, s: CallableType) -> bool:
+    """Can a single call match both t and s, based just on positional argument counts?"""
+    min_args = max(t.min_args, s.min_args)
+    max_args = min(t.max_possible_positional_args(), s.max_possible_positional_args())
+    return min_args <= max_args
+
+
+def is_unsafe_overlapping_overload_signatures(
+    signature: CallableType, other: CallableType
+) -> bool:
+    """Check if two overloaded signatures are unsafely overlapping or partially overlapping.
+
+    We consider two functions 's' and 't' to be unsafely overlapping if both
+    of the following are true:
+
+    1.  s's parameters are all more precise or partially overlapping with t's
+    2.  s's return type is NOT a subtype of t's.
+
+    Assumes that 'signature' appears earlier in the list of overload
+    alternatives then 'other' and that their argument counts are overlapping.
+    """
+    # Try detaching callables from the containing class so that all TypeVars
+    # are treated as being free.
+    #
+    # This lets us identify cases where the two signatures use completely
+    # incompatible types -- e.g. see the testOverloadingInferUnionReturnWithMixedTypevars
+    # test case.
+    signature = detach_callable(signature)
+    other = detach_callable(other)
+
+    # Note: We repeat this check twice in both directions due to a slight
+    # asymmetry in 'is_callable_compatible'. When checking for partial overlaps,
+    # we attempt to unify 'signature' and 'other' both against each other.
+    #
+    # If 'signature' cannot be unified with 'other', we end early. However,
+    # if 'other' cannot be modified with 'signature', the function continues
+    # using the older version of 'other'.
+    #
+    # This discrepancy is unfortunately difficult to get rid of, so we repeat the
+    # checks twice in both directions for now.
+    return is_callable_compatible(
+        signature,
+        other,
+        is_compat=is_overlapping_types_no_promote_no_uninhabited,
+        is_compat_return=lambda l, r: not is_subtype_no_promote(l, r),
+        ignore_return=False,
+        check_args_covariantly=True,
+        allow_partial_overlap=True,
+    ) or is_callable_compatible(
+        other,
+        signature,
+        is_compat=is_overlapping_types_no_promote_no_uninhabited,
+        is_compat_return=lambda l, r: not is_subtype_no_promote(r, l),
+        ignore_return=False,
+        check_args_covariantly=False,
+        allow_partial_overlap=True,
+    )
+
+
+def detach_callable(typ: CallableType) -> CallableType:
+    """Ensures that the callable's type variables are 'detached' and independent of the context.
+
+    A callable normally keeps track of the type variables it uses within its 'variables' field.
+    However, if the callable is from a method and that method is using a class type variable,
+    the callable will not keep track of that type variable since it belongs to the class.
+
+    This function will traverse the callable and find all used type vars and add them to the
+    variables field if it isn't already present.
+
+    The caller can then unify on all type variables whether or not the callable is originally
+    from a class or not."""
+    type_list = typ.arg_types + [typ.ret_type]
+
+    appear_map: dict[str, list[int]] = {}
+    for i, inner_type in enumerate(type_list):
+        typevars_available = get_type_vars(inner_type)
+        for var in typevars_available:
+            if var.fullname not in appear_map:
+                appear_map[var.fullname] = []
+            appear_map[var.fullname].append(i)
+
+    used_type_var_names = set()
+    for var_name, appearances in appear_map.items():
+        used_type_var_names.add(var_name)
+
+    all_type_vars = get_type_vars(typ)
+    new_variables = []
+    for var in set(all_type_vars):
+        if var.fullname not in used_type_var_names:
+            continue
+        new_variables.append(
+            TypeVarType(
+                name=var.name,
+                fullname=var.fullname,
+                id=var.id,
+                values=var.values,
+                upper_bound=var.upper_bound,
+                default=var.default,
+                variance=var.variance,
+            )
+        )
+    out = typ.copy_modified(
+        variables=new_variables, arg_types=type_list[:-1], ret_type=type_list[-1]
+    )
+    return out
+
+
+def overload_can_never_match(signature: CallableType, other: CallableType) -> bool:
+    """Check if the 'other' method can never be matched due to 'signature'.
+
+    This can happen if signature's parameters are all strictly broader then
+    other's parameters.
+
+    Assumes that both signatures have overlapping argument counts.
+    """
+    # The extra erasure is needed to prevent spurious errors
+    # in situations where an `Any` overload is used as a fallback
+    # for an overload with type variables. The spurious error appears
+    # because the type variables turn into `Any` during unification in
+    # the below subtype check and (surprisingly?) `is_proper_subtype(Any, Any)`
+    # returns `True`.
+    # TODO: find a cleaner solution instead of this ad-hoc erasure.
+    exp_signature = expand_type(
+        signature, {tvar.id: erase_def_to_union_or_bound(tvar) for tvar in signature.variables}
+    )
+    return is_callable_compatible(
+        exp_signature, other, is_compat=is_more_precise, ignore_return=True
+    )
+
+
+def is_more_general_arg_prefix(t: FunctionLike, s: FunctionLike) -> bool:
+    """Does t have wider arguments than s?"""
+    # TODO should an overload with additional items be allowed to be more
+    #      general than one with fewer items (or just one item)?
+    if isinstance(t, CallableType):
+        if isinstance(s, CallableType):
+            return is_callable_compatible(t, s, is_compat=is_proper_subtype, ignore_return=True)
+    elif isinstance(t, FunctionLike):
+        if isinstance(s, FunctionLike):
+            if len(t.items) == len(s.items):
+                return all(
+                    is_same_arg_prefix(items, itemt) for items, itemt in zip(t.items, s.items)
+                )
+    return False
+
+
+def is_same_arg_prefix(t: CallableType, s: CallableType) -> bool:
+    return is_callable_compatible(
+        t,
+        s,
+        is_compat=is_same_type,
+        ignore_return=True,
+        check_args_covariantly=True,
+        ignore_pos_arg_names=True,
+    )
+
+
+def infer_operator_assignment_method(typ: Type, operator: str) -> tuple[bool, str]:
+    """Determine if operator assignment on given value type is in-place, and the method name.
+
+    For example, if operator is '+', return (True, '__iadd__') or (False, '__add__')
+    depending on which method is supported by the type.
+    """
+    typ = get_proper_type(typ)
+    method = operators.op_methods[operator]
+    if isinstance(typ, Instance):
+        if operator in operators.ops_with_inplace_method:
+            inplace_method = "__i" + method[2:]
+            if typ.type.has_readable_member(inplace_method):
+                return True, inplace_method
+    return False, method
+
+
+def is_valid_inferred_type(typ: Type, is_lvalue_final: bool = False) -> bool:
+    """Is an inferred type valid and needs no further refinement?
+
+    Examples of invalid types include the None type (when we are not assigning
+    None to a final lvalue) or List[<uninhabited>].
+
+    When not doing strict Optional checking, all types containing None are
+    invalid.  When doing strict Optional checking, only None and types that are
+    incompletely defined (i.e. contain UninhabitedType) are invalid.
+    """
+    proper_type = get_proper_type(typ)
+    if isinstance(proper_type, NoneType):
+        # If the lvalue is final, we may immediately infer NoneType when the
+        # initializer is None.
+        #
+        # If not, we want to defer making this decision. The final inferred
+        # type could either be NoneType or an Optional type, depending on
+        # the context. This resolution happens in leave_partial_types when
+        # we pop a partial types scope.
+        return is_lvalue_final
+    elif isinstance(proper_type, UninhabitedType):
+        return False
+    return not typ.accept(InvalidInferredTypes())
+
+
+class InvalidInferredTypes(BoolTypeQuery):
+    """Find type components that are not valid for an inferred type.
+
+    These include <Erased> type, and any <nothing> types resulting from failed
+    (ambiguous) type inference.
+    """
+
+    def __init__(self) -> None:
+        super().__init__(ANY_STRATEGY)
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
+        return t.ambiguous
+
+    def visit_erased_type(self, t: ErasedType) -> bool:
+        # This can happen inside a lambda.
+        return True
+
+
+class SetNothingToAny(TypeTranslator):
+    """Replace all ambiguous <nothing> types with Any (to avoid spurious extra errors)."""
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
+        if t.ambiguous:
+            return AnyType(TypeOfAny.from_error)
+        return t
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        # Target of the alias cannot be an ambiguous <nothing>, so we just
+        # replace the arguments.
+        return t.copy_modified(args=[a.accept(self) for a in t.args])
+
+
+def is_node_static(node: Node | None) -> bool | None:
+    """Find out if a node describes a static function method."""
+
+    if isinstance(node, FuncDef):
+        return node.is_static
+
+    if isinstance(node, Var):
+        return node.is_staticmethod
+
+    return None
+
+
+class CheckerScope:
+    # We keep two stacks combined, to maintain the relative order
+    stack: list[TypeInfo | FuncItem | MypyFile]
+
+    def __init__(self, module: MypyFile) -> None:
+        self.stack = [module]
+
+    def top_function(self) -> FuncItem | None:
+        for e in reversed(self.stack):
+            if isinstance(e, FuncItem):
+                return e
+        return None
+
+    def top_non_lambda_function(self) -> FuncItem | None:
+        for e in reversed(self.stack):
+            if isinstance(e, FuncItem) and not isinstance(e, LambdaExpr):
+                return e
+        return None
+
+    def active_class(self) -> TypeInfo | None:
+        if isinstance(self.stack[-1], TypeInfo):
+            return self.stack[-1]
+        return None
+
+    def enclosing_class(self) -> TypeInfo | None:
+        """Is there a class *directly* enclosing this function?"""
+        top = self.top_function()
+        assert top, "This method must be called from inside a function"
+        index = self.stack.index(top)
+        assert index, "CheckerScope stack must always start with a module"
+        enclosing = self.stack[index - 1]
+        if isinstance(enclosing, TypeInfo):
+            return enclosing
+        return None
+
+    def active_self_type(self) -> Instance | TupleType | None:
+        """An instance or tuple type representing the current class.
+
+        This returns None unless we are in class body or in a method.
+        In particular, inside a function nested in method this returns None.
+        """
+        info = self.active_class()
+        if not info and self.top_function():
+            info = self.enclosing_class()
+        if info:
+            return fill_typevars(info)
+        return None
+
+    @contextmanager
+    def push_function(self, item: FuncItem) -> Iterator[None]:
+        self.stack.append(item)
+        yield
+        self.stack.pop()
+
+    @contextmanager
+    def push_class(self, info: TypeInfo) -> Iterator[None]:
+        self.stack.append(info)
+        yield
+        self.stack.pop()
+
+
+TKey = TypeVar("TKey")
+TValue = TypeVar("TValue")
+
+
+class DisjointDict(Generic[TKey, TValue]):
+    """An variation of the union-find algorithm/data structure where instead of keeping
+    track of just disjoint sets, we keep track of disjoint dicts -- keep track of multiple
+    Set[Key] -> Set[Value] mappings, where each mapping's keys are guaranteed to be disjoint.
+
+    This data structure is currently used exclusively by 'group_comparison_operands' below
+    to merge chains of '==' and 'is' comparisons when two or more chains use the same expression
+    in best-case O(n), where n is the number of operands.
+
+    Specifically, the `add_mapping()` function and `items()` functions will take on average
+    O(k + v) and O(n) respectively, where k and v are the number of keys and values we're adding
+    for a given chain. Note that k <= n and v <= n.
+
+    We hit these average/best-case scenarios for most user code: e.g. when the user has just
+    a single chain like 'a == b == c == d == ...' or multiple disjoint chains like
+    'a==b < c==d < e==f < ...'. (Note that a naive iterative merging would be O(n^2) for
+    the latter case).
+
+    In comparison, this data structure will make 'group_comparison_operands' have a worst-case
+    runtime of O(n*log(n)): 'add_mapping()' and 'items()' are worst-case O(k*log(n) + v) and
+    O(k*log(n)) respectively. This happens only in the rare case where the user keeps repeatedly
+    making disjoint mappings before merging them in a way that persistently dodges the path
+    compression optimization in '_lookup_root_id', which would end up constructing a single
+    tree of height log_2(n). This makes root lookups no longer amoritized constant time when we
+    finally call 'items()'.
+    """
+
+    def __init__(self) -> None:
+        # Each key maps to a unique ID
+        self._key_to_id: dict[TKey, int] = {}
+
+        # Each id points to the parent id, forming a forest of upwards-pointing trees. If the
+        # current id already is the root, it points to itself. We gradually flatten these trees
+        # as we perform root lookups: eventually all nodes point directly to its root.
+        self._id_to_parent_id: dict[int, int] = {}
+
+        # Each root id in turn maps to the set of values.
+        self._root_id_to_values: dict[int, set[TValue]] = {}
+
+    def add_mapping(self, keys: set[TKey], values: set[TValue]) -> None:
+        """Adds a 'Set[TKey] -> Set[TValue]' mapping. If there already exists a mapping
+        containing one or more of the given keys, we merge the input mapping with the old one.
+
+        Note that the given set of keys must be non-empty -- otherwise, nothing happens.
+        """
+        if not keys:
+            return
+
+        subtree_roots = [self._lookup_or_make_root_id(key) for key in keys]
+        new_root = subtree_roots[0]
+
+        root_values = self._root_id_to_values[new_root]
+        root_values.update(values)
+        for subtree_root in subtree_roots[1:]:
+            if subtree_root == new_root or subtree_root not in self._root_id_to_values:
+                continue
+            self._id_to_parent_id[subtree_root] = new_root
+            root_values.update(self._root_id_to_values.pop(subtree_root))
+
+    def items(self) -> list[tuple[set[TKey], set[TValue]]]:
+        """Returns all disjoint mappings in key-value pairs."""
+        root_id_to_keys: dict[int, set[TKey]] = {}
+        for key in self._key_to_id:
+            root_id = self._lookup_root_id(key)
+            if root_id not in root_id_to_keys:
+                root_id_to_keys[root_id] = set()
+            root_id_to_keys[root_id].add(key)
+
+        output = []
+        for root_id, keys in root_id_to_keys.items():
+            output.append((keys, self._root_id_to_values[root_id]))
+
+        return output
+
+    def _lookup_or_make_root_id(self, key: TKey) -> int:
+        if key in self._key_to_id:
+            return self._lookup_root_id(key)
+        else:
+            new_id = len(self._key_to_id)
+            self._key_to_id[key] = new_id
+            self._id_to_parent_id[new_id] = new_id
+            self._root_id_to_values[new_id] = set()
+            return new_id
+
+    def _lookup_root_id(self, key: TKey) -> int:
+        i = self._key_to_id[key]
+        while i != self._id_to_parent_id[i]:
+            # Optimization: make keys directly point to their grandparents to speed up
+            # future traversals. This prevents degenerate trees of height n from forming.
+            new_parent = self._id_to_parent_id[self._id_to_parent_id[i]]
+            self._id_to_parent_id[i] = new_parent
+            i = new_parent
+        return i
+
+
+def group_comparison_operands(
+    pairwise_comparisons: Iterable[tuple[str, Expression, Expression]],
+    operand_to_literal_hash: Mapping[int, Key],
+    operators_to_group: set[str],
+) -> list[tuple[str, list[int]]]:
+    """Group a series of comparison operands together chained by any operand
+    in the 'operators_to_group' set. All other pairwise operands are kept in
+    groups of size 2.
+
+    For example, suppose we have the input comparison expression:
+
+        x0 == x1 == x2 < x3 < x4 is x5 is x6 is not x7 is not x8
+
+    If we get these expressions in a pairwise way (e.g. by calling ComparisionExpr's
+    'pairwise()' method), we get the following as input:
+
+        [('==', x0, x1), ('==', x1, x2), ('<', x2, x3), ('<', x3, x4),
+         ('is', x4, x5), ('is', x5, x6), ('is not', x6, x7), ('is not', x7, x8)]
+
+    If `operators_to_group` is the set {'==', 'is'}, this function will produce
+    the following "simplified operator list":
+
+       [("==", [0, 1, 2]), ("<", [2, 3]), ("<", [3, 4]),
+        ("is", [4, 5, 6]), ("is not", [6, 7]), ("is not", [7, 8])]
+
+    Note that (a) we yield *indices* to the operands rather then the operand
+    expressions themselves and that (b) operands used in a consecutive chain
+    of '==' or 'is' are grouped together.
+
+    If two of these chains happen to contain operands with the same underlying
+    literal hash (e.g. are assignable and correspond to the same expression),
+    we combine those chains together. For example, if we had:
+
+        same == x < y == same
+
+    ...and if 'operand_to_literal_hash' contained the same values for the indices
+    0 and 3, we'd produce the following output:
+
+        [("==", [0, 1, 2, 3]), ("<", [1, 2])]
+
+    But if the 'operand_to_literal_hash' did *not* contain an entry, we'd instead
+    default to returning:
+
+        [("==", [0, 1]), ("<", [1, 2]), ("==", [2, 3])]
+
+    This function is currently only used to assist with type-narrowing refinements
+    and is extracted out to a helper function so we can unit test it.
+    """
+    groups: dict[str, DisjointDict[Key, int]] = {op: DisjointDict() for op in operators_to_group}
+
+    simplified_operator_list: list[tuple[str, list[int]]] = []
+    last_operator: str | None = None
+    current_indices: set[int] = set()
+    current_hashes: set[Key] = set()
+    for i, (operator, left_expr, right_expr) in enumerate(pairwise_comparisons):
+        if last_operator is None:
+            last_operator = operator
+
+        if current_indices and (operator != last_operator or operator not in operators_to_group):
+            # If some of the operands in the chain are assignable, defer adding it: we might
+            # end up needing to merge it with other chains that appear later.
+            if not current_hashes:
+                simplified_operator_list.append((last_operator, sorted(current_indices)))
+            else:
+                groups[last_operator].add_mapping(current_hashes, current_indices)
+            last_operator = operator
+            current_indices = set()
+            current_hashes = set()
+
+        # Note: 'i' corresponds to the left operand index, so 'i + 1' is the
+        # right operand.
+        current_indices.add(i)
+        current_indices.add(i + 1)
+
+        # We only ever want to combine operands/combine chains for these operators
+        if operator in operators_to_group:
+            left_hash = operand_to_literal_hash.get(i)
+            if left_hash is not None:
+                current_hashes.add(left_hash)
+            right_hash = operand_to_literal_hash.get(i + 1)
+            if right_hash is not None:
+                current_hashes.add(right_hash)
+
+    if last_operator is not None:
+        if not current_hashes:
+            simplified_operator_list.append((last_operator, sorted(current_indices)))
+        else:
+            groups[last_operator].add_mapping(current_hashes, current_indices)
+
+    # Now that we know which chains happen to contain the same underlying expressions
+    # and can be merged together, add in this info back to the output.
+    for operator, disjoint_dict in groups.items():
+        for keys, indices in disjoint_dict.items():
+            simplified_operator_list.append((operator, sorted(indices)))
+
+    # For stability, reorder list by the first operand index to appear
+    simplified_operator_list.sort(key=lambda item: item[1][0])
+    return simplified_operator_list
+
+
+def is_typed_callable(c: Type | None) -> bool:
+    c = get_proper_type(c)
+    if not c or not isinstance(c, CallableType):
+        return False
+    return not all(
+        isinstance(t, AnyType) and t.type_of_any == TypeOfAny.unannotated
+        for t in get_proper_types(c.arg_types + [c.ret_type])
+    )
+
+
+def is_untyped_decorator(typ: Type | None) -> bool:
+    typ = get_proper_type(typ)
+    if not typ:
+        return True
+    elif isinstance(typ, CallableType):
+        return not is_typed_callable(typ)
+    elif isinstance(typ, Instance):
+        method = typ.type.get_method("__call__")
+        if method:
+            if isinstance(method, Decorator):
+                return is_untyped_decorator(method.func.type) or is_untyped_decorator(
+                    method.var.type
+                )
+
+            if isinstance(method.type, Overloaded):
+                return any(is_untyped_decorator(item) for item in method.type.items)
+            else:
+                return not is_typed_callable(method.type)
+        else:
+            return False
+    elif isinstance(typ, Overloaded):
+        return any(is_untyped_decorator(item) for item in typ.items)
+    return True
+
+
+def is_static(func: FuncBase | Decorator) -> bool:
+    if isinstance(func, Decorator):
+        return is_static(func.func)
+    elif isinstance(func, FuncBase):
+        return func.is_static
+    assert False, f"Unexpected func type: {type(func)}"
+
+
+def is_property(defn: SymbolNode) -> bool:
+    if isinstance(defn, Decorator):
+        return defn.func.is_property
+    if isinstance(defn, OverloadedFuncDef):
+        if defn.items and isinstance(defn.items[0], Decorator):
+            return defn.items[0].func.is_property
+    return False
+
+
+def get_property_type(t: ProperType) -> ProperType:
+    if isinstance(t, CallableType):
+        return get_proper_type(t.ret_type)
+    if isinstance(t, Overloaded):
+        return get_proper_type(t.items[0].ret_type)
+    return t
+
+
+def is_subtype_no_promote(left: Type, right: Type) -> bool:
+    return is_subtype(left, right, ignore_promotions=True)
+
+
+def is_overlapping_types_no_promote_no_uninhabited(left: Type, right: Type) -> bool:
+    # For the purpose of unsafe overload checks we consider list[<nothing>] and list[int]
+    # non-overlapping. This is consistent with how we treat list[int] and list[str] as
+    # non-overlapping, despite [] belongs to both. Also this will prevent false positives
+    # for failed type inference during unification.
+    return is_overlapping_types(left, right, ignore_promotions=True, ignore_uninhabited=True)
+
+
+def is_private(node_name: str) -> bool:
+    """Check if node is private to class definition."""
+    return node_name.startswith("__") and not node_name.endswith("__")
+
+
+def is_string_literal(typ: Type) -> bool:
+    strs = try_getting_str_literals_from_type(typ)
+    return strs is not None and len(strs) == 1
+
+
+def has_bool_item(typ: ProperType) -> bool:
+    """Return True if type is 'bool' or a union with a 'bool' item."""
+    if is_named_instance(typ, "builtins.bool"):
+        return True
+    if isinstance(typ, UnionType):
+        return any(is_named_instance(item, "builtins.bool") for item in typ.items)
+    return False
+
+
+def collapse_walrus(e: Expression) -> Expression:
+    """If an expression is an AssignmentExpr, pull out the assignment target.
+
+    We don't make any attempt to pull out all the targets in code like `x := (y := z)`.
+    We could support narrowing those if that sort of code turns out to be common.
+    """
+    if isinstance(e, AssignmentExpr):
+        return e.target
+    return e
+
+
+def find_last_var_assignment_line(n: Node, v: Var) -> int:
+    """Find the highest line number of a potential assignment to variable within node.
+
+    This supports local and global variables.
+
+    Return -1 if no assignment was found.
+    """
+    visitor = VarAssignVisitor(v)
+    n.accept(visitor)
+    return visitor.last_line
+
+
+class VarAssignVisitor(TraverserVisitor):
+    def __init__(self, v: Var) -> None:
+        self.last_line = -1
+        self.lvalue = False
+        self.var_node = v
+
+    def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
+        self.lvalue = True
+        for lv in s.lvalues:
+            lv.accept(self)
+        self.lvalue = False
+
+    def visit_name_expr(self, e: NameExpr) -> None:
+        if self.lvalue and e.node is self.var_node:
+            self.last_line = max(self.last_line, e.line)
+
+    def visit_member_expr(self, e: MemberExpr) -> None:
+        old_lvalue = self.lvalue
+        self.lvalue = False
+        super().visit_member_expr(e)
+        self.lvalue = old_lvalue
+
+    def visit_index_expr(self, e: IndexExpr) -> None:
+        old_lvalue = self.lvalue
+        self.lvalue = False
+        super().visit_index_expr(e)
+        self.lvalue = old_lvalue
+
+    def visit_with_stmt(self, s: WithStmt) -> None:
+        self.lvalue = True
+        for lv in s.target:
+            if lv is not None:
+                lv.accept(self)
+        self.lvalue = False
+        s.body.accept(self)
+
+    def visit_for_stmt(self, s: ForStmt) -> None:
+        self.lvalue = True
+        s.index.accept(self)
+        self.lvalue = False
+        s.body.accept(self)
+        if s.else_body:
+            s.else_body.accept(self)
+
+    def visit_assignment_expr(self, e: AssignmentExpr) -> None:
+        self.lvalue = True
+        e.target.accept(self)
+        self.lvalue = False
+        e.value.accept(self)
+
+    def visit_as_pattern(self, p: AsPattern) -> None:
+        if p.pattern is not None:
+            p.pattern.accept(self)
+        if p.name is not None:
+            self.lvalue = True
+            p.name.accept(self)
+            self.lvalue = False
+
+    def visit_starred_pattern(self, p: StarredPattern) -> None:
+        if p.capture is not None:
+            self.lvalue = True
+            p.capture.accept(self)
+            self.lvalue = False

二進制
venv/lib/python3.11/site-packages/mypy/checkexpr.cpython-311-x86_64-linux-gnu.so


+ 5972 - 0
venv/lib/python3.11/site-packages/mypy/checkexpr.py

@@ -0,0 +1,5972 @@
+"""Expression type checker. This file is conceptually part of TypeChecker."""
+
+from __future__ import annotations
+
+import itertools
+import time
+from collections import defaultdict
+from contextlib import contextmanager
+from typing import Callable, ClassVar, Final, Iterable, Iterator, List, Optional, Sequence, cast
+from typing_extensions import TypeAlias as _TypeAlias, overload
+
+import mypy.checker
+import mypy.errorcodes as codes
+from mypy import applytype, erasetype, join, message_registry, nodes, operators, types
+from mypy.argmap import ArgTypeExpander, map_actuals_to_formals, map_formals_to_actuals
+from mypy.checkmember import analyze_member_access, freeze_all_type_vars, type_object_type
+from mypy.checkstrformat import StringFormatterChecker
+from mypy.erasetype import erase_type, remove_instance_last_known_values, replace_meta_vars
+from mypy.errors import ErrorWatcher, report_internal_error
+from mypy.expandtype import expand_type, expand_type_by_instance, freshen_function_type_vars
+from mypy.infer import ArgumentInferContext, infer_function_type_arguments, infer_type_arguments
+from mypy.literals import literal
+from mypy.maptype import map_instance_to_supertype
+from mypy.meet import is_overlapping_types, narrow_declared_type
+from mypy.message_registry import ErrorMessage
+from mypy.messages import MessageBuilder
+from mypy.nodes import (
+    ARG_NAMED,
+    ARG_POS,
+    ARG_STAR,
+    ARG_STAR2,
+    IMPLICITLY_ABSTRACT,
+    LITERAL_TYPE,
+    REVEAL_TYPE,
+    ArgKind,
+    AssertTypeExpr,
+    AssignmentExpr,
+    AwaitExpr,
+    BytesExpr,
+    CallExpr,
+    CastExpr,
+    ComparisonExpr,
+    ComplexExpr,
+    ConditionalExpr,
+    Context,
+    Decorator,
+    DictExpr,
+    DictionaryComprehension,
+    EllipsisExpr,
+    EnumCallExpr,
+    Expression,
+    FloatExpr,
+    FuncDef,
+    GeneratorExpr,
+    IndexExpr,
+    IntExpr,
+    LambdaExpr,
+    ListComprehension,
+    ListExpr,
+    MemberExpr,
+    MypyFile,
+    NamedTupleExpr,
+    NameExpr,
+    NewTypeExpr,
+    OpExpr,
+    OverloadedFuncDef,
+    ParamSpecExpr,
+    PlaceholderNode,
+    PromoteExpr,
+    RefExpr,
+    RevealExpr,
+    SetComprehension,
+    SetExpr,
+    SliceExpr,
+    StarExpr,
+    StrExpr,
+    SuperExpr,
+    SymbolNode,
+    TempNode,
+    TupleExpr,
+    TypeAlias,
+    TypeAliasExpr,
+    TypeApplication,
+    TypedDictExpr,
+    TypeInfo,
+    TypeVarExpr,
+    TypeVarTupleExpr,
+    UnaryExpr,
+    Var,
+    YieldExpr,
+    YieldFromExpr,
+)
+from mypy.plugin import (
+    FunctionContext,
+    FunctionSigContext,
+    MethodContext,
+    MethodSigContext,
+    Plugin,
+)
+from mypy.semanal_enum import ENUM_BASES
+from mypy.state import state
+from mypy.subtypes import (
+    find_member,
+    is_equivalent,
+    is_same_type,
+    is_subtype,
+    non_method_protocol_members,
+)
+from mypy.traverser import has_await_expression
+from mypy.type_visitor import TypeTranslator
+from mypy.typeanal import (
+    check_for_explicit_any,
+    has_any_from_unimported_type,
+    instantiate_type_alias,
+    make_optional_type,
+    set_any_tvars,
+)
+from mypy.typeops import (
+    callable_type,
+    custom_special_method,
+    erase_to_union_or_bound,
+    false_only,
+    fixup_partial_type,
+    function_type,
+    get_type_vars,
+    is_literal_type_like,
+    make_simplified_union,
+    simple_literal_type,
+    true_only,
+    try_expanding_sum_type_to_union,
+    try_getting_str_literals,
+    tuple_fallback,
+)
+from mypy.types import (
+    LITERAL_TYPE_NAMES,
+    TUPLE_LIKE_INSTANCE_NAMES,
+    AnyType,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    ExtraAttrs,
+    FunctionLike,
+    Instance,
+    LiteralType,
+    LiteralValue,
+    NoneType,
+    Overloaded,
+    ParamSpecFlavor,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeOfAny,
+    TypeType,
+    TypeVarLikeType,
+    TypeVarTupleType,
+    TypeVarType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+    flatten_nested_tuples,
+    flatten_nested_unions,
+    get_proper_type,
+    get_proper_types,
+    has_recursive_types,
+    is_named_instance,
+    split_with_prefix_and_suffix,
+)
+from mypy.types_utils import is_generic_instance, is_optional, is_self_type_like, remove_optional
+from mypy.typestate import type_state
+from mypy.typevars import fill_typevars
+from mypy.typevartuples import find_unpack_in_list
+from mypy.util import split_module_names
+from mypy.visitor import ExpressionVisitor
+
+# Type of callback user for checking individual function arguments. See
+# check_args() below for details.
+ArgChecker: _TypeAlias = Callable[
+    [Type, Type, ArgKind, Type, int, int, CallableType, Optional[Type], Context, Context], None
+]
+
+# Maximum nesting level for math union in overloads, setting this to large values
+# may cause performance issues. The reason is that although union math algorithm we use
+# nicely captures most corner cases, its worst case complexity is exponential,
+# see https://github.com/python/mypy/pull/5255#discussion_r196896335 for discussion.
+MAX_UNIONS: Final = 5
+
+
+# Types considered safe for comparisons with --strict-equality due to known behaviour of __eq__.
+# NOTE: All these types are subtypes of AbstractSet.
+OVERLAPPING_TYPES_ALLOWLIST: Final = [
+    "builtins.set",
+    "builtins.frozenset",
+    "typing.KeysView",
+    "typing.ItemsView",
+    "builtins._dict_keys",
+    "builtins._dict_items",
+    "_collections_abc.dict_keys",
+    "_collections_abc.dict_items",
+]
+OVERLAPPING_BYTES_ALLOWLIST: Final = {
+    "builtins.bytes",
+    "builtins.bytearray",
+    "builtins.memoryview",
+}
+
+
+class TooManyUnions(Exception):
+    """Indicates that we need to stop splitting unions in an attempt
+    to match an overload in order to save performance.
+    """
+
+
+def allow_fast_container_literal(t: Type) -> bool:
+    if isinstance(t, TypeAliasType) and t.is_recursive:
+        return False
+    t = get_proper_type(t)
+    return isinstance(t, Instance) or (
+        isinstance(t, TupleType) and all(allow_fast_container_literal(it) for it in t.items)
+    )
+
+
+def extract_refexpr_names(expr: RefExpr) -> set[str]:
+    """Recursively extracts all module references from a reference expression.
+
+    Note that currently, the only two subclasses of RefExpr are NameExpr and
+    MemberExpr."""
+    output: set[str] = set()
+    while isinstance(expr.node, MypyFile) or expr.fullname:
+        if isinstance(expr.node, MypyFile) and expr.fullname:
+            # If it's None, something's wrong (perhaps due to an
+            # import cycle or a suppressed error).  For now we just
+            # skip it.
+            output.add(expr.fullname)
+
+        if isinstance(expr, NameExpr):
+            is_suppressed_import = isinstance(expr.node, Var) and expr.node.is_suppressed_import
+            if isinstance(expr.node, TypeInfo):
+                # Reference to a class or a nested class
+                output.update(split_module_names(expr.node.module_name))
+            elif "." in expr.fullname and not is_suppressed_import:
+                # Everything else (that is not a silenced import within a class)
+                output.add(expr.fullname.rsplit(".", 1)[0])
+            break
+        elif isinstance(expr, MemberExpr):
+            if isinstance(expr.expr, RefExpr):
+                expr = expr.expr
+            else:
+                break
+        else:
+            raise AssertionError(f"Unknown RefExpr subclass: {type(expr)}")
+    return output
+
+
+class Finished(Exception):
+    """Raised if we can terminate overload argument check early (no match)."""
+
+
+class ExpressionChecker(ExpressionVisitor[Type]):
+    """Expression type checker.
+
+    This class works closely together with checker.TypeChecker.
+    """
+
+    # Some services are provided by a TypeChecker instance.
+    chk: mypy.checker.TypeChecker
+    # This is shared with TypeChecker, but stored also here for convenience.
+    msg: MessageBuilder
+    # Type context for type inference
+    type_context: list[Type | None]
+
+    # cache resolved types in some cases
+    resolved_type: dict[Expression, ProperType]
+
+    strfrm_checker: StringFormatterChecker
+    plugin: Plugin
+
+    def __init__(
+        self,
+        chk: mypy.checker.TypeChecker,
+        msg: MessageBuilder,
+        plugin: Plugin,
+        per_line_checking_time_ns: dict[int, int],
+    ) -> None:
+        """Construct an expression type checker."""
+        self.chk = chk
+        self.msg = msg
+        self.plugin = plugin
+        self.per_line_checking_time_ns = per_line_checking_time_ns
+        self.collect_line_checking_stats = chk.options.line_checking_stats is not None
+        # Are we already visiting some expression? This is used to avoid double counting
+        # time for nested expressions.
+        self.in_expression = False
+        self.type_context = [None]
+
+        # Temporary overrides for expression types. This is currently
+        # used by the union math in overloads.
+        # TODO: refactor this to use a pattern similar to one in
+        # multiassign_from_union, or maybe even combine the two?
+        self.type_overrides: dict[Expression, Type] = {}
+        self.strfrm_checker = StringFormatterChecker(self, self.chk, self.msg)
+
+        self.resolved_type = {}
+
+        # Callee in a call expression is in some sense both runtime context and
+        # type context, because we support things like C[int](...). Store information
+        # on whether current expression is a callee, to give better error messages
+        # related to type context.
+        self.is_callee = False
+        type_state.infer_polymorphic = self.chk.options.new_type_inference
+
+    def reset(self) -> None:
+        self.resolved_type = {}
+
+    def visit_name_expr(self, e: NameExpr) -> Type:
+        """Type check a name expression.
+
+        It can be of any kind: local, member or global.
+        """
+        self.chk.module_refs.update(extract_refexpr_names(e))
+        result = self.analyze_ref_expr(e)
+        return self.narrow_type_from_binder(e, result)
+
+    def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
+        result: Type | None = None
+        node = e.node
+
+        if isinstance(e, NameExpr) and e.is_special_form:
+            # A special form definition, nothing to check here.
+            return AnyType(TypeOfAny.special_form)
+
+        if isinstance(node, Var):
+            # Variable reference.
+            result = self.analyze_var_ref(node, e)
+            if isinstance(result, PartialType):
+                result = self.chk.handle_partial_var_type(result, lvalue, node, e)
+        elif isinstance(node, FuncDef):
+            # Reference to a global function.
+            result = function_type(node, self.named_type("builtins.function"))
+        elif isinstance(node, OverloadedFuncDef) and node.type is not None:
+            # node.type is None when there are multiple definitions of a function
+            # and it's decorated by something that is not typing.overload
+            # TODO: use a dummy Overloaded instead of AnyType in this case
+            # like we do in mypy.types.function_type()?
+            result = node.type
+        elif isinstance(node, TypeInfo):
+            # Reference to a type object.
+            if node.typeddict_type:
+                # We special-case TypedDict, because they don't define any constructor.
+                result = self.typeddict_callable(node)
+            else:
+                result = type_object_type(node, self.named_type)
+            if isinstance(result, CallableType) and isinstance(  # type: ignore[misc]
+                result.ret_type, Instance
+            ):
+                # We need to set correct line and column
+                # TODO: always do this in type_object_type by passing the original context
+                result.ret_type.line = e.line
+                result.ret_type.column = e.column
+            if isinstance(get_proper_type(self.type_context[-1]), TypeType):
+                # This is the type in a Type[] expression, so substitute type
+                # variables with Any.
+                result = erasetype.erase_typevars(result)
+        elif isinstance(node, MypyFile):
+            # Reference to a module object.
+            result = self.module_type(node)
+        elif isinstance(node, Decorator):
+            result = self.analyze_var_ref(node.var, e)
+        elif isinstance(node, TypeAlias):
+            # Something that refers to a type alias appears in runtime context.
+            # Note that we suppress bogus errors for alias redefinitions,
+            # they are already reported in semanal.py.
+            result = self.alias_type_in_runtime_context(
+                node, ctx=e, alias_definition=e.is_alias_rvalue or lvalue
+            )
+        elif isinstance(node, (TypeVarExpr, ParamSpecExpr)):
+            result = self.object_type()
+        else:
+            if isinstance(node, PlaceholderNode):
+                assert False, f"PlaceholderNode {node.fullname!r} leaked to checker"
+            # Unknown reference; use any type implicitly to avoid
+            # generating extra type errors.
+            result = AnyType(TypeOfAny.from_error)
+        assert result is not None
+        return result
+
+    def analyze_var_ref(self, var: Var, context: Context) -> Type:
+        if var.type:
+            var_type = get_proper_type(var.type)
+            if isinstance(var_type, Instance):
+                if self.is_literal_context() and var_type.last_known_value is not None:
+                    return var_type.last_known_value
+                if var.name in {"True", "False"}:
+                    return self.infer_literal_expr_type(var.name == "True", "builtins.bool")
+            return var.type
+        else:
+            if not var.is_ready and self.chk.in_checked_function():
+                self.chk.handle_cannot_determine_type(var.name, context)
+            # Implicit 'Any' type.
+            return AnyType(TypeOfAny.special_form)
+
+    def module_type(self, node: MypyFile) -> Instance:
+        try:
+            result = self.named_type("types.ModuleType")
+        except KeyError:
+            # In test cases might 'types' may not be available.
+            # Fall back to a dummy 'object' type instead to
+            # avoid a crash.
+            result = self.named_type("builtins.object")
+        module_attrs = {}
+        immutable = set()
+        for name, n in node.names.items():
+            if not n.module_public:
+                continue
+            if isinstance(n.node, Var) and n.node.is_final:
+                immutable.add(name)
+            typ = self.chk.determine_type_of_member(n)
+            if typ:
+                module_attrs[name] = typ
+            else:
+                # TODO: what to do about nested module references?
+                # They are non-trivial because there may be import cycles.
+                module_attrs[name] = AnyType(TypeOfAny.special_form)
+        result.extra_attrs = ExtraAttrs(module_attrs, immutable, node.fullname)
+        return result
+
+    def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type:
+        """Type check a call expression."""
+        if e.analyzed:
+            if isinstance(e.analyzed, NamedTupleExpr) and not e.analyzed.is_typed:
+                # Type check the arguments, but ignore the results. This relies
+                # on the typeshed stubs to type check the arguments.
+                self.visit_call_expr_inner(e)
+            # It's really a special form that only looks like a call.
+            return self.accept(e.analyzed, self.type_context[-1])
+        return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
+
+    def refers_to_typeddict(self, base: Expression) -> bool:
+        if not isinstance(base, RefExpr):
+            return False
+        if isinstance(base.node, TypeInfo) and base.node.typeddict_type is not None:
+            # Direct reference.
+            return True
+        return isinstance(base.node, TypeAlias) and isinstance(
+            get_proper_type(base.node.target), TypedDictType
+        )
+
+    def visit_call_expr_inner(self, e: CallExpr, allow_none_return: bool = False) -> Type:
+        if (
+            self.refers_to_typeddict(e.callee)
+            or isinstance(e.callee, IndexExpr)
+            and self.refers_to_typeddict(e.callee.base)
+        ):
+            typeddict_callable = get_proper_type(self.accept(e.callee, is_callee=True))
+            if isinstance(typeddict_callable, CallableType):
+                typeddict_type = get_proper_type(typeddict_callable.ret_type)
+                assert isinstance(typeddict_type, TypedDictType)
+                return self.check_typeddict_call(
+                    typeddict_type, e.arg_kinds, e.arg_names, e.args, e, typeddict_callable
+                )
+        if (
+            isinstance(e.callee, NameExpr)
+            and e.callee.name in ("isinstance", "issubclass")
+            and len(e.args) == 2
+        ):
+            for typ in mypy.checker.flatten(e.args[1]):
+                node = None
+                if isinstance(typ, NameExpr):
+                    try:
+                        node = self.chk.lookup_qualified(typ.name)
+                    except KeyError:
+                        # Undefined names should already be reported in semantic analysis.
+                        pass
+                if is_expr_literal_type(typ):
+                    self.msg.cannot_use_function_with_type(e.callee.name, "Literal", e)
+                    continue
+                if (
+                    node
+                    and isinstance(node.node, TypeAlias)
+                    and isinstance(get_proper_type(node.node.target), AnyType)
+                ):
+                    self.msg.cannot_use_function_with_type(e.callee.name, "Any", e)
+                    continue
+                if (
+                    isinstance(typ, IndexExpr)
+                    and isinstance(typ.analyzed, (TypeApplication, TypeAliasExpr))
+                ) or (
+                    isinstance(typ, NameExpr)
+                    and node
+                    and isinstance(node.node, TypeAlias)
+                    and not node.node.no_args
+                ):
+                    self.msg.type_arguments_not_allowed(e)
+                if isinstance(typ, RefExpr) and isinstance(typ.node, TypeInfo):
+                    if typ.node.typeddict_type:
+                        self.msg.cannot_use_function_with_type(e.callee.name, "TypedDict", e)
+                    elif typ.node.is_newtype:
+                        self.msg.cannot_use_function_with_type(e.callee.name, "NewType", e)
+        self.try_infer_partial_type(e)
+        type_context = None
+        if isinstance(e.callee, LambdaExpr):
+            formal_to_actual = map_actuals_to_formals(
+                e.arg_kinds,
+                e.arg_names,
+                e.callee.arg_kinds,
+                e.callee.arg_names,
+                lambda i: self.accept(e.args[i]),
+            )
+
+            arg_types = [
+                join.join_type_list([self.accept(e.args[j]) for j in formal_to_actual[i]])
+                for i in range(len(e.callee.arg_kinds))
+            ]
+            type_context = CallableType(
+                arg_types,
+                e.callee.arg_kinds,
+                e.callee.arg_names,
+                ret_type=self.object_type(),
+                fallback=self.named_type("builtins.function"),
+            )
+        callee_type = get_proper_type(
+            self.accept(e.callee, type_context, always_allow_any=True, is_callee=True)
+        )
+        if (
+            self.chk.options.disallow_untyped_calls
+            and self.chk.in_checked_function()
+            and isinstance(callee_type, CallableType)
+            and callee_type.implicit
+        ):
+            self.msg.untyped_function_call(callee_type, e)
+
+        # Figure out the full name of the callee for plugin lookup.
+        object_type = None
+        member = None
+        fullname = None
+        if isinstance(e.callee, RefExpr):
+            # There are two special cases where plugins might act:
+            # * A "static" reference/alias to a class or function;
+            #   get_function_hook() will be invoked for these.
+            fullname = e.callee.fullname or None
+            if isinstance(e.callee.node, TypeAlias):
+                target = get_proper_type(e.callee.node.target)
+                if isinstance(target, Instance):
+                    fullname = target.type.fullname
+            # * Call to a method on object that has a full name (see
+            #   method_fullname() for details on supported objects);
+            #   get_method_hook() and get_method_signature_hook() will
+            #   be invoked for these.
+            if (
+                not fullname
+                and isinstance(e.callee, MemberExpr)
+                and self.chk.has_type(e.callee.expr)
+            ):
+                member = e.callee.name
+                object_type = self.chk.lookup_type(e.callee.expr)
+        ret_type = self.check_call_expr_with_callee_type(
+            callee_type, e, fullname, object_type, member
+        )
+        if isinstance(e.callee, RefExpr) and len(e.args) == 2:
+            if e.callee.fullname in ("builtins.isinstance", "builtins.issubclass"):
+                self.check_runtime_protocol_test(e)
+            if e.callee.fullname == "builtins.issubclass":
+                self.check_protocol_issubclass(e)
+        if isinstance(e.callee, MemberExpr) and e.callee.name == "format":
+            self.check_str_format_call(e)
+        ret_type = get_proper_type(ret_type)
+        if isinstance(ret_type, UnionType):
+            ret_type = make_simplified_union(ret_type.items)
+        if isinstance(ret_type, UninhabitedType) and not ret_type.ambiguous:
+            self.chk.binder.unreachable()
+        # Warn on calls to functions that always return None. The check
+        # of ret_type is both a common-case optimization and prevents reporting
+        # the error in dynamic functions (where it will be Any).
+        if (
+            not allow_none_return
+            and isinstance(ret_type, NoneType)
+            and self.always_returns_none(e.callee)
+        ):
+            self.chk.msg.does_not_return_value(callee_type, e)
+            return AnyType(TypeOfAny.from_error)
+        return ret_type
+
+    def check_str_format_call(self, e: CallExpr) -> None:
+        """More precise type checking for str.format() calls on literals."""
+        assert isinstance(e.callee, MemberExpr)
+        format_value = None
+        if isinstance(e.callee.expr, StrExpr):
+            format_value = e.callee.expr.value
+        elif self.chk.has_type(e.callee.expr):
+            base_typ = try_getting_literal(self.chk.lookup_type(e.callee.expr))
+            if isinstance(base_typ, LiteralType) and isinstance(base_typ.value, str):
+                format_value = base_typ.value
+        if format_value is not None:
+            self.strfrm_checker.check_str_format_call(e, format_value)
+
+    def method_fullname(self, object_type: Type, method_name: str) -> str | None:
+        """Convert a method name to a fully qualified name, based on the type of the object that
+        it is invoked on. Return `None` if the name of `object_type` cannot be determined.
+        """
+        object_type = get_proper_type(object_type)
+
+        if isinstance(object_type, CallableType) and object_type.is_type_obj():
+            # For class method calls, object_type is a callable representing the class object.
+            # We "unwrap" it to a regular type, as the class/instance method difference doesn't
+            # affect the fully qualified name.
+            object_type = get_proper_type(object_type.ret_type)
+        elif isinstance(object_type, TypeType):
+            object_type = object_type.item
+
+        type_name = None
+        if isinstance(object_type, Instance):
+            type_name = object_type.type.fullname
+        elif isinstance(object_type, (TypedDictType, LiteralType)):
+            info = object_type.fallback.type.get_containing_type_info(method_name)
+            type_name = info.fullname if info is not None else None
+        elif isinstance(object_type, TupleType):
+            type_name = tuple_fallback(object_type).type.fullname
+
+        if type_name:
+            return f"{type_name}.{method_name}"
+        else:
+            return None
+
+    def always_returns_none(self, node: Expression) -> bool:
+        """Check if `node` refers to something explicitly annotated as only returning None."""
+        if isinstance(node, RefExpr):
+            if self.defn_returns_none(node.node):
+                return True
+        if isinstance(node, MemberExpr) and node.node is None:  # instance or class attribute
+            typ = get_proper_type(self.chk.lookup_type(node.expr))
+            if isinstance(typ, Instance):
+                info = typ.type
+            elif isinstance(typ, CallableType) and typ.is_type_obj():
+                ret_type = get_proper_type(typ.ret_type)
+                if isinstance(ret_type, Instance):
+                    info = ret_type.type
+                else:
+                    return False
+            else:
+                return False
+            sym = info.get(node.name)
+            if sym and self.defn_returns_none(sym.node):
+                return True
+        return False
+
+    def defn_returns_none(self, defn: SymbolNode | None) -> bool:
+        """Check if `defn` can _only_ return None."""
+        if isinstance(defn, FuncDef):
+            return isinstance(defn.type, CallableType) and isinstance(
+                get_proper_type(defn.type.ret_type), NoneType
+            )
+        if isinstance(defn, OverloadedFuncDef):
+            return all(self.defn_returns_none(item) for item in defn.items)
+        if isinstance(defn, Var):
+            typ = get_proper_type(defn.type)
+            if (
+                not defn.is_inferred
+                and isinstance(typ, CallableType)
+                and isinstance(get_proper_type(typ.ret_type), NoneType)
+            ):
+                return True
+            if isinstance(typ, Instance):
+                sym = typ.type.get("__call__")
+                if sym and self.defn_returns_none(sym.node):
+                    return True
+        return False
+
+    def check_runtime_protocol_test(self, e: CallExpr) -> None:
+        for expr in mypy.checker.flatten(e.args[1]):
+            tp = get_proper_type(self.chk.lookup_type(expr))
+            if (
+                isinstance(tp, CallableType)
+                and tp.is_type_obj()
+                and tp.type_object().is_protocol
+                and not tp.type_object().runtime_protocol
+            ):
+                self.chk.fail(message_registry.RUNTIME_PROTOCOL_EXPECTED, e)
+
+    def check_protocol_issubclass(self, e: CallExpr) -> None:
+        for expr in mypy.checker.flatten(e.args[1]):
+            tp = get_proper_type(self.chk.lookup_type(expr))
+            if isinstance(tp, CallableType) and tp.is_type_obj() and tp.type_object().is_protocol:
+                attr_members = non_method_protocol_members(tp.type_object())
+                if attr_members:
+                    self.chk.msg.report_non_method_protocol(tp.type_object(), attr_members, e)
+
+    def check_typeddict_call(
+        self,
+        callee: TypedDictType,
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None],
+        args: list[Expression],
+        context: Context,
+        orig_callee: Type | None,
+    ) -> Type:
+        if args and all([ak in (ARG_NAMED, ARG_STAR2) for ak in arg_kinds]):
+            # ex: Point(x=42, y=1337, **extras)
+            # This is a bit ugly, but this is a price for supporting all possible syntax
+            # variants for TypedDict constructors.
+            kwargs = zip([StrExpr(n) if n is not None else None for n in arg_names], args)
+            result = self.validate_typeddict_kwargs(kwargs=kwargs, callee=callee)
+            if result is not None:
+                validated_kwargs, always_present_keys = result
+                return self.check_typeddict_call_with_kwargs(
+                    callee, validated_kwargs, context, orig_callee, always_present_keys
+                )
+            return AnyType(TypeOfAny.from_error)
+
+        if len(args) == 1 and arg_kinds[0] == ARG_POS:
+            unique_arg = args[0]
+            if isinstance(unique_arg, DictExpr):
+                # ex: Point({'x': 42, 'y': 1337, **extras})
+                return self.check_typeddict_call_with_dict(
+                    callee, unique_arg.items, context, orig_callee
+                )
+            if isinstance(unique_arg, CallExpr) and isinstance(unique_arg.analyzed, DictExpr):
+                # ex: Point(dict(x=42, y=1337, **extras))
+                return self.check_typeddict_call_with_dict(
+                    callee, unique_arg.analyzed.items, context, orig_callee
+                )
+
+        if not args:
+            # ex: EmptyDict()
+            return self.check_typeddict_call_with_kwargs(callee, {}, context, orig_callee, set())
+
+        self.chk.fail(message_registry.INVALID_TYPEDDICT_ARGS, context)
+        return AnyType(TypeOfAny.from_error)
+
+    def validate_typeddict_kwargs(
+        self, kwargs: Iterable[tuple[Expression | None, Expression]], callee: TypedDictType
+    ) -> tuple[dict[str, list[Expression]], set[str]] | None:
+        # All (actual or mapped from ** unpacks) expressions that can match given key.
+        result = defaultdict(list)
+        # Keys that are guaranteed to be present no matter what (e.g. for all items of a union)
+        always_present_keys = set()
+        # Indicates latest encountered ** unpack among items.
+        last_star_found = None
+
+        for item_name_expr, item_arg in kwargs:
+            if item_name_expr:
+                key_type = self.accept(item_name_expr)
+                values = try_getting_str_literals(item_name_expr, key_type)
+                literal_value = None
+                if values and len(values) == 1:
+                    literal_value = values[0]
+                if literal_value is None:
+                    key_context = item_name_expr or item_arg
+                    self.chk.fail(
+                        message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL,
+                        key_context,
+                        code=codes.LITERAL_REQ,
+                    )
+                    return None
+                else:
+                    # A directly present key unconditionally shadows all previously found
+                    # values from ** items.
+                    # TODO: for duplicate keys, type-check all values.
+                    result[literal_value] = [item_arg]
+                    always_present_keys.add(literal_value)
+            else:
+                last_star_found = item_arg
+                if not self.validate_star_typeddict_item(
+                    item_arg, callee, result, always_present_keys
+                ):
+                    return None
+        if self.chk.options.extra_checks and last_star_found is not None:
+            absent_keys = []
+            for key in callee.items:
+                if key not in callee.required_keys and key not in result:
+                    absent_keys.append(key)
+            if absent_keys:
+                # Having an optional key not explicitly declared by a ** unpacked
+                # TypedDict is unsafe, it may be an (incompatible) subtype at runtime.
+                # TODO: catch the cases where a declared key is overridden by a subsequent
+                # ** item without it (and not again overriden with complete ** item).
+                self.msg.non_required_keys_absent_with_star(absent_keys, last_star_found)
+        return result, always_present_keys
+
+    def validate_star_typeddict_item(
+        self,
+        item_arg: Expression,
+        callee: TypedDictType,
+        result: dict[str, list[Expression]],
+        always_present_keys: set[str],
+    ) -> bool:
+        """Update keys/expressions from a ** expression in TypedDict constructor.
+
+        Note `result` and `always_present_keys` are updated in place. Return true if the
+        expression `item_arg` may valid in `callee` TypedDict context.
+        """
+        with self.chk.local_type_map(), self.msg.filter_errors():
+            inferred = get_proper_type(self.accept(item_arg, type_context=callee))
+        possible_tds = []
+        if isinstance(inferred, TypedDictType):
+            possible_tds = [inferred]
+        elif isinstance(inferred, UnionType):
+            for item in get_proper_types(inferred.relevant_items()):
+                if isinstance(item, TypedDictType):
+                    possible_tds.append(item)
+                elif not self.valid_unpack_fallback_item(item):
+                    self.msg.unsupported_target_for_star_typeddict(item, item_arg)
+                    return False
+        elif not self.valid_unpack_fallback_item(inferred):
+            self.msg.unsupported_target_for_star_typeddict(inferred, item_arg)
+            return False
+        all_keys: set[str] = set()
+        for td in possible_tds:
+            all_keys |= td.items.keys()
+        for key in all_keys:
+            arg = TempNode(
+                UnionType.make_union([td.items[key] for td in possible_tds if key in td.items])
+            )
+            arg.set_line(item_arg)
+            if all(key in td.required_keys for td in possible_tds):
+                always_present_keys.add(key)
+                # Always present keys override previously found values. This is done
+                # to support use cases like `Config({**defaults, **overrides})`, where
+                # some `overrides` types are narrower that types in `defaults`, and
+                # former are too wide for `Config`.
+                if result[key]:
+                    first = result[key][0]
+                    if not isinstance(first, TempNode):
+                        # We must always preserve any non-synthetic values, so that
+                        # we will accept them even if they are shadowed.
+                        result[key] = [first, arg]
+                    else:
+                        result[key] = [arg]
+                else:
+                    result[key] = [arg]
+            else:
+                # If this key is not required at least in some item of a union
+                # it may not shadow previous item, so we need to type check both.
+                result[key].append(arg)
+        return True
+
+    def valid_unpack_fallback_item(self, typ: ProperType) -> bool:
+        if isinstance(typ, AnyType):
+            return True
+        if not isinstance(typ, Instance) or not typ.type.has_base("typing.Mapping"):
+            return False
+        mapped = map_instance_to_supertype(typ, self.chk.lookup_typeinfo("typing.Mapping"))
+        return all(isinstance(a, AnyType) for a in get_proper_types(mapped.args))
+
+    def match_typeddict_call_with_dict(
+        self,
+        callee: TypedDictType,
+        kwargs: list[tuple[Expression | None, Expression]],
+        context: Context,
+    ) -> bool:
+        result = self.validate_typeddict_kwargs(kwargs=kwargs, callee=callee)
+        if result is not None:
+            validated_kwargs, _ = result
+            return callee.required_keys <= set(validated_kwargs.keys()) <= set(callee.items.keys())
+        else:
+            return False
+
+    def check_typeddict_call_with_dict(
+        self,
+        callee: TypedDictType,
+        kwargs: list[tuple[Expression | None, Expression]],
+        context: Context,
+        orig_callee: Type | None,
+    ) -> Type:
+        result = self.validate_typeddict_kwargs(kwargs=kwargs, callee=callee)
+        if result is not None:
+            validated_kwargs, always_present_keys = result
+            return self.check_typeddict_call_with_kwargs(
+                callee,
+                kwargs=validated_kwargs,
+                context=context,
+                orig_callee=orig_callee,
+                always_present_keys=always_present_keys,
+            )
+        else:
+            return AnyType(TypeOfAny.from_error)
+
+    def typeddict_callable(self, info: TypeInfo) -> CallableType:
+        """Construct a reasonable type for a TypedDict type in runtime context.
+
+        If it appears as a callee, it will be special-cased anyway, e.g. it is
+        also allowed to accept a single positional argument if it is a dict literal.
+
+        Note it is not safe to move this to type_object_type() since it will crash
+        on plugin-generated TypedDicts, that may not have the special_alias.
+        """
+        assert info.special_alias is not None
+        target = info.special_alias.target
+        assert isinstance(target, ProperType) and isinstance(target, TypedDictType)
+        expected_types = list(target.items.values())
+        kinds = [ArgKind.ARG_NAMED] * len(expected_types)
+        names = list(target.items.keys())
+        return CallableType(
+            expected_types,
+            kinds,
+            names,
+            target,
+            self.named_type("builtins.type"),
+            variables=info.defn.type_vars,
+        )
+
+    def typeddict_callable_from_context(self, callee: TypedDictType) -> CallableType:
+        return CallableType(
+            list(callee.items.values()),
+            [ArgKind.ARG_NAMED] * len(callee.items),
+            list(callee.items.keys()),
+            callee,
+            self.named_type("builtins.type"),
+        )
+
+    def check_typeddict_call_with_kwargs(
+        self,
+        callee: TypedDictType,
+        kwargs: dict[str, list[Expression]],
+        context: Context,
+        orig_callee: Type | None,
+        always_present_keys: set[str],
+    ) -> Type:
+        actual_keys = kwargs.keys()
+        if not (
+            callee.required_keys <= always_present_keys and actual_keys <= callee.items.keys()
+        ):
+            if not (actual_keys <= callee.items.keys()):
+                self.msg.unexpected_typeddict_keys(
+                    callee,
+                    expected_keys=[
+                        key
+                        for key in callee.items.keys()
+                        if key in callee.required_keys or key in actual_keys
+                    ],
+                    actual_keys=list(actual_keys),
+                    context=context,
+                )
+            if not (callee.required_keys <= always_present_keys):
+                self.msg.unexpected_typeddict_keys(
+                    callee,
+                    expected_keys=[
+                        key for key in callee.items.keys() if key in callee.required_keys
+                    ],
+                    actual_keys=[
+                        key for key in always_present_keys if key in callee.required_keys
+                    ],
+                    context=context,
+                )
+            if callee.required_keys > actual_keys:
+                # found_set is a sub-set of the required_keys
+                # This means we're missing some keys and as such, we can't
+                # properly type the object
+                return AnyType(TypeOfAny.from_error)
+
+        orig_callee = get_proper_type(orig_callee)
+        if isinstance(orig_callee, CallableType):
+            infer_callee = orig_callee
+        else:
+            # Try reconstructing from type context.
+            if callee.fallback.type.special_alias is not None:
+                infer_callee = self.typeddict_callable(callee.fallback.type)
+            else:
+                # Likely a TypedDict type generated by a plugin.
+                infer_callee = self.typeddict_callable_from_context(callee)
+
+        # We don't show any errors, just infer types in a generic TypedDict type,
+        # a custom error message will be given below, if there are errors.
+        with self.msg.filter_errors(), self.chk.local_type_map():
+            orig_ret_type, _ = self.check_callable_call(
+                infer_callee,
+                # We use first expression for each key to infer type variables of a generic
+                # TypedDict. This is a bit arbitrary, but in most cases will work better than
+                # trying to infer a union or a join.
+                [args[0] for args in kwargs.values()],
+                [ArgKind.ARG_NAMED] * len(kwargs),
+                context,
+                list(kwargs.keys()),
+                None,
+                None,
+                None,
+            )
+
+        ret_type = get_proper_type(orig_ret_type)
+        if not isinstance(ret_type, TypedDictType):
+            # If something went really wrong, type-check call with original type,
+            # this may give a better error message.
+            ret_type = callee
+
+        for item_name, item_expected_type in ret_type.items.items():
+            if item_name in kwargs:
+                item_values = kwargs[item_name]
+                for item_value in item_values:
+                    self.chk.check_simple_assignment(
+                        lvalue_type=item_expected_type,
+                        rvalue=item_value,
+                        context=item_value,
+                        msg=ErrorMessage(
+                            message_registry.INCOMPATIBLE_TYPES.value, code=codes.TYPEDDICT_ITEM
+                        ),
+                        lvalue_name=f'TypedDict item "{item_name}"',
+                        rvalue_name="expression",
+                    )
+
+        return orig_ret_type
+
+    def get_partial_self_var(self, expr: MemberExpr) -> Var | None:
+        """Get variable node for a partial self attribute.
+
+        If the expression is not a self attribute, or attribute is not variable,
+        or variable is not partial, return None.
+        """
+        if not (
+            isinstance(expr.expr, NameExpr)
+            and isinstance(expr.expr.node, Var)
+            and expr.expr.node.is_self
+        ):
+            # Not a self.attr expression.
+            return None
+        info = self.chk.scope.enclosing_class()
+        if not info or expr.name not in info.names:
+            # Don't mess with partial types in superclasses.
+            return None
+        sym = info.names[expr.name]
+        if isinstance(sym.node, Var) and isinstance(sym.node.type, PartialType):
+            return sym.node
+        return None
+
+    # Types and methods that can be used to infer partial types.
+    item_args: ClassVar[dict[str, list[str]]] = {
+        "builtins.list": ["append"],
+        "builtins.set": ["add", "discard"],
+    }
+    container_args: ClassVar[dict[str, dict[str, list[str]]]] = {
+        "builtins.list": {"extend": ["builtins.list"]},
+        "builtins.dict": {"update": ["builtins.dict"]},
+        "collections.OrderedDict": {"update": ["builtins.dict"]},
+        "builtins.set": {"update": ["builtins.set", "builtins.list"]},
+    }
+
+    def try_infer_partial_type(self, e: CallExpr) -> None:
+        """Try to make partial type precise from a call."""
+        if not isinstance(e.callee, MemberExpr):
+            return
+        callee = e.callee
+        if isinstance(callee.expr, RefExpr):
+            # Call a method with a RefExpr callee, such as 'x.method(...)'.
+            ret = self.get_partial_var(callee.expr)
+            if ret is None:
+                return
+            var, partial_types = ret
+            typ = self.try_infer_partial_value_type_from_call(e, callee.name, var)
+            # Var may be deleted from partial_types in try_infer_partial_value_type_from_call
+            if typ is not None and var in partial_types:
+                var.type = typ
+                del partial_types[var]
+        elif isinstance(callee.expr, IndexExpr) and isinstance(callee.expr.base, RefExpr):
+            # Call 'x[y].method(...)'; may infer type of 'x' if it's a partial defaultdict.
+            if callee.expr.analyzed is not None:
+                return  # A special form
+            base = callee.expr.base
+            index = callee.expr.index
+            ret = self.get_partial_var(base)
+            if ret is None:
+                return
+            var, partial_types = ret
+            partial_type = get_partial_instance_type(var.type)
+            if partial_type is None or partial_type.value_type is None:
+                return
+            value_type = self.try_infer_partial_value_type_from_call(e, callee.name, var)
+            if value_type is not None:
+                # Infer key type.
+                key_type = self.accept(index)
+                if mypy.checker.is_valid_inferred_type(key_type):
+                    # Store inferred partial type.
+                    assert partial_type.type is not None
+                    typename = partial_type.type.fullname
+                    var.type = self.chk.named_generic_type(typename, [key_type, value_type])
+                    del partial_types[var]
+
+    def get_partial_var(self, ref: RefExpr) -> tuple[Var, dict[Var, Context]] | None:
+        var = ref.node
+        if var is None and isinstance(ref, MemberExpr):
+            var = self.get_partial_self_var(ref)
+        if not isinstance(var, Var):
+            return None
+        partial_types = self.chk.find_partial_types(var)
+        if partial_types is None:
+            return None
+        return var, partial_types
+
+    def try_infer_partial_value_type_from_call(
+        self, e: CallExpr, methodname: str, var: Var
+    ) -> Instance | None:
+        """Try to make partial type precise from a call such as 'x.append(y)'."""
+        if self.chk.current_node_deferred:
+            return None
+        partial_type = get_partial_instance_type(var.type)
+        if partial_type is None:
+            return None
+        if partial_type.value_type:
+            typename = partial_type.value_type.type.fullname
+        else:
+            assert partial_type.type is not None
+            typename = partial_type.type.fullname
+        # Sometimes we can infer a full type for a partial List, Dict or Set type.
+        # TODO: Don't infer argument expression twice.
+        if (
+            typename in self.item_args
+            and methodname in self.item_args[typename]
+            and e.arg_kinds == [ARG_POS]
+        ):
+            item_type = self.accept(e.args[0])
+            if mypy.checker.is_valid_inferred_type(item_type):
+                return self.chk.named_generic_type(typename, [item_type])
+        elif (
+            typename in self.container_args
+            and methodname in self.container_args[typename]
+            and e.arg_kinds == [ARG_POS]
+        ):
+            arg_type = get_proper_type(self.accept(e.args[0]))
+            if isinstance(arg_type, Instance):
+                arg_typename = arg_type.type.fullname
+                if arg_typename in self.container_args[typename][methodname]:
+                    if all(
+                        mypy.checker.is_valid_inferred_type(item_type)
+                        for item_type in arg_type.args
+                    ):
+                        return self.chk.named_generic_type(typename, list(arg_type.args))
+            elif isinstance(arg_type, AnyType):
+                return self.chk.named_type(typename)
+
+        return None
+
+    def apply_function_plugin(
+        self,
+        callee: CallableType,
+        arg_kinds: list[ArgKind],
+        arg_types: list[Type],
+        arg_names: Sequence[str | None] | None,
+        formal_to_actual: list[list[int]],
+        args: list[Expression],
+        fullname: str,
+        object_type: Type | None,
+        context: Context,
+    ) -> Type:
+        """Use special case logic to infer the return type of a specific named function/method.
+
+        Caller must ensure that a plugin hook exists. There are two different cases:
+
+        - If object_type is None, the caller must ensure that a function hook exists
+          for fullname.
+        - If object_type is not None, the caller must ensure that a method hook exists
+          for fullname.
+
+        Return the inferred return type.
+        """
+        num_formals = len(callee.arg_types)
+        formal_arg_types: list[list[Type]] = [[] for _ in range(num_formals)]
+        formal_arg_exprs: list[list[Expression]] = [[] for _ in range(num_formals)]
+        formal_arg_names: list[list[str | None]] = [[] for _ in range(num_formals)]
+        formal_arg_kinds: list[list[ArgKind]] = [[] for _ in range(num_formals)]
+        for formal, actuals in enumerate(formal_to_actual):
+            for actual in actuals:
+                formal_arg_types[formal].append(arg_types[actual])
+                formal_arg_exprs[formal].append(args[actual])
+                if arg_names:
+                    formal_arg_names[formal].append(arg_names[actual])
+                formal_arg_kinds[formal].append(arg_kinds[actual])
+
+        if object_type is None:
+            # Apply function plugin
+            callback = self.plugin.get_function_hook(fullname)
+            assert callback is not None  # Assume that caller ensures this
+            return callback(
+                FunctionContext(
+                    formal_arg_types,
+                    formal_arg_kinds,
+                    callee.arg_names,
+                    formal_arg_names,
+                    callee.ret_type,
+                    formal_arg_exprs,
+                    context,
+                    self.chk,
+                )
+            )
+        else:
+            # Apply method plugin
+            method_callback = self.plugin.get_method_hook(fullname)
+            assert method_callback is not None  # Assume that caller ensures this
+            object_type = get_proper_type(object_type)
+            return method_callback(
+                MethodContext(
+                    object_type,
+                    formal_arg_types,
+                    formal_arg_kinds,
+                    callee.arg_names,
+                    formal_arg_names,
+                    callee.ret_type,
+                    formal_arg_exprs,
+                    context,
+                    self.chk,
+                )
+            )
+
+    def apply_signature_hook(
+        self,
+        callee: FunctionLike,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        hook: Callable[[list[list[Expression]], CallableType], FunctionLike],
+    ) -> FunctionLike:
+        """Helper to apply a signature hook for either a function or method"""
+        if isinstance(callee, CallableType):
+            num_formals = len(callee.arg_kinds)
+            formal_to_actual = map_actuals_to_formals(
+                arg_kinds,
+                arg_names,
+                callee.arg_kinds,
+                callee.arg_names,
+                lambda i: self.accept(args[i]),
+            )
+            formal_arg_exprs: list[list[Expression]] = [[] for _ in range(num_formals)]
+            for formal, actuals in enumerate(formal_to_actual):
+                for actual in actuals:
+                    formal_arg_exprs[formal].append(args[actual])
+            return hook(formal_arg_exprs, callee)
+        else:
+            assert isinstance(callee, Overloaded)
+            items = []
+            for item in callee.items:
+                adjusted = self.apply_signature_hook(item, args, arg_kinds, arg_names, hook)
+                assert isinstance(adjusted, CallableType)
+                items.append(adjusted)
+            return Overloaded(items)
+
+    def apply_function_signature_hook(
+        self,
+        callee: FunctionLike,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        arg_names: Sequence[str | None] | None,
+        signature_hook: Callable[[FunctionSigContext], FunctionLike],
+    ) -> FunctionLike:
+        """Apply a plugin hook that may infer a more precise signature for a function."""
+        return self.apply_signature_hook(
+            callee,
+            args,
+            arg_kinds,
+            arg_names,
+            (lambda args, sig: signature_hook(FunctionSigContext(args, sig, context, self.chk))),
+        )
+
+    def apply_method_signature_hook(
+        self,
+        callee: FunctionLike,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        arg_names: Sequence[str | None] | None,
+        object_type: Type,
+        signature_hook: Callable[[MethodSigContext], FunctionLike],
+    ) -> FunctionLike:
+        """Apply a plugin hook that may infer a more precise signature for a method."""
+        pobject_type = get_proper_type(object_type)
+        return self.apply_signature_hook(
+            callee,
+            args,
+            arg_kinds,
+            arg_names,
+            (
+                lambda args, sig: signature_hook(
+                    MethodSigContext(pobject_type, args, sig, context, self.chk)
+                )
+            ),
+        )
+
+    def transform_callee_type(
+        self,
+        callable_name: str | None,
+        callee: Type,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        arg_names: Sequence[str | None] | None = None,
+        object_type: Type | None = None,
+    ) -> Type:
+        """Attempt to determine a more accurate signature for a method call.
+
+        This is done by looking up and applying a method signature hook (if one exists for the
+        given method name).
+
+        If no matching method signature hook is found, callee is returned unmodified. The same
+        happens if the arguments refer to a non-method callable (this is allowed so that the code
+        calling transform_callee_type needs to perform fewer boilerplate checks).
+
+        Note: this method is *not* called automatically as part of check_call, because in some
+        cases check_call is called multiple times while checking a single call (for example when
+        dealing with overloads). Instead, this method needs to be called explicitly
+        (if appropriate) before the signature is passed to check_call.
+        """
+        callee = get_proper_type(callee)
+        if callable_name is not None and isinstance(callee, FunctionLike):
+            if object_type is not None:
+                method_sig_hook = self.plugin.get_method_signature_hook(callable_name)
+                if method_sig_hook:
+                    return self.apply_method_signature_hook(
+                        callee, args, arg_kinds, context, arg_names, object_type, method_sig_hook
+                    )
+            else:
+                function_sig_hook = self.plugin.get_function_signature_hook(callable_name)
+                if function_sig_hook:
+                    return self.apply_function_signature_hook(
+                        callee, args, arg_kinds, context, arg_names, function_sig_hook
+                    )
+
+        return callee
+
+    def check_call_expr_with_callee_type(
+        self,
+        callee_type: Type,
+        e: CallExpr,
+        callable_name: str | None,
+        object_type: Type | None,
+        member: str | None = None,
+    ) -> Type:
+        """Type check call expression.
+
+        The callee_type should be used as the type of callee expression. In particular,
+        in case of a union type this can be a particular item of the union, so that we can
+        apply plugin hooks to each item.
+
+        The 'member', 'callable_name' and 'object_type' are only used to call plugin hooks.
+        If 'callable_name' is None but 'member' is not None (member call), try constructing
+        'callable_name' using 'object_type' (the base type on which the method is called),
+        for example 'typing.Mapping.get'.
+        """
+        if callable_name is None and member is not None:
+            assert object_type is not None
+            callable_name = self.method_fullname(object_type, member)
+        object_type = get_proper_type(object_type)
+        if callable_name:
+            # Try to refine the call signature using plugin hooks before checking the call.
+            callee_type = self.transform_callee_type(
+                callable_name, callee_type, e.args, e.arg_kinds, e, e.arg_names, object_type
+            )
+        # Unions are special-cased to allow plugins to act on each item in the union.
+        elif member is not None and isinstance(object_type, UnionType):
+            return self.check_union_call_expr(e, object_type, member)
+        ret_type, callee_type = self.check_call(
+            callee_type,
+            e.args,
+            e.arg_kinds,
+            e,
+            e.arg_names,
+            callable_node=e.callee,
+            callable_name=callable_name,
+            object_type=object_type,
+        )
+        proper_callee = get_proper_type(callee_type)
+        if (
+            isinstance(e.callee, RefExpr)
+            and isinstance(proper_callee, CallableType)
+            and proper_callee.type_guard is not None
+        ):
+            # Cache it for find_isinstance_check()
+            e.callee.type_guard = proper_callee.type_guard
+        return ret_type
+
+    def check_union_call_expr(self, e: CallExpr, object_type: UnionType, member: str) -> Type:
+        """Type check calling a member expression where the base type is a union."""
+        res: list[Type] = []
+        for typ in object_type.relevant_items():
+            # Member access errors are already reported when visiting the member expression.
+            with self.msg.filter_errors():
+                item = analyze_member_access(
+                    member,
+                    typ,
+                    e,
+                    False,
+                    False,
+                    False,
+                    self.msg,
+                    original_type=object_type,
+                    chk=self.chk,
+                    in_literal_context=self.is_literal_context(),
+                    self_type=typ,
+                )
+            narrowed = self.narrow_type_from_binder(e.callee, item, skip_non_overlapping=True)
+            if narrowed is None:
+                continue
+            callable_name = self.method_fullname(typ, member)
+            item_object_type = typ if callable_name else None
+            res.append(
+                self.check_call_expr_with_callee_type(narrowed, e, callable_name, item_object_type)
+            )
+        return make_simplified_union(res)
+
+    def check_call(
+        self,
+        callee: Type,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        arg_names: Sequence[str | None] | None = None,
+        callable_node: Expression | None = None,
+        callable_name: str | None = None,
+        object_type: Type | None = None,
+    ) -> tuple[Type, Type]:
+        """Type check a call.
+
+        Also infer type arguments if the callee is a generic function.
+
+        Return (result type, inferred callee type).
+
+        Arguments:
+            callee: type of the called value
+            args: actual argument expressions
+            arg_kinds: contains nodes.ARG_* constant for each argument in args
+                 describing whether the argument is positional, *arg, etc.
+            context: current expression context, used for inference.
+            arg_names: names of arguments (optional)
+            callable_node: associate the inferred callable type to this node,
+                if specified
+            callable_name: Fully-qualified name of the function/method to call,
+                or None if unavailable (examples: 'builtins.open', 'typing.Mapping.get')
+            object_type: If callable_name refers to a method, the type of the object
+                on which the method is being called
+        """
+        callee = get_proper_type(callee)
+
+        if isinstance(callee, CallableType):
+            return self.check_callable_call(
+                callee,
+                args,
+                arg_kinds,
+                context,
+                arg_names,
+                callable_node,
+                callable_name,
+                object_type,
+            )
+        elif isinstance(callee, Overloaded):
+            return self.check_overload_call(
+                callee, args, arg_kinds, arg_names, callable_name, object_type, context
+            )
+        elif isinstance(callee, AnyType) or not self.chk.in_checked_function():
+            return self.check_any_type_call(args, callee)
+        elif isinstance(callee, UnionType):
+            return self.check_union_call(callee, args, arg_kinds, arg_names, context)
+        elif isinstance(callee, Instance):
+            call_function = analyze_member_access(
+                "__call__",
+                callee,
+                context,
+                is_lvalue=False,
+                is_super=False,
+                is_operator=True,
+                msg=self.msg,
+                original_type=callee,
+                chk=self.chk,
+                in_literal_context=self.is_literal_context(),
+            )
+            callable_name = callee.type.fullname + ".__call__"
+            # Apply method signature hook, if one exists
+            call_function = self.transform_callee_type(
+                callable_name, call_function, args, arg_kinds, context, arg_names, callee
+            )
+            result = self.check_call(
+                call_function,
+                args,
+                arg_kinds,
+                context,
+                arg_names,
+                callable_node,
+                callable_name,
+                callee,
+            )
+            if callable_node:
+                # check_call() stored "call_function" as the type, which is incorrect.
+                # Override the type.
+                self.chk.store_type(callable_node, callee)
+            return result
+        elif isinstance(callee, TypeVarType):
+            return self.check_call(
+                callee.upper_bound, args, arg_kinds, context, arg_names, callable_node
+            )
+        elif isinstance(callee, TypeType):
+            item = self.analyze_type_type_callee(callee.item, context)
+            return self.check_call(item, args, arg_kinds, context, arg_names, callable_node)
+        elif isinstance(callee, TupleType):
+            return self.check_call(
+                tuple_fallback(callee),
+                args,
+                arg_kinds,
+                context,
+                arg_names,
+                callable_node,
+                callable_name,
+                object_type,
+            )
+        else:
+            return self.msg.not_callable(callee, context), AnyType(TypeOfAny.from_error)
+
+    def check_callable_call(
+        self,
+        callee: CallableType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        arg_names: Sequence[str | None] | None,
+        callable_node: Expression | None,
+        callable_name: str | None,
+        object_type: Type | None,
+    ) -> tuple[Type, Type]:
+        """Type check a call that targets a callable value.
+
+        See the docstring of check_call for more information.
+        """
+        # Always unpack **kwargs before checking a call.
+        callee = callee.with_unpacked_kwargs()
+        if callable_name is None and callee.name:
+            callable_name = callee.name
+        ret_type = get_proper_type(callee.ret_type)
+        if callee.is_type_obj() and isinstance(ret_type, Instance):
+            callable_name = ret_type.type.fullname
+        if isinstance(callable_node, RefExpr) and callable_node.fullname in ENUM_BASES:
+            # An Enum() call that failed SemanticAnalyzerPass2.check_enum_call().
+            return callee.ret_type, callee
+
+        if (
+            callee.is_type_obj()
+            and callee.type_object().is_protocol
+            # Exception for Type[...]
+            and not callee.from_type_type
+        ):
+            self.chk.fail(
+                message_registry.CANNOT_INSTANTIATE_PROTOCOL.format(callee.type_object().name),
+                context,
+            )
+        elif (
+            callee.is_type_obj()
+            and callee.type_object().is_abstract
+            # Exception for Type[...]
+            and not callee.from_type_type
+            and not callee.type_object().fallback_to_any
+        ):
+            type = callee.type_object()
+            # Determine whether the implicitly abstract attributes are functions with
+            # None-compatible return types.
+            abstract_attributes: dict[str, bool] = {}
+            for attr_name, abstract_status in type.abstract_attributes:
+                if abstract_status == IMPLICITLY_ABSTRACT:
+                    abstract_attributes[attr_name] = self.can_return_none(type, attr_name)
+                else:
+                    abstract_attributes[attr_name] = False
+            self.msg.cannot_instantiate_abstract_class(
+                callee.type_object().name, abstract_attributes, context
+            )
+
+        formal_to_actual = map_actuals_to_formals(
+            arg_kinds,
+            arg_names,
+            callee.arg_kinds,
+            callee.arg_names,
+            lambda i: self.accept(args[i]),
+        )
+
+        if callee.is_generic():
+            need_refresh = any(
+                isinstance(v, (ParamSpecType, TypeVarTupleType)) for v in callee.variables
+            )
+            callee = freshen_function_type_vars(callee)
+            callee = self.infer_function_type_arguments_using_context(callee, context)
+            if need_refresh:
+                # Argument kinds etc. may have changed due to
+                # ParamSpec or TypeVarTuple variables being replaced with an arbitrary
+                # number of arguments; recalculate actual-to-formal map
+                formal_to_actual = map_actuals_to_formals(
+                    arg_kinds,
+                    arg_names,
+                    callee.arg_kinds,
+                    callee.arg_names,
+                    lambda i: self.accept(args[i]),
+                )
+            callee = self.infer_function_type_arguments(
+                callee, args, arg_kinds, formal_to_actual, context
+            )
+            if need_refresh:
+                formal_to_actual = map_actuals_to_formals(
+                    arg_kinds,
+                    arg_names,
+                    callee.arg_kinds,
+                    callee.arg_names,
+                    lambda i: self.accept(args[i]),
+                )
+
+        param_spec = callee.param_spec()
+        if param_spec is not None and arg_kinds == [ARG_STAR, ARG_STAR2]:
+            arg1 = self.accept(args[0])
+            arg2 = self.accept(args[1])
+            if (
+                isinstance(arg1, ParamSpecType)
+                and isinstance(arg2, ParamSpecType)
+                and arg1.flavor == ParamSpecFlavor.ARGS
+                and arg2.flavor == ParamSpecFlavor.KWARGS
+                and arg1.id == arg2.id == param_spec.id
+            ):
+                return callee.ret_type, callee
+
+        arg_types = self.infer_arg_types_in_context(callee, args, arg_kinds, formal_to_actual)
+
+        self.check_argument_count(
+            callee,
+            arg_types,
+            arg_kinds,
+            arg_names,
+            formal_to_actual,
+            context,
+            object_type,
+            callable_name,
+        )
+
+        self.check_argument_types(
+            arg_types, arg_kinds, args, callee, formal_to_actual, context, object_type=object_type
+        )
+
+        if (
+            callee.is_type_obj()
+            and (len(arg_types) == 1)
+            and is_equivalent(callee.ret_type, self.named_type("builtins.type"))
+        ):
+            callee = callee.copy_modified(ret_type=TypeType.make_normalized(arg_types[0]))
+
+        if callable_node:
+            # Store the inferred callable type.
+            self.chk.store_type(callable_node, callee)
+
+        if callable_name and (
+            (object_type is None and self.plugin.get_function_hook(callable_name))
+            or (object_type is not None and self.plugin.get_method_hook(callable_name))
+        ):
+            new_ret_type = self.apply_function_plugin(
+                callee,
+                arg_kinds,
+                arg_types,
+                arg_names,
+                formal_to_actual,
+                args,
+                callable_name,
+                object_type,
+                context,
+            )
+            callee = callee.copy_modified(ret_type=new_ret_type)
+        return callee.ret_type, callee
+
+    def can_return_none(self, type: TypeInfo, attr_name: str) -> bool:
+        """Is the given attribute a method with a None-compatible return type?
+
+        Overloads are only checked if there is an implementation.
+        """
+        if not state.strict_optional:
+            # If strict-optional is not set, is_subtype(NoneType(), T) is always True.
+            # So, we cannot do anything useful here in that case.
+            return False
+        for base in type.mro:
+            symnode = base.names.get(attr_name)
+            if symnode is None:
+                continue
+            node = symnode.node
+            if isinstance(node, OverloadedFuncDef):
+                node = node.impl
+            if isinstance(node, Decorator):
+                node = node.func
+            if isinstance(node, FuncDef):
+                if node.type is not None:
+                    assert isinstance(node.type, CallableType)
+                    return is_subtype(NoneType(), node.type.ret_type)
+        return False
+
+    def analyze_type_type_callee(self, item: ProperType, context: Context) -> Type:
+        """Analyze the callee X in X(...) where X is Type[item].
+
+        Return a Y that we can pass to check_call(Y, ...).
+        """
+        if isinstance(item, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=item)
+        if isinstance(item, Instance):
+            res = type_object_type(item.type, self.named_type)
+            if isinstance(res, CallableType):
+                res = res.copy_modified(from_type_type=True)
+            expanded = expand_type_by_instance(res, item)
+            if isinstance(expanded, CallableType):
+                # Callee of the form Type[...] should never be generic, only
+                # proper class objects can be.
+                expanded = expanded.copy_modified(variables=[])
+            return expanded
+        if isinstance(item, UnionType):
+            return UnionType(
+                [
+                    self.analyze_type_type_callee(get_proper_type(tp), context)
+                    for tp in item.relevant_items()
+                ],
+                item.line,
+            )
+        if isinstance(item, TypeVarType):
+            # Pretend we're calling the typevar's upper bound,
+            # i.e. its constructor (a poor approximation for reality,
+            # but better than AnyType...), but replace the return type
+            # with typevar.
+            callee = self.analyze_type_type_callee(get_proper_type(item.upper_bound), context)
+            callee = get_proper_type(callee)
+            if isinstance(callee, CallableType):
+                callee = callee.copy_modified(ret_type=item)
+            elif isinstance(callee, Overloaded):
+                callee = Overloaded([c.copy_modified(ret_type=item) for c in callee.items])
+            return callee
+        # We support Type of namedtuples but not of tuples in general
+        if isinstance(item, TupleType) and tuple_fallback(item).type.fullname != "builtins.tuple":
+            return self.analyze_type_type_callee(tuple_fallback(item), context)
+
+        self.msg.unsupported_type_type(item, context)
+        return AnyType(TypeOfAny.from_error)
+
+    def infer_arg_types_in_empty_context(self, args: list[Expression]) -> list[Type]:
+        """Infer argument expression types in an empty context.
+
+        In short, we basically recurse on each argument without considering
+        in what context the argument was called.
+        """
+        res: list[Type] = []
+
+        for arg in args:
+            arg_type = self.accept(arg)
+            if has_erased_component(arg_type):
+                res.append(NoneType())
+            else:
+                res.append(arg_type)
+        return res
+
+    def infer_more_unions_for_recursive_type(self, type_context: Type) -> bool:
+        """Adjust type inference of unions if type context has a recursive type.
+
+        Return the old state. The caller must assign it to type_state.infer_unions
+        afterwards.
+
+        This is a hack to better support inference for recursive types.
+
+        Note: This is performance-sensitive and must not be a context manager
+        until mypyc supports them better.
+        """
+        old = type_state.infer_unions
+        if has_recursive_types(type_context):
+            type_state.infer_unions = True
+        return old
+
+    def infer_arg_types_in_context(
+        self,
+        callee: CallableType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        formal_to_actual: list[list[int]],
+    ) -> list[Type]:
+        """Infer argument expression types using a callable type as context.
+
+        For example, if callee argument 2 has type List[int], infer the
+        argument expression with List[int] type context.
+
+        Returns the inferred types of *actual arguments*.
+        """
+        res: list[Type | None] = [None] * len(args)
+
+        for i, actuals in enumerate(formal_to_actual):
+            for ai in actuals:
+                if not arg_kinds[ai].is_star():
+                    arg_type = callee.arg_types[i]
+                    # When the outer context for a function call is known to be recursive,
+                    # we solve type constraints inferred from arguments using unions instead
+                    # of joins. This is a bit arbitrary, but in practice it works for most
+                    # cases. A cleaner alternative would be to switch to single bin type
+                    # inference, but this is a lot of work.
+                    old = self.infer_more_unions_for_recursive_type(arg_type)
+                    res[ai] = self.accept(args[ai], arg_type)
+                    # We need to manually restore union inference state, ugh.
+                    type_state.infer_unions = old
+
+        # Fill in the rest of the argument types.
+        for i, t in enumerate(res):
+            if not t:
+                res[i] = self.accept(args[i])
+        assert all(tp is not None for tp in res)
+        return cast(List[Type], res)
+
+    def infer_function_type_arguments_using_context(
+        self, callable: CallableType, error_context: Context
+    ) -> CallableType:
+        """Unify callable return type to type context to infer type vars.
+
+        For example, if the return type is set[t] where 't' is a type variable
+        of callable, and if the context is set[int], return callable modified
+        by substituting 't' with 'int'.
+        """
+        ctx = self.type_context[-1]
+        if not ctx:
+            return callable
+        # The return type may have references to type metavariables that
+        # we are inferring right now. We must consider them as indeterminate
+        # and they are not potential results; thus we replace them with the
+        # special ErasedType type. On the other hand, class type variables are
+        # valid results.
+        erased_ctx = replace_meta_vars(ctx, ErasedType())
+        ret_type = callable.ret_type
+        if is_optional(ret_type) and is_optional(ctx):
+            # If both the context and the return type are optional, unwrap the optional,
+            # since in 99% cases this is what a user expects. In other words, we replace
+            #     Optional[T] <: Optional[int]
+            # with
+            #     T <: int
+            # while the former would infer T <: Optional[int].
+            ret_type = remove_optional(ret_type)
+            erased_ctx = remove_optional(erased_ctx)
+            #
+            # TODO: Instead of this hack and the one below, we need to use outer and
+            # inner contexts at the same time. This is however not easy because of two
+            # reasons:
+            #   * We need to support constraints like [1 <: 2, 2 <: X], i.e. with variables
+            #     on both sides. (This is not too hard.)
+            #   * We need to update all the inference "infrastructure", so that all
+            #     variables in an expression are inferred at the same time.
+            #     (And this is hard, also we need to be careful with lambdas that require
+            #     two passes.)
+        if isinstance(ret_type, TypeVarType):
+            # Another special case: the return type is a type variable. If it's unrestricted,
+            # we could infer a too general type for the type variable if we use context,
+            # and this could result in confusing and spurious type errors elsewhere.
+            #
+            # So we give up and just use function arguments for type inference, with just two
+            # exceptions:
+            #
+            # 1. If the context is a generic instance type, actually use it as context, as
+            #    this *seems* to usually be the reasonable thing to do.
+            #
+            #    See also github issues #462 and #360.
+            #
+            # 2. If the context is some literal type, we want to "propagate" that information
+            #    down so that we infer a more precise type for literal expressions. For example,
+            #    the expression `3` normally has an inferred type of `builtins.int`: but if it's
+            #    in a literal context like below, we want it to infer `Literal[3]` instead.
+            #
+            #        def expects_literal(x: Literal[3]) -> None: pass
+            #        def identity(x: T) -> T: return x
+            #
+            #        expects_literal(identity(3))  # Should type-check
+            if not is_generic_instance(ctx) and not is_literal_type_like(ctx):
+                return callable.copy_modified()
+        args = infer_type_arguments(callable.type_var_ids(), ret_type, erased_ctx)
+        # Only substitute non-Uninhabited and non-erased types.
+        new_args: list[Type | None] = []
+        for arg in args:
+            if has_uninhabited_component(arg) or has_erased_component(arg):
+                new_args.append(None)
+            else:
+                new_args.append(arg)
+        # Don't show errors after we have only used the outer context for inference.
+        # We will use argument context to infer more variables.
+        return self.apply_generic_arguments(
+            callable, new_args, error_context, skip_unsatisfied=True
+        )
+
+    def infer_function_type_arguments(
+        self,
+        callee_type: CallableType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        formal_to_actual: list[list[int]],
+        context: Context,
+    ) -> CallableType:
+        """Infer the type arguments for a generic callee type.
+
+        Infer based on the types of arguments.
+
+        Return a derived callable type that has the arguments applied.
+        """
+        if self.chk.in_checked_function():
+            # Disable type errors during type inference. There may be errors
+            # due to partial available context information at this time, but
+            # these errors can be safely ignored as the arguments will be
+            # inferred again later.
+            with self.msg.filter_errors():
+                arg_types = self.infer_arg_types_in_context(
+                    callee_type, args, arg_kinds, formal_to_actual
+                )
+
+            arg_pass_nums = self.get_arg_infer_passes(
+                callee_type.arg_types, formal_to_actual, len(args)
+            )
+
+            pass1_args: list[Type | None] = []
+            for i, arg in enumerate(arg_types):
+                if arg_pass_nums[i] > 1:
+                    pass1_args.append(None)
+                else:
+                    pass1_args.append(arg)
+
+            inferred_args = infer_function_type_arguments(
+                callee_type,
+                pass1_args,
+                arg_kinds,
+                formal_to_actual,
+                context=self.argument_infer_context(),
+                strict=self.chk.in_checked_function(),
+            )
+
+            if 2 in arg_pass_nums:
+                # Second pass of type inference.
+                (callee_type, inferred_args) = self.infer_function_type_arguments_pass2(
+                    callee_type, args, arg_kinds, formal_to_actual, inferred_args, context
+                )
+
+            if (
+                callee_type.special_sig == "dict"
+                and len(inferred_args) == 2
+                and (ARG_NAMED in arg_kinds or ARG_STAR2 in arg_kinds)
+            ):
+                # HACK: Infer str key type for dict(...) with keyword args. The type system
+                #       can't represent this so we special case it, as this is a pretty common
+                #       thing. This doesn't quite work with all possible subclasses of dict
+                #       if they shuffle type variables around, as we assume that there is a 1-1
+                #       correspondence with dict type variables. This is a marginal issue and
+                #       a little tricky to fix so it's left unfixed for now.
+                first_arg = get_proper_type(inferred_args[0])
+                if isinstance(first_arg, (NoneType, UninhabitedType)):
+                    inferred_args[0] = self.named_type("builtins.str")
+                elif not first_arg or not is_subtype(self.named_type("builtins.str"), first_arg):
+                    self.chk.fail(message_registry.KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE, context)
+
+            if self.chk.options.new_type_inference and any(
+                a is None
+                or isinstance(get_proper_type(a), UninhabitedType)
+                or set(get_type_vars(a)) & set(callee_type.variables)
+                for a in inferred_args
+            ):
+                # If the regular two-phase inference didn't work, try inferring type
+                # variables while allowing for polymorphic solutions, i.e. for solutions
+                # potentially involving free variables.
+                # TODO: support the similar inference for return type context.
+                poly_inferred_args = infer_function_type_arguments(
+                    callee_type,
+                    arg_types,
+                    arg_kinds,
+                    formal_to_actual,
+                    context=self.argument_infer_context(),
+                    strict=self.chk.in_checked_function(),
+                    allow_polymorphic=True,
+                )
+                for i, pa in enumerate(get_proper_types(poly_inferred_args)):
+                    if isinstance(pa, (NoneType, UninhabitedType)) or has_erased_component(pa):
+                        # Indicate that free variables should not be applied in the call below.
+                        poly_inferred_args[i] = None
+                poly_callee_type = self.apply_generic_arguments(
+                    callee_type, poly_inferred_args, context
+                )
+                yes_vars = poly_callee_type.variables
+                no_vars = {v for v in callee_type.variables if v not in poly_callee_type.variables}
+                if not set(get_type_vars(poly_callee_type)) & no_vars:
+                    # Try applying inferred polymorphic type if possible, e.g. Callable[[T], T] can
+                    # be interpreted as def [T] (T) -> T, but dict[T, T] cannot be expressed.
+                    applied = apply_poly(poly_callee_type, yes_vars)
+                    if applied is not None and poly_inferred_args != [UninhabitedType()] * len(
+                        poly_inferred_args
+                    ):
+                        freeze_all_type_vars(applied)
+                        return applied
+                # If it didn't work, erase free variables as <nothing>, to avoid confusing errors.
+                inferred_args = [
+                    expand_type(a, {v.id: UninhabitedType() for v in callee_type.variables})
+                    if a is not None
+                    else None
+                    for a in inferred_args
+                ]
+        else:
+            # In dynamically typed functions use implicit 'Any' types for
+            # type variables.
+            inferred_args = [AnyType(TypeOfAny.unannotated)] * len(callee_type.variables)
+        return self.apply_inferred_arguments(callee_type, inferred_args, context)
+
+    def infer_function_type_arguments_pass2(
+        self,
+        callee_type: CallableType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        formal_to_actual: list[list[int]],
+        old_inferred_args: Sequence[Type | None],
+        context: Context,
+    ) -> tuple[CallableType, list[Type | None]]:
+        """Perform second pass of generic function type argument inference.
+
+        The second pass is needed for arguments with types such as Callable[[T], S],
+        where both T and S are type variables, when the actual argument is a
+        lambda with inferred types.  The idea is to infer the type variable T
+        in the first pass (based on the types of other arguments).  This lets
+        us infer the argument and return type of the lambda expression and
+        thus also the type variable S in this second pass.
+
+        Return (the callee with type vars applied, inferred actual arg types).
+        """
+        # None or erased types in inferred types mean that there was not enough
+        # information to infer the argument. Replace them with None values so
+        # that they are not applied yet below.
+        inferred_args = list(old_inferred_args)
+        for i, arg in enumerate(get_proper_types(inferred_args)):
+            if isinstance(arg, (NoneType, UninhabitedType)) or has_erased_component(arg):
+                inferred_args[i] = None
+        callee_type = self.apply_generic_arguments(callee_type, inferred_args, context)
+
+        arg_types = self.infer_arg_types_in_context(callee_type, args, arg_kinds, formal_to_actual)
+
+        inferred_args = infer_function_type_arguments(
+            callee_type,
+            arg_types,
+            arg_kinds,
+            formal_to_actual,
+            context=self.argument_infer_context(),
+        )
+
+        return callee_type, inferred_args
+
+    def argument_infer_context(self) -> ArgumentInferContext:
+        return ArgumentInferContext(
+            self.chk.named_type("typing.Mapping"), self.chk.named_type("typing.Iterable")
+        )
+
+    def get_arg_infer_passes(
+        self, arg_types: list[Type], formal_to_actual: list[list[int]], num_actuals: int
+    ) -> list[int]:
+        """Return pass numbers for args for two-pass argument type inference.
+
+        For each actual, the pass number is either 1 (first pass) or 2 (second
+        pass).
+
+        Two-pass argument type inference primarily lets us infer types of
+        lambdas more effectively.
+        """
+        res = [1] * num_actuals
+        for i, arg in enumerate(arg_types):
+            if arg.accept(ArgInferSecondPassQuery()):
+                for j in formal_to_actual[i]:
+                    res[j] = 2
+        return res
+
+    def apply_inferred_arguments(
+        self, callee_type: CallableType, inferred_args: Sequence[Type | None], context: Context
+    ) -> CallableType:
+        """Apply inferred values of type arguments to a generic function.
+
+        Inferred_args contains the values of function type arguments.
+        """
+        # Report error if some of the variables could not be solved. In that
+        # case assume that all variables have type Any to avoid extra
+        # bogus error messages.
+        for i, inferred_type in enumerate(inferred_args):
+            if not inferred_type or has_erased_component(inferred_type):
+                # Could not infer a non-trivial type for a type variable.
+                self.msg.could_not_infer_type_arguments(callee_type, i + 1, context)
+                inferred_args = [AnyType(TypeOfAny.from_error)] * len(inferred_args)
+        # Apply the inferred types to the function type. In this case the
+        # return type must be CallableType, since we give the right number of type
+        # arguments.
+        return self.apply_generic_arguments(callee_type, inferred_args, context)
+
+    def check_argument_count(
+        self,
+        callee: CallableType,
+        actual_types: list[Type],
+        actual_kinds: list[ArgKind],
+        actual_names: Sequence[str | None] | None,
+        formal_to_actual: list[list[int]],
+        context: Context | None,
+        object_type: Type | None = None,
+        callable_name: str | None = None,
+    ) -> bool:
+        """Check that there is a value for all required arguments to a function.
+
+        Also check that there are no duplicate values for arguments. Report found errors
+        using 'messages' if it's not None. If 'messages' is given, 'context' must also be given.
+
+        Return False if there were any errors. Otherwise return True
+        """
+        if context is None:
+            # Avoid "is None" checks
+            context = TempNode(AnyType(TypeOfAny.special_form))
+
+        # TODO(jukka): We could return as soon as we find an error if messages is None.
+
+        # Collect dict of all actual arguments matched to formal arguments, with occurrence count
+        all_actuals: dict[int, int] = {}
+        for actuals in formal_to_actual:
+            for a in actuals:
+                all_actuals[a] = all_actuals.get(a, 0) + 1
+
+        ok, is_unexpected_arg_error = self.check_for_extra_actual_arguments(
+            callee, actual_types, actual_kinds, actual_names, all_actuals, context
+        )
+
+        # Check for too many or few values for formals.
+        for i, kind in enumerate(callee.arg_kinds):
+            if kind.is_required() and not formal_to_actual[i] and not is_unexpected_arg_error:
+                # No actual for a mandatory formal
+                if kind.is_positional():
+                    self.msg.too_few_arguments(callee, context, actual_names)
+                    if object_type and callable_name and "." in callable_name:
+                        self.missing_classvar_callable_note(object_type, callable_name, context)
+                else:
+                    argname = callee.arg_names[i] or "?"
+                    self.msg.missing_named_argument(callee, context, argname)
+                ok = False
+            elif not kind.is_star() and is_duplicate_mapping(
+                formal_to_actual[i], actual_types, actual_kinds
+            ):
+                if self.chk.in_checked_function() or isinstance(
+                    get_proper_type(actual_types[formal_to_actual[i][0]]), TupleType
+                ):
+                    self.msg.duplicate_argument_value(callee, i, context)
+                    ok = False
+            elif (
+                kind.is_named()
+                and formal_to_actual[i]
+                and actual_kinds[formal_to_actual[i][0]] not in [nodes.ARG_NAMED, nodes.ARG_STAR2]
+            ):
+                # Positional argument when expecting a keyword argument.
+                self.msg.too_many_positional_arguments(callee, context)
+                ok = False
+        return ok
+
+    def check_for_extra_actual_arguments(
+        self,
+        callee: CallableType,
+        actual_types: list[Type],
+        actual_kinds: list[ArgKind],
+        actual_names: Sequence[str | None] | None,
+        all_actuals: dict[int, int],
+        context: Context,
+    ) -> tuple[bool, bool]:
+        """Check for extra actual arguments.
+
+        Return tuple (was everything ok,
+                      was there an extra keyword argument error [used to avoid duplicate errors]).
+        """
+
+        is_unexpected_arg_error = False  # Keep track of errors to avoid duplicate errors
+        ok = True  # False if we've found any error
+
+        for i, kind in enumerate(actual_kinds):
+            if (
+                i not in all_actuals
+                and
+                # We accept the other iterables than tuple (including Any)
+                # as star arguments because they could be empty, resulting no arguments.
+                (kind != nodes.ARG_STAR or is_non_empty_tuple(actual_types[i]))
+                and
+                # Accept all types for double-starred arguments, because they could be empty
+                # dictionaries and we can't tell it from their types
+                kind != nodes.ARG_STAR2
+            ):
+                # Extra actual: not matched by a formal argument.
+                ok = False
+                if kind != nodes.ARG_NAMED:
+                    self.msg.too_many_arguments(callee, context)
+                else:
+                    assert actual_names, "Internal error: named kinds without names given"
+                    act_name = actual_names[i]
+                    assert act_name is not None
+                    act_type = actual_types[i]
+                    self.msg.unexpected_keyword_argument(callee, act_name, act_type, context)
+                    is_unexpected_arg_error = True
+            elif (
+                kind == nodes.ARG_STAR and nodes.ARG_STAR not in callee.arg_kinds
+            ) or kind == nodes.ARG_STAR2:
+                actual_type = get_proper_type(actual_types[i])
+                if isinstance(actual_type, (TupleType, TypedDictType)):
+                    if all_actuals.get(i, 0) < len(actual_type.items):
+                        # Too many tuple/dict items as some did not match.
+                        if kind != nodes.ARG_STAR2 or not isinstance(actual_type, TypedDictType):
+                            self.msg.too_many_arguments(callee, context)
+                        else:
+                            self.msg.too_many_arguments_from_typed_dict(
+                                callee, actual_type, context
+                            )
+                            is_unexpected_arg_error = True
+                        ok = False
+                # *args/**kwargs can be applied even if the function takes a fixed
+                # number of positional arguments. This may succeed at runtime.
+
+        return ok, is_unexpected_arg_error
+
+    def missing_classvar_callable_note(
+        self, object_type: Type, callable_name: str, context: Context
+    ) -> None:
+        if isinstance(object_type, ProperType) and isinstance(object_type, Instance):
+            _, var_name = callable_name.rsplit(".", maxsplit=1)
+            node = object_type.type.get(var_name)
+            if node is not None and isinstance(node.node, Var):
+                if not node.node.is_inferred and not node.node.is_classvar:
+                    self.msg.note(
+                        f'"{var_name}" is considered instance variable,'
+                        " to make it class variable use ClassVar[...]",
+                        context,
+                    )
+
+    def check_argument_types(
+        self,
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        args: list[Expression],
+        callee: CallableType,
+        formal_to_actual: list[list[int]],
+        context: Context,
+        check_arg: ArgChecker | None = None,
+        object_type: Type | None = None,
+    ) -> None:
+        """Check argument types against a callable type.
+
+        Report errors if the argument types are not compatible.
+
+        The check_call docstring describes some of the arguments.
+        """
+        check_arg = check_arg or self.check_arg
+        # Keep track of consumed tuple *arg items.
+        mapper = ArgTypeExpander(self.argument_infer_context())
+        for i, actuals in enumerate(formal_to_actual):
+            orig_callee_arg_type = get_proper_type(callee.arg_types[i])
+
+            # Checking the case that we have more than one item but the first argument
+            # is an unpack, so this would be something like:
+            # [Tuple[Unpack[Ts]], int]
+            #
+            # In this case we have to check everything together, we do this by re-unifying
+            # the suffices to the tuple, e.g. a single actual like
+            # Tuple[Unpack[Ts], int]
+            expanded_tuple = False
+            if len(actuals) > 1:
+                first_actual_arg_type = get_proper_type(arg_types[actuals[0]])
+                if (
+                    isinstance(first_actual_arg_type, TupleType)
+                    and len(first_actual_arg_type.items) == 1
+                    and isinstance(first_actual_arg_type.items[0], UnpackType)
+                ):
+                    # TODO: use walrus operator
+                    actual_types = [first_actual_arg_type.items[0]] + [
+                        arg_types[a] for a in actuals[1:]
+                    ]
+                    actual_kinds = [nodes.ARG_STAR] + [nodes.ARG_POS] * (len(actuals) - 1)
+
+                    assert isinstance(orig_callee_arg_type, TupleType)
+                    assert orig_callee_arg_type.items
+                    callee_arg_types = orig_callee_arg_type.items
+                    callee_arg_kinds = [nodes.ARG_STAR] + [nodes.ARG_POS] * (
+                        len(orig_callee_arg_type.items) - 1
+                    )
+                    expanded_tuple = True
+
+            if not expanded_tuple:
+                actual_types = [arg_types[a] for a in actuals]
+                actual_kinds = [arg_kinds[a] for a in actuals]
+                if isinstance(orig_callee_arg_type, UnpackType):
+                    unpacked_type = get_proper_type(orig_callee_arg_type.type)
+                    if isinstance(unpacked_type, TupleType):
+                        inner_unpack_index = find_unpack_in_list(unpacked_type.items)
+                        if inner_unpack_index is None:
+                            callee_arg_types = unpacked_type.items
+                            callee_arg_kinds = [ARG_POS] * len(actuals)
+                        else:
+                            inner_unpack = unpacked_type.items[inner_unpack_index]
+                            assert isinstance(inner_unpack, UnpackType)
+                            inner_unpacked_type = get_proper_type(inner_unpack.type)
+                            # We assume heterogenous tuples are desugared earlier
+                            assert isinstance(inner_unpacked_type, Instance)
+                            assert inner_unpacked_type.type.fullname == "builtins.tuple"
+                            callee_arg_types = (
+                                unpacked_type.items[:inner_unpack_index]
+                                + [inner_unpacked_type.args[0]]
+                                * (len(actuals) - len(unpacked_type.items) + 1)
+                                + unpacked_type.items[inner_unpack_index + 1 :]
+                            )
+                            callee_arg_kinds = [ARG_POS] * len(actuals)
+                    else:
+                        assert isinstance(unpacked_type, Instance)
+                        assert unpacked_type.type.fullname == "builtins.tuple"
+                        callee_arg_types = [unpacked_type.args[0]] * len(actuals)
+                        callee_arg_kinds = [ARG_POS] * len(actuals)
+                else:
+                    callee_arg_types = [orig_callee_arg_type] * len(actuals)
+                    callee_arg_kinds = [callee.arg_kinds[i]] * len(actuals)
+
+            assert len(actual_types) == len(actuals) == len(actual_kinds)
+
+            if len(callee_arg_types) != len(actual_types):
+                # TODO: Improve error message
+                self.chk.fail("Invalid number of arguments", context)
+                continue
+
+            assert len(callee_arg_types) == len(actual_types)
+            assert len(callee_arg_types) == len(callee_arg_kinds)
+            for actual, actual_type, actual_kind, callee_arg_type, callee_arg_kind in zip(
+                actuals, actual_types, actual_kinds, callee_arg_types, callee_arg_kinds
+            ):
+                if actual_type is None:
+                    continue  # Some kind of error was already reported.
+                # Check that a *arg is valid as varargs.
+                if actual_kind == nodes.ARG_STAR and not self.is_valid_var_arg(actual_type):
+                    self.msg.invalid_var_arg(actual_type, context)
+                if actual_kind == nodes.ARG_STAR2 and not self.is_valid_keyword_var_arg(
+                    actual_type
+                ):
+                    is_mapping = is_subtype(
+                        actual_type, self.chk.named_type("_typeshed.SupportsKeysAndGetItem")
+                    )
+                    self.msg.invalid_keyword_var_arg(actual_type, is_mapping, context)
+                expanded_actual = mapper.expand_actual_type(
+                    actual_type, actual_kind, callee.arg_names[i], callee_arg_kind
+                )
+                check_arg(
+                    expanded_actual,
+                    actual_type,
+                    actual_kind,
+                    callee_arg_type,
+                    actual + 1,
+                    i + 1,
+                    callee,
+                    object_type,
+                    args[actual],
+                    context,
+                )
+
+    def check_arg(
+        self,
+        caller_type: Type,
+        original_caller_type: Type,
+        caller_kind: ArgKind,
+        callee_type: Type,
+        n: int,
+        m: int,
+        callee: CallableType,
+        object_type: Type | None,
+        context: Context,
+        outer_context: Context,
+    ) -> None:
+        """Check the type of a single argument in a call."""
+        caller_type = get_proper_type(caller_type)
+        original_caller_type = get_proper_type(original_caller_type)
+        callee_type = get_proper_type(callee_type)
+
+        if isinstance(caller_type, DeletedType):
+            self.msg.deleted_as_rvalue(caller_type, context)
+        # Only non-abstract non-protocol class can be given where Type[...] is expected...
+        elif self.has_abstract_type_part(caller_type, callee_type):
+            self.msg.concrete_only_call(callee_type, context)
+        elif not is_subtype(caller_type, callee_type, options=self.chk.options):
+            code = self.msg.incompatible_argument(
+                n,
+                m,
+                callee,
+                original_caller_type,
+                caller_kind,
+                object_type=object_type,
+                context=context,
+                outer_context=outer_context,
+            )
+            self.msg.incompatible_argument_note(
+                original_caller_type, callee_type, context, code=code
+            )
+            if not self.msg.prefer_simple_messages():
+                self.chk.check_possible_missing_await(caller_type, callee_type, context)
+
+    def check_overload_call(
+        self,
+        callee: Overloaded,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        callable_name: str | None,
+        object_type: Type | None,
+        context: Context,
+    ) -> tuple[Type, Type]:
+        """Checks a call to an overloaded function."""
+        # Normalize unpacked kwargs before checking the call.
+        callee = callee.with_unpacked_kwargs()
+        arg_types = self.infer_arg_types_in_empty_context(args)
+        # Step 1: Filter call targets to remove ones where the argument counts don't match
+        plausible_targets = self.plausible_overload_call_targets(
+            arg_types, arg_kinds, arg_names, callee
+        )
+
+        # Step 2: If the arguments contain a union, we try performing union math first,
+        #         instead of picking the first matching overload.
+        #         This is because picking the first overload often ends up being too greedy:
+        #         for example, when we have a fallback alternative that accepts an unrestricted
+        #         typevar. See https://github.com/python/mypy/issues/4063 for related discussion.
+        erased_targets: list[CallableType] | None = None
+        unioned_result: tuple[Type, Type] | None = None
+        union_interrupted = False  # did we try all union combinations?
+        if any(self.real_union(arg) for arg in arg_types):
+            try:
+                with self.msg.filter_errors():
+                    unioned_return = self.union_overload_result(
+                        plausible_targets,
+                        args,
+                        arg_types,
+                        arg_kinds,
+                        arg_names,
+                        callable_name,
+                        object_type,
+                        context,
+                    )
+            except TooManyUnions:
+                union_interrupted = True
+            else:
+                # Record if we succeeded. Next we need to see if maybe normal procedure
+                # gives a narrower type.
+                if unioned_return:
+                    returns, inferred_types = zip(*unioned_return)
+                    # Note that we use `combine_function_signatures` instead of just returning
+                    # a union of inferred callables because for example a call
+                    # Union[int -> int, str -> str](Union[int, str]) is invalid and
+                    # we don't want to introduce internal inconsistencies.
+                    unioned_result = (
+                        make_simplified_union(list(returns), context.line, context.column),
+                        self.combine_function_signatures(get_proper_types(inferred_types)),
+                    )
+
+        # Step 3: We try checking each branch one-by-one.
+        inferred_result = self.infer_overload_return_type(
+            plausible_targets,
+            args,
+            arg_types,
+            arg_kinds,
+            arg_names,
+            callable_name,
+            object_type,
+            context,
+        )
+        # If any of checks succeed, stop early.
+        if inferred_result is not None and unioned_result is not None:
+            # Both unioned and direct checks succeeded, choose the more precise type.
+            if is_subtype(inferred_result[0], unioned_result[0]) and not isinstance(
+                get_proper_type(inferred_result[0]), AnyType
+            ):
+                return inferred_result
+            return unioned_result
+        elif unioned_result is not None:
+            return unioned_result
+        elif inferred_result is not None:
+            return inferred_result
+
+        # Step 4: Failure. At this point, we know there is no match. We fall back to trying
+        #         to find a somewhat plausible overload target using the erased types
+        #         so we can produce a nice error message.
+        #
+        #         For example, suppose the user passes a value of type 'List[str]' into an
+        #         overload with signatures f(x: int) -> int and f(x: List[int]) -> List[int].
+        #
+        #         Neither alternative matches, but we can guess the user probably wants the
+        #         second one.
+        erased_targets = self.overload_erased_call_targets(
+            plausible_targets, arg_types, arg_kinds, arg_names, args, context
+        )
+
+        # Step 5: We try and infer a second-best alternative if possible. If not, fall back
+        #         to using 'Any'.
+        if len(erased_targets) > 0:
+            # Pick the first plausible erased target as the fallback
+            # TODO: Adjust the error message here to make it clear there was no match.
+            #       In order to do this, we need to find a clean way of associating
+            #       a note with whatever error message 'self.check_call' will generate.
+            #       In particular, the note's line and column numbers need to be the same
+            #       as the error's.
+            target: Type = erased_targets[0]
+        else:
+            # There was no plausible match: give up
+            target = AnyType(TypeOfAny.from_error)
+            if not is_operator_method(callable_name):
+                code = None
+            else:
+                code = codes.OPERATOR
+            self.msg.no_variant_matches_arguments(callee, arg_types, context, code=code)
+
+        result = self.check_call(
+            target,
+            args,
+            arg_kinds,
+            context,
+            arg_names,
+            callable_name=callable_name,
+            object_type=object_type,
+        )
+        if union_interrupted:
+            self.chk.fail(message_registry.TOO_MANY_UNION_COMBINATIONS, context)
+        return result
+
+    def plausible_overload_call_targets(
+        self,
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        overload: Overloaded,
+    ) -> list[CallableType]:
+        """Returns all overload call targets that having matching argument counts.
+
+        If the given args contains a star-arg (*arg or **kwarg argument), this method
+        will ensure all star-arg overloads appear at the start of the list, instead
+        of their usual location.
+
+        The only exception is if the starred argument is something like a Tuple or a
+        NamedTuple, which has a definitive "shape". If so, we don't move the corresponding
+        alternative to the front since we can infer a more precise match using the original
+        order."""
+
+        def has_shape(typ: Type) -> bool:
+            typ = get_proper_type(typ)
+            return isinstance(typ, (TupleType, TypedDictType)) or (
+                isinstance(typ, Instance) and typ.type.is_named_tuple
+            )
+
+        matches: list[CallableType] = []
+        star_matches: list[CallableType] = []
+
+        args_have_var_arg = False
+        args_have_kw_arg = False
+        for kind, typ in zip(arg_kinds, arg_types):
+            if kind == ARG_STAR and not has_shape(typ):
+                args_have_var_arg = True
+            if kind == ARG_STAR2 and not has_shape(typ):
+                args_have_kw_arg = True
+
+        for typ in overload.items:
+            formal_to_actual = map_actuals_to_formals(
+                arg_kinds, arg_names, typ.arg_kinds, typ.arg_names, lambda i: arg_types[i]
+            )
+
+            with self.msg.filter_errors():
+                if self.check_argument_count(
+                    typ, arg_types, arg_kinds, arg_names, formal_to_actual, None
+                ):
+                    if args_have_var_arg and typ.is_var_arg:
+                        star_matches.append(typ)
+                    elif args_have_kw_arg and typ.is_kw_arg:
+                        star_matches.append(typ)
+                    else:
+                        matches.append(typ)
+
+        return star_matches + matches
+
+    def infer_overload_return_type(
+        self,
+        plausible_targets: list[CallableType],
+        args: list[Expression],
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        callable_name: str | None,
+        object_type: Type | None,
+        context: Context,
+    ) -> tuple[Type, Type] | None:
+        """Attempts to find the first matching callable from the given list.
+
+        If a match is found, returns a tuple containing the result type and the inferred
+        callee type. (This tuple is meant to be eventually returned by check_call.)
+        If multiple targets match due to ambiguous Any parameters, returns (AnyType, AnyType).
+        If no targets match, returns None.
+
+        Assumes all of the given targets have argument counts compatible with the caller.
+        """
+
+        matches: list[CallableType] = []
+        return_types: list[Type] = []
+        inferred_types: list[Type] = []
+        args_contain_any = any(map(has_any_type, arg_types))
+        type_maps: list[dict[Expression, Type]] = []
+
+        for typ in plausible_targets:
+            assert self.msg is self.chk.msg
+            with self.msg.filter_errors() as w:
+                with self.chk.local_type_map() as m:
+                    ret_type, infer_type = self.check_call(
+                        callee=typ,
+                        args=args,
+                        arg_kinds=arg_kinds,
+                        arg_names=arg_names,
+                        context=context,
+                        callable_name=callable_name,
+                        object_type=object_type,
+                    )
+            is_match = not w.has_new_errors()
+            if is_match:
+                # Return early if possible; otherwise record info so we can
+                # check for ambiguity due to 'Any' below.
+                if not args_contain_any:
+                    return ret_type, infer_type
+                matches.append(typ)
+                return_types.append(ret_type)
+                inferred_types.append(infer_type)
+                type_maps.append(m)
+
+        if not matches:
+            return None
+        elif any_causes_overload_ambiguity(matches, return_types, arg_types, arg_kinds, arg_names):
+            # An argument of type or containing the type 'Any' caused ambiguity.
+            # We try returning a precise type if we can. If not, we give up and just return 'Any'.
+            if all_same_types(return_types):
+                self.chk.store_types(type_maps[0])
+                return return_types[0], inferred_types[0]
+            elif all_same_types([erase_type(typ) for typ in return_types]):
+                self.chk.store_types(type_maps[0])
+                return erase_type(return_types[0]), erase_type(inferred_types[0])
+            else:
+                return self.check_call(
+                    callee=AnyType(TypeOfAny.special_form),
+                    args=args,
+                    arg_kinds=arg_kinds,
+                    arg_names=arg_names,
+                    context=context,
+                    callable_name=callable_name,
+                    object_type=object_type,
+                )
+        else:
+            # Success! No ambiguity; return the first match.
+            self.chk.store_types(type_maps[0])
+            return return_types[0], inferred_types[0]
+
+    def overload_erased_call_targets(
+        self,
+        plausible_targets: list[CallableType],
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        args: list[Expression],
+        context: Context,
+    ) -> list[CallableType]:
+        """Returns a list of all targets that match the caller after erasing types.
+
+        Assumes all of the given targets have argument counts compatible with the caller.
+        """
+        matches: list[CallableType] = []
+        for typ in plausible_targets:
+            if self.erased_signature_similarity(
+                arg_types, arg_kinds, arg_names, args, typ, context
+            ):
+                matches.append(typ)
+        return matches
+
+    def union_overload_result(
+        self,
+        plausible_targets: list[CallableType],
+        args: list[Expression],
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        callable_name: str | None,
+        object_type: Type | None,
+        context: Context,
+        level: int = 0,
+    ) -> list[tuple[Type, Type]] | None:
+        """Accepts a list of overload signatures and attempts to match calls by destructuring
+        the first union.
+
+        Return a list of (<return type>, <inferred variant type>) if call succeeds for every
+        item of the desctructured union. Returns None if there is no match.
+        """
+        # Step 1: If we are already too deep, then stop immediately. Otherwise mypy might
+        # hang for long time because of a weird overload call. The caller will get
+        # the exception and generate an appropriate note message, if needed.
+        if level >= MAX_UNIONS:
+            raise TooManyUnions
+
+        # Step 2: Find position of the first union in arguments. Return the normal inferred
+        # type if no more unions left.
+        for idx, typ in enumerate(arg_types):
+            if self.real_union(typ):
+                break
+        else:
+            # No unions in args, just fall back to normal inference
+            with self.type_overrides_set(args, arg_types):
+                res = self.infer_overload_return_type(
+                    plausible_targets,
+                    args,
+                    arg_types,
+                    arg_kinds,
+                    arg_names,
+                    callable_name,
+                    object_type,
+                    context,
+                )
+            if res is not None:
+                return [res]
+            return None
+
+        # Step 3: Try a direct match before splitting to avoid unnecessary union splits
+        # and save performance.
+        with self.type_overrides_set(args, arg_types):
+            direct = self.infer_overload_return_type(
+                plausible_targets,
+                args,
+                arg_types,
+                arg_kinds,
+                arg_names,
+                callable_name,
+                object_type,
+                context,
+            )
+        if direct is not None and not isinstance(get_proper_type(direct[0]), (UnionType, AnyType)):
+            # We only return non-unions soon, to avoid greedy match.
+            return [direct]
+
+        # Step 4: Split the first remaining union type in arguments into items and
+        # try to match each item individually (recursive).
+        first_union = get_proper_type(arg_types[idx])
+        assert isinstance(first_union, UnionType)
+        res_items = []
+        for item in first_union.relevant_items():
+            new_arg_types = arg_types.copy()
+            new_arg_types[idx] = item
+            sub_result = self.union_overload_result(
+                plausible_targets,
+                args,
+                new_arg_types,
+                arg_kinds,
+                arg_names,
+                callable_name,
+                object_type,
+                context,
+                level + 1,
+            )
+            if sub_result is not None:
+                res_items.extend(sub_result)
+            else:
+                # Some item doesn't match, return soon.
+                return None
+
+        # Step 5: If splitting succeeded, then filter out duplicate items before returning.
+        seen: set[tuple[Type, Type]] = set()
+        result = []
+        for pair in res_items:
+            if pair not in seen:
+                seen.add(pair)
+                result.append(pair)
+        return result
+
+    def real_union(self, typ: Type) -> bool:
+        typ = get_proper_type(typ)
+        return isinstance(typ, UnionType) and len(typ.relevant_items()) > 1
+
+    @contextmanager
+    def type_overrides_set(
+        self, exprs: Sequence[Expression], overrides: Sequence[Type]
+    ) -> Iterator[None]:
+        """Set _temporary_ type overrides for given expressions."""
+        assert len(exprs) == len(overrides)
+        for expr, typ in zip(exprs, overrides):
+            self.type_overrides[expr] = typ
+        try:
+            yield
+        finally:
+            for expr in exprs:
+                del self.type_overrides[expr]
+
+    def combine_function_signatures(self, types: list[ProperType]) -> AnyType | CallableType:
+        """Accepts a list of function signatures and attempts to combine them together into a
+        new CallableType consisting of the union of all of the given arguments and return types.
+
+        If there is at least one non-callable type, return Any (this can happen if there is
+        an ambiguity because of Any in arguments).
+        """
+        assert types, "Trying to merge no callables"
+        if not all(isinstance(c, CallableType) for c in types):
+            return AnyType(TypeOfAny.special_form)
+        callables = cast("list[CallableType]", types)
+        if len(callables) == 1:
+            return callables[0]
+
+        # Note: we are assuming here that if a user uses some TypeVar 'T' in
+        # two different functions, they meant for that TypeVar to mean the
+        # same thing.
+        #
+        # This function will make sure that all instances of that TypeVar 'T'
+        # refer to the same underlying TypeVarType objects to simplify the union-ing
+        # logic below.
+        #
+        # (If the user did *not* mean for 'T' to be consistently bound to the
+        # same type in their overloads, well, their code is probably too
+        # confusing and ought to be re-written anyways.)
+        callables, variables = merge_typevars_in_callables_by_name(callables)
+
+        new_args: list[list[Type]] = [[] for _ in range(len(callables[0].arg_types))]
+        new_kinds = list(callables[0].arg_kinds)
+        new_returns: list[Type] = []
+
+        too_complex = False
+        for target in callables:
+            # We fall back to Callable[..., Union[<returns>]] if the functions do not have
+            # the exact same signature. The only exception is if one arg is optional and
+            # the other is positional: in that case, we continue unioning (and expect a
+            # positional arg).
+            # TODO: Enhance the merging logic to handle a wider variety of signatures.
+            if len(new_kinds) != len(target.arg_kinds):
+                too_complex = True
+                break
+            for i, (new_kind, target_kind) in enumerate(zip(new_kinds, target.arg_kinds)):
+                if new_kind == target_kind:
+                    continue
+                elif new_kind.is_positional() and target_kind.is_positional():
+                    new_kinds[i] = ARG_POS
+                else:
+                    too_complex = True
+                    break
+
+            if too_complex:
+                break  # outer loop
+
+            for i, arg in enumerate(target.arg_types):
+                new_args[i].append(arg)
+            new_returns.append(target.ret_type)
+
+        union_return = make_simplified_union(new_returns)
+        if too_complex:
+            any = AnyType(TypeOfAny.special_form)
+            return callables[0].copy_modified(
+                arg_types=[any, any],
+                arg_kinds=[ARG_STAR, ARG_STAR2],
+                arg_names=[None, None],
+                ret_type=union_return,
+                variables=variables,
+                implicit=True,
+            )
+
+        final_args = []
+        for args_list in new_args:
+            new_type = make_simplified_union(args_list)
+            final_args.append(new_type)
+
+        return callables[0].copy_modified(
+            arg_types=final_args,
+            arg_kinds=new_kinds,
+            ret_type=union_return,
+            variables=variables,
+            implicit=True,
+        )
+
+    def erased_signature_similarity(
+        self,
+        arg_types: list[Type],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        args: list[Expression],
+        callee: CallableType,
+        context: Context,
+    ) -> bool:
+        """Determine whether arguments could match the signature at runtime, after
+        erasing types."""
+        formal_to_actual = map_actuals_to_formals(
+            arg_kinds, arg_names, callee.arg_kinds, callee.arg_names, lambda i: arg_types[i]
+        )
+
+        with self.msg.filter_errors():
+            if not self.check_argument_count(
+                callee, arg_types, arg_kinds, arg_names, formal_to_actual, None
+            ):
+                # Too few or many arguments -> no match.
+                return False
+
+        def check_arg(
+            caller_type: Type,
+            original_ccaller_type: Type,
+            caller_kind: ArgKind,
+            callee_type: Type,
+            n: int,
+            m: int,
+            callee: CallableType,
+            object_type: Type | None,
+            context: Context,
+            outer_context: Context,
+        ) -> None:
+            if not arg_approximate_similarity(caller_type, callee_type):
+                # No match -- exit early since none of the remaining work can change
+                # the result.
+                raise Finished
+
+        try:
+            self.check_argument_types(
+                arg_types,
+                arg_kinds,
+                args,
+                callee,
+                formal_to_actual,
+                context=context,
+                check_arg=check_arg,
+            )
+            return True
+        except Finished:
+            return False
+
+    def apply_generic_arguments(
+        self,
+        callable: CallableType,
+        types: Sequence[Type | None],
+        context: Context,
+        skip_unsatisfied: bool = False,
+    ) -> CallableType:
+        """Simple wrapper around mypy.applytype.apply_generic_arguments."""
+        return applytype.apply_generic_arguments(
+            callable,
+            types,
+            self.msg.incompatible_typevar_value,
+            context,
+            skip_unsatisfied=skip_unsatisfied,
+        )
+
+    def check_any_type_call(self, args: list[Expression], callee: Type) -> tuple[Type, Type]:
+        self.infer_arg_types_in_empty_context(args)
+        callee = get_proper_type(callee)
+        if isinstance(callee, AnyType):
+            return (
+                AnyType(TypeOfAny.from_another_any, source_any=callee),
+                AnyType(TypeOfAny.from_another_any, source_any=callee),
+            )
+        else:
+            return AnyType(TypeOfAny.special_form), AnyType(TypeOfAny.special_form)
+
+    def check_union_call(
+        self,
+        callee: UnionType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        arg_names: Sequence[str | None] | None,
+        context: Context,
+    ) -> tuple[Type, Type]:
+        with self.msg.disable_type_names():
+            results = [
+                self.check_call(subtype, args, arg_kinds, context, arg_names)
+                for subtype in callee.relevant_items()
+            ]
+
+        return (make_simplified_union([res[0] for res in results]), callee)
+
+    def visit_member_expr(self, e: MemberExpr, is_lvalue: bool = False) -> Type:
+        """Visit member expression (of form e.id)."""
+        self.chk.module_refs.update(extract_refexpr_names(e))
+        result = self.analyze_ordinary_member_access(e, is_lvalue)
+        return self.narrow_type_from_binder(e, result)
+
+    def analyze_ordinary_member_access(self, e: MemberExpr, is_lvalue: bool) -> Type:
+        """Analyse member expression or member lvalue."""
+        if e.kind is not None:
+            # This is a reference to a module attribute.
+            return self.analyze_ref_expr(e)
+        else:
+            # This is a reference to a non-module attribute.
+            original_type = self.accept(e.expr, is_callee=self.is_callee)
+            base = e.expr
+            module_symbol_table = None
+
+            if isinstance(base, RefExpr) and isinstance(base.node, MypyFile):
+                module_symbol_table = base.node.names
+            if isinstance(base, RefExpr) and isinstance(base.node, Var):
+                is_self = base.node.is_self
+            else:
+                is_self = False
+
+            member_type = analyze_member_access(
+                e.name,
+                original_type,
+                e,
+                is_lvalue,
+                False,
+                False,
+                self.msg,
+                original_type=original_type,
+                chk=self.chk,
+                in_literal_context=self.is_literal_context(),
+                module_symbol_table=module_symbol_table,
+                is_self=is_self,
+            )
+
+            return member_type
+
+    def analyze_external_member_access(
+        self, member: str, base_type: Type, context: Context
+    ) -> Type:
+        """Analyse member access that is external, i.e. it cannot
+        refer to private definitions. Return the result type.
+        """
+        # TODO remove; no private definitions in mypy
+        return analyze_member_access(
+            member,
+            base_type,
+            context,
+            False,
+            False,
+            False,
+            self.msg,
+            original_type=base_type,
+            chk=self.chk,
+            in_literal_context=self.is_literal_context(),
+        )
+
+    def is_literal_context(self) -> bool:
+        return is_literal_type_like(self.type_context[-1])
+
+    def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Type:
+        """Analyzes the given literal expression and determines if we should be
+        inferring an Instance type, a Literal[...] type, or an Instance that
+        remembers the original literal. We...
+
+        1. ...Infer a normal Instance in most circumstances.
+
+        2. ...Infer a Literal[...] if we're in a literal context. For example, if we
+           were analyzing the "3" in "foo(3)" where "foo" has a signature of
+           "def foo(Literal[3]) -> None", we'd want to infer that the "3" has a
+           type of Literal[3] instead of Instance.
+
+        3. ...Infer an Instance that remembers the original Literal if we're declaring
+           a Final variable with an inferred type -- for example, "bar" in "bar: Final = 3"
+           would be assigned an Instance that remembers it originated from a '3'. See
+           the comments in Instance's constructor for more details.
+        """
+        typ = self.named_type(fallback_name)
+        if self.is_literal_context():
+            return LiteralType(value=value, fallback=typ)
+        else:
+            return typ.copy_modified(
+                last_known_value=LiteralType(
+                    value=value, fallback=typ, line=typ.line, column=typ.column
+                )
+            )
+
+    def concat_tuples(self, left: TupleType, right: TupleType) -> TupleType:
+        """Concatenate two fixed length tuples."""
+        return TupleType(
+            items=left.items + right.items, fallback=self.named_type("builtins.tuple")
+        )
+
+    def visit_int_expr(self, e: IntExpr) -> Type:
+        """Type check an integer literal (trivial)."""
+        return self.infer_literal_expr_type(e.value, "builtins.int")
+
+    def visit_str_expr(self, e: StrExpr) -> Type:
+        """Type check a string literal (trivial)."""
+        return self.infer_literal_expr_type(e.value, "builtins.str")
+
+    def visit_bytes_expr(self, e: BytesExpr) -> Type:
+        """Type check a bytes literal (trivial)."""
+        return self.infer_literal_expr_type(e.value, "builtins.bytes")
+
+    def visit_float_expr(self, e: FloatExpr) -> Type:
+        """Type check a float literal (trivial)."""
+        return self.named_type("builtins.float")
+
+    def visit_complex_expr(self, e: ComplexExpr) -> Type:
+        """Type check a complex literal."""
+        return self.named_type("builtins.complex")
+
+    def visit_ellipsis(self, e: EllipsisExpr) -> Type:
+        """Type check '...'."""
+        return self.named_type("builtins.ellipsis")
+
+    def visit_op_expr(self, e: OpExpr) -> Type:
+        """Type check a binary operator expression."""
+        if e.analyzed:
+            # It's actually a type expression X | Y.
+            return self.accept(e.analyzed)
+        if e.op == "and" or e.op == "or":
+            return self.check_boolean_op(e, e)
+        if e.op == "*" and isinstance(e.left, ListExpr):
+            # Expressions of form [...] * e get special type inference.
+            return self.check_list_multiply(e)
+        if e.op == "%":
+            if isinstance(e.left, BytesExpr) and self.chk.options.python_version >= (3, 5):
+                return self.strfrm_checker.check_str_interpolation(e.left, e.right)
+            if isinstance(e.left, StrExpr):
+                return self.strfrm_checker.check_str_interpolation(e.left, e.right)
+        left_type = self.accept(e.left)
+
+        proper_left_type = get_proper_type(left_type)
+        if isinstance(proper_left_type, TupleType) and e.op == "+":
+            left_add_method = proper_left_type.partial_fallback.type.get("__add__")
+            if left_add_method and left_add_method.fullname == "builtins.tuple.__add__":
+                proper_right_type = get_proper_type(self.accept(e.right))
+                if isinstance(proper_right_type, TupleType):
+                    right_radd_method = proper_right_type.partial_fallback.type.get("__radd__")
+                    if right_radd_method is None:
+                        return self.concat_tuples(proper_left_type, proper_right_type)
+
+        if e.op in operators.op_methods:
+            method = operators.op_methods[e.op]
+            result, method_type = self.check_op(method, left_type, e.right, e, allow_reverse=True)
+            e.method_type = method_type
+            return result
+        else:
+            raise RuntimeError(f"Unknown operator {e.op}")
+
+    def visit_comparison_expr(self, e: ComparisonExpr) -> Type:
+        """Type check a comparison expression.
+
+        Comparison expressions are type checked consecutive-pair-wise
+        That is, 'a < b > c == d' is check as 'a < b and b > c and c == d'
+        """
+        result: Type | None = None
+        sub_result: Type
+
+        # Check each consecutive operand pair and their operator
+        for left, right, operator in zip(e.operands, e.operands[1:], e.operators):
+            left_type = self.accept(left)
+
+            if operator == "in" or operator == "not in":
+                # This case covers both iterables and containers, which have different meanings.
+                # For a container, the in operator calls the __contains__ method.
+                # For an iterable, the in operator iterates over the iterable, and compares each item one-by-one.
+                # We allow `in` for a union of containers and iterables as long as at least one of them matches the
+                # type of the left operand, as the operation will simply return False if the union's container/iterator
+                # type doesn't match the left operand.
+
+                # If the right operand has partial type, look it up without triggering
+                # a "Need type annotation ..." message, as it would be noise.
+                right_type = self.find_partial_type_ref_fast_path(right)
+                if right_type is None:
+                    right_type = self.accept(right)  # Validate the right operand
+
+                right_type = get_proper_type(right_type)
+                item_types: Sequence[Type] = [right_type]
+                if isinstance(right_type, UnionType):
+                    item_types = list(right_type.relevant_items())
+
+                sub_result = self.bool_type()
+
+                container_types: list[Type] = []
+                iterable_types: list[Type] = []
+                failed_out = False
+                encountered_partial_type = False
+
+                for item_type in item_types:
+                    # Keep track of whether we get type check errors (these won't be reported, they
+                    # are just to verify whether something is valid typing wise).
+                    with self.msg.filter_errors(save_filtered_errors=True) as container_errors:
+                        _, method_type = self.check_method_call_by_name(
+                            method="__contains__",
+                            base_type=item_type,
+                            args=[left],
+                            arg_kinds=[ARG_POS],
+                            context=e,
+                            original_type=right_type,
+                        )
+                        # Container item type for strict type overlap checks. Note: we need to only
+                        # check for nominal type, because a usual "Unsupported operands for in"
+                        # will be reported for types incompatible with __contains__().
+                        # See testCustomContainsCheckStrictEquality for an example.
+                        cont_type = self.chk.analyze_container_item_type(item_type)
+
+                    if isinstance(item_type, PartialType):
+                        # We don't really know if this is an error or not, so just shut up.
+                        encountered_partial_type = True
+                        pass
+                    elif (
+                        container_errors.has_new_errors()
+                        and
+                        # is_valid_var_arg is True for any Iterable
+                        self.is_valid_var_arg(item_type)
+                    ):
+                        # it's not a container, but it is an iterable
+                        with self.msg.filter_errors(save_filtered_errors=True) as iterable_errors:
+                            _, itertype = self.chk.analyze_iterable_item_type_without_expression(
+                                item_type, e
+                            )
+                        if iterable_errors.has_new_errors():
+                            self.msg.add_errors(iterable_errors.filtered_errors())
+                            failed_out = True
+                        else:
+                            method_type = CallableType(
+                                [left_type],
+                                [nodes.ARG_POS],
+                                [None],
+                                self.bool_type(),
+                                self.named_type("builtins.function"),
+                            )
+                            e.method_types.append(method_type)
+                            iterable_types.append(itertype)
+                    elif not container_errors.has_new_errors() and cont_type:
+                        container_types.append(cont_type)
+                        e.method_types.append(method_type)
+                    else:
+                        self.msg.add_errors(container_errors.filtered_errors())
+                        failed_out = True
+
+                if not encountered_partial_type and not failed_out:
+                    iterable_type = UnionType.make_union(iterable_types)
+                    if not is_subtype(left_type, iterable_type):
+                        if not container_types:
+                            self.msg.unsupported_operand_types("in", left_type, right_type, e)
+                        else:
+                            container_type = UnionType.make_union(container_types)
+                            if self.dangerous_comparison(
+                                left_type,
+                                container_type,
+                                original_container=right_type,
+                                prefer_literal=False,
+                            ):
+                                self.msg.dangerous_comparison(
+                                    left_type, container_type, "container", e
+                                )
+
+            elif operator in operators.op_methods:
+                method = operators.op_methods[operator]
+
+                with ErrorWatcher(self.msg.errors) as w:
+                    sub_result, method_type = self.check_op(
+                        method, left_type, right, e, allow_reverse=True
+                    )
+                    e.method_types.append(method_type)
+
+                # Only show dangerous overlap if there are no other errors. See
+                # testCustomEqCheckStrictEquality for an example.
+                if not w.has_new_errors() and operator in ("==", "!="):
+                    right_type = self.accept(right)
+                    if self.dangerous_comparison(left_type, right_type):
+                        # Show the most specific literal types possible
+                        left_type = try_getting_literal(left_type)
+                        right_type = try_getting_literal(right_type)
+                        self.msg.dangerous_comparison(left_type, right_type, "equality", e)
+
+            elif operator == "is" or operator == "is not":
+                right_type = self.accept(right)  # validate the right operand
+                sub_result = self.bool_type()
+                if self.dangerous_comparison(left_type, right_type):
+                    # Show the most specific literal types possible
+                    left_type = try_getting_literal(left_type)
+                    right_type = try_getting_literal(right_type)
+                    self.msg.dangerous_comparison(left_type, right_type, "identity", e)
+                e.method_types.append(None)
+            else:
+                raise RuntimeError(f"Unknown comparison operator {operator}")
+
+            #  Determine type of boolean-and of result and sub_result
+            if result is None:
+                result = sub_result
+            else:
+                result = join.join_types(result, sub_result)
+
+        assert result is not None
+        return result
+
+    def find_partial_type_ref_fast_path(self, expr: Expression) -> Type | None:
+        """If expression has a partial generic type, return it without additional checks.
+
+        In particular, this does not generate an error about a missing annotation.
+
+        Otherwise, return None.
+        """
+        if not isinstance(expr, RefExpr):
+            return None
+        if isinstance(expr.node, Var):
+            result = self.analyze_var_ref(expr.node, expr)
+            if isinstance(result, PartialType) and result.type is not None:
+                self.chk.store_type(expr, fixup_partial_type(result))
+                return result
+        return None
+
+    def dangerous_comparison(
+        self,
+        left: Type,
+        right: Type,
+        original_container: Type | None = None,
+        *,
+        prefer_literal: bool = True,
+    ) -> bool:
+        """Check for dangerous non-overlapping comparisons like 42 == 'no'.
+
+        The original_container is the original container type for 'in' checks
+        (and None for equality checks).
+
+        Rules:
+            * X and None are overlapping even in strict-optional mode. This is to allow
+            'assert x is not None' for x defined as 'x = None  # type: str' in class body
+            (otherwise mypy itself would have couple dozen errors because of this).
+            * Optional[X] and Optional[Y] are non-overlapping if X and Y are
+            non-overlapping, although technically None is overlap, it is most
+            likely an error.
+            * Any overlaps with everything, i.e. always safe.
+            * Special case: b'abc' in b'cde' is safe.
+        """
+        if not self.chk.options.strict_equality:
+            return False
+
+        left, right = get_proper_types((left, right))
+
+        # We suppress the error if there is a custom __eq__() method on either
+        # side. User defined (or even standard library) classes can define this
+        # to return True for comparisons between non-overlapping types.
+        if custom_special_method(left, "__eq__") or custom_special_method(right, "__eq__"):
+            return False
+
+        if prefer_literal:
+            # Also flag non-overlapping literals in situations like:
+            #    x: Literal['a', 'b']
+            #    if x == 'c':
+            #        ...
+            left = try_getting_literal(left)
+            right = try_getting_literal(right)
+
+        if self.chk.binder.is_unreachable_warning_suppressed():
+            # We are inside a function that contains type variables with value restrictions in
+            # its signature. In this case we just suppress all strict-equality checks to avoid
+            # false positives for code like:
+            #
+            #     T = TypeVar('T', str, int)
+            #     def f(x: T) -> T:
+            #         if x == 0:
+            #             ...
+            #         return x
+            #
+            # TODO: find a way of disabling the check only for types resulted from the expansion.
+            return False
+        if isinstance(left, NoneType) or isinstance(right, NoneType):
+            return False
+        if isinstance(left, UnionType) and isinstance(right, UnionType):
+            left = remove_optional(left)
+            right = remove_optional(right)
+            left, right = get_proper_types((left, right))
+        if (
+            original_container
+            and has_bytes_component(original_container)
+            and has_bytes_component(left)
+        ):
+            # We need to special case bytes and bytearray, because 97 in b'abc', b'a' in b'abc',
+            # b'a' in bytearray(b'abc') etc. all return True (and we want to show the error only
+            # if the check can _never_ be True).
+            return False
+        if isinstance(left, Instance) and isinstance(right, Instance):
+            # Special case some builtin implementations of AbstractSet.
+            left_name = left.type.fullname
+            right_name = right.type.fullname
+            if (
+                left_name in OVERLAPPING_TYPES_ALLOWLIST
+                and right_name in OVERLAPPING_TYPES_ALLOWLIST
+            ):
+                abstract_set = self.chk.lookup_typeinfo("typing.AbstractSet")
+                left = map_instance_to_supertype(left, abstract_set)
+                right = map_instance_to_supertype(right, abstract_set)
+                return self.dangerous_comparison(left.args[0], right.args[0])
+            elif left_name in ("builtins.list", "builtins.tuple") and right_name == left_name:
+                return self.dangerous_comparison(left.args[0], right.args[0])
+            elif left_name in OVERLAPPING_BYTES_ALLOWLIST and right_name in (
+                OVERLAPPING_BYTES_ALLOWLIST
+            ):
+                return False
+        if isinstance(left, LiteralType) and isinstance(right, LiteralType):
+            if isinstance(left.value, bool) and isinstance(right.value, bool):
+                # Comparing different booleans is not dangerous.
+                return False
+        return not is_overlapping_types(left, right, ignore_promotions=False)
+
+    def check_method_call_by_name(
+        self,
+        method: str,
+        base_type: Type,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        original_type: Type | None = None,
+    ) -> tuple[Type, Type]:
+        """Type check a call to a named method on an object.
+
+        Return tuple (result type, inferred method type). The 'original_type'
+        is used for error messages.
+        """
+        original_type = original_type or base_type
+        # Unions are special-cased to allow plugins to act on each element of the union.
+        base_type = get_proper_type(base_type)
+        if isinstance(base_type, UnionType):
+            return self.check_union_method_call_by_name(
+                method, base_type, args, arg_kinds, context, original_type
+            )
+
+        method_type = analyze_member_access(
+            method,
+            base_type,
+            context,
+            False,
+            False,
+            True,
+            self.msg,
+            original_type=original_type,
+            chk=self.chk,
+            in_literal_context=self.is_literal_context(),
+        )
+        return self.check_method_call(method, base_type, method_type, args, arg_kinds, context)
+
+    def check_union_method_call_by_name(
+        self,
+        method: str,
+        base_type: UnionType,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+        original_type: Type | None = None,
+    ) -> tuple[Type, Type]:
+        """Type check a call to a named method on an object with union type.
+
+        This essentially checks the call using check_method_call_by_name() for each
+        union item and unions the result. We do this to allow plugins to act on
+        individual union items.
+        """
+        res: list[Type] = []
+        meth_res: list[Type] = []
+        for typ in base_type.relevant_items():
+            # Format error messages consistently with
+            # mypy.checkmember.analyze_union_member_access().
+            with self.msg.disable_type_names():
+                item, meth_item = self.check_method_call_by_name(
+                    method, typ, args, arg_kinds, context, original_type
+                )
+            res.append(item)
+            meth_res.append(meth_item)
+        return make_simplified_union(res), make_simplified_union(meth_res)
+
+    def check_method_call(
+        self,
+        method_name: str,
+        base_type: Type,
+        method_type: Type,
+        args: list[Expression],
+        arg_kinds: list[ArgKind],
+        context: Context,
+    ) -> tuple[Type, Type]:
+        """Type check a call to a method with the given name and type on an object.
+
+        Return tuple (result type, inferred method type).
+        """
+        callable_name = self.method_fullname(base_type, method_name)
+        object_type = base_type if callable_name is not None else None
+
+        # Try to refine the method signature using plugin hooks before checking the call.
+        method_type = self.transform_callee_type(
+            callable_name, method_type, args, arg_kinds, context, object_type=object_type
+        )
+
+        return self.check_call(
+            method_type,
+            args,
+            arg_kinds,
+            context,
+            callable_name=callable_name,
+            object_type=base_type,
+        )
+
+    def check_op_reversible(
+        self,
+        op_name: str,
+        left_type: Type,
+        left_expr: Expression,
+        right_type: Type,
+        right_expr: Expression,
+        context: Context,
+    ) -> tuple[Type, Type]:
+        def lookup_operator(op_name: str, base_type: Type) -> Type | None:
+            """Looks up the given operator and returns the corresponding type,
+            if it exists."""
+
+            # This check is an important performance optimization,
+            # even though it is mostly a subset of
+            # analyze_member_access.
+            # TODO: Find a way to remove this call without performance implications.
+            if not self.has_member(base_type, op_name):
+                return None
+
+            with self.msg.filter_errors() as w:
+                member = analyze_member_access(
+                    name=op_name,
+                    typ=base_type,
+                    is_lvalue=False,
+                    is_super=False,
+                    is_operator=True,
+                    original_type=base_type,
+                    context=context,
+                    msg=self.msg,
+                    chk=self.chk,
+                    in_literal_context=self.is_literal_context(),
+                )
+                return None if w.has_new_errors() else member
+
+        def lookup_definer(typ: Instance, attr_name: str) -> str | None:
+            """Returns the name of the class that contains the actual definition of attr_name.
+
+            So if class A defines foo and class B subclasses A, running
+            'get_class_defined_in(B, "foo")` would return the full name of A.
+
+            However, if B were to override and redefine foo, that method call would
+            return the full name of B instead.
+
+            If the attr name is not present in the given class or its MRO, returns None.
+            """
+            for cls in typ.type.mro:
+                if cls.names.get(attr_name):
+                    return cls.fullname
+            return None
+
+        left_type = get_proper_type(left_type)
+        right_type = get_proper_type(right_type)
+
+        # If either the LHS or the RHS are Any, we can't really concluding anything
+        # about the operation since the Any type may or may not define an
+        # __op__ or __rop__ method. So, we punt and return Any instead.
+
+        if isinstance(left_type, AnyType):
+            any_type = AnyType(TypeOfAny.from_another_any, source_any=left_type)
+            return any_type, any_type
+        if isinstance(right_type, AnyType):
+            any_type = AnyType(TypeOfAny.from_another_any, source_any=right_type)
+            return any_type, any_type
+
+        # STEP 1:
+        # We start by getting the __op__ and __rop__ methods, if they exist.
+
+        rev_op_name = operators.reverse_op_methods[op_name]
+
+        left_op = lookup_operator(op_name, left_type)
+        right_op = lookup_operator(rev_op_name, right_type)
+
+        # STEP 2a:
+        # We figure out in which order Python will call the operator methods. As it
+        # turns out, it's not as simple as just trying to call __op__ first and
+        # __rop__ second.
+        #
+        # We store the determined order inside the 'variants_raw' variable,
+        # which records tuples containing the method, base type, and the argument.
+
+        if op_name in operators.op_methods_that_shortcut and is_same_type(left_type, right_type):
+            # When we do "A() + A()", for example, Python will only call the __add__ method,
+            # never the __radd__ method.
+            #
+            # This is the case even if the __add__ method is completely missing and the __radd__
+            # method is defined.
+
+            variants_raw = [(left_op, left_type, right_expr)]
+        elif (
+            is_subtype(right_type, left_type)
+            and isinstance(left_type, Instance)
+            and isinstance(right_type, Instance)
+            and not (
+                left_type.type.alt_promote is not None
+                and left_type.type.alt_promote.type is right_type.type
+            )
+            and lookup_definer(left_type, op_name) != lookup_definer(right_type, rev_op_name)
+        ):
+            # When we do "A() + B()" where B is a subclass of A, we'll actually try calling
+            # B's __radd__ method first, but ONLY if B explicitly defines or overrides the
+            # __radd__ method.
+            #
+            # This mechanism lets subclasses "refine" the expected outcome of the operation, even
+            # if they're located on the RHS.
+            #
+            # As a special case, the alt_promote check makes sure that we don't use the
+            # __radd__ method of int if the LHS is a native int type.
+
+            variants_raw = [(right_op, right_type, left_expr), (left_op, left_type, right_expr)]
+        else:
+            # In all other cases, we do the usual thing and call __add__ first and
+            # __radd__ second when doing "A() + B()".
+
+            variants_raw = [(left_op, left_type, right_expr), (right_op, right_type, left_expr)]
+
+        # STEP 3:
+        # We now filter out all non-existent operators. The 'variants' list contains
+        # all operator methods that are actually present, in the order that Python
+        # attempts to invoke them.
+
+        variants = [(op, obj, arg) for (op, obj, arg) in variants_raw if op is not None]
+
+        # STEP 4:
+        # We now try invoking each one. If an operation succeeds, end early and return
+        # the corresponding result. Otherwise, return the result and errors associated
+        # with the first entry.
+
+        errors = []
+        results = []
+        for method, obj, arg in variants:
+            with self.msg.filter_errors(save_filtered_errors=True) as local_errors:
+                result = self.check_method_call(op_name, obj, method, [arg], [ARG_POS], context)
+            if local_errors.has_new_errors():
+                errors.append(local_errors.filtered_errors())
+                results.append(result)
+            else:
+                return result
+
+        # We finish invoking above operators and no early return happens. Therefore,
+        # we check if either the LHS or the RHS is Instance and fallbacks to Any,
+        # if so, we also return Any
+        if (isinstance(left_type, Instance) and left_type.type.fallback_to_any) or (
+            isinstance(right_type, Instance) and right_type.type.fallback_to_any
+        ):
+            any_type = AnyType(TypeOfAny.special_form)
+            return any_type, any_type
+
+        # STEP 4b:
+        # Sometimes, the variants list is empty. In that case, we fall-back to attempting to
+        # call the __op__ method (even though it's missing).
+
+        if not variants:
+            with self.msg.filter_errors(save_filtered_errors=True) as local_errors:
+                result = self.check_method_call_by_name(
+                    op_name, left_type, [right_expr], [ARG_POS], context
+                )
+
+            if local_errors.has_new_errors():
+                errors.append(local_errors.filtered_errors())
+                results.append(result)
+            else:
+                # In theory, we should never enter this case, but it seems
+                # we sometimes do, when dealing with Type[...]? E.g. see
+                # check-classes.testTypeTypeComparisonWorks.
+                #
+                # This is probably related to the TODO in lookup_operator(...)
+                # up above.
+                #
+                # TODO: Remove this extra case
+                return result
+
+        self.msg.add_errors(errors[0])
+        if len(results) == 1:
+            return results[0]
+        else:
+            error_any = AnyType(TypeOfAny.from_error)
+            result = error_any, error_any
+            return result
+
+    def check_op(
+        self,
+        method: str,
+        base_type: Type,
+        arg: Expression,
+        context: Context,
+        allow_reverse: bool = False,
+    ) -> tuple[Type, Type]:
+        """Type check a binary operation which maps to a method call.
+
+        Return tuple (result type, inferred operator method type).
+        """
+
+        if allow_reverse:
+            left_variants = [base_type]
+            base_type = get_proper_type(base_type)
+            if isinstance(base_type, UnionType):
+                left_variants = [
+                    item for item in flatten_nested_unions(base_type.relevant_items())
+                ]
+            right_type = self.accept(arg)
+
+            # Step 1: We first try leaving the right arguments alone and destructure
+            # just the left ones. (Mypy can sometimes perform some more precise inference
+            # if we leave the right operands a union -- see testOperatorWithEmptyListAndSum.)
+            all_results = []
+            all_inferred = []
+
+            with self.msg.filter_errors() as local_errors:
+                for left_possible_type in left_variants:
+                    result, inferred = self.check_op_reversible(
+                        op_name=method,
+                        left_type=left_possible_type,
+                        left_expr=TempNode(left_possible_type, context=context),
+                        right_type=right_type,
+                        right_expr=arg,
+                        context=context,
+                    )
+                    all_results.append(result)
+                    all_inferred.append(inferred)
+
+            if not local_errors.has_new_errors():
+                results_final = make_simplified_union(all_results)
+                inferred_final = make_simplified_union(all_inferred)
+                return results_final, inferred_final
+
+            # Step 2: If that fails, we try again but also destructure the right argument.
+            # This is also necessary to make certain edge cases work -- see
+            # testOperatorDoubleUnionInterwovenUnionAdd, for example.
+
+            # Note: We want to pass in the original 'arg' for 'left_expr' and 'right_expr'
+            # whenever possible so that plugins and similar things can introspect on the original
+            # node if possible.
+            #
+            # We don't do the same for the base expression because it could lead to weird
+            # type inference errors -- e.g. see 'testOperatorDoubleUnionSum'.
+            # TODO: Can we use `type_overrides_set()` here?
+            right_variants = [(right_type, arg)]
+            right_type = get_proper_type(right_type)
+            if isinstance(right_type, UnionType):
+                right_variants = [
+                    (item, TempNode(item, context=context))
+                    for item in flatten_nested_unions(right_type.relevant_items())
+                ]
+
+            all_results = []
+            all_inferred = []
+
+            with self.msg.filter_errors(save_filtered_errors=True) as local_errors:
+                for left_possible_type in left_variants:
+                    for right_possible_type, right_expr in right_variants:
+                        result, inferred = self.check_op_reversible(
+                            op_name=method,
+                            left_type=left_possible_type,
+                            left_expr=TempNode(left_possible_type, context=context),
+                            right_type=right_possible_type,
+                            right_expr=right_expr,
+                            context=context,
+                        )
+                        all_results.append(result)
+                        all_inferred.append(inferred)
+
+            if local_errors.has_new_errors():
+                self.msg.add_errors(local_errors.filtered_errors())
+                # Point any notes to the same location as an existing message.
+                err = local_errors.filtered_errors()[-1]
+                recent_context = TempNode(NoneType())
+                recent_context.line = err.line
+                recent_context.column = err.column
+                if len(left_variants) >= 2 and len(right_variants) >= 2:
+                    self.msg.warn_both_operands_are_from_unions(recent_context)
+                elif len(left_variants) >= 2:
+                    self.msg.warn_operand_was_from_union("Left", base_type, context=recent_context)
+                elif len(right_variants) >= 2:
+                    self.msg.warn_operand_was_from_union(
+                        "Right", right_type, context=recent_context
+                    )
+
+            # See the comment in 'check_overload_call' for more details on why
+            # we call 'combine_function_signature' instead of just unioning the inferred
+            # callable types.
+            results_final = make_simplified_union(all_results)
+            inferred_final = self.combine_function_signatures(get_proper_types(all_inferred))
+            return results_final, inferred_final
+        else:
+            return self.check_method_call_by_name(
+                method=method,
+                base_type=base_type,
+                args=[arg],
+                arg_kinds=[ARG_POS],
+                context=context,
+            )
+
+    def check_boolean_op(self, e: OpExpr, context: Context) -> Type:
+        """Type check a boolean operation ('and' or 'or')."""
+
+        # A boolean operation can evaluate to either of the operands.
+
+        # We use the current type context to guide the type inference of of
+        # the left operand. We also use the left operand type to guide the type
+        # inference of the right operand so that expressions such as
+        # '[1] or []' are inferred correctly.
+        ctx = self.type_context[-1]
+        left_type = self.accept(e.left, ctx)
+        expanded_left_type = try_expanding_sum_type_to_union(
+            self.accept(e.left, ctx), "builtins.bool"
+        )
+
+        assert e.op in ("and", "or")  # Checked by visit_op_expr
+
+        if e.right_always:
+            left_map: mypy.checker.TypeMap = None
+            right_map: mypy.checker.TypeMap = {}
+        elif e.right_unreachable:
+            left_map, right_map = {}, None
+        elif e.op == "and":
+            right_map, left_map = self.chk.find_isinstance_check(e.left)
+        elif e.op == "or":
+            left_map, right_map = self.chk.find_isinstance_check(e.left)
+
+        # If left_map is None then we know mypy considers the left expression
+        # to be redundant.
+        if (
+            codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes
+            and left_map is None
+            # don't report an error if it's intentional
+            and not e.right_always
+        ):
+            self.msg.redundant_left_operand(e.op, e.left)
+
+        if (
+            self.chk.should_report_unreachable_issues()
+            and right_map is None
+            # don't report an error if it's intentional
+            and not e.right_unreachable
+        ):
+            self.msg.unreachable_right_operand(e.op, e.right)
+
+        # If right_map is None then we know mypy considers the right branch
+        # to be unreachable and therefore any errors found in the right branch
+        # should be suppressed.
+        with self.msg.filter_errors(filter_errors=right_map is None):
+            right_type = self.analyze_cond_branch(right_map, e.right, expanded_left_type)
+
+        if left_map is None and right_map is None:
+            return UninhabitedType()
+
+        if right_map is None:
+            # The boolean expression is statically known to be the left value
+            assert left_map is not None
+            return left_type
+        if left_map is None:
+            # The boolean expression is statically known to be the right value
+            assert right_map is not None
+            return right_type
+
+        if e.op == "and":
+            restricted_left_type = false_only(expanded_left_type)
+            result_is_left = not expanded_left_type.can_be_true
+        elif e.op == "or":
+            restricted_left_type = true_only(expanded_left_type)
+            result_is_left = not expanded_left_type.can_be_false
+
+        if isinstance(restricted_left_type, UninhabitedType):
+            # The left operand can never be the result
+            return right_type
+        elif result_is_left:
+            # The left operand is always the result
+            return left_type
+        else:
+            return make_simplified_union([restricted_left_type, right_type])
+
+    def check_list_multiply(self, e: OpExpr) -> Type:
+        """Type check an expression of form '[...] * e'.
+
+        Type inference is special-cased for this common construct.
+        """
+        right_type = self.accept(e.right)
+        if is_subtype(right_type, self.named_type("builtins.int")):
+            # Special case: [...] * <int value>. Use the type context of the
+            # OpExpr, since the multiplication does not affect the type.
+            left_type = self.accept(e.left, type_context=self.type_context[-1])
+        else:
+            left_type = self.accept(e.left)
+        result, method_type = self.check_op("__mul__", left_type, e.right, e)
+        e.method_type = method_type
+        return result
+
+    def visit_assignment_expr(self, e: AssignmentExpr) -> Type:
+        value = self.accept(e.value)
+        self.chk.check_assignment(e.target, e.value)
+        self.chk.check_final(e)
+        self.chk.store_type(e.target, value)
+        self.find_partial_type_ref_fast_path(e.target)
+        return value
+
+    def visit_unary_expr(self, e: UnaryExpr) -> Type:
+        """Type check an unary operation ('not', '-', '+' or '~')."""
+        operand_type = self.accept(e.expr)
+        op = e.op
+        if op == "not":
+            result: Type = self.bool_type()
+        else:
+            method = operators.unary_op_methods[op]
+            result, method_type = self.check_method_call_by_name(method, operand_type, [], [], e)
+            e.method_type = method_type
+        return result
+
+    def visit_index_expr(self, e: IndexExpr) -> Type:
+        """Type check an index expression (base[index]).
+
+        It may also represent type application.
+        """
+        result = self.visit_index_expr_helper(e)
+        result = self.narrow_type_from_binder(e, result)
+        p_result = get_proper_type(result)
+        if (
+            self.is_literal_context()
+            and isinstance(p_result, Instance)
+            and p_result.last_known_value is not None
+        ):
+            result = p_result.last_known_value
+        return result
+
+    def visit_index_expr_helper(self, e: IndexExpr) -> Type:
+        if e.analyzed:
+            # It's actually a type application.
+            return self.accept(e.analyzed)
+        left_type = self.accept(e.base)
+        return self.visit_index_with_type(left_type, e)
+
+    def visit_index_with_type(
+        self, left_type: Type, e: IndexExpr, original_type: ProperType | None = None
+    ) -> Type:
+        """Analyze type of an index expression for a given type of base expression.
+
+        The 'original_type' is used for error messages (currently used for union types).
+        """
+        index = e.index
+        left_type = get_proper_type(left_type)
+
+        # Visit the index, just to make sure we have a type for it available
+        self.accept(index)
+
+        if isinstance(left_type, UnionType):
+            original_type = original_type or left_type
+            # Don't combine literal types, since we may need them for type narrowing.
+            return make_simplified_union(
+                [
+                    self.visit_index_with_type(typ, e, original_type)
+                    for typ in left_type.relevant_items()
+                ],
+                contract_literals=False,
+            )
+        elif isinstance(left_type, TupleType) and self.chk.in_checked_function():
+            # Special case for tuples. They return a more specific type when
+            # indexed by an integer literal.
+            if isinstance(index, SliceExpr):
+                return self.visit_tuple_slice_helper(left_type, index)
+
+            ns = self.try_getting_int_literals(index)
+            if ns is not None:
+                out = []
+                for n in ns:
+                    if n < 0:
+                        n += len(left_type.items)
+                    if 0 <= n < len(left_type.items):
+                        out.append(left_type.items[n])
+                    else:
+                        self.chk.fail(message_registry.TUPLE_INDEX_OUT_OF_RANGE, e)
+                        return AnyType(TypeOfAny.from_error)
+                return make_simplified_union(out)
+            else:
+                return self.nonliteral_tuple_index_helper(left_type, index)
+        elif isinstance(left_type, TypedDictType):
+            return self.visit_typeddict_index_expr(left_type, e.index)
+        elif (
+            isinstance(left_type, CallableType)
+            and left_type.is_type_obj()
+            and left_type.type_object().is_enum
+        ):
+            return self.visit_enum_index_expr(left_type.type_object(), e.index, e)
+        elif isinstance(left_type, TypeVarType) and not self.has_member(
+            left_type.upper_bound, "__getitem__"
+        ):
+            return self.visit_index_with_type(left_type.upper_bound, e, original_type)
+        else:
+            result, method_type = self.check_method_call_by_name(
+                "__getitem__", left_type, [e.index], [ARG_POS], e, original_type=original_type
+            )
+            e.method_type = method_type
+            return result
+
+    def visit_tuple_slice_helper(self, left_type: TupleType, slic: SliceExpr) -> Type:
+        begin: Sequence[int | None] = [None]
+        end: Sequence[int | None] = [None]
+        stride: Sequence[int | None] = [None]
+
+        if slic.begin_index:
+            begin_raw = self.try_getting_int_literals(slic.begin_index)
+            if begin_raw is None:
+                return self.nonliteral_tuple_index_helper(left_type, slic)
+            begin = begin_raw
+
+        if slic.end_index:
+            end_raw = self.try_getting_int_literals(slic.end_index)
+            if end_raw is None:
+                return self.nonliteral_tuple_index_helper(left_type, slic)
+            end = end_raw
+
+        if slic.stride:
+            stride_raw = self.try_getting_int_literals(slic.stride)
+            if stride_raw is None:
+                return self.nonliteral_tuple_index_helper(left_type, slic)
+            stride = stride_raw
+
+        items: list[Type] = []
+        for b, e, s in itertools.product(begin, end, stride):
+            items.append(left_type.slice(b, e, s))
+        return make_simplified_union(items)
+
+    def try_getting_int_literals(self, index: Expression) -> list[int] | None:
+        """If the given expression or type corresponds to an int literal
+        or a union of int literals, returns a list of the underlying ints.
+        Otherwise, returns None.
+
+        Specifically, this function is guaranteed to return a list with
+        one or more ints if one one the following is true:
+
+        1. 'expr' is a IntExpr or a UnaryExpr backed by an IntExpr
+        2. 'typ' is a LiteralType containing an int
+        3. 'typ' is a UnionType containing only LiteralType of ints
+        """
+        if isinstance(index, IntExpr):
+            return [index.value]
+        elif isinstance(index, UnaryExpr):
+            if index.op == "-":
+                operand = index.expr
+                if isinstance(operand, IntExpr):
+                    return [-1 * operand.value]
+        typ = get_proper_type(self.accept(index))
+        if isinstance(typ, Instance) and typ.last_known_value is not None:
+            typ = typ.last_known_value
+        if isinstance(typ, LiteralType) and isinstance(typ.value, int):
+            return [typ.value]
+        if isinstance(typ, UnionType):
+            out = []
+            for item in get_proper_types(typ.items):
+                if isinstance(item, LiteralType) and isinstance(item.value, int):
+                    out.append(item.value)
+                else:
+                    return None
+            return out
+        return None
+
+    def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) -> Type:
+        self.check_method_call_by_name("__getitem__", left_type, [index], [ARG_POS], context=index)
+        # We could return the return type from above, but unions are often better than the join
+        union = make_simplified_union(left_type.items)
+        if isinstance(index, SliceExpr):
+            return self.chk.named_generic_type("builtins.tuple", [union])
+        return union
+
+    def visit_typeddict_index_expr(
+        self, td_type: TypedDictType, index: Expression, setitem: bool = False
+    ) -> Type:
+        if isinstance(index, StrExpr):
+            key_names = [index.value]
+        else:
+            typ = get_proper_type(self.accept(index))
+            if isinstance(typ, UnionType):
+                key_types: list[Type] = list(typ.items)
+            else:
+                key_types = [typ]
+
+            key_names = []
+            for key_type in get_proper_types(key_types):
+                if isinstance(key_type, Instance) and key_type.last_known_value is not None:
+                    key_type = key_type.last_known_value
+
+                if (
+                    isinstance(key_type, LiteralType)
+                    and isinstance(key_type.value, str)
+                    and key_type.fallback.type.fullname != "builtins.bytes"
+                ):
+                    key_names.append(key_type.value)
+                else:
+                    self.msg.typeddict_key_must_be_string_literal(td_type, index)
+                    return AnyType(TypeOfAny.from_error)
+
+        value_types = []
+        for key_name in key_names:
+            value_type = td_type.items.get(key_name)
+            if value_type is None:
+                self.msg.typeddict_key_not_found(td_type, key_name, index, setitem)
+                return AnyType(TypeOfAny.from_error)
+            else:
+                value_types.append(value_type)
+        return make_simplified_union(value_types)
+
+    def visit_enum_index_expr(
+        self, enum_type: TypeInfo, index: Expression, context: Context
+    ) -> Type:
+        string_type: Type = self.named_type("builtins.str")
+        self.chk.check_subtype(
+            self.accept(index),
+            string_type,
+            context,
+            "Enum index should be a string",
+            "actual index type",
+        )
+        return Instance(enum_type, [])
+
+    def visit_cast_expr(self, expr: CastExpr) -> Type:
+        """Type check a cast expression."""
+        source_type = self.accept(
+            expr.expr,
+            type_context=AnyType(TypeOfAny.special_form),
+            allow_none_return=True,
+            always_allow_any=True,
+        )
+        target_type = expr.type
+        options = self.chk.options
+        if (
+            options.warn_redundant_casts
+            and not isinstance(get_proper_type(target_type), AnyType)
+            and source_type == target_type
+        ):
+            self.msg.redundant_cast(target_type, expr)
+        if options.disallow_any_unimported and has_any_from_unimported_type(target_type):
+            self.msg.unimported_type_becomes_any("Target type of cast", target_type, expr)
+        check_for_explicit_any(
+            target_type, self.chk.options, self.chk.is_typeshed_stub, self.msg, context=expr
+        )
+        return target_type
+
+    def visit_assert_type_expr(self, expr: AssertTypeExpr) -> Type:
+        source_type = self.accept(
+            expr.expr,
+            type_context=self.type_context[-1],
+            allow_none_return=True,
+            always_allow_any=True,
+        )
+        target_type = expr.type
+        proper_source_type = get_proper_type(source_type)
+        if (
+            isinstance(proper_source_type, mypy.types.Instance)
+            and proper_source_type.last_known_value is not None
+        ):
+            source_type = proper_source_type.last_known_value
+        if not is_same_type(source_type, target_type):
+            if not self.chk.in_checked_function():
+                self.msg.note(
+                    '"assert_type" expects everything to be "Any" in unchecked functions',
+                    expr.expr,
+                )
+            self.msg.assert_type_fail(source_type, target_type, expr)
+        return source_type
+
+    def visit_reveal_expr(self, expr: RevealExpr) -> Type:
+        """Type check a reveal_type expression."""
+        if expr.kind == REVEAL_TYPE:
+            assert expr.expr is not None
+            revealed_type = self.accept(
+                expr.expr, type_context=self.type_context[-1], allow_none_return=True
+            )
+            if not self.chk.current_node_deferred:
+                self.msg.reveal_type(revealed_type, expr.expr)
+                if not self.chk.in_checked_function():
+                    self.msg.note(
+                        "'reveal_type' always outputs 'Any' in unchecked functions", expr.expr
+                    )
+            return revealed_type
+        else:
+            # REVEAL_LOCALS
+            if not self.chk.current_node_deferred:
+                # the RevealExpr contains a local_nodes attribute,
+                # calculated at semantic analysis time. Use it to pull out the
+                # corresponding subset of variables in self.chk.type_map
+                names_to_types = (
+                    {var_node.name: var_node.type for var_node in expr.local_nodes}
+                    if expr.local_nodes is not None
+                    else {}
+                )
+
+                self.msg.reveal_locals(names_to_types, expr)
+            return NoneType()
+
+    def visit_type_application(self, tapp: TypeApplication) -> Type:
+        """Type check a type application (expr[type, ...]).
+
+        There are two different options here, depending on whether expr refers
+        to a type alias or directly to a generic class. In the first case we need
+        to use a dedicated function typeanal.instantiate_type_alias(). This
+        is due to slight differences in how type arguments are applied and checked.
+        """
+        if isinstance(tapp.expr, RefExpr) and isinstance(tapp.expr.node, TypeAlias):
+            # Subscription of a (generic) alias in runtime context, expand the alias.
+            item = instantiate_type_alias(
+                tapp.expr.node,
+                tapp.types,
+                self.chk.fail,
+                tapp.expr.node.no_args,
+                tapp,
+                self.chk.options,
+            )
+            item = get_proper_type(item)
+            if isinstance(item, Instance):
+                tp = type_object_type(item.type, self.named_type)
+                return self.apply_type_arguments_to_callable(tp, item.args, tapp)
+            elif isinstance(item, TupleType) and item.partial_fallback.type.is_named_tuple:
+                tp = type_object_type(item.partial_fallback.type, self.named_type)
+                return self.apply_type_arguments_to_callable(tp, item.partial_fallback.args, tapp)
+            elif isinstance(item, TypedDictType):
+                return self.typeddict_callable_from_context(item)
+            else:
+                self.chk.fail(message_registry.ONLY_CLASS_APPLICATION, tapp)
+                return AnyType(TypeOfAny.from_error)
+        # Type application of a normal generic class in runtime context.
+        # This is typically used as `x = G[int]()`.
+        tp = get_proper_type(self.accept(tapp.expr))
+        if isinstance(tp, (CallableType, Overloaded)):
+            if not tp.is_type_obj():
+                self.chk.fail(message_registry.ONLY_CLASS_APPLICATION, tapp)
+            return self.apply_type_arguments_to_callable(tp, tapp.types, tapp)
+        if isinstance(tp, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=tp)
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_type_alias_expr(self, alias: TypeAliasExpr) -> Type:
+        """Right hand side of a type alias definition.
+
+        It has the same type as if the alias itself was used in a runtime context.
+        For example, here:
+
+            A = reveal_type(List[T])
+            reveal_type(A)
+
+        both `reveal_type` instances will reveal the same type `def (...) -> builtins.list[Any]`.
+        Note that type variables are implicitly substituted with `Any`.
+        """
+        return self.alias_type_in_runtime_context(alias.node, ctx=alias, alias_definition=True)
+
+    def alias_type_in_runtime_context(
+        self, alias: TypeAlias, *, ctx: Context, alias_definition: bool = False
+    ) -> Type:
+        """Get type of a type alias (could be generic) in a runtime expression.
+
+        Note that this function can be called only if the alias appears _not_
+        as a target of type application, which is treated separately in the
+        visit_type_application method. Some examples where this method is called are
+        casts and instantiation:
+
+            class LongName(Generic[T]): ...
+            A = LongName[int]
+
+            x = A()
+            y = cast(A, ...)
+        """
+        if isinstance(alias.target, Instance) and alias.target.invalid:  # type: ignore[misc]
+            # An invalid alias, error already has been reported
+            return AnyType(TypeOfAny.from_error)
+        # If this is a generic alias, we set all variables to `Any`.
+        # For example:
+        #     A = List[Tuple[T, T]]
+        #     x = A() <- same as List[Tuple[Any, Any]], see PEP 484.
+        disallow_any = self.chk.options.disallow_any_generics and self.is_callee
+        item = get_proper_type(
+            set_any_tvars(
+                alias,
+                ctx.line,
+                ctx.column,
+                self.chk.options,
+                disallow_any=disallow_any,
+                fail=self.msg.fail,
+            )
+        )
+        if isinstance(item, Instance):
+            # Normally we get a callable type (or overloaded) with .is_type_obj() true
+            # representing the class's constructor
+            tp = type_object_type(item.type, self.named_type)
+            if alias.no_args:
+                return tp
+            return self.apply_type_arguments_to_callable(tp, item.args, ctx)
+        elif (
+            isinstance(item, TupleType)
+            and
+            # Tuple[str, int]() fails at runtime, only named tuples and subclasses work.
+            tuple_fallback(item).type.fullname != "builtins.tuple"
+        ):
+            return type_object_type(tuple_fallback(item).type, self.named_type)
+        elif isinstance(item, TypedDictType):
+            return self.typeddict_callable_from_context(item)
+        elif isinstance(item, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=item)
+        else:
+            if alias_definition:
+                return AnyType(TypeOfAny.special_form)
+            # The _SpecialForm type can be used in some runtime contexts (e.g. it may have __or__).
+            return self.named_type("typing._SpecialForm")
+
+    def split_for_callable(
+        self, t: CallableType, args: Sequence[Type], ctx: Context
+    ) -> list[Type]:
+        """Handle directly applying type arguments to a variadic Callable.
+
+        This is needed in situations where e.g. variadic class object appears in
+        runtime context. For example:
+            class C(Generic[T, Unpack[Ts]]): ...
+            x = C[int, str]()
+
+        We simply group the arguments that need to go into Ts variable into a TupleType,
+        similar to how it is done in other places using split_with_prefix_and_suffix().
+        """
+        vars = t.variables
+        if not vars or not any(isinstance(v, TypeVarTupleType) for v in vars):
+            return list(args)
+
+        prefix = next(i for (i, v) in enumerate(vars) if isinstance(v, TypeVarTupleType))
+        suffix = len(vars) - prefix - 1
+        args = flatten_nested_tuples(args)
+        if len(args) < len(vars) - 1:
+            self.msg.incompatible_type_application(len(vars), len(args), ctx)
+            return [AnyType(TypeOfAny.from_error)] * len(vars)
+
+        tvt = vars[prefix]
+        assert isinstance(tvt, TypeVarTupleType)
+        start, middle, end = split_with_prefix_and_suffix(tuple(args), prefix, suffix)
+        return list(start) + [TupleType(list(middle), tvt.tuple_fallback)] + list(end)
+
+    def apply_type_arguments_to_callable(
+        self, tp: Type, args: Sequence[Type], ctx: Context
+    ) -> Type:
+        """Apply type arguments to a generic callable type coming from a type object.
+
+        This will first perform type arguments count checks, report the
+        error as needed, and return the correct kind of Any. As a special
+        case this returns Any for non-callable types, because if type object type
+        is not callable, then an error should be already reported.
+        """
+        tp = get_proper_type(tp)
+
+        if isinstance(tp, CallableType):
+            if len(tp.variables) != len(args) and not any(
+                isinstance(v, TypeVarTupleType) for v in tp.variables
+            ):
+                if tp.is_type_obj() and tp.type_object().fullname == "builtins.tuple":
+                    # TODO: Specialize the callable for the type arguments
+                    return tp
+                self.msg.incompatible_type_application(len(tp.variables), len(args), ctx)
+                return AnyType(TypeOfAny.from_error)
+            return self.apply_generic_arguments(tp, self.split_for_callable(tp, args, ctx), ctx)
+        if isinstance(tp, Overloaded):
+            for it in tp.items:
+                if len(it.variables) != len(args) and not any(
+                    isinstance(v, TypeVarTupleType) for v in it.variables
+                ):
+                    self.msg.incompatible_type_application(len(it.variables), len(args), ctx)
+                    return AnyType(TypeOfAny.from_error)
+            return Overloaded(
+                [
+                    self.apply_generic_arguments(it, self.split_for_callable(it, args, ctx), ctx)
+                    for it in tp.items
+                ]
+            )
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_list_expr(self, e: ListExpr) -> Type:
+        """Type check a list expression [...]."""
+        return self.check_lst_expr(e, "builtins.list", "<list>")
+
+    def visit_set_expr(self, e: SetExpr) -> Type:
+        return self.check_lst_expr(e, "builtins.set", "<set>")
+
+    def fast_container_type(
+        self, e: ListExpr | SetExpr | TupleExpr, container_fullname: str
+    ) -> Type | None:
+        """
+        Fast path to determine the type of a list or set literal,
+        based on the list of entries. This mostly impacts large
+        module-level constant definitions.
+
+        Limitations:
+         - no active type context
+         - no star expressions
+         - the joined type of all entries must be an Instance or Tuple type
+        """
+        ctx = self.type_context[-1]
+        if ctx:
+            return None
+        rt = self.resolved_type.get(e, None)
+        if rt is not None:
+            return rt if isinstance(rt, Instance) else None
+        values: list[Type] = []
+        for item in e.items:
+            if isinstance(item, StarExpr):
+                # fallback to slow path
+                self.resolved_type[e] = NoneType()
+                return None
+            values.append(self.accept(item))
+        vt = join.join_type_list(values)
+        if not allow_fast_container_literal(vt):
+            self.resolved_type[e] = NoneType()
+            return None
+        ct = self.chk.named_generic_type(container_fullname, [vt])
+        self.resolved_type[e] = ct
+        return ct
+
+    def check_lst_expr(self, e: ListExpr | SetExpr | TupleExpr, fullname: str, tag: str) -> Type:
+        # fast path
+        t = self.fast_container_type(e, fullname)
+        if t:
+            return t
+
+        # Translate into type checking a generic function call.
+        # Used for list and set expressions, as well as for tuples
+        # containing star expressions that don't refer to a
+        # Tuple. (Note: "lst" stands for list-set-tuple. :-)
+        tv = TypeVarType(
+            "T",
+            "T",
+            id=-1,
+            values=[],
+            upper_bound=self.object_type(),
+            default=AnyType(TypeOfAny.from_omitted_generics),
+        )
+        constructor = CallableType(
+            [tv],
+            [nodes.ARG_STAR],
+            [None],
+            self.chk.named_generic_type(fullname, [tv]),
+            self.named_type("builtins.function"),
+            name=tag,
+            variables=[tv],
+        )
+        out = self.check_call(
+            constructor,
+            [(i.expr if isinstance(i, StarExpr) else i) for i in e.items],
+            [(nodes.ARG_STAR if isinstance(i, StarExpr) else nodes.ARG_POS) for i in e.items],
+            e,
+        )[0]
+        return remove_instance_last_known_values(out)
+
+    def visit_tuple_expr(self, e: TupleExpr) -> Type:
+        """Type check a tuple expression."""
+        # Try to determine type context for type inference.
+        type_context = get_proper_type(self.type_context[-1])
+        type_context_items = None
+        if isinstance(type_context, UnionType):
+            tuples_in_context = [
+                t
+                for t in get_proper_types(type_context.items)
+                if (isinstance(t, TupleType) and len(t.items) == len(e.items))
+                or is_named_instance(t, TUPLE_LIKE_INSTANCE_NAMES)
+            ]
+            if len(tuples_in_context) == 1:
+                type_context = tuples_in_context[0]
+            else:
+                # There are either no relevant tuples in the Union, or there is
+                # more than one.  Either way, we can't decide on a context.
+                pass
+
+        if isinstance(type_context, TupleType):
+            type_context_items = type_context.items
+        elif type_context and is_named_instance(type_context, TUPLE_LIKE_INSTANCE_NAMES):
+            assert isinstance(type_context, Instance)
+            if type_context.args:
+                type_context_items = [type_context.args[0]] * len(e.items)
+        # NOTE: it's possible for the context to have a different
+        # number of items than e.  In that case we use those context
+        # items that match a position in e, and we'll worry about type
+        # mismatches later.
+
+        # Infer item types.  Give up if there's a star expression
+        # that's not a Tuple.
+        items: list[Type] = []
+        j = 0  # Index into type_context_items; irrelevant if type_context_items is none
+        for i in range(len(e.items)):
+            item = e.items[i]
+            if isinstance(item, StarExpr):
+                # Special handling for star expressions.
+                # TODO: If there's a context, and item.expr is a
+                # TupleExpr, flatten it, so we can benefit from the
+                # context?  Counterargument: Why would anyone write
+                # (1, *(2, 3)) instead of (1, 2, 3) except in a test?
+                tt = self.accept(item.expr)
+                tt = get_proper_type(tt)
+                if isinstance(tt, TupleType):
+                    items.extend(tt.items)
+                    j += len(tt.items)
+                else:
+                    # A star expression that's not a Tuple.
+                    # Treat the whole thing as a variable-length tuple.
+                    return self.check_lst_expr(e, "builtins.tuple", "<tuple>")
+            else:
+                if not type_context_items or j >= len(type_context_items):
+                    tt = self.accept(item)
+                else:
+                    tt = self.accept(item, type_context_items[j])
+                    j += 1
+                items.append(tt)
+        # This is a partial fallback item type. A precise type will be calculated on demand.
+        fallback_item = AnyType(TypeOfAny.special_form)
+        return TupleType(items, self.chk.named_generic_type("builtins.tuple", [fallback_item]))
+
+    def fast_dict_type(self, e: DictExpr) -> Type | None:
+        """
+        Fast path to determine the type of a dict literal,
+        based on the list of entries. This mostly impacts large
+        module-level constant definitions.
+
+        Limitations:
+         - no active type context
+         - only supported star expressions are other dict instances
+         - the joined types of all keys and values must be Instance or Tuple types
+        """
+        ctx = self.type_context[-1]
+        if ctx:
+            return None
+        rt = self.resolved_type.get(e, None)
+        if rt is not None:
+            return rt if isinstance(rt, Instance) else None
+        keys: list[Type] = []
+        values: list[Type] = []
+        stargs: tuple[Type, Type] | None = None
+        for key, value in e.items:
+            if key is None:
+                st = get_proper_type(self.accept(value))
+                if (
+                    isinstance(st, Instance)
+                    and st.type.fullname == "builtins.dict"
+                    and len(st.args) == 2
+                ):
+                    stargs = (st.args[0], st.args[1])
+                else:
+                    self.resolved_type[e] = NoneType()
+                    return None
+            else:
+                keys.append(self.accept(key))
+                values.append(self.accept(value))
+        kt = join.join_type_list(keys)
+        vt = join.join_type_list(values)
+        if not (allow_fast_container_literal(kt) and allow_fast_container_literal(vt)):
+            self.resolved_type[e] = NoneType()
+            return None
+        if stargs and (stargs[0] != kt or stargs[1] != vt):
+            self.resolved_type[e] = NoneType()
+            return None
+        dt = self.chk.named_generic_type("builtins.dict", [kt, vt])
+        self.resolved_type[e] = dt
+        return dt
+
+    def check_typeddict_literal_in_context(
+        self, e: DictExpr, typeddict_context: TypedDictType
+    ) -> Type:
+        orig_ret_type = self.check_typeddict_call_with_dict(
+            callee=typeddict_context, kwargs=e.items, context=e, orig_callee=None
+        )
+        ret_type = get_proper_type(orig_ret_type)
+        if isinstance(ret_type, TypedDictType):
+            return ret_type.copy_modified()
+        return typeddict_context.copy_modified()
+
+    def visit_dict_expr(self, e: DictExpr) -> Type:
+        """Type check a dict expression.
+
+        Translate it into a call to dict(), with provisions for **expr.
+        """
+        # if the dict literal doesn't match TypedDict, check_typeddict_call_with_dict reports
+        # an error, but returns the TypedDict type that matches the literal it found
+        # that would cause a second error when that TypedDict type is returned upstream
+        # to avoid the second error, we always return TypedDict type that was requested
+        typeddict_contexts = self.find_typeddict_context(self.type_context[-1], e)
+        if typeddict_contexts:
+            if len(typeddict_contexts) == 1:
+                return self.check_typeddict_literal_in_context(e, typeddict_contexts[0])
+            # Multiple items union, check if at least one of them matches cleanly.
+            for typeddict_context in typeddict_contexts:
+                with self.msg.filter_errors() as err, self.chk.local_type_map() as tmap:
+                    ret_type = self.check_typeddict_literal_in_context(e, typeddict_context)
+                if err.has_new_errors():
+                    continue
+                self.chk.store_types(tmap)
+                return ret_type
+            # No item matched without an error, so we can't unambiguously choose the item.
+            self.msg.typeddict_context_ambiguous(typeddict_contexts, e)
+
+        # fast path attempt
+        dt = self.fast_dict_type(e)
+        if dt:
+            return dt
+
+        # Define type variables (used in constructors below).
+        kt = TypeVarType(
+            "KT",
+            "KT",
+            id=-1,
+            values=[],
+            upper_bound=self.object_type(),
+            default=AnyType(TypeOfAny.from_omitted_generics),
+        )
+        vt = TypeVarType(
+            "VT",
+            "VT",
+            id=-2,
+            values=[],
+            upper_bound=self.object_type(),
+            default=AnyType(TypeOfAny.from_omitted_generics),
+        )
+
+        # Collect function arguments, watching out for **expr.
+        args: list[Expression] = []
+        expected_types: list[Type] = []
+        for key, value in e.items:
+            if key is None:
+                args.append(value)
+                expected_types.append(
+                    self.chk.named_generic_type("_typeshed.SupportsKeysAndGetItem", [kt, vt])
+                )
+            else:
+                tup = TupleExpr([key, value])
+                if key.line >= 0:
+                    tup.line = key.line
+                    tup.column = key.column
+                else:
+                    tup.line = value.line
+                    tup.column = value.column
+                tup.end_line = value.end_line
+                tup.end_column = value.end_column
+                args.append(tup)
+                expected_types.append(TupleType([kt, vt], self.named_type("builtins.tuple")))
+
+        # The callable type represents a function like this (except we adjust for **expr):
+        #   def <dict>(*v: Tuple[kt, vt]) -> Dict[kt, vt]: ...
+        constructor = CallableType(
+            expected_types,
+            [nodes.ARG_POS] * len(expected_types),
+            [None] * len(expected_types),
+            self.chk.named_generic_type("builtins.dict", [kt, vt]),
+            self.named_type("builtins.function"),
+            name="<dict>",
+            variables=[kt, vt],
+        )
+        return self.check_call(constructor, args, [nodes.ARG_POS] * len(args), e)[0]
+
+    def find_typeddict_context(
+        self, context: Type | None, dict_expr: DictExpr
+    ) -> list[TypedDictType]:
+        context = get_proper_type(context)
+        if isinstance(context, TypedDictType):
+            return [context]
+        elif isinstance(context, UnionType):
+            items = []
+            for item in context.items:
+                item_contexts = self.find_typeddict_context(item, dict_expr)
+                for item_context in item_contexts:
+                    if self.match_typeddict_call_with_dict(
+                        item_context, dict_expr.items, dict_expr
+                    ):
+                        items.append(item_context)
+            return items
+        # No TypedDict type in context.
+        return []
+
+    def visit_lambda_expr(self, e: LambdaExpr) -> Type:
+        """Type check lambda expression."""
+        self.chk.check_default_args(e, body_is_trivial=False)
+        inferred_type, type_override = self.infer_lambda_type_using_context(e)
+        if not inferred_type:
+            self.chk.return_types.append(AnyType(TypeOfAny.special_form))
+            # Type check everything in the body except for the final return
+            # statement (it can contain tuple unpacking before return).
+            with self.chk.scope.push_function(e):
+                # Lambdas can have more than one element in body,
+                # when we add "fictional" AssigmentStatement nodes, like in:
+                # `lambda (a, b): a`
+                for stmt in e.body.body[:-1]:
+                    stmt.accept(self.chk)
+                # Only type check the return expression, not the return statement.
+                # This is important as otherwise the following statements would be
+                # considered unreachable. There's no useful type context.
+                ret_type = self.accept(e.expr(), allow_none_return=True)
+            fallback = self.named_type("builtins.function")
+            self.chk.return_types.pop()
+            return callable_type(e, fallback, ret_type)
+        else:
+            # Type context available.
+            self.chk.return_types.append(inferred_type.ret_type)
+            self.chk.check_func_item(e, type_override=type_override)
+            if not self.chk.has_type(e.expr()):
+                # TODO: return expression must be accepted before exiting function scope.
+                self.accept(e.expr(), allow_none_return=True)
+            ret_type = self.chk.lookup_type(e.expr())
+            self.chk.return_types.pop()
+            return replace_callable_return_type(inferred_type, ret_type)
+
+    def infer_lambda_type_using_context(
+        self, e: LambdaExpr
+    ) -> tuple[CallableType | None, CallableType | None]:
+        """Try to infer lambda expression type using context.
+
+        Return None if could not infer type.
+        The second item in the return type is the type_override parameter for check_func_item.
+        """
+        # TODO also accept 'Any' context
+        ctx = get_proper_type(self.type_context[-1])
+
+        if isinstance(ctx, UnionType):
+            callables = [
+                t for t in get_proper_types(ctx.relevant_items()) if isinstance(t, CallableType)
+            ]
+            if len(callables) == 1:
+                ctx = callables[0]
+
+        if not ctx or not isinstance(ctx, CallableType):
+            return None, None
+
+        # The context may have function type variables in it. We replace them
+        # since these are the type variables we are ultimately trying to infer;
+        # they must be considered as indeterminate. We use ErasedType since it
+        # does not affect type inference results (it is for purposes like this
+        # only).
+        callable_ctx = get_proper_type(replace_meta_vars(ctx, ErasedType()))
+        assert isinstance(callable_ctx, CallableType)
+
+        # The callable_ctx may have a fallback of builtins.type if the context
+        # is a constructor -- but this fallback doesn't make sense for lambdas.
+        callable_ctx = callable_ctx.copy_modified(fallback=self.named_type("builtins.function"))
+
+        if callable_ctx.type_guard is not None:
+            # Lambda's return type cannot be treated as a `TypeGuard`,
+            # because it is implicit. And `TypeGuard`s must be explicit.
+            # See https://github.com/python/mypy/issues/9927
+            return None, None
+
+        arg_kinds = [arg.kind for arg in e.arguments]
+
+        if callable_ctx.is_ellipsis_args or ctx.param_spec() is not None:
+            # Fill in Any arguments to match the arguments of the lambda.
+            callable_ctx = callable_ctx.copy_modified(
+                is_ellipsis_args=False,
+                arg_types=[AnyType(TypeOfAny.special_form)] * len(arg_kinds),
+                arg_kinds=arg_kinds,
+                arg_names=e.arg_names.copy(),
+            )
+
+        if ARG_STAR in arg_kinds or ARG_STAR2 in arg_kinds:
+            # TODO treat this case appropriately
+            return callable_ctx, None
+
+        if callable_ctx.arg_kinds != arg_kinds:
+            # Incompatible context; cannot use it to infer types.
+            self.chk.fail(message_registry.CANNOT_INFER_LAMBDA_TYPE, e)
+            return None, None
+
+        return callable_ctx, callable_ctx
+
+    def visit_super_expr(self, e: SuperExpr) -> Type:
+        """Type check a super expression (non-lvalue)."""
+
+        # We have an expression like super(T, var).member
+
+        # First compute the types of T and var
+        types = self._super_arg_types(e)
+        if isinstance(types, tuple):
+            type_type, instance_type = types
+        else:
+            return types
+
+        # Now get the MRO
+        type_info = type_info_from_type(type_type)
+        if type_info is None:
+            self.chk.fail(message_registry.UNSUPPORTED_ARG_1_FOR_SUPER, e)
+            return AnyType(TypeOfAny.from_error)
+
+        instance_info = type_info_from_type(instance_type)
+        if instance_info is None:
+            self.chk.fail(message_registry.UNSUPPORTED_ARG_2_FOR_SUPER, e)
+            return AnyType(TypeOfAny.from_error)
+
+        mro = instance_info.mro
+
+        # The base is the first MRO entry *after* type_info that has a member
+        # with the right name
+        index = None
+        if type_info in mro:
+            index = mro.index(type_info)
+        else:
+            method = self.chk.scope.top_function()
+            # Mypy explicitly allows supertype upper bounds (and no upper bound at all)
+            # for annotating self-types. However, if such an annotation is used for
+            # checking super() we will still get an error. So to be consistent, we also
+            # allow such imprecise annotations for use with super(), where we fall back
+            # to the current class MRO instead. This works only from inside a method.
+            if method is not None and is_self_type_like(
+                instance_type, is_classmethod=method.is_class
+            ):
+                if e.info and type_info in e.info.mro:
+                    mro = e.info.mro
+                    index = mro.index(type_info)
+        if index is None:
+            if (
+                instance_info.is_protocol
+                and instance_info != type_info
+                and not type_info.is_protocol
+            ):
+                # A special case for mixins, in this case super() should point
+                # directly to the host protocol, this is not safe, since the real MRO
+                # is not known yet for mixin, but this feature is more like an escape hatch.
+                index = -1
+            else:
+                self.chk.fail(message_registry.SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1, e)
+                return AnyType(TypeOfAny.from_error)
+
+        if len(mro) == index + 1:
+            self.chk.fail(message_registry.TARGET_CLASS_HAS_NO_BASE_CLASS, e)
+            return AnyType(TypeOfAny.from_error)
+
+        for base in mro[index + 1 :]:
+            if e.name in base.names or base == mro[-1]:
+                if e.info and e.info.fallback_to_any and base == mro[-1]:
+                    # There's an undefined base class, and we're at the end of the
+                    # chain.  That's not an error.
+                    return AnyType(TypeOfAny.special_form)
+
+                return analyze_member_access(
+                    name=e.name,
+                    typ=instance_type,
+                    is_lvalue=False,
+                    is_super=True,
+                    is_operator=False,
+                    original_type=instance_type,
+                    override_info=base,
+                    context=e,
+                    msg=self.msg,
+                    chk=self.chk,
+                    in_literal_context=self.is_literal_context(),
+                )
+
+        assert False, "unreachable"
+
+    def _super_arg_types(self, e: SuperExpr) -> Type | tuple[Type, Type]:
+        """
+        Computes the types of the type and instance expressions in super(T, instance), or the
+        implicit ones for zero-argument super() expressions.  Returns a single type for the whole
+        super expression when possible (for errors, anys), otherwise the pair of computed types.
+        """
+
+        if not self.chk.in_checked_function():
+            return AnyType(TypeOfAny.unannotated)
+        elif len(e.call.args) == 0:
+            if not e.info:
+                # This has already been reported by the semantic analyzer.
+                return AnyType(TypeOfAny.from_error)
+            elif self.chk.scope.active_class():
+                self.chk.fail(message_registry.SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED, e)
+                return AnyType(TypeOfAny.from_error)
+
+            # Zero-argument super() is like super(<current class>, <self>)
+            current_type = fill_typevars(e.info)
+            type_type: ProperType = TypeType(current_type)
+
+            # Use the type of the self argument, in case it was annotated
+            method = self.chk.scope.top_function()
+            assert method is not None
+            if method.arguments:
+                instance_type: Type = method.arguments[0].variable.type or current_type
+            else:
+                self.chk.fail(message_registry.SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED, e)
+                return AnyType(TypeOfAny.from_error)
+        elif ARG_STAR in e.call.arg_kinds:
+            self.chk.fail(message_registry.SUPER_VARARGS_NOT_SUPPORTED, e)
+            return AnyType(TypeOfAny.from_error)
+        elif set(e.call.arg_kinds) != {ARG_POS}:
+            self.chk.fail(message_registry.SUPER_POSITIONAL_ARGS_REQUIRED, e)
+            return AnyType(TypeOfAny.from_error)
+        elif len(e.call.args) == 1:
+            self.chk.fail(message_registry.SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED, e)
+            return AnyType(TypeOfAny.from_error)
+        elif len(e.call.args) == 2:
+            type_type = get_proper_type(self.accept(e.call.args[0]))
+            instance_type = self.accept(e.call.args[1])
+        else:
+            self.chk.fail(message_registry.TOO_MANY_ARGS_FOR_SUPER, e)
+            return AnyType(TypeOfAny.from_error)
+
+        # Imprecisely assume that the type is the current class
+        if isinstance(type_type, AnyType):
+            if e.info:
+                type_type = TypeType(fill_typevars(e.info))
+            else:
+                return AnyType(TypeOfAny.from_another_any, source_any=type_type)
+        elif isinstance(type_type, TypeType):
+            type_item = type_type.item
+            if isinstance(type_item, AnyType):
+                if e.info:
+                    type_type = TypeType(fill_typevars(e.info))
+                else:
+                    return AnyType(TypeOfAny.from_another_any, source_any=type_item)
+
+        if not isinstance(type_type, TypeType) and not (
+            isinstance(type_type, FunctionLike) and type_type.is_type_obj()
+        ):
+            self.msg.first_argument_for_super_must_be_type(type_type, e)
+            return AnyType(TypeOfAny.from_error)
+
+        # Imprecisely assume that the instance is of the current class
+        instance_type = get_proper_type(instance_type)
+        if isinstance(instance_type, AnyType):
+            if e.info:
+                instance_type = fill_typevars(e.info)
+            else:
+                return AnyType(TypeOfAny.from_another_any, source_any=instance_type)
+        elif isinstance(instance_type, TypeType):
+            instance_item = instance_type.item
+            if isinstance(instance_item, AnyType):
+                if e.info:
+                    instance_type = TypeType(fill_typevars(e.info))
+                else:
+                    return AnyType(TypeOfAny.from_another_any, source_any=instance_item)
+
+        return type_type, instance_type
+
+    def visit_slice_expr(self, e: SliceExpr) -> Type:
+        try:
+            supports_index = self.chk.named_type("typing_extensions.SupportsIndex")
+        except KeyError:
+            supports_index = self.chk.named_type("builtins.int")  # thanks, fixture life
+        expected = make_optional_type(supports_index)
+        for index in [e.begin_index, e.end_index, e.stride]:
+            if index:
+                t = self.accept(index)
+                self.chk.check_subtype(t, expected, index, message_registry.INVALID_SLICE_INDEX)
+        return self.named_type("builtins.slice")
+
+    def visit_list_comprehension(self, e: ListComprehension) -> Type:
+        return self.check_generator_or_comprehension(
+            e.generator, "builtins.list", "<list-comprehension>"
+        )
+
+    def visit_set_comprehension(self, e: SetComprehension) -> Type:
+        return self.check_generator_or_comprehension(
+            e.generator, "builtins.set", "<set-comprehension>"
+        )
+
+    def visit_generator_expr(self, e: GeneratorExpr) -> Type:
+        # If any of the comprehensions use async for, the expression will return an async generator
+        # object, or if the left-side expression uses await.
+        if any(e.is_async) or has_await_expression(e.left_expr):
+            typ = "typing.AsyncGenerator"
+            # received type is always None in async generator expressions
+            additional_args: list[Type] = [NoneType()]
+        else:
+            typ = "typing.Generator"
+            # received type and returned type are None
+            additional_args = [NoneType(), NoneType()]
+        return self.check_generator_or_comprehension(
+            e, typ, "<generator>", additional_args=additional_args
+        )
+
+    def check_generator_or_comprehension(
+        self,
+        gen: GeneratorExpr,
+        type_name: str,
+        id_for_messages: str,
+        additional_args: list[Type] | None = None,
+    ) -> Type:
+        """Type check a generator expression or a list comprehension."""
+        additional_args = additional_args or []
+        with self.chk.binder.frame_context(can_skip=True, fall_through=0):
+            self.check_for_comp(gen)
+
+            # Infer the type of the list comprehension by using a synthetic generic
+            # callable type.
+            tv = TypeVarType(
+                "T",
+                "T",
+                id=-1,
+                values=[],
+                upper_bound=self.object_type(),
+                default=AnyType(TypeOfAny.from_omitted_generics),
+            )
+            tv_list: list[Type] = [tv]
+            constructor = CallableType(
+                tv_list,
+                [nodes.ARG_POS],
+                [None],
+                self.chk.named_generic_type(type_name, tv_list + additional_args),
+                self.chk.named_type("builtins.function"),
+                name=id_for_messages,
+                variables=[tv],
+            )
+            return self.check_call(constructor, [gen.left_expr], [nodes.ARG_POS], gen)[0]
+
+    def visit_dictionary_comprehension(self, e: DictionaryComprehension) -> Type:
+        """Type check a dictionary comprehension."""
+        with self.chk.binder.frame_context(can_skip=True, fall_through=0):
+            self.check_for_comp(e)
+
+            # Infer the type of the list comprehension by using a synthetic generic
+            # callable type.
+            ktdef = TypeVarType(
+                "KT",
+                "KT",
+                id=-1,
+                values=[],
+                upper_bound=self.object_type(),
+                default=AnyType(TypeOfAny.from_omitted_generics),
+            )
+            vtdef = TypeVarType(
+                "VT",
+                "VT",
+                id=-2,
+                values=[],
+                upper_bound=self.object_type(),
+                default=AnyType(TypeOfAny.from_omitted_generics),
+            )
+            constructor = CallableType(
+                [ktdef, vtdef],
+                [nodes.ARG_POS, nodes.ARG_POS],
+                [None, None],
+                self.chk.named_generic_type("builtins.dict", [ktdef, vtdef]),
+                self.chk.named_type("builtins.function"),
+                name="<dictionary-comprehension>",
+                variables=[ktdef, vtdef],
+            )
+            return self.check_call(
+                constructor, [e.key, e.value], [nodes.ARG_POS, nodes.ARG_POS], e
+            )[0]
+
+    def check_for_comp(self, e: GeneratorExpr | DictionaryComprehension) -> None:
+        """Check the for_comp part of comprehensions. That is the part from 'for':
+        ... for x in y if z
+
+        Note: This adds the type information derived from the condlists to the current binder.
+        """
+        for index, sequence, conditions, is_async in zip(
+            e.indices, e.sequences, e.condlists, e.is_async
+        ):
+            if is_async:
+                _, sequence_type = self.chk.analyze_async_iterable_item_type(sequence)
+            else:
+                _, sequence_type = self.chk.analyze_iterable_item_type(sequence)
+            self.chk.analyze_index_variables(index, sequence_type, True, e)
+            for condition in conditions:
+                self.accept(condition)
+
+                # values are only part of the comprehension when all conditions are true
+                true_map, false_map = self.chk.find_isinstance_check(condition)
+
+                if true_map:
+                    self.chk.push_type_map(true_map)
+
+                if codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes:
+                    if true_map is None:
+                        self.msg.redundant_condition_in_comprehension(False, condition)
+                    elif false_map is None:
+                        self.msg.redundant_condition_in_comprehension(True, condition)
+
+    def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = False) -> Type:
+        self.accept(e.cond)
+        ctx = self.type_context[-1]
+
+        # Gain type information from isinstance if it is there
+        # but only for the current expression
+        if_map, else_map = self.chk.find_isinstance_check(e.cond)
+        if codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes:
+            if if_map is None:
+                self.msg.redundant_condition_in_if(False, e.cond)
+            elif else_map is None:
+                self.msg.redundant_condition_in_if(True, e.cond)
+
+        if_type = self.analyze_cond_branch(
+            if_map, e.if_expr, context=ctx, allow_none_return=allow_none_return
+        )
+
+        # we want to keep the narrowest value of if_type for union'ing the branches
+        # however, it would be silly to pass a literal as a type context. Pass the
+        # underlying fallback type instead.
+        if_type_fallback = simple_literal_type(get_proper_type(if_type)) or if_type
+
+        # Analyze the right branch using full type context and store the type
+        full_context_else_type = self.analyze_cond_branch(
+            else_map, e.else_expr, context=ctx, allow_none_return=allow_none_return
+        )
+
+        if not mypy.checker.is_valid_inferred_type(if_type):
+            # Analyze the right branch disregarding the left branch.
+            else_type = full_context_else_type
+            # we want to keep the narrowest value of else_type for union'ing the branches
+            # however, it would be silly to pass a literal as a type context. Pass the
+            # underlying fallback type instead.
+            else_type_fallback = simple_literal_type(get_proper_type(else_type)) or else_type
+
+            # If it would make a difference, re-analyze the left
+            # branch using the right branch's type as context.
+            if ctx is None or not is_equivalent(else_type_fallback, ctx):
+                # TODO: If it's possible that the previous analysis of
+                # the left branch produced errors that are avoided
+                # using this context, suppress those errors.
+                if_type = self.analyze_cond_branch(
+                    if_map,
+                    e.if_expr,
+                    context=else_type_fallback,
+                    allow_none_return=allow_none_return,
+                )
+
+        elif if_type_fallback == ctx:
+            # There is no point re-running the analysis if if_type is equal to ctx.
+            # That would  be an exact duplicate of the work we just did.
+            # This optimization is particularly important to avoid exponential blowup with nested
+            # if/else expressions: https://github.com/python/mypy/issues/9591
+            # TODO: would checking for is_proper_subtype also work and cover more cases?
+            else_type = full_context_else_type
+        else:
+            # Analyze the right branch in the context of the left
+            # branch's type.
+            else_type = self.analyze_cond_branch(
+                else_map,
+                e.else_expr,
+                context=if_type_fallback,
+                allow_none_return=allow_none_return,
+            )
+
+        # Only create a union type if the type context is a union, to be mostly
+        # compatible with older mypy versions where we always did a join.
+        #
+        # TODO: Always create a union or at least in more cases?
+        if isinstance(get_proper_type(self.type_context[-1]), UnionType):
+            res: Type = make_simplified_union([if_type, full_context_else_type])
+        else:
+            res = join.join_types(if_type, else_type)
+
+        return res
+
+    def analyze_cond_branch(
+        self,
+        map: dict[Expression, Type] | None,
+        node: Expression,
+        context: Type | None,
+        allow_none_return: bool = False,
+    ) -> Type:
+        with self.chk.binder.frame_context(can_skip=True, fall_through=0):
+            if map is None:
+                # We still need to type check node, in case we want to
+                # process it for isinstance checks later
+                self.accept(node, type_context=context, allow_none_return=allow_none_return)
+                return UninhabitedType()
+            self.chk.push_type_map(map)
+            return self.accept(node, type_context=context, allow_none_return=allow_none_return)
+
+    #
+    # Helpers
+    #
+
+    def accept(
+        self,
+        node: Expression,
+        type_context: Type | None = None,
+        allow_none_return: bool = False,
+        always_allow_any: bool = False,
+        is_callee: bool = False,
+    ) -> Type:
+        """Type check a node in the given type context.  If allow_none_return
+        is True and this expression is a call, allow it to return None.  This
+        applies only to this expression and not any subexpressions.
+        """
+        if node in self.type_overrides:
+            # This branch is very fast, there is no point timing it.
+            return self.type_overrides[node]
+        # We don't use context manager here to get most precise data (and avoid overhead).
+        record_time = False
+        if self.collect_line_checking_stats and not self.in_expression:
+            t0 = time.perf_counter_ns()
+            self.in_expression = True
+            record_time = True
+        self.type_context.append(type_context)
+        old_is_callee = self.is_callee
+        self.is_callee = is_callee
+        try:
+            if allow_none_return and isinstance(node, CallExpr):
+                typ = self.visit_call_expr(node, allow_none_return=True)
+            elif allow_none_return and isinstance(node, YieldFromExpr):
+                typ = self.visit_yield_from_expr(node, allow_none_return=True)
+            elif allow_none_return and isinstance(node, ConditionalExpr):
+                typ = self.visit_conditional_expr(node, allow_none_return=True)
+            elif allow_none_return and isinstance(node, AwaitExpr):
+                typ = self.visit_await_expr(node, allow_none_return=True)
+            else:
+                typ = node.accept(self)
+        except Exception as err:
+            report_internal_error(
+                err, self.chk.errors.file, node.line, self.chk.errors, self.chk.options
+            )
+        self.is_callee = old_is_callee
+        self.type_context.pop()
+        assert typ is not None
+        self.chk.store_type(node, typ)
+
+        if (
+            self.chk.options.disallow_any_expr
+            and not always_allow_any
+            and not self.chk.is_stub
+            and self.chk.in_checked_function()
+            and has_any_type(typ)
+            and not self.chk.current_node_deferred
+        ):
+            self.msg.disallowed_any_type(typ, node)
+
+        if not self.chk.in_checked_function() or self.chk.current_node_deferred:
+            result: Type = AnyType(TypeOfAny.unannotated)
+        else:
+            result = typ
+        if record_time:
+            self.per_line_checking_time_ns[node.line] += time.perf_counter_ns() - t0
+            self.in_expression = False
+        return result
+
+    def named_type(self, name: str) -> Instance:
+        """Return an instance type with type given by the name and no type
+        arguments. Alias for TypeChecker.named_type.
+        """
+        return self.chk.named_type(name)
+
+    def is_valid_var_arg(self, typ: Type) -> bool:
+        """Is a type valid as a *args argument?"""
+        typ = get_proper_type(typ)
+        return isinstance(typ, (TupleType, AnyType, ParamSpecType, UnpackType)) or is_subtype(
+            typ, self.chk.named_generic_type("typing.Iterable", [AnyType(TypeOfAny.special_form)])
+        )
+
+    def is_valid_keyword_var_arg(self, typ: Type) -> bool:
+        """Is a type valid as a **kwargs argument?"""
+        return (
+            is_subtype(
+                typ,
+                self.chk.named_generic_type(
+                    "_typeshed.SupportsKeysAndGetItem",
+                    [self.named_type("builtins.str"), AnyType(TypeOfAny.special_form)],
+                ),
+            )
+            or is_subtype(
+                typ,
+                self.chk.named_generic_type(
+                    "_typeshed.SupportsKeysAndGetItem", [UninhabitedType(), UninhabitedType()]
+                ),
+            )
+            or isinstance(typ, ParamSpecType)
+        )
+
+    def has_member(self, typ: Type, member: str) -> bool:
+        """Does type have member with the given name?"""
+        # TODO: refactor this to use checkmember.analyze_member_access, otherwise
+        # these two should be carefully kept in sync.
+        # This is much faster than analyze_member_access, though, and so using
+        # it first as a filter is important for performance.
+        typ = get_proper_type(typ)
+
+        if isinstance(typ, TypeVarType):
+            typ = get_proper_type(typ.upper_bound)
+        if isinstance(typ, TupleType):
+            typ = tuple_fallback(typ)
+        if isinstance(typ, LiteralType):
+            typ = typ.fallback
+        if isinstance(typ, Instance):
+            return typ.type.has_readable_member(member)
+        if isinstance(typ, FunctionLike) and typ.is_type_obj():
+            return typ.fallback.type.has_readable_member(member)
+        elif isinstance(typ, AnyType):
+            return True
+        elif isinstance(typ, UnionType):
+            result = all(self.has_member(x, member) for x in typ.relevant_items())
+            return result
+        elif isinstance(typ, TypeType):
+            # Type[Union[X, ...]] is always normalized to Union[Type[X], ...],
+            # so we don't need to care about unions here.
+            item = typ.item
+            if isinstance(item, TypeVarType):
+                item = get_proper_type(item.upper_bound)
+            if isinstance(item, TupleType):
+                item = tuple_fallback(item)
+            if isinstance(item, Instance) and item.type.metaclass_type is not None:
+                return self.has_member(item.type.metaclass_type, member)
+            if isinstance(item, AnyType):
+                return True
+            return False
+        else:
+            return False
+
+    def not_ready_callback(self, name: str, context: Context) -> None:
+        """Called when we can't infer the type of a variable because it's not ready yet.
+
+        Either defer type checking of the enclosing function to the next
+        pass or report an error.
+        """
+        self.chk.handle_cannot_determine_type(name, context)
+
+    def visit_yield_expr(self, e: YieldExpr) -> Type:
+        return_type = self.chk.return_types[-1]
+        expected_item_type = self.chk.get_generator_yield_type(return_type, False)
+        if e.expr is None:
+            if (
+                not isinstance(get_proper_type(expected_item_type), (NoneType, AnyType))
+                and self.chk.in_checked_function()
+            ):
+                self.chk.fail(message_registry.YIELD_VALUE_EXPECTED, e)
+        else:
+            actual_item_type = self.accept(e.expr, expected_item_type)
+            self.chk.check_subtype(
+                actual_item_type,
+                expected_item_type,
+                e,
+                message_registry.INCOMPATIBLE_TYPES_IN_YIELD,
+                "actual type",
+                "expected type",
+            )
+        return self.chk.get_generator_receive_type(return_type, False)
+
+    def visit_await_expr(self, e: AwaitExpr, allow_none_return: bool = False) -> Type:
+        expected_type = self.type_context[-1]
+        if expected_type is not None:
+            expected_type = self.chk.named_generic_type("typing.Awaitable", [expected_type])
+        actual_type = get_proper_type(self.accept(e.expr, expected_type))
+        if isinstance(actual_type, AnyType):
+            return AnyType(TypeOfAny.from_another_any, source_any=actual_type)
+        ret = self.check_awaitable_expr(
+            actual_type, e, message_registry.INCOMPATIBLE_TYPES_IN_AWAIT
+        )
+        if not allow_none_return and isinstance(get_proper_type(ret), NoneType):
+            self.chk.msg.does_not_return_value(None, e)
+        return ret
+
+    def check_awaitable_expr(
+        self, t: Type, ctx: Context, msg: str | ErrorMessage, ignore_binder: bool = False
+    ) -> Type:
+        """Check the argument to `await` and extract the type of value.
+
+        Also used by `async for` and `async with`.
+        """
+        if not self.chk.check_subtype(
+            t, self.named_type("typing.Awaitable"), ctx, msg, "actual type", "expected type"
+        ):
+            return AnyType(TypeOfAny.special_form)
+        else:
+            generator = self.check_method_call_by_name("__await__", t, [], [], ctx)[0]
+            ret_type = self.chk.get_generator_return_type(generator, False)
+            ret_type = get_proper_type(ret_type)
+            if (
+                not ignore_binder
+                and isinstance(ret_type, UninhabitedType)
+                and not ret_type.ambiguous
+            ):
+                self.chk.binder.unreachable()
+            return ret_type
+
+    def visit_yield_from_expr(self, e: YieldFromExpr, allow_none_return: bool = False) -> Type:
+        # NOTE: Whether `yield from` accepts an `async def` decorated
+        # with `@types.coroutine` (or `@asyncio.coroutine`) depends on
+        # whether the generator containing the `yield from` is itself
+        # thus decorated.  But it accepts a generator regardless of
+        # how it's decorated.
+        return_type = self.chk.return_types[-1]
+        # TODO: What should the context for the sub-expression be?
+        # If the containing function has type Generator[X, Y, ...],
+        # the context should be Generator[X, Y, T], where T is the
+        # context of the 'yield from' itself (but it isn't known).
+        subexpr_type = get_proper_type(self.accept(e.expr))
+
+        # Check that the expr is an instance of Iterable and get the type of the iterator produced
+        # by __iter__.
+        if isinstance(subexpr_type, AnyType):
+            iter_type: Type = AnyType(TypeOfAny.from_another_any, source_any=subexpr_type)
+        elif self.chk.type_is_iterable(subexpr_type):
+            if is_async_def(subexpr_type) and not has_coroutine_decorator(return_type):
+                self.chk.msg.yield_from_invalid_operand_type(subexpr_type, e)
+
+            any_type = AnyType(TypeOfAny.special_form)
+            generic_generator_type = self.chk.named_generic_type(
+                "typing.Generator", [any_type, any_type, any_type]
+            )
+            iter_type, _ = self.check_method_call_by_name(
+                "__iter__", subexpr_type, [], [], context=generic_generator_type
+            )
+        else:
+            if not (is_async_def(subexpr_type) and has_coroutine_decorator(return_type)):
+                self.chk.msg.yield_from_invalid_operand_type(subexpr_type, e)
+                iter_type = AnyType(TypeOfAny.from_error)
+            else:
+                iter_type = self.check_awaitable_expr(
+                    subexpr_type, e, message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM
+                )
+
+        # Check that the iterator's item type matches the type yielded by the Generator function
+        # containing this `yield from` expression.
+        expected_item_type = self.chk.get_generator_yield_type(return_type, False)
+        actual_item_type = self.chk.get_generator_yield_type(iter_type, False)
+
+        self.chk.check_subtype(
+            actual_item_type,
+            expected_item_type,
+            e,
+            message_registry.INCOMPATIBLE_TYPES_IN_YIELD_FROM,
+            "actual type",
+            "expected type",
+        )
+
+        # Determine the type of the entire yield from expression.
+        iter_type = get_proper_type(iter_type)
+        if isinstance(iter_type, Instance) and iter_type.type.fullname == "typing.Generator":
+            expr_type = self.chk.get_generator_return_type(iter_type, False)
+        else:
+            # Non-Generators don't return anything from `yield from` expressions.
+            # However special-case Any (which might be produced by an error).
+            actual_item_type = get_proper_type(actual_item_type)
+            if isinstance(actual_item_type, AnyType):
+                expr_type = AnyType(TypeOfAny.from_another_any, source_any=actual_item_type)
+            else:
+                # Treat `Iterator[X]` as a shorthand for `Generator[X, None, Any]`.
+                expr_type = NoneType()
+
+        if not allow_none_return and isinstance(get_proper_type(expr_type), NoneType):
+            self.chk.msg.does_not_return_value(None, e)
+        return expr_type
+
+    def visit_temp_node(self, e: TempNode) -> Type:
+        return e.type
+
+    def visit_type_var_expr(self, e: TypeVarExpr) -> Type:
+        p_default = get_proper_type(e.default)
+        if not (
+            isinstance(p_default, AnyType)
+            and p_default.type_of_any == TypeOfAny.from_omitted_generics
+        ):
+            if not is_subtype(p_default, e.upper_bound):
+                self.chk.fail("TypeVar default must be a subtype of the bound type", e)
+            if e.values and not any(p_default == value for value in e.values):
+                self.chk.fail("TypeVar default must be one of the constraint types", e)
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_paramspec_expr(self, e: ParamSpecExpr) -> Type:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_type_var_tuple_expr(self, e: TypeVarTupleExpr) -> Type:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_newtype_expr(self, e: NewTypeExpr) -> Type:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_namedtuple_expr(self, e: NamedTupleExpr) -> Type:
+        tuple_type = e.info.tuple_type
+        if tuple_type:
+            if self.chk.options.disallow_any_unimported and has_any_from_unimported_type(
+                tuple_type
+            ):
+                self.msg.unimported_type_becomes_any("NamedTuple type", tuple_type, e)
+            check_for_explicit_any(
+                tuple_type, self.chk.options, self.chk.is_typeshed_stub, self.msg, context=e
+            )
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_enum_call_expr(self, e: EnumCallExpr) -> Type:
+        for name, value in zip(e.items, e.values):
+            if value is not None:
+                typ = self.accept(value)
+                if not isinstance(get_proper_type(typ), AnyType):
+                    var = e.info.names[name].node
+                    if isinstance(var, Var):
+                        # Inline TypeChecker.set_inferred_type(),
+                        # without the lvalue.  (This doesn't really do
+                        # much, since the value attribute is defined
+                        # to have type Any in the typeshed stub.)
+                        var.type = typ
+                        var.is_inferred = True
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_typeddict_expr(self, e: TypedDictExpr) -> Type:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit__promote_expr(self, e: PromoteExpr) -> Type:
+        return e.type
+
+    def visit_star_expr(self, e: StarExpr) -> Type:
+        # TODO: should this ever be called (see e.g. mypyc visitor)?
+        return self.accept(e.expr)
+
+    def object_type(self) -> Instance:
+        """Return instance type 'object'."""
+        return self.named_type("builtins.object")
+
+    def bool_type(self) -> Instance:
+        """Return instance type 'bool'."""
+        return self.named_type("builtins.bool")
+
+    @overload
+    def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type:
+        ...
+
+    @overload
+    def narrow_type_from_binder(
+        self, expr: Expression, known_type: Type, skip_non_overlapping: bool
+    ) -> Type | None:
+        ...
+
+    def narrow_type_from_binder(
+        self, expr: Expression, known_type: Type, skip_non_overlapping: bool = False
+    ) -> Type | None:
+        """Narrow down a known type of expression using information in conditional type binder.
+
+        If 'skip_non_overlapping' is True, return None if the type and restriction are
+        non-overlapping.
+        """
+        if literal(expr) >= LITERAL_TYPE:
+            restriction = self.chk.binder.get(expr)
+            # If the current node is deferred, some variables may get Any types that they
+            # otherwise wouldn't have. We don't want to narrow down these since it may
+            # produce invalid inferred Optional[Any] types, at least.
+            if restriction and not (
+                isinstance(get_proper_type(known_type), AnyType) and self.chk.current_node_deferred
+            ):
+                # Note: this call should match the one in narrow_declared_type().
+                if skip_non_overlapping and not is_overlapping_types(
+                    known_type, restriction, prohibit_none_typevar_overlap=True
+                ):
+                    return None
+                return narrow_declared_type(known_type, restriction)
+        return known_type
+
+    def has_abstract_type_part(self, caller_type: ProperType, callee_type: ProperType) -> bool:
+        # TODO: support other possible types here
+        if isinstance(caller_type, TupleType) and isinstance(callee_type, TupleType):
+            return any(
+                self.has_abstract_type(get_proper_type(caller), get_proper_type(callee))
+                for caller, callee in zip(caller_type.items, callee_type.items)
+            )
+        return self.has_abstract_type(caller_type, callee_type)
+
+    def has_abstract_type(self, caller_type: ProperType, callee_type: ProperType) -> bool:
+        return (
+            isinstance(caller_type, CallableType)
+            and isinstance(callee_type, TypeType)
+            and caller_type.is_type_obj()
+            and (caller_type.type_object().is_abstract or caller_type.type_object().is_protocol)
+            and isinstance(callee_type.item, Instance)
+            and (callee_type.item.type.is_abstract or callee_type.item.type.is_protocol)
+            and not self.chk.allow_abstract_call
+        )
+
+
+def has_any_type(t: Type, ignore_in_type_obj: bool = False) -> bool:
+    """Whether t contains an Any type"""
+    return t.accept(HasAnyType(ignore_in_type_obj))
+
+
+class HasAnyType(types.BoolTypeQuery):
+    def __init__(self, ignore_in_type_obj: bool) -> None:
+        super().__init__(types.ANY_STRATEGY)
+        self.ignore_in_type_obj = ignore_in_type_obj
+
+    def visit_any(self, t: AnyType) -> bool:
+        return t.type_of_any != TypeOfAny.special_form  # special forms are not real Any types
+
+    def visit_callable_type(self, t: CallableType) -> bool:
+        if self.ignore_in_type_obj and t.is_type_obj():
+            return False
+        return super().visit_callable_type(t)
+
+    def visit_type_var(self, t: TypeVarType) -> bool:
+        default = [t.default] if t.has_default() else []
+        return self.query_types([t.upper_bound, *default] + t.values)
+
+    def visit_param_spec(self, t: ParamSpecType) -> bool:
+        default = [t.default] if t.has_default() else []
+        return self.query_types([t.upper_bound, *default])
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> bool:
+        default = [t.default] if t.has_default() else []
+        return self.query_types([t.upper_bound, *default])
+
+
+def has_coroutine_decorator(t: Type) -> bool:
+    """Whether t came from a function decorated with `@coroutine`."""
+    t = get_proper_type(t)
+    return isinstance(t, Instance) and t.type.fullname == "typing.AwaitableGenerator"
+
+
+def is_async_def(t: Type) -> bool:
+    """Whether t came from a function defined using `async def`."""
+    # In check_func_def(), when we see a function decorated with
+    # `@typing.coroutine` or `@async.coroutine`, we change the
+    # return type to typing.AwaitableGenerator[...], so that its
+    # type is compatible with either Generator or Awaitable.
+    # But for the check here we need to know whether the original
+    # function (before decoration) was an `async def`.  The
+    # AwaitableGenerator type conveniently preserves the original
+    # type as its 4th parameter (3rd when using 0-origin indexing
+    # :-), so that we can recover that information here.
+    # (We really need to see whether the original, undecorated
+    # function was an `async def`, which is orthogonal to its
+    # decorations.)
+    t = get_proper_type(t)
+    if (
+        isinstance(t, Instance)
+        and t.type.fullname == "typing.AwaitableGenerator"
+        and len(t.args) >= 4
+    ):
+        t = get_proper_type(t.args[3])
+    return isinstance(t, Instance) and t.type.fullname == "typing.Coroutine"
+
+
+def is_non_empty_tuple(t: Type) -> bool:
+    t = get_proper_type(t)
+    return isinstance(t, TupleType) and bool(t.items)
+
+
+def is_duplicate_mapping(
+    mapping: list[int], actual_types: list[Type], actual_kinds: list[ArgKind]
+) -> bool:
+    return (
+        len(mapping) > 1
+        # Multiple actuals can map to the same formal if they both come from
+        # varargs (*args and **kwargs); in this case at runtime it is possible
+        # that here are no duplicates. We need to allow this, as the convention
+        # f(..., *args, **kwargs) is common enough.
+        and not (
+            len(mapping) == 2
+            and actual_kinds[mapping[0]] == nodes.ARG_STAR
+            and actual_kinds[mapping[1]] == nodes.ARG_STAR2
+        )
+        # Multiple actuals can map to the same formal if there are multiple
+        # **kwargs which cannot be mapped with certainty (non-TypedDict
+        # **kwargs).
+        and not all(
+            actual_kinds[m] == nodes.ARG_STAR2
+            and not isinstance(get_proper_type(actual_types[m]), TypedDictType)
+            for m in mapping
+        )
+    )
+
+
+def replace_callable_return_type(c: CallableType, new_ret_type: Type) -> CallableType:
+    """Return a copy of a callable type with a different return type."""
+    return c.copy_modified(ret_type=new_ret_type)
+
+
+def apply_poly(tp: CallableType, poly_tvars: Sequence[TypeVarLikeType]) -> CallableType | None:
+    """Make free type variables generic in the type if possible.
+
+    This will translate the type `tp` while trying to create valid bindings for
+    type variables `poly_tvars` while traversing the type. This follows the same rules
+    as we do during semantic analysis phase, examples:
+      * Callable[Callable[[T], T], T] -> def [T] (def (T) -> T) -> T
+      * Callable[[], Callable[[T], T]] -> def () -> def [T] (T -> T)
+      * List[T] -> None (not possible)
+    """
+    try:
+        return tp.copy_modified(
+            arg_types=[t.accept(PolyTranslator(poly_tvars)) for t in tp.arg_types],
+            ret_type=tp.ret_type.accept(PolyTranslator(poly_tvars)),
+            variables=[],
+        )
+    except PolyTranslationError:
+        return None
+
+
+class PolyTranslationError(Exception):
+    pass
+
+
+class PolyTranslator(TypeTranslator):
+    """Make free type variables generic in the type if possible.
+
+    See docstring for apply_poly() for details.
+    """
+
+    def __init__(self, poly_tvars: Sequence[TypeVarLikeType]) -> None:
+        self.poly_tvars = set(poly_tvars)
+        # This is a simplified version of TypeVarScope used during semantic analysis.
+        self.bound_tvars: set[TypeVarLikeType] = set()
+        self.seen_aliases: set[TypeInfo] = set()
+
+    def visit_callable_type(self, t: CallableType) -> Type:
+        found_vars = set()
+        for arg in t.arg_types:
+            found_vars |= set(get_type_vars(arg)) & self.poly_tvars
+
+        found_vars -= self.bound_tvars
+        self.bound_tvars |= found_vars
+        result = super().visit_callable_type(t)
+        self.bound_tvars -= found_vars
+
+        assert isinstance(result, ProperType) and isinstance(result, CallableType)
+        result.variables = list(result.variables) + list(found_vars)
+        return result
+
+    def visit_type_var(self, t: TypeVarType) -> Type:
+        if t in self.poly_tvars and t not in self.bound_tvars:
+            raise PolyTranslationError()
+        return super().visit_type_var(t)
+
+    def visit_param_spec(self, t: ParamSpecType) -> Type:
+        # TODO: Support polymorphic apply for ParamSpec.
+        raise PolyTranslationError()
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
+        # TODO: Support polymorphic apply for TypeVarTuple.
+        raise PolyTranslationError()
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        if not t.args:
+            return t.copy_modified()
+        if not t.is_recursive:
+            return get_proper_type(t).accept(self)
+        # We can't handle polymorphic application for recursive generic aliases
+        # without risking an infinite recursion, just give up for now.
+        raise PolyTranslationError()
+
+    def visit_instance(self, t: Instance) -> Type:
+        # There is the same problem with callback protocols as with aliases
+        # (callback protocols are essentially more flexible aliases to callables).
+        # Note: consider supporting bindings in instances, e.g. LRUCache[[x: T], T].
+        if t.args and t.type.is_protocol and t.type.protocol_members == ["__call__"]:
+            if t.type in self.seen_aliases:
+                raise PolyTranslationError()
+            self.seen_aliases.add(t.type)
+            call = find_member("__call__", t, t, is_operator=True)
+            assert call is not None
+            return call.accept(self)
+        return super().visit_instance(t)
+
+
+class ArgInferSecondPassQuery(types.BoolTypeQuery):
+    """Query whether an argument type should be inferred in the second pass.
+
+    The result is True if the type has a type variable in a callable return
+    type anywhere. For example, the result for Callable[[], T] is True if t is
+    a type variable.
+    """
+
+    def __init__(self) -> None:
+        super().__init__(types.ANY_STRATEGY)
+
+    def visit_callable_type(self, t: CallableType) -> bool:
+        return self.query_types(t.arg_types) or t.accept(HasTypeVarQuery())
+
+
+class HasTypeVarQuery(types.BoolTypeQuery):
+    """Visitor for querying whether a type has a type variable component."""
+
+    def __init__(self) -> None:
+        super().__init__(types.ANY_STRATEGY)
+
+    def visit_type_var(self, t: TypeVarType) -> bool:
+        return True
+
+
+def has_erased_component(t: Type | None) -> bool:
+    return t is not None and t.accept(HasErasedComponentsQuery())
+
+
+class HasErasedComponentsQuery(types.BoolTypeQuery):
+    """Visitor for querying whether a type has an erased component."""
+
+    def __init__(self) -> None:
+        super().__init__(types.ANY_STRATEGY)
+
+    def visit_erased_type(self, t: ErasedType) -> bool:
+        return True
+
+
+def has_uninhabited_component(t: Type | None) -> bool:
+    return t is not None and t.accept(HasUninhabitedComponentsQuery())
+
+
+class HasUninhabitedComponentsQuery(types.BoolTypeQuery):
+    """Visitor for querying whether a type has an UninhabitedType component."""
+
+    def __init__(self) -> None:
+        super().__init__(types.ANY_STRATEGY)
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
+        return True
+
+
+def arg_approximate_similarity(actual: Type, formal: Type) -> bool:
+    """Return if caller argument (actual) is roughly compatible with signature arg (formal).
+
+    This function is deliberately loose and will report two types are similar
+    as long as their "shapes" are plausibly the same.
+
+    This is useful when we're doing error reporting: for example, if we're trying
+    to select an overload alternative and there's no exact match, we can use
+    this function to help us identify which alternative the user might have
+    *meant* to match.
+    """
+    actual = get_proper_type(actual)
+    formal = get_proper_type(formal)
+
+    # Erase typevars: we'll consider them all to have the same "shape".
+    if isinstance(actual, TypeVarType):
+        actual = erase_to_union_or_bound(actual)
+    if isinstance(formal, TypeVarType):
+        formal = erase_to_union_or_bound(formal)
+
+    # Callable or Type[...]-ish types
+    def is_typetype_like(typ: ProperType) -> bool:
+        return (
+            isinstance(typ, TypeType)
+            or (isinstance(typ, FunctionLike) and typ.is_type_obj())
+            or (isinstance(typ, Instance) and typ.type.fullname == "builtins.type")
+        )
+
+    if isinstance(formal, CallableType):
+        if isinstance(actual, (CallableType, Overloaded, TypeType)):
+            return True
+    if is_typetype_like(actual) and is_typetype_like(formal):
+        return True
+
+    # Unions
+    if isinstance(actual, UnionType):
+        return any(arg_approximate_similarity(item, formal) for item in actual.relevant_items())
+    if isinstance(formal, UnionType):
+        return any(arg_approximate_similarity(actual, item) for item in formal.relevant_items())
+
+    # TypedDicts
+    if isinstance(actual, TypedDictType):
+        if isinstance(formal, TypedDictType):
+            return True
+        return arg_approximate_similarity(actual.fallback, formal)
+
+    # Instances
+    # For instances, we mostly defer to the existing is_subtype check.
+    if isinstance(formal, Instance):
+        if isinstance(actual, CallableType):
+            actual = actual.fallback
+        if isinstance(actual, Overloaded):
+            actual = actual.items[0].fallback
+        if isinstance(actual, TupleType):
+            actual = tuple_fallback(actual)
+        if isinstance(actual, Instance) and formal.type in actual.type.mro:
+            # Try performing a quick check as an optimization
+            return True
+
+    # Fall back to a standard subtype check for the remaining kinds of type.
+    return is_subtype(erasetype.erase_type(actual), erasetype.erase_type(formal))
+
+
+def any_causes_overload_ambiguity(
+    items: list[CallableType],
+    return_types: list[Type],
+    arg_types: list[Type],
+    arg_kinds: list[ArgKind],
+    arg_names: Sequence[str | None] | None,
+) -> bool:
+    """May an argument containing 'Any' cause ambiguous result type on call to overloaded function?
+
+    Note that this sometimes returns True even if there is no ambiguity, since a correct
+    implementation would be complex (and the call would be imprecisely typed due to Any
+    types anyway).
+
+    Args:
+        items: Overload items matching the actual arguments
+        arg_types: Actual argument types
+        arg_kinds: Actual argument kinds
+        arg_names: Actual argument names
+    """
+    if all_same_types(return_types):
+        return False
+
+    actual_to_formal = [
+        map_formals_to_actuals(
+            arg_kinds, arg_names, item.arg_kinds, item.arg_names, lambda i: arg_types[i]
+        )
+        for item in items
+    ]
+
+    for arg_idx, arg_type in enumerate(arg_types):
+        # We ignore Anys in type object callables as ambiguity
+        # creators, since that can lead to falsely claiming ambiguity
+        # for overloads between Type and Callable.
+        if has_any_type(arg_type, ignore_in_type_obj=True):
+            matching_formals_unfiltered = [
+                (item_idx, lookup[arg_idx])
+                for item_idx, lookup in enumerate(actual_to_formal)
+                if lookup[arg_idx]
+            ]
+
+            matching_returns = []
+            matching_formals = []
+            for item_idx, formals in matching_formals_unfiltered:
+                matched_callable = items[item_idx]
+                matching_returns.append(matched_callable.ret_type)
+
+                # Note: if an actual maps to multiple formals of differing types within
+                # a single callable, then we know at least one of those formals must be
+                # a different type then the formal(s) in some other callable.
+                # So it's safe to just append everything to the same list.
+                for formal in formals:
+                    matching_formals.append(matched_callable.arg_types[formal])
+            if not all_same_types(matching_formals) and not all_same_types(matching_returns):
+                # Any maps to multiple different types, and the return types of these items differ.
+                return True
+    return False
+
+
+def all_same_types(types: list[Type]) -> bool:
+    if not types:
+        return True
+    return all(is_same_type(t, types[0]) for t in types[1:])
+
+
+def merge_typevars_in_callables_by_name(
+    callables: Sequence[CallableType],
+) -> tuple[list[CallableType], list[TypeVarType]]:
+    """Takes all the typevars present in the callables and 'combines' the ones with the same name.
+
+    For example, suppose we have two callables with signatures "f(x: T, y: S) -> T" and
+    "f(x: List[Tuple[T, S]]) -> Tuple[T, S]". Both callables use typevars named "T" and
+    "S", but we treat them as distinct, unrelated typevars. (E.g. they could both have
+    distinct ids.)
+
+    If we pass in both callables into this function, it returns a list containing two
+    new callables that are identical in signature, but use the same underlying TypeVarType
+    for T and S.
+
+    This is useful if we want to take the output lists and "merge" them into one callable
+    in some way -- for example, when unioning together overloads.
+
+    Returns both the new list of callables and a list of all distinct TypeVarType objects used.
+    """
+    output: list[CallableType] = []
+    unique_typevars: dict[str, TypeVarType] = {}
+    variables: list[TypeVarType] = []
+
+    for target in callables:
+        if target.is_generic():
+            target = freshen_function_type_vars(target)
+
+            rename = {}  # Dict[TypeVarId, TypeVar]
+            for tv in target.variables:
+                name = tv.fullname
+                if name not in unique_typevars:
+                    # TODO(PEP612): fix for ParamSpecType
+                    if isinstance(tv, ParamSpecType):
+                        continue
+                    assert isinstance(tv, TypeVarType)
+                    unique_typevars[name] = tv
+                    variables.append(tv)
+                rename[tv.id] = unique_typevars[name]
+
+            target = expand_type(target, rename)
+        output.append(target)
+
+    return output, variables
+
+
+def try_getting_literal(typ: Type) -> ProperType:
+    """If possible, get a more precise literal type for a given type."""
+    typ = get_proper_type(typ)
+    if isinstance(typ, Instance) and typ.last_known_value is not None:
+        return typ.last_known_value
+    return typ
+
+
+def is_expr_literal_type(node: Expression) -> bool:
+    """Returns 'true' if the given node is a Literal"""
+    if isinstance(node, IndexExpr):
+        base = node.base
+        return isinstance(base, RefExpr) and base.fullname in LITERAL_TYPE_NAMES
+    if isinstance(node, NameExpr):
+        underlying = node.node
+        return isinstance(underlying, TypeAlias) and isinstance(
+            get_proper_type(underlying.target), LiteralType
+        )
+    return False
+
+
+def has_bytes_component(typ: Type) -> bool:
+    """Is this one of builtin byte types, or a union that contains it?"""
+    typ = get_proper_type(typ)
+    byte_types = {"builtins.bytes", "builtins.bytearray"}
+    if isinstance(typ, UnionType):
+        return any(has_bytes_component(t) for t in typ.items)
+    if isinstance(typ, Instance) and typ.type.fullname in byte_types:
+        return True
+    return False
+
+
+def type_info_from_type(typ: Type) -> TypeInfo | None:
+    """Gets the TypeInfo for a type, indirecting through things like type variables and tuples."""
+    typ = get_proper_type(typ)
+    if isinstance(typ, FunctionLike) and typ.is_type_obj():
+        return typ.type_object()
+    if isinstance(typ, TypeType):
+        typ = typ.item
+    if isinstance(typ, TypeVarType):
+        typ = get_proper_type(typ.upper_bound)
+    if isinstance(typ, TupleType):
+        typ = tuple_fallback(typ)
+    if isinstance(typ, Instance):
+        return typ.type
+
+    # A complicated type. Too tricky, give up.
+    # TODO: Do something more clever here.
+    return None
+
+
+def is_operator_method(fullname: str | None) -> bool:
+    if not fullname:
+        return False
+    short_name = fullname.split(".")[-1]
+    return (
+        short_name in operators.op_methods.values()
+        or short_name in operators.reverse_op_methods.values()
+        or short_name in operators.unary_op_methods.values()
+    )
+
+
+def get_partial_instance_type(t: Type | None) -> PartialType | None:
+    if t is None or not isinstance(t, PartialType) or t.type is None:
+        return None
+    return t

二進制
venv/lib/python3.11/site-packages/mypy/checkmember.cpython-311-x86_64-linux-gnu.so


+ 1316 - 0
venv/lib/python3.11/site-packages/mypy/checkmember.py

@@ -0,0 +1,1316 @@
+"""Type checking of attribute access"""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Callable, Sequence, cast
+
+from mypy import meet, message_registry, subtypes
+from mypy.erasetype import erase_typevars
+from mypy.expandtype import (
+    expand_self_type,
+    expand_type_by_instance,
+    freshen_all_functions_type_vars,
+)
+from mypy.maptype import map_instance_to_supertype
+from mypy.messages import MessageBuilder
+from mypy.nodes import (
+    ARG_POS,
+    ARG_STAR,
+    ARG_STAR2,
+    SYMBOL_FUNCBASE_TYPES,
+    Context,
+    Decorator,
+    FuncBase,
+    FuncDef,
+    IndexExpr,
+    MypyFile,
+    OverloadedFuncDef,
+    SymbolNode,
+    SymbolTable,
+    TempNode,
+    TypeAlias,
+    TypeInfo,
+    TypeVarExpr,
+    Var,
+    is_final_node,
+)
+from mypy.plugin import AttributeContext
+from mypy.typeops import (
+    bind_self,
+    class_callable,
+    erase_to_bound,
+    function_type,
+    get_type_vars,
+    make_simplified_union,
+    supported_self_type,
+    tuple_fallback,
+    type_object_type_from_function,
+)
+from mypy.types import (
+    ENUM_REMOVED_PROPS,
+    AnyType,
+    CallableType,
+    DeletedType,
+    FunctionLike,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypedDictType,
+    TypeOfAny,
+    TypeType,
+    TypeVarLikeType,
+    TypeVarTupleType,
+    TypeVarType,
+    UnionType,
+    get_proper_type,
+)
+from mypy.typetraverser import TypeTraverserVisitor
+
+if TYPE_CHECKING:  # import for forward declaration only
+    import mypy.checker
+
+from mypy import state
+
+
+class MemberContext:
+    """Information and objects needed to type check attribute access.
+
+    Look at the docstring of analyze_member_access for more information.
+    """
+
+    def __init__(
+        self,
+        is_lvalue: bool,
+        is_super: bool,
+        is_operator: bool,
+        original_type: Type,
+        context: Context,
+        msg: MessageBuilder,
+        chk: mypy.checker.TypeChecker,
+        self_type: Type | None,
+        module_symbol_table: SymbolTable | None = None,
+        no_deferral: bool = False,
+        is_self: bool = False,
+    ) -> None:
+        self.is_lvalue = is_lvalue
+        self.is_super = is_super
+        self.is_operator = is_operator
+        self.original_type = original_type
+        self.self_type = self_type or original_type
+        self.context = context  # Error context
+        self.msg = msg
+        self.chk = chk
+        self.module_symbol_table = module_symbol_table
+        self.no_deferral = no_deferral
+        self.is_self = is_self
+
+    def named_type(self, name: str) -> Instance:
+        return self.chk.named_type(name)
+
+    def not_ready_callback(self, name: str, context: Context) -> None:
+        self.chk.handle_cannot_determine_type(name, context)
+
+    def copy_modified(
+        self,
+        *,
+        messages: MessageBuilder | None = None,
+        self_type: Type | None = None,
+        is_lvalue: bool | None = None,
+    ) -> MemberContext:
+        mx = MemberContext(
+            self.is_lvalue,
+            self.is_super,
+            self.is_operator,
+            self.original_type,
+            self.context,
+            self.msg,
+            self.chk,
+            self.self_type,
+            self.module_symbol_table,
+            self.no_deferral,
+        )
+        if messages is not None:
+            mx.msg = messages
+        if self_type is not None:
+            mx.self_type = self_type
+        if is_lvalue is not None:
+            mx.is_lvalue = is_lvalue
+        return mx
+
+
+def analyze_member_access(
+    name: str,
+    typ: Type,
+    context: Context,
+    is_lvalue: bool,
+    is_super: bool,
+    is_operator: bool,
+    msg: MessageBuilder,
+    *,
+    original_type: Type,
+    chk: mypy.checker.TypeChecker,
+    override_info: TypeInfo | None = None,
+    in_literal_context: bool = False,
+    self_type: Type | None = None,
+    module_symbol_table: SymbolTable | None = None,
+    no_deferral: bool = False,
+    is_self: bool = False,
+) -> Type:
+    """Return the type of attribute 'name' of 'typ'.
+
+    The actual implementation is in '_analyze_member_access' and this docstring
+    also applies to it.
+
+    This is a general operation that supports various different variations:
+
+      1. lvalue or non-lvalue access (setter or getter access)
+      2. supertype access when using super() (is_super == True and
+         'override_info' should refer to the supertype)
+
+    'original_type' is the most precise inferred or declared type of the base object
+    that we have available. When looking for an attribute of 'typ', we may perform
+    recursive calls targeting the fallback type, and 'typ' may become some supertype
+    of 'original_type'. 'original_type' is always preserved as the 'typ' type used in
+    the initial, non-recursive call. The 'self_type' is a component of 'original_type'
+    to which generic self should be bound (a narrower type that has a fallback to instance).
+    Currently this is used only for union types.
+
+    'module_symbol_table' is passed to this function if 'typ' is actually a module
+    and we want to keep track of the available attributes of the module (since they
+    are not available via the type object directly)
+    """
+    mx = MemberContext(
+        is_lvalue,
+        is_super,
+        is_operator,
+        original_type,
+        context,
+        msg,
+        chk=chk,
+        self_type=self_type,
+        module_symbol_table=module_symbol_table,
+        no_deferral=no_deferral,
+        is_self=is_self,
+    )
+    result = _analyze_member_access(name, typ, mx, override_info)
+    possible_literal = get_proper_type(result)
+    if (
+        in_literal_context
+        and isinstance(possible_literal, Instance)
+        and possible_literal.last_known_value is not None
+    ):
+        return possible_literal.last_known_value
+    else:
+        return result
+
+
+def _analyze_member_access(
+    name: str, typ: Type, mx: MemberContext, override_info: TypeInfo | None = None
+) -> Type:
+    # TODO: This and following functions share some logic with subtypes.find_member;
+    #       consider refactoring.
+    typ = get_proper_type(typ)
+    if isinstance(typ, Instance):
+        return analyze_instance_member_access(name, typ, mx, override_info)
+    elif isinstance(typ, AnyType):
+        # The base object has dynamic type.
+        return AnyType(TypeOfAny.from_another_any, source_any=typ)
+    elif isinstance(typ, UnionType):
+        return analyze_union_member_access(name, typ, mx)
+    elif isinstance(typ, FunctionLike) and typ.is_type_obj():
+        return analyze_type_callable_member_access(name, typ, mx)
+    elif isinstance(typ, TypeType):
+        return analyze_type_type_member_access(name, typ, mx, override_info)
+    elif isinstance(typ, TupleType):
+        # Actually look up from the fallback instance type.
+        return _analyze_member_access(name, tuple_fallback(typ), mx, override_info)
+    elif isinstance(typ, (LiteralType, FunctionLike)):
+        # Actually look up from the fallback instance type.
+        return _analyze_member_access(name, typ.fallback, mx, override_info)
+    elif isinstance(typ, TypedDictType):
+        return analyze_typeddict_access(name, typ, mx, override_info)
+    elif isinstance(typ, NoneType):
+        return analyze_none_member_access(name, typ, mx)
+    elif isinstance(typ, TypeVarLikeType):
+        if isinstance(typ, TypeVarType) and typ.values:
+            return _analyze_member_access(
+                name, make_simplified_union(typ.values), mx, override_info
+            )
+        return _analyze_member_access(name, typ.upper_bound, mx, override_info)
+    elif isinstance(typ, DeletedType):
+        mx.msg.deleted_as_rvalue(typ, mx.context)
+        return AnyType(TypeOfAny.from_error)
+    return report_missing_attribute(mx.original_type, typ, name, mx)
+
+
+def may_be_awaitable_attribute(
+    name: str, typ: Type, mx: MemberContext, override_info: TypeInfo | None = None
+) -> bool:
+    """Check if the given type has the attribute when awaited."""
+    if mx.chk.checking_missing_await:
+        # Avoid infinite recursion.
+        return False
+    with mx.chk.checking_await_set(), mx.msg.filter_errors() as local_errors:
+        aw_type = mx.chk.get_precise_awaitable_type(typ, local_errors)
+        if aw_type is None:
+            return False
+        _ = _analyze_member_access(name, aw_type, mx, override_info)
+        return not local_errors.has_new_errors()
+
+
+def report_missing_attribute(
+    original_type: Type,
+    typ: Type,
+    name: str,
+    mx: MemberContext,
+    override_info: TypeInfo | None = None,
+) -> Type:
+    res_type = mx.msg.has_no_attr(original_type, typ, name, mx.context, mx.module_symbol_table)
+    if not mx.msg.prefer_simple_messages():
+        if may_be_awaitable_attribute(name, typ, mx, override_info):
+            mx.msg.possible_missing_await(mx.context)
+    return res_type
+
+
+# The several functions that follow implement analyze_member_access for various
+# types and aren't documented individually.
+
+
+def analyze_instance_member_access(
+    name: str, typ: Instance, mx: MemberContext, override_info: TypeInfo | None
+) -> Type:
+    if name == "__init__" and not mx.is_super:
+        # Accessing __init__ in statically typed code would compromise
+        # type safety unless used via super().
+        mx.msg.fail(message_registry.CANNOT_ACCESS_INIT, mx.context)
+        return AnyType(TypeOfAny.from_error)
+
+    # The base object has an instance type.
+
+    info = typ.type
+    if override_info:
+        info = override_info
+
+    if (
+        state.find_occurrences
+        and info.name == state.find_occurrences[0]
+        and name == state.find_occurrences[1]
+    ):
+        mx.msg.note("Occurrence of '{}.{}'".format(*state.find_occurrences), mx.context)
+
+    # Look up the member. First look up the method dictionary.
+    method = info.get_method(name)
+    if method and not isinstance(method, Decorator):
+        if mx.is_super:
+            validate_super_call(method, mx)
+
+        if method.is_property:
+            assert isinstance(method, OverloadedFuncDef)
+            first_item = method.items[0]
+            assert isinstance(first_item, Decorator)
+            return analyze_var(name, first_item.var, typ, info, mx)
+        if mx.is_lvalue:
+            mx.msg.cant_assign_to_method(mx.context)
+        signature = function_type(method, mx.named_type("builtins.function"))
+        signature = freshen_all_functions_type_vars(signature)
+        if not method.is_static:
+            if name != "__call__":
+                # TODO: use proper treatment of special methods on unions instead
+                #       of this hack here and below (i.e. mx.self_type).
+                dispatched_type = meet.meet_types(mx.original_type, typ)
+                signature = check_self_arg(
+                    signature, dispatched_type, method.is_class, mx.context, name, mx.msg
+                )
+            signature = bind_self(signature, mx.self_type, is_classmethod=method.is_class)
+        # TODO: should we skip these steps for static methods as well?
+        # Since generic static methods should not be allowed.
+        typ = map_instance_to_supertype(typ, method.info)
+        member_type = expand_type_by_instance(signature, typ)
+        freeze_all_type_vars(member_type)
+        return member_type
+    else:
+        # Not a method.
+        return analyze_member_var_access(name, typ, info, mx)
+
+
+def validate_super_call(node: FuncBase, mx: MemberContext) -> None:
+    unsafe_super = False
+    if isinstance(node, FuncDef) and node.is_trivial_body:
+        unsafe_super = True
+        impl = node
+    elif isinstance(node, OverloadedFuncDef):
+        if node.impl:
+            impl = node.impl if isinstance(node.impl, FuncDef) else node.impl.func
+            unsafe_super = impl.is_trivial_body
+    if unsafe_super:
+        ret_type = (
+            impl.type.ret_type
+            if isinstance(impl.type, CallableType)
+            else AnyType(TypeOfAny.unannotated)
+        )
+        if not subtypes.is_subtype(NoneType(), ret_type):
+            mx.msg.unsafe_super(node.name, node.info.name, mx.context)
+
+
+def analyze_type_callable_member_access(name: str, typ: FunctionLike, mx: MemberContext) -> Type:
+    # Class attribute.
+    # TODO super?
+    ret_type = typ.items[0].ret_type
+    assert isinstance(ret_type, ProperType)
+    if isinstance(ret_type, TupleType):
+        ret_type = tuple_fallback(ret_type)
+    if isinstance(ret_type, TypedDictType):
+        ret_type = ret_type.fallback
+    if isinstance(ret_type, Instance):
+        if not mx.is_operator:
+            # When Python sees an operator (eg `3 == 4`), it automatically translates that
+            # into something like `int.__eq__(3, 4)` instead of `(3).__eq__(4)` as an
+            # optimization.
+            #
+            # While it normally it doesn't matter which of the two versions are used, it
+            # does cause inconsistencies when working with classes. For example, translating
+            # `int == int` to `int.__eq__(int)` would not work since `int.__eq__` is meant to
+            # compare two int _instances_. What we really want is `type(int).__eq__`, which
+            # is meant to compare two types or classes.
+            #
+            # This check makes sure that when we encounter an operator, we skip looking up
+            # the corresponding method in the current instance to avoid this edge case.
+            # See https://github.com/python/mypy/pull/1787 for more info.
+            # TODO: do not rely on same type variables being present in all constructor overloads.
+            result = analyze_class_attribute_access(
+                ret_type, name, mx, original_vars=typ.items[0].variables, mcs_fallback=typ.fallback
+            )
+            if result:
+                return result
+        # Look up from the 'type' type.
+        return _analyze_member_access(name, typ.fallback, mx)
+    else:
+        assert False, f"Unexpected type {ret_type!r}"
+
+
+def analyze_type_type_member_access(
+    name: str, typ: TypeType, mx: MemberContext, override_info: TypeInfo | None
+) -> Type:
+    # Similar to analyze_type_callable_attribute_access.
+    item = None
+    fallback = mx.named_type("builtins.type")
+    if isinstance(typ.item, Instance):
+        item = typ.item
+    elif isinstance(typ.item, AnyType):
+        with mx.msg.filter_errors():
+            return _analyze_member_access(name, fallback, mx, override_info)
+    elif isinstance(typ.item, TypeVarType):
+        upper_bound = get_proper_type(typ.item.upper_bound)
+        if isinstance(upper_bound, Instance):
+            item = upper_bound
+        elif isinstance(upper_bound, UnionType):
+            return _analyze_member_access(
+                name,
+                TypeType.make_normalized(upper_bound, line=typ.line, column=typ.column),
+                mx,
+                override_info,
+            )
+        elif isinstance(upper_bound, TupleType):
+            item = tuple_fallback(upper_bound)
+        elif isinstance(upper_bound, AnyType):
+            with mx.msg.filter_errors():
+                return _analyze_member_access(name, fallback, mx, override_info)
+    elif isinstance(typ.item, TupleType):
+        item = tuple_fallback(typ.item)
+    elif isinstance(typ.item, FunctionLike) and typ.item.is_type_obj():
+        item = typ.item.fallback
+    elif isinstance(typ.item, TypeType):
+        # Access member on metaclass object via Type[Type[C]]
+        if isinstance(typ.item.item, Instance):
+            item = typ.item.item.type.metaclass_type
+    ignore_messages = False
+
+    if item is not None:
+        fallback = item.type.metaclass_type or fallback
+
+    if item and not mx.is_operator:
+        # See comment above for why operators are skipped
+        result = analyze_class_attribute_access(
+            item, name, mx, mcs_fallback=fallback, override_info=override_info
+        )
+        if result:
+            if not (isinstance(get_proper_type(result), AnyType) and item.type.fallback_to_any):
+                return result
+            else:
+                # We don't want errors on metaclass lookup for classes with Any fallback
+                ignore_messages = True
+
+    with mx.msg.filter_errors(filter_errors=ignore_messages):
+        return _analyze_member_access(name, fallback, mx, override_info)
+
+
+def analyze_union_member_access(name: str, typ: UnionType, mx: MemberContext) -> Type:
+    with mx.msg.disable_type_names():
+        results = []
+        for subtype in typ.relevant_items():
+            # Self types should be bound to every individual item of a union.
+            item_mx = mx.copy_modified(self_type=subtype)
+            results.append(_analyze_member_access(name, subtype, item_mx))
+    return make_simplified_union(results)
+
+
+def analyze_none_member_access(name: str, typ: NoneType, mx: MemberContext) -> Type:
+    if name == "__bool__":
+        literal_false = LiteralType(False, fallback=mx.named_type("builtins.bool"))
+        return CallableType(
+            arg_types=[],
+            arg_kinds=[],
+            arg_names=[],
+            ret_type=literal_false,
+            fallback=mx.named_type("builtins.function"),
+        )
+    else:
+        return _analyze_member_access(name, mx.named_type("builtins.object"), mx)
+
+
+def analyze_member_var_access(
+    name: str, itype: Instance, info: TypeInfo, mx: MemberContext
+) -> Type:
+    """Analyse attribute access that does not target a method.
+
+    This is logically part of analyze_member_access and the arguments are similar.
+
+    original_type is the type of E in the expression E.var
+    """
+    # It was not a method. Try looking up a variable.
+    v = lookup_member_var_or_accessor(info, name, mx.is_lvalue)
+
+    vv = v
+    if isinstance(vv, Decorator):
+        # The associated Var node of a decorator contains the type.
+        v = vv.var
+        if mx.is_super:
+            validate_super_call(vv.func, mx)
+
+    if isinstance(vv, TypeInfo):
+        # If the associated variable is a TypeInfo synthesize a Var node for
+        # the purposes of type checking.  This enables us to type check things
+        # like accessing class attributes on an inner class.
+        v = Var(name, type=type_object_type(vv, mx.named_type))
+        v.info = info
+
+    if isinstance(vv, TypeAlias):
+        # Similar to the above TypeInfo case, we allow using
+        # qualified type aliases in runtime context if it refers to an
+        # instance type. For example:
+        #     class C:
+        #         A = List[int]
+        #     x = C.A() <- this is OK
+        typ = mx.chk.expr_checker.alias_type_in_runtime_context(
+            vv, ctx=mx.context, alias_definition=mx.is_lvalue
+        )
+        v = Var(name, type=typ)
+        v.info = info
+
+    if isinstance(v, Var):
+        implicit = info[name].implicit
+
+        # An assignment to final attribute is always an error,
+        # independently of types.
+        if mx.is_lvalue and not mx.chk.get_final_context():
+            check_final_member(name, info, mx.msg, mx.context)
+
+        return analyze_var(name, v, itype, info, mx, implicit=implicit)
+    elif isinstance(v, FuncDef):
+        assert False, "Did not expect a function"
+    elif isinstance(v, MypyFile):
+        mx.chk.module_refs.add(v.fullname)
+        return mx.chk.expr_checker.module_type(v)
+    elif (
+        not v
+        and name not in ["__getattr__", "__setattr__", "__getattribute__"]
+        and not mx.is_operator
+        and mx.module_symbol_table is None
+    ):
+        # Above we skip ModuleType.__getattr__ etc. if we have a
+        # module symbol table, since the symbol table allows precise
+        # checking.
+        if not mx.is_lvalue:
+            for method_name in ("__getattribute__", "__getattr__"):
+                method = info.get_method(method_name)
+
+                # __getattribute__ is defined on builtins.object and returns Any, so without
+                # the guard this search will always find object.__getattribute__ and conclude
+                # that the attribute exists
+                if method and method.info.fullname != "builtins.object":
+                    bound_method = analyze_decorator_or_funcbase_access(
+                        defn=method,
+                        itype=itype,
+                        info=info,
+                        self_type=mx.self_type,
+                        name=method_name,
+                        mx=mx,
+                    )
+                    typ = map_instance_to_supertype(itype, method.info)
+                    getattr_type = get_proper_type(expand_type_by_instance(bound_method, typ))
+                    if isinstance(getattr_type, CallableType):
+                        result = getattr_type.ret_type
+                    else:
+                        result = getattr_type
+
+                    # Call the attribute hook before returning.
+                    fullname = f"{method.info.fullname}.{name}"
+                    hook = mx.chk.plugin.get_attribute_hook(fullname)
+                    if hook:
+                        result = hook(
+                            AttributeContext(
+                                get_proper_type(mx.original_type), result, mx.context, mx.chk
+                            )
+                        )
+                    return result
+        else:
+            setattr_meth = info.get_method("__setattr__")
+            if setattr_meth and setattr_meth.info.fullname != "builtins.object":
+                bound_type = analyze_decorator_or_funcbase_access(
+                    defn=setattr_meth,
+                    itype=itype,
+                    info=info,
+                    self_type=mx.self_type,
+                    name=name,
+                    mx=mx.copy_modified(is_lvalue=False),
+                )
+                typ = map_instance_to_supertype(itype, setattr_meth.info)
+                setattr_type = get_proper_type(expand_type_by_instance(bound_type, typ))
+                if isinstance(setattr_type, CallableType) and len(setattr_type.arg_types) > 0:
+                    return setattr_type.arg_types[-1]
+
+    if itype.type.fallback_to_any:
+        return AnyType(TypeOfAny.special_form)
+
+    # Could not find the member.
+    if itype.extra_attrs and name in itype.extra_attrs.attrs:
+        # For modules use direct symbol table lookup.
+        if not itype.extra_attrs.mod_name:
+            return itype.extra_attrs.attrs[name]
+
+    if mx.is_super:
+        mx.msg.undefined_in_superclass(name, mx.context)
+        return AnyType(TypeOfAny.from_error)
+    else:
+        return report_missing_attribute(mx.original_type, itype, name, mx)
+
+
+def check_final_member(name: str, info: TypeInfo, msg: MessageBuilder, ctx: Context) -> None:
+    """Give an error if the name being assigned was declared as final."""
+    for base in info.mro:
+        sym = base.names.get(name)
+        if sym and is_final_node(sym.node):
+            msg.cant_assign_to_final(name, attr_assign=True, ctx=ctx)
+
+
+def analyze_descriptor_access(descriptor_type: Type, mx: MemberContext) -> Type:
+    """Type check descriptor access.
+
+    Arguments:
+        descriptor_type: The type of the descriptor attribute being accessed
+            (the type of ``f`` in ``a.f`` when ``f`` is a descriptor).
+        mx: The current member access context.
+    Return:
+        The return type of the appropriate ``__get__`` overload for the descriptor.
+    """
+    instance_type = get_proper_type(mx.original_type)
+    orig_descriptor_type = descriptor_type
+    descriptor_type = get_proper_type(descriptor_type)
+
+    if isinstance(descriptor_type, UnionType):
+        # Map the access over union types
+        return make_simplified_union(
+            [analyze_descriptor_access(typ, mx) for typ in descriptor_type.items]
+        )
+    elif not isinstance(descriptor_type, Instance):
+        return orig_descriptor_type
+
+    if not descriptor_type.type.has_readable_member("__get__"):
+        return orig_descriptor_type
+
+    dunder_get = descriptor_type.type.get_method("__get__")
+    if dunder_get is None:
+        mx.msg.fail(
+            message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(
+                descriptor_type.str_with_options(mx.msg.options)
+            ),
+            mx.context,
+        )
+        return AnyType(TypeOfAny.from_error)
+
+    bound_method = analyze_decorator_or_funcbase_access(
+        defn=dunder_get,
+        itype=descriptor_type,
+        info=descriptor_type.type,
+        self_type=descriptor_type,
+        name="__get__",
+        mx=mx,
+    )
+
+    typ = map_instance_to_supertype(descriptor_type, dunder_get.info)
+    dunder_get_type = expand_type_by_instance(bound_method, typ)
+
+    if isinstance(instance_type, FunctionLike) and instance_type.is_type_obj():
+        owner_type = instance_type.items[0].ret_type
+        instance_type = NoneType()
+    elif isinstance(instance_type, TypeType):
+        owner_type = instance_type.item
+        instance_type = NoneType()
+    else:
+        owner_type = instance_type
+
+    callable_name = mx.chk.expr_checker.method_fullname(descriptor_type, "__get__")
+    dunder_get_type = mx.chk.expr_checker.transform_callee_type(
+        callable_name,
+        dunder_get_type,
+        [
+            TempNode(instance_type, context=mx.context),
+            TempNode(TypeType.make_normalized(owner_type), context=mx.context),
+        ],
+        [ARG_POS, ARG_POS],
+        mx.context,
+        object_type=descriptor_type,
+    )
+
+    _, inferred_dunder_get_type = mx.chk.expr_checker.check_call(
+        dunder_get_type,
+        [
+            TempNode(instance_type, context=mx.context),
+            TempNode(TypeType.make_normalized(owner_type), context=mx.context),
+        ],
+        [ARG_POS, ARG_POS],
+        mx.context,
+        object_type=descriptor_type,
+        callable_name=callable_name,
+    )
+
+    inferred_dunder_get_type = get_proper_type(inferred_dunder_get_type)
+    if isinstance(inferred_dunder_get_type, AnyType):
+        # check_call failed, and will have reported an error
+        return inferred_dunder_get_type
+
+    if not isinstance(inferred_dunder_get_type, CallableType):
+        mx.msg.fail(
+            message_registry.DESCRIPTOR_GET_NOT_CALLABLE.format(
+                descriptor_type.str_with_options(mx.msg.options)
+            ),
+            mx.context,
+        )
+        return AnyType(TypeOfAny.from_error)
+
+    return inferred_dunder_get_type.ret_type
+
+
+def is_instance_var(var: Var) -> bool:
+    """Return if var is an instance variable according to PEP 526."""
+    return (
+        # check the type_info node is the var (not a decorated function, etc.)
+        var.name in var.info.names
+        and var.info.names[var.name].node is var
+        and not var.is_classvar
+        # variables without annotations are treated as classvar
+        and not var.is_inferred
+    )
+
+
+def analyze_var(
+    name: str,
+    var: Var,
+    itype: Instance,
+    info: TypeInfo,
+    mx: MemberContext,
+    *,
+    implicit: bool = False,
+) -> Type:
+    """Analyze access to an attribute via a Var node.
+
+    This is conceptually part of analyze_member_access and the arguments are similar.
+    itype is the instance type in which attribute should be looked up
+    original_type is the type of E in the expression E.var
+    if implicit is True, the original Var was created as an assignment to self
+    """
+    # Found a member variable.
+    original_itype = itype
+    itype = map_instance_to_supertype(itype, var.info)
+    typ = var.type
+    if typ:
+        if isinstance(typ, PartialType):
+            return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context)
+        if mx.is_lvalue and var.is_property and not var.is_settable_property:
+            # TODO allow setting attributes in subclass (although it is probably an error)
+            mx.msg.read_only_property(name, itype.type, mx.context)
+        if mx.is_lvalue and var.is_classvar:
+            mx.msg.cant_assign_to_classvar(name, mx.context)
+        t = freshen_all_functions_type_vars(typ)
+        if not (mx.is_self or mx.is_super) or supported_self_type(
+            get_proper_type(mx.original_type)
+        ):
+            t = expand_self_type(var, t, mx.original_type)
+        elif (
+            mx.is_self
+            and original_itype.type != var.info
+            # If an attribute with Self-type was defined in a supertype, we need to
+            # rebind the Self type variable to Self type variable of current class...
+            and original_itype.type.self_type is not None
+            # ...unless `self` has an explicit non-trivial annotation.
+            and original_itype == mx.chk.scope.active_self_type()
+        ):
+            t = expand_self_type(var, t, original_itype.type.self_type)
+        t = get_proper_type(expand_type_by_instance(t, itype))
+        freeze_all_type_vars(t)
+        result: Type = t
+        typ = get_proper_type(typ)
+        if (
+            var.is_initialized_in_class
+            and (not is_instance_var(var) or mx.is_operator)
+            and isinstance(typ, FunctionLike)
+            and not typ.is_type_obj()
+        ):
+            if mx.is_lvalue:
+                if var.is_property:
+                    if not var.is_settable_property:
+                        mx.msg.read_only_property(name, itype.type, mx.context)
+                else:
+                    mx.msg.cant_assign_to_method(mx.context)
+
+            if not var.is_staticmethod:
+                # Class-level function objects and classmethods become bound methods:
+                # the former to the instance, the latter to the class.
+                functype = typ
+                # Use meet to narrow original_type to the dispatched type.
+                # For example, assume
+                # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
+                # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
+                # * x: Union[A1, B1]
+                # In `x.f`, when checking `x` against A1 we assume x is compatible with A
+                # and similarly for B1 when checking against B
+                dispatched_type = meet.meet_types(mx.original_type, itype)
+                signature = freshen_all_functions_type_vars(functype)
+                bound = get_proper_type(expand_self_type(var, signature, mx.original_type))
+                assert isinstance(bound, FunctionLike)
+                signature = bound
+                signature = check_self_arg(
+                    signature, dispatched_type, var.is_classmethod, mx.context, name, mx.msg
+                )
+                signature = bind_self(signature, mx.self_type, var.is_classmethod)
+                expanded_signature = expand_type_by_instance(signature, itype)
+                freeze_all_type_vars(expanded_signature)
+                if var.is_property:
+                    # A property cannot have an overloaded type => the cast is fine.
+                    assert isinstance(expanded_signature, CallableType)
+                    result = expanded_signature.ret_type
+                else:
+                    result = expanded_signature
+    else:
+        if not var.is_ready and not mx.no_deferral:
+            mx.not_ready_callback(var.name, mx.context)
+        # Implicit 'Any' type.
+        result = AnyType(TypeOfAny.special_form)
+    fullname = f"{var.info.fullname}.{name}"
+    hook = mx.chk.plugin.get_attribute_hook(fullname)
+    if result and not mx.is_lvalue and not implicit:
+        result = analyze_descriptor_access(result, mx)
+    if hook:
+        result = hook(
+            AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk)
+        )
+    return result
+
+
+def freeze_all_type_vars(member_type: Type) -> None:
+    member_type.accept(FreezeTypeVarsVisitor())
+
+
+class FreezeTypeVarsVisitor(TypeTraverserVisitor):
+    def visit_callable_type(self, t: CallableType) -> None:
+        for v in t.variables:
+            v.id.meta_level = 0
+        super().visit_callable_type(t)
+
+
+def lookup_member_var_or_accessor(info: TypeInfo, name: str, is_lvalue: bool) -> SymbolNode | None:
+    """Find the attribute/accessor node that refers to a member of a type."""
+    # TODO handle lvalues
+    node = info.get(name)
+    if node:
+        return node.node
+    else:
+        return None
+
+
+def check_self_arg(
+    functype: FunctionLike,
+    dispatched_arg_type: Type,
+    is_classmethod: bool,
+    context: Context,
+    name: str,
+    msg: MessageBuilder,
+) -> FunctionLike:
+    """Check that an instance has a valid type for a method with annotated 'self'.
+
+    For example if the method is defined as:
+        class A:
+            def f(self: S) -> T: ...
+    then for 'x.f' we check that meet(type(x), A) <: S. If the method is overloaded, we
+    select only overloads items that satisfy this requirement. If there are no matching
+    overloads, an error is generated.
+
+    Note: dispatched_arg_type uses a meet to select a relevant item in case if the
+    original type of 'x' is a union. This is done because several special methods
+    treat union types in ad-hoc manner, so we can't use MemberContext.self_type yet.
+    """
+    items = functype.items
+    if not items:
+        return functype
+    new_items = []
+    if is_classmethod:
+        dispatched_arg_type = TypeType.make_normalized(dispatched_arg_type)
+
+    for item in items:
+        if not item.arg_types or item.arg_kinds[0] not in (ARG_POS, ARG_STAR):
+            # No positional first (self) argument (*args is okay).
+            msg.no_formal_self(name, item, context)
+            # This is pretty bad, so just return the original signature if
+            # there is at least one such error.
+            return functype
+        else:
+            selfarg = get_proper_type(item.arg_types[0])
+            if subtypes.is_subtype(dispatched_arg_type, erase_typevars(erase_to_bound(selfarg))):
+                new_items.append(item)
+            elif isinstance(selfarg, ParamSpecType):
+                # TODO: This is not always right. What's the most reasonable thing to do here?
+                new_items.append(item)
+            elif isinstance(selfarg, TypeVarTupleType):
+                raise NotImplementedError
+    if not new_items:
+        # Choose first item for the message (it may be not very helpful for overloads).
+        msg.incompatible_self_argument(
+            name, dispatched_arg_type, items[0], is_classmethod, context
+        )
+        return functype
+    if len(new_items) == 1:
+        return new_items[0]
+    return Overloaded(new_items)
+
+
+def analyze_class_attribute_access(
+    itype: Instance,
+    name: str,
+    mx: MemberContext,
+    *,
+    mcs_fallback: Instance,
+    override_info: TypeInfo | None = None,
+    original_vars: Sequence[TypeVarLikeType] | None = None,
+) -> Type | None:
+    """Analyze access to an attribute on a class object.
+
+    itype is the return type of the class object callable, original_type is the type
+    of E in the expression E.var, original_vars are type variables of the class callable
+    (for generic classes).
+    """
+    info = itype.type
+    if override_info:
+        info = override_info
+
+    fullname = f"{info.fullname}.{name}"
+    hook = mx.chk.plugin.get_class_attribute_hook(fullname)
+
+    node = info.get(name)
+    if not node:
+        if itype.extra_attrs and name in itype.extra_attrs.attrs:
+            # For modules use direct symbol table lookup.
+            if not itype.extra_attrs.mod_name:
+                return itype.extra_attrs.attrs[name]
+        if info.fallback_to_any or info.meta_fallback_to_any:
+            return apply_class_attr_hook(mx, hook, AnyType(TypeOfAny.special_form))
+        return None
+
+    if (
+        isinstance(node.node, Var)
+        and not node.node.is_classvar
+        and not hook
+        and mcs_fallback.type.get(name)
+    ):
+        # If the same attribute is declared on the metaclass and the class but with different types,
+        # and the attribute on the class is not a ClassVar,
+        # the type of the attribute on the metaclass should take priority
+        # over the type of the attribute on the class,
+        # when the attribute is being accessed from the class object itself.
+        #
+        # Return `None` here to signify that the name should be looked up
+        # on the class object itself rather than the instance.
+        return None
+
+    is_decorated = isinstance(node.node, Decorator)
+    is_method = is_decorated or isinstance(node.node, FuncBase)
+    if mx.is_lvalue:
+        if is_method:
+            mx.msg.cant_assign_to_method(mx.context)
+        if isinstance(node.node, TypeInfo):
+            mx.msg.fail(message_registry.CANNOT_ASSIGN_TO_TYPE, mx.context)
+
+    # Refuse class attribute access if slot defined
+    if info.slots and name in info.slots:
+        mx.msg.fail(message_registry.CLASS_VAR_CONFLICTS_SLOTS.format(name), mx.context)
+
+    # If a final attribute was declared on `self` in `__init__`, then it
+    # can't be accessed on the class object.
+    if node.implicit and isinstance(node.node, Var) and node.node.is_final:
+        mx.msg.fail(
+            message_registry.CANNOT_ACCESS_FINAL_INSTANCE_ATTR.format(node.node.name), mx.context
+        )
+
+    # An assignment to final attribute on class object is also always an error,
+    # independently of types.
+    if mx.is_lvalue and not mx.chk.get_final_context():
+        check_final_member(name, info, mx.msg, mx.context)
+
+    if info.is_enum and not (mx.is_lvalue or is_decorated or is_method):
+        enum_class_attribute_type = analyze_enum_class_attribute_access(itype, name, mx)
+        if enum_class_attribute_type:
+            return apply_class_attr_hook(mx, hook, enum_class_attribute_type)
+
+    t = node.type
+    if t:
+        if isinstance(t, PartialType):
+            symnode = node.node
+            assert isinstance(symnode, Var)
+            return apply_class_attr_hook(
+                mx, hook, mx.chk.handle_partial_var_type(t, mx.is_lvalue, symnode, mx.context)
+            )
+
+        # Find the class where method/variable was defined.
+        if isinstance(node.node, Decorator):
+            super_info: TypeInfo | None = node.node.var.info
+        elif isinstance(node.node, (Var, SYMBOL_FUNCBASE_TYPES)):
+            super_info = node.node.info
+        else:
+            super_info = None
+
+        # Map the type to how it would look as a defining class. For example:
+        #     class C(Generic[T]): ...
+        #     class D(C[Tuple[T, S]]): ...
+        #     D[int, str].method()
+        # Here itype is D[int, str], isuper is C[Tuple[int, str]].
+        if not super_info:
+            isuper = None
+        else:
+            isuper = map_instance_to_supertype(itype, super_info)
+
+        if isinstance(node.node, Var):
+            assert isuper is not None
+            # Check if original variable type has type variables. For example:
+            #     class C(Generic[T]):
+            #         x: T
+            #     C.x  # Error, ambiguous access
+            #     C[int].x  # Also an error, since C[int] is same as C at runtime
+            # Exception is Self type wrapped in ClassVar, that is safe.
+            def_vars = set(node.node.info.defn.type_vars)
+            if not node.node.is_classvar and node.node.info.self_type:
+                def_vars.add(node.node.info.self_type)
+            typ_vars = set(get_type_vars(t))
+            if def_vars & typ_vars:
+                # Exception: access on Type[...], including first argument of class methods is OK.
+                if not isinstance(get_proper_type(mx.original_type), TypeType) or node.implicit:
+                    if node.node.is_classvar:
+                        message = message_registry.GENERIC_CLASS_VAR_ACCESS
+                    else:
+                        message = message_registry.GENERIC_INSTANCE_VAR_CLASS_ACCESS
+                    mx.msg.fail(message, mx.context)
+
+            # Erase non-mapped variables, but keep mapped ones, even if there is an error.
+            # In the above example this means that we infer following types:
+            #     C.x -> Any
+            #     C[int].x -> int
+            t = get_proper_type(expand_self_type(node.node, t, itype))
+            t = erase_typevars(expand_type_by_instance(t, isuper), {tv.id for tv in def_vars})
+
+        is_classmethod = (is_decorated and cast(Decorator, node.node).func.is_class) or (
+            isinstance(node.node, FuncBase) and node.node.is_class
+        )
+        t = get_proper_type(t)
+        if isinstance(t, FunctionLike) and is_classmethod:
+            t = check_self_arg(t, mx.self_type, False, mx.context, name, mx.msg)
+        result = add_class_tvars(
+            t, isuper, is_classmethod, mx.self_type, original_vars=original_vars
+        )
+        if not mx.is_lvalue:
+            result = analyze_descriptor_access(result, mx)
+
+        return apply_class_attr_hook(mx, hook, result)
+    elif isinstance(node.node, Var):
+        mx.not_ready_callback(name, mx.context)
+        return AnyType(TypeOfAny.special_form)
+
+    if isinstance(node.node, TypeVarExpr):
+        mx.msg.fail(
+            message_registry.CANNOT_USE_TYPEVAR_AS_EXPRESSION.format(info.name, name), mx.context
+        )
+        return AnyType(TypeOfAny.from_error)
+
+    if isinstance(node.node, TypeInfo):
+        return type_object_type(node.node, mx.named_type)
+
+    if isinstance(node.node, MypyFile):
+        # Reference to a module object.
+        return mx.named_type("types.ModuleType")
+
+    if isinstance(node.node, TypeAlias):
+        return mx.chk.expr_checker.alias_type_in_runtime_context(
+            node.node, ctx=mx.context, alias_definition=mx.is_lvalue
+        )
+
+    if is_decorated:
+        assert isinstance(node.node, Decorator)
+        if node.node.type:
+            return apply_class_attr_hook(mx, hook, node.node.type)
+        else:
+            mx.not_ready_callback(name, mx.context)
+            return AnyType(TypeOfAny.from_error)
+    else:
+        assert isinstance(node.node, FuncBase)
+        typ = function_type(node.node, mx.named_type("builtins.function"))
+        # Note: if we are accessing class method on class object, the cls argument is bound.
+        # Annotated and/or explicit class methods go through other code paths above, for
+        # unannotated implicit class methods we do this here.
+        if node.node.is_class:
+            typ = bind_self(typ, is_classmethod=True)
+        return apply_class_attr_hook(mx, hook, typ)
+
+
+def apply_class_attr_hook(
+    mx: MemberContext, hook: Callable[[AttributeContext], Type] | None, result: Type
+) -> Type | None:
+    if hook:
+        result = hook(
+            AttributeContext(get_proper_type(mx.original_type), result, mx.context, mx.chk)
+        )
+    return result
+
+
+def analyze_enum_class_attribute_access(
+    itype: Instance, name: str, mx: MemberContext
+) -> Type | None:
+    # Skip these since Enum will remove it
+    if name in ENUM_REMOVED_PROPS:
+        return report_missing_attribute(mx.original_type, itype, name, mx)
+    # For other names surrendered by underscores, we don't make them Enum members
+    if name.startswith("__") and name.endswith("__") and name.replace("_", "") != "":
+        return None
+
+    enum_literal = LiteralType(name, fallback=itype)
+    return itype.copy_modified(last_known_value=enum_literal)
+
+
+def analyze_typeddict_access(
+    name: str, typ: TypedDictType, mx: MemberContext, override_info: TypeInfo | None
+) -> Type:
+    if name == "__setitem__":
+        if isinstance(mx.context, IndexExpr):
+            # Since we can get this during `a['key'] = ...`
+            # it is safe to assume that the context is `IndexExpr`.
+            item_type = mx.chk.expr_checker.visit_typeddict_index_expr(
+                typ, mx.context.index, setitem=True
+            )
+        else:
+            # It can also be `a.__setitem__(...)` direct call.
+            # In this case `item_type` can be `Any`,
+            # because we don't have args available yet.
+            # TODO: check in `default` plugin that `__setitem__` is correct.
+            item_type = AnyType(TypeOfAny.implementation_artifact)
+        return CallableType(
+            arg_types=[mx.chk.named_type("builtins.str"), item_type],
+            arg_kinds=[ARG_POS, ARG_POS],
+            arg_names=[None, None],
+            ret_type=NoneType(),
+            fallback=mx.chk.named_type("builtins.function"),
+            name=name,
+        )
+    elif name == "__delitem__":
+        return CallableType(
+            arg_types=[mx.chk.named_type("builtins.str")],
+            arg_kinds=[ARG_POS],
+            arg_names=[None],
+            ret_type=NoneType(),
+            fallback=mx.chk.named_type("builtins.function"),
+            name=name,
+        )
+    return _analyze_member_access(name, typ.fallback, mx, override_info)
+
+
+def add_class_tvars(
+    t: ProperType,
+    isuper: Instance | None,
+    is_classmethod: bool,
+    original_type: Type,
+    original_vars: Sequence[TypeVarLikeType] | None = None,
+) -> Type:
+    """Instantiate type variables during analyze_class_attribute_access,
+    e.g T and Q in the following:
+
+    class A(Generic[T]):
+        @classmethod
+        def foo(cls: Type[Q]) -> Tuple[T, Q]: ...
+
+    class B(A[str]): pass
+    B.foo()
+
+    Args:
+        t: Declared type of the method (or property)
+        isuper: Current instance mapped to the superclass where method was defined, this
+            is usually done by map_instance_to_supertype()
+        is_classmethod: True if this method is decorated with @classmethod
+        original_type: The value of the type B in the expression B.foo() or the corresponding
+            component in case of a union (this is used to bind the self-types)
+        original_vars: Type variables of the class callable on which the method was accessed
+    Returns:
+        Expanded method type with added type variables (when needed).
+    """
+    # TODO: verify consistency between Q and T
+
+    # We add class type variables if the class method is accessed on class object
+    # without applied type arguments, this matches the behavior of __init__().
+    # For example (continuing the example in docstring):
+    #     A       # The type of callable is def [T] () -> A[T], _not_ def () -> A[Any]
+    #     A[int]  # The type of callable is def () -> A[int]
+    # and
+    #     A.foo       # The type is generic def [T] () -> Tuple[T, A[T]]
+    #     A[int].foo  # The type is non-generic def () -> Tuple[int, A[int]]
+    #
+    # This behaviour is useful for defining alternative constructors for generic classes.
+    # To achieve such behaviour, we add the class type variables that are still free
+    # (i.e. appear in the return type of the class object on which the method was accessed).
+    if isinstance(t, CallableType):
+        tvars = original_vars if original_vars is not None else []
+        if is_classmethod:
+            t = freshen_all_functions_type_vars(t)
+            t = bind_self(t, original_type, is_classmethod=True)
+            assert isuper is not None
+            t = expand_type_by_instance(t, isuper)
+            freeze_all_type_vars(t)
+        return t.copy_modified(variables=list(tvars) + list(t.variables))
+    elif isinstance(t, Overloaded):
+        return Overloaded(
+            [
+                cast(
+                    CallableType,
+                    add_class_tvars(
+                        item, isuper, is_classmethod, original_type, original_vars=original_vars
+                    ),
+                )
+                for item in t.items
+            ]
+        )
+    if isuper is not None:
+        t = expand_type_by_instance(t, isuper)
+    return t
+
+
+def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> ProperType:
+    """Return the type of a type object.
+
+    For a generic type G with type variables T and S the type is generally of form
+
+      Callable[..., G[T, S]]
+
+    where ... are argument types for the __init__/__new__ method (without the self
+    argument). Also, the fallback type will be 'type' instead of 'function'.
+    """
+
+    # We take the type from whichever of __init__ and __new__ is first
+    # in the MRO, preferring __init__ if there is a tie.
+    init_method = info.get("__init__")
+    new_method = info.get("__new__")
+    if not init_method or not is_valid_constructor(init_method.node):
+        # Must be an invalid class definition.
+        return AnyType(TypeOfAny.from_error)
+    # There *should* always be a __new__ method except the test stubs
+    # lack it, so just copy init_method in that situation
+    new_method = new_method or init_method
+    if not is_valid_constructor(new_method.node):
+        # Must be an invalid class definition.
+        return AnyType(TypeOfAny.from_error)
+
+    # The two is_valid_constructor() checks ensure this.
+    assert isinstance(new_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
+    assert isinstance(init_method.node, (SYMBOL_FUNCBASE_TYPES, Decorator))
+
+    init_index = info.mro.index(init_method.node.info)
+    new_index = info.mro.index(new_method.node.info)
+
+    fallback = info.metaclass_type or named_type("builtins.type")
+    if init_index < new_index:
+        method: FuncBase | Decorator = init_method.node
+        is_new = False
+    elif init_index > new_index:
+        method = new_method.node
+        is_new = True
+    else:
+        if init_method.node.info.fullname == "builtins.object":
+            # Both are defined by object.  But if we've got a bogus
+            # base class, we can't know for sure, so check for that.
+            if info.fallback_to_any:
+                # Construct a universal callable as the prototype.
+                any_type = AnyType(TypeOfAny.special_form)
+                sig = CallableType(
+                    arg_types=[any_type, any_type],
+                    arg_kinds=[ARG_STAR, ARG_STAR2],
+                    arg_names=["_args", "_kwds"],
+                    ret_type=any_type,
+                    fallback=named_type("builtins.function"),
+                )
+                return class_callable(sig, info, fallback, None, is_new=False)
+
+        # Otherwise prefer __init__ in a tie. It isn't clear that this
+        # is the right thing, but __new__ caused problems with
+        # typeshed (#5647).
+        method = init_method.node
+        is_new = False
+    # Construct callable type based on signature of __init__. Adjust
+    # return type and insert type arguments.
+    if isinstance(method, FuncBase):
+        t = function_type(method, fallback)
+    else:
+        assert isinstance(method.type, ProperType)
+        assert isinstance(method.type, FunctionLike)  # is_valid_constructor() ensures this
+        t = method.type
+    return type_object_type_from_function(t, info, method.info, fallback, is_new)
+
+
+def analyze_decorator_or_funcbase_access(
+    defn: Decorator | FuncBase,
+    itype: Instance,
+    info: TypeInfo,
+    self_type: Type | None,
+    name: str,
+    mx: MemberContext,
+) -> Type:
+    """Analyzes the type behind method access.
+
+    The function itself can possibly be decorated.
+    See: https://github.com/python/mypy/issues/10409
+    """
+    if isinstance(defn, Decorator):
+        return analyze_var(name, defn.var, itype, info, mx)
+    return bind_self(
+        function_type(defn, mx.chk.named_type("builtins.function")), original_type=self_type
+    )
+
+
+def is_valid_constructor(n: SymbolNode | None) -> bool:
+    """Does this node represents a valid constructor method?
+
+    This includes normal functions, overloaded functions, and decorators
+    that return a callable type.
+    """
+    if isinstance(n, FuncBase):
+        return True
+    if isinstance(n, Decorator):
+        return isinstance(get_proper_type(n.type), FunctionLike)
+    return False

二進制
venv/lib/python3.11/site-packages/mypy/checkpattern.cpython-311-x86_64-linux-gnu.so


+ 721 - 0
venv/lib/python3.11/site-packages/mypy/checkpattern.py

@@ -0,0 +1,721 @@
+"""Pattern checker. This file is conceptually part of TypeChecker."""
+
+from __future__ import annotations
+
+from collections import defaultdict
+from typing import Final, NamedTuple
+
+import mypy.checker
+from mypy import message_registry
+from mypy.checkmember import analyze_member_access
+from mypy.expandtype import expand_type_by_instance
+from mypy.join import join_types
+from mypy.literals import literal_hash
+from mypy.maptype import map_instance_to_supertype
+from mypy.meet import narrow_declared_type
+from mypy.messages import MessageBuilder
+from mypy.nodes import ARG_POS, Context, Expression, NameExpr, TypeAlias, TypeInfo, Var
+from mypy.options import Options
+from mypy.patterns import (
+    AsPattern,
+    ClassPattern,
+    MappingPattern,
+    OrPattern,
+    Pattern,
+    SequencePattern,
+    SingletonPattern,
+    StarredPattern,
+    ValuePattern,
+)
+from mypy.plugin import Plugin
+from mypy.subtypes import is_subtype
+from mypy.typeops import (
+    coerce_to_literal,
+    make_simplified_union,
+    try_getting_str_literals_from_type,
+    tuple_fallback,
+)
+from mypy.types import (
+    AnyType,
+    Instance,
+    LiteralType,
+    NoneType,
+    ProperType,
+    TupleType,
+    Type,
+    TypedDictType,
+    TypeOfAny,
+    UninhabitedType,
+    UnionType,
+    get_proper_type,
+)
+from mypy.typevars import fill_typevars
+from mypy.visitor import PatternVisitor
+
+self_match_type_names: Final = [
+    "builtins.bool",
+    "builtins.bytearray",
+    "builtins.bytes",
+    "builtins.dict",
+    "builtins.float",
+    "builtins.frozenset",
+    "builtins.int",
+    "builtins.list",
+    "builtins.set",
+    "builtins.str",
+    "builtins.tuple",
+]
+
+non_sequence_match_type_names: Final = ["builtins.str", "builtins.bytes", "builtins.bytearray"]
+
+
+# For every Pattern a PatternType can be calculated. This requires recursively calculating
+# the PatternTypes of the sub-patterns first.
+# Using the data in the PatternType the match subject and captured names can be narrowed/inferred.
+class PatternType(NamedTuple):
+    type: Type  # The type the match subject can be narrowed to
+    rest_type: Type  # The remaining type if the pattern didn't match
+    captures: dict[Expression, Type]  # The variables captured by the pattern
+
+
+class PatternChecker(PatternVisitor[PatternType]):
+    """Pattern checker.
+
+    This class checks if a pattern can match a type, what the type can be narrowed to, and what
+    type capture patterns should be inferred as.
+    """
+
+    # Some services are provided by a TypeChecker instance.
+    chk: mypy.checker.TypeChecker
+    # This is shared with TypeChecker, but stored also here for convenience.
+    msg: MessageBuilder
+    # Currently unused
+    plugin: Plugin
+    # The expression being matched against the pattern
+    subject: Expression
+
+    subject_type: Type
+    # Type of the subject to check the (sub)pattern against
+    type_context: list[Type]
+    # Types that match against self instead of their __match_args__ if used as a class pattern
+    # Filled in from self_match_type_names
+    self_match_types: list[Type]
+    # Types that are sequences, but don't match sequence patterns. Filled in from
+    # non_sequence_match_type_names
+    non_sequence_match_types: list[Type]
+
+    options: Options
+
+    def __init__(
+        self, chk: mypy.checker.TypeChecker, msg: MessageBuilder, plugin: Plugin, options: Options
+    ) -> None:
+        self.chk = chk
+        self.msg = msg
+        self.plugin = plugin
+
+        self.type_context = []
+        self.self_match_types = self.generate_types_from_names(self_match_type_names)
+        self.non_sequence_match_types = self.generate_types_from_names(
+            non_sequence_match_type_names
+        )
+        self.options = options
+
+    def accept(self, o: Pattern, type_context: Type) -> PatternType:
+        self.type_context.append(type_context)
+        result = o.accept(self)
+        self.type_context.pop()
+
+        return result
+
+    def visit_as_pattern(self, o: AsPattern) -> PatternType:
+        current_type = self.type_context[-1]
+        if o.pattern is not None:
+            pattern_type = self.accept(o.pattern, current_type)
+            typ, rest_type, type_map = pattern_type
+        else:
+            typ, rest_type, type_map = current_type, UninhabitedType(), {}
+
+        if not is_uninhabited(typ) and o.name is not None:
+            typ, _ = self.chk.conditional_types_with_intersection(
+                current_type, [get_type_range(typ)], o, default=current_type
+            )
+            if not is_uninhabited(typ):
+                type_map[o.name] = typ
+
+        return PatternType(typ, rest_type, type_map)
+
+    def visit_or_pattern(self, o: OrPattern) -> PatternType:
+        current_type = self.type_context[-1]
+
+        #
+        # Check all the subpatterns
+        #
+        pattern_types = []
+        for pattern in o.patterns:
+            pattern_type = self.accept(pattern, current_type)
+            pattern_types.append(pattern_type)
+            current_type = pattern_type.rest_type
+
+        #
+        # Collect the final type
+        #
+        types = []
+        for pattern_type in pattern_types:
+            if not is_uninhabited(pattern_type.type):
+                types.append(pattern_type.type)
+
+        #
+        # Check the capture types
+        #
+        capture_types: dict[Var, list[tuple[Expression, Type]]] = defaultdict(list)
+        # Collect captures from the first subpattern
+        for expr, typ in pattern_types[0].captures.items():
+            node = get_var(expr)
+            capture_types[node].append((expr, typ))
+
+        # Check if other subpatterns capture the same names
+        for i, pattern_type in enumerate(pattern_types[1:]):
+            vars = {get_var(expr) for expr, _ in pattern_type.captures.items()}
+            if capture_types.keys() != vars:
+                self.msg.fail(message_registry.OR_PATTERN_ALTERNATIVE_NAMES, o.patterns[i])
+            for expr, typ in pattern_type.captures.items():
+                node = get_var(expr)
+                capture_types[node].append((expr, typ))
+
+        captures: dict[Expression, Type] = {}
+        for var, capture_list in capture_types.items():
+            typ = UninhabitedType()
+            for _, other in capture_list:
+                typ = join_types(typ, other)
+
+            captures[capture_list[0][0]] = typ
+
+        union_type = make_simplified_union(types)
+        return PatternType(union_type, current_type, captures)
+
+    def visit_value_pattern(self, o: ValuePattern) -> PatternType:
+        current_type = self.type_context[-1]
+        typ = self.chk.expr_checker.accept(o.expr)
+        typ = coerce_to_literal(typ)
+        narrowed_type, rest_type = self.chk.conditional_types_with_intersection(
+            current_type, [get_type_range(typ)], o, default=current_type
+        )
+        if not isinstance(get_proper_type(narrowed_type), (LiteralType, UninhabitedType)):
+            return PatternType(narrowed_type, UnionType.make_union([narrowed_type, rest_type]), {})
+        return PatternType(narrowed_type, rest_type, {})
+
+    def visit_singleton_pattern(self, o: SingletonPattern) -> PatternType:
+        current_type = self.type_context[-1]
+        value: bool | None = o.value
+        if isinstance(value, bool):
+            typ = self.chk.expr_checker.infer_literal_expr_type(value, "builtins.bool")
+        elif value is None:
+            typ = NoneType()
+        else:
+            assert False
+
+        narrowed_type, rest_type = self.chk.conditional_types_with_intersection(
+            current_type, [get_type_range(typ)], o, default=current_type
+        )
+        return PatternType(narrowed_type, rest_type, {})
+
+    def visit_sequence_pattern(self, o: SequencePattern) -> PatternType:
+        #
+        # check for existence of a starred pattern
+        #
+        current_type = get_proper_type(self.type_context[-1])
+        if not self.can_match_sequence(current_type):
+            return self.early_non_match()
+        star_positions = [i for i, p in enumerate(o.patterns) if isinstance(p, StarredPattern)]
+        star_position: int | None = None
+        if len(star_positions) == 1:
+            star_position = star_positions[0]
+        elif len(star_positions) >= 2:
+            assert False, "Parser should prevent multiple starred patterns"
+        required_patterns = len(o.patterns)
+        if star_position is not None:
+            required_patterns -= 1
+
+        #
+        # get inner types of original type
+        #
+        if isinstance(current_type, TupleType):
+            inner_types = current_type.items
+            size_diff = len(inner_types) - required_patterns
+            if size_diff < 0:
+                return self.early_non_match()
+            elif size_diff > 0 and star_position is None:
+                return self.early_non_match()
+        else:
+            inner_type = self.get_sequence_type(current_type, o)
+            if inner_type is None:
+                inner_type = self.chk.named_type("builtins.object")
+            inner_types = [inner_type] * len(o.patterns)
+
+        #
+        # match inner patterns
+        #
+        contracted_new_inner_types: list[Type] = []
+        contracted_rest_inner_types: list[Type] = []
+        captures: dict[Expression, Type] = {}
+
+        contracted_inner_types = self.contract_starred_pattern_types(
+            inner_types, star_position, required_patterns
+        )
+        for p, t in zip(o.patterns, contracted_inner_types):
+            pattern_type = self.accept(p, t)
+            typ, rest, type_map = pattern_type
+            contracted_new_inner_types.append(typ)
+            contracted_rest_inner_types.append(rest)
+            self.update_type_map(captures, type_map)
+
+        new_inner_types = self.expand_starred_pattern_types(
+            contracted_new_inner_types, star_position, len(inner_types)
+        )
+        rest_inner_types = self.expand_starred_pattern_types(
+            contracted_rest_inner_types, star_position, len(inner_types)
+        )
+
+        #
+        # Calculate new type
+        #
+        new_type: Type
+        rest_type: Type = current_type
+        if isinstance(current_type, TupleType):
+            narrowed_inner_types = []
+            inner_rest_types = []
+            for inner_type, new_inner_type in zip(inner_types, new_inner_types):
+                (
+                    narrowed_inner_type,
+                    inner_rest_type,
+                ) = self.chk.conditional_types_with_intersection(
+                    new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type
+                )
+                narrowed_inner_types.append(narrowed_inner_type)
+                inner_rest_types.append(inner_rest_type)
+            if all(not is_uninhabited(typ) for typ in narrowed_inner_types):
+                new_type = TupleType(narrowed_inner_types, current_type.partial_fallback)
+            else:
+                new_type = UninhabitedType()
+
+            if all(is_uninhabited(typ) for typ in inner_rest_types):
+                # All subpatterns always match, so we can apply negative narrowing
+                rest_type = TupleType(rest_inner_types, current_type.partial_fallback)
+        else:
+            new_inner_type = UninhabitedType()
+            for typ in new_inner_types:
+                new_inner_type = join_types(new_inner_type, typ)
+            new_type = self.construct_sequence_child(current_type, new_inner_type)
+            if is_subtype(new_type, current_type):
+                new_type, _ = self.chk.conditional_types_with_intersection(
+                    current_type, [get_type_range(new_type)], o, default=current_type
+                )
+            else:
+                new_type = current_type
+        return PatternType(new_type, rest_type, captures)
+
+    def get_sequence_type(self, t: Type, context: Context) -> Type | None:
+        t = get_proper_type(t)
+        if isinstance(t, AnyType):
+            return AnyType(TypeOfAny.from_another_any, t)
+        if isinstance(t, UnionType):
+            items = [self.get_sequence_type(item, context) for item in t.items]
+            not_none_items = [item for item in items if item is not None]
+            if not_none_items:
+                return make_simplified_union(not_none_items)
+            else:
+                return None
+
+        if self.chk.type_is_iterable(t) and isinstance(t, (Instance, TupleType)):
+            if isinstance(t, TupleType):
+                t = tuple_fallback(t)
+            return self.chk.iterable_item_type(t, context)
+        else:
+            return None
+
+    def contract_starred_pattern_types(
+        self, types: list[Type], star_pos: int | None, num_patterns: int
+    ) -> list[Type]:
+        """
+        Contracts a list of types in a sequence pattern depending on the position of a starred
+        capture pattern.
+
+        For example if the sequence pattern [a, *b, c] is matched against types [bool, int, str,
+        bytes] the contracted types are [bool, Union[int, str], bytes].
+
+        If star_pos in None the types are returned unchanged.
+        """
+        if star_pos is None:
+            return types
+        new_types = types[:star_pos]
+        star_length = len(types) - num_patterns
+        new_types.append(make_simplified_union(types[star_pos : star_pos + star_length]))
+        new_types += types[star_pos + star_length :]
+
+        return new_types
+
+    def expand_starred_pattern_types(
+        self, types: list[Type], star_pos: int | None, num_types: int
+    ) -> list[Type]:
+        """Undoes the contraction done by contract_starred_pattern_types.
+
+        For example if the sequence pattern is [a, *b, c] and types [bool, int, str] are extended
+        to length 4 the result is [bool, int, int, str].
+        """
+        if star_pos is None:
+            return types
+        new_types = types[:star_pos]
+        star_length = num_types - len(types) + 1
+        new_types += [types[star_pos]] * star_length
+        new_types += types[star_pos + 1 :]
+
+        return new_types
+
+    def visit_starred_pattern(self, o: StarredPattern) -> PatternType:
+        captures: dict[Expression, Type] = {}
+        if o.capture is not None:
+            list_type = self.chk.named_generic_type("builtins.list", [self.type_context[-1]])
+            captures[o.capture] = list_type
+        return PatternType(self.type_context[-1], UninhabitedType(), captures)
+
+    def visit_mapping_pattern(self, o: MappingPattern) -> PatternType:
+        current_type = get_proper_type(self.type_context[-1])
+        can_match = True
+        captures: dict[Expression, Type] = {}
+        for key, value in zip(o.keys, o.values):
+            inner_type = self.get_mapping_item_type(o, current_type, key)
+            if inner_type is None:
+                can_match = False
+                inner_type = self.chk.named_type("builtins.object")
+            pattern_type = self.accept(value, inner_type)
+            if is_uninhabited(pattern_type.type):
+                can_match = False
+            else:
+                self.update_type_map(captures, pattern_type.captures)
+
+        if o.rest is not None:
+            mapping = self.chk.named_type("typing.Mapping")
+            if is_subtype(current_type, mapping) and isinstance(current_type, Instance):
+                mapping_inst = map_instance_to_supertype(current_type, mapping.type)
+                dict_typeinfo = self.chk.lookup_typeinfo("builtins.dict")
+                rest_type = Instance(dict_typeinfo, mapping_inst.args)
+            else:
+                object_type = self.chk.named_type("builtins.object")
+                rest_type = self.chk.named_generic_type(
+                    "builtins.dict", [object_type, object_type]
+                )
+
+            captures[o.rest] = rest_type
+
+        if can_match:
+            # We can't narrow the type here, as Mapping key is invariant.
+            new_type = self.type_context[-1]
+        else:
+            new_type = UninhabitedType()
+        return PatternType(new_type, current_type, captures)
+
+    def get_mapping_item_type(
+        self, pattern: MappingPattern, mapping_type: Type, key: Expression
+    ) -> Type | None:
+        mapping_type = get_proper_type(mapping_type)
+        if isinstance(mapping_type, TypedDictType):
+            with self.msg.filter_errors() as local_errors:
+                result: Type | None = self.chk.expr_checker.visit_typeddict_index_expr(
+                    mapping_type, key
+                )
+                has_local_errors = local_errors.has_new_errors()
+            # If we can't determine the type statically fall back to treating it as a normal
+            # mapping
+            if has_local_errors:
+                with self.msg.filter_errors() as local_errors:
+                    result = self.get_simple_mapping_item_type(pattern, mapping_type, key)
+
+                    if local_errors.has_new_errors():
+                        result = None
+        else:
+            with self.msg.filter_errors():
+                result = self.get_simple_mapping_item_type(pattern, mapping_type, key)
+        return result
+
+    def get_simple_mapping_item_type(
+        self, pattern: MappingPattern, mapping_type: Type, key: Expression
+    ) -> Type:
+        result, _ = self.chk.expr_checker.check_method_call_by_name(
+            "__getitem__", mapping_type, [key], [ARG_POS], pattern
+        )
+        return result
+
+    def visit_class_pattern(self, o: ClassPattern) -> PatternType:
+        current_type = get_proper_type(self.type_context[-1])
+
+        #
+        # Check class type
+        #
+        type_info = o.class_ref.node
+        if type_info is None:
+            return PatternType(AnyType(TypeOfAny.from_error), AnyType(TypeOfAny.from_error), {})
+        if isinstance(type_info, TypeAlias) and not type_info.no_args:
+            self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o)
+            return self.early_non_match()
+        if isinstance(type_info, TypeInfo):
+            any_type = AnyType(TypeOfAny.implementation_artifact)
+            typ: Type = Instance(type_info, [any_type] * len(type_info.defn.type_vars))
+        elif isinstance(type_info, TypeAlias):
+            typ = type_info.target
+        else:
+            if isinstance(type_info, Var) and type_info.type is not None:
+                name = type_info.type.str_with_options(self.options)
+            else:
+                name = type_info.name
+            self.msg.fail(message_registry.CLASS_PATTERN_TYPE_REQUIRED.format(name), o)
+            return self.early_non_match()
+
+        new_type, rest_type = self.chk.conditional_types_with_intersection(
+            current_type, [get_type_range(typ)], o, default=current_type
+        )
+        if is_uninhabited(new_type):
+            return self.early_non_match()
+        # TODO: Do I need this?
+        narrowed_type = narrow_declared_type(current_type, new_type)
+
+        #
+        # Convert positional to keyword patterns
+        #
+        keyword_pairs: list[tuple[str | None, Pattern]] = []
+        match_arg_set: set[str] = set()
+
+        captures: dict[Expression, Type] = {}
+
+        if len(o.positionals) != 0:
+            if self.should_self_match(typ):
+                if len(o.positionals) > 1:
+                    self.msg.fail(message_registry.CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o)
+                pattern_type = self.accept(o.positionals[0], narrowed_type)
+                if not is_uninhabited(pattern_type.type):
+                    return PatternType(
+                        pattern_type.type,
+                        join_types(rest_type, pattern_type.rest_type),
+                        pattern_type.captures,
+                    )
+                captures = pattern_type.captures
+            else:
+                with self.msg.filter_errors() as local_errors:
+                    match_args_type = analyze_member_access(
+                        "__match_args__",
+                        typ,
+                        o,
+                        False,
+                        False,
+                        False,
+                        self.msg,
+                        original_type=typ,
+                        chk=self.chk,
+                    )
+                    has_local_errors = local_errors.has_new_errors()
+                if has_local_errors:
+                    self.msg.fail(
+                        message_registry.MISSING_MATCH_ARGS.format(
+                            typ.str_with_options(self.options)
+                        ),
+                        o,
+                    )
+                    return self.early_non_match()
+
+                proper_match_args_type = get_proper_type(match_args_type)
+                if isinstance(proper_match_args_type, TupleType):
+                    match_arg_names = get_match_arg_names(proper_match_args_type)
+
+                    if len(o.positionals) > len(match_arg_names):
+                        self.msg.fail(message_registry.CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o)
+                        return self.early_non_match()
+                else:
+                    match_arg_names = [None] * len(o.positionals)
+
+                for arg_name, pos in zip(match_arg_names, o.positionals):
+                    keyword_pairs.append((arg_name, pos))
+                    if arg_name is not None:
+                        match_arg_set.add(arg_name)
+
+        #
+        # Check for duplicate patterns
+        #
+        keyword_arg_set = set()
+        has_duplicates = False
+        for key, value in zip(o.keyword_keys, o.keyword_values):
+            keyword_pairs.append((key, value))
+            if key in match_arg_set:
+                self.msg.fail(
+                    message_registry.CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL.format(key), value
+                )
+                has_duplicates = True
+            elif key in keyword_arg_set:
+                self.msg.fail(
+                    message_registry.CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN.format(key), value
+                )
+                has_duplicates = True
+            keyword_arg_set.add(key)
+
+        if has_duplicates:
+            return self.early_non_match()
+
+        #
+        # Check keyword patterns
+        #
+        can_match = True
+        for keyword, pattern in keyword_pairs:
+            key_type: Type | None = None
+            with self.msg.filter_errors() as local_errors:
+                if keyword is not None:
+                    key_type = analyze_member_access(
+                        keyword,
+                        narrowed_type,
+                        pattern,
+                        False,
+                        False,
+                        False,
+                        self.msg,
+                        original_type=new_type,
+                        chk=self.chk,
+                    )
+                else:
+                    key_type = AnyType(TypeOfAny.from_error)
+                has_local_errors = local_errors.has_new_errors()
+            if has_local_errors or key_type is None:
+                key_type = AnyType(TypeOfAny.from_error)
+                self.msg.fail(
+                    message_registry.CLASS_PATTERN_UNKNOWN_KEYWORD.format(
+                        typ.str_with_options(self.options), keyword
+                    ),
+                    pattern,
+                )
+
+            inner_type, inner_rest_type, inner_captures = self.accept(pattern, key_type)
+            if is_uninhabited(inner_type):
+                can_match = False
+            else:
+                self.update_type_map(captures, inner_captures)
+                if not is_uninhabited(inner_rest_type):
+                    rest_type = current_type
+
+        if not can_match:
+            new_type = UninhabitedType()
+        return PatternType(new_type, rest_type, captures)
+
+    def should_self_match(self, typ: Type) -> bool:
+        typ = get_proper_type(typ)
+        if isinstance(typ, Instance) and typ.type.is_named_tuple:
+            return False
+        for other in self.self_match_types:
+            if is_subtype(typ, other):
+                return True
+        return False
+
+    def can_match_sequence(self, typ: ProperType) -> bool:
+        if isinstance(typ, UnionType):
+            return any(self.can_match_sequence(get_proper_type(item)) for item in typ.items)
+        for other in self.non_sequence_match_types:
+            # We have to ignore promotions, as memoryview should match, but bytes,
+            # which it can be promoted to, shouldn't
+            if is_subtype(typ, other, ignore_promotions=True):
+                return False
+        sequence = self.chk.named_type("typing.Sequence")
+        # If the static type is more general than sequence the actual type could still match
+        return is_subtype(typ, sequence) or is_subtype(sequence, typ)
+
+    def generate_types_from_names(self, type_names: list[str]) -> list[Type]:
+        types: list[Type] = []
+        for name in type_names:
+            try:
+                types.append(self.chk.named_type(name))
+            except KeyError as e:
+                # Some built in types are not defined in all test cases
+                if not name.startswith("builtins."):
+                    raise e
+        return types
+
+    def update_type_map(
+        self, original_type_map: dict[Expression, Type], extra_type_map: dict[Expression, Type]
+    ) -> None:
+        # Calculating this would not be needed if TypeMap directly used literal hashes instead of
+        # expressions, as suggested in the TODO above it's definition
+        already_captured = {literal_hash(expr) for expr in original_type_map}
+        for expr, typ in extra_type_map.items():
+            if literal_hash(expr) in already_captured:
+                node = get_var(expr)
+                self.msg.fail(
+                    message_registry.MULTIPLE_ASSIGNMENTS_IN_PATTERN.format(node.name), expr
+                )
+            else:
+                original_type_map[expr] = typ
+
+    def construct_sequence_child(self, outer_type: Type, inner_type: Type) -> Type:
+        """
+        If outer_type is a child class of typing.Sequence returns a new instance of
+        outer_type, that is a Sequence of inner_type. If outer_type is not a child class of
+        typing.Sequence just returns a Sequence of inner_type
+
+        For example:
+        construct_sequence_child(List[int], str) = List[str]
+
+        TODO: this doesn't make sense. For example if one has class S(Sequence[int], Generic[T])
+        or class T(Sequence[Tuple[T, T]]), there is no way any of those can map to Sequence[str].
+        """
+        proper_type = get_proper_type(outer_type)
+        if isinstance(proper_type, UnionType):
+            types = [
+                self.construct_sequence_child(item, inner_type)
+                for item in proper_type.items
+                if self.can_match_sequence(get_proper_type(item))
+            ]
+            return make_simplified_union(types)
+        sequence = self.chk.named_generic_type("typing.Sequence", [inner_type])
+        if is_subtype(outer_type, self.chk.named_type("typing.Sequence")):
+            proper_type = get_proper_type(outer_type)
+            if isinstance(proper_type, TupleType):
+                proper_type = tuple_fallback(proper_type)
+            assert isinstance(proper_type, Instance)
+            empty_type = fill_typevars(proper_type.type)
+            partial_type = expand_type_by_instance(empty_type, sequence)
+            return expand_type_by_instance(partial_type, proper_type)
+        else:
+            return sequence
+
+    def early_non_match(self) -> PatternType:
+        return PatternType(UninhabitedType(), self.type_context[-1], {})
+
+
+def get_match_arg_names(typ: TupleType) -> list[str | None]:
+    args: list[str | None] = []
+    for item in typ.items:
+        values = try_getting_str_literals_from_type(item)
+        if values is None or len(values) != 1:
+            args.append(None)
+        else:
+            args.append(values[0])
+    return args
+
+
+def get_var(expr: Expression) -> Var:
+    """
+    Warning: this in only true for expressions captured by a match statement.
+    Don't call it from anywhere else
+    """
+    assert isinstance(expr, NameExpr)
+    node = expr.node
+    assert isinstance(node, Var)
+    return node
+
+
+def get_type_range(typ: Type) -> mypy.checker.TypeRange:
+    typ = get_proper_type(typ)
+    if (
+        isinstance(typ, Instance)
+        and typ.last_known_value
+        and isinstance(typ.last_known_value.value, bool)
+    ):
+        typ = typ.last_known_value
+    return mypy.checker.TypeRange(typ, is_upper_bound=False)
+
+
+def is_uninhabited(typ: Type) -> bool:
+    return isinstance(get_proper_type(typ), UninhabitedType)

二進制
venv/lib/python3.11/site-packages/mypy/checkstrformat.cpython-311-x86_64-linux-gnu.so


+ 1105 - 0
venv/lib/python3.11/site-packages/mypy/checkstrformat.py

@@ -0,0 +1,1105 @@
+"""
+Format expression type checker.
+
+This file is conceptually part of ExpressionChecker and TypeChecker. Main functionality
+is located in StringFormatterChecker.check_str_format_call() for '{}'.format(), and in
+StringFormatterChecker.check_str_interpolation() for printf-style % interpolation.
+
+Note that although at runtime format strings are parsed using custom parsers,
+here we use a regexp-based approach. This way we 99% match runtime behaviour while keeping
+implementation simple.
+"""
+
+from __future__ import annotations
+
+import re
+from typing import TYPE_CHECKING, Callable, Dict, Final, Match, Pattern, Tuple, Union, cast
+from typing_extensions import TypeAlias as _TypeAlias
+
+import mypy.errorcodes as codes
+from mypy.errors import Errors
+from mypy.nodes import (
+    ARG_NAMED,
+    ARG_POS,
+    ARG_STAR,
+    ARG_STAR2,
+    BytesExpr,
+    CallExpr,
+    Context,
+    DictExpr,
+    Expression,
+    ExpressionStmt,
+    IndexExpr,
+    IntExpr,
+    MemberExpr,
+    MypyFile,
+    NameExpr,
+    Node,
+    StarExpr,
+    StrExpr,
+    TempNode,
+    TupleExpr,
+)
+from mypy.types import (
+    AnyType,
+    Instance,
+    LiteralType,
+    TupleType,
+    Type,
+    TypeOfAny,
+    TypeVarType,
+    UnionType,
+    get_proper_type,
+    get_proper_types,
+)
+
+if TYPE_CHECKING:
+    # break import cycle only needed for mypy
+    import mypy.checker
+    import mypy.checkexpr
+
+from mypy import message_registry
+from mypy.maptype import map_instance_to_supertype
+from mypy.messages import MessageBuilder
+from mypy.parse import parse
+from mypy.subtypes import is_subtype
+from mypy.typeops import custom_special_method
+
+FormatStringExpr: _TypeAlias = Union[StrExpr, BytesExpr]
+Checkers: _TypeAlias = Tuple[Callable[[Expression], None], Callable[[Type], bool]]
+MatchMap: _TypeAlias = Dict[Tuple[int, int], Match[str]]  # span -> match
+
+
+def compile_format_re() -> Pattern[str]:
+    """Construct regexp to match format conversion specifiers in % interpolation.
+
+    See https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting
+    The regexp is intentionally a bit wider to report better errors.
+    """
+    key_re = r"(\((?P<key>[^)]*)\))?"  # (optional) parenthesised sequence of characters.
+    flags_re = r"(?P<flags>[#0\-+ ]*)"  # (optional) sequence of flags.
+    width_re = r"(?P<width>[1-9][0-9]*|\*)?"  # (optional) minimum field width (* or numbers).
+    precision_re = r"(?:\.(?P<precision>\*|[0-9]+)?)?"  # (optional) . followed by * of numbers.
+    length_mod_re = r"[hlL]?"  # (optional) length modifier (unused).
+    type_re = r"(?P<type>.)?"  # conversion type.
+    format_re = "%" + key_re + flags_re + width_re + precision_re + length_mod_re + type_re
+    return re.compile(format_re)
+
+
+def compile_new_format_re(custom_spec: bool) -> Pattern[str]:
+    """Construct regexps to match format conversion specifiers in str.format() calls.
+
+    See After https://docs.python.org/3/library/string.html#formatspec for
+    specifications. The regexps are intentionally wider, to report better errors,
+    instead of just not matching.
+    """
+
+    # Field (optional) is an integer/identifier possibly followed by several .attr and [index].
+    field = r"(?P<field>(?P<key>[^.[!:]*)([^:!]+)?)"
+
+    # Conversion (optional) is ! followed by one of letters for forced repr(), str(), or ascii().
+    conversion = r"(?P<conversion>![^:])?"
+
+    # Format specification (optional) follows its own mini-language:
+    if not custom_spec:
+        # Fill and align is valid for all builtin types.
+        fill_align = r"(?P<fill_align>.?[<>=^])?"
+        # Number formatting options are only valid for int, float, complex, and Decimal,
+        # except if only width is given (it is valid for all types).
+        # This contains sign, flags (sign, # and/or 0), width, grouping (_ or ,) and precision.
+        num_spec = r"(?P<flags>[+\- ]?#?0?)(?P<width>\d+)?[_,]?(?P<precision>\.\d+)?"
+        # The last element is type.
+        conv_type = r"(?P<type>.)?"  # only some are supported, but we want to give a better error
+        format_spec = r"(?P<format_spec>:" + fill_align + num_spec + conv_type + r")?"
+    else:
+        # Custom types can define their own form_spec using __format__().
+        format_spec = r"(?P<format_spec>:.*)?"
+
+    return re.compile(field + conversion + format_spec)
+
+
+FORMAT_RE: Final = compile_format_re()
+FORMAT_RE_NEW: Final = compile_new_format_re(False)
+FORMAT_RE_NEW_CUSTOM: Final = compile_new_format_re(True)
+DUMMY_FIELD_NAME: Final = "__dummy_name__"
+
+# Types that require either int or float.
+NUMERIC_TYPES_OLD: Final = {"d", "i", "o", "u", "x", "X", "e", "E", "f", "F", "g", "G"}
+NUMERIC_TYPES_NEW: Final = {"b", "d", "o", "e", "E", "f", "F", "g", "G", "n", "x", "X", "%"}
+
+# These types accept _only_ int.
+REQUIRE_INT_OLD: Final = {"o", "x", "X"}
+REQUIRE_INT_NEW: Final = {"b", "d", "o", "x", "X"}
+
+# These types fall back to SupportsFloat with % (other fall back to SupportsInt)
+FLOAT_TYPES: Final = {"e", "E", "f", "F", "g", "G"}
+
+
+class ConversionSpecifier:
+    def __init__(
+        self, match: Match[str], start_pos: int = -1, non_standard_format_spec: bool = False
+    ) -> None:
+        self.whole_seq = match.group()
+        self.start_pos = start_pos
+
+        m_dict = match.groupdict()
+        self.key = m_dict.get("key")
+
+        # Replace unmatched optional groups with empty matches (for convenience).
+        self.conv_type = m_dict.get("type", "")
+        self.flags = m_dict.get("flags", "")
+        self.width = m_dict.get("width", "")
+        self.precision = m_dict.get("precision", "")
+
+        # Used only for str.format() calls (it may be custom for types with __format__()).
+        self.format_spec = m_dict.get("format_spec")
+        self.non_standard_format_spec = non_standard_format_spec
+        # Used only for str.format() calls.
+        self.conversion = m_dict.get("conversion")
+        # Full formatted expression (i.e. key plus following attributes and/or indexes).
+        # Used only for str.format() calls.
+        self.field = m_dict.get("field")
+
+    def has_key(self) -> bool:
+        return self.key is not None
+
+    def has_star(self) -> bool:
+        return self.width == "*" or self.precision == "*"
+
+
+def parse_conversion_specifiers(format_str: str) -> list[ConversionSpecifier]:
+    """Parse c-printf-style format string into list of conversion specifiers."""
+    specifiers: list[ConversionSpecifier] = []
+    for m in re.finditer(FORMAT_RE, format_str):
+        specifiers.append(ConversionSpecifier(m, start_pos=m.start()))
+    return specifiers
+
+
+def parse_format_value(
+    format_value: str, ctx: Context, msg: MessageBuilder, nested: bool = False
+) -> list[ConversionSpecifier] | None:
+    """Parse format string into list of conversion specifiers.
+
+    The specifiers may be nested (two levels maximum), in this case they are ordered as
+    '{0:{1}}, {2:{3}{4}}'. Return None in case of an error.
+    """
+    top_targets = find_non_escaped_targets(format_value, ctx, msg)
+    if top_targets is None:
+        return None
+
+    result: list[ConversionSpecifier] = []
+    for target, start_pos in top_targets:
+        match = FORMAT_RE_NEW.fullmatch(target)
+        if match:
+            conv_spec = ConversionSpecifier(match, start_pos=start_pos)
+        else:
+            custom_match = FORMAT_RE_NEW_CUSTOM.fullmatch(target)
+            if custom_match:
+                conv_spec = ConversionSpecifier(
+                    custom_match, start_pos=start_pos, non_standard_format_spec=True
+                )
+            else:
+                msg.fail(
+                    "Invalid conversion specifier in format string",
+                    ctx,
+                    code=codes.STRING_FORMATTING,
+                )
+                return None
+
+        if conv_spec.key and ("{" in conv_spec.key or "}" in conv_spec.key):
+            msg.fail("Conversion value must not contain { or }", ctx, code=codes.STRING_FORMATTING)
+            return None
+        result.append(conv_spec)
+
+        # Parse nested conversions that are allowed in format specifier.
+        if (
+            conv_spec.format_spec
+            and conv_spec.non_standard_format_spec
+            and ("{" in conv_spec.format_spec or "}" in conv_spec.format_spec)
+        ):
+            if nested:
+                msg.fail(
+                    "Formatting nesting must be at most two levels deep",
+                    ctx,
+                    code=codes.STRING_FORMATTING,
+                )
+                return None
+            sub_conv_specs = parse_format_value(conv_spec.format_spec, ctx, msg, nested=True)
+            if sub_conv_specs is None:
+                return None
+            result.extend(sub_conv_specs)
+    return result
+
+
+def find_non_escaped_targets(
+    format_value: str, ctx: Context, msg: MessageBuilder
+) -> list[tuple[str, int]] | None:
+    """Return list of raw (un-parsed) format specifiers in format string.
+
+    Format specifiers don't include enclosing braces. We don't use regexp for
+    this because they don't work well with nested/repeated patterns
+    (both greedy and non-greedy), and these are heavily used internally for
+    representation of f-strings.
+
+    Return None in case of an error.
+    """
+    result = []
+    next_spec = ""
+    pos = 0
+    nesting = 0
+    while pos < len(format_value):
+        c = format_value[pos]
+        if not nesting:
+            # Skip any paired '{{' and '}}', enter nesting on '{', report error on '}'.
+            if c == "{":
+                if pos < len(format_value) - 1 and format_value[pos + 1] == "{":
+                    pos += 1
+                else:
+                    nesting = 1
+            if c == "}":
+                if pos < len(format_value) - 1 and format_value[pos + 1] == "}":
+                    pos += 1
+                else:
+                    msg.fail(
+                        "Invalid conversion specifier in format string: unexpected }",
+                        ctx,
+                        code=codes.STRING_FORMATTING,
+                    )
+                    return None
+        else:
+            # Adjust nesting level, then either continue adding chars or move on.
+            if c == "{":
+                nesting += 1
+            if c == "}":
+                nesting -= 1
+            if nesting:
+                next_spec += c
+            else:
+                result.append((next_spec, pos - len(next_spec)))
+                next_spec = ""
+        pos += 1
+    if nesting:
+        msg.fail(
+            "Invalid conversion specifier in format string: unmatched {",
+            ctx,
+            code=codes.STRING_FORMATTING,
+        )
+        return None
+    return result
+
+
+class StringFormatterChecker:
+    """String interpolation/formatter type checker.
+
+    This class works closely together with checker.ExpressionChecker.
+    """
+
+    # Some services are provided by a TypeChecker instance.
+    chk: mypy.checker.TypeChecker
+    # This is shared with TypeChecker, but stored also here for convenience.
+    msg: MessageBuilder
+    # Some services are provided by a ExpressionChecker instance.
+    exprchk: mypy.checkexpr.ExpressionChecker
+
+    def __init__(
+        self,
+        exprchk: mypy.checkexpr.ExpressionChecker,
+        chk: mypy.checker.TypeChecker,
+        msg: MessageBuilder,
+    ) -> None:
+        """Construct an expression type checker."""
+        self.chk = chk
+        self.exprchk = exprchk
+        self.msg = msg
+
+    def check_str_format_call(self, call: CallExpr, format_value: str) -> None:
+        """Perform more precise checks for str.format() calls when possible.
+
+        Currently the checks are performed for:
+          * Actual string literals
+          * Literal types with string values
+          * Final names with string values
+
+        The checks that we currently perform:
+          * Check generic validity (e.g. unmatched { or }, and {} in invalid positions)
+          * Check consistency of specifiers' auto-numbering
+          * Verify that replacements can be found for all conversion specifiers,
+            and all arguments were used
+          * Non-standard format specs are only allowed for types with custom __format__
+          * Type check replacements with accessors applied (if any).
+          * Verify that specifier type is known and matches replacement type
+          * Perform special checks for some specifier types:
+            - 'c' requires a single character string
+            - 's' must not accept bytes
+            - non-empty flags are only allowed for numeric types
+        """
+        conv_specs = parse_format_value(format_value, call, self.msg)
+        if conv_specs is None:
+            return
+        if not self.auto_generate_keys(conv_specs, call):
+            return
+        self.check_specs_in_format_call(call, conv_specs, format_value)
+
+    def check_specs_in_format_call(
+        self, call: CallExpr, specs: list[ConversionSpecifier], format_value: str
+    ) -> None:
+        """Perform pairwise checks for conversion specifiers vs their replacements.
+
+        The core logic for format checking is implemented in this method.
+        """
+        assert all(s.key for s in specs), "Keys must be auto-generated first!"
+        replacements = self.find_replacements_in_call(call, [cast(str, s.key) for s in specs])
+        assert len(replacements) == len(specs)
+        for spec, repl in zip(specs, replacements):
+            repl = self.apply_field_accessors(spec, repl, ctx=call)
+            actual_type = repl.type if isinstance(repl, TempNode) else self.chk.lookup_type(repl)
+            assert actual_type is not None
+
+            # Special case custom formatting.
+            if (
+                spec.format_spec
+                and spec.non_standard_format_spec
+                and
+                # Exclude "dynamic" specifiers (i.e. containing nested formatting).
+                not ("{" in spec.format_spec or "}" in spec.format_spec)
+            ):
+                if (
+                    not custom_special_method(actual_type, "__format__", check_all=True)
+                    or spec.conversion
+                ):
+                    # TODO: add support for some custom specs like datetime?
+                    self.msg.fail(
+                        "Unrecognized format" ' specification "{}"'.format(spec.format_spec[1:]),
+                        call,
+                        code=codes.STRING_FORMATTING,
+                    )
+                    continue
+            # Adjust expected and actual types.
+            if not spec.conv_type:
+                expected_type: Type | None = AnyType(TypeOfAny.special_form)
+            else:
+                assert isinstance(call.callee, MemberExpr)
+                if isinstance(call.callee.expr, StrExpr):
+                    format_str = call.callee.expr
+                else:
+                    format_str = StrExpr(format_value)
+                expected_type = self.conversion_type(
+                    spec.conv_type, call, format_str, format_call=True
+                )
+            if spec.conversion is not None:
+                # If the explicit conversion is given, then explicit conversion is called _first_.
+                if spec.conversion[1] not in "rsa":
+                    self.msg.fail(
+                        'Invalid conversion type "{}",'
+                        ' must be one of "r", "s" or "a"'.format(spec.conversion[1]),
+                        call,
+                        code=codes.STRING_FORMATTING,
+                    )
+                actual_type = self.named_type("builtins.str")
+
+            # Perform the checks for given types.
+            if expected_type is None:
+                continue
+
+            a_type = get_proper_type(actual_type)
+            actual_items = (
+                get_proper_types(a_type.items) if isinstance(a_type, UnionType) else [a_type]
+            )
+            for a_type in actual_items:
+                if custom_special_method(a_type, "__format__"):
+                    continue
+                self.check_placeholder_type(a_type, expected_type, call)
+                self.perform_special_format_checks(spec, call, repl, a_type, expected_type)
+
+    def perform_special_format_checks(
+        self,
+        spec: ConversionSpecifier,
+        call: CallExpr,
+        repl: Expression,
+        actual_type: Type,
+        expected_type: Type,
+    ) -> None:
+        # TODO: try refactoring to combine this logic with % formatting.
+        if spec.conv_type == "c":
+            if isinstance(repl, (StrExpr, BytesExpr)) and len(repl.value) != 1:
+                self.msg.requires_int_or_char(call, format_call=True)
+            c_typ = get_proper_type(self.chk.lookup_type(repl))
+            if isinstance(c_typ, Instance) and c_typ.last_known_value:
+                c_typ = c_typ.last_known_value
+            if isinstance(c_typ, LiteralType) and isinstance(c_typ.value, str):
+                if len(c_typ.value) != 1:
+                    self.msg.requires_int_or_char(call, format_call=True)
+        if (not spec.conv_type or spec.conv_type == "s") and not spec.conversion:
+            if has_type_component(actual_type, "builtins.bytes") and not custom_special_method(
+                actual_type, "__str__"
+            ):
+                self.msg.fail(
+                    'If x = b\'abc\' then f"{x}" or "{}".format(x) produces "b\'abc\'", '
+                    'not "abc". If this is desired behavior, use f"{x!r}" or "{!r}".format(x). '
+                    "Otherwise, decode the bytes",
+                    call,
+                    code=codes.STR_BYTES_PY3,
+                )
+        if spec.flags:
+            numeric_types = UnionType(
+                [self.named_type("builtins.int"), self.named_type("builtins.float")]
+            )
+            if (
+                spec.conv_type
+                and spec.conv_type not in NUMERIC_TYPES_NEW
+                or not spec.conv_type
+                and not is_subtype(actual_type, numeric_types)
+                and not custom_special_method(actual_type, "__format__")
+            ):
+                self.msg.fail(
+                    "Numeric flags are only allowed for numeric types",
+                    call,
+                    code=codes.STRING_FORMATTING,
+                )
+
+    def find_replacements_in_call(self, call: CallExpr, keys: list[str]) -> list[Expression]:
+        """Find replacement expression for every specifier in str.format() call.
+
+        In case of an error use TempNode(AnyType).
+        """
+        result: list[Expression] = []
+        used: set[Expression] = set()
+        for key in keys:
+            if key.isdecimal():
+                expr = self.get_expr_by_position(int(key), call)
+                if not expr:
+                    self.msg.fail(
+                        "Cannot find replacement for positional"
+                        " format specifier {}".format(key),
+                        call,
+                        code=codes.STRING_FORMATTING,
+                    )
+                    expr = TempNode(AnyType(TypeOfAny.from_error))
+            else:
+                expr = self.get_expr_by_name(key, call)
+                if not expr:
+                    self.msg.fail(
+                        "Cannot find replacement for named" ' format specifier "{}"'.format(key),
+                        call,
+                        code=codes.STRING_FORMATTING,
+                    )
+                    expr = TempNode(AnyType(TypeOfAny.from_error))
+            result.append(expr)
+            if not isinstance(expr, TempNode):
+                used.add(expr)
+        # Strictly speaking not using all replacements is not a type error, but most likely
+        # a typo in user code, so we show an error like we do for % formatting.
+        total_explicit = len([kind for kind in call.arg_kinds if kind in (ARG_POS, ARG_NAMED)])
+        if len(used) < total_explicit:
+            self.msg.too_many_string_formatting_arguments(call)
+        return result
+
+    def get_expr_by_position(self, pos: int, call: CallExpr) -> Expression | None:
+        """Get positional replacement expression from '{0}, {1}'.format(x, y, ...) call.
+
+        If the type is from *args, return TempNode(<item type>). Return None in case of
+        an error.
+        """
+        pos_args = [arg for arg, kind in zip(call.args, call.arg_kinds) if kind == ARG_POS]
+        if pos < len(pos_args):
+            return pos_args[pos]
+        star_args = [arg for arg, kind in zip(call.args, call.arg_kinds) if kind == ARG_STAR]
+        if not star_args:
+            return None
+
+        # Fall back to *args when present in call.
+        star_arg = star_args[0]
+        varargs_type = get_proper_type(self.chk.lookup_type(star_arg))
+        if not isinstance(varargs_type, Instance) or not varargs_type.type.has_base(
+            "typing.Sequence"
+        ):
+            # Error should be already reported.
+            return TempNode(AnyType(TypeOfAny.special_form))
+        iter_info = self.chk.named_generic_type(
+            "typing.Sequence", [AnyType(TypeOfAny.special_form)]
+        ).type
+        return TempNode(map_instance_to_supertype(varargs_type, iter_info).args[0])
+
+    def get_expr_by_name(self, key: str, call: CallExpr) -> Expression | None:
+        """Get named replacement expression from '{name}'.format(name=...) call.
+
+        If the type is from **kwargs, return TempNode(<item type>). Return None in case of
+        an error.
+        """
+        named_args = [
+            arg
+            for arg, kind, name in zip(call.args, call.arg_kinds, call.arg_names)
+            if kind == ARG_NAMED and name == key
+        ]
+        if named_args:
+            return named_args[0]
+        star_args_2 = [arg for arg, kind in zip(call.args, call.arg_kinds) if kind == ARG_STAR2]
+        if not star_args_2:
+            return None
+        star_arg_2 = star_args_2[0]
+        kwargs_type = get_proper_type(self.chk.lookup_type(star_arg_2))
+        if not isinstance(kwargs_type, Instance) or not kwargs_type.type.has_base(
+            "typing.Mapping"
+        ):
+            # Error should be already reported.
+            return TempNode(AnyType(TypeOfAny.special_form))
+        any_type = AnyType(TypeOfAny.special_form)
+        mapping_info = self.chk.named_generic_type("typing.Mapping", [any_type, any_type]).type
+        return TempNode(map_instance_to_supertype(kwargs_type, mapping_info).args[1])
+
+    def auto_generate_keys(self, all_specs: list[ConversionSpecifier], ctx: Context) -> bool:
+        """Translate '{} {name} {}' to '{0} {name} {1}'.
+
+        Return True if generation was successful, otherwise report an error and return false.
+        """
+        some_defined = any(s.key and s.key.isdecimal() for s in all_specs)
+        all_defined = all(bool(s.key) for s in all_specs)
+        if some_defined and not all_defined:
+            self.msg.fail(
+                "Cannot combine automatic field numbering and manual field specification",
+                ctx,
+                code=codes.STRING_FORMATTING,
+            )
+            return False
+        if all_defined:
+            return True
+        next_index = 0
+        for spec in all_specs:
+            if not spec.key:
+                str_index = str(next_index)
+                spec.key = str_index
+                # Update also the full field (i.e. turn {.x} into {0.x}).
+                if not spec.field:
+                    spec.field = str_index
+                else:
+                    spec.field = str_index + spec.field
+                next_index += 1
+        return True
+
+    def apply_field_accessors(
+        self, spec: ConversionSpecifier, repl: Expression, ctx: Context
+    ) -> Expression:
+        """Transform and validate expr in '{.attr[item]}'.format(expr) into expr.attr['item'].
+
+        If validation fails, return TempNode(AnyType).
+        """
+        assert spec.key, "Keys must be auto-generated first!"
+        if spec.field == spec.key:
+            return repl
+        assert spec.field
+
+        temp_errors = Errors(self.chk.options)
+        dummy = DUMMY_FIELD_NAME + spec.field[len(spec.key) :]
+        temp_ast: Node = parse(
+            dummy, fnam="<format>", module=None, options=self.chk.options, errors=temp_errors
+        )
+        if temp_errors.is_errors():
+            self.msg.fail(
+                f'Syntax error in format specifier "{spec.field}"',
+                ctx,
+                code=codes.STRING_FORMATTING,
+            )
+            return TempNode(AnyType(TypeOfAny.from_error))
+
+        # These asserts are guaranteed by the original regexp.
+        assert isinstance(temp_ast, MypyFile)
+        temp_ast = temp_ast.defs[0]
+        assert isinstance(temp_ast, ExpressionStmt)
+        temp_ast = temp_ast.expr
+        if not self.validate_and_transform_accessors(temp_ast, repl, spec, ctx=ctx):
+            return TempNode(AnyType(TypeOfAny.from_error))
+
+        # Check if there are any other errors (like missing members).
+        # TODO: fix column to point to actual start of the format specifier _within_ string.
+        temp_ast.line = ctx.line
+        temp_ast.column = ctx.column
+        self.exprchk.accept(temp_ast)
+        return temp_ast
+
+    def validate_and_transform_accessors(
+        self,
+        temp_ast: Expression,
+        original_repl: Expression,
+        spec: ConversionSpecifier,
+        ctx: Context,
+    ) -> bool:
+        """Validate and transform (in-place) format field accessors.
+
+        On error, report it and return False. The transformations include replacing the dummy
+        variable with actual replacement expression and translating any name expressions in an
+        index into strings, so that this will work:
+
+            class User(TypedDict):
+                name: str
+                id: int
+            u: User
+            '{[id]:d} -> {[name]}'.format(u)
+        """
+        if not isinstance(temp_ast, (MemberExpr, IndexExpr)):
+            self.msg.fail(
+                "Only index and member expressions are allowed in"
+                ' format field accessors; got "{}"'.format(spec.field),
+                ctx,
+                code=codes.STRING_FORMATTING,
+            )
+            return False
+        if isinstance(temp_ast, MemberExpr):
+            node = temp_ast.expr
+        else:
+            node = temp_ast.base
+            if not isinstance(temp_ast.index, (NameExpr, IntExpr)):
+                assert spec.key, "Call this method only after auto-generating keys!"
+                assert spec.field
+                self.msg.fail(
+                    "Invalid index expression in format field"
+                    ' accessor "{}"'.format(spec.field[len(spec.key) :]),
+                    ctx,
+                    code=codes.STRING_FORMATTING,
+                )
+                return False
+            if isinstance(temp_ast.index, NameExpr):
+                temp_ast.index = StrExpr(temp_ast.index.name)
+        if isinstance(node, NameExpr) and node.name == DUMMY_FIELD_NAME:
+            # Replace it with the actual replacement expression.
+            assert isinstance(temp_ast, (IndexExpr, MemberExpr))  # XXX: this is redundant
+            if isinstance(temp_ast, IndexExpr):
+                temp_ast.base = original_repl
+            else:
+                temp_ast.expr = original_repl
+            return True
+        node.line = ctx.line
+        node.column = ctx.column
+        return self.validate_and_transform_accessors(
+            node, original_repl=original_repl, spec=spec, ctx=ctx
+        )
+
+    # TODO: In Python 3, the bytes formatting has a more restricted set of options
+    #       compared to string formatting.
+    def check_str_interpolation(self, expr: FormatStringExpr, replacements: Expression) -> Type:
+        """Check the types of the 'replacements' in a string interpolation
+        expression: str % replacements.
+        """
+        self.exprchk.accept(expr)
+        specifiers = parse_conversion_specifiers(expr.value)
+        has_mapping_keys = self.analyze_conversion_specifiers(specifiers, expr)
+        if isinstance(expr, BytesExpr) and self.chk.options.python_version < (3, 5):
+            self.msg.fail(
+                "Bytes formatting is only supported in Python 3.5 and later",
+                replacements,
+                code=codes.STRING_FORMATTING,
+            )
+            return AnyType(TypeOfAny.from_error)
+
+        if has_mapping_keys is None:
+            pass  # Error was reported
+        elif has_mapping_keys:
+            self.check_mapping_str_interpolation(specifiers, replacements, expr)
+        else:
+            self.check_simple_str_interpolation(specifiers, replacements, expr)
+
+        if isinstance(expr, BytesExpr):
+            return self.named_type("builtins.bytes")
+        elif isinstance(expr, StrExpr):
+            return self.named_type("builtins.str")
+        else:
+            assert False
+
+    def analyze_conversion_specifiers(
+        self, specifiers: list[ConversionSpecifier], context: Context
+    ) -> bool | None:
+        has_star = any(specifier.has_star() for specifier in specifiers)
+        has_key = any(specifier.has_key() for specifier in specifiers)
+        all_have_keys = all(
+            specifier.has_key() or specifier.conv_type == "%" for specifier in specifiers
+        )
+
+        if has_key and has_star:
+            self.msg.string_interpolation_with_star_and_key(context)
+            return None
+        if has_key and not all_have_keys:
+            self.msg.string_interpolation_mixing_key_and_non_keys(context)
+            return None
+        return has_key
+
+    def check_simple_str_interpolation(
+        self,
+        specifiers: list[ConversionSpecifier],
+        replacements: Expression,
+        expr: FormatStringExpr,
+    ) -> None:
+        """Check % string interpolation with positional specifiers '%s, %d' % ('yes, 42')."""
+        checkers = self.build_replacement_checkers(specifiers, replacements, expr)
+        if checkers is None:
+            return
+
+        rhs_type = get_proper_type(self.accept(replacements))
+        rep_types: list[Type] = []
+        if isinstance(rhs_type, TupleType):
+            rep_types = rhs_type.items
+        elif isinstance(rhs_type, AnyType):
+            return
+        elif isinstance(rhs_type, Instance) and rhs_type.type.fullname == "builtins.tuple":
+            # Assume that an arbitrary-length tuple has the right number of items.
+            rep_types = [rhs_type.args[0]] * len(checkers)
+        elif isinstance(rhs_type, UnionType):
+            for typ in rhs_type.relevant_items():
+                temp_node = TempNode(typ)
+                temp_node.line = replacements.line
+                self.check_simple_str_interpolation(specifiers, temp_node, expr)
+            return
+        else:
+            rep_types = [rhs_type]
+
+        if len(checkers) > len(rep_types):
+            # Only check the fix-length Tuple type. Other Iterable types would skip.
+            if is_subtype(rhs_type, self.chk.named_type("typing.Iterable")) and not isinstance(
+                rhs_type, TupleType
+            ):
+                return
+            else:
+                self.msg.too_few_string_formatting_arguments(replacements)
+        elif len(checkers) < len(rep_types):
+            self.msg.too_many_string_formatting_arguments(replacements)
+        else:
+            if len(checkers) == 1:
+                check_node, check_type = checkers[0]
+                if isinstance(rhs_type, TupleType) and len(rhs_type.items) == 1:
+                    check_type(rhs_type.items[0])
+                else:
+                    check_node(replacements)
+            elif isinstance(replacements, TupleExpr) and not any(
+                isinstance(item, StarExpr) for item in replacements.items
+            ):
+                for checks, rep_node in zip(checkers, replacements.items):
+                    check_node, check_type = checks
+                    check_node(rep_node)
+            else:
+                for checks, rep_type in zip(checkers, rep_types):
+                    check_node, check_type = checks
+                    check_type(rep_type)
+
+    def check_mapping_str_interpolation(
+        self,
+        specifiers: list[ConversionSpecifier],
+        replacements: Expression,
+        expr: FormatStringExpr,
+    ) -> None:
+        """Check % string interpolation with names specifiers '%(name)s' % {'name': 'John'}."""
+        if isinstance(replacements, DictExpr) and all(
+            isinstance(k, (StrExpr, BytesExpr)) for k, v in replacements.items
+        ):
+            mapping: dict[str, Type] = {}
+            for k, v in replacements.items:
+                if isinstance(expr, BytesExpr):
+                    # Special case: for bytes formatting keys must be bytes.
+                    if not isinstance(k, BytesExpr):
+                        self.msg.fail(
+                            "Dictionary keys in bytes formatting must be bytes, not strings",
+                            expr,
+                            code=codes.STRING_FORMATTING,
+                        )
+                key_str = cast(FormatStringExpr, k).value
+                mapping[key_str] = self.accept(v)
+
+            for specifier in specifiers:
+                if specifier.conv_type == "%":
+                    # %% is allowed in mappings, no checking is required
+                    continue
+                assert specifier.key is not None
+                if specifier.key not in mapping:
+                    self.msg.key_not_in_mapping(specifier.key, replacements)
+                    return
+                rep_type = mapping[specifier.key]
+                assert specifier.conv_type is not None
+                expected_type = self.conversion_type(specifier.conv_type, replacements, expr)
+                if expected_type is None:
+                    return
+                self.chk.check_subtype(
+                    rep_type,
+                    expected_type,
+                    replacements,
+                    message_registry.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION,
+                    "expression has type",
+                    f"placeholder with key '{specifier.key}' has type",
+                    code=codes.STRING_FORMATTING,
+                )
+                if specifier.conv_type == "s":
+                    self.check_s_special_cases(expr, rep_type, expr)
+        else:
+            rep_type = self.accept(replacements)
+            dict_type = self.build_dict_type(expr)
+            self.chk.check_subtype(
+                rep_type,
+                dict_type,
+                replacements,
+                message_registry.FORMAT_REQUIRES_MAPPING,
+                "expression has type",
+                "expected type for mapping is",
+                code=codes.STRING_FORMATTING,
+            )
+
+    def build_dict_type(self, expr: FormatStringExpr) -> Type:
+        """Build expected mapping type for right operand in % formatting."""
+        any_type = AnyType(TypeOfAny.special_form)
+        if isinstance(expr, BytesExpr):
+            bytes_type = self.chk.named_generic_type("builtins.bytes", [])
+            return self.chk.named_generic_type(
+                "_typeshed.SupportsKeysAndGetItem", [bytes_type, any_type]
+            )
+        elif isinstance(expr, StrExpr):
+            str_type = self.chk.named_generic_type("builtins.str", [])
+            return self.chk.named_generic_type(
+                "_typeshed.SupportsKeysAndGetItem", [str_type, any_type]
+            )
+        else:
+            assert False, "Unreachable"
+
+    def build_replacement_checkers(
+        self, specifiers: list[ConversionSpecifier], context: Context, expr: FormatStringExpr
+    ) -> list[Checkers] | None:
+        checkers: list[Checkers] = []
+        for specifier in specifiers:
+            checker = self.replacement_checkers(specifier, context, expr)
+            if checker is None:
+                return None
+            checkers.extend(checker)
+        return checkers
+
+    def replacement_checkers(
+        self, specifier: ConversionSpecifier, context: Context, expr: FormatStringExpr
+    ) -> list[Checkers] | None:
+        """Returns a list of tuples of two functions that check whether a replacement is
+        of the right type for the specifier. The first function takes a node and checks
+        its type in the right type context. The second function just checks a type.
+        """
+        checkers: list[Checkers] = []
+
+        if specifier.width == "*":
+            checkers.append(self.checkers_for_star(context))
+        if specifier.precision == "*":
+            checkers.append(self.checkers_for_star(context))
+
+        if specifier.conv_type == "c":
+            c = self.checkers_for_c_type(specifier.conv_type, context, expr)
+            if c is None:
+                return None
+            checkers.append(c)
+        elif specifier.conv_type is not None and specifier.conv_type != "%":
+            c = self.checkers_for_regular_type(specifier.conv_type, context, expr)
+            if c is None:
+                return None
+            checkers.append(c)
+        return checkers
+
+    def checkers_for_star(self, context: Context) -> Checkers:
+        """Returns a tuple of check functions that check whether, respectively,
+        a node or a type is compatible with a star in a conversion specifier.
+        """
+        expected = self.named_type("builtins.int")
+
+        def check_type(type: Type) -> bool:
+            expected = self.named_type("builtins.int")
+            return self.chk.check_subtype(
+                type, expected, context, "* wants int", code=codes.STRING_FORMATTING
+            )
+
+        def check_expr(expr: Expression) -> None:
+            type = self.accept(expr, expected)
+            check_type(type)
+
+        return check_expr, check_type
+
+    def check_placeholder_type(self, typ: Type, expected_type: Type, context: Context) -> bool:
+        return self.chk.check_subtype(
+            typ,
+            expected_type,
+            context,
+            message_registry.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION,
+            "expression has type",
+            "placeholder has type",
+            code=codes.STRING_FORMATTING,
+        )
+
+    def checkers_for_regular_type(
+        self, conv_type: str, context: Context, expr: FormatStringExpr
+    ) -> Checkers | None:
+        """Returns a tuple of check functions that check whether, respectively,
+        a node or a type is compatible with 'type'. Return None in case of an error.
+        """
+        expected_type = self.conversion_type(conv_type, context, expr)
+        if expected_type is None:
+            return None
+
+        def check_type(typ: Type) -> bool:
+            assert expected_type is not None
+            ret = self.check_placeholder_type(typ, expected_type, context)
+            if ret and conv_type == "s":
+                ret = self.check_s_special_cases(expr, typ, context)
+            return ret
+
+        def check_expr(expr: Expression) -> None:
+            type = self.accept(expr, expected_type)
+            check_type(type)
+
+        return check_expr, check_type
+
+    def check_s_special_cases(self, expr: FormatStringExpr, typ: Type, context: Context) -> bool:
+        """Additional special cases for %s in bytes vs string context."""
+        if isinstance(expr, StrExpr):
+            # Couple special cases for string formatting.
+            if has_type_component(typ, "builtins.bytes"):
+                self.msg.fail(
+                    'If x = b\'abc\' then "%s" % x produces "b\'abc\'", not "abc". '
+                    'If this is desired behavior use "%r" % x. Otherwise, decode the bytes',
+                    context,
+                    code=codes.STR_BYTES_PY3,
+                )
+                return False
+        if isinstance(expr, BytesExpr):
+            # A special case for bytes formatting: b'%s' actually requires bytes on Python 3.
+            if has_type_component(typ, "builtins.str"):
+                self.msg.fail(
+                    "On Python 3 b'%s' requires bytes, not string",
+                    context,
+                    code=codes.STRING_FORMATTING,
+                )
+                return False
+        return True
+
+    def checkers_for_c_type(
+        self, type: str, context: Context, format_expr: FormatStringExpr
+    ) -> Checkers | None:
+        """Returns a tuple of check functions that check whether, respectively,
+        a node or a type is compatible with 'type' that is a character type.
+        """
+        expected_type = self.conversion_type(type, context, format_expr)
+        if expected_type is None:
+            return None
+
+        def check_type(type: Type) -> bool:
+            assert expected_type is not None
+            if isinstance(format_expr, BytesExpr):
+                err_msg = '"%c" requires an integer in range(256) or a single byte'
+            else:
+                err_msg = '"%c" requires int or char'
+            return self.chk.check_subtype(
+                type,
+                expected_type,
+                context,
+                err_msg,
+                "expression has type",
+                code=codes.STRING_FORMATTING,
+            )
+
+        def check_expr(expr: Expression) -> None:
+            """int, or str with length 1"""
+            type = self.accept(expr, expected_type)
+            # We need further check with expr to make sure that
+            # it has exact one char or one single byte.
+            if check_type(type):
+                # Python 3 doesn't support b'%c' % str
+                if (
+                    isinstance(format_expr, BytesExpr)
+                    and isinstance(expr, BytesExpr)
+                    and len(expr.value) != 1
+                ):
+                    self.msg.requires_int_or_single_byte(context)
+                elif isinstance(expr, (StrExpr, BytesExpr)) and len(expr.value) != 1:
+                    self.msg.requires_int_or_char(context)
+
+        return check_expr, check_type
+
+    def conversion_type(
+        self, p: str, context: Context, expr: FormatStringExpr, format_call: bool = False
+    ) -> Type | None:
+        """Return the type that is accepted for a string interpolation conversion specifier type.
+
+        Note that both Python's float (e.g. %f) and integer (e.g. %d)
+        specifier types accept both float and integers.
+
+        The 'format_call' argument indicates whether this type came from % interpolation or from
+        a str.format() call, the meaning of few formatting types are different.
+        """
+        NUMERIC_TYPES = NUMERIC_TYPES_NEW if format_call else NUMERIC_TYPES_OLD
+        INT_TYPES = REQUIRE_INT_NEW if format_call else REQUIRE_INT_OLD
+        if p == "b" and not format_call:
+            if self.chk.options.python_version < (3, 5):
+                self.msg.fail(
+                    'Format character "b" is only supported in Python 3.5 and later',
+                    context,
+                    code=codes.STRING_FORMATTING,
+                )
+                return None
+            if not isinstance(expr, BytesExpr):
+                self.msg.fail(
+                    'Format character "b" is only supported on bytes patterns',
+                    context,
+                    code=codes.STRING_FORMATTING,
+                )
+                return None
+            return self.named_type("builtins.bytes")
+        elif p == "a":
+            # TODO: return type object?
+            return AnyType(TypeOfAny.special_form)
+        elif p in ["s", "r"]:
+            return AnyType(TypeOfAny.special_form)
+        elif p in NUMERIC_TYPES:
+            if p in INT_TYPES:
+                numeric_types = [self.named_type("builtins.int")]
+            else:
+                numeric_types = [
+                    self.named_type("builtins.int"),
+                    self.named_type("builtins.float"),
+                ]
+                if not format_call:
+                    if p in FLOAT_TYPES:
+                        numeric_types.append(self.named_type("typing.SupportsFloat"))
+                    else:
+                        numeric_types.append(self.named_type("typing.SupportsInt"))
+            return UnionType.make_union(numeric_types)
+        elif p in ["c"]:
+            if isinstance(expr, BytesExpr):
+                return UnionType(
+                    [self.named_type("builtins.int"), self.named_type("builtins.bytes")]
+                )
+            else:
+                return UnionType(
+                    [self.named_type("builtins.int"), self.named_type("builtins.str")]
+                )
+        else:
+            self.msg.unsupported_placeholder(p, context)
+            return None
+
+    #
+    # Helpers
+    #
+
+    def named_type(self, name: str) -> Instance:
+        """Return an instance type with type given by the name and no type
+        arguments. Alias for TypeChecker.named_type.
+        """
+        return self.chk.named_type(name)
+
+    def accept(self, expr: Expression, context: Type | None = None) -> Type:
+        """Type check a node. Alias for TypeChecker.accept."""
+        return self.chk.expr_checker.accept(expr, context)
+
+
+def has_type_component(typ: Type, fullname: str) -> bool:
+    """Is this a specific instance type, or a union that contains it?
+
+    We use this ad-hoc function instead of a proper visitor or subtype check
+    because some str vs bytes errors are strictly speaking not runtime errors,
+    but rather highly counter-intuitive behavior. This is similar to what is used for
+    --strict-equality.
+    """
+    typ = get_proper_type(typ)
+    if isinstance(typ, Instance):
+        return typ.type.has_base(fullname)
+    elif isinstance(typ, TypeVarType):
+        return has_type_component(typ.upper_bound, fullname) or any(
+            has_type_component(v, fullname) for v in typ.values
+        )
+    elif isinstance(typ, UnionType):
+        return any(has_type_component(t, fullname) for t in typ.relevant_items())
+    return False

二進制
venv/lib/python3.11/site-packages/mypy/config_parser.cpython-311-x86_64-linux-gnu.so


+ 620 - 0
venv/lib/python3.11/site-packages/mypy/config_parser.py

@@ -0,0 +1,620 @@
+from __future__ import annotations
+
+import argparse
+import configparser
+import glob as fileglob
+import os
+import re
+import sys
+from io import StringIO
+
+from mypy.errorcodes import error_codes
+
+if sys.version_info >= (3, 11):
+    import tomllib
+else:
+    import tomli as tomllib
+
+from typing import (
+    Any,
+    Callable,
+    Dict,
+    Final,
+    Iterable,
+    List,
+    Mapping,
+    MutableMapping,
+    Sequence,
+    TextIO,
+    Tuple,
+    Union,
+)
+from typing_extensions import TypeAlias as _TypeAlias
+
+from mypy import defaults
+from mypy.options import PER_MODULE_OPTIONS, Options
+
+_CONFIG_VALUE_TYPES: _TypeAlias = Union[
+    str, bool, int, float, Dict[str, str], List[str], Tuple[int, int]
+]
+_INI_PARSER_CALLABLE: _TypeAlias = Callable[[Any], _CONFIG_VALUE_TYPES]
+
+
+def parse_version(v: str | float) -> tuple[int, int]:
+    m = re.match(r"\A(\d)\.(\d+)\Z", str(v))
+    if not m:
+        raise argparse.ArgumentTypeError(f"Invalid python version '{v}' (expected format: 'x.y')")
+    major, minor = int(m.group(1)), int(m.group(2))
+    if major == 2 and minor == 7:
+        pass  # Error raised elsewhere
+    elif major == 3:
+        if minor < defaults.PYTHON3_VERSION_MIN[1]:
+            msg = "Python 3.{} is not supported (must be {}.{} or higher)".format(
+                minor, *defaults.PYTHON3_VERSION_MIN
+            )
+
+            if isinstance(v, float):
+                msg += ". You may need to put quotes around your Python version"
+
+            raise argparse.ArgumentTypeError(msg)
+    else:
+        raise argparse.ArgumentTypeError(
+            f"Python major version '{major}' out of range (must be 3)"
+        )
+    return major, minor
+
+
+def try_split(v: str | Sequence[str], split_regex: str = "[,]") -> list[str]:
+    """Split and trim a str or list of str into a list of str"""
+    if isinstance(v, str):
+        return [p.strip() for p in re.split(split_regex, v)]
+
+    return [p.strip() for p in v]
+
+
+def validate_codes(codes: list[str]) -> list[str]:
+    invalid_codes = set(codes) - set(error_codes.keys())
+    if invalid_codes:
+        raise argparse.ArgumentTypeError(
+            f"Invalid error code(s): {', '.join(sorted(invalid_codes))}"
+        )
+    return codes
+
+
+def expand_path(path: str) -> str:
+    """Expand the user home directory and any environment variables contained within
+    the provided path.
+    """
+
+    return os.path.expandvars(os.path.expanduser(path))
+
+
+def str_or_array_as_list(v: str | Sequence[str]) -> list[str]:
+    if isinstance(v, str):
+        return [v.strip()] if v.strip() else []
+    return [p.strip() for p in v if p.strip()]
+
+
+def split_and_match_files_list(paths: Sequence[str]) -> list[str]:
+    """Take a list of files/directories (with support for globbing through the glob library).
+
+    Where a path/glob matches no file, we still include the raw path in the resulting list.
+
+    Returns a list of file paths
+    """
+    expanded_paths = []
+
+    for path in paths:
+        path = expand_path(path.strip())
+        globbed_files = fileglob.glob(path, recursive=True)
+        if globbed_files:
+            expanded_paths.extend(globbed_files)
+        else:
+            expanded_paths.append(path)
+
+    return expanded_paths
+
+
+def split_and_match_files(paths: str) -> list[str]:
+    """Take a string representing a list of files/directories (with support for globbing
+    through the glob library).
+
+    Where a path/glob matches no file, we still include the raw path in the resulting list.
+
+    Returns a list of file paths
+    """
+
+    return split_and_match_files_list(paths.split(","))
+
+
+def check_follow_imports(choice: str) -> str:
+    choices = ["normal", "silent", "skip", "error"]
+    if choice not in choices:
+        raise argparse.ArgumentTypeError(
+            "invalid choice '{}' (choose from {})".format(
+                choice, ", ".join(f"'{x}'" for x in choices)
+            )
+        )
+    return choice
+
+
+def split_commas(value: str) -> list[str]:
+    # Uses a bit smarter technique to allow last trailing comma
+    # and to remove last `""` item from the split.
+    items = value.split(",")
+    if items and items[-1] == "":
+        items.pop(-1)
+    return items
+
+
+# For most options, the type of the default value set in options.py is
+# sufficient, and we don't have to do anything here.  This table
+# exists to specify types for values initialized to None or container
+# types.
+ini_config_types: Final[dict[str, _INI_PARSER_CALLABLE]] = {
+    "python_version": parse_version,
+    "custom_typing_module": str,
+    "custom_typeshed_dir": expand_path,
+    "mypy_path": lambda s: [expand_path(p.strip()) for p in re.split("[,:]", s)],
+    "files": split_and_match_files,
+    "quickstart_file": expand_path,
+    "junit_xml": expand_path,
+    "follow_imports": check_follow_imports,
+    "no_site_packages": bool,
+    "plugins": lambda s: [p.strip() for p in split_commas(s)],
+    "always_true": lambda s: [p.strip() for p in split_commas(s)],
+    "always_false": lambda s: [p.strip() for p in split_commas(s)],
+    "enable_incomplete_feature": lambda s: [p.strip() for p in split_commas(s)],
+    "disable_error_code": lambda s: validate_codes([p.strip() for p in split_commas(s)]),
+    "enable_error_code": lambda s: validate_codes([p.strip() for p in split_commas(s)]),
+    "package_root": lambda s: [p.strip() for p in split_commas(s)],
+    "cache_dir": expand_path,
+    "python_executable": expand_path,
+    "strict": bool,
+    "exclude": lambda s: [s.strip()],
+    "packages": try_split,
+    "modules": try_split,
+}
+
+# Reuse the ini_config_types and overwrite the diff
+toml_config_types: Final[dict[str, _INI_PARSER_CALLABLE]] = ini_config_types.copy()
+toml_config_types.update(
+    {
+        "python_version": parse_version,
+        "mypy_path": lambda s: [expand_path(p) for p in try_split(s, "[,:]")],
+        "files": lambda s: split_and_match_files_list(try_split(s)),
+        "follow_imports": lambda s: check_follow_imports(str(s)),
+        "plugins": try_split,
+        "always_true": try_split,
+        "always_false": try_split,
+        "enable_incomplete_feature": try_split,
+        "disable_error_code": lambda s: validate_codes(try_split(s)),
+        "enable_error_code": lambda s: validate_codes(try_split(s)),
+        "package_root": try_split,
+        "exclude": str_or_array_as_list,
+        "packages": try_split,
+        "modules": try_split,
+    }
+)
+
+
+def parse_config_file(
+    options: Options,
+    set_strict_flags: Callable[[], None],
+    filename: str | None,
+    stdout: TextIO | None = None,
+    stderr: TextIO | None = None,
+) -> None:
+    """Parse a config file into an Options object.
+
+    Errors are written to stderr but are not fatal.
+
+    If filename is None, fall back to default config files.
+    """
+    stdout = stdout or sys.stdout
+    stderr = stderr or sys.stderr
+
+    if filename is not None:
+        config_files: tuple[str, ...] = (filename,)
+    else:
+        config_files_iter: Iterable[str] = map(os.path.expanduser, defaults.CONFIG_FILES)
+        config_files = tuple(config_files_iter)
+
+    config_parser = configparser.RawConfigParser()
+
+    for config_file in config_files:
+        if not os.path.exists(config_file):
+            continue
+        try:
+            if is_toml(config_file):
+                with open(config_file, "rb") as f:
+                    toml_data = tomllib.load(f)
+                # Filter down to just mypy relevant toml keys
+                toml_data = toml_data.get("tool", {})
+                if "mypy" not in toml_data:
+                    continue
+                toml_data = {"mypy": toml_data["mypy"]}
+                parser: MutableMapping[str, Any] = destructure_overrides(toml_data)
+                config_types = toml_config_types
+            else:
+                config_parser.read(config_file)
+                parser = config_parser
+                config_types = ini_config_types
+        except (tomllib.TOMLDecodeError, configparser.Error, ConfigTOMLValueError) as err:
+            print(f"{config_file}: {err}", file=stderr)
+        else:
+            if config_file in defaults.SHARED_CONFIG_FILES and "mypy" not in parser:
+                continue
+            file_read = config_file
+            options.config_file = file_read
+            break
+    else:
+        return
+
+    os.environ["MYPY_CONFIG_FILE_DIR"] = os.path.dirname(os.path.abspath(config_file))
+
+    if "mypy" not in parser:
+        if filename or file_read not in defaults.SHARED_CONFIG_FILES:
+            print(f"{file_read}: No [mypy] section in config file", file=stderr)
+    else:
+        section = parser["mypy"]
+        prefix = f"{file_read}: [mypy]: "
+        updates, report_dirs = parse_section(
+            prefix, options, set_strict_flags, section, config_types, stderr
+        )
+        for k, v in updates.items():
+            setattr(options, k, v)
+        options.report_dirs.update(report_dirs)
+
+    for name, section in parser.items():
+        if name.startswith("mypy-"):
+            prefix = get_prefix(file_read, name)
+            updates, report_dirs = parse_section(
+                prefix, options, set_strict_flags, section, config_types, stderr
+            )
+            if report_dirs:
+                print(
+                    "%sPer-module sections should not specify reports (%s)"
+                    % (prefix, ", ".join(s + "_report" for s in sorted(report_dirs))),
+                    file=stderr,
+                )
+            if set(updates) - PER_MODULE_OPTIONS:
+                print(
+                    "%sPer-module sections should only specify per-module flags (%s)"
+                    % (prefix, ", ".join(sorted(set(updates) - PER_MODULE_OPTIONS))),
+                    file=stderr,
+                )
+                updates = {k: v for k, v in updates.items() if k in PER_MODULE_OPTIONS}
+
+            globs = name[5:]
+            for glob in globs.split(","):
+                # For backwards compatibility, replace (back)slashes with dots.
+                glob = glob.replace(os.sep, ".")
+                if os.altsep:
+                    glob = glob.replace(os.altsep, ".")
+
+                if any(c in glob for c in "?[]!") or any(
+                    "*" in x and x != "*" for x in glob.split(".")
+                ):
+                    print(
+                        "%sPatterns must be fully-qualified module names, optionally "
+                        "with '*' in some components (e.g spam.*.eggs.*)" % prefix,
+                        file=stderr,
+                    )
+                else:
+                    options.per_module_options[glob] = updates
+
+
+def get_prefix(file_read: str, name: str) -> str:
+    if is_toml(file_read):
+        module_name_str = 'module = "%s"' % "-".join(name.split("-")[1:])
+    else:
+        module_name_str = name
+
+    return f"{file_read}: [{module_name_str}]: "
+
+
+def is_toml(filename: str) -> bool:
+    return filename.lower().endswith(".toml")
+
+
+def destructure_overrides(toml_data: dict[str, Any]) -> dict[str, Any]:
+    """Take the new [[tool.mypy.overrides]] section array in the pyproject.toml file,
+    and convert it back to a flatter structure that the existing config_parser can handle.
+
+    E.g. the following pyproject.toml file:
+
+        [[tool.mypy.overrides]]
+        module = [
+            "a.b",
+            "b.*"
+        ]
+        disallow_untyped_defs = true
+
+        [[tool.mypy.overrides]]
+        module = 'c'
+        disallow_untyped_defs = false
+
+    Would map to the following config dict that it would have gotten from parsing an equivalent
+    ini file:
+
+        {
+            "mypy-a.b": {
+                disallow_untyped_defs = true,
+            },
+            "mypy-b.*": {
+                disallow_untyped_defs = true,
+            },
+            "mypy-c": {
+                disallow_untyped_defs: false,
+            },
+        }
+    """
+    if "overrides" not in toml_data["mypy"]:
+        return toml_data
+
+    if not isinstance(toml_data["mypy"]["overrides"], list):
+        raise ConfigTOMLValueError(
+            "tool.mypy.overrides sections must be an array. Please make "
+            "sure you are using double brackets like so: [[tool.mypy.overrides]]"
+        )
+
+    result = toml_data.copy()
+    for override in result["mypy"]["overrides"]:
+        if "module" not in override:
+            raise ConfigTOMLValueError(
+                "toml config file contains a [[tool.mypy.overrides]] "
+                "section, but no module to override was specified."
+            )
+
+        if isinstance(override["module"], str):
+            modules = [override["module"]]
+        elif isinstance(override["module"], list):
+            modules = override["module"]
+        else:
+            raise ConfigTOMLValueError(
+                "toml config file contains a [[tool.mypy.overrides]] "
+                "section with a module value that is not a string or a list of "
+                "strings"
+            )
+
+        for module in modules:
+            module_overrides = override.copy()
+            del module_overrides["module"]
+            old_config_name = f"mypy-{module}"
+            if old_config_name not in result:
+                result[old_config_name] = module_overrides
+            else:
+                for new_key, new_value in module_overrides.items():
+                    if (
+                        new_key in result[old_config_name]
+                        and result[old_config_name][new_key] != new_value
+                    ):
+                        raise ConfigTOMLValueError(
+                            "toml config file contains "
+                            "[[tool.mypy.overrides]] sections with conflicting "
+                            "values. Module '%s' has two different values for '%s'"
+                            % (module, new_key)
+                        )
+                    result[old_config_name][new_key] = new_value
+
+    del result["mypy"]["overrides"]
+    return result
+
+
+def parse_section(
+    prefix: str,
+    template: Options,
+    set_strict_flags: Callable[[], None],
+    section: Mapping[str, Any],
+    config_types: dict[str, Any],
+    stderr: TextIO = sys.stderr,
+) -> tuple[dict[str, object], dict[str, str]]:
+    """Parse one section of a config file.
+
+    Returns a dict of option values encountered, and a dict of report directories.
+    """
+    results: dict[str, object] = {}
+    report_dirs: dict[str, str] = {}
+    for key in section:
+        invert = False
+        options_key = key
+        if key in config_types:
+            ct = config_types[key]
+        else:
+            dv = None
+            # We have to keep new_semantic_analyzer in Options
+            # for plugin compatibility but it is not a valid option anymore.
+            assert hasattr(template, "new_semantic_analyzer")
+            if key != "new_semantic_analyzer":
+                dv = getattr(template, key, None)
+            if dv is None:
+                if key.endswith("_report"):
+                    report_type = key[:-7].replace("_", "-")
+                    if report_type in defaults.REPORTER_NAMES:
+                        report_dirs[report_type] = str(section[key])
+                    else:
+                        print(f"{prefix}Unrecognized report type: {key}", file=stderr)
+                    continue
+                if key.startswith("x_"):
+                    pass  # Don't complain about `x_blah` flags
+                elif key.startswith("no_") and hasattr(template, key[3:]):
+                    options_key = key[3:]
+                    invert = True
+                elif key.startswith("allow") and hasattr(template, "dis" + key):
+                    options_key = "dis" + key
+                    invert = True
+                elif key.startswith("disallow") and hasattr(template, key[3:]):
+                    options_key = key[3:]
+                    invert = True
+                elif key.startswith("show_") and hasattr(template, "hide_" + key[5:]):
+                    options_key = "hide_" + key[5:]
+                    invert = True
+                elif key == "strict":
+                    pass  # Special handling below
+                else:
+                    print(f"{prefix}Unrecognized option: {key} = {section[key]}", file=stderr)
+                if invert:
+                    dv = getattr(template, options_key, None)
+                else:
+                    continue
+            ct = type(dv)
+        v: Any = None
+        try:
+            if ct is bool:
+                if isinstance(section, dict):
+                    v = convert_to_boolean(section.get(key))
+                else:
+                    v = section.getboolean(key)  # type: ignore[attr-defined]  # Until better stub
+                if invert:
+                    v = not v
+            elif callable(ct):
+                if invert:
+                    print(f"{prefix}Can not invert non-boolean key {options_key}", file=stderr)
+                    continue
+                try:
+                    v = ct(section.get(key))
+                except argparse.ArgumentTypeError as err:
+                    print(f"{prefix}{key}: {err}", file=stderr)
+                    continue
+            else:
+                print(f"{prefix}Don't know what type {key} should have", file=stderr)
+                continue
+        except ValueError as err:
+            print(f"{prefix}{key}: {err}", file=stderr)
+            continue
+        if key == "strict":
+            if v:
+                set_strict_flags()
+            continue
+        results[options_key] = v
+
+    # These two flags act as per-module overrides, so store the empty defaults.
+    if "disable_error_code" not in results:
+        results["disable_error_code"] = []
+    if "enable_error_code" not in results:
+        results["enable_error_code"] = []
+
+    return results, report_dirs
+
+
+def convert_to_boolean(value: Any | None) -> bool:
+    """Return a boolean value translating from other types if necessary."""
+    if isinstance(value, bool):
+        return value
+    if not isinstance(value, str):
+        value = str(value)
+    if value.lower() not in configparser.RawConfigParser.BOOLEAN_STATES:
+        raise ValueError(f"Not a boolean: {value}")
+    return configparser.RawConfigParser.BOOLEAN_STATES[value.lower()]
+
+
+def split_directive(s: str) -> tuple[list[str], list[str]]:
+    """Split s on commas, except during quoted sections.
+
+    Returns the parts and a list of error messages."""
+    parts = []
+    cur: list[str] = []
+    errors = []
+    i = 0
+    while i < len(s):
+        if s[i] == ",":
+            parts.append("".join(cur).strip())
+            cur = []
+        elif s[i] == '"':
+            i += 1
+            while i < len(s) and s[i] != '"':
+                cur.append(s[i])
+                i += 1
+            if i == len(s):
+                errors.append("Unterminated quote in configuration comment")
+                cur.clear()
+        else:
+            cur.append(s[i])
+        i += 1
+    if cur:
+        parts.append("".join(cur).strip())
+
+    return parts, errors
+
+
+def mypy_comments_to_config_map(line: str, template: Options) -> tuple[dict[str, str], list[str]]:
+    """Rewrite the mypy comment syntax into ini file syntax."""
+    options = {}
+    entries, errors = split_directive(line)
+    for entry in entries:
+        if "=" not in entry:
+            name = entry
+            value = None
+        else:
+            name, value = (x.strip() for x in entry.split("=", 1))
+
+        name = name.replace("-", "_")
+        if value is None:
+            value = "True"
+        options[name] = value
+
+    return options, errors
+
+
+def parse_mypy_comments(
+    args: list[tuple[int, str]], template: Options
+) -> tuple[dict[str, object], list[tuple[int, str]]]:
+    """Parse a collection of inline mypy: configuration comments.
+
+    Returns a dictionary of options to be applied and a list of error messages
+    generated.
+    """
+
+    errors: list[tuple[int, str]] = []
+    sections = {}
+
+    for lineno, line in args:
+        # In order to easily match the behavior for bools, we abuse configparser.
+        # Oddly, the only way to get the SectionProxy object with the getboolean
+        # method is to create a config parser.
+        parser = configparser.RawConfigParser()
+        options, parse_errors = mypy_comments_to_config_map(line, template)
+        parser["dummy"] = options
+        errors.extend((lineno, x) for x in parse_errors)
+
+        stderr = StringIO()
+        strict_found = False
+
+        def set_strict_flags() -> None:
+            nonlocal strict_found
+            strict_found = True
+
+        new_sections, reports = parse_section(
+            "", template, set_strict_flags, parser["dummy"], ini_config_types, stderr=stderr
+        )
+        errors.extend((lineno, x) for x in stderr.getvalue().strip().split("\n") if x)
+        if reports:
+            errors.append((lineno, "Reports not supported in inline configuration"))
+        if strict_found:
+            errors.append(
+                (
+                    lineno,
+                    'Setting "strict" not supported in inline configuration: specify it in '
+                    "a configuration file instead, or set individual inline flags "
+                    '(see "mypy -h" for the list of flags enabled in strict mode)',
+                )
+            )
+
+        sections.update(new_sections)
+
+    return sections, errors
+
+
+def get_config_module_names(filename: str | None, modules: list[str]) -> str:
+    if not filename or not modules:
+        return ""
+
+    if not is_toml(filename):
+        return ", ".join(f"[mypy-{module}]" for module in modules)
+
+    return "module = ['%s']" % ("', '".join(sorted(modules)))
+
+
+class ConfigTOMLValueError(ValueError):
+    pass

二進制
venv/lib/python3.11/site-packages/mypy/constant_fold.cpython-311-x86_64-linux-gnu.so


+ 187 - 0
venv/lib/python3.11/site-packages/mypy/constant_fold.py

@@ -0,0 +1,187 @@
+"""Constant folding of expressions.
+
+For example, 3 + 5 can be constant folded into 8.
+"""
+
+from __future__ import annotations
+
+from typing import Final, Union
+
+from mypy.nodes import (
+    ComplexExpr,
+    Expression,
+    FloatExpr,
+    IntExpr,
+    NameExpr,
+    OpExpr,
+    StrExpr,
+    UnaryExpr,
+    Var,
+)
+
+# All possible result types of constant folding
+ConstantValue = Union[int, bool, float, complex, str]
+CONST_TYPES: Final = (int, bool, float, complex, str)
+
+
+def constant_fold_expr(expr: Expression, cur_mod_id: str) -> ConstantValue | None:
+    """Return the constant value of an expression for supported operations.
+
+    Among other things, support int arithmetic and string
+    concatenation. For example, the expression 3 + 5 has the constant
+    value 8.
+
+    Also bind simple references to final constants defined in the
+    current module (cur_mod_id). Binding to references is best effort
+    -- we don't bind references to other modules. Mypyc trusts these
+    to be correct in compiled modules, so that it can replace a
+    constant expression (or a reference to one) with the statically
+    computed value. We don't want to infer constant values based on
+    stubs, in particular, as these might not match the implementation
+    (due to version skew, for example).
+
+    Return None if unsuccessful.
+    """
+    if isinstance(expr, IntExpr):
+        return expr.value
+    if isinstance(expr, StrExpr):
+        return expr.value
+    if isinstance(expr, FloatExpr):
+        return expr.value
+    if isinstance(expr, ComplexExpr):
+        return expr.value
+    elif isinstance(expr, NameExpr):
+        if expr.name == "True":
+            return True
+        elif expr.name == "False":
+            return False
+        node = expr.node
+        if (
+            isinstance(node, Var)
+            and node.is_final
+            and node.fullname.rsplit(".", 1)[0] == cur_mod_id
+        ):
+            value = node.final_value
+            if isinstance(value, (CONST_TYPES)):
+                return value
+    elif isinstance(expr, OpExpr):
+        left = constant_fold_expr(expr.left, cur_mod_id)
+        right = constant_fold_expr(expr.right, cur_mod_id)
+        if left is not None and right is not None:
+            return constant_fold_binary_op(expr.op, left, right)
+    elif isinstance(expr, UnaryExpr):
+        value = constant_fold_expr(expr.expr, cur_mod_id)
+        if value is not None:
+            return constant_fold_unary_op(expr.op, value)
+    return None
+
+
+def constant_fold_binary_op(
+    op: str, left: ConstantValue, right: ConstantValue
+) -> ConstantValue | None:
+    if isinstance(left, int) and isinstance(right, int):
+        return constant_fold_binary_int_op(op, left, right)
+
+    # Float and mixed int/float arithmetic.
+    if isinstance(left, float) and isinstance(right, float):
+        return constant_fold_binary_float_op(op, left, right)
+    elif isinstance(left, float) and isinstance(right, int):
+        return constant_fold_binary_float_op(op, left, right)
+    elif isinstance(left, int) and isinstance(right, float):
+        return constant_fold_binary_float_op(op, left, right)
+
+    # String concatenation and multiplication.
+    if op == "+" and isinstance(left, str) and isinstance(right, str):
+        return left + right
+    elif op == "*" and isinstance(left, str) and isinstance(right, int):
+        return left * right
+    elif op == "*" and isinstance(left, int) and isinstance(right, str):
+        return left * right
+
+    # Complex construction.
+    if op == "+" and isinstance(left, (int, float)) and isinstance(right, complex):
+        return left + right
+    elif op == "+" and isinstance(left, complex) and isinstance(right, (int, float)):
+        return left + right
+    elif op == "-" and isinstance(left, (int, float)) and isinstance(right, complex):
+        return left - right
+    elif op == "-" and isinstance(left, complex) and isinstance(right, (int, float)):
+        return left - right
+
+    return None
+
+
+def constant_fold_binary_int_op(op: str, left: int, right: int) -> int | float | None:
+    if op == "+":
+        return left + right
+    if op == "-":
+        return left - right
+    elif op == "*":
+        return left * right
+    elif op == "/":
+        if right != 0:
+            return left / right
+    elif op == "//":
+        if right != 0:
+            return left // right
+    elif op == "%":
+        if right != 0:
+            return left % right
+    elif op == "&":
+        return left & right
+    elif op == "|":
+        return left | right
+    elif op == "^":
+        return left ^ right
+    elif op == "<<":
+        if right >= 0:
+            return left << right
+    elif op == ">>":
+        if right >= 0:
+            return left >> right
+    elif op == "**":
+        if right >= 0:
+            ret = left**right
+            assert isinstance(ret, int)
+            return ret
+    return None
+
+
+def constant_fold_binary_float_op(op: str, left: int | float, right: int | float) -> float | None:
+    assert not (isinstance(left, int) and isinstance(right, int)), (op, left, right)
+    if op == "+":
+        return left + right
+    elif op == "-":
+        return left - right
+    elif op == "*":
+        return left * right
+    elif op == "/":
+        if right != 0:
+            return left / right
+    elif op == "//":
+        if right != 0:
+            return left // right
+    elif op == "%":
+        if right != 0:
+            return left % right
+    elif op == "**":
+        if (left < 0 and isinstance(right, int)) or left > 0:
+            try:
+                ret = left**right
+            except OverflowError:
+                return None
+            else:
+                assert isinstance(ret, float), ret
+                return ret
+
+    return None
+
+
+def constant_fold_unary_op(op: str, value: ConstantValue) -> int | float | None:
+    if op == "-" and isinstance(value, (int, float)):
+        return -value
+    elif op == "~" and isinstance(value, int):
+        return ~value
+    elif op == "+" and isinstance(value, (int, float)):
+        return value
+    return None

二進制
venv/lib/python3.11/site-packages/mypy/constraints.cpython-311-x86_64-linux-gnu.so


+ 1262 - 0
venv/lib/python3.11/site-packages/mypy/constraints.py

@@ -0,0 +1,1262 @@
+"""Type inference constraints."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Final, Iterable, List, Sequence, cast
+
+import mypy.subtypes
+import mypy.typeops
+from mypy.argmap import ArgTypeExpander
+from mypy.erasetype import erase_typevars
+from mypy.maptype import map_instance_to_supertype
+from mypy.nodes import ARG_OPT, ARG_POS, CONTRAVARIANT, COVARIANT, ArgKind
+from mypy.types import (
+    TUPLE_LIKE_INSTANCE_NAMES,
+    AnyType,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    Parameters,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeOfAny,
+    TypeQuery,
+    TypeType,
+    TypeVarId,
+    TypeVarLikeType,
+    TypeVarTupleType,
+    TypeVarType,
+    TypeVisitor,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+    callable_with_ellipsis,
+    get_proper_type,
+    has_recursive_types,
+    has_type_vars,
+    is_named_instance,
+    split_with_prefix_and_suffix,
+)
+from mypy.types_utils import is_union_with_any
+from mypy.typestate import type_state
+from mypy.typevartuples import extract_unpack, find_unpack_in_list, split_with_mapped_and_template
+
+if TYPE_CHECKING:
+    from mypy.infer import ArgumentInferContext
+
+SUBTYPE_OF: Final = 0
+SUPERTYPE_OF: Final = 1
+
+
+class Constraint:
+    """A representation of a type constraint.
+
+    It can be either T <: type or T :> type (T is a type variable).
+    """
+
+    type_var: TypeVarId
+    op = 0  # SUBTYPE_OF or SUPERTYPE_OF
+    target: Type
+
+    def __init__(self, type_var: TypeVarLikeType, op: int, target: Type) -> None:
+        self.type_var = type_var.id
+        self.op = op
+        self.target = target
+        self.origin_type_var = type_var
+
+    def __repr__(self) -> str:
+        op_str = "<:"
+        if self.op == SUPERTYPE_OF:
+            op_str = ":>"
+        return f"{self.type_var} {op_str} {self.target}"
+
+    def __hash__(self) -> int:
+        return hash((self.type_var, self.op, self.target))
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Constraint):
+            return False
+        return (self.type_var, self.op, self.target) == (other.type_var, other.op, other.target)
+
+
+def infer_constraints_for_callable(
+    callee: CallableType,
+    arg_types: Sequence[Type | None],
+    arg_kinds: list[ArgKind],
+    formal_to_actual: list[list[int]],
+    context: ArgumentInferContext,
+) -> list[Constraint]:
+    """Infer type variable constraints for a callable and actual arguments.
+
+    Return a list of constraints.
+    """
+    constraints: list[Constraint] = []
+    mapper = ArgTypeExpander(context)
+
+    for i, actuals in enumerate(formal_to_actual):
+        if isinstance(callee.arg_types[i], UnpackType):
+            unpack_type = callee.arg_types[i]
+            assert isinstance(unpack_type, UnpackType)
+
+            # In this case we are binding all of the actuals to *args
+            # and we want a constraint that the typevar tuple being unpacked
+            # is equal to a type list of all the actuals.
+            actual_types = []
+            for actual in actuals:
+                actual_arg_type = arg_types[actual]
+                if actual_arg_type is None:
+                    continue
+
+                actual_types.append(
+                    mapper.expand_actual_type(
+                        actual_arg_type,
+                        arg_kinds[actual],
+                        callee.arg_names[i],
+                        callee.arg_kinds[i],
+                    )
+                )
+
+            unpacked_type = get_proper_type(unpack_type.type)
+            if isinstance(unpacked_type, TypeVarTupleType):
+                constraints.append(
+                    Constraint(
+                        unpacked_type,
+                        SUPERTYPE_OF,
+                        TupleType(actual_types, unpacked_type.tuple_fallback),
+                    )
+                )
+            elif isinstance(unpacked_type, TupleType):
+                # Prefixes get converted to positional args, so technically the only case we
+                # should have here is like Tuple[Unpack[Ts], Y1, Y2, Y3]. If this turns out
+                # not to hold we can always handle the prefixes too.
+                inner_unpack = unpacked_type.items[0]
+                assert isinstance(inner_unpack, UnpackType)
+                inner_unpacked_type = inner_unpack.type
+                assert isinstance(inner_unpacked_type, TypeVarTupleType)
+                suffix_len = len(unpacked_type.items) - 1
+                constraints.append(
+                    Constraint(
+                        inner_unpacked_type,
+                        SUPERTYPE_OF,
+                        TupleType(actual_types[:-suffix_len], inner_unpacked_type.tuple_fallback),
+                    )
+                )
+            else:
+                assert False, "mypy bug: unhandled constraint inference case"
+        else:
+            for actual in actuals:
+                actual_arg_type = arg_types[actual]
+                if actual_arg_type is None:
+                    continue
+
+                actual_type = mapper.expand_actual_type(
+                    actual_arg_type, arg_kinds[actual], callee.arg_names[i], callee.arg_kinds[i]
+                )
+                c = infer_constraints(callee.arg_types[i], actual_type, SUPERTYPE_OF)
+                constraints.extend(c)
+
+    return constraints
+
+
+def infer_constraints(template: Type, actual: Type, direction: int) -> list[Constraint]:
+    """Infer type constraints.
+
+    Match a template type, which may contain type variable references,
+    recursively against a type which does not contain (the same) type
+    variable references. The result is a list of type constrains of
+    form 'T is a supertype/subtype of x', where T is a type variable
+    present in the template and x is a type without reference to type
+    variables present in the template.
+
+    Assume T and S are type variables. Now the following results can be
+    calculated (read as '(template, actual) --> result'):
+
+      (T, X)            -->  T :> X
+      (X[T], X[Y])      -->  T <: Y and T :> Y
+      ((T, T), (X, Y))  -->  T :> X and T :> Y
+      ((T, S), (X, Y))  -->  T :> X and S :> Y
+      (X[T], Any)       -->  T <: Any and T :> Any
+
+    The constraints are represented as Constraint objects.
+    """
+    if any(
+        get_proper_type(template) == get_proper_type(t)
+        and get_proper_type(actual) == get_proper_type(a)
+        for (t, a) in reversed(type_state.inferring)
+    ):
+        return []
+    if has_recursive_types(template) or isinstance(get_proper_type(template), Instance):
+        # This case requires special care because it may cause infinite recursion.
+        # Note that we include Instances because the may be recursive as str(Sequence[str]).
+        if not has_type_vars(template):
+            # Return early on an empty branch.
+            return []
+        type_state.inferring.append((template, actual))
+        res = _infer_constraints(template, actual, direction)
+        type_state.inferring.pop()
+        return res
+    return _infer_constraints(template, actual, direction)
+
+
+def _infer_constraints(template: Type, actual: Type, direction: int) -> list[Constraint]:
+    orig_template = template
+    template = get_proper_type(template)
+    actual = get_proper_type(actual)
+
+    # Type inference shouldn't be affected by whether union types have been simplified.
+    # We however keep any ErasedType items, so that the caller will see it when using
+    # checkexpr.has_erased_component().
+    if isinstance(template, UnionType):
+        template = mypy.typeops.make_simplified_union(template.items, keep_erased=True)
+    if isinstance(actual, UnionType):
+        actual = mypy.typeops.make_simplified_union(actual.items, keep_erased=True)
+
+    # Ignore Any types from the type suggestion engine to avoid them
+    # causing us to infer Any in situations where a better job could
+    # be done otherwise. (This can produce false positives but that
+    # doesn't really matter because it is all heuristic anyway.)
+    if isinstance(actual, AnyType) and actual.type_of_any == TypeOfAny.suggestion_engine:
+        return []
+
+    # If the template is simply a type variable, emit a Constraint directly.
+    # We need to handle this case before handling Unions for two reasons:
+    #  1. "T <: Union[U1, U2]" is not equivalent to "T <: U1 or T <: U2",
+    #     because T can itself be a union (notably, Union[U1, U2] itself).
+    #  2. "T :> Union[U1, U2]" is logically equivalent to "T :> U1 and
+    #     T :> U2", but they are not equivalent to the constraint solver,
+    #     which never introduces new Union types (it uses join() instead).
+    if isinstance(template, TypeVarType):
+        return [Constraint(template, direction, actual)]
+
+    # Now handle the case of either template or actual being a Union.
+    # For a Union to be a subtype of another type, every item of the Union
+    # must be a subtype of that type, so concatenate the constraints.
+    if direction == SUBTYPE_OF and isinstance(template, UnionType):
+        res = []
+        for t_item in template.items:
+            res.extend(infer_constraints(t_item, actual, direction))
+        return res
+    if direction == SUPERTYPE_OF and isinstance(actual, UnionType):
+        res = []
+        for a_item in actual.items:
+            res.extend(infer_constraints(orig_template, a_item, direction))
+        return res
+
+    # Now the potential subtype is known not to be a Union or a type
+    # variable that we are solving for. In that case, for a Union to
+    # be a supertype of the potential subtype, some item of the Union
+    # must be a supertype of it.
+    if direction == SUBTYPE_OF and isinstance(actual, UnionType):
+        # If some of items is not a complete type, disregard that.
+        items = simplify_away_incomplete_types(actual.items)
+        # We infer constraints eagerly -- try to find constraints for a type
+        # variable if possible. This seems to help with some real-world
+        # use cases.
+        return any_constraints(
+            [infer_constraints_if_possible(template, a_item, direction) for a_item in items],
+            eager=True,
+        )
+    if direction == SUPERTYPE_OF and isinstance(template, UnionType):
+        # When the template is a union, we are okay with leaving some
+        # type variables indeterminate. This helps with some special
+        # cases, though this isn't very principled.
+        result = any_constraints(
+            [
+                infer_constraints_if_possible(t_item, actual, direction)
+                for t_item in template.items
+            ],
+            eager=False,
+        )
+        if result:
+            return result
+        elif has_recursive_types(template) and not has_recursive_types(actual):
+            return handle_recursive_union(template, actual, direction)
+        return []
+
+    # Remaining cases are handled by ConstraintBuilderVisitor.
+    return template.accept(ConstraintBuilderVisitor(actual, direction))
+
+
+def infer_constraints_if_possible(
+    template: Type, actual: Type, direction: int
+) -> list[Constraint] | None:
+    """Like infer_constraints, but return None if the input relation is
+    known to be unsatisfiable, for example if template=List[T] and actual=int.
+    (In this case infer_constraints would return [], just like it would for
+    an automatically satisfied relation like template=List[T] and actual=object.)
+    """
+    if direction == SUBTYPE_OF and not mypy.subtypes.is_subtype(erase_typevars(template), actual):
+        return None
+    if direction == SUPERTYPE_OF and not mypy.subtypes.is_subtype(
+        actual, erase_typevars(template)
+    ):
+        return None
+    if (
+        direction == SUPERTYPE_OF
+        and isinstance(template, TypeVarType)
+        and not mypy.subtypes.is_subtype(actual, erase_typevars(template.upper_bound))
+    ):
+        # This is not caught by the above branch because of the erase_typevars() call,
+        # that would return 'Any' for a type variable.
+        return None
+    return infer_constraints(template, actual, direction)
+
+
+def select_trivial(options: Sequence[list[Constraint] | None]) -> list[list[Constraint]]:
+    """Select only those lists where each item is a constraint against Any."""
+    res = []
+    for option in options:
+        if option is None:
+            continue
+        if all(isinstance(get_proper_type(c.target), AnyType) for c in option):
+            res.append(option)
+    return res
+
+
+def merge_with_any(constraint: Constraint) -> Constraint:
+    """Transform a constraint target into a union with given Any type."""
+    target = constraint.target
+    if is_union_with_any(target):
+        # Do not produce redundant unions.
+        return constraint
+    # TODO: if we will support multiple sources Any, use this here instead.
+    any_type = AnyType(TypeOfAny.implementation_artifact)
+    return Constraint(
+        constraint.origin_type_var,
+        constraint.op,
+        UnionType.make_union([target, any_type], target.line, target.column),
+    )
+
+
+def handle_recursive_union(template: UnionType, actual: Type, direction: int) -> list[Constraint]:
+    # This is a hack to special-case things like Union[T, Inst[T]] in recursive types. Although
+    # it is quite arbitrary, it is a relatively common pattern, so we should handle it well.
+    # This function may be called when inferring against such union resulted in different
+    # constraints for each item. Normally we give up in such case, but here we instead split
+    # the union in two parts, and try inferring sequentially.
+    non_type_var_items = [t for t in template.items if not isinstance(t, TypeVarType)]
+    type_var_items = [t for t in template.items if isinstance(t, TypeVarType)]
+    return infer_constraints(
+        UnionType.make_union(non_type_var_items), actual, direction
+    ) or infer_constraints(UnionType.make_union(type_var_items), actual, direction)
+
+
+def any_constraints(options: list[list[Constraint] | None], eager: bool) -> list[Constraint]:
+    """Deduce what we can from a collection of constraint lists.
+
+    It's a given that at least one of the lists must be satisfied. A
+    None element in the list of options represents an unsatisfiable
+    constraint and is ignored.  Ignore empty constraint lists if eager
+    is true -- they are always trivially satisfiable.
+    """
+    if eager:
+        valid_options = [option for option in options if option]
+    else:
+        valid_options = [option for option in options if option is not None]
+
+    if not valid_options:
+        return []
+
+    if len(valid_options) == 1:
+        return valid_options[0]
+
+    if all(is_same_constraints(valid_options[0], c) for c in valid_options[1:]):
+        # Multiple sets of constraints that are all the same. Just pick any one of them.
+        return valid_options[0]
+
+    if all(is_similar_constraints(valid_options[0], c) for c in valid_options[1:]):
+        # All options have same structure. In this case we can merge-in trivial
+        # options (i.e. those that only have Any) and try again.
+        # TODO: More generally, if a given (variable, direction) pair appears in
+        # every option, combine the bounds with meet/join always, not just for Any.
+        trivial_options = select_trivial(valid_options)
+        if trivial_options and len(trivial_options) < len(valid_options):
+            merged_options = []
+            for option in valid_options:
+                if option in trivial_options:
+                    continue
+                if option is not None:
+                    merged_option: list[Constraint] | None = [merge_with_any(c) for c in option]
+                else:
+                    merged_option = None
+                merged_options.append(merged_option)
+            return any_constraints(list(merged_options), eager)
+
+    # If normal logic didn't work, try excluding trivially unsatisfiable constraint (due to
+    # upper bounds) from each option, and comparing them again.
+    filtered_options = [filter_satisfiable(o) for o in options]
+    if filtered_options != options:
+        return any_constraints(filtered_options, eager=eager)
+
+    # Otherwise, there are either no valid options or multiple, inconsistent valid
+    # options. Give up and deduce nothing.
+    return []
+
+
+def filter_satisfiable(option: list[Constraint] | None) -> list[Constraint] | None:
+    """Keep only constraints that can possibly be satisfied.
+
+    Currently, we filter out constraints where target is not a subtype of the upper bound.
+    Since those can be never satisfied. We may add more cases in future if it improves type
+    inference.
+    """
+    if not option:
+        return option
+    satisfiable = []
+    for c in option:
+        if isinstance(c.origin_type_var, TypeVarType) and c.origin_type_var.values:
+            if any(
+                mypy.subtypes.is_subtype(c.target, value) for value in c.origin_type_var.values
+            ):
+                satisfiable.append(c)
+        elif mypy.subtypes.is_subtype(c.target, c.origin_type_var.upper_bound):
+            satisfiable.append(c)
+    if not satisfiable:
+        return None
+    return satisfiable
+
+
+def is_same_constraints(x: list[Constraint], y: list[Constraint]) -> bool:
+    for c1 in x:
+        if not any(is_same_constraint(c1, c2) for c2 in y):
+            return False
+    for c1 in y:
+        if not any(is_same_constraint(c1, c2) for c2 in x):
+            return False
+    return True
+
+
+def is_same_constraint(c1: Constraint, c2: Constraint) -> bool:
+    # Ignore direction when comparing constraints against Any.
+    skip_op_check = isinstance(get_proper_type(c1.target), AnyType) and isinstance(
+        get_proper_type(c2.target), AnyType
+    )
+    return (
+        c1.type_var == c2.type_var
+        and (c1.op == c2.op or skip_op_check)
+        and mypy.subtypes.is_same_type(c1.target, c2.target)
+    )
+
+
+def is_similar_constraints(x: list[Constraint], y: list[Constraint]) -> bool:
+    """Check that two lists of constraints have similar structure.
+
+    This means that each list has same type variable plus direction pairs (i.e we
+    ignore the target). Except for constraints where target is Any type, there
+    we ignore direction as well.
+    """
+    return _is_similar_constraints(x, y) and _is_similar_constraints(y, x)
+
+
+def _is_similar_constraints(x: list[Constraint], y: list[Constraint]) -> bool:
+    """Check that every constraint in the first list has a similar one in the second.
+
+    See docstring above for definition of similarity.
+    """
+    for c1 in x:
+        has_similar = False
+        for c2 in y:
+            # Ignore direction when either constraint is against Any.
+            skip_op_check = isinstance(get_proper_type(c1.target), AnyType) or isinstance(
+                get_proper_type(c2.target), AnyType
+            )
+            if c1.type_var == c2.type_var and (c1.op == c2.op or skip_op_check):
+                has_similar = True
+                break
+        if not has_similar:
+            return False
+    return True
+
+
+def simplify_away_incomplete_types(types: Iterable[Type]) -> list[Type]:
+    complete = [typ for typ in types if is_complete_type(typ)]
+    if complete:
+        return complete
+    else:
+        return list(types)
+
+
+def is_complete_type(typ: Type) -> bool:
+    """Is a type complete?
+
+    A complete doesn't have uninhabited type components or (when not in strict
+    optional mode) None components.
+    """
+    return typ.accept(CompleteTypeVisitor())
+
+
+class CompleteTypeVisitor(TypeQuery[bool]):
+    def __init__(self) -> None:
+        super().__init__(all)
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
+        return False
+
+
+class ConstraintBuilderVisitor(TypeVisitor[List[Constraint]]):
+    """Visitor class for inferring type constraints."""
+
+    # The type that is compared against a template
+    # TODO: The value may be None. Is that actually correct?
+    actual: ProperType
+
+    def __init__(self, actual: ProperType, direction: int) -> None:
+        # Direction must be SUBTYPE_OF or SUPERTYPE_OF.
+        self.actual = actual
+        self.direction = direction
+
+    # Trivial leaf types
+
+    def visit_unbound_type(self, template: UnboundType) -> list[Constraint]:
+        return []
+
+    def visit_any(self, template: AnyType) -> list[Constraint]:
+        return []
+
+    def visit_none_type(self, template: NoneType) -> list[Constraint]:
+        return []
+
+    def visit_uninhabited_type(self, template: UninhabitedType) -> list[Constraint]:
+        return []
+
+    def visit_erased_type(self, template: ErasedType) -> list[Constraint]:
+        return []
+
+    def visit_deleted_type(self, template: DeletedType) -> list[Constraint]:
+        return []
+
+    def visit_literal_type(self, template: LiteralType) -> list[Constraint]:
+        return []
+
+    # Errors
+
+    def visit_partial_type(self, template: PartialType) -> list[Constraint]:
+        # We can't do anything useful with a partial type here.
+        assert False, "Internal error"
+
+    # Non-trivial leaf type
+
+    def visit_type_var(self, template: TypeVarType) -> list[Constraint]:
+        assert False, (
+            "Unexpected TypeVarType in ConstraintBuilderVisitor"
+            " (should have been handled in infer_constraints)"
+        )
+
+    def visit_param_spec(self, template: ParamSpecType) -> list[Constraint]:
+        # Can't infer ParamSpecs from component values (only via Callable[P, T]).
+        return []
+
+    def visit_type_var_tuple(self, template: TypeVarTupleType) -> list[Constraint]:
+        raise NotImplementedError
+
+    def visit_unpack_type(self, template: UnpackType) -> list[Constraint]:
+        raise RuntimeError("Mypy bug: unpack should be handled at a higher level.")
+
+    def visit_parameters(self, template: Parameters) -> list[Constraint]:
+        # constraining Any against C[P] turns into infer_against_any([P], Any)
+        # ... which seems like the only case this can happen. Better to fail loudly.
+        if isinstance(self.actual, AnyType):
+            return self.infer_against_any(template.arg_types, self.actual)
+        raise RuntimeError("Parameters cannot be constrained to")
+
+    # Non-leaf types
+
+    def visit_instance(self, template: Instance) -> list[Constraint]:
+        original_actual = actual = self.actual
+        res: list[Constraint] = []
+        if isinstance(actual, (CallableType, Overloaded)) and template.type.is_protocol:
+            if "__call__" in template.type.protocol_members:
+                # Special case: a generic callback protocol
+                if not any(template == t for t in template.type.inferring):
+                    template.type.inferring.append(template)
+                    call = mypy.subtypes.find_member(
+                        "__call__", template, actual, is_operator=True
+                    )
+                    assert call is not None
+                    if mypy.subtypes.is_subtype(actual, erase_typevars(call)):
+                        subres = infer_constraints(call, actual, self.direction)
+                        res.extend(subres)
+                    template.type.inferring.pop()
+        if isinstance(actual, CallableType) and actual.fallback is not None:
+            if actual.is_type_obj() and template.type.is_protocol:
+                ret_type = get_proper_type(actual.ret_type)
+                if isinstance(ret_type, TupleType):
+                    ret_type = mypy.typeops.tuple_fallback(ret_type)
+                if isinstance(ret_type, Instance):
+                    if self.direction == SUBTYPE_OF:
+                        subtype = template
+                    else:
+                        subtype = ret_type
+                    res.extend(
+                        self.infer_constraints_from_protocol_members(
+                            ret_type, template, subtype, template, class_obj=True
+                        )
+                    )
+            actual = actual.fallback
+        if isinstance(actual, TypeType) and template.type.is_protocol:
+            if isinstance(actual.item, Instance):
+                if self.direction == SUBTYPE_OF:
+                    subtype = template
+                else:
+                    subtype = actual.item
+                res.extend(
+                    self.infer_constraints_from_protocol_members(
+                        actual.item, template, subtype, template, class_obj=True
+                    )
+                )
+            if self.direction == SUPERTYPE_OF:
+                # Infer constraints for Type[T] via metaclass of T when it makes sense.
+                a_item = actual.item
+                if isinstance(a_item, TypeVarType):
+                    a_item = get_proper_type(a_item.upper_bound)
+                if isinstance(a_item, Instance) and a_item.type.metaclass_type:
+                    res.extend(
+                        self.infer_constraints_from_protocol_members(
+                            a_item.type.metaclass_type, template, actual, template
+                        )
+                    )
+
+        if isinstance(actual, Overloaded) and actual.fallback is not None:
+            actual = actual.fallback
+        if isinstance(actual, TypedDictType):
+            actual = actual.as_anonymous().fallback
+        if isinstance(actual, LiteralType):
+            actual = actual.fallback
+        if isinstance(actual, Instance):
+            instance = actual
+            erased = erase_typevars(template)
+            assert isinstance(erased, Instance)  # type: ignore[misc]
+            # We always try nominal inference if possible,
+            # it is much faster than the structural one.
+            if self.direction == SUBTYPE_OF and template.type.has_base(instance.type.fullname):
+                mapped = map_instance_to_supertype(template, instance.type)
+                tvars = mapped.type.defn.type_vars
+
+                if instance.type.has_type_var_tuple_type:
+                    assert instance.type.type_var_tuple_prefix is not None
+                    assert instance.type.type_var_tuple_suffix is not None
+                    assert mapped.type.type_var_tuple_prefix is not None
+                    assert mapped.type.type_var_tuple_suffix is not None
+
+                    unpack_constraints, mapped_args, instance_args = build_constraints_for_unpack(
+                        mapped.args,
+                        mapped.type.type_var_tuple_prefix,
+                        mapped.type.type_var_tuple_suffix,
+                        instance.args,
+                        instance.type.type_var_tuple_prefix,
+                        instance.type.type_var_tuple_suffix,
+                        self.direction,
+                    )
+                    res.extend(unpack_constraints)
+
+                    tvars_prefix, _, tvars_suffix = split_with_prefix_and_suffix(
+                        tuple(tvars),
+                        instance.type.type_var_tuple_prefix,
+                        instance.type.type_var_tuple_suffix,
+                    )
+                    tvars = cast("list[TypeVarLikeType]", list(tvars_prefix + tvars_suffix))
+                else:
+                    mapped_args = mapped.args
+                    instance_args = instance.args
+
+                # N.B: We use zip instead of indexing because the lengths might have
+                # mismatches during daemon reprocessing.
+                for tvar, mapped_arg, instance_arg in zip(tvars, mapped_args, instance_args):
+                    # TODO(PEP612): More ParamSpec work (or is Parameters the only thing accepted)
+                    if isinstance(tvar, TypeVarType):
+                        # The constraints for generic type parameters depend on variance.
+                        # Include constraints from both directions if invariant.
+                        if tvar.variance != CONTRAVARIANT:
+                            res.extend(infer_constraints(mapped_arg, instance_arg, self.direction))
+                        if tvar.variance != COVARIANT:
+                            res.extend(
+                                infer_constraints(mapped_arg, instance_arg, neg_op(self.direction))
+                            )
+                    elif isinstance(tvar, ParamSpecType) and isinstance(mapped_arg, ParamSpecType):
+                        suffix = get_proper_type(instance_arg)
+
+                        if isinstance(suffix, CallableType):
+                            prefix = mapped_arg.prefix
+                            from_concat = bool(prefix.arg_types) or suffix.from_concatenate
+                            suffix = suffix.copy_modified(from_concatenate=from_concat)
+
+                        if isinstance(suffix, (Parameters, CallableType)):
+                            # no such thing as variance for ParamSpecs
+                            # TODO: is there a case I am missing?
+                            # TODO: constraints between prefixes
+                            prefix = mapped_arg.prefix
+                            suffix = suffix.copy_modified(
+                                suffix.arg_types[len(prefix.arg_types) :],
+                                suffix.arg_kinds[len(prefix.arg_kinds) :],
+                                suffix.arg_names[len(prefix.arg_names) :],
+                            )
+                            res.append(Constraint(mapped_arg, SUPERTYPE_OF, suffix))
+                        elif isinstance(suffix, ParamSpecType):
+                            res.append(Constraint(mapped_arg, SUPERTYPE_OF, suffix))
+                    else:
+                        # This case should have been handled above.
+                        assert not isinstance(tvar, TypeVarTupleType)
+
+                return res
+            elif self.direction == SUPERTYPE_OF and instance.type.has_base(template.type.fullname):
+                mapped = map_instance_to_supertype(instance, template.type)
+                tvars = template.type.defn.type_vars
+                if template.type.has_type_var_tuple_type:
+                    assert mapped.type.type_var_tuple_prefix is not None
+                    assert mapped.type.type_var_tuple_suffix is not None
+                    assert template.type.type_var_tuple_prefix is not None
+                    assert template.type.type_var_tuple_suffix is not None
+
+                    unpack_constraints, mapped_args, template_args = build_constraints_for_unpack(
+                        mapped.args,
+                        mapped.type.type_var_tuple_prefix,
+                        mapped.type.type_var_tuple_suffix,
+                        template.args,
+                        template.type.type_var_tuple_prefix,
+                        template.type.type_var_tuple_suffix,
+                        self.direction,
+                    )
+                    res.extend(unpack_constraints)
+
+                    tvars_prefix, _, tvars_suffix = split_with_prefix_and_suffix(
+                        tuple(tvars),
+                        template.type.type_var_tuple_prefix,
+                        template.type.type_var_tuple_suffix,
+                    )
+                    tvars = cast("list[TypeVarLikeType]", list(tvars_prefix + tvars_suffix))
+                else:
+                    mapped_args = mapped.args
+                    template_args = template.args
+                # N.B: We use zip instead of indexing because the lengths might have
+                # mismatches during daemon reprocessing.
+                for tvar, mapped_arg, template_arg in zip(tvars, mapped_args, template_args):
+                    assert not isinstance(tvar, TypeVarTupleType)
+                    if isinstance(tvar, TypeVarType):
+                        # The constraints for generic type parameters depend on variance.
+                        # Include constraints from both directions if invariant.
+                        if tvar.variance != CONTRAVARIANT:
+                            res.extend(infer_constraints(template_arg, mapped_arg, self.direction))
+                        if tvar.variance != COVARIANT:
+                            res.extend(
+                                infer_constraints(template_arg, mapped_arg, neg_op(self.direction))
+                            )
+                    elif isinstance(tvar, ParamSpecType) and isinstance(
+                        template_arg, ParamSpecType
+                    ):
+                        suffix = get_proper_type(mapped_arg)
+
+                        if isinstance(suffix, CallableType):
+                            prefix = template_arg.prefix
+                            from_concat = bool(prefix.arg_types) or suffix.from_concatenate
+                            suffix = suffix.copy_modified(from_concatenate=from_concat)
+
+                        if isinstance(suffix, (Parameters, CallableType)):
+                            # no such thing as variance for ParamSpecs
+                            # TODO: is there a case I am missing?
+                            # TODO: constraints between prefixes
+                            prefix = template_arg.prefix
+
+                            suffix = suffix.copy_modified(
+                                suffix.arg_types[len(prefix.arg_types) :],
+                                suffix.arg_kinds[len(prefix.arg_kinds) :],
+                                suffix.arg_names[len(prefix.arg_names) :],
+                            )
+                            res.append(Constraint(template_arg, SUPERTYPE_OF, suffix))
+                        elif isinstance(suffix, ParamSpecType):
+                            res.append(Constraint(template_arg, SUPERTYPE_OF, suffix))
+                    else:
+                        # This case should have been handled above.
+                        assert not isinstance(tvar, TypeVarTupleType)
+                return res
+            if (
+                template.type.is_protocol
+                and self.direction == SUPERTYPE_OF
+                and
+                # We avoid infinite recursion for structural subtypes by checking
+                # whether this type already appeared in the inference chain.
+                # This is a conservative way to break the inference cycles.
+                # It never produces any "false" constraints but gives up soon
+                # on purely structural inference cycles, see #3829.
+                # Note that we use is_protocol_implementation instead of is_subtype
+                # because some type may be considered a subtype of a protocol
+                # due to _promote, but still not implement the protocol.
+                not any(template == t for t in reversed(template.type.inferring))
+                and mypy.subtypes.is_protocol_implementation(instance, erased, skip=["__call__"])
+            ):
+                template.type.inferring.append(template)
+                res.extend(
+                    self.infer_constraints_from_protocol_members(
+                        instance, template, original_actual, template
+                    )
+                )
+                template.type.inferring.pop()
+                return res
+            elif (
+                instance.type.is_protocol
+                and self.direction == SUBTYPE_OF
+                and
+                # We avoid infinite recursion for structural subtypes also here.
+                not any(instance == i for i in reversed(instance.type.inferring))
+                and mypy.subtypes.is_protocol_implementation(erased, instance, skip=["__call__"])
+            ):
+                instance.type.inferring.append(instance)
+                res.extend(
+                    self.infer_constraints_from_protocol_members(
+                        instance, template, template, instance
+                    )
+                )
+                instance.type.inferring.pop()
+                return res
+        if res:
+            return res
+
+        if isinstance(actual, AnyType):
+            return self.infer_against_any(template.args, actual)
+        if (
+            isinstance(actual, TupleType)
+            and is_named_instance(template, TUPLE_LIKE_INSTANCE_NAMES)
+            and self.direction == SUPERTYPE_OF
+        ):
+            for item in actual.items:
+                cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
+                res.extend(cb)
+            return res
+        elif isinstance(actual, TupleType) and self.direction == SUPERTYPE_OF:
+            return infer_constraints(template, mypy.typeops.tuple_fallback(actual), self.direction)
+        elif isinstance(actual, TypeVarType):
+            if not actual.values:
+                return infer_constraints(template, actual.upper_bound, self.direction)
+            return []
+        elif isinstance(actual, ParamSpecType):
+            return infer_constraints(template, actual.upper_bound, self.direction)
+        elif isinstance(actual, TypeVarTupleType):
+            raise NotImplementedError
+        else:
+            return []
+
+    def infer_constraints_from_protocol_members(
+        self,
+        instance: Instance,
+        template: Instance,
+        subtype: Type,
+        protocol: Instance,
+        class_obj: bool = False,
+    ) -> list[Constraint]:
+        """Infer constraints for situations where either 'template' or 'instance' is a protocol.
+
+        The 'protocol' is the one of two that is an instance of protocol type, 'subtype'
+        is the type used to bind self during inference. Currently, we just infer constrains for
+        every protocol member type (both ways for settable members).
+        """
+        res = []
+        for member in protocol.type.protocol_members:
+            inst = mypy.subtypes.find_member(member, instance, subtype, class_obj=class_obj)
+            temp = mypy.subtypes.find_member(member, template, subtype)
+            if inst is None or temp is None:
+                if member == "__call__":
+                    continue
+                return []  # See #11020
+            # The above is safe since at this point we know that 'instance' is a subtype
+            # of (erased) 'template', therefore it defines all protocol members
+            res.extend(infer_constraints(temp, inst, self.direction))
+            if mypy.subtypes.IS_SETTABLE in mypy.subtypes.get_member_flags(member, protocol):
+                # Settable members are invariant, add opposite constraints
+                res.extend(infer_constraints(temp, inst, neg_op(self.direction)))
+        return res
+
+    def visit_callable_type(self, template: CallableType) -> list[Constraint]:
+        # Normalize callables before matching against each other.
+        # Note that non-normalized callables can be created in annotations
+        # using e.g. callback protocols.
+        template = template.with_unpacked_kwargs()
+        if isinstance(self.actual, CallableType):
+            res: list[Constraint] = []
+            cactual = self.actual.with_unpacked_kwargs()
+            param_spec = template.param_spec()
+            if param_spec is None:
+                # FIX verify argument counts
+                # TODO: Erase template variables if it is generic?
+                if (
+                    type_state.infer_polymorphic
+                    and cactual.variables
+                    and cactual.param_spec() is None
+                    # Technically, the correct inferred type for application of e.g.
+                    # Callable[..., T] -> Callable[..., T] (with literal ellipsis), to a generic
+                    # like U -> U, should be Callable[..., Any], but if U is a self-type, we can
+                    # allow it to leak, to be later bound to self. A bunch of existing code
+                    # depends on this old behaviour.
+                    and not any(tv.id.raw_id == 0 for tv in cactual.variables)
+                ):
+                    # If actual is generic, unify it with template. Note: this is
+                    # not an ideal solution (which would be adding the generic variables
+                    # to the constraint inference set), but it's a good first approximation,
+                    # and this will prevent leaking these variables in the solutions.
+                    # Note: this may infer constraints like T <: S or T <: List[S]
+                    # that contain variables in the target.
+                    unified = mypy.subtypes.unify_generic_callable(
+                        cactual, template, ignore_return=True
+                    )
+                    if unified is not None:
+                        cactual = unified
+                        res.extend(infer_constraints(cactual, template, neg_op(self.direction)))
+
+                # We can't infer constraints from arguments if the template is Callable[..., T]
+                # (with literal '...').
+                if not template.is_ellipsis_args:
+                    if find_unpack_in_list(template.arg_types) is not None:
+                        (
+                            unpack_constraints,
+                            cactual_args_t,
+                            template_args_t,
+                        ) = find_and_build_constraints_for_unpack(
+                            tuple(cactual.arg_types), tuple(template.arg_types), self.direction
+                        )
+                        template_args = list(template_args_t)
+                        cactual_args = list(cactual_args_t)
+                        res.extend(unpack_constraints)
+                        assert len(template_args) == len(cactual_args)
+                    else:
+                        template_args = template.arg_types
+                        cactual_args = cactual.arg_types
+                    # The lengths should match, but don't crash (it will error elsewhere).
+                    for t, a in zip(template_args, cactual_args):
+                        # Negate direction due to function argument type contravariance.
+                        res.extend(infer_constraints(t, a, neg_op(self.direction)))
+            else:
+                # sometimes, it appears we try to get constraints between two paramspec callables?
+
+                # TODO: Direction
+                # TODO: check the prefixes match
+                prefix = param_spec.prefix
+                prefix_len = len(prefix.arg_types)
+                cactual_ps = cactual.param_spec()
+
+                if not cactual_ps:
+                    max_prefix_len = len([k for k in cactual.arg_kinds if k in (ARG_POS, ARG_OPT)])
+                    prefix_len = min(prefix_len, max_prefix_len)
+                    res.append(
+                        Constraint(
+                            param_spec,
+                            SUBTYPE_OF,
+                            cactual.copy_modified(
+                                arg_types=cactual.arg_types[prefix_len:],
+                                arg_kinds=cactual.arg_kinds[prefix_len:],
+                                arg_names=cactual.arg_names[prefix_len:],
+                                ret_type=UninhabitedType(),
+                            ),
+                        )
+                    )
+                else:
+                    res.append(Constraint(param_spec, SUBTYPE_OF, cactual_ps))
+
+                # compare prefixes
+                cactual_prefix = cactual.copy_modified(
+                    arg_types=cactual.arg_types[:prefix_len],
+                    arg_kinds=cactual.arg_kinds[:prefix_len],
+                    arg_names=cactual.arg_names[:prefix_len],
+                )
+
+                # TODO: see above "FIX" comments for param_spec is None case
+                # TODO: this assumes positional arguments
+                for t, a in zip(prefix.arg_types, cactual_prefix.arg_types):
+                    res.extend(infer_constraints(t, a, neg_op(self.direction)))
+
+            template_ret_type, cactual_ret_type = template.ret_type, cactual.ret_type
+            if template.type_guard is not None:
+                template_ret_type = template.type_guard
+            if cactual.type_guard is not None:
+                cactual_ret_type = cactual.type_guard
+
+            res.extend(infer_constraints(template_ret_type, cactual_ret_type, self.direction))
+            return res
+        elif isinstance(self.actual, AnyType):
+            param_spec = template.param_spec()
+            any_type = AnyType(TypeOfAny.from_another_any, source_any=self.actual)
+            if param_spec is None:
+                # FIX what if generic
+                res = self.infer_against_any(template.arg_types, self.actual)
+            else:
+                res = [
+                    Constraint(
+                        param_spec,
+                        SUBTYPE_OF,
+                        callable_with_ellipsis(any_type, any_type, template.fallback),
+                    )
+                ]
+            res.extend(infer_constraints(template.ret_type, any_type, self.direction))
+            return res
+        elif isinstance(self.actual, Overloaded):
+            return self.infer_against_overloaded(self.actual, template)
+        elif isinstance(self.actual, TypeType):
+            return infer_constraints(template.ret_type, self.actual.item, self.direction)
+        elif isinstance(self.actual, Instance):
+            # Instances with __call__ method defined are considered structural
+            # subtypes of Callable with a compatible signature.
+            call = mypy.subtypes.find_member(
+                "__call__", self.actual, self.actual, is_operator=True
+            )
+            if call:
+                return infer_constraints(template, call, self.direction)
+            else:
+                return []
+        else:
+            return []
+
+    def infer_against_overloaded(
+        self, overloaded: Overloaded, template: CallableType
+    ) -> list[Constraint]:
+        # Create constraints by matching an overloaded type against a template.
+        # This is tricky to do in general. We cheat by only matching against
+        # the first overload item that is callable compatible. This
+        # seems to work somewhat well, but we should really use a more
+        # reliable technique.
+        item = find_matching_overload_item(overloaded, template)
+        return infer_constraints(template, item, self.direction)
+
+    def visit_tuple_type(self, template: TupleType) -> list[Constraint]:
+        actual = self.actual
+        unpack_index = find_unpack_in_list(template.items)
+        is_varlength_tuple = (
+            isinstance(actual, Instance) and actual.type.fullname == "builtins.tuple"
+        )
+
+        if isinstance(actual, TupleType) or is_varlength_tuple:
+            res: list[Constraint] = []
+            if unpack_index is not None:
+                if is_varlength_tuple:
+                    unpack_type = template.items[unpack_index]
+                    assert isinstance(unpack_type, UnpackType)
+                    unpacked_type = unpack_type.type
+                    assert isinstance(unpacked_type, TypeVarTupleType)
+                    return [Constraint(type_var=unpacked_type, op=self.direction, target=actual)]
+                else:
+                    assert isinstance(actual, TupleType)
+                    (
+                        unpack_constraints,
+                        actual_items,
+                        template_items,
+                    ) = find_and_build_constraints_for_unpack(
+                        tuple(actual.items), tuple(template.items), self.direction
+                    )
+                    res.extend(unpack_constraints)
+            elif isinstance(actual, TupleType):
+                actual_items = tuple(actual.items)
+                template_items = tuple(template.items)
+            else:
+                return res
+
+            # Cases above will return if actual wasn't a TupleType.
+            assert isinstance(actual, TupleType)
+            if len(actual_items) == len(template_items):
+                if (
+                    actual.partial_fallback.type.is_named_tuple
+                    and template.partial_fallback.type.is_named_tuple
+                ):
+                    # For named tuples using just the fallbacks usually gives better results.
+                    return res + infer_constraints(
+                        template.partial_fallback, actual.partial_fallback, self.direction
+                    )
+                for i in range(len(template_items)):
+                    res.extend(
+                        infer_constraints(template_items[i], actual_items[i], self.direction)
+                    )
+            return res
+        elif isinstance(actual, AnyType):
+            return self.infer_against_any(template.items, actual)
+        else:
+            return []
+
+    def visit_typeddict_type(self, template: TypedDictType) -> list[Constraint]:
+        actual = self.actual
+        if isinstance(actual, TypedDictType):
+            res: list[Constraint] = []
+            # NOTE: Non-matching keys are ignored. Compatibility is checked
+            #       elsewhere so this shouldn't be unsafe.
+            for item_name, template_item_type, actual_item_type in template.zip(actual):
+                res.extend(infer_constraints(template_item_type, actual_item_type, self.direction))
+            return res
+        elif isinstance(actual, AnyType):
+            return self.infer_against_any(template.items.values(), actual)
+        else:
+            return []
+
+    def visit_union_type(self, template: UnionType) -> list[Constraint]:
+        assert False, (
+            "Unexpected UnionType in ConstraintBuilderVisitor"
+            " (should have been handled in infer_constraints)"
+        )
+
+    def visit_type_alias_type(self, template: TypeAliasType) -> list[Constraint]:
+        assert False, f"This should be never called, got {template}"
+
+    def infer_against_any(self, types: Iterable[Type], any_type: AnyType) -> list[Constraint]:
+        res: list[Constraint] = []
+        for t in types:
+            if isinstance(t, UnpackType) and isinstance(t.type, TypeVarTupleType):
+                res.append(Constraint(t.type, self.direction, any_type))
+            else:
+                # Note that we ignore variance and simply always use the
+                # original direction. This is because for Any targets direction is
+                # irrelevant in most cases, see e.g. is_same_constraint().
+                res.extend(infer_constraints(t, any_type, self.direction))
+        return res
+
+    def visit_overloaded(self, template: Overloaded) -> list[Constraint]:
+        if isinstance(self.actual, CallableType):
+            items = find_matching_overload_items(template, self.actual)
+        else:
+            items = template.items
+        res: list[Constraint] = []
+        for t in items:
+            res.extend(infer_constraints(t, self.actual, self.direction))
+        return res
+
+    def visit_type_type(self, template: TypeType) -> list[Constraint]:
+        if isinstance(self.actual, CallableType):
+            return infer_constraints(template.item, self.actual.ret_type, self.direction)
+        elif isinstance(self.actual, Overloaded):
+            return infer_constraints(template.item, self.actual.items[0].ret_type, self.direction)
+        elif isinstance(self.actual, TypeType):
+            return infer_constraints(template.item, self.actual.item, self.direction)
+        elif isinstance(self.actual, AnyType):
+            return infer_constraints(template.item, self.actual, self.direction)
+        else:
+            return []
+
+
+def neg_op(op: int) -> int:
+    """Map SubtypeOf to SupertypeOf and vice versa."""
+
+    if op == SUBTYPE_OF:
+        return SUPERTYPE_OF
+    elif op == SUPERTYPE_OF:
+        return SUBTYPE_OF
+    else:
+        raise ValueError(f"Invalid operator {op}")
+
+
+def find_matching_overload_item(overloaded: Overloaded, template: CallableType) -> CallableType:
+    """Disambiguate overload item against a template."""
+    items = overloaded.items
+    for item in items:
+        # Return type may be indeterminate in the template, so ignore it when performing a
+        # subtype check.
+        if mypy.subtypes.is_callable_compatible(
+            item, template, is_compat=mypy.subtypes.is_subtype, ignore_return=True
+        ):
+            return item
+    # Fall back to the first item if we can't find a match. This is totally arbitrary --
+    # maybe we should just bail out at this point.
+    return items[0]
+
+
+def find_matching_overload_items(
+    overloaded: Overloaded, template: CallableType
+) -> list[CallableType]:
+    """Like find_matching_overload_item, but return all matches, not just the first."""
+    items = overloaded.items
+    res = []
+    for item in items:
+        # Return type may be indeterminate in the template, so ignore it when performing a
+        # subtype check.
+        if mypy.subtypes.is_callable_compatible(
+            item, template, is_compat=mypy.subtypes.is_subtype, ignore_return=True
+        ):
+            res.append(item)
+    if not res:
+        # Falling back to all items if we can't find a match is pretty arbitrary, but
+        # it maintains backward compatibility.
+        res = items.copy()
+    return res
+
+
+def find_and_build_constraints_for_unpack(
+    mapped: tuple[Type, ...], template: tuple[Type, ...], direction: int
+) -> tuple[list[Constraint], tuple[Type, ...], tuple[Type, ...]]:
+    mapped_prefix_len = find_unpack_in_list(mapped)
+    if mapped_prefix_len is not None:
+        mapped_suffix_len: int | None = len(mapped) - mapped_prefix_len - 1
+    else:
+        mapped_suffix_len = None
+
+    template_prefix_len = find_unpack_in_list(template)
+    assert template_prefix_len is not None
+    template_suffix_len = len(template) - template_prefix_len - 1
+
+    return build_constraints_for_unpack(
+        mapped,
+        mapped_prefix_len,
+        mapped_suffix_len,
+        template,
+        template_prefix_len,
+        template_suffix_len,
+        direction,
+    )
+
+
+def build_constraints_for_unpack(
+    mapped: tuple[Type, ...],
+    mapped_prefix_len: int | None,
+    mapped_suffix_len: int | None,
+    template: tuple[Type, ...],
+    template_prefix_len: int,
+    template_suffix_len: int,
+    direction: int,
+) -> tuple[list[Constraint], tuple[Type, ...], tuple[Type, ...]]:
+    if mapped_prefix_len is None:
+        mapped_prefix_len = template_prefix_len
+    if mapped_suffix_len is None:
+        mapped_suffix_len = template_suffix_len
+
+    split_result = split_with_mapped_and_template(
+        mapped,
+        mapped_prefix_len,
+        mapped_suffix_len,
+        template,
+        template_prefix_len,
+        template_suffix_len,
+    )
+    assert split_result is not None
+    (
+        mapped_prefix,
+        mapped_middle,
+        mapped_suffix,
+        template_prefix,
+        template_middle,
+        template_suffix,
+    ) = split_result
+
+    template_unpack = extract_unpack(template_middle)
+    res = []
+
+    if template_unpack is not None:
+        if isinstance(template_unpack, TypeVarTupleType):
+            res.append(
+                Constraint(
+                    template_unpack,
+                    direction,
+                    TupleType(list(mapped_middle), template_unpack.tuple_fallback),
+                )
+            )
+        elif (
+            isinstance(template_unpack, Instance)
+            and template_unpack.type.fullname == "builtins.tuple"
+        ):
+            for item in mapped_middle:
+                res.extend(infer_constraints(template_unpack.args[0], item, direction))
+
+        elif isinstance(template_unpack, TupleType):
+            if len(template_unpack.items) == len(mapped_middle):
+                for template_arg, item in zip(template_unpack.items, mapped_middle):
+                    res.extend(infer_constraints(template_arg, item, direction))
+    return (res, mapped_prefix + mapped_suffix, template_prefix + template_suffix)

二進制
venv/lib/python3.11/site-packages/mypy/copytype.cpython-311-x86_64-linux-gnu.so


+ 133 - 0
venv/lib/python3.11/site-packages/mypy/copytype.py

@@ -0,0 +1,133 @@
+from __future__ import annotations
+
+from typing import Any, cast
+
+from mypy.types import (
+    AnyType,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    Parameters,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    TypeAliasType,
+    TypedDictType,
+    TypeType,
+    TypeVarTupleType,
+    TypeVarType,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+)
+
+# type_visitor needs to be imported after types
+from mypy.type_visitor import TypeVisitor  # ruff: isort: skip
+
+
+def copy_type(t: ProperType) -> ProperType:
+    """Create a shallow copy of a type.
+
+    This can be used to mutate the copy with truthiness information.
+
+    Classes compiled with mypyc don't support copy.copy(), so we need
+    a custom implementation.
+    """
+    return t.accept(TypeShallowCopier())
+
+
+class TypeShallowCopier(TypeVisitor[ProperType]):
+    def visit_unbound_type(self, t: UnboundType) -> ProperType:
+        return t
+
+    def visit_any(self, t: AnyType) -> ProperType:
+        return self.copy_common(t, AnyType(t.type_of_any, t.source_any, t.missing_import_name))
+
+    def visit_none_type(self, t: NoneType) -> ProperType:
+        return self.copy_common(t, NoneType())
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType:
+        dup = UninhabitedType(t.is_noreturn)
+        dup.ambiguous = t.ambiguous
+        return self.copy_common(t, dup)
+
+    def visit_erased_type(self, t: ErasedType) -> ProperType:
+        return self.copy_common(t, ErasedType())
+
+    def visit_deleted_type(self, t: DeletedType) -> ProperType:
+        return self.copy_common(t, DeletedType(t.source))
+
+    def visit_instance(self, t: Instance) -> ProperType:
+        dup = Instance(t.type, t.args, last_known_value=t.last_known_value)
+        dup.invalid = t.invalid
+        return self.copy_common(t, dup)
+
+    def visit_type_var(self, t: TypeVarType) -> ProperType:
+        return self.copy_common(t, t.copy_modified())
+
+    def visit_param_spec(self, t: ParamSpecType) -> ProperType:
+        dup = ParamSpecType(
+            t.name, t.fullname, t.id, t.flavor, t.upper_bound, t.default, prefix=t.prefix
+        )
+        return self.copy_common(t, dup)
+
+    def visit_parameters(self, t: Parameters) -> ProperType:
+        dup = Parameters(
+            t.arg_types,
+            t.arg_kinds,
+            t.arg_names,
+            variables=t.variables,
+            is_ellipsis_args=t.is_ellipsis_args,
+        )
+        return self.copy_common(t, dup)
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
+        dup = TypeVarTupleType(
+            t.name, t.fullname, t.id, t.upper_bound, t.tuple_fallback, t.default
+        )
+        return self.copy_common(t, dup)
+
+    def visit_unpack_type(self, t: UnpackType) -> ProperType:
+        dup = UnpackType(t.type)
+        return self.copy_common(t, dup)
+
+    def visit_partial_type(self, t: PartialType) -> ProperType:
+        return self.copy_common(t, PartialType(t.type, t.var, t.value_type))
+
+    def visit_callable_type(self, t: CallableType) -> ProperType:
+        return self.copy_common(t, t.copy_modified())
+
+    def visit_tuple_type(self, t: TupleType) -> ProperType:
+        return self.copy_common(t, TupleType(t.items, t.partial_fallback, implicit=t.implicit))
+
+    def visit_typeddict_type(self, t: TypedDictType) -> ProperType:
+        return self.copy_common(t, TypedDictType(t.items, t.required_keys, t.fallback))
+
+    def visit_literal_type(self, t: LiteralType) -> ProperType:
+        return self.copy_common(t, LiteralType(value=t.value, fallback=t.fallback))
+
+    def visit_union_type(self, t: UnionType) -> ProperType:
+        return self.copy_common(t, UnionType(t.items))
+
+    def visit_overloaded(self, t: Overloaded) -> ProperType:
+        return self.copy_common(t, Overloaded(items=t.items))
+
+    def visit_type_type(self, t: TypeType) -> ProperType:
+        # Use cast since the type annotations in TypeType are imprecise.
+        return self.copy_common(t, TypeType(cast(Any, t.item)))
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> ProperType:
+        assert False, "only ProperTypes supported"
+
+    def copy_common(self, t: ProperType, t2: ProperType) -> ProperType:
+        t2.line = t.line
+        t2.column = t.column
+        t2.can_be_false = t.can_be_false
+        t2.can_be_true = t.can_be_true
+        return t2

二進制
venv/lib/python3.11/site-packages/mypy/defaults.cpython-311-x86_64-linux-gnu.so


+ 48 - 0
venv/lib/python3.11/site-packages/mypy/defaults.py

@@ -0,0 +1,48 @@
+from __future__ import annotations
+
+import os
+from typing import Final
+
+PYTHON2_VERSION: Final = (2, 7)
+
+# Earliest fully supported Python 3.x version. Used as the default Python
+# version in tests. Mypy wheels should be built starting with this version,
+# and CI tests should be run on this version (and later versions).
+PYTHON3_VERSION: Final = (3, 8)
+
+# Earliest Python 3.x version supported via --python-version 3.x. To run
+# mypy, at least version PYTHON3_VERSION is needed.
+PYTHON3_VERSION_MIN: Final = (3, 4)
+
+CACHE_DIR: Final = ".mypy_cache"
+CONFIG_FILE: Final = ["mypy.ini", ".mypy.ini"]
+PYPROJECT_CONFIG_FILES: Final = ["pyproject.toml"]
+SHARED_CONFIG_FILES: Final = ["setup.cfg"]
+USER_CONFIG_FILES: Final = ["~/.config/mypy/config", "~/.mypy.ini"]
+if os.environ.get("XDG_CONFIG_HOME"):
+    USER_CONFIG_FILES.insert(0, os.path.join(os.environ["XDG_CONFIG_HOME"], "mypy/config"))
+
+CONFIG_FILES: Final = (
+    CONFIG_FILE + PYPROJECT_CONFIG_FILES + SHARED_CONFIG_FILES + USER_CONFIG_FILES
+)
+
+# This must include all reporters defined in mypy.report. This is defined here
+# to make reporter names available without importing mypy.report -- this speeds
+# up startup.
+REPORTER_NAMES: Final = [
+    "linecount",
+    "any-exprs",
+    "linecoverage",
+    "memory-xml",
+    "cobertura-xml",
+    "xml",
+    "xslt-html",
+    "xslt-txt",
+    "html",
+    "txt",
+    "lineprecision",
+]
+
+# Threshold after which we sometimes filter out most errors to avoid very
+# verbose output. The default is to show all errors.
+MANY_ERRORS_THRESHOLD: Final = -1

二進制
venv/lib/python3.11/site-packages/mypy/dmypy/__init__.cpython-311-x86_64-linux-gnu.so


+ 0 - 0
venv/lib/python3.11/site-packages/mypy/dmypy/__init__.py


+ 6 - 0
venv/lib/python3.11/site-packages/mypy/dmypy/__main__.py

@@ -0,0 +1,6 @@
+from __future__ import annotations
+
+from mypy.dmypy.client import console_entry
+
+if __name__ == "__main__":
+    console_entry()

二進制
venv/lib/python3.11/site-packages/mypy/dmypy/client.cpython-311-x86_64-linux-gnu.so


+ 744 - 0
venv/lib/python3.11/site-packages/mypy/dmypy/client.py

@@ -0,0 +1,744 @@
+"""Client for mypy daemon mode.
+
+This manages a daemon process which keeps useful state in memory
+rather than having to read it back from disk on each run.
+"""
+
+from __future__ import annotations
+
+import argparse
+import base64
+import json
+import os
+import pickle
+import sys
+import time
+import traceback
+from typing import Any, Callable, Mapping, NoReturn
+
+from mypy.dmypy_os import alive, kill
+from mypy.dmypy_util import DEFAULT_STATUS_FILE, receive
+from mypy.ipc import IPCClient, IPCException
+from mypy.util import check_python_version, get_terminal_width, should_force_color
+from mypy.version import __version__
+
+# Argument parser.  Subparsers are tied to action functions by the
+# @action(subparse) decorator.
+
+
+class AugmentedHelpFormatter(argparse.RawDescriptionHelpFormatter):
+    def __init__(self, prog: str) -> None:
+        super().__init__(prog=prog, max_help_position=30)
+
+
+parser = argparse.ArgumentParser(
+    prog="dmypy", description="Client for mypy daemon mode", fromfile_prefix_chars="@"
+)
+parser.set_defaults(action=None)
+parser.add_argument(
+    "--status-file", default=DEFAULT_STATUS_FILE, help="status file to retrieve daemon details"
+)
+parser.add_argument(
+    "-V",
+    "--version",
+    action="version",
+    version="%(prog)s " + __version__,
+    help="Show program's version number and exit",
+)
+subparsers = parser.add_subparsers()
+
+start_parser = p = subparsers.add_parser("start", help="Start daemon")
+p.add_argument("--log-file", metavar="FILE", type=str, help="Direct daemon stdout/stderr to FILE")
+p.add_argument(
+    "--timeout", metavar="TIMEOUT", type=int, help="Server shutdown timeout (in seconds)"
+)
+p.add_argument(
+    "flags", metavar="FLAG", nargs="*", type=str, help="Regular mypy flags (precede with --)"
+)
+
+restart_parser = p = subparsers.add_parser(
+    "restart", help="Restart daemon (stop or kill followed by start)"
+)
+p.add_argument("--log-file", metavar="FILE", type=str, help="Direct daemon stdout/stderr to FILE")
+p.add_argument(
+    "--timeout", metavar="TIMEOUT", type=int, help="Server shutdown timeout (in seconds)"
+)
+p.add_argument(
+    "flags", metavar="FLAG", nargs="*", type=str, help="Regular mypy flags (precede with --)"
+)
+
+status_parser = p = subparsers.add_parser("status", help="Show daemon status")
+p.add_argument("-v", "--verbose", action="store_true", help="Print detailed status")
+p.add_argument("--fswatcher-dump-file", help="Collect information about the current file state")
+
+stop_parser = p = subparsers.add_parser("stop", help="Stop daemon (asks it politely to go away)")
+
+kill_parser = p = subparsers.add_parser("kill", help="Kill daemon (kills the process)")
+
+check_parser = p = subparsers.add_parser(
+    "check", formatter_class=AugmentedHelpFormatter, help="Check some files (requires daemon)"
+)
+p.add_argument("-v", "--verbose", action="store_true", help="Print detailed status")
+p.add_argument("-q", "--quiet", action="store_true", help=argparse.SUPPRESS)  # Deprecated
+p.add_argument("--junit-xml", help="Write junit.xml to the given file")
+p.add_argument("--perf-stats-file", help="write performance information to the given file")
+p.add_argument("files", metavar="FILE", nargs="+", help="File (or directory) to check")
+p.add_argument(
+    "--export-types",
+    action="store_true",
+    help="Store types of all expressions in a shared location (useful for inspections)",
+)
+
+run_parser = p = subparsers.add_parser(
+    "run",
+    formatter_class=AugmentedHelpFormatter,
+    help="Check some files, [re]starting daemon if necessary",
+)
+p.add_argument("-v", "--verbose", action="store_true", help="Print detailed status")
+p.add_argument("--junit-xml", help="Write junit.xml to the given file")
+p.add_argument("--perf-stats-file", help="write performance information to the given file")
+p.add_argument(
+    "--timeout", metavar="TIMEOUT", type=int, help="Server shutdown timeout (in seconds)"
+)
+p.add_argument("--log-file", metavar="FILE", type=str, help="Direct daemon stdout/stderr to FILE")
+p.add_argument(
+    "--export-types",
+    action="store_true",
+    help="Store types of all expressions in a shared location (useful for inspections)",
+)
+p.add_argument(
+    "flags",
+    metavar="ARG",
+    nargs="*",
+    type=str,
+    help="Regular mypy flags and files (precede with --)",
+)
+
+recheck_parser = p = subparsers.add_parser(
+    "recheck",
+    formatter_class=AugmentedHelpFormatter,
+    help="Re-check the previous list of files, with optional modifications (requires daemon)",
+)
+p.add_argument("-v", "--verbose", action="store_true", help="Print detailed status")
+p.add_argument("-q", "--quiet", action="store_true", help=argparse.SUPPRESS)  # Deprecated
+p.add_argument("--junit-xml", help="Write junit.xml to the given file")
+p.add_argument("--perf-stats-file", help="write performance information to the given file")
+p.add_argument(
+    "--export-types",
+    action="store_true",
+    help="Store types of all expressions in a shared location (useful for inspections)",
+)
+p.add_argument(
+    "--update",
+    metavar="FILE",
+    nargs="*",
+    help="Files in the run to add or check again (default: all from previous run)",
+)
+p.add_argument("--remove", metavar="FILE", nargs="*", help="Files to remove from the run")
+
+suggest_parser = p = subparsers.add_parser(
+    "suggest", help="Suggest a signature or show call sites for a specific function"
+)
+p.add_argument(
+    "function",
+    metavar="FUNCTION",
+    type=str,
+    help="Function specified as '[package.]module.[class.]function'",
+)
+p.add_argument(
+    "--json",
+    action="store_true",
+    help="Produce json that pyannotate can use to apply a suggestion",
+)
+p.add_argument(
+    "--no-errors", action="store_true", help="Only produce suggestions that cause no errors"
+)
+p.add_argument(
+    "--no-any", action="store_true", help="Only produce suggestions that don't contain Any"
+)
+p.add_argument(
+    "--flex-any",
+    type=float,
+    help="Allow anys in types if they go above a certain score (scores are from 0-1)",
+)
+p.add_argument(
+    "--callsites", action="store_true", help="Find callsites instead of suggesting a type"
+)
+p.add_argument(
+    "--use-fixme",
+    metavar="NAME",
+    type=str,
+    help="A dummy name to use instead of Any for types that can't be inferred",
+)
+p.add_argument(
+    "--max-guesses",
+    type=int,
+    help="Set the maximum number of types to try for a function (default 64)",
+)
+
+inspect_parser = p = subparsers.add_parser(
+    "inspect", help="Locate and statically inspect expression(s)"
+)
+p.add_argument(
+    "location",
+    metavar="LOCATION",
+    type=str,
+    help="Location specified as path/to/file.py:line:column[:end_line:end_column]."
+    " If position is given (i.e. only line and column), this will return all"
+    " enclosing expressions",
+)
+p.add_argument(
+    "--show",
+    metavar="INSPECTION",
+    type=str,
+    default="type",
+    choices=["type", "attrs", "definition"],
+    help="What kind of inspection to run",
+)
+p.add_argument(
+    "--verbose",
+    "-v",
+    action="count",
+    default=0,
+    help="Increase verbosity of the type string representation (can be repeated)",
+)
+p.add_argument(
+    "--limit",
+    metavar="NUM",
+    type=int,
+    default=0,
+    help="Return at most NUM innermost expressions (if position is given); 0 means no limit",
+)
+p.add_argument(
+    "--include-span",
+    action="store_true",
+    help="Prepend each inspection result with the span of corresponding expression"
+    ' (e.g. 1:2:3:4:"int")',
+)
+p.add_argument(
+    "--include-kind",
+    action="store_true",
+    help="Prepend each inspection result with the kind of corresponding expression"
+    ' (e.g. NameExpr:"int")',
+)
+p.add_argument(
+    "--include-object-attrs",
+    action="store_true",
+    help='Include attributes of "object" in "attrs" inspection',
+)
+p.add_argument(
+    "--union-attrs",
+    action="store_true",
+    help="Include attributes valid for some of possible expression types"
+    " (by default an intersection is returned)",
+)
+p.add_argument(
+    "--force-reload",
+    action="store_true",
+    help="Re-parse and re-type-check file before inspection (may be slow)",
+)
+
+hang_parser = p = subparsers.add_parser("hang", help="Hang for 100 seconds")
+
+daemon_parser = p = subparsers.add_parser("daemon", help="Run daemon in foreground")
+p.add_argument(
+    "--timeout", metavar="TIMEOUT", type=int, help="Server shutdown timeout (in seconds)"
+)
+p.add_argument("--log-file", metavar="FILE", type=str, help="Direct daemon stdout/stderr to FILE")
+p.add_argument(
+    "flags", metavar="FLAG", nargs="*", type=str, help="Regular mypy flags (precede with --)"
+)
+p.add_argument("--options-data", help=argparse.SUPPRESS)
+help_parser = p = subparsers.add_parser("help")
+
+del p
+
+
+class BadStatus(Exception):
+    """Exception raised when there is something wrong with the status file.
+
+    For example:
+    - No status file found
+    - Status file malformed
+    - Process whose pid is in the status file does not exist
+    """
+
+
+def main(argv: list[str]) -> None:
+    """The code is top-down."""
+    check_python_version("dmypy")
+    args = parser.parse_args(argv)
+    if not args.action:
+        parser.print_usage()
+    else:
+        try:
+            args.action(args)
+        except BadStatus as err:
+            fail(err.args[0])
+        except Exception:
+            # We do this explicitly to avoid exceptions percolating up
+            # through mypy.api invocations
+            traceback.print_exc()
+            sys.exit(2)
+
+
+def fail(msg: str) -> NoReturn:
+    print(msg, file=sys.stderr)
+    sys.exit(2)
+
+
+ActionFunction = Callable[[argparse.Namespace], None]
+
+
+def action(subparser: argparse.ArgumentParser) -> Callable[[ActionFunction], ActionFunction]:
+    """Decorator to tie an action function to a subparser."""
+
+    def register(func: ActionFunction) -> ActionFunction:
+        subparser.set_defaults(action=func)
+        return func
+
+    return register
+
+
+# Action functions (run in client from command line).
+
+
+@action(start_parser)
+def do_start(args: argparse.Namespace) -> None:
+    """Start daemon (it must not already be running).
+
+    This is where mypy flags are set from the command line.
+
+    Setting flags is a bit awkward; you have to use e.g.:
+
+      dmypy start -- --strict
+
+    since we don't want to duplicate mypy's huge list of flags.
+    """
+    try:
+        get_status(args.status_file)
+    except BadStatus:
+        # Bad or missing status file or dead process; good to start.
+        pass
+    else:
+        fail("Daemon is still alive")
+    start_server(args)
+
+
+@action(restart_parser)
+def do_restart(args: argparse.Namespace) -> None:
+    """Restart daemon (it may or may not be running; but not hanging).
+
+    We first try to stop it politely if it's running.  This also sets
+    mypy flags from the command line (see do_start()).
+    """
+    restart_server(args)
+
+
+def restart_server(args: argparse.Namespace, allow_sources: bool = False) -> None:
+    """Restart daemon (it may or may not be running; but not hanging)."""
+    try:
+        do_stop(args)
+    except BadStatus:
+        # Bad or missing status file or dead process; good to start.
+        pass
+    start_server(args, allow_sources)
+
+
+def start_server(args: argparse.Namespace, allow_sources: bool = False) -> None:
+    """Start the server from command arguments and wait for it."""
+    # Lazy import so this import doesn't slow down other commands.
+    from mypy.dmypy_server import daemonize, process_start_options
+
+    start_options = process_start_options(args.flags, allow_sources)
+    if daemonize(start_options, args.status_file, timeout=args.timeout, log_file=args.log_file):
+        sys.exit(2)
+    wait_for_server(args.status_file)
+
+
+def wait_for_server(status_file: str, timeout: float = 5.0) -> None:
+    """Wait until the server is up.
+
+    Exit if it doesn't happen within the timeout.
+    """
+    endtime = time.time() + timeout
+    while time.time() < endtime:
+        try:
+            data = read_status(status_file)
+        except BadStatus:
+            # If the file isn't there yet, retry later.
+            time.sleep(0.1)
+            continue
+        # If the file's content is bogus or the process is dead, fail.
+        check_status(data)
+        print("Daemon started")
+        return
+    fail("Timed out waiting for daemon to start")
+
+
+@action(run_parser)
+def do_run(args: argparse.Namespace) -> None:
+    """Do a check, starting (or restarting) the daemon as necessary
+
+    Restarts the daemon if the running daemon reports that it is
+    required (due to a configuration change, for example).
+
+    Setting flags is a bit awkward; you have to use e.g.:
+
+      dmypy run -- --strict a.py b.py ...
+
+    since we don't want to duplicate mypy's huge list of flags.
+    (The -- is only necessary if flags are specified.)
+    """
+    if not is_running(args.status_file):
+        # Bad or missing status file or dead process; good to start.
+        start_server(args, allow_sources=True)
+    t0 = time.time()
+    response = request(
+        args.status_file,
+        "run",
+        version=__version__,
+        args=args.flags,
+        export_types=args.export_types,
+    )
+    # If the daemon signals that a restart is necessary, do it
+    if "restart" in response:
+        print(f"Restarting: {response['restart']}")
+        restart_server(args, allow_sources=True)
+        response = request(
+            args.status_file,
+            "run",
+            version=__version__,
+            args=args.flags,
+            export_types=args.export_types,
+        )
+
+    t1 = time.time()
+    response["roundtrip_time"] = t1 - t0
+    check_output(response, args.verbose, args.junit_xml, args.perf_stats_file)
+
+
+@action(status_parser)
+def do_status(args: argparse.Namespace) -> None:
+    """Print daemon status.
+
+    This verifies that it is responsive to requests.
+    """
+    status = read_status(args.status_file)
+    if args.verbose:
+        show_stats(status)
+    # Both check_status() and request() may raise BadStatus,
+    # which will be handled by main().
+    check_status(status)
+    response = request(
+        args.status_file, "status", fswatcher_dump_file=args.fswatcher_dump_file, timeout=5
+    )
+    if args.verbose or "error" in response:
+        show_stats(response)
+    if "error" in response:
+        fail(f"Daemon is stuck; consider {sys.argv[0]} kill")
+    print("Daemon is up and running")
+
+
+@action(stop_parser)
+def do_stop(args: argparse.Namespace) -> None:
+    """Stop daemon via a 'stop' request."""
+    # May raise BadStatus, which will be handled by main().
+    response = request(args.status_file, "stop", timeout=5)
+    if "error" in response:
+        show_stats(response)
+        fail(f"Daemon is stuck; consider {sys.argv[0]} kill")
+    else:
+        print("Daemon stopped")
+
+
+@action(kill_parser)
+def do_kill(args: argparse.Namespace) -> None:
+    """Kill daemon process with SIGKILL."""
+    pid, _ = get_status(args.status_file)
+    try:
+        kill(pid)
+    except OSError as err:
+        fail(str(err))
+    else:
+        print("Daemon killed")
+
+
+@action(check_parser)
+def do_check(args: argparse.Namespace) -> None:
+    """Ask the daemon to check a list of files."""
+    t0 = time.time()
+    response = request(args.status_file, "check", files=args.files, export_types=args.export_types)
+    t1 = time.time()
+    response["roundtrip_time"] = t1 - t0
+    check_output(response, args.verbose, args.junit_xml, args.perf_stats_file)
+
+
+@action(recheck_parser)
+def do_recheck(args: argparse.Namespace) -> None:
+    """Ask the daemon to recheck the previous list of files, with optional modifications.
+
+    If at least one of --remove or --update is given, the server will
+    update the list of files to check accordingly and assume that any other files
+    are unchanged.  If none of these flags are given, the server will call stat()
+    on each file last checked to determine its status.
+
+    Files given in --update ought to exist.  Files given in --remove need not exist;
+    if they don't they will be ignored.
+    The lists may be empty but oughtn't contain duplicates or overlap.
+
+    NOTE: The list of files is lost when the daemon is restarted.
+    """
+    t0 = time.time()
+    if args.remove is not None or args.update is not None:
+        response = request(
+            args.status_file,
+            "recheck",
+            export_types=args.export_types,
+            remove=args.remove,
+            update=args.update,
+        )
+    else:
+        response = request(args.status_file, "recheck", export_types=args.export_types)
+    t1 = time.time()
+    response["roundtrip_time"] = t1 - t0
+    check_output(response, args.verbose, args.junit_xml, args.perf_stats_file)
+
+
+@action(suggest_parser)
+def do_suggest(args: argparse.Namespace) -> None:
+    """Ask the daemon for a suggested signature.
+
+    This just prints whatever the daemon reports as output.
+    For now it may be closer to a list of call sites.
+    """
+    response = request(
+        args.status_file,
+        "suggest",
+        function=args.function,
+        json=args.json,
+        callsites=args.callsites,
+        no_errors=args.no_errors,
+        no_any=args.no_any,
+        flex_any=args.flex_any,
+        use_fixme=args.use_fixme,
+        max_guesses=args.max_guesses,
+    )
+    check_output(response, verbose=False, junit_xml=None, perf_stats_file=None)
+
+
+@action(inspect_parser)
+def do_inspect(args: argparse.Namespace) -> None:
+    """Ask daemon to print the type of an expression."""
+    response = request(
+        args.status_file,
+        "inspect",
+        show=args.show,
+        location=args.location,
+        verbosity=args.verbose,
+        limit=args.limit,
+        include_span=args.include_span,
+        include_kind=args.include_kind,
+        include_object_attrs=args.include_object_attrs,
+        union_attrs=args.union_attrs,
+        force_reload=args.force_reload,
+    )
+    check_output(response, verbose=False, junit_xml=None, perf_stats_file=None)
+
+
+def check_output(
+    response: dict[str, Any], verbose: bool, junit_xml: str | None, perf_stats_file: str | None
+) -> None:
+    """Print the output from a check or recheck command.
+
+    Call sys.exit() unless the status code is zero.
+    """
+    if "error" in response:
+        fail(response["error"])
+    try:
+        out, err, status_code = response["out"], response["err"], response["status"]
+    except KeyError:
+        fail(f"Response: {str(response)}")
+    sys.stdout.write(out)
+    sys.stdout.flush()
+    sys.stderr.write(err)
+    if verbose:
+        show_stats(response)
+    if junit_xml:
+        # Lazy import so this import doesn't slow things down when not writing junit
+        from mypy.util import write_junit_xml
+
+        messages = (out + err).splitlines()
+        write_junit_xml(
+            response["roundtrip_time"],
+            bool(err),
+            messages,
+            junit_xml,
+            response["python_version"],
+            response["platform"],
+        )
+    if perf_stats_file:
+        telemetry = response.get("stats", {})
+        with open(perf_stats_file, "w") as f:
+            json.dump(telemetry, f)
+
+    if status_code:
+        sys.exit(status_code)
+
+
+def show_stats(response: Mapping[str, object]) -> None:
+    for key, value in sorted(response.items()):
+        if key not in ("out", "err"):
+            print("%-24s: %10s" % (key, "%.3f" % value if isinstance(value, float) else value))
+        else:
+            value = repr(value)[1:-1]
+            if len(value) > 50:
+                value = value[:40] + " ..."
+            print("%-24s: %s" % (key, value))
+
+
+@action(hang_parser)
+def do_hang(args: argparse.Namespace) -> None:
+    """Hang for 100 seconds, as a debug hack."""
+    print(request(args.status_file, "hang", timeout=1))
+
+
+@action(daemon_parser)
+def do_daemon(args: argparse.Namespace) -> None:
+    """Serve requests in the foreground."""
+    # Lazy import so this import doesn't slow down other commands.
+    from mypy.dmypy_server import Server, process_start_options
+
+    if args.log_file:
+        sys.stdout = sys.stderr = open(args.log_file, "a", buffering=1)
+        fd = sys.stdout.fileno()
+        os.dup2(fd, 2)
+        os.dup2(fd, 1)
+
+    if args.options_data:
+        from mypy.options import Options
+
+        options_dict = pickle.loads(base64.b64decode(args.options_data))
+        options_obj = Options()
+        options = options_obj.apply_changes(options_dict)
+    else:
+        options = process_start_options(args.flags, allow_sources=False)
+
+    Server(options, args.status_file, timeout=args.timeout).serve()
+
+
+@action(help_parser)
+def do_help(args: argparse.Namespace) -> None:
+    """Print full help (same as dmypy --help)."""
+    parser.print_help()
+
+
+# Client-side infrastructure.
+
+
+def request(
+    status_file: str, command: str, *, timeout: int | None = None, **kwds: object
+) -> dict[str, Any]:
+    """Send a request to the daemon.
+
+    Return the JSON dict with the response.
+
+    Raise BadStatus if there is something wrong with the status file
+    or if the process whose pid is in the status file has died.
+
+    Return {'error': <message>} if an IPC operation or receive()
+    raised OSError.  This covers cases such as connection refused or
+    closed prematurely as well as invalid JSON received.
+    """
+    response: dict[str, str] = {}
+    args = dict(kwds)
+    args["command"] = command
+    # Tell the server whether this request was initiated from a human-facing terminal,
+    # so that it can format the type checking output accordingly.
+    args["is_tty"] = sys.stdout.isatty() or should_force_color()
+    args["terminal_width"] = get_terminal_width()
+    bdata = json.dumps(args).encode("utf8")
+    _, name = get_status(status_file)
+    try:
+        with IPCClient(name, timeout) as client:
+            client.write(bdata)
+            response = receive(client)
+    except (OSError, IPCException) as err:
+        return {"error": str(err)}
+    # TODO: Other errors, e.g. ValueError, UnicodeError
+    else:
+        # Display debugging output written to stdout/stderr in the server process for convenience.
+        stdout = response.get("stdout")
+        if stdout:
+            sys.stdout.write(stdout)
+        stderr = response.get("stderr")
+        if stderr:
+            print("-" * 79)
+            print("stderr:")
+            sys.stdout.write(stderr)
+        return response
+
+
+def get_status(status_file: str) -> tuple[int, str]:
+    """Read status file and check if the process is alive.
+
+    Return (pid, connection_name) on success.
+
+    Raise BadStatus if something's wrong.
+    """
+    data = read_status(status_file)
+    return check_status(data)
+
+
+def check_status(data: dict[str, Any]) -> tuple[int, str]:
+    """Check if the process is alive.
+
+    Return (pid, connection_name) on success.
+
+    Raise BadStatus if something's wrong.
+    """
+    if "pid" not in data:
+        raise BadStatus("Invalid status file (no pid field)")
+    pid = data["pid"]
+    if not isinstance(pid, int):
+        raise BadStatus("pid field is not an int")
+    if not alive(pid):
+        raise BadStatus("Daemon has died")
+    if "connection_name" not in data:
+        raise BadStatus("Invalid status file (no connection_name field)")
+    connection_name = data["connection_name"]
+    if not isinstance(connection_name, str):
+        raise BadStatus("connection_name field is not a string")
+    return pid, connection_name
+
+
+def read_status(status_file: str) -> dict[str, object]:
+    """Read status file.
+
+    Raise BadStatus if the status file doesn't exist or contains
+    invalid JSON or the JSON is not a dict.
+    """
+    if not os.path.isfile(status_file):
+        raise BadStatus("No status file found")
+    with open(status_file) as f:
+        try:
+            data = json.load(f)
+        except Exception as e:
+            raise BadStatus("Malformed status file (not JSON)") from e
+    if not isinstance(data, dict):
+        raise BadStatus("Invalid status file (not a dict)")
+    return data
+
+
+def is_running(status_file: str) -> bool:
+    """Check if the server is running cleanly"""
+    try:
+        get_status(status_file)
+    except BadStatus:
+        return False
+    return True
+
+
+# Run main().
+def console_entry() -> None:
+    main(sys.argv[1:])

二進制
venv/lib/python3.11/site-packages/mypy/dmypy_os.cpython-311-x86_64-linux-gnu.so


+ 42 - 0
venv/lib/python3.11/site-packages/mypy/dmypy_os.py

@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+import sys
+from typing import Any, Callable
+
+if sys.platform == "win32":
+    import ctypes
+    import subprocess
+    from ctypes.wintypes import DWORD, HANDLE
+
+    PROCESS_QUERY_LIMITED_INFORMATION = ctypes.c_ulong(0x1000)
+
+    kernel32 = ctypes.windll.kernel32
+    OpenProcess: Callable[[DWORD, int, int], HANDLE] = kernel32.OpenProcess
+    GetExitCodeProcess: Callable[[HANDLE, Any], int] = kernel32.GetExitCodeProcess
+else:
+    import os
+    import signal
+
+
+def alive(pid: int) -> bool:
+    """Is the process alive?"""
+    if sys.platform == "win32":
+        # why can't anything be easy...
+        status = DWORD()
+        handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
+        GetExitCodeProcess(handle, ctypes.byref(status))
+        return status.value == 259  # STILL_ACTIVE
+    else:
+        try:
+            os.kill(pid, 0)
+        except OSError:
+            return False
+        return True
+
+
+def kill(pid: int) -> None:
+    """Kill the process."""
+    if sys.platform == "win32":
+        subprocess.check_output(f"taskkill /pid {pid} /f /t")
+    else:
+        os.kill(pid, signal.SIGKILL)

二進制
venv/lib/python3.11/site-packages/mypy/dmypy_server.cpython-311-x86_64-linux-gnu.so


+ 1063 - 0
venv/lib/python3.11/site-packages/mypy/dmypy_server.py

@@ -0,0 +1,1063 @@
+"""Server for mypy daemon mode.
+
+This implements a daemon process which keeps useful state in memory
+to enable fine-grained incremental reprocessing of changes.
+"""
+
+from __future__ import annotations
+
+import argparse
+import base64
+import io
+import json
+import os
+import pickle
+import subprocess
+import sys
+import time
+import traceback
+from contextlib import redirect_stderr, redirect_stdout
+from typing import AbstractSet, Any, Callable, Final, List, Sequence, Tuple
+from typing_extensions import TypeAlias as _TypeAlias
+
+import mypy.build
+import mypy.errors
+import mypy.main
+from mypy.dmypy_util import receive
+from mypy.find_sources import InvalidSourceList, create_source_list
+from mypy.fscache import FileSystemCache
+from mypy.fswatcher import FileData, FileSystemWatcher
+from mypy.inspections import InspectionEngine
+from mypy.ipc import IPCServer
+from mypy.modulefinder import BuildSource, FindModuleCache, SearchPaths, compute_search_paths
+from mypy.options import Options
+from mypy.server.update import FineGrainedBuildManager, refresh_suppressed_submodules
+from mypy.suggestions import SuggestionEngine, SuggestionFailure
+from mypy.typestate import reset_global_state
+from mypy.util import FancyFormatter, count_stats
+from mypy.version import __version__
+
+MEM_PROFILE: Final = False  # If True, dump memory profile after initialization
+
+if sys.platform == "win32":
+    from subprocess import STARTUPINFO
+
+    def daemonize(
+        options: Options, status_file: str, timeout: int | None = None, log_file: str | None = None
+    ) -> int:
+        """Create the daemon process via "dmypy daemon" and pass options via command line
+
+        When creating the daemon grandchild, we create it in a new console, which is
+        started hidden. We cannot use DETACHED_PROCESS since it will cause console windows
+        to pop up when starting. See
+        https://github.com/python/cpython/pull/4150#issuecomment-340215696
+        for more on why we can't have nice things.
+
+        It also pickles the options to be unpickled by mypy.
+        """
+        command = [sys.executable, "-m", "mypy.dmypy", "--status-file", status_file, "daemon"]
+        pickled_options = pickle.dumps(options.snapshot())
+        command.append(f'--options-data="{base64.b64encode(pickled_options).decode()}"')
+        if timeout:
+            command.append(f"--timeout={timeout}")
+        if log_file:
+            command.append(f"--log-file={log_file}")
+        info = STARTUPINFO()
+        info.dwFlags = 0x1  # STARTF_USESHOWWINDOW aka use wShowWindow's value
+        info.wShowWindow = 0  # SW_HIDE aka make the window invisible
+        try:
+            subprocess.Popen(command, creationflags=0x10, startupinfo=info)  # CREATE_NEW_CONSOLE
+            return 0
+        except subprocess.CalledProcessError as e:
+            return e.returncode
+
+else:
+
+    def _daemonize_cb(func: Callable[[], None], log_file: str | None = None) -> int:
+        """Arrange to call func() in a grandchild of the current process.
+
+        Return 0 for success, exit status for failure, negative if
+        subprocess killed by signal.
+        """
+        # See https://stackoverflow.com/questions/473620/how-do-you-create-a-daemon-in-python
+        sys.stdout.flush()
+        sys.stderr.flush()
+        pid = os.fork()
+        if pid:
+            # Parent process: wait for child in case things go bad there.
+            npid, sts = os.waitpid(pid, 0)
+            sig = sts & 0xFF
+            if sig:
+                print("Child killed by signal", sig)
+                return -sig
+            sts = sts >> 8
+            if sts:
+                print("Child exit status", sts)
+            return sts
+        # Child process: do a bunch of UNIX stuff and then fork a grandchild.
+        try:
+            os.setsid()  # Detach controlling terminal
+            os.umask(0o27)
+            devnull = os.open("/dev/null", os.O_RDWR)
+            os.dup2(devnull, 0)
+            os.dup2(devnull, 1)
+            os.dup2(devnull, 2)
+            os.close(devnull)
+            pid = os.fork()
+            if pid:
+                # Child is done, exit to parent.
+                os._exit(0)
+            # Grandchild: run the server.
+            if log_file:
+                sys.stdout = sys.stderr = open(log_file, "a", buffering=1)
+                fd = sys.stdout.fileno()
+                os.dup2(fd, 2)
+                os.dup2(fd, 1)
+            func()
+        finally:
+            # Make sure we never get back into the caller.
+            os._exit(1)
+
+    def daemonize(
+        options: Options, status_file: str, timeout: int | None = None, log_file: str | None = None
+    ) -> int:
+        """Run the mypy daemon in a grandchild of the current process
+
+        Return 0 for success, exit status for failure, negative if
+        subprocess killed by signal.
+        """
+        return _daemonize_cb(Server(options, status_file, timeout).serve, log_file)
+
+
+# Server code.
+
+CONNECTION_NAME: Final = "dmypy"
+
+
+def process_start_options(flags: list[str], allow_sources: bool) -> Options:
+    _, options = mypy.main.process_options(
+        ["-i"] + flags, require_targets=False, server_options=True
+    )
+    if options.report_dirs:
+        print("dmypy: Ignoring report generation settings. Start/restart cannot generate reports.")
+    if options.junit_xml:
+        print(
+            "dmypy: Ignoring report generation settings. "
+            "Start/restart does not support --junit-xml. Pass it to check/recheck instead"
+        )
+        options.junit_xml = None
+    if not options.incremental:
+        sys.exit("dmypy: start/restart should not disable incremental mode")
+    if options.follow_imports not in ("skip", "error", "normal"):
+        sys.exit("dmypy: follow-imports=silent not supported")
+    return options
+
+
+def ignore_suppressed_imports(module: str) -> bool:
+    """Can we skip looking for newly unsuppressed imports to module?"""
+    # Various submodules of 'encodings' can be suppressed, since it
+    # uses module-level '__getattr__'. Skip them since there are many
+    # of them, and following imports to them is kind of pointless.
+    return module.startswith("encodings.")
+
+
+ModulePathPair: _TypeAlias = Tuple[str, str]
+ModulePathPairs: _TypeAlias = List[ModulePathPair]
+ChangesAndRemovals: _TypeAlias = Tuple[ModulePathPairs, ModulePathPairs]
+
+
+class Server:
+    # NOTE: the instance is constructed in the parent process but
+    # serve() is called in the grandchild (by daemonize()).
+
+    def __init__(self, options: Options, status_file: str, timeout: int | None = None) -> None:
+        """Initialize the server with the desired mypy flags."""
+        self.options = options
+        # Snapshot the options info before we muck with it, to detect changes
+        self.options_snapshot = options.snapshot()
+        self.timeout = timeout
+        self.fine_grained_manager: FineGrainedBuildManager | None = None
+
+        if os.path.isfile(status_file):
+            os.unlink(status_file)
+
+        self.fscache = FileSystemCache()
+
+        options.raise_exceptions = True
+        options.incremental = True
+        options.fine_grained_incremental = True
+        options.show_traceback = True
+        if options.use_fine_grained_cache:
+            # Using fine_grained_cache implies generating and caring
+            # about the fine grained cache
+            options.cache_fine_grained = True
+        else:
+            options.cache_dir = os.devnull
+        # Fine-grained incremental doesn't support general partial types
+        # (details in https://github.com/python/mypy/issues/4492)
+        options.local_partial_types = True
+        self.status_file = status_file
+
+        # Since the object is created in the parent process we can check
+        # the output terminal options here.
+        self.formatter = FancyFormatter(sys.stdout, sys.stderr, options.hide_error_codes)
+
+    def _response_metadata(self) -> dict[str, str]:
+        py_version = f"{self.options.python_version[0]}_{self.options.python_version[1]}"
+        return {"platform": self.options.platform, "python_version": py_version}
+
+    def serve(self) -> None:
+        """Serve requests, synchronously (no thread or fork)."""
+        command = None
+        server = IPCServer(CONNECTION_NAME, self.timeout)
+        try:
+            with open(self.status_file, "w") as f:
+                json.dump({"pid": os.getpid(), "connection_name": server.connection_name}, f)
+                f.write("\n")  # I like my JSON with a trailing newline
+            while True:
+                with server:
+                    data = receive(server)
+                    debug_stdout = io.StringIO()
+                    debug_stderr = io.StringIO()
+                    sys.stdout = debug_stdout
+                    sys.stderr = debug_stderr
+                    resp: dict[str, Any] = {}
+                    if "command" not in data:
+                        resp = {"error": "No command found in request"}
+                    else:
+                        command = data["command"]
+                        if not isinstance(command, str):
+                            resp = {"error": "Command is not a string"}
+                        else:
+                            command = data.pop("command")
+                            try:
+                                resp = self.run_command(command, data)
+                            except Exception:
+                                # If we are crashing, report the crash to the client
+                                tb = traceback.format_exception(*sys.exc_info())
+                                resp = {"error": "Daemon crashed!\n" + "".join(tb)}
+                                resp.update(self._response_metadata())
+                                resp["stdout"] = debug_stdout.getvalue()
+                                resp["stderr"] = debug_stderr.getvalue()
+                                server.write(json.dumps(resp).encode("utf8"))
+                                raise
+                    resp["stdout"] = debug_stdout.getvalue()
+                    resp["stderr"] = debug_stderr.getvalue()
+                    try:
+                        resp.update(self._response_metadata())
+                        server.write(json.dumps(resp).encode("utf8"))
+                    except OSError:
+                        pass  # Maybe the client hung up
+                    if command == "stop":
+                        reset_global_state()
+                        sys.exit(0)
+        finally:
+            # If the final command is something other than a clean
+            # stop, remove the status file. (We can't just
+            # simplify the logic and always remove the file, since
+            # that could cause us to remove a future server's
+            # status file.)
+            if command != "stop":
+                os.unlink(self.status_file)
+            try:
+                server.cleanup()  # try to remove the socket dir on Linux
+            except OSError:
+                pass
+            exc_info = sys.exc_info()
+            if exc_info[0] and exc_info[0] is not SystemExit:
+                traceback.print_exception(*exc_info)
+
+    def run_command(self, command: str, data: dict[str, object]) -> dict[str, object]:
+        """Run a specific command from the registry."""
+        key = "cmd_" + command
+        method = getattr(self.__class__, key, None)
+        if method is None:
+            return {"error": f"Unrecognized command '{command}'"}
+        else:
+            if command not in {"check", "recheck", "run"}:
+                # Only the above commands use some error formatting.
+                del data["is_tty"]
+                del data["terminal_width"]
+            ret = method(self, **data)
+            assert isinstance(ret, dict)
+            return ret
+
+    # Command functions (run in the server via RPC).
+
+    def cmd_status(self, fswatcher_dump_file: str | None = None) -> dict[str, object]:
+        """Return daemon status."""
+        res: dict[str, object] = {}
+        res.update(get_meminfo())
+        if fswatcher_dump_file:
+            data = self.fswatcher.dump_file_data() if hasattr(self, "fswatcher") else {}
+            # Using .dumps and then writing was noticeably faster than using dump
+            s = json.dumps(data)
+            with open(fswatcher_dump_file, "w") as f:
+                f.write(s)
+        return res
+
+    def cmd_stop(self) -> dict[str, object]:
+        """Stop daemon."""
+        # We need to remove the status file *before* we complete the
+        # RPC. Otherwise a race condition exists where a subsequent
+        # command can see a status file from a dying server and think
+        # it is a live one.
+        os.unlink(self.status_file)
+        return {}
+
+    def cmd_run(
+        self,
+        version: str,
+        args: Sequence[str],
+        export_types: bool,
+        is_tty: bool,
+        terminal_width: int,
+    ) -> dict[str, object]:
+        """Check a list of files, triggering a restart if needed."""
+        stderr = io.StringIO()
+        stdout = io.StringIO()
+        try:
+            # Process options can exit on improper arguments, so we need to catch that and
+            # capture stderr so the client can report it
+            with redirect_stderr(stderr):
+                with redirect_stdout(stdout):
+                    sources, options = mypy.main.process_options(
+                        ["-i"] + list(args),
+                        require_targets=True,
+                        server_options=True,
+                        fscache=self.fscache,
+                        program="mypy-daemon",
+                        header=argparse.SUPPRESS,
+                    )
+            # Signal that we need to restart if the options have changed
+            if not options.compare_stable(self.options_snapshot):
+                return {"restart": "configuration changed"}
+            if __version__ != version:
+                return {"restart": "mypy version changed"}
+            if self.fine_grained_manager:
+                manager = self.fine_grained_manager.manager
+                start_plugins_snapshot = manager.plugins_snapshot
+                _, current_plugins_snapshot = mypy.build.load_plugins(
+                    options, manager.errors, sys.stdout, extra_plugins=()
+                )
+                if current_plugins_snapshot != start_plugins_snapshot:
+                    return {"restart": "plugins changed"}
+        except InvalidSourceList as err:
+            return {"out": "", "err": str(err), "status": 2}
+        except SystemExit as e:
+            return {"out": stdout.getvalue(), "err": stderr.getvalue(), "status": e.code}
+        return self.check(sources, export_types, is_tty, terminal_width)
+
+    def cmd_check(
+        self, files: Sequence[str], export_types: bool, is_tty: bool, terminal_width: int
+    ) -> dict[str, object]:
+        """Check a list of files."""
+        try:
+            sources = create_source_list(files, self.options, self.fscache)
+        except InvalidSourceList as err:
+            return {"out": "", "err": str(err), "status": 2}
+        return self.check(sources, export_types, is_tty, terminal_width)
+
+    def cmd_recheck(
+        self,
+        is_tty: bool,
+        terminal_width: int,
+        export_types: bool,
+        remove: list[str] | None = None,
+        update: list[str] | None = None,
+    ) -> dict[str, object]:
+        """Check the same list of files we checked most recently.
+
+        If remove/update is given, they modify the previous list;
+        if all are None, stat() is called for each file in the previous list.
+        """
+        t0 = time.time()
+        if not self.fine_grained_manager:
+            return {"error": "Command 'recheck' is only valid after a 'check' command"}
+        sources = self.previous_sources
+        if remove:
+            removals = set(remove)
+            sources = [s for s in sources if s.path and s.path not in removals]
+        if update:
+            known = {s.path for s in sources if s.path}
+            added = [p for p in update if p not in known]
+            try:
+                added_sources = create_source_list(added, self.options, self.fscache)
+            except InvalidSourceList as err:
+                return {"out": "", "err": str(err), "status": 2}
+            sources = sources + added_sources  # Make a copy!
+        t1 = time.time()
+        manager = self.fine_grained_manager.manager
+        manager.log(f"fine-grained increment: cmd_recheck: {t1 - t0:.3f}s")
+        self.options.export_types = export_types
+        if not self.following_imports():
+            messages = self.fine_grained_increment(sources, remove, update)
+        else:
+            assert remove is None and update is None
+            messages = self.fine_grained_increment_follow_imports(sources)
+        res = self.increment_output(messages, sources, is_tty, terminal_width)
+        self.flush_caches()
+        self.update_stats(res)
+        return res
+
+    def check(
+        self, sources: list[BuildSource], export_types: bool, is_tty: bool, terminal_width: int
+    ) -> dict[str, Any]:
+        """Check using fine-grained incremental mode.
+
+        If is_tty is True format the output nicely with colors and summary line
+        (unless disabled in self.options). Also pass the terminal_width to formatter.
+        """
+        self.options.export_types = export_types
+        if not self.fine_grained_manager:
+            res = self.initialize_fine_grained(sources, is_tty, terminal_width)
+        else:
+            if not self.following_imports():
+                messages = self.fine_grained_increment(sources)
+            else:
+                messages = self.fine_grained_increment_follow_imports(sources)
+            res = self.increment_output(messages, sources, is_tty, terminal_width)
+        self.flush_caches()
+        self.update_stats(res)
+        return res
+
+    def flush_caches(self) -> None:
+        self.fscache.flush()
+        if self.fine_grained_manager:
+            self.fine_grained_manager.flush_cache()
+
+    def update_stats(self, res: dict[str, Any]) -> None:
+        if self.fine_grained_manager:
+            manager = self.fine_grained_manager.manager
+            manager.dump_stats()
+            res["stats"] = manager.stats
+            manager.stats = {}
+
+    def following_imports(self) -> bool:
+        """Are we following imports?"""
+        # TODO: What about silent?
+        return self.options.follow_imports == "normal"
+
+    def initialize_fine_grained(
+        self, sources: list[BuildSource], is_tty: bool, terminal_width: int
+    ) -> dict[str, Any]:
+        self.fswatcher = FileSystemWatcher(self.fscache)
+        t0 = time.time()
+        self.update_sources(sources)
+        t1 = time.time()
+        try:
+            result = mypy.build.build(sources=sources, options=self.options, fscache=self.fscache)
+        except mypy.errors.CompileError as e:
+            output = "".join(s + "\n" for s in e.messages)
+            if e.use_stdout:
+                out, err = output, ""
+            else:
+                out, err = "", output
+            return {"out": out, "err": err, "status": 2}
+        messages = result.errors
+        self.fine_grained_manager = FineGrainedBuildManager(result)
+
+        if self.following_imports():
+            sources = find_all_sources_in_build(self.fine_grained_manager.graph, sources)
+            self.update_sources(sources)
+
+        self.previous_sources = sources
+
+        # If we are using the fine-grained cache, build hasn't actually done
+        # the typechecking on the updated files yet.
+        # Run a fine-grained update starting from the cached data
+        if result.used_cache:
+            t2 = time.time()
+            # Pull times and hashes out of the saved_cache and stick them into
+            # the fswatcher, so we pick up the changes.
+            for state in self.fine_grained_manager.graph.values():
+                meta = state.meta
+                if meta is None:
+                    continue
+                assert state.path is not None
+                self.fswatcher.set_file_data(
+                    state.path,
+                    FileData(st_mtime=float(meta.mtime), st_size=meta.size, hash=meta.hash),
+                )
+
+            changed, removed = self.find_changed(sources)
+            changed += self.find_added_suppressed(
+                self.fine_grained_manager.graph,
+                set(),
+                self.fine_grained_manager.manager.search_paths,
+            )
+
+            # Find anything that has had its dependency list change
+            for state in self.fine_grained_manager.graph.values():
+                if not state.is_fresh():
+                    assert state.path is not None
+                    changed.append((state.id, state.path))
+
+            t3 = time.time()
+            # Run an update
+            messages = self.fine_grained_manager.update(changed, removed)
+
+            if self.following_imports():
+                # We need to do another update to any new files found by following imports.
+                messages = self.fine_grained_increment_follow_imports(sources)
+
+            t4 = time.time()
+            self.fine_grained_manager.manager.add_stats(
+                update_sources_time=t1 - t0,
+                build_time=t2 - t1,
+                find_changes_time=t3 - t2,
+                fg_update_time=t4 - t3,
+                files_changed=len(removed) + len(changed),
+            )
+
+        else:
+            # Stores the initial state of sources as a side effect.
+            self.fswatcher.find_changed()
+
+        if MEM_PROFILE:
+            from mypy.memprofile import print_memory_profile
+
+            print_memory_profile(run_gc=False)
+
+        __, n_notes, __ = count_stats(messages)
+        status = 1 if messages and n_notes < len(messages) else 0
+        messages = self.pretty_messages(messages, len(sources), is_tty, terminal_width)
+        return {"out": "".join(s + "\n" for s in messages), "err": "", "status": status}
+
+    def fine_grained_increment(
+        self,
+        sources: list[BuildSource],
+        remove: list[str] | None = None,
+        update: list[str] | None = None,
+    ) -> list[str]:
+        """Perform a fine-grained type checking increment.
+
+        If remove and update are None, determine changed paths by using
+        fswatcher. Otherwise, assume that only these files have changes.
+
+        Args:
+            sources: sources passed on the command line
+            remove: paths of files that have been removed
+            update: paths of files that have been changed or created
+        """
+        assert self.fine_grained_manager is not None
+        manager = self.fine_grained_manager.manager
+
+        t0 = time.time()
+        if remove is None and update is None:
+            # Use the fswatcher to determine which files were changed
+            # (updated or added) or removed.
+            self.update_sources(sources)
+            changed, removed = self.find_changed(sources)
+        else:
+            # Use the remove/update lists to update fswatcher.
+            # This avoids calling stat() for unchanged files.
+            changed, removed = self.update_changed(sources, remove or [], update or [])
+        changed += self.find_added_suppressed(
+            self.fine_grained_manager.graph, set(), manager.search_paths
+        )
+        manager.search_paths = compute_search_paths(sources, manager.options, manager.data_dir)
+        t1 = time.time()
+        manager.log(f"fine-grained increment: find_changed: {t1 - t0:.3f}s")
+        messages = self.fine_grained_manager.update(changed, removed)
+        t2 = time.time()
+        manager.log(f"fine-grained increment: update: {t2 - t1:.3f}s")
+        manager.add_stats(
+            find_changes_time=t1 - t0,
+            fg_update_time=t2 - t1,
+            files_changed=len(removed) + len(changed),
+        )
+
+        self.previous_sources = sources
+        return messages
+
+    def fine_grained_increment_follow_imports(self, sources: list[BuildSource]) -> list[str]:
+        """Like fine_grained_increment, but follow imports."""
+        t0 = time.time()
+
+        # TODO: Support file events
+
+        assert self.fine_grained_manager is not None
+        fine_grained_manager = self.fine_grained_manager
+        graph = fine_grained_manager.graph
+        manager = fine_grained_manager.manager
+
+        orig_modules = list(graph.keys())
+
+        self.update_sources(sources)
+        changed_paths = self.fswatcher.find_changed()
+        manager.search_paths = compute_search_paths(sources, manager.options, manager.data_dir)
+
+        t1 = time.time()
+        manager.log(f"fine-grained increment: find_changed: {t1 - t0:.3f}s")
+
+        seen = {source.module for source in sources}
+
+        # Find changed modules reachable from roots (or in roots) already in graph.
+        changed, new_files = self.find_reachable_changed_modules(
+            sources, graph, seen, changed_paths
+        )
+        sources.extend(new_files)
+
+        # Process changes directly reachable from roots.
+        messages = fine_grained_manager.update(changed, [], followed=True)
+
+        # Follow deps from changed modules (still within graph).
+        worklist = changed.copy()
+        while worklist:
+            module = worklist.pop()
+            if module[0] not in graph:
+                continue
+            sources2 = self.direct_imports(module, graph)
+            # Filter anything already seen before. This prevents
+            # infinite looping if there are any self edges. (Self
+            # edges are maybe a bug, but...)
+            sources2 = [source for source in sources2 if source.module not in seen]
+            changed, new_files = self.find_reachable_changed_modules(
+                sources2, graph, seen, changed_paths
+            )
+            self.update_sources(new_files)
+            messages = fine_grained_manager.update(changed, [], followed=True)
+            worklist.extend(changed)
+
+        t2 = time.time()
+
+        def refresh_file(module: str, path: str) -> list[str]:
+            return fine_grained_manager.update([(module, path)], [], followed=True)
+
+        for module_id, state in list(graph.items()):
+            new_messages = refresh_suppressed_submodules(
+                module_id, state.path, fine_grained_manager.deps, graph, self.fscache, refresh_file
+            )
+            if new_messages is not None:
+                messages = new_messages
+
+        t3 = time.time()
+
+        # There may be new files that became available, currently treated as
+        # suppressed imports. Process them.
+        while True:
+            new_unsuppressed = self.find_added_suppressed(graph, seen, manager.search_paths)
+            if not new_unsuppressed:
+                break
+            new_files = [BuildSource(mod[1], mod[0], followed=True) for mod in new_unsuppressed]
+            sources.extend(new_files)
+            self.update_sources(new_files)
+            messages = fine_grained_manager.update(new_unsuppressed, [], followed=True)
+
+            for module_id, path in new_unsuppressed:
+                new_messages = refresh_suppressed_submodules(
+                    module_id, path, fine_grained_manager.deps, graph, self.fscache, refresh_file
+                )
+                if new_messages is not None:
+                    messages = new_messages
+
+        t4 = time.time()
+
+        # Find all original modules in graph that were not reached -- they are deleted.
+        to_delete = []
+        for module_id in orig_modules:
+            if module_id not in graph:
+                continue
+            if module_id not in seen:
+                module_path = graph[module_id].path
+                assert module_path is not None
+                to_delete.append((module_id, module_path))
+        if to_delete:
+            messages = fine_grained_manager.update([], to_delete)
+
+        fix_module_deps(graph)
+
+        self.previous_sources = find_all_sources_in_build(graph)
+        self.update_sources(self.previous_sources)
+
+        # Store current file state as side effect
+        self.fswatcher.find_changed()
+
+        t5 = time.time()
+
+        manager.log(f"fine-grained increment: update: {t5 - t1:.3f}s")
+        manager.add_stats(
+            find_changes_time=t1 - t0,
+            fg_update_time=t2 - t1,
+            refresh_suppressed_time=t3 - t2,
+            find_added_supressed_time=t4 - t3,
+            cleanup_time=t5 - t4,
+        )
+
+        return messages
+
+    def find_reachable_changed_modules(
+        self,
+        roots: list[BuildSource],
+        graph: mypy.build.Graph,
+        seen: set[str],
+        changed_paths: AbstractSet[str],
+    ) -> tuple[list[tuple[str, str]], list[BuildSource]]:
+        """Follow imports within graph from given sources until hitting changed modules.
+
+        If we find a changed module, we can't continue following imports as the imports
+        may have changed.
+
+        Args:
+            roots: modules where to start search from
+            graph: module graph to use for the search
+            seen: modules we've seen before that won't be visited (mutated here!!)
+            changed_paths: which paths have changed (stop search here and return any found)
+
+        Return (encountered reachable changed modules,
+                unchanged files not in sources_set traversed).
+        """
+        changed = []
+        new_files = []
+        worklist = roots.copy()
+        seen.update(source.module for source in worklist)
+        while worklist:
+            nxt = worklist.pop()
+            if nxt.module not in seen:
+                seen.add(nxt.module)
+                new_files.append(nxt)
+            if nxt.path in changed_paths:
+                assert nxt.path is not None  # TODO
+                changed.append((nxt.module, nxt.path))
+            elif nxt.module in graph:
+                state = graph[nxt.module]
+                for dep in state.dependencies:
+                    if dep not in seen:
+                        seen.add(dep)
+                        worklist.append(BuildSource(graph[dep].path, graph[dep].id, followed=True))
+        return changed, new_files
+
+    def direct_imports(
+        self, module: tuple[str, str], graph: mypy.build.Graph
+    ) -> list[BuildSource]:
+        """Return the direct imports of module not included in seen."""
+        state = graph[module[0]]
+        return [BuildSource(graph[dep].path, dep, followed=True) for dep in state.dependencies]
+
+    def find_added_suppressed(
+        self, graph: mypy.build.Graph, seen: set[str], search_paths: SearchPaths
+    ) -> list[tuple[str, str]]:
+        """Find suppressed modules that have been added (and not included in seen).
+
+        Args:
+            seen: reachable modules we've seen before (mutated here!!)
+
+        Return suppressed, added modules.
+        """
+        all_suppressed = set()
+        for state in graph.values():
+            all_suppressed |= state.suppressed_set
+
+        # Filter out things that shouldn't actually be considered suppressed.
+        #
+        # TODO: Figure out why these are treated as suppressed
+        all_suppressed = {
+            module
+            for module in all_suppressed
+            if module not in graph and not ignore_suppressed_imports(module)
+        }
+
+        # Optimization: skip top-level packages that are obviously not
+        # there, to avoid calling the relatively slow find_module()
+        # below too many times.
+        packages = {module.split(".", 1)[0] for module in all_suppressed}
+        packages = filter_out_missing_top_level_packages(packages, search_paths, self.fscache)
+
+        # TODO: Namespace packages
+
+        finder = FindModuleCache(search_paths, self.fscache, self.options)
+
+        found = []
+
+        for module in all_suppressed:
+            top_level_pkg = module.split(".", 1)[0]
+            if top_level_pkg not in packages:
+                # Fast path: non-existent top-level package
+                continue
+            result = finder.find_module(module, fast_path=True)
+            if isinstance(result, str) and module not in seen:
+                # When not following imports, we only follow imports to .pyi files.
+                if not self.following_imports() and not result.endswith(".pyi"):
+                    continue
+                found.append((module, result))
+                seen.add(module)
+
+        return found
+
+    def increment_output(
+        self, messages: list[str], sources: list[BuildSource], is_tty: bool, terminal_width: int
+    ) -> dict[str, Any]:
+        status = 1 if messages else 0
+        messages = self.pretty_messages(messages, len(sources), is_tty, terminal_width)
+        return {"out": "".join(s + "\n" for s in messages), "err": "", "status": status}
+
+    def pretty_messages(
+        self,
+        messages: list[str],
+        n_sources: int,
+        is_tty: bool = False,
+        terminal_width: int | None = None,
+    ) -> list[str]:
+        use_color = self.options.color_output and is_tty
+        fit_width = self.options.pretty and is_tty
+        if fit_width:
+            messages = self.formatter.fit_in_terminal(
+                messages, fixed_terminal_width=terminal_width
+            )
+        if self.options.error_summary:
+            summary: str | None = None
+            n_errors, n_notes, n_files = count_stats(messages)
+            if n_errors:
+                summary = self.formatter.format_error(
+                    n_errors, n_files, n_sources, use_color=use_color
+                )
+            elif not messages or n_notes == len(messages):
+                summary = self.formatter.format_success(n_sources, use_color)
+            if summary:
+                # Create new list to avoid appending multiple summaries on successive runs.
+                messages = messages + [summary]
+        if use_color:
+            messages = [self.formatter.colorize(m) for m in messages]
+        return messages
+
+    def update_sources(self, sources: list[BuildSource]) -> None:
+        paths = [source.path for source in sources if source.path is not None]
+        if self.following_imports():
+            # Filter out directories (used for namespace packages).
+            paths = [path for path in paths if self.fscache.isfile(path)]
+        self.fswatcher.add_watched_paths(paths)
+
+    def update_changed(
+        self, sources: list[BuildSource], remove: list[str], update: list[str]
+    ) -> ChangesAndRemovals:
+        changed_paths = self.fswatcher.update_changed(remove, update)
+        return self._find_changed(sources, changed_paths)
+
+    def find_changed(self, sources: list[BuildSource]) -> ChangesAndRemovals:
+        changed_paths = self.fswatcher.find_changed()
+        return self._find_changed(sources, changed_paths)
+
+    def _find_changed(
+        self, sources: list[BuildSource], changed_paths: AbstractSet[str]
+    ) -> ChangesAndRemovals:
+        # Find anything that has been added or modified
+        changed = [
+            (source.module, source.path)
+            for source in sources
+            if source.path and source.path in changed_paths
+        ]
+
+        # Now find anything that has been removed from the build
+        modules = {source.module for source in sources}
+        omitted = [source for source in self.previous_sources if source.module not in modules]
+        removed = []
+        for source in omitted:
+            path = source.path
+            assert path
+            removed.append((source.module, path))
+
+        # Always add modules that were (re-)added, since they may be detected as not changed by
+        # fswatcher (if they were actually not changed), but they may still need to be checked
+        # in case they had errors before they were deleted from sources on previous runs.
+        previous_modules = {source.module for source in self.previous_sources}
+        changed_set = set(changed)
+        changed.extend(
+            [
+                (source.module, source.path)
+                for source in sources
+                if source.path
+                and source.module not in previous_modules
+                and (source.module, source.path) not in changed_set
+            ]
+        )
+
+        # Find anything that has had its module path change because of added or removed __init__s
+        last = {s.path: s.module for s in self.previous_sources}
+        for s in sources:
+            assert s.path
+            if s.path in last and last[s.path] != s.module:
+                # Mark it as removed from its old name and changed at its new name
+                removed.append((last[s.path], s.path))
+                changed.append((s.module, s.path))
+
+        return changed, removed
+
+    def cmd_inspect(
+        self,
+        show: str,
+        location: str,
+        verbosity: int = 0,
+        limit: int = 0,
+        include_span: bool = False,
+        include_kind: bool = False,
+        include_object_attrs: bool = False,
+        union_attrs: bool = False,
+        force_reload: bool = False,
+    ) -> dict[str, object]:
+        """Locate and inspect expression(s)."""
+        if not self.fine_grained_manager:
+            return {
+                "error": 'Command "inspect" is only valid after a "check" command'
+                " (that produces no parse errors)"
+            }
+        engine = InspectionEngine(
+            self.fine_grained_manager,
+            verbosity=verbosity,
+            limit=limit,
+            include_span=include_span,
+            include_kind=include_kind,
+            include_object_attrs=include_object_attrs,
+            union_attrs=union_attrs,
+            force_reload=force_reload,
+        )
+        old_inspections = self.options.inspections
+        self.options.inspections = True
+        try:
+            if show == "type":
+                result = engine.get_type(location)
+            elif show == "attrs":
+                result = engine.get_attrs(location)
+            elif show == "definition":
+                result = engine.get_definition(location)
+            else:
+                assert False, "Unknown inspection kind"
+        finally:
+            self.options.inspections = old_inspections
+        if "out" in result:
+            assert isinstance(result["out"], str)
+            result["out"] += "\n"
+        return result
+
+    def cmd_suggest(self, function: str, callsites: bool, **kwargs: Any) -> dict[str, object]:
+        """Suggest a signature for a function."""
+        if not self.fine_grained_manager:
+            return {
+                "error": "Command 'suggest' is only valid after a 'check' command"
+                " (that produces no parse errors)"
+            }
+        engine = SuggestionEngine(self.fine_grained_manager, **kwargs)
+        try:
+            if callsites:
+                out = engine.suggest_callsites(function)
+            else:
+                out = engine.suggest(function)
+        except SuggestionFailure as err:
+            return {"error": str(err)}
+        else:
+            if not out:
+                out = "No suggestions\n"
+            elif not out.endswith("\n"):
+                out += "\n"
+            return {"out": out, "err": "", "status": 0}
+        finally:
+            self.flush_caches()
+
+    def cmd_hang(self) -> dict[str, object]:
+        """Hang for 100 seconds, as a debug hack."""
+        time.sleep(100)
+        return {}
+
+
+# Misc utilities.
+
+
+MiB: Final = 2**20
+
+
+def get_meminfo() -> dict[str, Any]:
+    res: dict[str, Any] = {}
+    try:
+        import psutil
+    except ImportError:
+        res["memory_psutil_missing"] = (
+            "psutil not found, run pip install mypy[dmypy] "
+            "to install the needed components for dmypy"
+        )
+    else:
+        process = psutil.Process()
+        meminfo = process.memory_info()
+        res["memory_rss_mib"] = meminfo.rss / MiB
+        res["memory_vms_mib"] = meminfo.vms / MiB
+        if sys.platform == "win32":
+            res["memory_maxrss_mib"] = meminfo.peak_wset / MiB
+        else:
+            # See https://stackoverflow.com/questions/938733/total-memory-used-by-python-process
+            import resource  # Since it doesn't exist on Windows.
+
+            rusage = resource.getrusage(resource.RUSAGE_SELF)
+            if sys.platform == "darwin":
+                factor = 1
+            else:
+                factor = 1024  # Linux
+            res["memory_maxrss_mib"] = rusage.ru_maxrss * factor / MiB
+    return res
+
+
+def find_all_sources_in_build(
+    graph: mypy.build.Graph, extra: Sequence[BuildSource] = ()
+) -> list[BuildSource]:
+    result = list(extra)
+    seen = {source.module for source in result}
+    for module, state in graph.items():
+        if module not in seen:
+            result.append(BuildSource(state.path, module))
+    return result
+
+
+def fix_module_deps(graph: mypy.build.Graph) -> None:
+    """After an incremental update, update module dependencies to reflect the new state.
+
+    This can make some suppressed dependencies non-suppressed, and vice versa (if modules
+    have been added to or removed from the build).
+    """
+    for module, state in graph.items():
+        new_suppressed = []
+        new_dependencies = []
+        for dep in state.dependencies + state.suppressed:
+            if dep in graph:
+                new_dependencies.append(dep)
+            else:
+                new_suppressed.append(dep)
+        state.dependencies = new_dependencies
+        state.dependencies_set = set(new_dependencies)
+        state.suppressed = new_suppressed
+        state.suppressed_set = set(new_suppressed)
+
+
+def filter_out_missing_top_level_packages(
+    packages: set[str], search_paths: SearchPaths, fscache: FileSystemCache
+) -> set[str]:
+    """Quickly filter out obviously missing top-level packages.
+
+    Return packages with entries that can't be found removed.
+
+    This is approximate: some packages that aren't actually valid may be
+    included. However, all potentially valid packages must be returned.
+    """
+    # Start with a empty set and add all potential top-level packages.
+    found = set()
+    paths = (
+        search_paths.python_path
+        + search_paths.mypy_path
+        + search_paths.package_path
+        + search_paths.typeshed_path
+    )
+    for p in paths:
+        try:
+            entries = fscache.listdir(p)
+        except Exception:
+            entries = []
+        for entry in entries:
+            # The code is hand-optimized for mypyc since this may be somewhat
+            # performance-critical.
+            if entry.endswith(".py"):
+                entry = entry[:-3]
+            elif entry.endswith(".pyi"):
+                entry = entry[:-4]
+            elif entry.endswith("-stubs"):
+                # Possible PEP 561 stub package
+                entry = entry[:-6]
+            if entry in packages:
+                found.add(entry)
+    return found

二進制
venv/lib/python3.11/site-packages/mypy/dmypy_util.cpython-311-x86_64-linux-gnu.so


+ 31 - 0
venv/lib/python3.11/site-packages/mypy/dmypy_util.py

@@ -0,0 +1,31 @@
+"""Shared code between dmypy.py and dmypy_server.py.
+
+This should be pretty lightweight and not depend on other mypy code (other than ipc).
+"""
+
+from __future__ import annotations
+
+import json
+from typing import Any, Final
+
+from mypy.ipc import IPCBase
+
+DEFAULT_STATUS_FILE: Final = ".dmypy.json"
+
+
+def receive(connection: IPCBase) -> Any:
+    """Receive JSON data from a connection until EOF.
+
+    Raise OSError if the data received is not valid JSON or if it is
+    not a dict.
+    """
+    bdata = connection.read()
+    if not bdata:
+        raise OSError("No data received")
+    try:
+        data = json.loads(bdata.decode("utf8"))
+    except Exception as e:
+        raise OSError("Data received is not valid JSON") from e
+    if not isinstance(data, dict):
+        raise OSError(f"Data received is not a dict ({type(data)})")
+    return data

二進制
venv/lib/python3.11/site-packages/mypy/erasetype.cpython-311-x86_64-linux-gnu.so


+ 233 - 0
venv/lib/python3.11/site-packages/mypy/erasetype.py

@@ -0,0 +1,233 @@
+from __future__ import annotations
+
+from typing import Callable, Container, cast
+
+from mypy.nodes import ARG_STAR, ARG_STAR2
+from mypy.types import (
+    AnyType,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    Parameters,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeOfAny,
+    TypeTranslator,
+    TypeType,
+    TypeVarId,
+    TypeVarTupleType,
+    TypeVarType,
+    TypeVisitor,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+    get_proper_type,
+    get_proper_types,
+)
+
+
+def erase_type(typ: Type) -> ProperType:
+    """Erase any type variables from a type.
+
+    Also replace tuple types with the corresponding concrete types.
+
+    Examples:
+      A -> A
+      B[X] -> B[Any]
+      Tuple[A, B] -> tuple
+      Callable[[A1, A2, ...], R] -> Callable[..., Any]
+      Type[X] -> Type[Any]
+    """
+    typ = get_proper_type(typ)
+    return typ.accept(EraseTypeVisitor())
+
+
+class EraseTypeVisitor(TypeVisitor[ProperType]):
+    def visit_unbound_type(self, t: UnboundType) -> ProperType:
+        # TODO: replace with an assert after UnboundType can't leak from semantic analysis.
+        return AnyType(TypeOfAny.from_error)
+
+    def visit_any(self, t: AnyType) -> ProperType:
+        return t
+
+    def visit_none_type(self, t: NoneType) -> ProperType:
+        return t
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType:
+        return t
+
+    def visit_erased_type(self, t: ErasedType) -> ProperType:
+        return t
+
+    def visit_partial_type(self, t: PartialType) -> ProperType:
+        # Should not get here.
+        raise RuntimeError()
+
+    def visit_deleted_type(self, t: DeletedType) -> ProperType:
+        return t
+
+    def visit_instance(self, t: Instance) -> ProperType:
+        return Instance(t.type, [AnyType(TypeOfAny.special_form)] * len(t.args), t.line)
+
+    def visit_type_var(self, t: TypeVarType) -> ProperType:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_param_spec(self, t: ParamSpecType) -> ProperType:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_parameters(self, t: Parameters) -> ProperType:
+        raise RuntimeError("Parameters should have been bound to a class")
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_unpack_type(self, t: UnpackType) -> ProperType:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_callable_type(self, t: CallableType) -> ProperType:
+        # We must preserve the fallback type for overload resolution to work.
+        any_type = AnyType(TypeOfAny.special_form)
+        return CallableType(
+            arg_types=[any_type, any_type],
+            arg_kinds=[ARG_STAR, ARG_STAR2],
+            arg_names=[None, None],
+            ret_type=any_type,
+            fallback=t.fallback,
+            is_ellipsis_args=True,
+            implicit=True,
+        )
+
+    def visit_overloaded(self, t: Overloaded) -> ProperType:
+        return t.fallback.accept(self)
+
+    def visit_tuple_type(self, t: TupleType) -> ProperType:
+        return t.partial_fallback.accept(self)
+
+    def visit_typeddict_type(self, t: TypedDictType) -> ProperType:
+        return t.fallback.accept(self)
+
+    def visit_literal_type(self, t: LiteralType) -> ProperType:
+        # The fallback for literal types should always be either
+        # something like int or str, or an enum class -- types that
+        # don't contain any TypeVars. So there's no need to visit it.
+        return t
+
+    def visit_union_type(self, t: UnionType) -> ProperType:
+        erased_items = [erase_type(item) for item in t.items]
+        from mypy.typeops import make_simplified_union
+
+        return make_simplified_union(erased_items)
+
+    def visit_type_type(self, t: TypeType) -> ProperType:
+        return TypeType.make_normalized(t.item.accept(self), line=t.line)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> ProperType:
+        raise RuntimeError("Type aliases should be expanded before accepting this visitor")
+
+
+def erase_typevars(t: Type, ids_to_erase: Container[TypeVarId] | None = None) -> Type:
+    """Replace all type variables in a type with any,
+    or just the ones in the provided collection.
+    """
+
+    def erase_id(id: TypeVarId) -> bool:
+        if ids_to_erase is None:
+            return True
+        return id in ids_to_erase
+
+    return t.accept(TypeVarEraser(erase_id, AnyType(TypeOfAny.special_form)))
+
+
+def replace_meta_vars(t: Type, target_type: Type) -> Type:
+    """Replace unification variables in a type with the target type."""
+    return t.accept(TypeVarEraser(lambda id: id.is_meta_var(), target_type))
+
+
+class TypeVarEraser(TypeTranslator):
+    """Implementation of type erasure"""
+
+    def __init__(self, erase_id: Callable[[TypeVarId], bool], replacement: Type) -> None:
+        self.erase_id = erase_id
+        self.replacement = replacement
+
+    def visit_type_var(self, t: TypeVarType) -> Type:
+        if self.erase_id(t.id):
+            return self.replacement
+        return t
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
+        if self.erase_id(t.id):
+            return self.replacement
+        return t
+
+    def visit_param_spec(self, t: ParamSpecType) -> Type:
+        if self.erase_id(t.id):
+            return self.replacement
+        return t
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        # Type alias target can't contain bound type variables (not bound by the type
+        # alias itself), so it is safe to just erase the arguments.
+        return t.copy_modified(args=[a.accept(self) for a in t.args])
+
+
+def remove_instance_last_known_values(t: Type) -> Type:
+    return t.accept(LastKnownValueEraser())
+
+
+class LastKnownValueEraser(TypeTranslator):
+    """Removes the Literal[...] type that may be associated with any
+    Instance types."""
+
+    def visit_instance(self, t: Instance) -> Type:
+        if not t.last_known_value and not t.args:
+            return t
+        return t.copy_modified(args=[a.accept(self) for a in t.args], last_known_value=None)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        # Type aliases can't contain literal values, because they are
+        # always constructed as explicit types.
+        return t
+
+    def visit_union_type(self, t: UnionType) -> Type:
+        new = cast(UnionType, super().visit_union_type(t))
+        # Erasure can result in many duplicate items; merge them.
+        # Call make_simplified_union only on lists of instance types
+        # that all have the same fullname, to avoid simplifying too
+        # much.
+        instances = [item for item in new.items if isinstance(get_proper_type(item), Instance)]
+        # Avoid merge in simple cases such as optional types.
+        if len(instances) > 1:
+            instances_by_name: dict[str, list[Instance]] = {}
+            p_new_items = get_proper_types(new.items)
+            for p_item in p_new_items:
+                if isinstance(p_item, Instance) and not p_item.args:
+                    instances_by_name.setdefault(p_item.type.fullname, []).append(p_item)
+            merged: list[Type] = []
+            for item in new.items:
+                orig_item = item
+                item = get_proper_type(item)
+                if isinstance(item, Instance) and not item.args:
+                    types = instances_by_name.get(item.type.fullname)
+                    if types is not None:
+                        if len(types) == 1:
+                            merged.append(item)
+                        else:
+                            from mypy.typeops import make_simplified_union
+
+                            merged.append(make_simplified_union(types))
+                            del instances_by_name[item.type.fullname]
+                else:
+                    merged.append(orig_item)
+            return UnionType.make_union(merged)
+        return new

二進制
venv/lib/python3.11/site-packages/mypy/errorcodes.cpython-311-x86_64-linux-gnu.so


+ 255 - 0
venv/lib/python3.11/site-packages/mypy/errorcodes.py

@@ -0,0 +1,255 @@
+"""Classification of possible errors mypy can detect.
+
+These can be used for filtering specific errors.
+"""
+
+from __future__ import annotations
+
+from collections import defaultdict
+from typing import Final
+
+from mypy_extensions import mypyc_attr
+
+error_codes: dict[str, ErrorCode] = {}
+sub_code_map: dict[str, set[str]] = defaultdict(set)
+
+
+@mypyc_attr(allow_interpreted_subclasses=True)
+class ErrorCode:
+    def __init__(
+        self,
+        code: str,
+        description: str,
+        category: str,
+        default_enabled: bool = True,
+        sub_code_of: ErrorCode | None = None,
+    ) -> None:
+        self.code = code
+        self.description = description
+        self.category = category
+        self.default_enabled = default_enabled
+        self.sub_code_of = sub_code_of
+        if sub_code_of is not None:
+            assert sub_code_of.sub_code_of is None, "Nested subcategories are not supported"
+            sub_code_map[sub_code_of.code].add(code)
+        error_codes[code] = self
+
+    def __str__(self) -> str:
+        return f"<ErrorCode {self.code}>"
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, ErrorCode):
+            return False
+        return self.code == other.code
+
+    def __hash__(self) -> int:
+        return hash((self.code,))
+
+
+ATTR_DEFINED: Final = ErrorCode("attr-defined", "Check that attribute exists", "General")
+NAME_DEFINED: Final = ErrorCode("name-defined", "Check that name is defined", "General")
+CALL_ARG: Final[ErrorCode] = ErrorCode(
+    "call-arg", "Check number, names and kinds of arguments in calls", "General"
+)
+ARG_TYPE: Final = ErrorCode("arg-type", "Check argument types in calls", "General")
+CALL_OVERLOAD: Final = ErrorCode(
+    "call-overload", "Check that an overload variant matches arguments", "General"
+)
+VALID_TYPE: Final[ErrorCode] = ErrorCode(
+    "valid-type", "Check that type (annotation) is valid", "General"
+)
+VAR_ANNOTATED: Final = ErrorCode(
+    "var-annotated", "Require variable annotation if type can't be inferred", "General"
+)
+OVERRIDE: Final = ErrorCode(
+    "override", "Check that method override is compatible with base class", "General"
+)
+RETURN: Final[ErrorCode] = ErrorCode(
+    "return", "Check that function always returns a value", "General"
+)
+RETURN_VALUE: Final[ErrorCode] = ErrorCode(
+    "return-value", "Check that return value is compatible with signature", "General"
+)
+ASSIGNMENT: Final[ErrorCode] = ErrorCode(
+    "assignment", "Check that assigned value is compatible with target", "General"
+)
+METHOD_ASSIGN: Final[ErrorCode] = ErrorCode(
+    "method-assign",
+    "Check that assignment target is not a method",
+    "General",
+    sub_code_of=ASSIGNMENT,
+)
+TYPE_ARG: Final = ErrorCode("type-arg", "Check that generic type arguments are present", "General")
+TYPE_VAR: Final = ErrorCode("type-var", "Check that type variable values are valid", "General")
+UNION_ATTR: Final = ErrorCode(
+    "union-attr", "Check that attribute exists in each item of a union", "General"
+)
+INDEX: Final = ErrorCode("index", "Check indexing operations", "General")
+OPERATOR: Final = ErrorCode("operator", "Check that operator is valid for operands", "General")
+LIST_ITEM: Final = ErrorCode(
+    "list-item", "Check list items in a list expression [item, ...]", "General"
+)
+DICT_ITEM: Final = ErrorCode(
+    "dict-item", "Check dict items in a dict expression {key: value, ...}", "General"
+)
+TYPEDDICT_ITEM: Final = ErrorCode(
+    "typeddict-item", "Check items when constructing TypedDict", "General"
+)
+TYPEDDICT_UNKNOWN_KEY: Final = ErrorCode(
+    "typeddict-unknown-key",
+    "Check unknown keys when constructing TypedDict",
+    "General",
+    sub_code_of=TYPEDDICT_ITEM,
+)
+HAS_TYPE: Final = ErrorCode(
+    "has-type", "Check that type of reference can be determined", "General"
+)
+IMPORT: Final = ErrorCode(
+    "import", "Require that imported module can be found or has stubs", "General"
+)
+NO_REDEF: Final = ErrorCode("no-redef", "Check that each name is defined once", "General")
+FUNC_RETURNS_VALUE: Final = ErrorCode(
+    "func-returns-value", "Check that called function returns a value in value context", "General"
+)
+ABSTRACT: Final = ErrorCode(
+    "abstract", "Prevent instantiation of classes with abstract attributes", "General"
+)
+TYPE_ABSTRACT: Final = ErrorCode(
+    "type-abstract", "Require only concrete classes where Type[...] is expected", "General"
+)
+VALID_NEWTYPE: Final = ErrorCode(
+    "valid-newtype", "Check that argument 2 to NewType is valid", "General"
+)
+STRING_FORMATTING: Final = ErrorCode(
+    "str-format", "Check that string formatting/interpolation is type-safe", "General"
+)
+STR_BYTES_PY3: Final = ErrorCode(
+    "str-bytes-safe", "Warn about implicit coercions related to bytes and string types", "General"
+)
+EXIT_RETURN: Final = ErrorCode(
+    "exit-return", "Warn about too general return type for '__exit__'", "General"
+)
+LITERAL_REQ: Final = ErrorCode("literal-required", "Check that value is a literal", "General")
+UNUSED_COROUTINE: Final = ErrorCode(
+    "unused-coroutine", "Ensure that all coroutines are used", "General"
+)
+# TODO: why do we need the explicit type here? Without it mypyc CI builds fail with
+# mypy/message_registry.py:37: error: Cannot determine type of "EMPTY_BODY"  [has-type]
+EMPTY_BODY: Final[ErrorCode] = ErrorCode(
+    "empty-body",
+    "A dedicated error code to opt out return errors for empty/trivial bodies",
+    "General",
+)
+SAFE_SUPER: Final = ErrorCode(
+    "safe-super", "Warn about calls to abstract methods with empty/trivial bodies", "General"
+)
+TOP_LEVEL_AWAIT: Final = ErrorCode(
+    "top-level-await", "Warn about top level await expressions", "General"
+)
+
+# These error codes aren't enabled by default.
+NO_UNTYPED_DEF: Final[ErrorCode] = ErrorCode(
+    "no-untyped-def", "Check that every function has an annotation", "General"
+)
+NO_UNTYPED_CALL: Final = ErrorCode(
+    "no-untyped-call",
+    "Disallow calling functions without type annotations from annotated functions",
+    "General",
+)
+REDUNDANT_CAST: Final = ErrorCode(
+    "redundant-cast", "Check that cast changes type of expression", "General"
+)
+ASSERT_TYPE: Final = ErrorCode("assert-type", "Check that assert_type() call succeeds", "General")
+COMPARISON_OVERLAP: Final = ErrorCode(
+    "comparison-overlap", "Check that types in comparisons and 'in' expressions overlap", "General"
+)
+NO_ANY_UNIMPORTED: Final = ErrorCode(
+    "no-any-unimported", 'Reject "Any" types from unfollowed imports', "General"
+)
+NO_ANY_RETURN: Final = ErrorCode(
+    "no-any-return",
+    'Reject returning value with "Any" type if return type is not "Any"',
+    "General",
+)
+UNREACHABLE: Final = ErrorCode(
+    "unreachable", "Warn about unreachable statements or expressions", "General"
+)
+ANNOTATION_UNCHECKED = ErrorCode(
+    "annotation-unchecked", "Notify about type annotations in unchecked functions", "General"
+)
+POSSIBLY_UNDEFINED: Final[ErrorCode] = ErrorCode(
+    "possibly-undefined",
+    "Warn about variables that are defined only in some execution paths",
+    "General",
+    default_enabled=False,
+)
+REDUNDANT_EXPR: Final = ErrorCode(
+    "redundant-expr", "Warn about redundant expressions", "General", default_enabled=False
+)
+TRUTHY_BOOL: Final[ErrorCode] = ErrorCode(
+    "truthy-bool",
+    "Warn about expressions that could always evaluate to true in boolean contexts",
+    "General",
+    default_enabled=False,
+)
+TRUTHY_FUNCTION: Final[ErrorCode] = ErrorCode(
+    "truthy-function",
+    "Warn about function that always evaluate to true in boolean contexts",
+    "General",
+)
+TRUTHY_ITERABLE: Final[ErrorCode] = ErrorCode(
+    "truthy-iterable",
+    "Warn about Iterable expressions that could always evaluate to true in boolean contexts",
+    "General",
+    default_enabled=False,
+)
+NAME_MATCH: Final = ErrorCode(
+    "name-match", "Check that type definition has consistent naming", "General"
+)
+NO_OVERLOAD_IMPL: Final = ErrorCode(
+    "no-overload-impl",
+    "Check that overloaded functions outside stub files have an implementation",
+    "General",
+)
+IGNORE_WITHOUT_CODE: Final = ErrorCode(
+    "ignore-without-code",
+    "Warn about '# type: ignore' comments which do not have error codes",
+    "General",
+    default_enabled=False,
+)
+UNUSED_AWAITABLE: Final = ErrorCode(
+    "unused-awaitable",
+    "Ensure that all awaitable values are used",
+    "General",
+    default_enabled=False,
+)
+REDUNDANT_SELF_TYPE = ErrorCode(
+    "redundant-self",
+    "Warn about redundant Self type annotations on method first argument",
+    "General",
+    default_enabled=False,
+)
+USED_BEFORE_DEF: Final[ErrorCode] = ErrorCode(
+    "used-before-def", "Warn about variables that are used before they are defined", "General"
+)
+UNUSED_IGNORE: Final = ErrorCode(
+    "unused-ignore", "Ensure that all type ignores are used", "General", default_enabled=False
+)
+EXPLICIT_OVERRIDE_REQUIRED: Final = ErrorCode(
+    "explicit-override",
+    "Require @override decorator if method is overriding a base class method",
+    "General",
+    default_enabled=False,
+)
+
+
+# Syntax errors are often blocking.
+SYNTAX: Final[ErrorCode] = ErrorCode("syntax", "Report syntax errors", "General")
+
+# This is an internal marker code for a whole-file ignore. It is not intended to
+# be user-visible.
+FILE: Final = ErrorCode("file", "Internal marker for a whole file being ignored", "General")
+del error_codes[FILE.code]
+
+# This is a catch-all for remaining uncategorized errors.
+MISC: Final = ErrorCode("misc", "Miscellaneous other checks", "General")

二進制
venv/lib/python3.11/site-packages/mypy/errors.cpython-311-x86_64-linux-gnu.so


+ 1276 - 0
venv/lib/python3.11/site-packages/mypy/errors.py

@@ -0,0 +1,1276 @@
+from __future__ import annotations
+
+import os.path
+import sys
+import traceback
+from collections import defaultdict
+from typing import Callable, Final, Iterable, NoReturn, Optional, TextIO, Tuple, TypeVar
+from typing_extensions import Literal, TypeAlias as _TypeAlias
+
+from mypy import errorcodes as codes
+from mypy.errorcodes import IMPORT, ErrorCode
+from mypy.message_registry import ErrorMessage
+from mypy.options import Options
+from mypy.scope import Scope
+from mypy.util import DEFAULT_SOURCE_OFFSET, is_typeshed_file
+from mypy.version import __version__ as mypy_version
+
+T = TypeVar("T")
+
+# Show error codes for some note-level messages (these usually appear alone
+# and not as a comment for a previous error-level message).
+SHOW_NOTE_CODES: Final = {codes.ANNOTATION_UNCHECKED}
+
+# Do not add notes with links to error code docs to errors with these codes.
+# We can tweak this set as we get more experience about what is helpful and what is not.
+HIDE_LINK_CODES: Final = {
+    # This is a generic error code, so it has no useful docs
+    codes.MISC,
+    # These are trivial and have some custom notes (e.g. for list being invariant)
+    codes.ASSIGNMENT,
+    codes.ARG_TYPE,
+    codes.RETURN_VALUE,
+    # Undefined name/attribute errors are self-explanatory
+    codes.ATTR_DEFINED,
+    codes.NAME_DEFINED,
+    # Overrides have a custom link to docs
+    codes.OVERRIDE,
+}
+
+allowed_duplicates: Final = ["@overload", "Got:", "Expected:"]
+
+BASE_RTD_URL: Final = "https://mypy.rtfd.io/en/stable/_refs.html#code"
+
+# Keep track of the original error code when the error code of a message is changed.
+# This is used to give notes about out-of-date "type: ignore" comments.
+original_error_codes: Final = {codes.LITERAL_REQ: codes.MISC, codes.TYPE_ABSTRACT: codes.MISC}
+
+
+class ErrorInfo:
+    """Representation of a single error message."""
+
+    # Description of a sequence of imports that refer to the source file
+    # related to this error. Each item is a (path, line number) tuple.
+    import_ctx: list[tuple[str, int]]
+
+    # The path to source file that was the source of this error.
+    file = ""
+
+    # The fully-qualified id of the source module for this error.
+    module: str | None = None
+
+    # The name of the type in which this error is located at.
+    type: str | None = ""  # Unqualified, may be None
+
+    # The name of the function or member in which this error is located at.
+    function_or_member: str | None = ""  # Unqualified, may be None
+
+    # The line number related to this error within file.
+    line = 0  # -1 if unknown
+
+    # The column number related to this error with file.
+    column = 0  # -1 if unknown
+
+    # The end line number related to this error within file.
+    end_line = 0  # -1 if unknown
+
+    # The end column number related to this error with file.
+    end_column = 0  # -1 if unknown
+
+    # Either 'error' or 'note'
+    severity = ""
+
+    # The error message.
+    message = ""
+
+    # The error code.
+    code: ErrorCode | None = None
+
+    # If True, we should halt build after the file that generated this error.
+    blocker = False
+
+    # Only report this particular messages once per program.
+    only_once = False
+
+    # Do not remove duplicate copies of this message (ignored if only_once is True).
+    allow_dups = False
+
+    # Actual origin of the error message as tuple (path, line number, end line number)
+    # If end line number is unknown, use line number.
+    origin: tuple[str, Iterable[int]]
+
+    # Fine-grained incremental target where this was reported
+    target: str | None = None
+
+    # If True, don't show this message in output, but still record the error (needed
+    # by mypy daemon)
+    hidden = False
+
+    def __init__(
+        self,
+        import_ctx: list[tuple[str, int]],
+        *,
+        file: str,
+        module: str | None,
+        typ: str | None,
+        function_or_member: str | None,
+        line: int,
+        column: int,
+        end_line: int,
+        end_column: int,
+        severity: str,
+        message: str,
+        code: ErrorCode | None,
+        blocker: bool,
+        only_once: bool,
+        allow_dups: bool,
+        origin: tuple[str, Iterable[int]] | None = None,
+        target: str | None = None,
+        priority: int = 0,
+    ) -> None:
+        self.import_ctx = import_ctx
+        self.file = file
+        self.module = module
+        self.type = typ
+        self.function_or_member = function_or_member
+        self.line = line
+        self.column = column
+        self.end_line = end_line
+        self.end_column = end_column
+        self.severity = severity
+        self.message = message
+        self.code = code
+        self.blocker = blocker
+        self.only_once = only_once
+        self.allow_dups = allow_dups
+        self.origin = origin or (file, [line])
+        self.target = target
+        self.priority = priority
+
+
+# Type used internally to represent errors:
+#   (path, line, column, end_line, end_column, severity, message, allow_dups, code)
+ErrorTuple: _TypeAlias = Tuple[
+    Optional[str], int, int, int, int, str, str, bool, Optional[ErrorCode]
+]
+
+
+class ErrorWatcher:
+    """Context manager that can be used to keep track of new errors recorded
+    around a given operation.
+
+    Errors maintain a stack of such watchers. The handler is called starting
+    at the top of the stack, and is propagated down the stack unless filtered
+    out by one of the ErrorWatcher instances.
+    """
+
+    def __init__(
+        self,
+        errors: Errors,
+        *,
+        filter_errors: bool | Callable[[str, ErrorInfo], bool] = False,
+        save_filtered_errors: bool = False,
+    ):
+        self.errors = errors
+        self._has_new_errors = False
+        self._filter = filter_errors
+        self._filtered: list[ErrorInfo] | None = [] if save_filtered_errors else None
+
+    def __enter__(self) -> ErrorWatcher:
+        self.errors._watchers.append(self)
+        return self
+
+    def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> Literal[False]:
+        last = self.errors._watchers.pop()
+        assert last == self
+        return False
+
+    def on_error(self, file: str, info: ErrorInfo) -> bool:
+        """Handler called when a new error is recorded.
+
+        The default implementation just sets the has_new_errors flag
+
+        Return True to filter out the error, preventing it from being seen by other
+        ErrorWatcher further down the stack and from being recorded by Errors
+        """
+        self._has_new_errors = True
+        if isinstance(self._filter, bool):
+            should_filter = self._filter
+        elif callable(self._filter):
+            should_filter = self._filter(file, info)
+        else:
+            raise AssertionError(f"invalid error filter: {type(self._filter)}")
+        if should_filter and self._filtered is not None:
+            self._filtered.append(info)
+
+        return should_filter
+
+    def has_new_errors(self) -> bool:
+        return self._has_new_errors
+
+    def filtered_errors(self) -> list[ErrorInfo]:
+        assert self._filtered is not None
+        return self._filtered
+
+
+class Errors:
+    """Container for compile errors.
+
+    This class generates and keeps tracks of compile errors and the
+    current error context (nested imports).
+    """
+
+    # Map from files to generated error messages. Is an OrderedDict so
+    # that it can be used to order messages based on the order the
+    # files were processed.
+    error_info_map: dict[str, list[ErrorInfo]]
+
+    # optimization for legacy codebases with many files with errors
+    has_blockers: set[str]
+
+    # Files that we have reported the errors for
+    flushed_files: set[str]
+
+    # Current error context: nested import context/stack, as a list of (path, line) pairs.
+    import_ctx: list[tuple[str, int]]
+
+    # Path name prefix that is removed from all paths, if set.
+    ignore_prefix: str | None = None
+
+    # Path to current file.
+    file: str = ""
+
+    # Ignore some errors on these lines of each file
+    # (path -> line -> error-codes)
+    ignored_lines: dict[str, dict[int, list[str]]]
+
+    # Lines that were skipped during semantic analysis e.g. due to ALWAYS_FALSE, MYPY_FALSE,
+    # or platform/version checks. Those lines would not be type-checked.
+    skipped_lines: dict[str, set[int]]
+
+    # Lines on which an error was actually ignored.
+    used_ignored_lines: dict[str, dict[int, list[str]]]
+
+    # Files where all errors should be ignored.
+    ignored_files: set[str]
+
+    # Collection of reported only_once messages.
+    only_once_messages: set[str]
+
+    # Set to True to show "In function "foo":" messages.
+    show_error_context: bool = False
+
+    # Set to True to show column numbers in error messages.
+    show_column_numbers: bool = False
+
+    # Set to True to show end line and end column in error messages.
+    # Ths implies `show_column_numbers`.
+    show_error_end: bool = False
+
+    # Set to True to show absolute file paths in error messages.
+    show_absolute_path: bool = False
+
+    # State for keeping track of the current fine-grained incremental mode target.
+    # (See mypy.server.update for more about targets.)
+    # Current module id.
+    target_module: str | None = None
+    scope: Scope | None = None
+
+    # Have we seen an import-related error so far? If yes, we filter out other messages
+    # in some cases to avoid reporting huge numbers of errors.
+    seen_import_error = False
+
+    _watchers: list[ErrorWatcher] = []
+
+    def __init__(
+        self,
+        options: Options,
+        *,
+        read_source: Callable[[str], list[str] | None] | None = None,
+        hide_error_codes: bool | None = None,
+    ) -> None:
+        self.options = options
+        self.hide_error_codes = (
+            hide_error_codes if hide_error_codes is not None else options.hide_error_codes
+        )
+        # We use fscache to read source code when showing snippets.
+        self.read_source = read_source
+        self.initialize()
+
+    def initialize(self) -> None:
+        self.error_info_map = {}
+        self.flushed_files = set()
+        self.import_ctx = []
+        self.function_or_member = [None]
+        self.ignored_lines = {}
+        self.skipped_lines = {}
+        self.used_ignored_lines = defaultdict(lambda: defaultdict(list))
+        self.ignored_files = set()
+        self.only_once_messages = set()
+        self.has_blockers = set()
+        self.scope = None
+        self.target_module = None
+        self.seen_import_error = False
+
+    def reset(self) -> None:
+        self.initialize()
+
+    def set_ignore_prefix(self, prefix: str) -> None:
+        """Set path prefix that will be removed from all paths."""
+        prefix = os.path.normpath(prefix)
+        # Add separator to the end, if not given.
+        if os.path.basename(prefix) != "":
+            prefix += os.sep
+        self.ignore_prefix = prefix
+
+    def simplify_path(self, file: str) -> str:
+        if self.options.show_absolute_path:
+            return os.path.abspath(file)
+        else:
+            file = os.path.normpath(file)
+            return remove_path_prefix(file, self.ignore_prefix)
+
+    def set_file(
+        self, file: str, module: str | None, options: Options, scope: Scope | None = None
+    ) -> None:
+        """Set the path and module id of the current file."""
+        # The path will be simplified later, in render_messages. That way
+        #  * 'file' is always a key that uniquely identifies a source file
+        #    that mypy read (simplified paths might not be unique); and
+        #  * we only have to simplify in one place, while still supporting
+        #    reporting errors for files other than the one currently being
+        #    processed.
+        self.file = file
+        self.target_module = module
+        self.scope = scope
+        self.options = options
+
+    def set_file_ignored_lines(
+        self, file: str, ignored_lines: dict[int, list[str]], ignore_all: bool = False
+    ) -> None:
+        self.ignored_lines[file] = ignored_lines
+        if ignore_all:
+            self.ignored_files.add(file)
+
+    def set_skipped_lines(self, file: str, skipped_lines: set[int]) -> None:
+        self.skipped_lines[file] = skipped_lines
+
+    def current_target(self) -> str | None:
+        """Retrieves the current target from the associated scope.
+
+        If there is no associated scope, use the target module."""
+        if self.scope is not None:
+            return self.scope.current_target()
+        return self.target_module
+
+    def current_module(self) -> str | None:
+        return self.target_module
+
+    def import_context(self) -> list[tuple[str, int]]:
+        """Return a copy of the import context."""
+        return self.import_ctx.copy()
+
+    def set_import_context(self, ctx: list[tuple[str, int]]) -> None:
+        """Replace the entire import context with a new value."""
+        self.import_ctx = ctx.copy()
+
+    def report(
+        self,
+        line: int,
+        column: int | None,
+        message: str,
+        code: ErrorCode | None = None,
+        *,
+        blocker: bool = False,
+        severity: str = "error",
+        file: str | None = None,
+        only_once: bool = False,
+        allow_dups: bool = False,
+        origin_span: Iterable[int] | None = None,
+        offset: int = 0,
+        end_line: int | None = None,
+        end_column: int | None = None,
+    ) -> None:
+        """Report message at the given line using the current error context.
+
+        Args:
+            line: line number of error
+            column: column number of error
+            message: message to report
+            code: error code (defaults to 'misc'; not shown for notes)
+            blocker: if True, don't continue analysis after this error
+            severity: 'error' or 'note'
+            file: if non-None, override current file as context
+            only_once: if True, only report this exact message once per build
+            allow_dups: if True, allow duplicate copies of this message (ignored if only_once)
+            origin_span: if non-None, override current context as origin
+                         (type: ignores have effect here)
+            end_line: if non-None, override current context as end
+        """
+        if self.scope:
+            type = self.scope.current_type_name()
+            if self.scope.ignored > 0:
+                type = None  # Omit type context if nested function
+            function = self.scope.current_function_name()
+        else:
+            type = None
+            function = None
+
+        if column is None:
+            column = -1
+        if end_column is None:
+            if column == -1:
+                end_column = -1
+            else:
+                end_column = column + 1
+
+        if file is None:
+            file = self.file
+        if offset:
+            message = " " * offset + message
+
+        if origin_span is None:
+            origin_span = [line]
+
+        if end_line is None:
+            end_line = line
+
+        code = code or (codes.MISC if not blocker else None)
+
+        info = ErrorInfo(
+            import_ctx=self.import_context(),
+            file=file,
+            module=self.current_module(),
+            typ=type,
+            function_or_member=function,
+            line=line,
+            column=column,
+            end_line=end_line,
+            end_column=end_column,
+            severity=severity,
+            message=message,
+            code=code,
+            blocker=blocker,
+            only_once=only_once,
+            allow_dups=allow_dups,
+            origin=(self.file, origin_span),
+            target=self.current_target(),
+        )
+        self.add_error_info(info)
+
+    def _add_error_info(self, file: str, info: ErrorInfo) -> None:
+        assert file not in self.flushed_files
+        # process the stack of ErrorWatchers before modifying any internal state
+        # in case we need to filter out the error entirely
+        if self._filter_error(file, info):
+            return
+        if file not in self.error_info_map:
+            self.error_info_map[file] = []
+        self.error_info_map[file].append(info)
+        if info.blocker:
+            self.has_blockers.add(file)
+        if info.code is IMPORT:
+            self.seen_import_error = True
+
+    def _filter_error(self, file: str, info: ErrorInfo) -> bool:
+        """
+        process ErrorWatcher stack from top to bottom,
+        stopping early if error needs to be filtered out
+        """
+        i = len(self._watchers)
+        while i > 0:
+            i -= 1
+            w = self._watchers[i]
+            if w.on_error(file, info):
+                return True
+        return False
+
+    def add_error_info(self, info: ErrorInfo) -> None:
+        file, lines = info.origin
+        # process the stack of ErrorWatchers before modifying any internal state
+        # in case we need to filter out the error entirely
+        # NB: we need to do this both here and in _add_error_info, otherwise we
+        # might incorrectly update the sets of ignored or only_once messages
+        if self._filter_error(file, info):
+            return
+        if not info.blocker:  # Blockers cannot be ignored
+            if file in self.ignored_lines:
+                # Check each line in this context for "type: ignore" comments.
+                # line == end_line for most nodes, so we only loop once.
+                for scope_line in lines:
+                    if self.is_ignored_error(scope_line, info, self.ignored_lines[file]):
+                        # Annotation requests us to ignore all errors on this line.
+                        self.used_ignored_lines[file][scope_line].append(
+                            (info.code or codes.MISC).code
+                        )
+                        return
+            if file in self.ignored_files:
+                return
+        if info.only_once:
+            if info.message in self.only_once_messages:
+                return
+            self.only_once_messages.add(info.message)
+        if self.seen_import_error and info.code is not IMPORT and self.has_many_errors():
+            # Missing stubs can easily cause thousands of errors about
+            # Any types, especially when upgrading to mypy 0.900,
+            # which no longer bundles third-party library stubs. Avoid
+            # showing too many errors to make it easier to see
+            # import-related errors.
+            info.hidden = True
+            self.report_hidden_errors(info)
+        self._add_error_info(file, info)
+        ignored_codes = self.ignored_lines.get(file, {}).get(info.line, [])
+        if ignored_codes and info.code:
+            # Something is ignored on the line, but not this error, so maybe the error
+            # code is incorrect.
+            msg = f'Error code "{info.code.code}" not covered by "type: ignore" comment'
+            if info.code in original_error_codes:
+                # If there seems to be a "type: ignore" with a stale error
+                # code, report a more specific note.
+                old_code = original_error_codes[info.code].code
+                if old_code in ignored_codes:
+                    msg = (
+                        f'Error code changed to {info.code.code}; "type: ignore" comment '
+                        + "may be out of date"
+                    )
+            note = ErrorInfo(
+                import_ctx=info.import_ctx,
+                file=info.file,
+                module=info.module,
+                typ=info.type,
+                function_or_member=info.function_or_member,
+                line=info.line,
+                column=info.column,
+                end_line=info.end_line,
+                end_column=info.end_column,
+                severity="note",
+                message=msg,
+                code=None,
+                blocker=False,
+                only_once=False,
+                allow_dups=False,
+            )
+            self._add_error_info(file, note)
+        if (
+            self.options.show_error_code_links
+            and not self.options.hide_error_codes
+            and info.code is not None
+            and info.code not in HIDE_LINK_CODES
+        ):
+            message = f"See {BASE_RTD_URL}-{info.code.code} for more info"
+            if message in self.only_once_messages:
+                return
+            self.only_once_messages.add(message)
+            info = ErrorInfo(
+                import_ctx=info.import_ctx,
+                file=info.file,
+                module=info.module,
+                typ=info.type,
+                function_or_member=info.function_or_member,
+                line=info.line,
+                column=info.column,
+                end_line=info.end_line,
+                end_column=info.end_column,
+                severity="note",
+                message=message,
+                code=info.code,
+                blocker=False,
+                only_once=True,
+                allow_dups=False,
+                priority=20,
+            )
+            self._add_error_info(file, info)
+
+    def has_many_errors(self) -> bool:
+        if self.options.many_errors_threshold < 0:
+            return False
+        if len(self.error_info_map) >= self.options.many_errors_threshold:
+            return True
+        if (
+            sum(len(errors) for errors in self.error_info_map.values())
+            >= self.options.many_errors_threshold
+        ):
+            return True
+        return False
+
+    def report_hidden_errors(self, info: ErrorInfo) -> None:
+        message = (
+            "(Skipping most remaining errors due to unresolved imports or missing stubs; "
+            + "fix these first)"
+        )
+        if message in self.only_once_messages:
+            return
+        self.only_once_messages.add(message)
+        new_info = ErrorInfo(
+            import_ctx=info.import_ctx,
+            file=info.file,
+            module=info.module,
+            typ=None,
+            function_or_member=None,
+            line=info.line,
+            column=info.column,
+            end_line=info.end_line,
+            end_column=info.end_column,
+            severity="note",
+            message=message,
+            code=None,
+            blocker=False,
+            only_once=True,
+            allow_dups=False,
+            origin=info.origin,
+            target=info.target,
+        )
+        self._add_error_info(info.origin[0], new_info)
+
+    def is_ignored_error(self, line: int, info: ErrorInfo, ignores: dict[int, list[str]]) -> bool:
+        if info.blocker:
+            # Blocking errors can never be ignored
+            return False
+        if info.code and not self.is_error_code_enabled(info.code):
+            return True
+        if line not in ignores:
+            return False
+        if not ignores[line]:
+            # Empty list means that we ignore all errors
+            return True
+        if info.code and self.is_error_code_enabled(info.code):
+            return (
+                info.code.code in ignores[line]
+                or info.code.sub_code_of is not None
+                and info.code.sub_code_of.code in ignores[line]
+            )
+        return False
+
+    def is_error_code_enabled(self, error_code: ErrorCode) -> bool:
+        if self.options:
+            current_mod_disabled = self.options.disabled_error_codes
+            current_mod_enabled = self.options.enabled_error_codes
+        else:
+            current_mod_disabled = set()
+            current_mod_enabled = set()
+
+        if error_code in current_mod_disabled:
+            return False
+        elif error_code in current_mod_enabled:
+            return True
+        elif error_code.sub_code_of is not None and error_code.sub_code_of in current_mod_disabled:
+            return False
+        else:
+            return error_code.default_enabled
+
+    def clear_errors_in_targets(self, path: str, targets: set[str]) -> None:
+        """Remove errors in specific fine-grained targets within a file."""
+        if path in self.error_info_map:
+            new_errors = []
+            has_blocker = False
+            for info in self.error_info_map[path]:
+                if info.target not in targets:
+                    new_errors.append(info)
+                    has_blocker |= info.blocker
+                elif info.only_once:
+                    self.only_once_messages.remove(info.message)
+            self.error_info_map[path] = new_errors
+            if not has_blocker and path in self.has_blockers:
+                self.has_blockers.remove(path)
+
+    def generate_unused_ignore_errors(self, file: str) -> None:
+        if (
+            is_typeshed_file(self.options.abs_custom_typeshed_dir if self.options else None, file)
+            or file in self.ignored_files
+        ):
+            return
+        ignored_lines = self.ignored_lines[file]
+        used_ignored_lines = self.used_ignored_lines[file]
+        for line, ignored_codes in ignored_lines.items():
+            if line in self.skipped_lines[file]:
+                continue
+            if codes.UNUSED_IGNORE.code in ignored_codes:
+                continue
+            used_ignored_codes = used_ignored_lines[line]
+            unused_ignored_codes = set(ignored_codes) - set(used_ignored_codes)
+            # `ignore` is used
+            if not ignored_codes and used_ignored_codes:
+                continue
+            # All codes appearing in `ignore[...]` are used
+            if ignored_codes and not unused_ignored_codes:
+                continue
+            # Display detail only when `ignore[...]` specifies more than one error code
+            unused_codes_message = ""
+            if len(ignored_codes) > 1 and unused_ignored_codes:
+                unused_codes_message = f"[{', '.join(sorted(unused_ignored_codes))}]"
+            message = f'Unused "type: ignore{unused_codes_message}" comment'
+            for unused in unused_ignored_codes:
+                narrower = set(used_ignored_codes) & codes.sub_code_map[unused]
+                if narrower:
+                    message += f", use narrower [{', '.join(narrower)}] instead of [{unused}] code"
+            # Don't use report since add_error_info will ignore the error!
+            info = ErrorInfo(
+                import_ctx=self.import_context(),
+                file=file,
+                module=self.current_module(),
+                typ=None,
+                function_or_member=None,
+                line=line,
+                column=-1,
+                end_line=line,
+                end_column=-1,
+                severity="error",
+                message=message,
+                code=codes.UNUSED_IGNORE,
+                blocker=False,
+                only_once=False,
+                allow_dups=False,
+            )
+            self._add_error_info(file, info)
+
+    def generate_ignore_without_code_errors(
+        self, file: str, is_warning_unused_ignores: bool
+    ) -> None:
+        if (
+            is_typeshed_file(self.options.abs_custom_typeshed_dir if self.options else None, file)
+            or file in self.ignored_files
+        ):
+            return
+
+        used_ignored_lines = self.used_ignored_lines[file]
+
+        # If the whole file is ignored, ignore it.
+        if used_ignored_lines:
+            _, used_codes = min(used_ignored_lines.items())
+            if codes.FILE.code in used_codes:
+                return
+
+        for line, ignored_codes in self.ignored_lines[file].items():
+            if ignored_codes:
+                continue
+
+            # If the ignore is itself unused and that would be warned about, let
+            # that error stand alone
+            if is_warning_unused_ignores and not used_ignored_lines[line]:
+                continue
+
+            codes_hint = ""
+            ignored_codes = sorted(set(used_ignored_lines[line]))
+            if ignored_codes:
+                codes_hint = f' (consider "type: ignore[{", ".join(ignored_codes)}]" instead)'
+
+            message = f'"type: ignore" comment without error code{codes_hint}'
+            # Don't use report since add_error_info will ignore the error!
+            info = ErrorInfo(
+                import_ctx=self.import_context(),
+                file=file,
+                module=self.current_module(),
+                typ=None,
+                function_or_member=None,
+                line=line,
+                column=-1,
+                end_line=line,
+                end_column=-1,
+                severity="error",
+                message=message,
+                code=codes.IGNORE_WITHOUT_CODE,
+                blocker=False,
+                only_once=False,
+                allow_dups=False,
+            )
+            self._add_error_info(file, info)
+
+    def num_messages(self) -> int:
+        """Return the number of generated messages."""
+        return sum(len(x) for x in self.error_info_map.values())
+
+    def is_errors(self) -> bool:
+        """Are there any generated messages?"""
+        return bool(self.error_info_map)
+
+    def is_blockers(self) -> bool:
+        """Are the any errors that are blockers?"""
+        return bool(self.has_blockers)
+
+    def blocker_module(self) -> str | None:
+        """Return the module with a blocking error, or None if not possible."""
+        for path in self.has_blockers:
+            for err in self.error_info_map[path]:
+                if err.blocker:
+                    return err.module
+        return None
+
+    def is_errors_for_file(self, file: str) -> bool:
+        """Are there any errors for the given file?"""
+        return file in self.error_info_map
+
+    def prefer_simple_messages(self) -> bool:
+        """Should we generate simple/fast error messages?
+
+        Return True if errors are not shown to user, i.e. errors are ignored
+        or they are collected for internal use only.
+
+        If True, we should prefer to generate a simple message quickly.
+        All normal errors should still be reported.
+        """
+        if self.file in self.ignored_files:
+            # Errors ignored, so no point generating fancy messages
+            return True
+        for _watcher in self._watchers:
+            if _watcher._filter is True and _watcher._filtered is None:
+                # Errors are filtered
+                return True
+        return False
+
+    def raise_error(self, use_stdout: bool = True) -> NoReturn:
+        """Raise a CompileError with the generated messages.
+
+        Render the messages suitable for displaying.
+        """
+        # self.new_messages() will format all messages that haven't already
+        # been returned from a file_messages() call.
+        raise CompileError(
+            self.new_messages(), use_stdout=use_stdout, module_with_blocker=self.blocker_module()
+        )
+
+    def format_messages(
+        self, error_info: list[ErrorInfo], source_lines: list[str] | None
+    ) -> list[str]:
+        """Return a string list that represents the error messages.
+
+        Use a form suitable for displaying to the user. If self.pretty
+        is True also append a relevant trimmed source code line (only for
+        severity 'error').
+        """
+        a: list[str] = []
+        error_info = [info for info in error_info if not info.hidden]
+        errors = self.render_messages(self.sort_messages(error_info))
+        errors = self.remove_duplicates(errors)
+        for (
+            file,
+            line,
+            column,
+            end_line,
+            end_column,
+            severity,
+            message,
+            allow_dups,
+            code,
+        ) in errors:
+            s = ""
+            if file is not None:
+                if self.options.show_column_numbers and line >= 0 and column >= 0:
+                    srcloc = f"{file}:{line}:{1 + column}"
+                    if self.options.show_error_end and end_line >= 0 and end_column >= 0:
+                        srcloc += f":{end_line}:{end_column}"
+                elif line >= 0:
+                    srcloc = f"{file}:{line}"
+                else:
+                    srcloc = file
+                s = f"{srcloc}: {severity}: {message}"
+            else:
+                s = message
+            if (
+                not self.hide_error_codes
+                and code
+                and (severity != "note" or code in SHOW_NOTE_CODES)
+            ):
+                # If note has an error code, it is related to a previous error. Avoid
+                # displaying duplicate error codes.
+                s = f"{s}  [{code.code}]"
+            a.append(s)
+            if self.options.pretty:
+                # Add source code fragment and a location marker.
+                if severity == "error" and source_lines and line > 0:
+                    source_line = source_lines[line - 1]
+                    source_line_expanded = source_line.expandtabs()
+                    if column < 0:
+                        # Something went wrong, take first non-empty column.
+                        column = len(source_line) - len(source_line.lstrip())
+
+                    # Shifts column after tab expansion
+                    column = len(source_line[:column].expandtabs())
+                    end_column = len(source_line[:end_column].expandtabs())
+
+                    # Note, currently coloring uses the offset to detect source snippets,
+                    # so these offsets should not be arbitrary.
+                    a.append(" " * DEFAULT_SOURCE_OFFSET + source_line_expanded)
+                    marker = "^"
+                    if end_line == line and end_column > column:
+                        marker = f'^{"~" * (end_column - column - 1)}'
+                    a.append(" " * (DEFAULT_SOURCE_OFFSET + column) + marker)
+        return a
+
+    def file_messages(self, path: str) -> list[str]:
+        """Return a string list of new error messages from a given file.
+
+        Use a form suitable for displaying to the user.
+        """
+        if path not in self.error_info_map:
+            return []
+        self.flushed_files.add(path)
+        source_lines = None
+        if self.options.pretty:
+            assert self.read_source
+            source_lines = self.read_source(path)
+        return self.format_messages(self.error_info_map[path], source_lines)
+
+    def new_messages(self) -> list[str]:
+        """Return a string list of new error messages.
+
+        Use a form suitable for displaying to the user.
+        Errors from different files are ordered based on the order in which
+        they first generated an error.
+        """
+        msgs = []
+        for path in self.error_info_map.keys():
+            if path not in self.flushed_files:
+                msgs.extend(self.file_messages(path))
+        return msgs
+
+    def targets(self) -> set[str]:
+        """Return a set of all targets that contain errors."""
+        # TODO: Make sure that either target is always defined or that not being defined
+        #       is okay for fine-grained incremental checking.
+        return {
+            info.target for errs in self.error_info_map.values() for info in errs if info.target
+        }
+
+    def render_messages(self, errors: list[ErrorInfo]) -> list[ErrorTuple]:
+        """Translate the messages into a sequence of tuples.
+
+        Each tuple is of form (path, line, col, severity, message, allow_dups, code).
+        The rendered sequence includes information about error contexts.
+        The path item may be None. If the line item is negative, the
+        line number is not defined for the tuple.
+        """
+        result: list[ErrorTuple] = []
+        prev_import_context: list[tuple[str, int]] = []
+        prev_function_or_member: str | None = None
+        prev_type: str | None = None
+
+        for e in errors:
+            # Report module import context, if different from previous message.
+            if not self.options.show_error_context:
+                pass
+            elif e.import_ctx != prev_import_context:
+                last = len(e.import_ctx) - 1
+                i = last
+                while i >= 0:
+                    path, line = e.import_ctx[i]
+                    fmt = "{}:{}: note: In module imported here"
+                    if i < last:
+                        fmt = "{}:{}: note: ... from here"
+                    if i > 0:
+                        fmt += ","
+                    else:
+                        fmt += ":"
+                    # Remove prefix to ignore from path (if present) to
+                    # simplify path.
+                    path = remove_path_prefix(path, self.ignore_prefix)
+                    result.append(
+                        (None, -1, -1, -1, -1, "note", fmt.format(path, line), e.allow_dups, None)
+                    )
+                    i -= 1
+
+            file = self.simplify_path(e.file)
+
+            # Report context within a source file.
+            if not self.options.show_error_context:
+                pass
+            elif e.function_or_member != prev_function_or_member or e.type != prev_type:
+                if e.function_or_member is None:
+                    if e.type is None:
+                        result.append(
+                            (file, -1, -1, -1, -1, "note", "At top level:", e.allow_dups, None)
+                        )
+                    else:
+                        result.append(
+                            (
+                                file,
+                                -1,
+                                -1,
+                                -1,
+                                -1,
+                                "note",
+                                f'In class "{e.type}":',
+                                e.allow_dups,
+                                None,
+                            )
+                        )
+                else:
+                    if e.type is None:
+                        result.append(
+                            (
+                                file,
+                                -1,
+                                -1,
+                                -1,
+                                -1,
+                                "note",
+                                f'In function "{e.function_or_member}":',
+                                e.allow_dups,
+                                None,
+                            )
+                        )
+                    else:
+                        result.append(
+                            (
+                                file,
+                                -1,
+                                -1,
+                                -1,
+                                -1,
+                                "note",
+                                'In member "{}" of class "{}":'.format(
+                                    e.function_or_member, e.type
+                                ),
+                                e.allow_dups,
+                                None,
+                            )
+                        )
+            elif e.type != prev_type:
+                if e.type is None:
+                    result.append(
+                        (file, -1, -1, -1, -1, "note", "At top level:", e.allow_dups, None)
+                    )
+                else:
+                    result.append(
+                        (file, -1, -1, -1, -1, "note", f'In class "{e.type}":', e.allow_dups, None)
+                    )
+
+            if isinstance(e.message, ErrorMessage):
+                result.append(
+                    (
+                        file,
+                        e.line,
+                        e.column,
+                        e.end_line,
+                        e.end_column,
+                        e.severity,
+                        e.message.value,
+                        e.allow_dups,
+                        e.code,
+                    )
+                )
+            else:
+                result.append(
+                    (
+                        file,
+                        e.line,
+                        e.column,
+                        e.end_line,
+                        e.end_column,
+                        e.severity,
+                        e.message,
+                        e.allow_dups,
+                        e.code,
+                    )
+                )
+
+            prev_import_context = e.import_ctx
+            prev_function_or_member = e.function_or_member
+            prev_type = e.type
+
+        return result
+
+    def sort_messages(self, errors: list[ErrorInfo]) -> list[ErrorInfo]:
+        """Sort an array of error messages locally by line number.
+
+        I.e., sort a run of consecutive messages with the same
+        context by line number, but otherwise retain the general
+        ordering of the messages.
+        """
+        result: list[ErrorInfo] = []
+        i = 0
+        while i < len(errors):
+            i0 = i
+            # Find neighbouring errors with the same context and file.
+            while (
+                i + 1 < len(errors)
+                and errors[i + 1].import_ctx == errors[i].import_ctx
+                and errors[i + 1].file == errors[i].file
+            ):
+                i += 1
+            i += 1
+
+            # Sort the errors specific to a file according to line number and column.
+            a = sorted(errors[i0:i], key=lambda x: (x.line, x.column))
+            a = self.sort_within_context(a)
+            result.extend(a)
+        return result
+
+    def sort_within_context(self, errors: list[ErrorInfo]) -> list[ErrorInfo]:
+        """For the same location decide which messages to show first/last.
+
+        Currently, we only compare within the same error code, to decide the
+        order of various additional notes.
+        """
+        result = []
+        i = 0
+        while i < len(errors):
+            i0 = i
+            # Find neighbouring errors with the same position and error code.
+            while (
+                i + 1 < len(errors)
+                and errors[i + 1].line == errors[i].line
+                and errors[i + 1].column == errors[i].column
+                and errors[i + 1].end_line == errors[i].end_line
+                and errors[i + 1].end_column == errors[i].end_column
+                and errors[i + 1].code == errors[i].code
+            ):
+                i += 1
+            i += 1
+
+            # Sort the messages specific to a given error by priority.
+            a = sorted(errors[i0:i], key=lambda x: x.priority)
+            result.extend(a)
+        return result
+
+    def remove_duplicates(self, errors: list[ErrorTuple]) -> list[ErrorTuple]:
+        """Remove duplicates from a sorted error list."""
+        res: list[ErrorTuple] = []
+        i = 0
+        while i < len(errors):
+            dup = False
+            # Use slightly special formatting for member conflicts reporting.
+            conflicts_notes = False
+            j = i - 1
+            # Find duplicates, unless duplicates are allowed.
+            if not errors[i][7]:
+                while j >= 0 and errors[j][0] == errors[i][0]:
+                    if errors[j][6].strip() == "Got:":
+                        conflicts_notes = True
+                    j -= 1
+                j = i - 1
+                while j >= 0 and errors[j][0] == errors[i][0] and errors[j][1] == errors[i][1]:
+                    if (
+                        errors[j][5] == errors[i][5]
+                        and
+                        # Allow duplicate notes in overload conflicts reporting.
+                        not (
+                            (errors[i][5] == "note" and errors[i][6].strip() in allowed_duplicates)
+                            or (errors[i][6].strip().startswith("def ") and conflicts_notes)
+                        )
+                        and errors[j][6] == errors[i][6]
+                    ):  # ignore column
+                        dup = True
+                        break
+                    j -= 1
+            if not dup:
+                res.append(errors[i])
+            i += 1
+        return res
+
+
+class CompileError(Exception):
+    """Exception raised when there is a compile error.
+
+    It can be a parse, semantic analysis, type check or other
+    compilation-related error.
+
+    CompileErrors raised from an errors object carry all of the
+    messages that have not been reported out by error streaming.
+    This is patched up by build.build to contain either all error
+    messages (if errors were streamed) or none (if they were not).
+
+    """
+
+    messages: list[str]
+    use_stdout = False
+    # Can be set in case there was a module with a blocking error
+    module_with_blocker: str | None = None
+
+    def __init__(
+        self, messages: list[str], use_stdout: bool = False, module_with_blocker: str | None = None
+    ) -> None:
+        super().__init__("\n".join(messages))
+        self.messages = messages
+        self.use_stdout = use_stdout
+        self.module_with_blocker = module_with_blocker
+
+
+def remove_path_prefix(path: str, prefix: str | None) -> str:
+    """If path starts with prefix, return copy of path with the prefix removed.
+    Otherwise, return path. If path is None, return None.
+    """
+    if prefix is not None and path.startswith(prefix):
+        return path[len(prefix) :]
+    else:
+        return path
+
+
+def report_internal_error(
+    err: Exception,
+    file: str | None,
+    line: int,
+    errors: Errors,
+    options: Options,
+    stdout: TextIO | None = None,
+    stderr: TextIO | None = None,
+) -> NoReturn:
+    """Report internal error and exit.
+
+    This optionally starts pdb or shows a traceback.
+    """
+    stdout = stdout or sys.stdout
+    stderr = stderr or sys.stderr
+    # Dump out errors so far, they often provide a clue.
+    # But catch unexpected errors rendering them.
+    try:
+        for msg in errors.new_messages():
+            print(msg)
+    except Exception as e:
+        print("Failed to dump errors:", repr(e), file=stderr)
+
+    # Compute file:line prefix for official-looking error messages.
+    if file:
+        if line:
+            prefix = f"{file}:{line}: "
+        else:
+            prefix = f"{file}: "
+    else:
+        prefix = ""
+
+    # Print "INTERNAL ERROR" message.
+    print(
+        f"{prefix}error: INTERNAL ERROR --",
+        "Please try using mypy master on GitHub:\n"
+        "https://mypy.readthedocs.io/en/stable/common_issues.html"
+        "#using-a-development-mypy-build",
+        file=stderr,
+    )
+    if options.show_traceback:
+        print("Please report a bug at https://github.com/python/mypy/issues", file=stderr)
+    else:
+        print(
+            "If this issue continues with mypy master, "
+            "please report a bug at https://github.com/python/mypy/issues",
+            file=stderr,
+        )
+    print(f"version: {mypy_version}", file=stderr)
+
+    # If requested, drop into pdb. This overrides show_tb.
+    if options.pdb:
+        print("Dropping into pdb", file=stderr)
+        import pdb
+
+        pdb.post_mortem(sys.exc_info()[2])
+
+    # If requested, print traceback, else print note explaining how to get one.
+    if options.raise_exceptions:
+        raise err
+    if not options.show_traceback:
+        if not options.pdb:
+            print(
+                "{}: note: please use --show-traceback to print a traceback "
+                "when reporting a bug".format(prefix),
+                file=stderr,
+            )
+    else:
+        tb = traceback.extract_stack()[:-2]
+        tb2 = traceback.extract_tb(sys.exc_info()[2])
+        print("Traceback (most recent call last):")
+        for s in traceback.format_list(tb + tb2):
+            print(s.rstrip("\n"))
+        print(f"{type(err).__name__}: {err}", file=stdout)
+        print(f"{prefix}: note: use --pdb to drop into pdb", file=stderr)
+
+    # Exit.  The caller has nothing more to say.
+    # We use exit code 2 to signal that this is no ordinary error.
+    raise SystemExit(2)

二進制
venv/lib/python3.11/site-packages/mypy/evalexpr.cpython-311-x86_64-linux-gnu.so


+ 204 - 0
venv/lib/python3.11/site-packages/mypy/evalexpr.py

@@ -0,0 +1,204 @@
+"""
+
+Evaluate an expression.
+
+Used by stubtest; in a separate file because things break if we don't
+put it in a mypyc-compiled file.
+
+"""
+import ast
+from typing import Final
+
+import mypy.nodes
+from mypy.visitor import ExpressionVisitor
+
+UNKNOWN = object()
+
+
+class _NodeEvaluator(ExpressionVisitor[object]):
+    def visit_int_expr(self, o: mypy.nodes.IntExpr) -> int:
+        return o.value
+
+    def visit_str_expr(self, o: mypy.nodes.StrExpr) -> str:
+        return o.value
+
+    def visit_bytes_expr(self, o: mypy.nodes.BytesExpr) -> object:
+        # The value of a BytesExpr is a string created from the repr()
+        # of the bytes object. Get the original bytes back.
+        try:
+            return ast.literal_eval(f"b'{o.value}'")
+        except SyntaxError:
+            return ast.literal_eval(f'b"{o.value}"')
+
+    def visit_float_expr(self, o: mypy.nodes.FloatExpr) -> float:
+        return o.value
+
+    def visit_complex_expr(self, o: mypy.nodes.ComplexExpr) -> object:
+        return o.value
+
+    def visit_ellipsis(self, o: mypy.nodes.EllipsisExpr) -> object:
+        return Ellipsis
+
+    def visit_star_expr(self, o: mypy.nodes.StarExpr) -> object:
+        return UNKNOWN
+
+    def visit_name_expr(self, o: mypy.nodes.NameExpr) -> object:
+        if o.name == "True":
+            return True
+        elif o.name == "False":
+            return False
+        elif o.name == "None":
+            return None
+        # TODO: Handle more names by figuring out a way to hook into the
+        # symbol table.
+        return UNKNOWN
+
+    def visit_member_expr(self, o: mypy.nodes.MemberExpr) -> object:
+        return UNKNOWN
+
+    def visit_yield_from_expr(self, o: mypy.nodes.YieldFromExpr) -> object:
+        return UNKNOWN
+
+    def visit_yield_expr(self, o: mypy.nodes.YieldExpr) -> object:
+        return UNKNOWN
+
+    def visit_call_expr(self, o: mypy.nodes.CallExpr) -> object:
+        return UNKNOWN
+
+    def visit_op_expr(self, o: mypy.nodes.OpExpr) -> object:
+        return UNKNOWN
+
+    def visit_comparison_expr(self, o: mypy.nodes.ComparisonExpr) -> object:
+        return UNKNOWN
+
+    def visit_cast_expr(self, o: mypy.nodes.CastExpr) -> object:
+        return o.expr.accept(self)
+
+    def visit_assert_type_expr(self, o: mypy.nodes.AssertTypeExpr) -> object:
+        return o.expr.accept(self)
+
+    def visit_reveal_expr(self, o: mypy.nodes.RevealExpr) -> object:
+        return UNKNOWN
+
+    def visit_super_expr(self, o: mypy.nodes.SuperExpr) -> object:
+        return UNKNOWN
+
+    def visit_unary_expr(self, o: mypy.nodes.UnaryExpr) -> object:
+        operand = o.expr.accept(self)
+        if operand is UNKNOWN:
+            return UNKNOWN
+        if o.op == "-":
+            if isinstance(operand, (int, float, complex)):
+                return -operand
+        elif o.op == "+":
+            if isinstance(operand, (int, float, complex)):
+                return +operand
+        elif o.op == "~":
+            if isinstance(operand, int):
+                return ~operand
+        elif o.op == "not":
+            if isinstance(operand, (bool, int, float, str, bytes)):
+                return not operand
+        return UNKNOWN
+
+    def visit_assignment_expr(self, o: mypy.nodes.AssignmentExpr) -> object:
+        return o.value.accept(self)
+
+    def visit_list_expr(self, o: mypy.nodes.ListExpr) -> object:
+        items = [item.accept(self) for item in o.items]
+        if all(item is not UNKNOWN for item in items):
+            return items
+        return UNKNOWN
+
+    def visit_dict_expr(self, o: mypy.nodes.DictExpr) -> object:
+        items = [
+            (UNKNOWN if key is None else key.accept(self), value.accept(self))
+            for key, value in o.items
+        ]
+        if all(key is not UNKNOWN and value is not None for key, value in items):
+            return dict(items)
+        return UNKNOWN
+
+    def visit_tuple_expr(self, o: mypy.nodes.TupleExpr) -> object:
+        items = [item.accept(self) for item in o.items]
+        if all(item is not UNKNOWN for item in items):
+            return tuple(items)
+        return UNKNOWN
+
+    def visit_set_expr(self, o: mypy.nodes.SetExpr) -> object:
+        items = [item.accept(self) for item in o.items]
+        if all(item is not UNKNOWN for item in items):
+            return set(items)
+        return UNKNOWN
+
+    def visit_index_expr(self, o: mypy.nodes.IndexExpr) -> object:
+        return UNKNOWN
+
+    def visit_type_application(self, o: mypy.nodes.TypeApplication) -> object:
+        return UNKNOWN
+
+    def visit_lambda_expr(self, o: mypy.nodes.LambdaExpr) -> object:
+        return UNKNOWN
+
+    def visit_list_comprehension(self, o: mypy.nodes.ListComprehension) -> object:
+        return UNKNOWN
+
+    def visit_set_comprehension(self, o: mypy.nodes.SetComprehension) -> object:
+        return UNKNOWN
+
+    def visit_dictionary_comprehension(self, o: mypy.nodes.DictionaryComprehension) -> object:
+        return UNKNOWN
+
+    def visit_generator_expr(self, o: mypy.nodes.GeneratorExpr) -> object:
+        return UNKNOWN
+
+    def visit_slice_expr(self, o: mypy.nodes.SliceExpr) -> object:
+        return UNKNOWN
+
+    def visit_conditional_expr(self, o: mypy.nodes.ConditionalExpr) -> object:
+        return UNKNOWN
+
+    def visit_type_var_expr(self, o: mypy.nodes.TypeVarExpr) -> object:
+        return UNKNOWN
+
+    def visit_paramspec_expr(self, o: mypy.nodes.ParamSpecExpr) -> object:
+        return UNKNOWN
+
+    def visit_type_var_tuple_expr(self, o: mypy.nodes.TypeVarTupleExpr) -> object:
+        return UNKNOWN
+
+    def visit_type_alias_expr(self, o: mypy.nodes.TypeAliasExpr) -> object:
+        return UNKNOWN
+
+    def visit_namedtuple_expr(self, o: mypy.nodes.NamedTupleExpr) -> object:
+        return UNKNOWN
+
+    def visit_enum_call_expr(self, o: mypy.nodes.EnumCallExpr) -> object:
+        return UNKNOWN
+
+    def visit_typeddict_expr(self, o: mypy.nodes.TypedDictExpr) -> object:
+        return UNKNOWN
+
+    def visit_newtype_expr(self, o: mypy.nodes.NewTypeExpr) -> object:
+        return UNKNOWN
+
+    def visit__promote_expr(self, o: mypy.nodes.PromoteExpr) -> object:
+        return UNKNOWN
+
+    def visit_await_expr(self, o: mypy.nodes.AwaitExpr) -> object:
+        return UNKNOWN
+
+    def visit_temp_node(self, o: mypy.nodes.TempNode) -> object:
+        return UNKNOWN
+
+
+_evaluator: Final = _NodeEvaluator()
+
+
+def evaluate_expression(expr: mypy.nodes.Expression) -> object:
+    """Evaluate an expression at runtime.
+
+    Return the result of the expression, or UNKNOWN if the expression cannot be
+    evaluated.
+    """
+    return expr.accept(_evaluator)

二進制
venv/lib/python3.11/site-packages/mypy/expandtype.cpython-311-x86_64-linux-gnu.so


+ 613 - 0
venv/lib/python3.11/site-packages/mypy/expandtype.py

@@ -0,0 +1,613 @@
+from __future__ import annotations
+
+from typing import Final, Iterable, Mapping, Sequence, TypeVar, cast, overload
+
+from mypy.nodes import ARG_POS, ARG_STAR, ArgKind, Var
+from mypy.state import state
+from mypy.types import (
+    ANY_STRATEGY,
+    AnyType,
+    BoolTypeQuery,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    FunctionLike,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    Parameters,
+    ParamSpecFlavor,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TrivialSyntheticTypeTranslator,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeType,
+    TypeVarId,
+    TypeVarLikeType,
+    TypeVarTupleType,
+    TypeVarType,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+    flatten_nested_tuples,
+    flatten_nested_unions,
+    get_proper_type,
+    split_with_prefix_and_suffix,
+)
+from mypy.typevartuples import find_unpack_in_list, split_with_instance
+
+# Solving the import cycle:
+import mypy.type_visitor  # ruff: isort: skip
+
+# WARNING: these functions should never (directly or indirectly) depend on
+# is_subtype(), meet_types(), join_types() etc.
+# TODO: add a static dependency test for this.
+
+
+@overload
+def expand_type(typ: CallableType, env: Mapping[TypeVarId, Type]) -> CallableType:
+    ...
+
+
+@overload
+def expand_type(typ: ProperType, env: Mapping[TypeVarId, Type]) -> ProperType:
+    ...
+
+
+@overload
+def expand_type(typ: Type, env: Mapping[TypeVarId, Type]) -> Type:
+    ...
+
+
+def expand_type(typ: Type, env: Mapping[TypeVarId, Type]) -> Type:
+    """Substitute any type variable references in a type given by a type
+    environment.
+    """
+    return typ.accept(ExpandTypeVisitor(env))
+
+
+@overload
+def expand_type_by_instance(typ: CallableType, instance: Instance) -> CallableType:
+    ...
+
+
+@overload
+def expand_type_by_instance(typ: ProperType, instance: Instance) -> ProperType:
+    ...
+
+
+@overload
+def expand_type_by_instance(typ: Type, instance: Instance) -> Type:
+    ...
+
+
+def expand_type_by_instance(typ: Type, instance: Instance) -> Type:
+    """Substitute type variables in type using values from an Instance.
+    Type variables are considered to be bound by the class declaration."""
+    if not instance.args:
+        return typ
+    else:
+        variables: dict[TypeVarId, Type] = {}
+        if instance.type.has_type_var_tuple_type:
+            assert instance.type.type_var_tuple_prefix is not None
+            assert instance.type.type_var_tuple_suffix is not None
+
+            args_prefix, args_middle, args_suffix = split_with_instance(instance)
+            tvars_prefix, tvars_middle, tvars_suffix = split_with_prefix_and_suffix(
+                tuple(instance.type.defn.type_vars),
+                instance.type.type_var_tuple_prefix,
+                instance.type.type_var_tuple_suffix,
+            )
+            tvar = tvars_middle[0]
+            assert isinstance(tvar, TypeVarTupleType)
+            variables = {tvar.id: TupleType(list(args_middle), tvar.tuple_fallback)}
+            instance_args = args_prefix + args_suffix
+            tvars = tvars_prefix + tvars_suffix
+        else:
+            tvars = tuple(instance.type.defn.type_vars)
+            instance_args = instance.args
+
+        for binder, arg in zip(tvars, instance_args):
+            assert isinstance(binder, TypeVarLikeType)
+            variables[binder.id] = arg
+
+        return expand_type(typ, variables)
+
+
+F = TypeVar("F", bound=FunctionLike)
+
+
+def freshen_function_type_vars(callee: F) -> F:
+    """Substitute fresh type variables for generic function type variables."""
+    if isinstance(callee, CallableType):
+        if not callee.is_generic():
+            return cast(F, callee)
+        tvs = []
+        tvmap: dict[TypeVarId, Type] = {}
+        for v in callee.variables:
+            tv = v.new_unification_variable(v)
+            tvs.append(tv)
+            tvmap[v.id] = tv
+        fresh = expand_type(callee, tvmap).copy_modified(variables=tvs)
+        return cast(F, fresh)
+    else:
+        assert isinstance(callee, Overloaded)
+        fresh_overload = Overloaded([freshen_function_type_vars(item) for item in callee.items])
+        return cast(F, fresh_overload)
+
+
+class HasGenericCallable(BoolTypeQuery):
+    def __init__(self) -> None:
+        super().__init__(ANY_STRATEGY)
+
+    def visit_callable_type(self, t: CallableType) -> bool:
+        return t.is_generic() or super().visit_callable_type(t)
+
+
+# Share a singleton since this is performance sensitive
+has_generic_callable: Final = HasGenericCallable()
+
+
+T = TypeVar("T", bound=Type)
+
+
+def freshen_all_functions_type_vars(t: T) -> T:
+    result: Type
+    has_generic_callable.reset()
+    if not t.accept(has_generic_callable):
+        return t  # Fast path to avoid expensive freshening
+    else:
+        result = t.accept(FreshenCallableVisitor())
+        assert isinstance(result, type(t))
+        return result
+
+
+class FreshenCallableVisitor(mypy.type_visitor.TypeTranslator):
+    def visit_callable_type(self, t: CallableType) -> Type:
+        result = super().visit_callable_type(t)
+        assert isinstance(result, ProperType) and isinstance(result, CallableType)
+        return freshen_function_type_vars(result)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        # Same as for ExpandTypeVisitor
+        return t.copy_modified(args=[arg.accept(self) for arg in t.args])
+
+
+class ExpandTypeVisitor(TrivialSyntheticTypeTranslator):
+    """Visitor that substitutes type variables with values."""
+
+    variables: Mapping[TypeVarId, Type]  # TypeVar id -> TypeVar value
+
+    def __init__(self, variables: Mapping[TypeVarId, Type]) -> None:
+        self.variables = variables
+
+    def visit_unbound_type(self, t: UnboundType) -> Type:
+        return t
+
+    def visit_any(self, t: AnyType) -> Type:
+        return t
+
+    def visit_none_type(self, t: NoneType) -> Type:
+        return t
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
+        return t
+
+    def visit_deleted_type(self, t: DeletedType) -> Type:
+        return t
+
+    def visit_erased_type(self, t: ErasedType) -> Type:
+        # This may happen during type inference if some function argument
+        # type is a generic callable, and its erased form will appear in inferred
+        # constraints, then solver may check subtyping between them, which will trigger
+        # unify_generic_callables(), this is why we can get here. Another example is
+        # when inferring type of lambda in generic context, the lambda body contains
+        # a generic method in generic class.
+        return t
+
+    def visit_instance(self, t: Instance) -> Type:
+        args = self.expand_types_with_unpack(list(t.args))
+        if isinstance(args, list):
+            return t.copy_modified(args=args)
+        else:
+            return args
+
+    def visit_type_var(self, t: TypeVarType) -> Type:
+        # Normally upper bounds can't contain other type variables, the only exception is
+        # special type variable Self`0 <: C[T, S], where C is the class where Self is used.
+        if t.id.raw_id == 0:
+            t = t.copy_modified(upper_bound=t.upper_bound.accept(self))
+        repl = self.variables.get(t.id, t)
+        if isinstance(repl, ProperType) and isinstance(repl, Instance):
+            # TODO: do we really need to do this?
+            # If I try to remove this special-casing ~40 tests fail on reveal_type().
+            return repl.copy_modified(last_known_value=None)
+        return repl
+
+    def visit_param_spec(self, t: ParamSpecType) -> Type:
+        # set prefix to something empty so we don't duplicate it
+        repl = get_proper_type(
+            self.variables.get(t.id, t.copy_modified(prefix=Parameters([], [], [])))
+        )
+        if isinstance(repl, Instance):
+            # TODO: what does prefix mean in this case?
+            # TODO: why does this case even happen? Instances aren't plural.
+            return repl
+        elif isinstance(repl, (ParamSpecType, Parameters, CallableType)):
+            if isinstance(repl, ParamSpecType):
+                return repl.copy_modified(
+                    flavor=t.flavor,
+                    prefix=t.prefix.copy_modified(
+                        arg_types=t.prefix.arg_types + repl.prefix.arg_types,
+                        arg_kinds=t.prefix.arg_kinds + repl.prefix.arg_kinds,
+                        arg_names=t.prefix.arg_names + repl.prefix.arg_names,
+                    ),
+                )
+            else:
+                # if the paramspec is *P.args or **P.kwargs:
+                if t.flavor != ParamSpecFlavor.BARE:
+                    assert isinstance(repl, CallableType), "Should not be able to get here."
+                    # Is this always the right thing to do?
+                    param_spec = repl.param_spec()
+                    if param_spec:
+                        return param_spec.with_flavor(t.flavor)
+                    else:
+                        return repl
+                else:
+                    return Parameters(
+                        t.prefix.arg_types + repl.arg_types,
+                        t.prefix.arg_kinds + repl.arg_kinds,
+                        t.prefix.arg_names + repl.arg_names,
+                        variables=[*t.prefix.variables, *repl.variables],
+                    )
+
+        else:
+            # TODO: should this branch be removed? better not to fail silently
+            return repl
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
+        raise NotImplementedError
+
+    def visit_unpack_type(self, t: UnpackType) -> Type:
+        # It is impossible to reasonably implement visit_unpack_type, because
+        # unpacking inherently expands to something more like a list of types.
+        #
+        # Relevant sections that can call unpack should call expand_unpack()
+        # instead.
+        # However, if the item is a variadic tuple, we can simply carry it over.
+        # it is hard to assert this without getting proper type.
+        return UnpackType(t.type.accept(self))
+
+    def expand_unpack(self, t: UnpackType) -> list[Type] | Instance | AnyType | None:
+        return expand_unpack_with_variables(t, self.variables)
+
+    def visit_parameters(self, t: Parameters) -> Type:
+        return t.copy_modified(arg_types=self.expand_types(t.arg_types))
+
+    def interpolate_args_for_unpack(
+        self, t: CallableType, var_arg: UnpackType
+    ) -> tuple[list[str | None], list[ArgKind], list[Type]]:
+        star_index = t.arg_kinds.index(ARG_STAR)
+
+        # We have something like Unpack[Tuple[X1, X2, Unpack[Ts], Y1, Y2]]
+        var_arg_type = get_proper_type(var_arg.type)
+        if isinstance(var_arg_type, TupleType):
+            expanded_tuple = var_arg_type.accept(self)
+            # TODO: handle the case that expanded_tuple is a variable length tuple.
+            assert isinstance(expanded_tuple, ProperType) and isinstance(expanded_tuple, TupleType)
+            expanded_items = expanded_tuple.items
+        else:
+            expanded_items_res = self.expand_unpack(var_arg)
+            if isinstance(expanded_items_res, list):
+                expanded_items = expanded_items_res
+            elif (
+                isinstance(expanded_items_res, Instance)
+                and expanded_items_res.type.fullname == "builtins.tuple"
+            ):
+                # TODO: We shouldnt't simply treat this as a *arg because of suffix handling
+                # (there cannot be positional args after a *arg)
+                arg_types = (
+                    t.arg_types[:star_index]
+                    + [expanded_items_res.args[0]]
+                    + t.arg_types[star_index + 1 :]
+                )
+                return (t.arg_names, t.arg_kinds, arg_types)
+            else:
+                return (t.arg_names, t.arg_kinds, t.arg_types)
+
+        expanded_unpack_index = find_unpack_in_list(expanded_items)
+        # This is the case where we just have Unpack[Tuple[X1, X2, X3]]
+        # (for example if either the tuple had no unpacks, or the unpack in the
+        # tuple got fully expanded to something with fixed length)
+        if expanded_unpack_index is None:
+            arg_names = (
+                t.arg_names[:star_index]
+                + [None] * len(expanded_items)
+                + t.arg_names[star_index + 1 :]
+            )
+            arg_kinds = (
+                t.arg_kinds[:star_index]
+                + [ARG_POS] * len(expanded_items)
+                + t.arg_kinds[star_index + 1 :]
+            )
+            arg_types = (
+                self.expand_types(t.arg_types[:star_index])
+                + expanded_items
+                + self.expand_types(t.arg_types[star_index + 1 :])
+            )
+        else:
+            # If Unpack[Ts] simplest form still has an unpack or is a
+            # homogenous tuple, then only the prefix can be represented as
+            # positional arguments, and we pass Tuple[Unpack[Ts-1], Y1, Y2]
+            # as the star arg, for example.
+            expanded_unpack = expanded_items[expanded_unpack_index]
+            assert isinstance(expanded_unpack, UnpackType)
+
+            # Extract the typevartuple so we can get a tuple fallback from it.
+            expanded_unpacked_tvt = expanded_unpack.type
+            if isinstance(expanded_unpacked_tvt, TypeVarTupleType):
+                fallback = expanded_unpacked_tvt.tuple_fallback
+            else:
+                # This can happen when tuple[Any, ...] is used to "patch" a variadic
+                # generic type without type arguments provided.
+                assert isinstance(expanded_unpacked_tvt, ProperType)
+                assert isinstance(expanded_unpacked_tvt, Instance)
+                assert expanded_unpacked_tvt.type.fullname == "builtins.tuple"
+                fallback = expanded_unpacked_tvt
+
+            prefix_len = expanded_unpack_index
+            arg_names = t.arg_names[:star_index] + [None] * prefix_len + t.arg_names[star_index:]
+            arg_kinds = (
+                t.arg_kinds[:star_index] + [ARG_POS] * prefix_len + t.arg_kinds[star_index:]
+            )
+            arg_types = (
+                self.expand_types(t.arg_types[:star_index])
+                + expanded_items[:prefix_len]
+                # Constructing the Unpack containing the tuple without the prefix.
+                + [
+                    UnpackType(TupleType(expanded_items[prefix_len:], fallback))
+                    if len(expanded_items) - prefix_len > 1
+                    else expanded_items[0]
+                ]
+                + self.expand_types(t.arg_types[star_index + 1 :])
+            )
+        return (arg_names, arg_kinds, arg_types)
+
+    def visit_callable_type(self, t: CallableType) -> CallableType:
+        param_spec = t.param_spec()
+        if param_spec is not None:
+            repl = get_proper_type(self.variables.get(param_spec.id))
+            # If a ParamSpec in a callable type is substituted with a
+            # callable type, we can't use normal substitution logic,
+            # since ParamSpec is actually split into two components
+            # *P.args and **P.kwargs in the original type. Instead, we
+            # must expand both of them with all the argument types,
+            # kinds and names in the replacement. The return type in
+            # the replacement is ignored.
+            if isinstance(repl, (CallableType, Parameters)):
+                # Substitute *args: P.args, **kwargs: P.kwargs
+                prefix = param_spec.prefix
+                # we need to expand the types in the prefix, so might as well
+                # not get them in the first place
+                t = t.expand_param_spec(repl, no_prefix=True)
+                return t.copy_modified(
+                    arg_types=self.expand_types(prefix.arg_types) + t.arg_types,
+                    arg_kinds=prefix.arg_kinds + t.arg_kinds,
+                    arg_names=prefix.arg_names + t.arg_names,
+                    ret_type=t.ret_type.accept(self),
+                    type_guard=(t.type_guard.accept(self) if t.type_guard is not None else None),
+                )
+            # TODO: Conceptually, the "len(t.arg_types) == 2" should not be here. However, this
+            #       errors without it. Either figure out how to eliminate this or place an
+            #       explanation for why this is necessary.
+            elif isinstance(repl, ParamSpecType) and len(t.arg_types) == 2:
+                # We're substituting one paramspec for another; this can mean that the prefix
+                # changes. (e.g. sub Concatenate[int, P] for Q)
+                prefix = repl.prefix
+                old_prefix = param_spec.prefix
+
+                # Check assumptions. I'm not sure what order to place new prefix vs old prefix:
+                assert not old_prefix.arg_types or not prefix.arg_types
+
+                t = t.copy_modified(
+                    arg_types=prefix.arg_types + old_prefix.arg_types + t.arg_types,
+                    arg_kinds=prefix.arg_kinds + old_prefix.arg_kinds + t.arg_kinds,
+                    arg_names=prefix.arg_names + old_prefix.arg_names + t.arg_names,
+                )
+
+        var_arg = t.var_arg()
+        if var_arg is not None and isinstance(var_arg.typ, UnpackType):
+            arg_names, arg_kinds, arg_types = self.interpolate_args_for_unpack(t, var_arg.typ)
+        else:
+            arg_names = t.arg_names
+            arg_kinds = t.arg_kinds
+            arg_types = self.expand_types(t.arg_types)
+
+        return t.copy_modified(
+            arg_types=arg_types,
+            arg_names=arg_names,
+            arg_kinds=arg_kinds,
+            ret_type=t.ret_type.accept(self),
+            type_guard=(t.type_guard.accept(self) if t.type_guard is not None else None),
+        )
+
+    def visit_overloaded(self, t: Overloaded) -> Type:
+        items: list[CallableType] = []
+        for item in t.items:
+            new_item = item.accept(self)
+            assert isinstance(new_item, ProperType)
+            assert isinstance(new_item, CallableType)
+            items.append(new_item)
+        return Overloaded(items)
+
+    def expand_types_with_unpack(
+        self, typs: Sequence[Type]
+    ) -> list[Type] | AnyType | UninhabitedType | Instance:
+        """Expands a list of types that has an unpack.
+
+        In corner cases, this can return a type rather than a list, in which case this
+        indicates use of Any or some error occurred earlier. In this case callers should
+        simply propagate the resulting type.
+        """
+        # TODO: this will cause a crash on aliases like A = Tuple[int, Unpack[A]].
+        # Although it is unlikely anyone will write this, we should fail gracefully.
+        typs = flatten_nested_tuples(typs)
+        items: list[Type] = []
+        for item in typs:
+            if isinstance(item, UnpackType) and isinstance(item.type, TypeVarTupleType):
+                unpacked_items = self.expand_unpack(item)
+                if unpacked_items is None:
+                    # TODO: better error, something like tuple of unknown?
+                    return UninhabitedType()
+                elif isinstance(unpacked_items, Instance):
+                    if len(typs) == 1:
+                        return unpacked_items
+                    else:
+                        assert False, "Invalid unpack of variable length tuple"
+                elif isinstance(unpacked_items, AnyType):
+                    return unpacked_items
+                else:
+                    items.extend(unpacked_items)
+            else:
+                # Must preserve original aliases when possible.
+                items.append(item.accept(self))
+        return items
+
+    def visit_tuple_type(self, t: TupleType) -> Type:
+        items = self.expand_types_with_unpack(t.items)
+        if isinstance(items, list):
+            fallback = t.partial_fallback.accept(self)
+            assert isinstance(fallback, ProperType) and isinstance(fallback, Instance)
+            return t.copy_modified(items=items, fallback=fallback)
+        else:
+            return items
+
+    def visit_typeddict_type(self, t: TypedDictType) -> Type:
+        fallback = t.fallback.accept(self)
+        assert isinstance(fallback, ProperType) and isinstance(fallback, Instance)
+        return t.copy_modified(item_types=self.expand_types(t.items.values()), fallback=fallback)
+
+    def visit_literal_type(self, t: LiteralType) -> Type:
+        # TODO: Verify this implementation is correct
+        return t
+
+    def visit_union_type(self, t: UnionType) -> Type:
+        expanded = self.expand_types(t.items)
+        # After substituting for type variables in t.items, some resulting types
+        # might be subtypes of others, however calling  make_simplified_union()
+        # can cause recursion, so we just remove strict duplicates.
+        simplified = UnionType.make_union(
+            remove_trivial(flatten_nested_unions(expanded)), t.line, t.column
+        )
+        # This call to get_proper_type() is unfortunate but is required to preserve
+        # the invariant that ProperType will stay ProperType after applying expand_type(),
+        # otherwise a single item union of a type alias will break it. Note this should not
+        # cause infinite recursion since pathological aliases like A = Union[A, B] are
+        # banned at the semantic analysis level.
+        return get_proper_type(simplified)
+
+    def visit_partial_type(self, t: PartialType) -> Type:
+        return t
+
+    def visit_type_type(self, t: TypeType) -> Type:
+        # TODO: Verify that the new item type is valid (instance or
+        # union of instances or Any).  Sadly we can't report errors
+        # here yet.
+        item = t.item.accept(self)
+        return TypeType.make_normalized(item)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
+        # Target of the type alias cannot contain type variables (not bound by the type
+        # alias itself), so we just expand the arguments.
+        args = self.expand_types_with_unpack(t.args)
+        if isinstance(args, list):
+            return t.copy_modified(args=args)
+        else:
+            return args
+
+    def expand_types(self, types: Iterable[Type]) -> list[Type]:
+        a: list[Type] = []
+        for t in types:
+            a.append(t.accept(self))
+        return a
+
+
+def expand_unpack_with_variables(
+    t: UnpackType, variables: Mapping[TypeVarId, Type]
+) -> list[Type] | Instance | AnyType | None:
+    """May return either a list of types to unpack to, any, or a single
+    variable length tuple. The latter may not be valid in all contexts.
+    """
+    if isinstance(t.type, TypeVarTupleType):
+        repl = get_proper_type(variables.get(t.type.id, t))
+        if isinstance(repl, TupleType):
+            return repl.items
+        elif isinstance(repl, Instance) and repl.type.fullname == "builtins.tuple":
+            return repl
+        elif isinstance(repl, AnyType):
+            # tuple[Any, ...] would be better, but we don't have
+            # the type info to construct that type here.
+            return repl
+        elif isinstance(repl, TypeVarTupleType):
+            return [UnpackType(typ=repl)]
+        elif isinstance(repl, UnpackType):
+            return [repl]
+        elif isinstance(repl, UninhabitedType):
+            return None
+        else:
+            raise NotImplementedError(f"Invalid type replacement to expand: {repl}")
+    else:
+        raise NotImplementedError(f"Invalid type to expand: {t.type}")
+
+
+@overload
+def expand_self_type(var: Var, typ: ProperType, replacement: ProperType) -> ProperType:
+    ...
+
+
+@overload
+def expand_self_type(var: Var, typ: Type, replacement: Type) -> Type:
+    ...
+
+
+def expand_self_type(var: Var, typ: Type, replacement: Type) -> Type:
+    """Expand appearances of Self type in a variable type."""
+    if var.info.self_type is not None and not var.is_property:
+        return expand_type(typ, {var.info.self_type.id: replacement})
+    return typ
+
+
+def remove_trivial(types: Iterable[Type]) -> list[Type]:
+    """Make trivial simplifications on a list of types without calling is_subtype().
+
+    This makes following simplifications:
+        * Remove bottom types (taking into account strict optional setting)
+        * Remove everything else if there is an `object`
+        * Remove strict duplicate types
+    """
+    removed_none = False
+    new_types = []
+    all_types = set()
+    for t in types:
+        p_t = get_proper_type(t)
+        if isinstance(p_t, UninhabitedType):
+            continue
+        if isinstance(p_t, NoneType) and not state.strict_optional:
+            removed_none = True
+            continue
+        if isinstance(p_t, Instance) and p_t.type.fullname == "builtins.object":
+            return [p_t]
+        if p_t not in all_types:
+            new_types.append(t)
+            all_types.add(p_t)
+    if new_types:
+        return new_types
+    if removed_none:
+        return [NoneType()]
+    return [UninhabitedType()]

二進制
venv/lib/python3.11/site-packages/mypy/exprtotype.cpython-311-x86_64-linux-gnu.so


+ 193 - 0
venv/lib/python3.11/site-packages/mypy/exprtotype.py

@@ -0,0 +1,193 @@
+"""Translate an Expression to a Type value."""
+
+from __future__ import annotations
+
+from mypy.fastparse import parse_type_string
+from mypy.nodes import (
+    BytesExpr,
+    CallExpr,
+    ComplexExpr,
+    EllipsisExpr,
+    Expression,
+    FloatExpr,
+    IndexExpr,
+    IntExpr,
+    ListExpr,
+    MemberExpr,
+    NameExpr,
+    OpExpr,
+    RefExpr,
+    StrExpr,
+    TupleExpr,
+    UnaryExpr,
+    get_member_expr_fullname,
+)
+from mypy.options import Options
+from mypy.types import (
+    ANNOTATED_TYPE_NAMES,
+    AnyType,
+    CallableArgument,
+    EllipsisType,
+    ProperType,
+    RawExpressionType,
+    Type,
+    TypeList,
+    TypeOfAny,
+    UnboundType,
+    UnionType,
+)
+
+
+class TypeTranslationError(Exception):
+    """Exception raised when an expression is not valid as a type."""
+
+
+def _extract_argument_name(expr: Expression) -> str | None:
+    if isinstance(expr, NameExpr) and expr.name == "None":
+        return None
+    elif isinstance(expr, StrExpr):
+        return expr.value
+    else:
+        raise TypeTranslationError()
+
+
+def expr_to_unanalyzed_type(
+    expr: Expression,
+    options: Options | None = None,
+    allow_new_syntax: bool = False,
+    _parent: Expression | None = None,
+) -> ProperType:
+    """Translate an expression to the corresponding type.
+
+    The result is not semantically analyzed. It can be UnboundType or TypeList.
+    Raise TypeTranslationError if the expression cannot represent a type.
+
+    If allow_new_syntax is True, allow all type syntax independent of the target
+    Python version (used in stubs).
+    """
+    # The `parent` parameter is used in recursive calls to provide context for
+    # understanding whether an CallableArgument is ok.
+    name: str | None = None
+    if isinstance(expr, NameExpr):
+        name = expr.name
+        if name == "True":
+            return RawExpressionType(True, "builtins.bool", line=expr.line, column=expr.column)
+        elif name == "False":
+            return RawExpressionType(False, "builtins.bool", line=expr.line, column=expr.column)
+        else:
+            return UnboundType(name, line=expr.line, column=expr.column)
+    elif isinstance(expr, MemberExpr):
+        fullname = get_member_expr_fullname(expr)
+        if fullname:
+            return UnboundType(fullname, line=expr.line, column=expr.column)
+        else:
+            raise TypeTranslationError()
+    elif isinstance(expr, IndexExpr):
+        base = expr_to_unanalyzed_type(expr.base, options, allow_new_syntax, expr)
+        if isinstance(base, UnboundType):
+            if base.args:
+                raise TypeTranslationError()
+            if isinstance(expr.index, TupleExpr):
+                args = expr.index.items
+            else:
+                args = [expr.index]
+
+            if isinstance(expr.base, RefExpr) and expr.base.fullname in ANNOTATED_TYPE_NAMES:
+                # TODO: this is not the optimal solution as we are basically getting rid
+                # of the Annotation definition and only returning the type information,
+                # losing all the annotations.
+
+                return expr_to_unanalyzed_type(args[0], options, allow_new_syntax, expr)
+            else:
+                base.args = tuple(
+                    expr_to_unanalyzed_type(arg, options, allow_new_syntax, expr) for arg in args
+                )
+            if not base.args:
+                base.empty_tuple_index = True
+            return base
+        else:
+            raise TypeTranslationError()
+    elif (
+        isinstance(expr, OpExpr)
+        and expr.op == "|"
+        and ((options and options.python_version >= (3, 10)) or allow_new_syntax)
+    ):
+        return UnionType(
+            [
+                expr_to_unanalyzed_type(expr.left, options, allow_new_syntax),
+                expr_to_unanalyzed_type(expr.right, options, allow_new_syntax),
+            ]
+        )
+    elif isinstance(expr, CallExpr) and isinstance(_parent, ListExpr):
+        c = expr.callee
+        names = []
+        # Go through the dotted member expr chain to get the full arg
+        # constructor name to look up
+        while True:
+            if isinstance(c, NameExpr):
+                names.append(c.name)
+                break
+            elif isinstance(c, MemberExpr):
+                names.append(c.name)
+                c = c.expr
+            else:
+                raise TypeTranslationError()
+        arg_const = ".".join(reversed(names))
+
+        # Go through the constructor args to get its name and type.
+        name = None
+        default_type = AnyType(TypeOfAny.unannotated)
+        typ: Type = default_type
+        for i, arg in enumerate(expr.args):
+            if expr.arg_names[i] is not None:
+                if expr.arg_names[i] == "name":
+                    if name is not None:
+                        # Two names
+                        raise TypeTranslationError()
+                    name = _extract_argument_name(arg)
+                    continue
+                elif expr.arg_names[i] == "type":
+                    if typ is not default_type:
+                        # Two types
+                        raise TypeTranslationError()
+                    typ = expr_to_unanalyzed_type(arg, options, allow_new_syntax, expr)
+                    continue
+                else:
+                    raise TypeTranslationError()
+            elif i == 0:
+                typ = expr_to_unanalyzed_type(arg, options, allow_new_syntax, expr)
+            elif i == 1:
+                name = _extract_argument_name(arg)
+            else:
+                raise TypeTranslationError()
+        return CallableArgument(typ, name, arg_const, expr.line, expr.column)
+    elif isinstance(expr, ListExpr):
+        return TypeList(
+            [expr_to_unanalyzed_type(t, options, allow_new_syntax, expr) for t in expr.items],
+            line=expr.line,
+            column=expr.column,
+        )
+    elif isinstance(expr, StrExpr):
+        return parse_type_string(expr.value, "builtins.str", expr.line, expr.column)
+    elif isinstance(expr, BytesExpr):
+        return parse_type_string(expr.value, "builtins.bytes", expr.line, expr.column)
+    elif isinstance(expr, UnaryExpr):
+        typ = expr_to_unanalyzed_type(expr.expr, options, allow_new_syntax)
+        if isinstance(typ, RawExpressionType):
+            if isinstance(typ.literal_value, int) and expr.op == "-":
+                typ.literal_value *= -1
+                return typ
+        raise TypeTranslationError()
+    elif isinstance(expr, IntExpr):
+        return RawExpressionType(expr.value, "builtins.int", line=expr.line, column=expr.column)
+    elif isinstance(expr, FloatExpr):
+        # Floats are not valid parameters for RawExpressionType , so we just
+        # pass in 'None' for now. We'll report the appropriate error at a later stage.
+        return RawExpressionType(None, "builtins.float", line=expr.line, column=expr.column)
+    elif isinstance(expr, ComplexExpr):
+        # Same thing as above with complex numbers.
+        return RawExpressionType(None, "builtins.complex", line=expr.line, column=expr.column)
+    elif isinstance(expr, EllipsisExpr):
+        return EllipsisType(expr.line)
+    else:
+        raise TypeTranslationError()

二進制
venv/lib/python3.11/site-packages/mypy/fastparse.cpython-311-x86_64-linux-gnu.so


+ 2100 - 0
venv/lib/python3.11/site-packages/mypy/fastparse.py

@@ -0,0 +1,2100 @@
+from __future__ import annotations
+
+import copy
+import re
+import sys
+import warnings
+from typing import Any, Callable, Final, List, Optional, Sequence, TypeVar, Union, cast
+from typing_extensions import Literal, overload
+
+from mypy import defaults, errorcodes as codes, message_registry
+from mypy.errors import Errors
+from mypy.message_registry import ErrorMessage
+from mypy.nodes import (
+    ARG_NAMED,
+    ARG_NAMED_OPT,
+    ARG_OPT,
+    ARG_POS,
+    ARG_STAR,
+    ARG_STAR2,
+    ArgKind,
+    Argument,
+    AssertStmt,
+    AssignmentExpr,
+    AssignmentStmt,
+    AwaitExpr,
+    Block,
+    BreakStmt,
+    BytesExpr,
+    CallExpr,
+    ClassDef,
+    ComparisonExpr,
+    ComplexExpr,
+    ConditionalExpr,
+    ContinueStmt,
+    Decorator,
+    DelStmt,
+    DictExpr,
+    DictionaryComprehension,
+    EllipsisExpr,
+    Expression,
+    ExpressionStmt,
+    FakeInfo,
+    FloatExpr,
+    ForStmt,
+    FuncDef,
+    GeneratorExpr,
+    GlobalDecl,
+    IfStmt,
+    Import,
+    ImportAll,
+    ImportBase,
+    ImportFrom,
+    IndexExpr,
+    IntExpr,
+    LambdaExpr,
+    ListComprehension,
+    ListExpr,
+    MatchStmt,
+    MemberExpr,
+    MypyFile,
+    NameExpr,
+    Node,
+    NonlocalDecl,
+    OperatorAssignmentStmt,
+    OpExpr,
+    OverloadedFuncDef,
+    OverloadPart,
+    PassStmt,
+    RaiseStmt,
+    RefExpr,
+    ReturnStmt,
+    SetComprehension,
+    SetExpr,
+    SliceExpr,
+    StarExpr,
+    Statement,
+    StrExpr,
+    SuperExpr,
+    TempNode,
+    TryStmt,
+    TupleExpr,
+    UnaryExpr,
+    Var,
+    WhileStmt,
+    WithStmt,
+    YieldExpr,
+    YieldFromExpr,
+    check_arg_names,
+)
+from mypy.options import Options
+from mypy.patterns import (
+    AsPattern,
+    ClassPattern,
+    MappingPattern,
+    OrPattern,
+    SequencePattern,
+    SingletonPattern,
+    StarredPattern,
+    ValuePattern,
+)
+from mypy.reachability import infer_reachability_of_if_statement, mark_block_unreachable
+from mypy.sharedparse import argument_elide_name, special_function_elide_names
+from mypy.traverser import TraverserVisitor
+from mypy.types import (
+    AnyType,
+    CallableArgument,
+    CallableType,
+    EllipsisType,
+    Instance,
+    ProperType,
+    RawExpressionType,
+    TupleType,
+    Type,
+    TypeList,
+    TypeOfAny,
+    UnboundType,
+    UnionType,
+)
+from mypy.util import bytes_to_human_readable_repr, unnamed_function
+
+# pull this into a final variable to make mypyc be quiet about the
+# the default argument warning
+PY_MINOR_VERSION: Final = sys.version_info[1]
+
+import ast as ast3
+
+# TODO: Index, ExtSlice are deprecated in 3.9.
+from ast import AST, Attribute, Call, FunctionType, Index, Name, Starred, UnaryOp, USub
+
+
+def ast3_parse(
+    source: str | bytes, filename: str, mode: str, feature_version: int = PY_MINOR_VERSION
+) -> AST:
+    return ast3.parse(
+        source,
+        filename,
+        mode,
+        type_comments=True,  # This works the magic
+        feature_version=feature_version,
+    )
+
+
+NamedExpr = ast3.NamedExpr
+Constant = ast3.Constant
+
+if sys.version_info >= (3, 10):
+    Match = ast3.Match
+    MatchValue = ast3.MatchValue
+    MatchSingleton = ast3.MatchSingleton
+    MatchSequence = ast3.MatchSequence
+    MatchStar = ast3.MatchStar
+    MatchMapping = ast3.MatchMapping
+    MatchClass = ast3.MatchClass
+    MatchAs = ast3.MatchAs
+    MatchOr = ast3.MatchOr
+    AstNode = Union[ast3.expr, ast3.stmt, ast3.pattern, ast3.ExceptHandler]
+else:
+    Match = Any
+    MatchValue = Any
+    MatchSingleton = Any
+    MatchSequence = Any
+    MatchStar = Any
+    MatchMapping = Any
+    MatchClass = Any
+    MatchAs = Any
+    MatchOr = Any
+    AstNode = Union[ast3.expr, ast3.stmt, ast3.ExceptHandler]
+if sys.version_info >= (3, 11):
+    TryStar = ast3.TryStar
+else:
+    TryStar = Any
+
+N = TypeVar("N", bound=Node)
+
+# There is no way to create reasonable fallbacks at this stage,
+# they must be patched later.
+MISSING_FALLBACK: Final = FakeInfo("fallback can't be filled out until semanal")
+_dummy_fallback: Final = Instance(MISSING_FALLBACK, [], -1)
+
+TYPE_IGNORE_PATTERN: Final = re.compile(r"[^#]*#\s*type:\s*ignore\s*(.*)")
+
+
+def parse(
+    source: str | bytes,
+    fnam: str,
+    module: str | None,
+    errors: Errors | None = None,
+    options: Options | None = None,
+) -> MypyFile:
+    """Parse a source file, without doing any semantic analysis.
+
+    Return the parse tree. If errors is not provided, raise ParseError
+    on failure. Otherwise, use the errors object to report parse errors.
+    """
+    ignore_errors = (options is not None and options.ignore_errors) or (
+        errors is not None and fnam in errors.ignored_files
+    )
+    # If errors are ignored, we can drop many function bodies to speed up type checking.
+    strip_function_bodies = ignore_errors and (options is None or not options.preserve_asts)
+    raise_on_error = False
+    if options is None:
+        options = Options()
+    if errors is None:
+        errors = Errors(options)
+        raise_on_error = True
+    errors.set_file(fnam, module, options=options)
+    is_stub_file = fnam.endswith(".pyi")
+    if is_stub_file:
+        feature_version = defaults.PYTHON3_VERSION[1]
+        if options.python_version[0] == 3 and options.python_version[1] > feature_version:
+            feature_version = options.python_version[1]
+    else:
+        assert options.python_version[0] >= 3
+        feature_version = options.python_version[1]
+    try:
+        # Disable deprecation warnings about \u
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", category=DeprecationWarning)
+            ast = ast3_parse(source, fnam, "exec", feature_version=feature_version)
+
+        tree = ASTConverter(
+            options=options,
+            is_stub=is_stub_file,
+            errors=errors,
+            ignore_errors=ignore_errors,
+            strip_function_bodies=strip_function_bodies,
+        ).visit(ast)
+        tree.path = fnam
+        tree.is_stub = is_stub_file
+    except SyntaxError as e:
+        # alias to please mypyc
+        is_py38_or_earlier = sys.version_info < (3, 9)
+        if is_py38_or_earlier and e.filename == "<fstring>":
+            # In Python 3.8 and earlier, syntax errors in f-strings have lineno relative to the
+            # start of the f-string. This would be misleading, as mypy will report the error as the
+            # lineno within the file.
+            e.lineno = None
+        message = e.msg
+        if feature_version > sys.version_info.minor and message.startswith("invalid syntax"):
+            python_version_str = f"{options.python_version[0]}.{options.python_version[1]}"
+            message += f"; you likely need to run mypy using Python {python_version_str} or newer"
+        errors.report(
+            e.lineno if e.lineno is not None else -1,
+            e.offset,
+            message,
+            blocker=True,
+            code=codes.SYNTAX,
+        )
+        tree = MypyFile([], [], False, {})
+
+    if raise_on_error and errors.is_errors():
+        errors.raise_error()
+
+    assert isinstance(tree, MypyFile)
+    return tree
+
+
+def parse_type_ignore_tag(tag: str | None) -> list[str] | None:
+    """Parse optional "[code, ...]" tag after "# type: ignore".
+
+    Return:
+     * [] if no tag was found (ignore all errors)
+     * list of ignored error codes if a tag was found
+     * None if the tag was invalid.
+    """
+    if not tag or tag.strip() == "" or tag.strip().startswith("#"):
+        # No tag -- ignore all errors.
+        return []
+    m = re.match(r"\s*\[([^]#]*)\]\s*(#.*)?$", tag)
+    if m is None:
+        # Invalid "# type: ignore" comment.
+        return None
+    return [code.strip() for code in m.group(1).split(",")]
+
+
+def parse_type_comment(
+    type_comment: str, line: int, column: int, errors: Errors | None
+) -> tuple[list[str] | None, ProperType | None]:
+    """Parse type portion of a type comment (+ optional type ignore).
+
+    Return (ignore info, parsed type).
+    """
+    try:
+        typ = ast3_parse(type_comment, "<type_comment>", "eval")
+    except SyntaxError:
+        if errors is not None:
+            stripped_type = type_comment.split("#", 2)[0].strip()
+            err_msg = message_registry.TYPE_COMMENT_SYNTAX_ERROR_VALUE.format(stripped_type)
+            errors.report(line, column, err_msg.value, blocker=True, code=err_msg.code)
+            return None, None
+        else:
+            raise
+    else:
+        extra_ignore = TYPE_IGNORE_PATTERN.match(type_comment)
+        if extra_ignore:
+            tag: str | None = extra_ignore.group(1)
+            ignored: list[str] | None = parse_type_ignore_tag(tag)
+            if ignored is None:
+                if errors is not None:
+                    errors.report(
+                        line, column, message_registry.INVALID_TYPE_IGNORE.value, code=codes.SYNTAX
+                    )
+                else:
+                    raise SyntaxError
+        else:
+            ignored = None
+        assert isinstance(typ, ast3.Expression)
+        converted = TypeConverter(
+            errors, line=line, override_column=column, is_evaluated=False
+        ).visit(typ.body)
+        return ignored, converted
+
+
+def parse_type_string(
+    expr_string: str, expr_fallback_name: str, line: int, column: int
+) -> ProperType:
+    """Parses a type that was originally present inside of an explicit string.
+
+    For example, suppose we have the type `Foo["blah"]`. We should parse the
+    string expression "blah" using this function.
+    """
+    try:
+        _, node = parse_type_comment(expr_string.strip(), line=line, column=column, errors=None)
+        if isinstance(node, UnboundType) and node.original_str_expr is None:
+            node.original_str_expr = expr_string
+            node.original_str_fallback = expr_fallback_name
+            return node
+        elif isinstance(node, UnionType):
+            return node
+        else:
+            return RawExpressionType(expr_string, expr_fallback_name, line, column)
+    except (SyntaxError, ValueError):
+        # Note: the parser will raise a `ValueError` instead of a SyntaxError if
+        # the string happens to contain things like \x00.
+        return RawExpressionType(expr_string, expr_fallback_name, line, column)
+
+
+def is_no_type_check_decorator(expr: ast3.expr) -> bool:
+    if isinstance(expr, Name):
+        return expr.id == "no_type_check"
+    elif isinstance(expr, Attribute):
+        if isinstance(expr.value, Name):
+            return expr.value.id == "typing" and expr.attr == "no_type_check"
+    return False
+
+
+class ASTConverter:
+    def __init__(
+        self,
+        options: Options,
+        is_stub: bool,
+        errors: Errors,
+        *,
+        ignore_errors: bool,
+        strip_function_bodies: bool,
+    ) -> None:
+        # 'C' for class, 'D' for function signature, 'F' for function, 'L' for lambda
+        self.class_and_function_stack: list[Literal["C", "D", "F", "L"]] = []
+        self.imports: list[ImportBase] = []
+
+        self.options = options
+        self.is_stub = is_stub
+        self.errors = errors
+        self.ignore_errors = ignore_errors
+        self.strip_function_bodies = strip_function_bodies
+
+        self.type_ignores: dict[int, list[str]] = {}
+
+        # Cache of visit_X methods keyed by type of visited object
+        self.visitor_cache: dict[type, Callable[[AST | None], Any]] = {}
+
+    def note(self, msg: str, line: int, column: int) -> None:
+        self.errors.report(line, column, msg, severity="note", code=codes.SYNTAX)
+
+    def fail(self, msg: ErrorMessage, line: int, column: int, blocker: bool = True) -> None:
+        if blocker or not self.options.ignore_errors:
+            self.errors.report(line, column, msg.value, blocker=blocker, code=msg.code)
+
+    def fail_merge_overload(self, node: IfStmt) -> None:
+        self.fail(
+            message_registry.FAILED_TO_MERGE_OVERLOADS,
+            line=node.line,
+            column=node.column,
+            blocker=False,
+        )
+
+    def visit(self, node: AST | None) -> Any:
+        if node is None:
+            return None
+        typeobj = type(node)
+        visitor = self.visitor_cache.get(typeobj)
+        if visitor is None:
+            method = "visit_" + node.__class__.__name__
+            visitor = getattr(self, method)
+            self.visitor_cache[typeobj] = visitor
+        return visitor(node)
+
+    def set_line(self, node: N, n: AstNode) -> N:
+        node.line = n.lineno
+        node.column = n.col_offset
+        node.end_line = getattr(n, "end_lineno", None)
+        node.end_column = getattr(n, "end_col_offset", None)
+
+        return node
+
+    def translate_opt_expr_list(self, l: Sequence[AST | None]) -> list[Expression | None]:
+        res: list[Expression | None] = []
+        for e in l:
+            exp = self.visit(e)
+            res.append(exp)
+        return res
+
+    def translate_expr_list(self, l: Sequence[AST]) -> list[Expression]:
+        return cast(List[Expression], self.translate_opt_expr_list(l))
+
+    def get_lineno(self, node: ast3.expr | ast3.stmt) -> int:
+        if (
+            isinstance(node, (ast3.AsyncFunctionDef, ast3.ClassDef, ast3.FunctionDef))
+            and node.decorator_list
+        ):
+            return node.decorator_list[0].lineno
+        return node.lineno
+
+    def translate_stmt_list(
+        self,
+        stmts: Sequence[ast3.stmt],
+        *,
+        ismodule: bool = False,
+        can_strip: bool = False,
+        is_coroutine: bool = False,
+    ) -> list[Statement]:
+        # A "# type: ignore" comment before the first statement of a module
+        # ignores the whole module:
+        if (
+            ismodule
+            and stmts
+            and self.type_ignores
+            and min(self.type_ignores) < self.get_lineno(stmts[0])
+        ):
+            ignores = self.type_ignores[min(self.type_ignores)]
+            if ignores:
+                joined_ignores = ", ".join(ignores)
+                self.fail(
+                    message_registry.TYPE_IGNORE_WITH_ERRCODE_ON_MODULE.format(joined_ignores),
+                    line=min(self.type_ignores),
+                    column=0,
+                    blocker=False,
+                )
+            self.errors.used_ignored_lines[self.errors.file][min(self.type_ignores)].append(
+                codes.FILE.code
+            )
+            block = Block(self.fix_function_overloads(self.translate_stmt_list(stmts)))
+            self.set_block_lines(block, stmts)
+            mark_block_unreachable(block)
+            return [block]
+
+        stack = self.class_and_function_stack
+        # Fast case for stripping function bodies
+        if (
+            can_strip
+            and self.strip_function_bodies
+            and len(stack) == 1
+            and stack[0] == "F"
+            and not is_coroutine
+        ):
+            return []
+
+        res: list[Statement] = []
+        for stmt in stmts:
+            node = self.visit(stmt)
+            res.append(node)
+
+        # Slow case for stripping function bodies
+        if can_strip and self.strip_function_bodies:
+            if stack[-2:] == ["C", "F"]:
+                if is_possible_trivial_body(res):
+                    can_strip = False
+                else:
+                    # We only strip method bodies if they don't assign to an attribute, as
+                    # this may define an attribute which has an externally visible effect.
+                    visitor = FindAttributeAssign()
+                    for s in res:
+                        s.accept(visitor)
+                        if visitor.found:
+                            can_strip = False
+                            break
+
+            if can_strip and stack[-1] == "F" and is_coroutine:
+                # Yields inside an async function affect the return type and should not
+                # be stripped.
+                yield_visitor = FindYield()
+                for s in res:
+                    s.accept(yield_visitor)
+                    if yield_visitor.found:
+                        can_strip = False
+                        break
+
+            if can_strip:
+                return []
+        return res
+
+    def translate_type_comment(
+        self, n: ast3.stmt | ast3.arg, type_comment: str | None
+    ) -> ProperType | None:
+        if type_comment is None:
+            return None
+        else:
+            lineno = n.lineno
+            extra_ignore, typ = parse_type_comment(type_comment, lineno, n.col_offset, self.errors)
+            if extra_ignore is not None:
+                self.type_ignores[lineno] = extra_ignore
+            return typ
+
+    op_map: Final[dict[type[AST], str]] = {
+        ast3.Add: "+",
+        ast3.Sub: "-",
+        ast3.Mult: "*",
+        ast3.MatMult: "@",
+        ast3.Div: "/",
+        ast3.Mod: "%",
+        ast3.Pow: "**",
+        ast3.LShift: "<<",
+        ast3.RShift: ">>",
+        ast3.BitOr: "|",
+        ast3.BitXor: "^",
+        ast3.BitAnd: "&",
+        ast3.FloorDiv: "//",
+    }
+
+    def from_operator(self, op: ast3.operator) -> str:
+        op_name = ASTConverter.op_map.get(type(op))
+        if op_name is None:
+            raise RuntimeError("Unknown operator " + str(type(op)))
+        else:
+            return op_name
+
+    comp_op_map: Final[dict[type[AST], str]] = {
+        ast3.Gt: ">",
+        ast3.Lt: "<",
+        ast3.Eq: "==",
+        ast3.GtE: ">=",
+        ast3.LtE: "<=",
+        ast3.NotEq: "!=",
+        ast3.Is: "is",
+        ast3.IsNot: "is not",
+        ast3.In: "in",
+        ast3.NotIn: "not in",
+    }
+
+    def from_comp_operator(self, op: ast3.cmpop) -> str:
+        op_name = ASTConverter.comp_op_map.get(type(op))
+        if op_name is None:
+            raise RuntimeError("Unknown comparison operator " + str(type(op)))
+        else:
+            return op_name
+
+    def set_block_lines(self, b: Block, stmts: Sequence[ast3.stmt]) -> None:
+        first, last = stmts[0], stmts[-1]
+        b.line = first.lineno
+        b.column = first.col_offset
+        b.end_line = getattr(last, "end_lineno", None)
+        b.end_column = getattr(last, "end_col_offset", None)
+        if not b.body:
+            return
+        new_first = b.body[0]
+        if isinstance(new_first, (Decorator, OverloadedFuncDef)):
+            # Decorated function lines are different between Python versions.
+            # copy the normalization we do for them to block first lines.
+            b.line = new_first.line
+            b.column = new_first.column
+
+    def as_block(self, stmts: list[ast3.stmt]) -> Block | None:
+        b = None
+        if stmts:
+            b = Block(self.fix_function_overloads(self.translate_stmt_list(stmts)))
+            self.set_block_lines(b, stmts)
+        return b
+
+    def as_required_block(
+        self, stmts: list[ast3.stmt], *, can_strip: bool = False, is_coroutine: bool = False
+    ) -> Block:
+        assert stmts  # must be non-empty
+        b = Block(
+            self.fix_function_overloads(
+                self.translate_stmt_list(stmts, can_strip=can_strip, is_coroutine=is_coroutine)
+            )
+        )
+        self.set_block_lines(b, stmts)
+        return b
+
+    def fix_function_overloads(self, stmts: list[Statement]) -> list[Statement]:
+        ret: list[Statement] = []
+        current_overload: list[OverloadPart] = []
+        current_overload_name: str | None = None
+        seen_unconditional_func_def = False
+        last_if_stmt: IfStmt | None = None
+        last_if_overload: Decorator | FuncDef | OverloadedFuncDef | None = None
+        last_if_stmt_overload_name: str | None = None
+        last_if_unknown_truth_value: IfStmt | None = None
+        skipped_if_stmts: list[IfStmt] = []
+        for stmt in stmts:
+            if_overload_name: str | None = None
+            if_block_with_overload: Block | None = None
+            if_unknown_truth_value: IfStmt | None = None
+            if isinstance(stmt, IfStmt) and seen_unconditional_func_def is False:
+                # Check IfStmt block to determine if function overloads can be merged
+                if_overload_name = self._check_ifstmt_for_overloads(stmt, current_overload_name)
+                if if_overload_name is not None:
+                    (
+                        if_block_with_overload,
+                        if_unknown_truth_value,
+                    ) = self._get_executable_if_block_with_overloads(stmt)
+
+            if (
+                current_overload_name is not None
+                and isinstance(stmt, (Decorator, FuncDef))
+                and stmt.name == current_overload_name
+            ):
+                if last_if_stmt is not None:
+                    skipped_if_stmts.append(last_if_stmt)
+                if last_if_overload is not None:
+                    # Last stmt was an IfStmt with same overload name
+                    # Add overloads to current_overload
+                    if isinstance(last_if_overload, OverloadedFuncDef):
+                        current_overload.extend(last_if_overload.items)
+                    else:
+                        current_overload.append(last_if_overload)
+                    last_if_stmt, last_if_overload = None, None
+                if last_if_unknown_truth_value:
+                    self.fail_merge_overload(last_if_unknown_truth_value)
+                    last_if_unknown_truth_value = None
+                current_overload.append(stmt)
+                if isinstance(stmt, FuncDef):
+                    seen_unconditional_func_def = True
+            elif (
+                current_overload_name is not None
+                and isinstance(stmt, IfStmt)
+                and if_overload_name == current_overload_name
+            ):
+                # IfStmt only contains stmts relevant to current_overload.
+                # Check if stmts are reachable and add them to current_overload,
+                # otherwise skip IfStmt to allow subsequent overload
+                # or function definitions.
+                skipped_if_stmts.append(stmt)
+                if if_block_with_overload is None:
+                    if if_unknown_truth_value is not None:
+                        self.fail_merge_overload(if_unknown_truth_value)
+                    continue
+                if last_if_overload is not None:
+                    # Last stmt was an IfStmt with same overload name
+                    # Add overloads to current_overload
+                    if isinstance(last_if_overload, OverloadedFuncDef):
+                        current_overload.extend(last_if_overload.items)
+                    else:
+                        current_overload.append(last_if_overload)
+                    last_if_stmt, last_if_overload = None, None
+                if isinstance(if_block_with_overload.body[-1], OverloadedFuncDef):
+                    skipped_if_stmts.extend(cast(List[IfStmt], if_block_with_overload.body[:-1]))
+                    current_overload.extend(if_block_with_overload.body[-1].items)
+                else:
+                    current_overload.append(
+                        cast(Union[Decorator, FuncDef], if_block_with_overload.body[0])
+                    )
+            else:
+                if last_if_stmt is not None:
+                    ret.append(last_if_stmt)
+                    last_if_stmt_overload_name = current_overload_name
+                    last_if_stmt, last_if_overload = None, None
+                    last_if_unknown_truth_value = None
+
+                if current_overload and current_overload_name == last_if_stmt_overload_name:
+                    # Remove last stmt (IfStmt) from ret if the overload names matched
+                    # Only happens if no executable block had been found in IfStmt
+                    popped = ret.pop()
+                    assert isinstance(popped, IfStmt)
+                    skipped_if_stmts.append(popped)
+                if current_overload and skipped_if_stmts:
+                    # Add bare IfStmt (without overloads) to ret
+                    # Required for mypy to be able to still check conditions
+                    for if_stmt in skipped_if_stmts:
+                        self._strip_contents_from_if_stmt(if_stmt)
+                        ret.append(if_stmt)
+                    skipped_if_stmts = []
+                if len(current_overload) == 1:
+                    ret.append(current_overload[0])
+                elif len(current_overload) > 1:
+                    ret.append(OverloadedFuncDef(current_overload))
+
+                # If we have multiple decorated functions named "_" next to each, we want to treat
+                # them as a series of regular FuncDefs instead of one OverloadedFuncDef because
+                # most of mypy/mypyc assumes that all the functions in an OverloadedFuncDef are
+                # related, but multiple underscore functions next to each other aren't necessarily
+                # related
+                seen_unconditional_func_def = False
+                if isinstance(stmt, Decorator) and not unnamed_function(stmt.name):
+                    current_overload = [stmt]
+                    current_overload_name = stmt.name
+                elif isinstance(stmt, IfStmt) and if_overload_name is not None:
+                    current_overload = []
+                    current_overload_name = if_overload_name
+                    last_if_stmt = stmt
+                    last_if_stmt_overload_name = None
+                    if if_block_with_overload is not None:
+                        skipped_if_stmts.extend(
+                            cast(List[IfStmt], if_block_with_overload.body[:-1])
+                        )
+                        last_if_overload = cast(
+                            Union[Decorator, FuncDef, OverloadedFuncDef],
+                            if_block_with_overload.body[-1],
+                        )
+                    last_if_unknown_truth_value = if_unknown_truth_value
+                else:
+                    current_overload = []
+                    current_overload_name = None
+                    ret.append(stmt)
+
+        if current_overload and skipped_if_stmts:
+            # Add bare IfStmt (without overloads) to ret
+            # Required for mypy to be able to still check conditions
+            for if_stmt in skipped_if_stmts:
+                self._strip_contents_from_if_stmt(if_stmt)
+                ret.append(if_stmt)
+        if len(current_overload) == 1:
+            ret.append(current_overload[0])
+        elif len(current_overload) > 1:
+            ret.append(OverloadedFuncDef(current_overload))
+        elif last_if_overload is not None:
+            ret.append(last_if_overload)
+        elif last_if_stmt is not None:
+            ret.append(last_if_stmt)
+        return ret
+
+    def _check_ifstmt_for_overloads(
+        self, stmt: IfStmt, current_overload_name: str | None = None
+    ) -> str | None:
+        """Check if IfStmt contains only overloads with the same name.
+        Return overload_name if found, None otherwise.
+        """
+        # Check that block only contains a single Decorator, FuncDef, or OverloadedFuncDef.
+        # Multiple overloads have already been merged as OverloadedFuncDef.
+        if not (
+            len(stmt.body[0].body) == 1
+            and (
+                isinstance(stmt.body[0].body[0], (Decorator, OverloadedFuncDef))
+                or current_overload_name is not None
+                and isinstance(stmt.body[0].body[0], FuncDef)
+            )
+            or len(stmt.body[0].body) > 1
+            and isinstance(stmt.body[0].body[-1], OverloadedFuncDef)
+            and all(self._is_stripped_if_stmt(if_stmt) for if_stmt in stmt.body[0].body[:-1])
+        ):
+            return None
+
+        overload_name = cast(
+            Union[Decorator, FuncDef, OverloadedFuncDef], stmt.body[0].body[-1]
+        ).name
+        if stmt.else_body is None:
+            return overload_name
+
+        if len(stmt.else_body.body) == 1:
+            # For elif: else_body contains an IfStmt itself -> do a recursive check.
+            if (
+                isinstance(stmt.else_body.body[0], (Decorator, FuncDef, OverloadedFuncDef))
+                and stmt.else_body.body[0].name == overload_name
+            ):
+                return overload_name
+            if (
+                isinstance(stmt.else_body.body[0], IfStmt)
+                and self._check_ifstmt_for_overloads(stmt.else_body.body[0], current_overload_name)
+                == overload_name
+            ):
+                return overload_name
+
+        return None
+
+    def _get_executable_if_block_with_overloads(
+        self, stmt: IfStmt
+    ) -> tuple[Block | None, IfStmt | None]:
+        """Return block from IfStmt that will get executed.
+
+        Return
+            0 -> A block if sure that alternative blocks are unreachable.
+            1 -> An IfStmt if the reachability of it can't be inferred,
+                 i.e. the truth value is unknown.
+        """
+        infer_reachability_of_if_statement(stmt, self.options)
+        if stmt.else_body is None and stmt.body[0].is_unreachable is True:
+            # always False condition with no else
+            return None, None
+        if (
+            stmt.else_body is None
+            or stmt.body[0].is_unreachable is False
+            and stmt.else_body.is_unreachable is False
+        ):
+            # The truth value is unknown, thus not conclusive
+            return None, stmt
+        if stmt.else_body.is_unreachable is True:
+            # else_body will be set unreachable if condition is always True
+            return stmt.body[0], None
+        if stmt.body[0].is_unreachable is True:
+            # body will be set unreachable if condition is always False
+            # else_body can contain an IfStmt itself (for elif) -> do a recursive check
+            if isinstance(stmt.else_body.body[0], IfStmt):
+                return self._get_executable_if_block_with_overloads(stmt.else_body.body[0])
+            return stmt.else_body, None
+        return None, stmt
+
+    def _strip_contents_from_if_stmt(self, stmt: IfStmt) -> None:
+        """Remove contents from IfStmt.
+
+        Needed to still be able to check the conditions after the contents
+        have been merged with the surrounding function overloads.
+        """
+        if len(stmt.body) == 1:
+            stmt.body[0].body = []
+        if stmt.else_body and len(stmt.else_body.body) == 1:
+            if isinstance(stmt.else_body.body[0], IfStmt):
+                self._strip_contents_from_if_stmt(stmt.else_body.body[0])
+            else:
+                stmt.else_body.body = []
+
+    def _is_stripped_if_stmt(self, stmt: Statement) -> bool:
+        """Check stmt to make sure it is a stripped IfStmt.
+
+        See also: _strip_contents_from_if_stmt
+        """
+        if not isinstance(stmt, IfStmt):
+            return False
+
+        if not (len(stmt.body) == 1 and len(stmt.body[0].body) == 0):
+            # Body not empty
+            return False
+
+        if not stmt.else_body or len(stmt.else_body.body) == 0:
+            # No or empty else_body
+            return True
+
+        # For elif, IfStmt are stored recursively in else_body
+        return self._is_stripped_if_stmt(stmt.else_body.body[0])
+
+    def translate_module_id(self, id: str) -> str:
+        """Return the actual, internal module id for a source text id."""
+        if id == self.options.custom_typing_module:
+            return "typing"
+        return id
+
+    def visit_Module(self, mod: ast3.Module) -> MypyFile:
+        self.type_ignores = {}
+        for ti in mod.type_ignores:
+            parsed = parse_type_ignore_tag(ti.tag)
+            if parsed is not None:
+                self.type_ignores[ti.lineno] = parsed
+            else:
+                self.fail(message_registry.INVALID_TYPE_IGNORE, ti.lineno, -1, blocker=False)
+        body = self.fix_function_overloads(self.translate_stmt_list(mod.body, ismodule=True))
+        return MypyFile(body, self.imports, False, self.type_ignores)
+
+    # --- stmt ---
+    # FunctionDef(identifier name, arguments args,
+    #             stmt* body, expr* decorator_list, expr? returns, string? type_comment)
+    # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
+    #              arg? kwarg, expr* defaults)
+    def visit_FunctionDef(self, n: ast3.FunctionDef) -> FuncDef | Decorator:
+        return self.do_func_def(n)
+
+    # AsyncFunctionDef(identifier name, arguments args,
+    #                  stmt* body, expr* decorator_list, expr? returns, string? type_comment)
+    def visit_AsyncFunctionDef(self, n: ast3.AsyncFunctionDef) -> FuncDef | Decorator:
+        return self.do_func_def(n, is_coroutine=True)
+
+    def do_func_def(
+        self, n: ast3.FunctionDef | ast3.AsyncFunctionDef, is_coroutine: bool = False
+    ) -> FuncDef | Decorator:
+        """Helper shared between visit_FunctionDef and visit_AsyncFunctionDef."""
+        self.class_and_function_stack.append("D")
+        no_type_check = bool(
+            n.decorator_list and any(is_no_type_check_decorator(d) for d in n.decorator_list)
+        )
+
+        lineno = n.lineno
+        args = self.transform_args(n.args, lineno, no_type_check=no_type_check)
+        if special_function_elide_names(n.name):
+            for arg in args:
+                arg.pos_only = True
+
+        arg_kinds = [arg.kind for arg in args]
+        arg_names = [None if arg.pos_only else arg.variable.name for arg in args]
+
+        arg_types: list[Type | None] = []
+        if no_type_check:
+            arg_types = [None] * len(args)
+            return_type = None
+        elif n.type_comment is not None:
+            try:
+                func_type_ast = ast3_parse(n.type_comment, "<func_type>", "func_type")
+                assert isinstance(func_type_ast, FunctionType)
+                # for ellipsis arg
+                if (
+                    len(func_type_ast.argtypes) == 1
+                    and isinstance(func_type_ast.argtypes[0], Constant)
+                    and func_type_ast.argtypes[0].value is Ellipsis
+                ):
+                    if n.returns:
+                        # PEP 484 disallows both type annotations and type comments
+                        self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset)
+                    arg_types = [
+                        a.type_annotation
+                        if a.type_annotation is not None
+                        else AnyType(TypeOfAny.unannotated)
+                        for a in args
+                    ]
+                else:
+                    # PEP 484 disallows both type annotations and type comments
+                    if n.returns or any(a.type_annotation is not None for a in args):
+                        self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, lineno, n.col_offset)
+                    translated_args: list[Type] = TypeConverter(
+                        self.errors, line=lineno, override_column=n.col_offset
+                    ).translate_expr_list(func_type_ast.argtypes)
+                    # Use a cast to work around `list` invariance
+                    arg_types = cast(List[Optional[Type]], translated_args)
+                return_type = TypeConverter(self.errors, line=lineno).visit(func_type_ast.returns)
+
+                # add implicit self type
+                in_method_scope = self.class_and_function_stack[-2:] == ["C", "D"]
+                if in_method_scope and len(arg_types) < len(args):
+                    arg_types.insert(0, AnyType(TypeOfAny.special_form))
+            except SyntaxError:
+                stripped_type = n.type_comment.split("#", 2)[0].strip()
+                err_msg = message_registry.TYPE_COMMENT_SYNTAX_ERROR_VALUE.format(stripped_type)
+                self.fail(err_msg, lineno, n.col_offset)
+                if n.type_comment and n.type_comment[0] not in ["(", "#"]:
+                    self.note(
+                        "Suggestion: wrap argument types in parentheses", lineno, n.col_offset
+                    )
+                arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
+                return_type = AnyType(TypeOfAny.from_error)
+        else:
+            arg_types = [a.type_annotation for a in args]
+            return_type = TypeConverter(
+                self.errors, line=n.returns.lineno if n.returns else lineno
+            ).visit(n.returns)
+
+        for arg, arg_type in zip(args, arg_types):
+            self.set_type_optional(arg_type, arg.initializer)
+
+        func_type = None
+        if any(arg_types) or return_type:
+            if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types):
+                self.fail(message_registry.ELLIPSIS_WITH_OTHER_TYPEARGS, lineno, n.col_offset)
+            elif len(arg_types) > len(arg_kinds):
+                self.fail(
+                    message_registry.TYPE_SIGNATURE_TOO_MANY_ARGS,
+                    lineno,
+                    n.col_offset,
+                    blocker=False,
+                )
+            elif len(arg_types) < len(arg_kinds):
+                self.fail(
+                    message_registry.TYPE_SIGNATURE_TOO_FEW_ARGS,
+                    lineno,
+                    n.col_offset,
+                    blocker=False,
+                )
+            else:
+                func_type = CallableType(
+                    [a if a is not None else AnyType(TypeOfAny.unannotated) for a in arg_types],
+                    arg_kinds,
+                    arg_names,
+                    return_type if return_type is not None else AnyType(TypeOfAny.unannotated),
+                    _dummy_fallback,
+                )
+
+        # End position is always the same.
+        end_line = getattr(n, "end_lineno", None)
+        end_column = getattr(n, "end_col_offset", None)
+
+        self.class_and_function_stack.pop()
+        self.class_and_function_stack.append("F")
+        body = self.as_required_block(n.body, can_strip=True, is_coroutine=is_coroutine)
+        func_def = FuncDef(n.name, args, body, func_type)
+        if isinstance(func_def.type, CallableType):
+            # semanal.py does some in-place modifications we want to avoid
+            func_def.unanalyzed_type = func_def.type.copy_modified()
+        if is_coroutine:
+            func_def.is_coroutine = True
+        if func_type is not None:
+            func_type.definition = func_def
+            func_type.line = lineno
+
+        if n.decorator_list:
+            # Set deco_line to the old pre-3.8 lineno, in order to keep
+            # existing "# type: ignore" comments working:
+            deco_line = n.decorator_list[0].lineno
+
+            var = Var(func_def.name)
+            var.is_ready = False
+            var.set_line(lineno)
+
+            func_def.is_decorated = True
+            func_def.deco_line = deco_line
+            func_def.set_line(lineno, n.col_offset, end_line, end_column)
+
+            deco = Decorator(func_def, self.translate_expr_list(n.decorator_list), var)
+            first = n.decorator_list[0]
+            deco.set_line(first.lineno, first.col_offset, end_line, end_column)
+            retval: FuncDef | Decorator = deco
+        else:
+            # FuncDef overrides set_line -- can't use self.set_line
+            func_def.set_line(lineno, n.col_offset, end_line, end_column)
+            retval = func_def
+        self.class_and_function_stack.pop()
+        return retval
+
+    def set_type_optional(self, type: Type | None, initializer: Expression | None) -> None:
+        if not self.options.implicit_optional:
+            return
+        # Indicate that type should be wrapped in an Optional if arg is initialized to None.
+        optional = isinstance(initializer, NameExpr) and initializer.name == "None"
+        if isinstance(type, UnboundType):
+            type.optional = optional
+
+    def transform_args(
+        self, args: ast3.arguments, line: int, no_type_check: bool = False
+    ) -> list[Argument]:
+        new_args = []
+        names: list[ast3.arg] = []
+        posonlyargs = getattr(args, "posonlyargs", cast(List[ast3.arg], []))
+        args_args = posonlyargs + args.args
+        args_defaults = args.defaults
+        num_no_defaults = len(args_args) - len(args_defaults)
+        # positional arguments without defaults
+        for i, a in enumerate(args_args[:num_no_defaults]):
+            pos_only = i < len(posonlyargs)
+            new_args.append(self.make_argument(a, None, ARG_POS, no_type_check, pos_only))
+            names.append(a)
+
+        # positional arguments with defaults
+        for i, (a, d) in enumerate(zip(args_args[num_no_defaults:], args_defaults)):
+            pos_only = num_no_defaults + i < len(posonlyargs)
+            new_args.append(self.make_argument(a, d, ARG_OPT, no_type_check, pos_only))
+            names.append(a)
+
+        # *arg
+        if args.vararg is not None:
+            new_args.append(self.make_argument(args.vararg, None, ARG_STAR, no_type_check))
+            names.append(args.vararg)
+
+        # keyword-only arguments with defaults
+        for a, kd in zip(args.kwonlyargs, args.kw_defaults):
+            new_args.append(
+                self.make_argument(
+                    a, kd, ARG_NAMED if kd is None else ARG_NAMED_OPT, no_type_check
+                )
+            )
+            names.append(a)
+
+        # **kwarg
+        if args.kwarg is not None:
+            new_args.append(self.make_argument(args.kwarg, None, ARG_STAR2, no_type_check))
+            names.append(args.kwarg)
+
+        check_arg_names([arg.variable.name for arg in new_args], names, self.fail_arg)
+
+        return new_args
+
+    def make_argument(
+        self,
+        arg: ast3.arg,
+        default: ast3.expr | None,
+        kind: ArgKind,
+        no_type_check: bool,
+        pos_only: bool = False,
+    ) -> Argument:
+        if no_type_check:
+            arg_type = None
+        else:
+            annotation = arg.annotation
+            type_comment = arg.type_comment
+            if annotation is not None and type_comment is not None:
+                self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES, arg.lineno, arg.col_offset)
+            arg_type = None
+            if annotation is not None:
+                arg_type = TypeConverter(self.errors, line=arg.lineno).visit(annotation)
+            else:
+                arg_type = self.translate_type_comment(arg, type_comment)
+        if argument_elide_name(arg.arg):
+            pos_only = True
+
+        argument = Argument(Var(arg.arg), arg_type, self.visit(default), kind, pos_only)
+        argument.set_line(
+            arg.lineno,
+            arg.col_offset,
+            getattr(arg, "end_lineno", None),
+            getattr(arg, "end_col_offset", None),
+        )
+        return argument
+
+    def fail_arg(self, msg: str, arg: ast3.arg) -> None:
+        self.fail(ErrorMessage(msg), arg.lineno, arg.col_offset)
+
+    # ClassDef(identifier name,
+    #  expr* bases,
+    #  keyword* keywords,
+    #  stmt* body,
+    #  expr* decorator_list)
+    def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef:
+        self.class_and_function_stack.append("C")
+        keywords = [(kw.arg, self.visit(kw.value)) for kw in n.keywords if kw.arg]
+
+        cdef = ClassDef(
+            n.name,
+            self.as_required_block(n.body),
+            None,
+            self.translate_expr_list(n.bases),
+            metaclass=dict(keywords).get("metaclass"),
+            keywords=keywords,
+        )
+        cdef.decorators = self.translate_expr_list(n.decorator_list)
+        # Set lines to match the old mypy 0.700 lines, in order to keep
+        # existing "# type: ignore" comments working:
+        cdef.line = n.lineno
+        cdef.deco_line = n.decorator_list[0].lineno if n.decorator_list else None
+
+        cdef.column = n.col_offset
+        cdef.end_line = getattr(n, "end_lineno", None)
+        cdef.end_column = getattr(n, "end_col_offset", None)
+        self.class_and_function_stack.pop()
+        return cdef
+
+    # Return(expr? value)
+    def visit_Return(self, n: ast3.Return) -> ReturnStmt:
+        node = ReturnStmt(self.visit(n.value))
+        return self.set_line(node, n)
+
+    # Delete(expr* targets)
+    def visit_Delete(self, n: ast3.Delete) -> DelStmt:
+        if len(n.targets) > 1:
+            tup = TupleExpr(self.translate_expr_list(n.targets))
+            tup.set_line(n.lineno)
+            node = DelStmt(tup)
+        else:
+            node = DelStmt(self.visit(n.targets[0]))
+        return self.set_line(node, n)
+
+    # Assign(expr* targets, expr? value, string? type_comment, expr? annotation)
+    def visit_Assign(self, n: ast3.Assign) -> AssignmentStmt:
+        lvalues = self.translate_expr_list(n.targets)
+        rvalue = self.visit(n.value)
+        typ = self.translate_type_comment(n, n.type_comment)
+        s = AssignmentStmt(lvalues, rvalue, type=typ, new_syntax=False)
+        return self.set_line(s, n)
+
+    # AnnAssign(expr target, expr annotation, expr? value, int simple)
+    def visit_AnnAssign(self, n: ast3.AnnAssign) -> AssignmentStmt:
+        line = n.lineno
+        if n.value is None:  # always allow 'x: int'
+            rvalue: Expression = TempNode(AnyType(TypeOfAny.special_form), no_rhs=True)
+            rvalue.line = line
+            rvalue.column = n.col_offset
+        else:
+            rvalue = self.visit(n.value)
+        typ = TypeConverter(self.errors, line=line).visit(n.annotation)
+        assert typ is not None
+        typ.column = n.annotation.col_offset
+        s = AssignmentStmt([self.visit(n.target)], rvalue, type=typ, new_syntax=True)
+        return self.set_line(s, n)
+
+    # AugAssign(expr target, operator op, expr value)
+    def visit_AugAssign(self, n: ast3.AugAssign) -> OperatorAssignmentStmt:
+        s = OperatorAssignmentStmt(
+            self.from_operator(n.op), self.visit(n.target), self.visit(n.value)
+        )
+        return self.set_line(s, n)
+
+    # For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
+    def visit_For(self, n: ast3.For) -> ForStmt:
+        target_type = self.translate_type_comment(n, n.type_comment)
+        node = ForStmt(
+            self.visit(n.target),
+            self.visit(n.iter),
+            self.as_required_block(n.body),
+            self.as_block(n.orelse),
+            target_type,
+        )
+        return self.set_line(node, n)
+
+    # AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
+    def visit_AsyncFor(self, n: ast3.AsyncFor) -> ForStmt:
+        target_type = self.translate_type_comment(n, n.type_comment)
+        node = ForStmt(
+            self.visit(n.target),
+            self.visit(n.iter),
+            self.as_required_block(n.body),
+            self.as_block(n.orelse),
+            target_type,
+        )
+        node.is_async = True
+        return self.set_line(node, n)
+
+    # While(expr test, stmt* body, stmt* orelse)
+    def visit_While(self, n: ast3.While) -> WhileStmt:
+        node = WhileStmt(
+            self.visit(n.test), self.as_required_block(n.body), self.as_block(n.orelse)
+        )
+        return self.set_line(node, n)
+
+    # If(expr test, stmt* body, stmt* orelse)
+    def visit_If(self, n: ast3.If) -> IfStmt:
+        node = IfStmt(
+            [self.visit(n.test)], [self.as_required_block(n.body)], self.as_block(n.orelse)
+        )
+        return self.set_line(node, n)
+
+    # With(withitem* items, stmt* body, string? type_comment)
+    def visit_With(self, n: ast3.With) -> WithStmt:
+        target_type = self.translate_type_comment(n, n.type_comment)
+        node = WithStmt(
+            [self.visit(i.context_expr) for i in n.items],
+            [self.visit(i.optional_vars) for i in n.items],
+            self.as_required_block(n.body),
+            target_type,
+        )
+        return self.set_line(node, n)
+
+    # AsyncWith(withitem* items, stmt* body, string? type_comment)
+    def visit_AsyncWith(self, n: ast3.AsyncWith) -> WithStmt:
+        target_type = self.translate_type_comment(n, n.type_comment)
+        s = WithStmt(
+            [self.visit(i.context_expr) for i in n.items],
+            [self.visit(i.optional_vars) for i in n.items],
+            self.as_required_block(n.body),
+            target_type,
+        )
+        s.is_async = True
+        return self.set_line(s, n)
+
+    # Raise(expr? exc, expr? cause)
+    def visit_Raise(self, n: ast3.Raise) -> RaiseStmt:
+        node = RaiseStmt(self.visit(n.exc), self.visit(n.cause))
+        return self.set_line(node, n)
+
+    # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
+    def visit_Try(self, n: ast3.Try) -> TryStmt:
+        vs = [
+            self.set_line(NameExpr(h.name), h) if h.name is not None else None for h in n.handlers
+        ]
+        types = [self.visit(h.type) for h in n.handlers]
+        handlers = [self.as_required_block(h.body) for h in n.handlers]
+
+        node = TryStmt(
+            self.as_required_block(n.body),
+            vs,
+            types,
+            handlers,
+            self.as_block(n.orelse),
+            self.as_block(n.finalbody),
+        )
+        return self.set_line(node, n)
+
+    def visit_TryStar(self, n: TryStar) -> TryStmt:
+        vs = [
+            self.set_line(NameExpr(h.name), h) if h.name is not None else None for h in n.handlers
+        ]
+        types = [self.visit(h.type) for h in n.handlers]
+        handlers = [self.as_required_block(h.body) for h in n.handlers]
+
+        node = TryStmt(
+            self.as_required_block(n.body),
+            vs,
+            types,
+            handlers,
+            self.as_block(n.orelse),
+            self.as_block(n.finalbody),
+        )
+        node.is_star = True
+        return self.set_line(node, n)
+
+    # Assert(expr test, expr? msg)
+    def visit_Assert(self, n: ast3.Assert) -> AssertStmt:
+        node = AssertStmt(self.visit(n.test), self.visit(n.msg))
+        return self.set_line(node, n)
+
+    # Import(alias* names)
+    def visit_Import(self, n: ast3.Import) -> Import:
+        names: list[tuple[str, str | None]] = []
+        for alias in n.names:
+            name = self.translate_module_id(alias.name)
+            asname = alias.asname
+            if asname is None and name != alias.name:
+                # if the module name has been translated (and it's not already
+                # an explicit import-as), make it an implicit import-as the
+                # original name
+                asname = alias.name
+            names.append((name, asname))
+        i = Import(names)
+        self.imports.append(i)
+        return self.set_line(i, n)
+
+    # ImportFrom(identifier? module, alias* names, int? level)
+    def visit_ImportFrom(self, n: ast3.ImportFrom) -> ImportBase:
+        assert n.level is not None
+        if len(n.names) == 1 and n.names[0].name == "*":
+            mod = n.module if n.module is not None else ""
+            i: ImportBase = ImportAll(mod, n.level)
+        else:
+            i = ImportFrom(
+                self.translate_module_id(n.module) if n.module is not None else "",
+                n.level,
+                [(a.name, a.asname) for a in n.names],
+            )
+        self.imports.append(i)
+        return self.set_line(i, n)
+
+    # Global(identifier* names)
+    def visit_Global(self, n: ast3.Global) -> GlobalDecl:
+        g = GlobalDecl(n.names)
+        return self.set_line(g, n)
+
+    # Nonlocal(identifier* names)
+    def visit_Nonlocal(self, n: ast3.Nonlocal) -> NonlocalDecl:
+        d = NonlocalDecl(n.names)
+        return self.set_line(d, n)
+
+    # Expr(expr value)
+    def visit_Expr(self, n: ast3.Expr) -> ExpressionStmt:
+        value = self.visit(n.value)
+        node = ExpressionStmt(value)
+        return self.set_line(node, n)
+
+    # Pass
+    def visit_Pass(self, n: ast3.Pass) -> PassStmt:
+        s = PassStmt()
+        return self.set_line(s, n)
+
+    # Break
+    def visit_Break(self, n: ast3.Break) -> BreakStmt:
+        s = BreakStmt()
+        return self.set_line(s, n)
+
+    # Continue
+    def visit_Continue(self, n: ast3.Continue) -> ContinueStmt:
+        s = ContinueStmt()
+        return self.set_line(s, n)
+
+    # --- expr ---
+
+    def visit_NamedExpr(self, n: NamedExpr) -> AssignmentExpr:
+        s = AssignmentExpr(self.visit(n.target), self.visit(n.value))
+        return self.set_line(s, n)
+
+    # BoolOp(boolop op, expr* values)
+    def visit_BoolOp(self, n: ast3.BoolOp) -> OpExpr:
+        # mypy translates (1 and 2 and 3) as (1 and (2 and 3))
+        assert len(n.values) >= 2
+        op_node = n.op
+        if isinstance(op_node, ast3.And):
+            op = "and"
+        elif isinstance(op_node, ast3.Or):
+            op = "or"
+        else:
+            raise RuntimeError("unknown BoolOp " + str(type(n)))
+
+        # potentially inefficient!
+        return self.group(op, self.translate_expr_list(n.values), n)
+
+    def group(self, op: str, vals: list[Expression], n: ast3.expr) -> OpExpr:
+        if len(vals) == 2:
+            e = OpExpr(op, vals[0], vals[1])
+        else:
+            e = OpExpr(op, vals[0], self.group(op, vals[1:], n))
+        return self.set_line(e, n)
+
+    # BinOp(expr left, operator op, expr right)
+    def visit_BinOp(self, n: ast3.BinOp) -> OpExpr:
+        op = self.from_operator(n.op)
+
+        if op is None:
+            raise RuntimeError("cannot translate BinOp " + str(type(n.op)))
+
+        e = OpExpr(op, self.visit(n.left), self.visit(n.right))
+        return self.set_line(e, n)
+
+    # UnaryOp(unaryop op, expr operand)
+    def visit_UnaryOp(self, n: ast3.UnaryOp) -> UnaryExpr:
+        op = None
+        if isinstance(n.op, ast3.Invert):
+            op = "~"
+        elif isinstance(n.op, ast3.Not):
+            op = "not"
+        elif isinstance(n.op, ast3.UAdd):
+            op = "+"
+        elif isinstance(n.op, ast3.USub):
+            op = "-"
+
+        if op is None:
+            raise RuntimeError("cannot translate UnaryOp " + str(type(n.op)))
+
+        e = UnaryExpr(op, self.visit(n.operand))
+        return self.set_line(e, n)
+
+    # Lambda(arguments args, expr body)
+    def visit_Lambda(self, n: ast3.Lambda) -> LambdaExpr:
+        body = ast3.Return(n.body)
+        body.lineno = n.body.lineno
+        body.col_offset = n.body.col_offset
+
+        self.class_and_function_stack.append("L")
+        e = LambdaExpr(self.transform_args(n.args, n.lineno), self.as_required_block([body]))
+        self.class_and_function_stack.pop()
+        e.set_line(n.lineno, n.col_offset)  # Overrides set_line -- can't use self.set_line
+        return e
+
+    # IfExp(expr test, expr body, expr orelse)
+    def visit_IfExp(self, n: ast3.IfExp) -> ConditionalExpr:
+        e = ConditionalExpr(self.visit(n.test), self.visit(n.body), self.visit(n.orelse))
+        return self.set_line(e, n)
+
+    # Dict(expr* keys, expr* values)
+    def visit_Dict(self, n: ast3.Dict) -> DictExpr:
+        e = DictExpr(
+            list(zip(self.translate_opt_expr_list(n.keys), self.translate_expr_list(n.values)))
+        )
+        return self.set_line(e, n)
+
+    # Set(expr* elts)
+    def visit_Set(self, n: ast3.Set) -> SetExpr:
+        e = SetExpr(self.translate_expr_list(n.elts))
+        return self.set_line(e, n)
+
+    # ListComp(expr elt, comprehension* generators)
+    def visit_ListComp(self, n: ast3.ListComp) -> ListComprehension:
+        e = ListComprehension(self.visit_GeneratorExp(cast(ast3.GeneratorExp, n)))
+        return self.set_line(e, n)
+
+    # SetComp(expr elt, comprehension* generators)
+    def visit_SetComp(self, n: ast3.SetComp) -> SetComprehension:
+        e = SetComprehension(self.visit_GeneratorExp(cast(ast3.GeneratorExp, n)))
+        return self.set_line(e, n)
+
+    # DictComp(expr key, expr value, comprehension* generators)
+    def visit_DictComp(self, n: ast3.DictComp) -> DictionaryComprehension:
+        targets = [self.visit(c.target) for c in n.generators]
+        iters = [self.visit(c.iter) for c in n.generators]
+        ifs_list = [self.translate_expr_list(c.ifs) for c in n.generators]
+        is_async = [bool(c.is_async) for c in n.generators]
+        e = DictionaryComprehension(
+            self.visit(n.key), self.visit(n.value), targets, iters, ifs_list, is_async
+        )
+        return self.set_line(e, n)
+
+    # GeneratorExp(expr elt, comprehension* generators)
+    def visit_GeneratorExp(self, n: ast3.GeneratorExp) -> GeneratorExpr:
+        targets = [self.visit(c.target) for c in n.generators]
+        iters = [self.visit(c.iter) for c in n.generators]
+        ifs_list = [self.translate_expr_list(c.ifs) for c in n.generators]
+        is_async = [bool(c.is_async) for c in n.generators]
+        e = GeneratorExpr(self.visit(n.elt), targets, iters, ifs_list, is_async)
+        return self.set_line(e, n)
+
+    # Await(expr value)
+    def visit_Await(self, n: ast3.Await) -> AwaitExpr:
+        v = self.visit(n.value)
+        e = AwaitExpr(v)
+        return self.set_line(e, n)
+
+    # Yield(expr? value)
+    def visit_Yield(self, n: ast3.Yield) -> YieldExpr:
+        e = YieldExpr(self.visit(n.value))
+        return self.set_line(e, n)
+
+    # YieldFrom(expr value)
+    def visit_YieldFrom(self, n: ast3.YieldFrom) -> YieldFromExpr:
+        e = YieldFromExpr(self.visit(n.value))
+        return self.set_line(e, n)
+
+    # Compare(expr left, cmpop* ops, expr* comparators)
+    def visit_Compare(self, n: ast3.Compare) -> ComparisonExpr:
+        operators = [self.from_comp_operator(o) for o in n.ops]
+        operands = self.translate_expr_list([n.left] + n.comparators)
+        e = ComparisonExpr(operators, operands)
+        return self.set_line(e, n)
+
+    # Call(expr func, expr* args, keyword* keywords)
+    # keyword = (identifier? arg, expr value)
+    def visit_Call(self, n: Call) -> CallExpr:
+        args = n.args
+        keywords = n.keywords
+        keyword_names = [k.arg for k in keywords]
+        arg_types = self.translate_expr_list(
+            [a.value if isinstance(a, Starred) else a for a in args] + [k.value for k in keywords]
+        )
+        arg_kinds = [ARG_STAR if type(a) is Starred else ARG_POS for a in args] + [
+            ARG_STAR2 if arg is None else ARG_NAMED for arg in keyword_names
+        ]
+        e = CallExpr(
+            self.visit(n.func),
+            arg_types,
+            arg_kinds,
+            cast("List[Optional[str]]", [None] * len(args)) + keyword_names,
+        )
+        return self.set_line(e, n)
+
+    # Constant(object value) -- a constant, in Python 3.8.
+    def visit_Constant(self, n: Constant) -> Any:
+        val = n.value
+        e: Any = None
+        if val is None:
+            e = NameExpr("None")
+        elif isinstance(val, str):
+            e = StrExpr(val)
+        elif isinstance(val, bytes):
+            e = BytesExpr(bytes_to_human_readable_repr(val))
+        elif isinstance(val, bool):  # Must check before int!
+            e = NameExpr(str(val))
+        elif isinstance(val, int):
+            e = IntExpr(val)
+        elif isinstance(val, float):
+            e = FloatExpr(val)
+        elif isinstance(val, complex):
+            e = ComplexExpr(val)
+        elif val is Ellipsis:
+            e = EllipsisExpr()
+        else:
+            raise RuntimeError("Constant not implemented for " + str(type(val)))
+        return self.set_line(e, n)
+
+    # JoinedStr(expr* values)
+    def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression:
+        # Each of n.values is a str or FormattedValue; we just concatenate
+        # them all using ''.join.
+        empty_string = StrExpr("")
+        empty_string.set_line(n.lineno, n.col_offset)
+        strs_to_join = ListExpr(self.translate_expr_list(n.values))
+        strs_to_join.set_line(empty_string)
+        # Don't make unnecessary join call if there is only one str to join
+        if len(strs_to_join.items) == 1:
+            return self.set_line(strs_to_join.items[0], n)
+        elif len(strs_to_join.items) > 1:
+            last = strs_to_join.items[-1]
+            if isinstance(last, StrExpr) and last.value == "":
+                # 3.12 can add an empty literal at the end. Delete it for consistency
+                # between Python versions.
+                del strs_to_join.items[-1:]
+        join_method = MemberExpr(empty_string, "join")
+        join_method.set_line(empty_string)
+        result_expression = CallExpr(join_method, [strs_to_join], [ARG_POS], [None])
+        return self.set_line(result_expression, n)
+
+    # FormattedValue(expr value)
+    def visit_FormattedValue(self, n: ast3.FormattedValue) -> Expression:
+        # A FormattedValue is a component of a JoinedStr, or it can exist
+        # on its own. We translate them to individual '{}'.format(value)
+        # calls. Format specifier and conversion information is passed along
+        # to allow mypyc to support f-strings with format specifiers and conversions.
+        val_exp = self.visit(n.value)
+        val_exp.set_line(n.lineno, n.col_offset)
+        conv_str = "" if n.conversion < 0 else "!" + chr(n.conversion)
+        format_string = StrExpr("{" + conv_str + ":{}}")
+        format_spec_exp = self.visit(n.format_spec) if n.format_spec is not None else StrExpr("")
+        format_string.set_line(n.lineno, n.col_offset)
+        format_method = MemberExpr(format_string, "format")
+        format_method.set_line(format_string)
+        result_expression = CallExpr(
+            format_method, [val_exp, format_spec_exp], [ARG_POS, ARG_POS], [None, None]
+        )
+        return self.set_line(result_expression, n)
+
+    # Attribute(expr value, identifier attr, expr_context ctx)
+    def visit_Attribute(self, n: Attribute) -> MemberExpr | SuperExpr:
+        value = n.value
+        member_expr = MemberExpr(self.visit(value), n.attr)
+        obj = member_expr.expr
+        if (
+            isinstance(obj, CallExpr)
+            and isinstance(obj.callee, NameExpr)
+            and obj.callee.name == "super"
+        ):
+            e: MemberExpr | SuperExpr = SuperExpr(member_expr.name, obj)
+        else:
+            e = member_expr
+        return self.set_line(e, n)
+
+    # Subscript(expr value, slice slice, expr_context ctx)
+    def visit_Subscript(self, n: ast3.Subscript) -> IndexExpr:
+        e = IndexExpr(self.visit(n.value), self.visit(n.slice))
+        self.set_line(e, n)
+        # alias to please mypyc
+        is_py38_or_earlier = sys.version_info < (3, 9)
+        if isinstance(n.slice, ast3.Slice) or (
+            is_py38_or_earlier and isinstance(n.slice, ast3.ExtSlice)
+        ):
+            # Before Python 3.9, Slice has no line/column in the raw ast. To avoid incompatibility
+            # visit_Slice doesn't set_line, even in Python 3.9 on.
+            # ExtSlice also has no line/column info. In Python 3.9 on, line/column is set for
+            # e.index when visiting n.slice.
+            e.index.line = e.line
+            e.index.column = e.column
+        return e
+
+    # Starred(expr value, expr_context ctx)
+    def visit_Starred(self, n: Starred) -> StarExpr:
+        e = StarExpr(self.visit(n.value))
+        return self.set_line(e, n)
+
+    # Name(identifier id, expr_context ctx)
+    def visit_Name(self, n: Name) -> NameExpr:
+        e = NameExpr(n.id)
+        return self.set_line(e, n)
+
+    # List(expr* elts, expr_context ctx)
+    def visit_List(self, n: ast3.List) -> ListExpr | TupleExpr:
+        expr_list: list[Expression] = [self.visit(e) for e in n.elts]
+        if isinstance(n.ctx, ast3.Store):
+            # [x, y] = z and (x, y) = z means exactly the same thing
+            e: ListExpr | TupleExpr = TupleExpr(expr_list)
+        else:
+            e = ListExpr(expr_list)
+        return self.set_line(e, n)
+
+    # Tuple(expr* elts, expr_context ctx)
+    def visit_Tuple(self, n: ast3.Tuple) -> TupleExpr:
+        e = TupleExpr(self.translate_expr_list(n.elts))
+        return self.set_line(e, n)
+
+    # --- slice ---
+
+    # Slice(expr? lower, expr? upper, expr? step)
+    def visit_Slice(self, n: ast3.Slice) -> SliceExpr:
+        return SliceExpr(self.visit(n.lower), self.visit(n.upper), self.visit(n.step))
+
+    # ExtSlice(slice* dims)
+    def visit_ExtSlice(self, n: ast3.ExtSlice) -> TupleExpr:
+        # cast for mypyc's benefit on Python 3.9
+        return TupleExpr(self.translate_expr_list(cast(Any, n).dims))
+
+    # Index(expr value)
+    def visit_Index(self, n: Index) -> Node:
+        # cast for mypyc's benefit on Python 3.9
+        value = self.visit(cast(Any, n).value)
+        assert isinstance(value, Node)
+        return value
+
+    # Match(expr subject, match_case* cases) # python 3.10 and later
+    def visit_Match(self, n: Match) -> MatchStmt:
+        node = MatchStmt(
+            self.visit(n.subject),
+            [self.visit(c.pattern) for c in n.cases],
+            [self.visit(c.guard) for c in n.cases],
+            [self.as_required_block(c.body) for c in n.cases],
+        )
+        return self.set_line(node, n)
+
+    def visit_MatchValue(self, n: MatchValue) -> ValuePattern:
+        node = ValuePattern(self.visit(n.value))
+        return self.set_line(node, n)
+
+    def visit_MatchSingleton(self, n: MatchSingleton) -> SingletonPattern:
+        node = SingletonPattern(n.value)
+        return self.set_line(node, n)
+
+    def visit_MatchSequence(self, n: MatchSequence) -> SequencePattern:
+        patterns = [self.visit(p) for p in n.patterns]
+        stars = [p for p in patterns if isinstance(p, StarredPattern)]
+        assert len(stars) < 2
+
+        node = SequencePattern(patterns)
+        return self.set_line(node, n)
+
+    def visit_MatchStar(self, n: MatchStar) -> StarredPattern:
+        if n.name is None:
+            node = StarredPattern(None)
+        else:
+            name = self.set_line(NameExpr(n.name), n)
+            node = StarredPattern(name)
+
+        return self.set_line(node, n)
+
+    def visit_MatchMapping(self, n: MatchMapping) -> MappingPattern:
+        keys = [self.visit(k) for k in n.keys]
+        values = [self.visit(v) for v in n.patterns]
+
+        if n.rest is None:
+            rest = None
+        else:
+            rest = NameExpr(n.rest)
+
+        node = MappingPattern(keys, values, rest)
+        return self.set_line(node, n)
+
+    def visit_MatchClass(self, n: MatchClass) -> ClassPattern:
+        class_ref = self.visit(n.cls)
+        assert isinstance(class_ref, RefExpr)
+        positionals = [self.visit(p) for p in n.patterns]
+        keyword_keys = n.kwd_attrs
+        keyword_values = [self.visit(p) for p in n.kwd_patterns]
+
+        node = ClassPattern(class_ref, positionals, keyword_keys, keyword_values)
+        return self.set_line(node, n)
+
+    # MatchAs(expr pattern, identifier name)
+    def visit_MatchAs(self, n: MatchAs) -> AsPattern:
+        if n.name is None:
+            name = None
+        else:
+            name = NameExpr(n.name)
+            name = self.set_line(name, n)
+        node = AsPattern(self.visit(n.pattern), name)
+        return self.set_line(node, n)
+
+    # MatchOr(expr* pattern)
+    def visit_MatchOr(self, n: MatchOr) -> OrPattern:
+        node = OrPattern([self.visit(pattern) for pattern in n.patterns])
+        return self.set_line(node, n)
+
+
+class TypeConverter:
+    def __init__(
+        self,
+        errors: Errors | None,
+        line: int = -1,
+        override_column: int = -1,
+        is_evaluated: bool = True,
+    ) -> None:
+        self.errors = errors
+        self.line = line
+        self.override_column = override_column
+        self.node_stack: list[AST] = []
+        self.is_evaluated = is_evaluated
+
+    def convert_column(self, column: int) -> int:
+        """Apply column override if defined; otherwise return column.
+
+        Column numbers are sometimes incorrect in the AST and the column
+        override can be used to work around that.
+        """
+        if self.override_column < 0:
+            return column
+        else:
+            return self.override_column
+
+    def invalid_type(self, node: AST, note: str | None = None) -> RawExpressionType:
+        """Constructs a type representing some expression that normally forms an invalid type.
+        For example, if we see a type hint that says "3 + 4", we would transform that
+        expression into a RawExpressionType.
+
+        The semantic analysis layer will report an "Invalid type" error when it
+        encounters this type, along with the given note if one is provided.
+
+        See RawExpressionType's docstring for more details on how it's used.
+        """
+        return RawExpressionType(
+            None, "typing.Any", line=self.line, column=getattr(node, "col_offset", -1), note=note
+        )
+
+    @overload
+    def visit(self, node: ast3.expr) -> ProperType:
+        ...
+
+    @overload
+    def visit(self, node: AST | None) -> ProperType | None:
+        ...
+
+    def visit(self, node: AST | None) -> ProperType | None:
+        """Modified visit -- keep track of the stack of nodes"""
+        if node is None:
+            return None
+        self.node_stack.append(node)
+        try:
+            method = "visit_" + node.__class__.__name__
+            visitor = getattr(self, method, None)
+            if visitor is not None:
+                typ = visitor(node)
+                assert isinstance(typ, ProperType)
+                return typ
+            else:
+                return self.invalid_type(node)
+        finally:
+            self.node_stack.pop()
+
+    def parent(self) -> AST | None:
+        """Return the AST node above the one we are processing"""
+        if len(self.node_stack) < 2:
+            return None
+        return self.node_stack[-2]
+
+    def fail(self, msg: ErrorMessage, line: int, column: int) -> None:
+        if self.errors:
+            self.errors.report(line, column, msg.value, blocker=True, code=msg.code)
+
+    def note(self, msg: str, line: int, column: int) -> None:
+        if self.errors:
+            self.errors.report(line, column, msg, severity="note", code=codes.SYNTAX)
+
+    def translate_expr_list(self, l: Sequence[ast3.expr]) -> list[Type]:
+        return [self.visit(e) for e in l]
+
+    def visit_Call(self, e: Call) -> Type:
+        # Parse the arg constructor
+        f = e.func
+        constructor = stringify_name(f)
+
+        if not isinstance(self.parent(), ast3.List):
+            note = None
+            if constructor:
+                note = "Suggestion: use {0}[...] instead of {0}(...)".format(constructor)
+            return self.invalid_type(e, note=note)
+        if not constructor:
+            self.fail(message_registry.ARG_CONSTRUCTOR_NAME_EXPECTED, e.lineno, e.col_offset)
+
+        name: str | None = None
+        default_type = AnyType(TypeOfAny.special_form)
+        typ: Type = default_type
+        for i, arg in enumerate(e.args):
+            if i == 0:
+                converted = self.visit(arg)
+                assert converted is not None
+                typ = converted
+            elif i == 1:
+                name = self._extract_argument_name(arg)
+            else:
+                self.fail(message_registry.ARG_CONSTRUCTOR_TOO_MANY_ARGS, f.lineno, f.col_offset)
+        for k in e.keywords:
+            value = k.value
+            if k.arg == "name":
+                if name is not None:
+                    self.fail(
+                        message_registry.MULTIPLE_VALUES_FOR_NAME_KWARG.format(constructor),
+                        f.lineno,
+                        f.col_offset,
+                    )
+                name = self._extract_argument_name(value)
+            elif k.arg == "type":
+                if typ is not default_type:
+                    self.fail(
+                        message_registry.MULTIPLE_VALUES_FOR_TYPE_KWARG.format(constructor),
+                        f.lineno,
+                        f.col_offset,
+                    )
+                converted = self.visit(value)
+                assert converted is not None
+                typ = converted
+            else:
+                self.fail(
+                    message_registry.ARG_CONSTRUCTOR_UNEXPECTED_ARG.format(k.arg),
+                    value.lineno,
+                    value.col_offset,
+                )
+        return CallableArgument(typ, name, constructor, e.lineno, e.col_offset)
+
+    def translate_argument_list(self, l: Sequence[ast3.expr]) -> TypeList:
+        return TypeList([self.visit(e) for e in l], line=self.line)
+
+    def _extract_argument_name(self, n: ast3.expr) -> str | None:
+        if isinstance(n, Constant) and isinstance(n.value, str):
+            return n.value.strip()
+        elif isinstance(n, Constant) and n.value is None:
+            return None
+        self.fail(
+            message_registry.ARG_NAME_EXPECTED_STRING_LITERAL.format(type(n).__name__),
+            self.line,
+            0,
+        )
+        return None
+
+    def visit_Name(self, n: Name) -> Type:
+        return UnboundType(n.id, line=self.line, column=self.convert_column(n.col_offset))
+
+    def visit_BinOp(self, n: ast3.BinOp) -> Type:
+        if not isinstance(n.op, ast3.BitOr):
+            return self.invalid_type(n)
+
+        left = self.visit(n.left)
+        right = self.visit(n.right)
+        return UnionType(
+            [left, right],
+            line=self.line,
+            column=self.convert_column(n.col_offset),
+            is_evaluated=self.is_evaluated,
+            uses_pep604_syntax=True,
+        )
+
+    def visit_Constant(self, n: Constant) -> Type:
+        val = n.value
+        if val is None:
+            # None is a type.
+            return UnboundType("None", line=self.line)
+        if isinstance(val, str):
+            # Parse forward reference.
+            return parse_type_string(val, "builtins.str", self.line, n.col_offset)
+        if val is Ellipsis:
+            # '...' is valid in some types.
+            return EllipsisType(line=self.line)
+        if isinstance(val, bool):
+            # Special case for True/False.
+            return RawExpressionType(val, "builtins.bool", line=self.line)
+        if isinstance(val, (int, float, complex)):
+            return self.numeric_type(val, n)
+        if isinstance(val, bytes):
+            contents = bytes_to_human_readable_repr(val)
+            return RawExpressionType(contents, "builtins.bytes", self.line, column=n.col_offset)
+        # Everything else is invalid.
+        return self.invalid_type(n)
+
+    # UnaryOp(op, operand)
+    def visit_UnaryOp(self, n: UnaryOp) -> Type:
+        # We support specifically Literal[-4] and nothing else.
+        # For example, Literal[+4] or Literal[~6] is not supported.
+        typ = self.visit(n.operand)
+        if isinstance(typ, RawExpressionType) and isinstance(n.op, USub):
+            if isinstance(typ.literal_value, int):
+                typ.literal_value *= -1
+                return typ
+        return self.invalid_type(n)
+
+    def numeric_type(self, value: object, n: AST) -> Type:
+        # The node's field has the type complex, but complex isn't *really*
+        # a parent of int and float, and this causes isinstance below
+        # to think that the complex branch is always picked. Avoid
+        # this by throwing away the type.
+        if isinstance(value, int):
+            numeric_value: int | None = value
+            type_name = "builtins.int"
+        else:
+            # Other kinds of numbers (floats, complex) are not valid parameters for
+            # RawExpressionType so we just pass in 'None' for now. We'll report the
+            # appropriate error at a later stage.
+            numeric_value = None
+            type_name = f"builtins.{type(value).__name__}"
+        return RawExpressionType(
+            numeric_value, type_name, line=self.line, column=getattr(n, "col_offset", -1)
+        )
+
+    def visit_Index(self, n: ast3.Index) -> Type:
+        # cast for mypyc's benefit on Python 3.9
+        value = self.visit(cast(Any, n).value)
+        assert isinstance(value, Type)
+        return value
+
+    def visit_Slice(self, n: ast3.Slice) -> Type:
+        return self.invalid_type(n, note="did you mean to use ',' instead of ':' ?")
+
+    # Subscript(expr value, slice slice, expr_context ctx)  # Python 3.8 and before
+    # Subscript(expr value, expr slice, expr_context ctx)  # Python 3.9 and later
+    def visit_Subscript(self, n: ast3.Subscript) -> Type:
+        if sys.version_info >= (3, 9):  # Really 3.9a5 or later
+            sliceval: Any = n.slice
+        # Python 3.8 or earlier use a different AST structure for subscripts
+        elif isinstance(n.slice, ast3.Index):
+            sliceval: Any = n.slice.value
+        elif isinstance(n.slice, ast3.Slice):
+            sliceval = copy.deepcopy(n.slice)  # so we don't mutate passed AST
+            if getattr(sliceval, "col_offset", None) is None:
+                # Fix column information so that we get Python 3.9+ message order
+                sliceval.col_offset = sliceval.lower.col_offset
+        else:
+            assert isinstance(n.slice, ast3.ExtSlice)
+            dims = copy.deepcopy(n.slice.dims)
+            for s in dims:
+                if getattr(s, "col_offset", None) is None:
+                    if isinstance(s, ast3.Index):
+                        s.col_offset = s.value.col_offset
+                    elif isinstance(s, ast3.Slice):
+                        assert s.lower is not None
+                        s.col_offset = s.lower.col_offset
+            sliceval = ast3.Tuple(dims, n.ctx)
+
+        empty_tuple_index = False
+        if isinstance(sliceval, ast3.Tuple):
+            params = self.translate_expr_list(sliceval.elts)
+            if len(sliceval.elts) == 0:
+                empty_tuple_index = True
+        else:
+            params = [self.visit(sliceval)]
+
+        value = self.visit(n.value)
+        if isinstance(value, UnboundType) and not value.args:
+            return UnboundType(
+                value.name,
+                params,
+                line=self.line,
+                column=value.column,
+                empty_tuple_index=empty_tuple_index,
+            )
+        else:
+            return self.invalid_type(n)
+
+    def visit_Tuple(self, n: ast3.Tuple) -> Type:
+        return TupleType(
+            self.translate_expr_list(n.elts),
+            _dummy_fallback,
+            implicit=True,
+            line=self.line,
+            column=self.convert_column(n.col_offset),
+        )
+
+    # Attribute(expr value, identifier attr, expr_context ctx)
+    def visit_Attribute(self, n: Attribute) -> Type:
+        before_dot = self.visit(n.value)
+
+        if isinstance(before_dot, UnboundType) and not before_dot.args:
+            return UnboundType(f"{before_dot.name}.{n.attr}", line=self.line)
+        else:
+            return self.invalid_type(n)
+
+    # List(expr* elts, expr_context ctx)
+    def visit_List(self, n: ast3.List) -> Type:
+        assert isinstance(n.ctx, ast3.Load)
+        return self.translate_argument_list(n.elts)
+
+
+def stringify_name(n: AST) -> str | None:
+    if isinstance(n, Name):
+        return n.id
+    elif isinstance(n, Attribute):
+        sv = stringify_name(n.value)
+        if sv is not None:
+            return f"{sv}.{n.attr}"
+    return None  # Can't do it.
+
+
+class FindAttributeAssign(TraverserVisitor):
+    """Check if an AST contains attribute assignments (e.g. self.x = 0)."""
+
+    def __init__(self) -> None:
+        self.lvalue = False
+        self.found = False
+
+    def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
+        self.lvalue = True
+        for lv in s.lvalues:
+            lv.accept(self)
+        self.lvalue = False
+
+    def visit_with_stmt(self, s: WithStmt) -> None:
+        self.lvalue = True
+        for lv in s.target:
+            if lv is not None:
+                lv.accept(self)
+        self.lvalue = False
+        s.body.accept(self)
+
+    def visit_for_stmt(self, s: ForStmt) -> None:
+        self.lvalue = True
+        s.index.accept(self)
+        self.lvalue = False
+        s.body.accept(self)
+        if s.else_body:
+            s.else_body.accept(self)
+
+    def visit_expression_stmt(self, s: ExpressionStmt) -> None:
+        # No need to look inside these
+        pass
+
+    def visit_call_expr(self, e: CallExpr) -> None:
+        # No need to look inside these
+        pass
+
+    def visit_index_expr(self, e: IndexExpr) -> None:
+        # No need to look inside these
+        pass
+
+    def visit_member_expr(self, e: MemberExpr) -> None:
+        if self.lvalue:
+            self.found = True
+
+
+class FindYield(TraverserVisitor):
+    """Check if an AST contains yields or yield froms."""
+
+    def __init__(self) -> None:
+        self.found = False
+
+    def visit_yield_expr(self, e: YieldExpr) -> None:
+        self.found = True
+
+    def visit_yield_from_expr(self, e: YieldFromExpr) -> None:
+        self.found = True
+
+
+def is_possible_trivial_body(s: list[Statement]) -> bool:
+    """Could the statements form a "trivial" function body, such as 'pass'?
+
+    This mimics mypy.semanal.is_trivial_body, but this runs before
+    semantic analysis so some checks must be conservative.
+    """
+    l = len(s)
+    if l == 0:
+        return False
+    i = 0
+    if isinstance(s[0], ExpressionStmt) and isinstance(s[0].expr, StrExpr):
+        # Skip docstring
+        i += 1
+    if i == l:
+        return True
+    if l > i + 1:
+        return False
+    stmt = s[i]
+    return isinstance(stmt, (PassStmt, RaiseStmt)) or (
+        isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, EllipsisExpr)
+    )

二進制
venv/lib/python3.11/site-packages/mypy/find_sources.cpython-311-x86_64-linux-gnu.so


+ 243 - 0
venv/lib/python3.11/site-packages/mypy/find_sources.py

@@ -0,0 +1,243 @@
+"""Routines for finding the sources that mypy will check"""
+
+from __future__ import annotations
+
+import functools
+import os
+from typing import Final, Sequence
+
+from mypy.fscache import FileSystemCache
+from mypy.modulefinder import PYTHON_EXTENSIONS, BuildSource, matches_exclude, mypy_path
+from mypy.options import Options
+
+PY_EXTENSIONS: Final = tuple(PYTHON_EXTENSIONS)
+
+
+class InvalidSourceList(Exception):
+    """Exception indicating a problem in the list of sources given to mypy."""
+
+
+def create_source_list(
+    paths: Sequence[str],
+    options: Options,
+    fscache: FileSystemCache | None = None,
+    allow_empty_dir: bool = False,
+) -> list[BuildSource]:
+    """From a list of source files/directories, makes a list of BuildSources.
+
+    Raises InvalidSourceList on errors.
+    """
+    fscache = fscache or FileSystemCache()
+    finder = SourceFinder(fscache, options)
+
+    sources = []
+    for path in paths:
+        path = os.path.normpath(path)
+        if path.endswith(PY_EXTENSIONS):
+            # Can raise InvalidSourceList if a directory doesn't have a valid module name.
+            name, base_dir = finder.crawl_up(path)
+            sources.append(BuildSource(path, name, None, base_dir))
+        elif fscache.isdir(path):
+            sub_sources = finder.find_sources_in_dir(path)
+            if not sub_sources and not allow_empty_dir:
+                raise InvalidSourceList(f"There are no .py[i] files in directory '{path}'")
+            sources.extend(sub_sources)
+        else:
+            mod = os.path.basename(path) if options.scripts_are_modules else None
+            sources.append(BuildSource(path, mod, None))
+    return sources
+
+
+def keyfunc(name: str) -> tuple[bool, int, str]:
+    """Determines sort order for directory listing.
+
+    The desirable properties are:
+    1) foo < foo.pyi < foo.py
+    2) __init__.py[i] < foo
+    """
+    base, suffix = os.path.splitext(name)
+    for i, ext in enumerate(PY_EXTENSIONS):
+        if suffix == ext:
+            return (base != "__init__", i, base)
+    return (base != "__init__", -1, name)
+
+
+def normalise_package_base(root: str) -> str:
+    if not root:
+        root = os.curdir
+    root = os.path.abspath(root)
+    if root.endswith(os.sep):
+        root = root[:-1]
+    return root
+
+
+def get_explicit_package_bases(options: Options) -> list[str] | None:
+    """Returns explicit package bases to use if the option is enabled, or None if disabled.
+
+    We currently use MYPYPATH and the current directory as the package bases. In the future,
+    when --namespace-packages is the default could also use the values passed with the
+    --package-root flag, see #9632.
+
+    Values returned are normalised so we can use simple string comparisons in
+    SourceFinder.is_explicit_package_base
+    """
+    if not options.explicit_package_bases:
+        return None
+    roots = mypy_path() + options.mypy_path + [os.getcwd()]
+    return [normalise_package_base(root) for root in roots]
+
+
+class SourceFinder:
+    def __init__(self, fscache: FileSystemCache, options: Options) -> None:
+        self.fscache = fscache
+        self.explicit_package_bases = get_explicit_package_bases(options)
+        self.namespace_packages = options.namespace_packages
+        self.exclude = options.exclude
+        self.verbosity = options.verbosity
+
+    def is_explicit_package_base(self, path: str) -> bool:
+        assert self.explicit_package_bases
+        return normalise_package_base(path) in self.explicit_package_bases
+
+    def find_sources_in_dir(self, path: str) -> list[BuildSource]:
+        sources = []
+
+        seen: set[str] = set()
+        names = sorted(self.fscache.listdir(path), key=keyfunc)
+        for name in names:
+            # Skip certain names altogether
+            if name in ("__pycache__", "site-packages", "node_modules") or name.startswith("."):
+                continue
+            subpath = os.path.join(path, name)
+
+            if matches_exclude(subpath, self.exclude, self.fscache, self.verbosity >= 2):
+                continue
+
+            if self.fscache.isdir(subpath):
+                sub_sources = self.find_sources_in_dir(subpath)
+                if sub_sources:
+                    seen.add(name)
+                    sources.extend(sub_sources)
+            else:
+                stem, suffix = os.path.splitext(name)
+                if stem not in seen and suffix in PY_EXTENSIONS:
+                    seen.add(stem)
+                    module, base_dir = self.crawl_up(subpath)
+                    sources.append(BuildSource(subpath, module, None, base_dir))
+
+        return sources
+
+    def crawl_up(self, path: str) -> tuple[str, str]:
+        """Given a .py[i] filename, return module and base directory.
+
+        For example, given "xxx/yyy/foo/bar.py", we might return something like:
+        ("foo.bar", "xxx/yyy")
+
+        If namespace packages is off, we crawl upwards until we find a directory without
+        an __init__.py
+
+        If namespace packages is on, we crawl upwards until the nearest explicit base directory.
+        Failing that, we return one past the highest directory containing an __init__.py
+
+        We won't crawl past directories with invalid package names.
+        The base directory returned is an absolute path.
+        """
+        path = os.path.abspath(path)
+        parent, filename = os.path.split(path)
+
+        module_name = strip_py(filename) or filename
+
+        parent_module, base_dir = self.crawl_up_dir(parent)
+        if module_name == "__init__":
+            return parent_module, base_dir
+
+        # Note that module_name might not actually be a valid identifier, but that's okay
+        # Ignoring this possibility sidesteps some search path confusion
+        module = module_join(parent_module, module_name)
+        return module, base_dir
+
+    def crawl_up_dir(self, dir: str) -> tuple[str, str]:
+        return self._crawl_up_helper(dir) or ("", dir)
+
+    @functools.lru_cache  # noqa: B019
+    def _crawl_up_helper(self, dir: str) -> tuple[str, str] | None:
+        """Given a directory, maybe returns module and base directory.
+
+        We return a non-None value if we were able to find something clearly intended as a base
+        directory (as adjudicated by being an explicit base directory or by containing a package
+        with __init__.py).
+
+        This distinction is necessary for namespace packages, so that we know when to treat
+        ourselves as a subpackage.
+        """
+        # stop crawling if we're an explicit base directory
+        if self.explicit_package_bases is not None and self.is_explicit_package_base(dir):
+            return "", dir
+
+        parent, name = os.path.split(dir)
+        if name.endswith("-stubs"):
+            name = name[:-6]  # PEP-561 stub-only directory
+
+        # recurse if there's an __init__.py
+        init_file = self.get_init_file(dir)
+        if init_file is not None:
+            if not name.isidentifier():
+                # in most cases the directory name is invalid, we'll just stop crawling upwards
+                # but if there's an __init__.py in the directory, something is messed up
+                raise InvalidSourceList(f"{name} is not a valid Python package name")
+            # we're definitely a package, so we always return a non-None value
+            mod_prefix, base_dir = self.crawl_up_dir(parent)
+            return module_join(mod_prefix, name), base_dir
+
+        # stop crawling if we're out of path components or our name is an invalid identifier
+        if not name or not parent or not name.isidentifier():
+            return None
+
+        # stop crawling if namespace packages is off (since we don't have an __init__.py)
+        if not self.namespace_packages:
+            return None
+
+        # at this point: namespace packages is on, we don't have an __init__.py and we're not an
+        # explicit base directory
+        result = self._crawl_up_helper(parent)
+        if result is None:
+            # we're not an explicit base directory and we don't have an __init__.py
+            # and none of our parents are either, so return
+            return None
+        # one of our parents was an explicit base directory or had an __init__.py, so we're
+        # definitely a subpackage! chain our name to the module.
+        mod_prefix, base_dir = result
+        return module_join(mod_prefix, name), base_dir
+
+    def get_init_file(self, dir: str) -> str | None:
+        """Check whether a directory contains a file named __init__.py[i].
+
+        If so, return the file's name (with dir prefixed).  If not, return None.
+
+        This prefers .pyi over .py (because of the ordering of PY_EXTENSIONS).
+        """
+        for ext in PY_EXTENSIONS:
+            f = os.path.join(dir, "__init__" + ext)
+            if self.fscache.isfile(f):
+                return f
+            if ext == ".py" and self.fscache.init_under_package_root(f):
+                return f
+        return None
+
+
+def module_join(parent: str, child: str) -> str:
+    """Join module ids, accounting for a possibly empty parent."""
+    if parent:
+        return parent + "." + child
+    return child
+
+
+def strip_py(arg: str) -> str | None:
+    """Strip a trailing .py or .pyi suffix.
+
+    Return None if no such suffix is found.
+    """
+    for ext in PY_EXTENSIONS:
+        if arg.endswith(ext):
+            return arg[: -len(ext)]
+    return None

二進制
venv/lib/python3.11/site-packages/mypy/fixup.cpython-311-x86_64-linux-gnu.so


+ 410 - 0
venv/lib/python3.11/site-packages/mypy/fixup.py

@@ -0,0 +1,410 @@
+"""Fix up various things after deserialization."""
+
+from __future__ import annotations
+
+from typing import Any, Final
+
+from mypy.lookup import lookup_fully_qualified
+from mypy.nodes import (
+    Block,
+    ClassDef,
+    Decorator,
+    FuncDef,
+    MypyFile,
+    OverloadedFuncDef,
+    ParamSpecExpr,
+    SymbolTable,
+    TypeAlias,
+    TypeInfo,
+    TypeVarExpr,
+    TypeVarTupleExpr,
+    Var,
+)
+from mypy.types import (
+    NOT_READY,
+    AnyType,
+    CallableType,
+    Instance,
+    LiteralType,
+    Overloaded,
+    Parameters,
+    ParamSpecType,
+    TupleType,
+    TypeAliasType,
+    TypedDictType,
+    TypeOfAny,
+    TypeType,
+    TypeVarTupleType,
+    TypeVarType,
+    TypeVisitor,
+    UnboundType,
+    UnionType,
+    UnpackType,
+)
+from mypy.visitor import NodeVisitor
+
+
+# N.B: we do a allow_missing fixup when fixing up a fine-grained
+# incremental cache load (since there may be cross-refs into deleted
+# modules)
+def fixup_module(tree: MypyFile, modules: dict[str, MypyFile], allow_missing: bool) -> None:
+    node_fixer = NodeFixer(modules, allow_missing)
+    node_fixer.visit_symbol_table(tree.names, tree.fullname)
+
+
+# TODO: Fix up .info when deserializing, i.e. much earlier.
+class NodeFixer(NodeVisitor[None]):
+    current_info: TypeInfo | None = None
+
+    def __init__(self, modules: dict[str, MypyFile], allow_missing: bool) -> None:
+        self.modules = modules
+        self.allow_missing = allow_missing
+        self.type_fixer = TypeFixer(self.modules, allow_missing)
+
+    # NOTE: This method isn't (yet) part of the NodeVisitor API.
+    def visit_type_info(self, info: TypeInfo) -> None:
+        save_info = self.current_info
+        try:
+            self.current_info = info
+            if info.defn:
+                info.defn.accept(self)
+            if info.names:
+                self.visit_symbol_table(info.names, info.fullname)
+            if info.bases:
+                for base in info.bases:
+                    base.accept(self.type_fixer)
+            if info._promote:
+                for p in info._promote:
+                    p.accept(self.type_fixer)
+            if info.tuple_type:
+                info.tuple_type.accept(self.type_fixer)
+                info.update_tuple_type(info.tuple_type)
+                if info.special_alias:
+                    info.special_alias.alias_tvars = list(info.defn.type_vars)
+            if info.typeddict_type:
+                info.typeddict_type.accept(self.type_fixer)
+                info.update_typeddict_type(info.typeddict_type)
+                if info.special_alias:
+                    info.special_alias.alias_tvars = list(info.defn.type_vars)
+            if info.declared_metaclass:
+                info.declared_metaclass.accept(self.type_fixer)
+            if info.metaclass_type:
+                info.metaclass_type.accept(self.type_fixer)
+            if info.alt_promote:
+                info.alt_promote.accept(self.type_fixer)
+                instance = Instance(info, [])
+                # Hack: We may also need to add a backwards promotion (from int to native int),
+                # since it might not be serialized.
+                if instance not in info.alt_promote.type._promote:
+                    info.alt_promote.type._promote.append(instance)
+            if info._mro_refs:
+                info.mro = [
+                    lookup_fully_qualified_typeinfo(
+                        self.modules, name, allow_missing=self.allow_missing
+                    )
+                    for name in info._mro_refs
+                ]
+                info._mro_refs = None
+        finally:
+            self.current_info = save_info
+
+    # NOTE: This method *definitely* isn't part of the NodeVisitor API.
+    def visit_symbol_table(self, symtab: SymbolTable, table_fullname: str) -> None:
+        # Copy the items because we may mutate symtab.
+        for key, value in list(symtab.items()):
+            cross_ref = value.cross_ref
+            if cross_ref is not None:  # Fix up cross-reference.
+                value.cross_ref = None
+                if cross_ref in self.modules:
+                    value.node = self.modules[cross_ref]
+                else:
+                    stnode = lookup_fully_qualified(
+                        cross_ref, self.modules, raise_on_missing=not self.allow_missing
+                    )
+                    if stnode is not None:
+                        assert stnode.node is not None, (table_fullname + "." + key, cross_ref)
+                        value.node = stnode.node
+                    elif not self.allow_missing:
+                        assert False, f"Could not find cross-ref {cross_ref}"
+                    else:
+                        # We have a missing crossref in allow missing mode, need to put something
+                        value.node = missing_info(self.modules)
+            else:
+                if isinstance(value.node, TypeInfo):
+                    # TypeInfo has no accept().  TODO: Add it?
+                    self.visit_type_info(value.node)
+                elif value.node is not None:
+                    value.node.accept(self)
+                else:
+                    assert False, f"Unexpected empty node {key!r}: {value}"
+
+    def visit_func_def(self, func: FuncDef) -> None:
+        if self.current_info is not None:
+            func.info = self.current_info
+        if func.type is not None:
+            func.type.accept(self.type_fixer)
+
+    def visit_overloaded_func_def(self, o: OverloadedFuncDef) -> None:
+        if self.current_info is not None:
+            o.info = self.current_info
+        if o.type:
+            o.type.accept(self.type_fixer)
+        for item in o.items:
+            item.accept(self)
+        if o.impl:
+            o.impl.accept(self)
+
+    def visit_decorator(self, d: Decorator) -> None:
+        if self.current_info is not None:
+            d.var.info = self.current_info
+        if d.func:
+            d.func.accept(self)
+        if d.var:
+            d.var.accept(self)
+        for node in d.decorators:
+            node.accept(self)
+
+    def visit_class_def(self, c: ClassDef) -> None:
+        for v in c.type_vars:
+            if isinstance(v, TypeVarType):
+                for value in v.values:
+                    value.accept(self.type_fixer)
+            v.upper_bound.accept(self.type_fixer)
+            v.default.accept(self.type_fixer)
+
+    def visit_type_var_expr(self, tv: TypeVarExpr) -> None:
+        for value in tv.values:
+            value.accept(self.type_fixer)
+        tv.upper_bound.accept(self.type_fixer)
+        tv.default.accept(self.type_fixer)
+
+    def visit_paramspec_expr(self, p: ParamSpecExpr) -> None:
+        p.upper_bound.accept(self.type_fixer)
+        p.default.accept(self.type_fixer)
+
+    def visit_type_var_tuple_expr(self, tv: TypeVarTupleExpr) -> None:
+        tv.upper_bound.accept(self.type_fixer)
+        tv.default.accept(self.type_fixer)
+
+    def visit_var(self, v: Var) -> None:
+        if self.current_info is not None:
+            v.info = self.current_info
+        if v.type is not None:
+            v.type.accept(self.type_fixer)
+
+    def visit_type_alias(self, a: TypeAlias) -> None:
+        a.target.accept(self.type_fixer)
+        for v in a.alias_tvars:
+            v.accept(self.type_fixer)
+
+
+class TypeFixer(TypeVisitor[None]):
+    def __init__(self, modules: dict[str, MypyFile], allow_missing: bool) -> None:
+        self.modules = modules
+        self.allow_missing = allow_missing
+
+    def visit_instance(self, inst: Instance) -> None:
+        # TODO: Combine Instances that are exactly the same?
+        type_ref = inst.type_ref
+        if type_ref is None:
+            return  # We've already been here.
+        inst.type_ref = None
+        inst.type = lookup_fully_qualified_typeinfo(
+            self.modules, type_ref, allow_missing=self.allow_missing
+        )
+        # TODO: Is this needed or redundant?
+        # Also fix up the bases, just in case.
+        for base in inst.type.bases:
+            if base.type is NOT_READY:
+                base.accept(self)
+        for a in inst.args:
+            a.accept(self)
+        if inst.last_known_value is not None:
+            inst.last_known_value.accept(self)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> None:
+        type_ref = t.type_ref
+        if type_ref is None:
+            return  # We've already been here.
+        t.type_ref = None
+        t.alias = lookup_fully_qualified_alias(
+            self.modules, type_ref, allow_missing=self.allow_missing
+        )
+        for a in t.args:
+            a.accept(self)
+
+    def visit_any(self, o: Any) -> None:
+        pass  # Nothing to descend into.
+
+    def visit_callable_type(self, ct: CallableType) -> None:
+        if ct.fallback:
+            ct.fallback.accept(self)
+        for argt in ct.arg_types:
+            # argt may be None, e.g. for __self in NamedTuple constructors.
+            if argt is not None:
+                argt.accept(self)
+        if ct.ret_type is not None:
+            ct.ret_type.accept(self)
+        for v in ct.variables:
+            v.accept(self)
+        for arg in ct.bound_args:
+            if arg:
+                arg.accept(self)
+        if ct.type_guard is not None:
+            ct.type_guard.accept(self)
+
+    def visit_overloaded(self, t: Overloaded) -> None:
+        for ct in t.items:
+            ct.accept(self)
+
+    def visit_erased_type(self, o: Any) -> None:
+        # This type should exist only temporarily during type inference
+        raise RuntimeError("Shouldn't get here", o)
+
+    def visit_deleted_type(self, o: Any) -> None:
+        pass  # Nothing to descend into.
+
+    def visit_none_type(self, o: Any) -> None:
+        pass  # Nothing to descend into.
+
+    def visit_uninhabited_type(self, o: Any) -> None:
+        pass  # Nothing to descend into.
+
+    def visit_partial_type(self, o: Any) -> None:
+        raise RuntimeError("Shouldn't get here", o)
+
+    def visit_tuple_type(self, tt: TupleType) -> None:
+        if tt.items:
+            for it in tt.items:
+                it.accept(self)
+        if tt.partial_fallback is not None:
+            tt.partial_fallback.accept(self)
+
+    def visit_typeddict_type(self, tdt: TypedDictType) -> None:
+        if tdt.items:
+            for it in tdt.items.values():
+                it.accept(self)
+        if tdt.fallback is not None:
+            if tdt.fallback.type_ref is not None:
+                if (
+                    lookup_fully_qualified(
+                        tdt.fallback.type_ref,
+                        self.modules,
+                        raise_on_missing=not self.allow_missing,
+                    )
+                    is None
+                ):
+                    # We reject fake TypeInfos for TypedDict fallbacks because
+                    # the latter are used in type checking and must be valid.
+                    tdt.fallback.type_ref = "typing._TypedDict"
+            tdt.fallback.accept(self)
+
+    def visit_literal_type(self, lt: LiteralType) -> None:
+        lt.fallback.accept(self)
+
+    def visit_type_var(self, tvt: TypeVarType) -> None:
+        if tvt.values:
+            for vt in tvt.values:
+                vt.accept(self)
+        tvt.upper_bound.accept(self)
+        tvt.default.accept(self)
+
+    def visit_param_spec(self, p: ParamSpecType) -> None:
+        p.upper_bound.accept(self)
+        p.default.accept(self)
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> None:
+        t.upper_bound.accept(self)
+        t.default.accept(self)
+
+    def visit_unpack_type(self, u: UnpackType) -> None:
+        u.type.accept(self)
+
+    def visit_parameters(self, p: Parameters) -> None:
+        for argt in p.arg_types:
+            if argt is not None:
+                argt.accept(self)
+        for var in p.variables:
+            var.accept(self)
+
+    def visit_unbound_type(self, o: UnboundType) -> None:
+        for a in o.args:
+            a.accept(self)
+
+    def visit_union_type(self, ut: UnionType) -> None:
+        if ut.items:
+            for it in ut.items:
+                it.accept(self)
+
+    def visit_void(self, o: Any) -> None:
+        pass  # Nothing to descend into.
+
+    def visit_type_type(self, t: TypeType) -> None:
+        t.item.accept(self)
+
+
+def lookup_fully_qualified_typeinfo(
+    modules: dict[str, MypyFile], name: str, *, allow_missing: bool
+) -> TypeInfo:
+    stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing)
+    node = stnode.node if stnode else None
+    if isinstance(node, TypeInfo):
+        return node
+    else:
+        # Looks like a missing TypeInfo during an initial daemon load, put something there
+        assert (
+            allow_missing
+        ), "Should never get here in normal mode, got {}:{} instead of TypeInfo".format(
+            type(node).__name__, node.fullname if node else ""
+        )
+        return missing_info(modules)
+
+
+def lookup_fully_qualified_alias(
+    modules: dict[str, MypyFile], name: str, *, allow_missing: bool
+) -> TypeAlias:
+    stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing)
+    node = stnode.node if stnode else None
+    if isinstance(node, TypeAlias):
+        return node
+    elif isinstance(node, TypeInfo):
+        if node.special_alias:
+            # Already fixed up.
+            return node.special_alias
+        if node.tuple_type:
+            alias = TypeAlias.from_tuple_type(node)
+        elif node.typeddict_type:
+            alias = TypeAlias.from_typeddict_type(node)
+        else:
+            assert allow_missing
+            return missing_alias()
+        node.special_alias = alias
+        return alias
+    else:
+        # Looks like a missing TypeAlias during an initial daemon load, put something there
+        assert (
+            allow_missing
+        ), "Should never get here in normal mode, got {}:{} instead of TypeAlias".format(
+            type(node).__name__, node.fullname if node else ""
+        )
+        return missing_alias()
+
+
+_SUGGESTION: Final = "<missing {}: *should* have gone away during fine-grained update>"
+
+
+def missing_info(modules: dict[str, MypyFile]) -> TypeInfo:
+    suggestion = _SUGGESTION.format("info")
+    dummy_def = ClassDef(suggestion, Block([]))
+    dummy_def.fullname = suggestion
+
+    info = TypeInfo(SymbolTable(), dummy_def, "<missing>")
+    obj_type = lookup_fully_qualified_typeinfo(modules, "builtins.object", allow_missing=False)
+    info.bases = [Instance(obj_type, [])]
+    info.mro = [info, obj_type]
+    return info
+
+
+def missing_alias() -> TypeAlias:
+    suggestion = _SUGGESTION.format("alias")
+    return TypeAlias(AnyType(TypeOfAny.special_form), suggestion, line=-1, column=-1)

二進制
venv/lib/python3.11/site-packages/mypy/freetree.cpython-311-x86_64-linux-gnu.so


+ 23 - 0
venv/lib/python3.11/site-packages/mypy/freetree.py

@@ -0,0 +1,23 @@
+"""Generic node traverser visitor"""
+
+from __future__ import annotations
+
+from mypy.nodes import Block, MypyFile
+from mypy.traverser import TraverserVisitor
+
+
+class TreeFreer(TraverserVisitor):
+    def visit_block(self, block: Block) -> None:
+        super().visit_block(block)
+        block.body.clear()
+
+
+def free_tree(tree: MypyFile) -> None:
+    """Free all the ASTs associated with a module.
+
+    This needs to be done recursively, since symbol tables contain
+    references to definitions, so those won't be freed but we want their
+    contents to be.
+    """
+    tree.accept(TreeFreer())
+    tree.defs.clear()

二進制
venv/lib/python3.11/site-packages/mypy/fscache.cpython-311-x86_64-linux-gnu.so


+ 309 - 0
venv/lib/python3.11/site-packages/mypy/fscache.py

@@ -0,0 +1,309 @@
+"""Interface for accessing the file system with automatic caching.
+
+The idea is to cache the results of any file system state reads during
+a single transaction. This has two main benefits:
+
+* This avoids redundant syscalls, as we won't perform the same OS
+  operations multiple times.
+
+* This makes it easier to reason about concurrent FS updates, as different
+  operations targeting the same paths can't report different state during
+  a transaction.
+
+Note that this only deals with reading state, not writing.
+
+Properties maintained by the API:
+
+* The contents of the file are always from the same or later time compared
+  to the reported mtime of the file, even if mtime is queried after reading
+  a file.
+
+* Repeating an operation produces the same result as the first one during
+  a transaction.
+
+* Call flush() to start a new transaction (flush the caches).
+
+The API is a bit limited. It's easy to add new cached operations, however.
+You should perform all file system reads through the API to actually take
+advantage of the benefits.
+"""
+
+from __future__ import annotations
+
+import os
+import stat
+
+from mypy_extensions import mypyc_attr
+
+from mypy.util import hash_digest
+
+
+@mypyc_attr(allow_interpreted_subclasses=True)  # for tests
+class FileSystemCache:
+    def __init__(self) -> None:
+        # The package root is not flushed with the caches.
+        # It is set by set_package_root() below.
+        self.package_root: list[str] = []
+        self.flush()
+
+    def set_package_root(self, package_root: list[str]) -> None:
+        self.package_root = package_root
+
+    def flush(self) -> None:
+        """Start another transaction and empty all caches."""
+        self.stat_cache: dict[str, os.stat_result] = {}
+        self.stat_error_cache: dict[str, OSError] = {}
+        self.listdir_cache: dict[str, list[str]] = {}
+        self.listdir_error_cache: dict[str, OSError] = {}
+        self.isfile_case_cache: dict[str, bool] = {}
+        self.exists_case_cache: dict[str, bool] = {}
+        self.read_cache: dict[str, bytes] = {}
+        self.read_error_cache: dict[str, Exception] = {}
+        self.hash_cache: dict[str, str] = {}
+        self.fake_package_cache: set[str] = set()
+
+    def stat(self, path: str) -> os.stat_result:
+        if path in self.stat_cache:
+            return self.stat_cache[path]
+        if path in self.stat_error_cache:
+            raise copy_os_error(self.stat_error_cache[path])
+        try:
+            st = os.stat(path)
+        except OSError as err:
+            if self.init_under_package_root(path):
+                try:
+                    return self._fake_init(path)
+                except OSError:
+                    pass
+            # Take a copy to get rid of associated traceback and frame objects.
+            # Just assigning to __traceback__ doesn't free them.
+            self.stat_error_cache[path] = copy_os_error(err)
+            raise err
+        self.stat_cache[path] = st
+        return st
+
+    def init_under_package_root(self, path: str) -> bool:
+        """Is this path an __init__.py under a package root?
+
+        This is used to detect packages that don't contain __init__.py
+        files, which is needed to support Bazel.  The function should
+        only be called for non-existing files.
+
+        It will return True if it refers to a __init__.py file that
+        Bazel would create, so that at runtime Python would think the
+        directory containing it is a package.  For this to work you
+        must pass one or more package roots using the --package-root
+        flag.
+
+        As an exceptional case, any directory that is a package root
+        itself will not be considered to contain a __init__.py file.
+        This is different from the rules Bazel itself applies, but is
+        necessary for mypy to properly distinguish packages from other
+        directories.
+
+        See https://docs.bazel.build/versions/master/be/python.html,
+        where this behavior is described under legacy_create_init.
+        """
+        if not self.package_root:
+            return False
+        dirname, basename = os.path.split(path)
+        if basename != "__init__.py":
+            return False
+        if not os.path.basename(dirname).isidentifier():
+            # Can't put an __init__.py in a place that's not an identifier
+            return False
+        try:
+            st = self.stat(dirname)
+        except OSError:
+            return False
+        else:
+            if not stat.S_ISDIR(st.st_mode):
+                return False
+        ok = False
+        drive, path = os.path.splitdrive(path)  # Ignore Windows drive name
+        if os.path.isabs(path):
+            path = os.path.relpath(path)
+        path = os.path.normpath(path)
+        for root in self.package_root:
+            if path.startswith(root):
+                if path == root + basename:
+                    # A package root itself is never a package.
+                    ok = False
+                    break
+                else:
+                    ok = True
+        return ok
+
+    def _fake_init(self, path: str) -> os.stat_result:
+        """Prime the cache with a fake __init__.py file.
+
+        This makes code that looks for path believe an empty file by
+        that name exists.  Should only be called after
+        init_under_package_root() returns True.
+        """
+        dirname, basename = os.path.split(path)
+        assert basename == "__init__.py", path
+        assert not os.path.exists(path), path  # Not cached!
+        dirname = os.path.normpath(dirname)
+        st = self.stat(dirname)  # May raise OSError
+        # Get stat result as a list so we can modify it.
+        seq: list[float] = list(st)
+        seq[stat.ST_MODE] = stat.S_IFREG | 0o444
+        seq[stat.ST_INO] = 1
+        seq[stat.ST_NLINK] = 1
+        seq[stat.ST_SIZE] = 0
+        st = os.stat_result(seq)
+        self.stat_cache[path] = st
+        # Make listdir() and read() also pretend this file exists.
+        self.fake_package_cache.add(dirname)
+        return st
+
+    def listdir(self, path: str) -> list[str]:
+        path = os.path.normpath(path)
+        if path in self.listdir_cache:
+            res = self.listdir_cache[path]
+            # Check the fake cache.
+            if path in self.fake_package_cache and "__init__.py" not in res:
+                res.append("__init__.py")  # Updates the result as well as the cache
+            return res
+        if path in self.listdir_error_cache:
+            raise copy_os_error(self.listdir_error_cache[path])
+        try:
+            results = os.listdir(path)
+        except OSError as err:
+            # Like above, take a copy to reduce memory use.
+            self.listdir_error_cache[path] = copy_os_error(err)
+            raise err
+        self.listdir_cache[path] = results
+        # Check the fake cache.
+        if path in self.fake_package_cache and "__init__.py" not in results:
+            results.append("__init__.py")
+        return results
+
+    def isfile(self, path: str) -> bool:
+        try:
+            st = self.stat(path)
+        except OSError:
+            return False
+        return stat.S_ISREG(st.st_mode)
+
+    def isfile_case(self, path: str, prefix: str) -> bool:
+        """Return whether path exists and is a file.
+
+        On case-insensitive filesystems (like Mac or Windows) this returns
+        False if the case of path's last component does not exactly match
+        the case found in the filesystem.
+
+        We check also the case of other path components up to prefix.
+        For example, if path is 'user-stubs/pack/mod.pyi' and prefix is 'user-stubs',
+        we check that the case of 'pack' and 'mod.py' matches exactly, 'user-stubs' will be
+        case insensitive on case insensitive filesystems.
+
+        The caller must ensure that prefix is a valid file system prefix of path.
+        """
+        if not self.isfile(path):
+            # Fast path
+            return False
+        if path in self.isfile_case_cache:
+            return self.isfile_case_cache[path]
+        head, tail = os.path.split(path)
+        if not tail:
+            self.isfile_case_cache[path] = False
+            return False
+        try:
+            names = self.listdir(head)
+            # This allows one to check file name case sensitively in
+            # case-insensitive filesystems.
+            res = tail in names
+        except OSError:
+            res = False
+        if res:
+            # Also recursively check the other path components in case sensitive way.
+            res = self.exists_case(head, prefix)
+        self.isfile_case_cache[path] = res
+        return res
+
+    def exists_case(self, path: str, prefix: str) -> bool:
+        """Return whether path exists - checking path components in case sensitive
+        fashion, up to prefix.
+        """
+        if path in self.exists_case_cache:
+            return self.exists_case_cache[path]
+        head, tail = os.path.split(path)
+        if not head.startswith(prefix) or not tail:
+            # Only perform the check for paths under prefix.
+            self.exists_case_cache[path] = True
+            return True
+        try:
+            names = self.listdir(head)
+            # This allows one to check file name case sensitively in
+            # case-insensitive filesystems.
+            res = tail in names
+        except OSError:
+            res = False
+        if res:
+            # Also recursively check other path components.
+            res = self.exists_case(head, prefix)
+        self.exists_case_cache[path] = res
+        return res
+
+    def isdir(self, path: str) -> bool:
+        try:
+            st = self.stat(path)
+        except OSError:
+            return False
+        return stat.S_ISDIR(st.st_mode)
+
+    def exists(self, path: str) -> bool:
+        try:
+            self.stat(path)
+        except FileNotFoundError:
+            return False
+        return True
+
+    def read(self, path: str) -> bytes:
+        if path in self.read_cache:
+            return self.read_cache[path]
+        if path in self.read_error_cache:
+            raise self.read_error_cache[path]
+
+        # Need to stat first so that the contents of file are from no
+        # earlier instant than the mtime reported by self.stat().
+        self.stat(path)
+
+        dirname, basename = os.path.split(path)
+        dirname = os.path.normpath(dirname)
+        # Check the fake cache.
+        if basename == "__init__.py" and dirname in self.fake_package_cache:
+            data = b""
+        else:
+            try:
+                with open(path, "rb") as f:
+                    data = f.read()
+            except OSError as err:
+                self.read_error_cache[path] = err
+                raise
+
+        self.read_cache[path] = data
+        self.hash_cache[path] = hash_digest(data)
+        return data
+
+    def hash_digest(self, path: str) -> str:
+        if path not in self.hash_cache:
+            self.read(path)
+        return self.hash_cache[path]
+
+    def samefile(self, f1: str, f2: str) -> bool:
+        s1 = self.stat(f1)
+        s2 = self.stat(f2)
+        return os.path.samestat(s1, s2)
+
+
+def copy_os_error(e: OSError) -> OSError:
+    new = OSError(*e.args)
+    new.errno = e.errno
+    new.strerror = e.strerror
+    new.filename = e.filename
+    if e.filename2:
+        new.filename2 = e.filename2
+    return new

二進制
venv/lib/python3.11/site-packages/mypy/fswatcher.cpython-311-x86_64-linux-gnu.so


+ 106 - 0
venv/lib/python3.11/site-packages/mypy/fswatcher.py

@@ -0,0 +1,106 @@
+"""Watch parts of the file system for changes."""
+
+from __future__ import annotations
+
+from typing import AbstractSet, Iterable, NamedTuple
+
+from mypy.fscache import FileSystemCache
+
+
+class FileData(NamedTuple):
+    st_mtime: float
+    st_size: int
+    hash: str
+
+
+class FileSystemWatcher:
+    """Watcher for file system changes among specific paths.
+
+    All file system access is performed using FileSystemCache. We
+    detect changed files by stat()ing them all and comparing hashes
+    of potentially changed files. If a file has both size and mtime
+    unmodified, the file is assumed to be unchanged.
+
+    An important goal of this class is to make it easier to eventually
+    use file system events to detect file changes.
+
+    Note: This class doesn't flush the file system cache. If you don't
+    manually flush it, changes won't be seen.
+    """
+
+    # TODO: Watching directories?
+    # TODO: Handle non-files
+
+    def __init__(self, fs: FileSystemCache) -> None:
+        self.fs = fs
+        self._paths: set[str] = set()
+        self._file_data: dict[str, FileData | None] = {}
+
+    def dump_file_data(self) -> dict[str, tuple[float, int, str]]:
+        return {k: v for k, v in self._file_data.items() if v is not None}
+
+    def set_file_data(self, path: str, data: FileData) -> None:
+        self._file_data[path] = data
+
+    def add_watched_paths(self, paths: Iterable[str]) -> None:
+        for path in paths:
+            if path not in self._paths:
+                # By storing None this path will get reported as changed by
+                # find_changed if it exists.
+                self._file_data[path] = None
+        self._paths |= set(paths)
+
+    def remove_watched_paths(self, paths: Iterable[str]) -> None:
+        for path in paths:
+            if path in self._file_data:
+                del self._file_data[path]
+        self._paths -= set(paths)
+
+    def _update(self, path: str) -> None:
+        st = self.fs.stat(path)
+        hash_digest = self.fs.hash_digest(path)
+        self._file_data[path] = FileData(st.st_mtime, st.st_size, hash_digest)
+
+    def _find_changed(self, paths: Iterable[str]) -> AbstractSet[str]:
+        changed = set()
+        for path in paths:
+            old = self._file_data[path]
+            try:
+                st = self.fs.stat(path)
+            except FileNotFoundError:
+                if old is not None:
+                    # File was deleted.
+                    changed.add(path)
+                    self._file_data[path] = None
+            else:
+                if old is None:
+                    # File is new.
+                    changed.add(path)
+                    self._update(path)
+                # Round mtimes down, to match the mtimes we write to meta files
+                elif st.st_size != old.st_size or int(st.st_mtime) != int(old.st_mtime):
+                    # Only look for changes if size or mtime has changed as an
+                    # optimization, since calculating hash is expensive.
+                    new_hash = self.fs.hash_digest(path)
+                    self._update(path)
+                    if st.st_size != old.st_size or new_hash != old.hash:
+                        # Changed file.
+                        changed.add(path)
+        return changed
+
+    def find_changed(self) -> AbstractSet[str]:
+        """Return paths that have changes since the last call, in the watched set."""
+        return self._find_changed(self._paths)
+
+    def update_changed(self, remove: list[str], update: list[str]) -> AbstractSet[str]:
+        """Alternative to find_changed() given explicit changes.
+
+        This only calls self.fs.stat() on added or updated files, not
+        on all files.  It believes all other files are unchanged!
+
+        Implies add_watched_paths() for add and update, and
+        remove_watched_paths() for remove.
+        """
+        self.remove_watched_paths(remove)
+        self.add_watched_paths(update)
+        return self._find_changed(update)

二進制
venv/lib/python3.11/site-packages/mypy/gclogger.cpython-311-x86_64-linux-gnu.so


+ 47 - 0
venv/lib/python3.11/site-packages/mypy/gclogger.py

@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+import gc
+import time
+from typing import Mapping
+
+
+class GcLogger:
+    """Context manager to log GC stats and overall time."""
+
+    def __enter__(self) -> GcLogger:
+        self.gc_start_time: float | None = None
+        self.gc_time = 0.0
+        self.gc_calls = 0
+        self.gc_collected = 0
+        self.gc_uncollectable = 0
+        gc.callbacks.append(self.gc_callback)
+        self.start_time = time.time()
+        return self
+
+    def gc_callback(self, phase: str, info: Mapping[str, int]) -> None:
+        if phase == "start":
+            assert self.gc_start_time is None, "Start phase out of sequence"
+            self.gc_start_time = time.time()
+        elif phase == "stop":
+            assert self.gc_start_time is not None, "Stop phase out of sequence"
+            self.gc_calls += 1
+            self.gc_time += time.time() - self.gc_start_time
+            self.gc_start_time = None
+            self.gc_collected += info["collected"]
+            self.gc_uncollectable += info["uncollectable"]
+        else:
+            assert False, f"Unrecognized gc phase ({phase!r})"
+
+    def __exit__(self, *args: object) -> None:
+        while self.gc_callback in gc.callbacks:
+            gc.callbacks.remove(self.gc_callback)
+
+    def get_stats(self) -> Mapping[str, float]:
+        end_time = time.time()
+        result = {}
+        result["gc_time"] = self.gc_time
+        result["gc_calls"] = self.gc_calls
+        result["gc_collected"] = self.gc_collected
+        result["gc_uncollectable"] = self.gc_uncollectable
+        result["build_time"] = end_time - self.start_time
+        return result

二進制
venv/lib/python3.11/site-packages/mypy/git.cpython-311-x86_64-linux-gnu.so


+ 34 - 0
venv/lib/python3.11/site-packages/mypy/git.py

@@ -0,0 +1,34 @@
+"""Git utilities."""
+
+# Used also from setup.py, so don't pull in anything additional here (like mypy or typing):
+from __future__ import annotations
+
+import os
+import subprocess
+
+
+def is_git_repo(dir: str) -> bool:
+    """Is the given directory version-controlled with git?"""
+    return os.path.exists(os.path.join(dir, ".git"))
+
+
+def have_git() -> bool:
+    """Can we run the git executable?"""
+    try:
+        subprocess.check_output(["git", "--help"])
+        return True
+    except subprocess.CalledProcessError:
+        return False
+    except OSError:
+        return False
+
+
+def git_revision(dir: str) -> bytes:
+    """Get the SHA-1 of the HEAD of a git repository."""
+    return subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=dir).strip()
+
+
+def is_dirty(dir: str) -> bool:
+    """Check whether a git repository has uncommitted changes."""
+    output = subprocess.check_output(["git", "status", "-uno", "--porcelain"], cwd=dir)
+    return output.strip() != b""

二進制
venv/lib/python3.11/site-packages/mypy/graph_utils.cpython-311-x86_64-linux-gnu.so


+ 112 - 0
venv/lib/python3.11/site-packages/mypy/graph_utils.py

@@ -0,0 +1,112 @@
+"""Helpers for manipulations with graphs."""
+
+from __future__ import annotations
+
+from typing import AbstractSet, Iterable, Iterator, TypeVar
+
+T = TypeVar("T")
+
+
+def strongly_connected_components(
+    vertices: AbstractSet[T], edges: dict[T, list[T]]
+) -> Iterator[set[T]]:
+    """Compute Strongly Connected Components of a directed graph.
+
+    Args:
+      vertices: the labels for the vertices
+      edges: for each vertex, gives the target vertices of its outgoing edges
+
+    Returns:
+      An iterator yielding strongly connected components, each
+      represented as a set of vertices.  Each input vertex will occur
+      exactly once; vertices not part of a SCC are returned as
+      singleton sets.
+
+    From https://code.activestate.com/recipes/578507/.
+    """
+    identified: set[T] = set()
+    stack: list[T] = []
+    index: dict[T, int] = {}
+    boundaries: list[int] = []
+
+    def dfs(v: T) -> Iterator[set[T]]:
+        index[v] = len(stack)
+        stack.append(v)
+        boundaries.append(index[v])
+
+        for w in edges[v]:
+            if w not in index:
+                yield from dfs(w)
+            elif w not in identified:
+                while index[w] < boundaries[-1]:
+                    boundaries.pop()
+
+        if boundaries[-1] == index[v]:
+            boundaries.pop()
+            scc = set(stack[index[v] :])
+            del stack[index[v] :]
+            identified.update(scc)
+            yield scc
+
+    for v in vertices:
+        if v not in index:
+            yield from dfs(v)
+
+
+def prepare_sccs(
+    sccs: list[set[T]], edges: dict[T, list[T]]
+) -> dict[AbstractSet[T], set[AbstractSet[T]]]:
+    """Use original edges to organize SCCs in a graph by dependencies between them."""
+    sccsmap = {v: frozenset(scc) for scc in sccs for v in scc}
+    data: dict[AbstractSet[T], set[AbstractSet[T]]] = {}
+    for scc in sccs:
+        deps: set[AbstractSet[T]] = set()
+        for v in scc:
+            deps.update(sccsmap[x] for x in edges[v])
+        data[frozenset(scc)] = deps
+    return data
+
+
+def topsort(data: dict[T, set[T]]) -> Iterable[set[T]]:
+    """Topological sort.
+
+    Args:
+      data: A map from vertices to all vertices that it has an edge
+            connecting it to.  NOTE: This data structure
+            is modified in place -- for normalization purposes,
+            self-dependencies are removed and entries representing
+            orphans are added.
+
+    Returns:
+      An iterator yielding sets of vertices that have an equivalent
+      ordering.
+
+    Example:
+      Suppose the input has the following structure:
+
+        {A: {B, C}, B: {D}, C: {D}}
+
+      This is normalized to:
+
+        {A: {B, C}, B: {D}, C: {D}, D: {}}
+
+      The algorithm will yield the following values:
+
+        {D}
+        {B, C}
+        {A}
+
+    From https://code.activestate.com/recipes/577413/.
+    """
+    # TODO: Use a faster algorithm?
+    for k, v in data.items():
+        v.discard(k)  # Ignore self dependencies.
+    for item in set.union(*data.values()) - set(data.keys()):
+        data[item] = set()
+    while True:
+        ready = {item for item, dep in data.items() if not dep}
+        if not ready:
+            break
+        yield ready
+        data = {item: (dep - ready) for item, dep in data.items() if item not in ready}
+    assert not data, f"A cyclic dependency exists amongst {data!r}"

二進制
venv/lib/python3.11/site-packages/mypy/indirection.cpython-311-x86_64-linux-gnu.so


+ 121 - 0
venv/lib/python3.11/site-packages/mypy/indirection.py

@@ -0,0 +1,121 @@
+from __future__ import annotations
+
+from typing import Iterable, Set
+
+import mypy.types as types
+from mypy.types import TypeVisitor
+from mypy.util import split_module_names
+
+
+def extract_module_names(type_name: str | None) -> list[str]:
+    """Returns the module names of a fully qualified type name."""
+    if type_name is not None:
+        # Discard the first one, which is just the qualified name of the type
+        possible_module_names = split_module_names(type_name)
+        return possible_module_names[1:]
+    else:
+        return []
+
+
+class TypeIndirectionVisitor(TypeVisitor[Set[str]]):
+    """Returns all module references within a particular type."""
+
+    def __init__(self) -> None:
+        self.cache: dict[types.Type, set[str]] = {}
+        self.seen_aliases: set[types.TypeAliasType] = set()
+
+    def find_modules(self, typs: Iterable[types.Type]) -> set[str]:
+        self.seen_aliases.clear()
+        return self._visit(typs)
+
+    def _visit(self, typ_or_typs: types.Type | Iterable[types.Type]) -> set[str]:
+        typs = [typ_or_typs] if isinstance(typ_or_typs, types.Type) else typ_or_typs
+        output: set[str] = set()
+        for typ in typs:
+            if isinstance(typ, types.TypeAliasType):
+                # Avoid infinite recursion for recursive type aliases.
+                if typ in self.seen_aliases:
+                    continue
+                self.seen_aliases.add(typ)
+            if typ in self.cache:
+                modules = self.cache[typ]
+            else:
+                modules = typ.accept(self)
+                self.cache[typ] = set(modules)
+            output.update(modules)
+        return output
+
+    def visit_unbound_type(self, t: types.UnboundType) -> set[str]:
+        return self._visit(t.args)
+
+    def visit_any(self, t: types.AnyType) -> set[str]:
+        return set()
+
+    def visit_none_type(self, t: types.NoneType) -> set[str]:
+        return set()
+
+    def visit_uninhabited_type(self, t: types.UninhabitedType) -> set[str]:
+        return set()
+
+    def visit_erased_type(self, t: types.ErasedType) -> set[str]:
+        return set()
+
+    def visit_deleted_type(self, t: types.DeletedType) -> set[str]:
+        return set()
+
+    def visit_type_var(self, t: types.TypeVarType) -> set[str]:
+        return self._visit(t.values) | self._visit(t.upper_bound) | self._visit(t.default)
+
+    def visit_param_spec(self, t: types.ParamSpecType) -> set[str]:
+        return self._visit(t.upper_bound) | self._visit(t.default)
+
+    def visit_type_var_tuple(self, t: types.TypeVarTupleType) -> set[str]:
+        return self._visit(t.upper_bound) | self._visit(t.default)
+
+    def visit_unpack_type(self, t: types.UnpackType) -> set[str]:
+        return t.type.accept(self)
+
+    def visit_parameters(self, t: types.Parameters) -> set[str]:
+        return self._visit(t.arg_types)
+
+    def visit_instance(self, t: types.Instance) -> set[str]:
+        out = self._visit(t.args)
+        if t.type:
+            # Uses of a class depend on everything in the MRO,
+            # as changes to classes in the MRO can add types to methods,
+            # change property types, change the MRO itself, etc.
+            for s in t.type.mro:
+                out.update(split_module_names(s.module_name))
+            if t.type.metaclass_type is not None:
+                out.update(split_module_names(t.type.metaclass_type.type.module_name))
+        return out
+
+    def visit_callable_type(self, t: types.CallableType) -> set[str]:
+        out = self._visit(t.arg_types) | self._visit(t.ret_type)
+        if t.definition is not None:
+            out.update(extract_module_names(t.definition.fullname))
+        return out
+
+    def visit_overloaded(self, t: types.Overloaded) -> set[str]:
+        return self._visit(t.items) | self._visit(t.fallback)
+
+    def visit_tuple_type(self, t: types.TupleType) -> set[str]:
+        return self._visit(t.items) | self._visit(t.partial_fallback)
+
+    def visit_typeddict_type(self, t: types.TypedDictType) -> set[str]:
+        return self._visit(t.items.values()) | self._visit(t.fallback)
+
+    def visit_literal_type(self, t: types.LiteralType) -> set[str]:
+        return self._visit(t.fallback)
+
+    def visit_union_type(self, t: types.UnionType) -> set[str]:
+        return self._visit(t.items)
+
+    def visit_partial_type(self, t: types.PartialType) -> set[str]:
+        return set()
+
+    def visit_type_type(self, t: types.TypeType) -> set[str]:
+        return self._visit(t.item)
+
+    def visit_type_alias_type(self, t: types.TypeAliasType) -> set[str]:
+        return self._visit(types.get_proper_type(t))

二進制
venv/lib/python3.11/site-packages/mypy/infer.cpython-311-x86_64-linux-gnu.so


+ 70 - 0
venv/lib/python3.11/site-packages/mypy/infer.py

@@ -0,0 +1,70 @@
+"""Utilities for type argument inference."""
+
+from __future__ import annotations
+
+from typing import NamedTuple, Sequence
+
+from mypy.constraints import (
+    SUBTYPE_OF,
+    SUPERTYPE_OF,
+    infer_constraints,
+    infer_constraints_for_callable,
+)
+from mypy.nodes import ArgKind
+from mypy.solve import solve_constraints
+from mypy.types import CallableType, Instance, Type, TypeVarId
+
+
+class ArgumentInferContext(NamedTuple):
+    """Type argument inference context.
+
+    We need this because we pass around ``Mapping`` and ``Iterable`` types.
+    These types are only known by ``TypeChecker`` itself.
+    It is required for ``*`` and ``**`` argument inference.
+
+    https://github.com/python/mypy/issues/11144
+    """
+
+    mapping_type: Instance
+    iterable_type: Instance
+
+
+def infer_function_type_arguments(
+    callee_type: CallableType,
+    arg_types: Sequence[Type | None],
+    arg_kinds: list[ArgKind],
+    formal_to_actual: list[list[int]],
+    context: ArgumentInferContext,
+    strict: bool = True,
+    allow_polymorphic: bool = False,
+) -> list[Type | None]:
+    """Infer the type arguments of a generic function.
+
+    Return an array of lower bound types for the type variables -1 (at
+    index 0), -2 (at index 1), etc. A lower bound is None if a value
+    could not be inferred.
+
+    Arguments:
+      callee_type: the target generic function
+      arg_types: argument types at the call site (each optional; if None,
+                 we are not considering this argument in the current pass)
+      arg_kinds: nodes.ARG_* values for arg_types
+      formal_to_actual: mapping from formal to actual variable indices
+    """
+    # Infer constraints.
+    constraints = infer_constraints_for_callable(
+        callee_type, arg_types, arg_kinds, formal_to_actual, context
+    )
+
+    # Solve constraints.
+    type_vars = callee_type.type_var_ids()
+    return solve_constraints(type_vars, constraints, strict, allow_polymorphic)
+
+
+def infer_type_arguments(
+    type_var_ids: list[TypeVarId], template: Type, actual: Type, is_supertype: bool = False
+) -> list[Type | None]:
+    # Like infer_function_type_arguments, but only match a single type
+    # against a generic type.
+    constraints = infer_constraints(template, actual, SUPERTYPE_OF if is_supertype else SUBTYPE_OF)
+    return solve_constraints(type_var_ids, constraints)

二進制
venv/lib/python3.11/site-packages/mypy/inspections.cpython-311-x86_64-linux-gnu.so


+ 625 - 0
venv/lib/python3.11/site-packages/mypy/inspections.py

@@ -0,0 +1,625 @@
+from __future__ import annotations
+
+import os
+from collections import defaultdict
+from functools import cmp_to_key
+from typing import Callable
+
+from mypy.build import State
+from mypy.find_sources import InvalidSourceList, SourceFinder
+from mypy.messages import format_type
+from mypy.modulefinder import PYTHON_EXTENSIONS
+from mypy.nodes import (
+    LDEF,
+    Decorator,
+    Expression,
+    FuncBase,
+    MemberExpr,
+    MypyFile,
+    Node,
+    OverloadedFuncDef,
+    RefExpr,
+    SymbolNode,
+    TypeInfo,
+    Var,
+)
+from mypy.server.update import FineGrainedBuildManager
+from mypy.traverser import ExtendedTraverserVisitor
+from mypy.typeops import tuple_fallback
+from mypy.types import (
+    FunctionLike,
+    Instance,
+    LiteralType,
+    ProperType,
+    TupleType,
+    TypedDictType,
+    TypeVarType,
+    UnionType,
+    get_proper_type,
+)
+from mypy.typevars import fill_typevars_with_any
+
+
+def node_starts_after(o: Node, line: int, column: int) -> bool:
+    return o.line > line or o.line == line and o.column > column
+
+
+def node_ends_before(o: Node, line: int, column: int) -> bool:
+    # Unfortunately, end positions for some statements are a mess,
+    # e.g. overloaded functions, so we return False when we don't know.
+    if o.end_line is not None and o.end_column is not None:
+        if o.end_line < line or o.end_line == line and o.end_column < column:
+            return True
+    return False
+
+
+def expr_span(expr: Expression) -> str:
+    """Format expression span as in mypy error messages."""
+    return f"{expr.line}:{expr.column + 1}:{expr.end_line}:{expr.end_column}"
+
+
+def get_instance_fallback(typ: ProperType) -> list[Instance]:
+    """Returns the Instance fallback for this type if one exists or None."""
+    if isinstance(typ, Instance):
+        return [typ]
+    elif isinstance(typ, TupleType):
+        return [tuple_fallback(typ)]
+    elif isinstance(typ, TypedDictType):
+        return [typ.fallback]
+    elif isinstance(typ, FunctionLike):
+        return [typ.fallback]
+    elif isinstance(typ, LiteralType):
+        return [typ.fallback]
+    elif isinstance(typ, TypeVarType):
+        if typ.values:
+            res = []
+            for t in typ.values:
+                res.extend(get_instance_fallback(get_proper_type(t)))
+            return res
+        return get_instance_fallback(get_proper_type(typ.upper_bound))
+    elif isinstance(typ, UnionType):
+        res = []
+        for t in typ.items:
+            res.extend(get_instance_fallback(get_proper_type(t)))
+        return res
+    return []
+
+
+def find_node(name: str, info: TypeInfo) -> Var | FuncBase | None:
+    """Find the node defining member 'name' in given TypeInfo."""
+    # TODO: this code shares some logic with checkmember.py
+    method = info.get_method(name)
+    if method:
+        if isinstance(method, Decorator):
+            return method.var
+        if method.is_property:
+            assert isinstance(method, OverloadedFuncDef)
+            dec = method.items[0]
+            assert isinstance(dec, Decorator)
+            return dec.var
+        return method
+    else:
+        # don't have such method, maybe variable?
+        node = info.get(name)
+        v = node.node if node else None
+        if isinstance(v, Var):
+            return v
+    return None
+
+
+def find_module_by_fullname(fullname: str, modules: dict[str, State]) -> State | None:
+    """Find module by a node fullname.
+
+    This logic mimics the one we use in fixup, so should be good enough.
+    """
+    head = fullname
+    # Special case: a module symbol is considered to be defined in itself, not in enclosing
+    # package, since this is what users want when clicking go to definition on a module.
+    if head in modules:
+        return modules[head]
+    while True:
+        if "." not in head:
+            return None
+        head, tail = head.rsplit(".", maxsplit=1)
+        mod = modules.get(head)
+        if mod is not None:
+            return mod
+
+
+class SearchVisitor(ExtendedTraverserVisitor):
+    """Visitor looking for an expression whose span matches given one exactly."""
+
+    def __init__(self, line: int, column: int, end_line: int, end_column: int) -> None:
+        self.line = line
+        self.column = column
+        self.end_line = end_line
+        self.end_column = end_column
+        self.result: Expression | None = None
+
+    def visit(self, o: Node) -> bool:
+        if node_starts_after(o, self.line, self.column):
+            return False
+        if node_ends_before(o, self.end_line, self.end_column):
+            return False
+        if (
+            o.line == self.line
+            and o.end_line == self.end_line
+            and o.column == self.column
+            and o.end_column == self.end_column
+        ):
+            if isinstance(o, Expression):
+                self.result = o
+        return self.result is None
+
+
+def find_by_location(
+    tree: MypyFile, line: int, column: int, end_line: int, end_column: int
+) -> Expression | None:
+    """Find an expression matching given span, or None if not found."""
+    if end_line < line:
+        raise ValueError('"end_line" must not be before "line"')
+    if end_line == line and end_column <= column:
+        raise ValueError('"end_column" must be after "column"')
+    visitor = SearchVisitor(line, column, end_line, end_column)
+    tree.accept(visitor)
+    return visitor.result
+
+
+class SearchAllVisitor(ExtendedTraverserVisitor):
+    """Visitor looking for all expressions whose spans enclose given position."""
+
+    def __init__(self, line: int, column: int) -> None:
+        self.line = line
+        self.column = column
+        self.result: list[Expression] = []
+
+    def visit(self, o: Node) -> bool:
+        if node_starts_after(o, self.line, self.column):
+            return False
+        if node_ends_before(o, self.line, self.column):
+            return False
+        if isinstance(o, Expression):
+            self.result.append(o)
+        return True
+
+
+def find_all_by_location(tree: MypyFile, line: int, column: int) -> list[Expression]:
+    """Find all expressions enclosing given position starting from innermost."""
+    visitor = SearchAllVisitor(line, column)
+    tree.accept(visitor)
+    return list(reversed(visitor.result))
+
+
+class InspectionEngine:
+    """Engine for locating and statically inspecting expressions."""
+
+    def __init__(
+        self,
+        fg_manager: FineGrainedBuildManager,
+        *,
+        verbosity: int = 0,
+        limit: int = 0,
+        include_span: bool = False,
+        include_kind: bool = False,
+        include_object_attrs: bool = False,
+        union_attrs: bool = False,
+        force_reload: bool = False,
+    ) -> None:
+        self.fg_manager = fg_manager
+        self.finder = SourceFinder(
+            self.fg_manager.manager.fscache, self.fg_manager.manager.options
+        )
+        self.verbosity = verbosity
+        self.limit = limit
+        self.include_span = include_span
+        self.include_kind = include_kind
+        self.include_object_attrs = include_object_attrs
+        self.union_attrs = union_attrs
+        self.force_reload = force_reload
+        # Module for which inspection was requested.
+        self.module: State | None = None
+
+    def parse_location(self, location: str) -> tuple[str, list[int]]:
+        if location.count(":") not in [2, 4]:
+            raise ValueError("Format should be file:line:column[:end_line:end_column]")
+        parts = location.split(":")
+        module, *rest = parts
+        return module, [int(p) for p in rest]
+
+    def reload_module(self, state: State) -> None:
+        """Reload given module while temporary exporting types."""
+        old = self.fg_manager.manager.options.export_types
+        self.fg_manager.manager.options.export_types = True
+        try:
+            self.fg_manager.flush_cache()
+            assert state.path is not None
+            self.fg_manager.update([(state.id, state.path)], [])
+        finally:
+            self.fg_manager.manager.options.export_types = old
+
+    def expr_type(self, expression: Expression) -> tuple[str, bool]:
+        """Format type for an expression using current options.
+
+        If type is known, second item returned is True. If type is not known, an error
+        message is returned instead, and second item returned is False.
+        """
+        expr_type = self.fg_manager.manager.all_types.get(expression)
+        if expr_type is None:
+            return self.missing_type(expression), False
+
+        type_str = format_type(
+            expr_type, self.fg_manager.manager.options, verbosity=self.verbosity
+        )
+        return self.add_prefixes(type_str, expression), True
+
+    def object_type(self) -> Instance:
+        builtins = self.fg_manager.graph["builtins"].tree
+        assert builtins is not None
+        object_node = builtins.names["object"].node
+        assert isinstance(object_node, TypeInfo)
+        return Instance(object_node, [])
+
+    def collect_attrs(self, instances: list[Instance]) -> dict[TypeInfo, list[str]]:
+        """Collect attributes from all union/typevar variants."""
+
+        def item_attrs(attr_dict: dict[TypeInfo, list[str]]) -> set[str]:
+            attrs = set()
+            for base in attr_dict:
+                attrs |= set(attr_dict[base])
+            return attrs
+
+        def cmp_types(x: TypeInfo, y: TypeInfo) -> int:
+            if x in y.mro:
+                return 1
+            if y in x.mro:
+                return -1
+            return 0
+
+        # First gather all attributes for every union variant.
+        assert instances
+        all_attrs = []
+        for instance in instances:
+            attrs = {}
+            mro = instance.type.mro
+            if not self.include_object_attrs:
+                mro = mro[:-1]
+            for base in mro:
+                attrs[base] = sorted(base.names)
+            all_attrs.append(attrs)
+
+        # Find attributes valid for all variants in a union or type variable.
+        intersection = item_attrs(all_attrs[0])
+        for item in all_attrs[1:]:
+            intersection &= item_attrs(item)
+
+        # Combine attributes from all variants into a single dict while
+        # also removing invalid attributes (unless using --union-attrs).
+        combined_attrs = defaultdict(list)
+        for item in all_attrs:
+            for base in item:
+                if base in combined_attrs:
+                    continue
+                for name in item[base]:
+                    if self.union_attrs or name in intersection:
+                        combined_attrs[base].append(name)
+
+        # Sort bases by MRO, unrelated will appear in the order they appeared as union variants.
+        sorted_bases = sorted(combined_attrs.keys(), key=cmp_to_key(cmp_types))
+        result = {}
+        for base in sorted_bases:
+            if not combined_attrs[base]:
+                # Skip bases where everytihng was filtered out.
+                continue
+            result[base] = combined_attrs[base]
+        return result
+
+    def _fill_from_dict(
+        self, attrs_strs: list[str], attrs_dict: dict[TypeInfo, list[str]]
+    ) -> None:
+        for base in attrs_dict:
+            cls_name = base.name if self.verbosity < 1 else base.fullname
+            attrs = [f'"{attr}"' for attr in attrs_dict[base]]
+            attrs_strs.append(f'"{cls_name}": [{", ".join(attrs)}]')
+
+    def expr_attrs(self, expression: Expression) -> tuple[str, bool]:
+        """Format attributes that are valid for a given expression.
+
+        If expression type is not an Instance, try using fallback. Attributes are
+        returned as a JSON (ordered by MRO) that maps base class name to list of
+        attributes. Attributes may appear in multiple bases if overridden (we simply
+        follow usual mypy logic for creating new Vars etc).
+        """
+        expr_type = self.fg_manager.manager.all_types.get(expression)
+        if expr_type is None:
+            return self.missing_type(expression), False
+
+        expr_type = get_proper_type(expr_type)
+        instances = get_instance_fallback(expr_type)
+        if not instances:
+            # Everything is an object in Python.
+            instances = [self.object_type()]
+
+        attrs_dict = self.collect_attrs(instances)
+
+        # Special case: modules have names apart from those from ModuleType.
+        if isinstance(expression, RefExpr) and isinstance(expression.node, MypyFile):
+            node = expression.node
+            names = sorted(node.names)
+            if "__builtins__" in names:
+                # This is just to make tests stable. No one will really need ths name.
+                names.remove("__builtins__")
+            mod_dict = {f'"<{node.fullname}>"': [f'"{name}"' for name in names]}
+        else:
+            mod_dict = {}
+
+        # Special case: for class callables, prepend with the class attributes.
+        # TODO: also handle cases when such callable appears in a union.
+        if isinstance(expr_type, FunctionLike) and expr_type.is_type_obj():
+            template = fill_typevars_with_any(expr_type.type_object())
+            class_dict = self.collect_attrs(get_instance_fallback(template))
+        else:
+            class_dict = {}
+
+        # We don't use JSON dump to be sure keys order is always preserved.
+        base_attrs = []
+        if mod_dict:
+            for mod in mod_dict:
+                base_attrs.append(f'{mod}: [{", ".join(mod_dict[mod])}]')
+        self._fill_from_dict(base_attrs, class_dict)
+        self._fill_from_dict(base_attrs, attrs_dict)
+        return self.add_prefixes(f'{{{", ".join(base_attrs)}}}', expression), True
+
+    def format_node(self, module: State, node: FuncBase | SymbolNode) -> str:
+        return f"{module.path}:{node.line}:{node.column + 1}:{node.name}"
+
+    def collect_nodes(self, expression: RefExpr) -> list[FuncBase | SymbolNode]:
+        """Collect nodes that can be referred to by an expression.
+
+        Note: it can be more than one for example in case of a union attribute.
+        """
+        node: FuncBase | SymbolNode | None = expression.node
+        nodes: list[FuncBase | SymbolNode]
+        if node is None:
+            # Tricky case: instance attribute
+            if isinstance(expression, MemberExpr) and expression.kind is None:
+                base_type = self.fg_manager.manager.all_types.get(expression.expr)
+                if base_type is None:
+                    return []
+
+                # Now we use the base type to figure out where the attribute is defined.
+                base_type = get_proper_type(base_type)
+                instances = get_instance_fallback(base_type)
+                nodes = []
+                for instance in instances:
+                    node = find_node(expression.name, instance.type)
+                    if node:
+                        nodes.append(node)
+                if not nodes:
+                    # Try checking class namespace if attribute is on a class object.
+                    if isinstance(base_type, FunctionLike) and base_type.is_type_obj():
+                        instances = get_instance_fallback(
+                            fill_typevars_with_any(base_type.type_object())
+                        )
+                        for instance in instances:
+                            node = find_node(expression.name, instance.type)
+                            if node:
+                                nodes.append(node)
+                    else:
+                        # Still no luck, give up.
+                        return []
+            else:
+                return []
+        else:
+            # Easy case: a module-level definition
+            nodes = [node]
+        return nodes
+
+    def modules_for_nodes(
+        self, nodes: list[FuncBase | SymbolNode], expression: RefExpr
+    ) -> tuple[dict[FuncBase | SymbolNode, State], bool]:
+        """Gather modules where given nodes where defined.
+
+        Also check if they need to be refreshed (cached nodes may have
+        lines/columns missing).
+        """
+        modules = {}
+        reload_needed = False
+        for node in nodes:
+            module = find_module_by_fullname(node.fullname, self.fg_manager.graph)
+            if not module:
+                if expression.kind == LDEF and self.module:
+                    module = self.module
+                else:
+                    continue
+            modules[node] = module
+            if not module.tree or module.tree.is_cache_skeleton or self.force_reload:
+                reload_needed |= not module.tree or module.tree.is_cache_skeleton
+                self.reload_module(module)
+        return modules, reload_needed
+
+    def expression_def(self, expression: Expression) -> tuple[str, bool]:
+        """Find and format definition location for an expression.
+
+        If it is not a RefExpr, it is effectively skipped by returning an
+        empty result.
+        """
+        if not isinstance(expression, RefExpr):
+            # If there are no suitable matches at all, we return error later.
+            return "", True
+
+        nodes = self.collect_nodes(expression)
+
+        if not nodes:
+            return self.missing_node(expression), False
+
+        modules, reload_needed = self.modules_for_nodes(nodes, expression)
+        if reload_needed:
+            # TODO: line/column are not stored in cache for vast majority of symbol nodes.
+            # Adding them will make thing faster, but will have visible memory impact.
+            nodes = self.collect_nodes(expression)
+            modules, reload_needed = self.modules_for_nodes(nodes, expression)
+            assert not reload_needed
+
+        result = []
+        for node in modules:
+            result.append(self.format_node(modules[node], node))
+
+        if not result:
+            return self.missing_node(expression), False
+
+        return self.add_prefixes(", ".join(result), expression), True
+
+    def missing_type(self, expression: Expression) -> str:
+        alt_suggestion = ""
+        if not self.force_reload:
+            alt_suggestion = " or try --force-reload"
+        return (
+            f'No known type available for "{type(expression).__name__}"'
+            f" (maybe unreachable{alt_suggestion})"
+        )
+
+    def missing_node(self, expression: Expression) -> str:
+        return (
+            f'Cannot find definition for "{type(expression).__name__}"'
+            f" at {expr_span(expression)}"
+        )
+
+    def add_prefixes(self, result: str, expression: Expression) -> str:
+        prefixes = []
+        if self.include_kind:
+            prefixes.append(f"{type(expression).__name__}")
+        if self.include_span:
+            prefixes.append(expr_span(expression))
+        if prefixes:
+            prefix = ":".join(prefixes) + " -> "
+        else:
+            prefix = ""
+        return prefix + result
+
+    def run_inspection_by_exact_location(
+        self,
+        tree: MypyFile,
+        line: int,
+        column: int,
+        end_line: int,
+        end_column: int,
+        method: Callable[[Expression], tuple[str, bool]],
+    ) -> dict[str, object]:
+        """Get type of an expression matching a span.
+
+        Type or error is returned as a standard daemon response dict.
+        """
+        try:
+            expression = find_by_location(tree, line, column - 1, end_line, end_column)
+        except ValueError as err:
+            return {"error": str(err)}
+
+        if expression is None:
+            span = f"{line}:{column}:{end_line}:{end_column}"
+            return {"out": f"Can't find expression at span {span}", "err": "", "status": 1}
+
+        inspection_str, success = method(expression)
+        return {"out": inspection_str, "err": "", "status": 0 if success else 1}
+
+    def run_inspection_by_position(
+        self,
+        tree: MypyFile,
+        line: int,
+        column: int,
+        method: Callable[[Expression], tuple[str, bool]],
+    ) -> dict[str, object]:
+        """Get types of all expressions enclosing a position.
+
+        Types and/or errors are returned as a standard daemon response dict.
+        """
+        expressions = find_all_by_location(tree, line, column - 1)
+        if not expressions:
+            position = f"{line}:{column}"
+            return {
+                "out": f"Can't find any expressions at position {position}",
+                "err": "",
+                "status": 1,
+            }
+
+        inspection_strs = []
+        status = 0
+        for expression in expressions:
+            inspection_str, success = method(expression)
+            if not success:
+                status = 1
+            if inspection_str:
+                inspection_strs.append(inspection_str)
+        if self.limit:
+            inspection_strs = inspection_strs[: self.limit]
+        return {"out": "\n".join(inspection_strs), "err": "", "status": status}
+
+    def find_module(self, file: str) -> tuple[State | None, dict[str, object]]:
+        """Find module by path, or return a suitable error message.
+
+        Note we don't use exceptions to simplify handling 1 vs 2 statuses.
+        """
+        if not any(file.endswith(ext) for ext in PYTHON_EXTENSIONS):
+            return None, {"error": "Source file is not a Python file"}
+
+        try:
+            module, _ = self.finder.crawl_up(os.path.normpath(file))
+        except InvalidSourceList:
+            return None, {"error": "Invalid source file name: " + file}
+
+        state = self.fg_manager.graph.get(module)
+        self.module = state
+        return (
+            state,
+            {"out": f"Unknown module: {module}", "err": "", "status": 1} if state is None else {},
+        )
+
+    def run_inspection(
+        self, location: str, method: Callable[[Expression], tuple[str, bool]]
+    ) -> dict[str, object]:
+        """Top-level logic to inspect expression(s) at a location.
+
+        This can be re-used by various simple inspections.
+        """
+        try:
+            file, pos = self.parse_location(location)
+        except ValueError as err:
+            return {"error": str(err)}
+
+        state, err_dict = self.find_module(file)
+        if state is None:
+            assert err_dict
+            return err_dict
+
+        # Force reloading to load from cache, account for any edits, etc.
+        if not state.tree or state.tree.is_cache_skeleton or self.force_reload:
+            self.reload_module(state)
+        assert state.tree is not None
+
+        if len(pos) == 4:
+            # Full span, return an exact match only.
+            line, column, end_line, end_column = pos
+            return self.run_inspection_by_exact_location(
+                state.tree, line, column, end_line, end_column, method
+            )
+        assert len(pos) == 2
+        # Inexact location, return all expressions.
+        line, column = pos
+        return self.run_inspection_by_position(state.tree, line, column, method)
+
+    def get_type(self, location: str) -> dict[str, object]:
+        """Get types of expression(s) at a location."""
+        return self.run_inspection(location, self.expr_type)
+
+    def get_attrs(self, location: str) -> dict[str, object]:
+        """Get attributes of expression(s) at a location."""
+        return self.run_inspection(location, self.expr_attrs)
+
+    def get_definition(self, location: str) -> dict[str, object]:
+        """Get symbol definitions of expression(s) at a location."""
+        result = self.run_inspection(location, self.expression_def)
+        if "out" in result and not result["out"]:
+            # None of the expressions found turns out to be a RefExpr.
+            _, location = location.split(":", maxsplit=1)
+            result["out"] = f"No name or member expressions at {location}"
+            result["status"] = 1
+        return result

二進制
venv/lib/python3.11/site-packages/mypy/ipc.cpython-311-x86_64-linux-gnu.so


+ 268 - 0
venv/lib/python3.11/site-packages/mypy/ipc.py

@@ -0,0 +1,268 @@
+"""Cross platform abstractions for inter-process communication
+
+On Unix, this uses AF_UNIX sockets.
+On Windows, this uses NamedPipes.
+"""
+
+from __future__ import annotations
+
+import base64
+import os
+import shutil
+import sys
+import tempfile
+from types import TracebackType
+from typing import Callable, Final
+
+if sys.platform == "win32":
+    # This may be private, but it is needed for IPC on Windows, and is basically stable
+    import ctypes
+
+    import _winapi
+
+    _IPCHandle = int
+
+    kernel32 = ctypes.windll.kernel32
+    DisconnectNamedPipe: Callable[[_IPCHandle], int] = kernel32.DisconnectNamedPipe
+    FlushFileBuffers: Callable[[_IPCHandle], int] = kernel32.FlushFileBuffers
+else:
+    import socket
+
+    _IPCHandle = socket.socket
+
+
+class IPCException(Exception):
+    """Exception for IPC issues."""
+
+
+class IPCBase:
+    """Base class for communication between the dmypy client and server.
+
+    This contains logic shared between the client and server, such as reading
+    and writing.
+    """
+
+    connection: _IPCHandle
+
+    def __init__(self, name: str, timeout: float | None) -> None:
+        self.name = name
+        self.timeout = timeout
+
+    def read(self, size: int = 100000) -> bytes:
+        """Read bytes from an IPC connection until its empty."""
+        bdata = bytearray()
+        if sys.platform == "win32":
+            while True:
+                ov, err = _winapi.ReadFile(self.connection, size, overlapped=True)
+                try:
+                    if err == _winapi.ERROR_IO_PENDING:
+                        timeout = int(self.timeout * 1000) if self.timeout else _winapi.INFINITE
+                        res = _winapi.WaitForSingleObject(ov.event, timeout)
+                        if res != _winapi.WAIT_OBJECT_0:
+                            raise IPCException(f"Bad result from I/O wait: {res}")
+                except BaseException:
+                    ov.cancel()
+                    raise
+                _, err = ov.GetOverlappedResult(True)
+                more = ov.getbuffer()
+                if more:
+                    bdata.extend(more)
+                if err == 0:
+                    # we are done!
+                    break
+                elif err == _winapi.ERROR_MORE_DATA:
+                    # read again
+                    continue
+                elif err == _winapi.ERROR_OPERATION_ABORTED:
+                    raise IPCException("ReadFile operation aborted.")
+        else:
+            while True:
+                more = self.connection.recv(size)
+                if not more:
+                    break
+                bdata.extend(more)
+        return bytes(bdata)
+
+    def write(self, data: bytes) -> None:
+        """Write bytes to an IPC connection."""
+        if sys.platform == "win32":
+            try:
+                ov, err = _winapi.WriteFile(self.connection, data, overlapped=True)
+                try:
+                    if err == _winapi.ERROR_IO_PENDING:
+                        timeout = int(self.timeout * 1000) if self.timeout else _winapi.INFINITE
+                        res = _winapi.WaitForSingleObject(ov.event, timeout)
+                        if res != _winapi.WAIT_OBJECT_0:
+                            raise IPCException(f"Bad result from I/O wait: {res}")
+                    elif err != 0:
+                        raise IPCException(f"Failed writing to pipe with error: {err}")
+                except BaseException:
+                    ov.cancel()
+                    raise
+                bytes_written, err = ov.GetOverlappedResult(True)
+                assert err == 0, err
+                assert bytes_written == len(data)
+            except OSError as e:
+                raise IPCException(f"Failed to write with error: {e.winerror}") from e
+        else:
+            self.connection.sendall(data)
+            self.connection.shutdown(socket.SHUT_WR)
+
+    def close(self) -> None:
+        if sys.platform == "win32":
+            if self.connection != _winapi.NULL:
+                _winapi.CloseHandle(self.connection)
+        else:
+            self.connection.close()
+
+
+class IPCClient(IPCBase):
+    """The client side of an IPC connection."""
+
+    def __init__(self, name: str, timeout: float | None) -> None:
+        super().__init__(name, timeout)
+        if sys.platform == "win32":
+            timeout = int(self.timeout * 1000) if self.timeout else _winapi.NMPWAIT_WAIT_FOREVER
+            try:
+                _winapi.WaitNamedPipe(self.name, timeout)
+            except FileNotFoundError as e:
+                raise IPCException(f"The NamedPipe at {self.name} was not found.") from e
+            except OSError as e:
+                if e.winerror == _winapi.ERROR_SEM_TIMEOUT:
+                    raise IPCException("Timed out waiting for connection.") from e
+                else:
+                    raise
+            try:
+                self.connection = _winapi.CreateFile(
+                    self.name,
+                    _winapi.GENERIC_READ | _winapi.GENERIC_WRITE,
+                    0,
+                    _winapi.NULL,
+                    _winapi.OPEN_EXISTING,
+                    _winapi.FILE_FLAG_OVERLAPPED,
+                    _winapi.NULL,
+                )
+            except OSError as e:
+                if e.winerror == _winapi.ERROR_PIPE_BUSY:
+                    raise IPCException("The connection is busy.") from e
+                else:
+                    raise
+            _winapi.SetNamedPipeHandleState(
+                self.connection, _winapi.PIPE_READMODE_MESSAGE, None, None
+            )
+        else:
+            self.connection = socket.socket(socket.AF_UNIX)
+            self.connection.settimeout(timeout)
+            self.connection.connect(name)
+
+    def __enter__(self) -> IPCClient:
+        return self
+
+    def __exit__(
+        self,
+        exc_ty: type[BaseException] | None = None,
+        exc_val: BaseException | None = None,
+        exc_tb: TracebackType | None = None,
+    ) -> None:
+        self.close()
+
+
+class IPCServer(IPCBase):
+    BUFFER_SIZE: Final = 2**16
+
+    def __init__(self, name: str, timeout: float | None = None) -> None:
+        if sys.platform == "win32":
+            name = r"\\.\pipe\{}-{}.pipe".format(
+                name, base64.urlsafe_b64encode(os.urandom(6)).decode()
+            )
+        else:
+            name = f"{name}.sock"
+        super().__init__(name, timeout)
+        if sys.platform == "win32":
+            self.connection = _winapi.CreateNamedPipe(
+                self.name,
+                _winapi.PIPE_ACCESS_DUPLEX
+                | _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
+                | _winapi.FILE_FLAG_OVERLAPPED,
+                _winapi.PIPE_READMODE_MESSAGE
+                | _winapi.PIPE_TYPE_MESSAGE
+                | _winapi.PIPE_WAIT
+                | 0x8,  # PIPE_REJECT_REMOTE_CLIENTS
+                1,  # one instance
+                self.BUFFER_SIZE,
+                self.BUFFER_SIZE,
+                _winapi.NMPWAIT_WAIT_FOREVER,
+                0,  # Use default security descriptor
+            )
+            if self.connection == -1:  # INVALID_HANDLE_VALUE
+                err = _winapi.GetLastError()
+                raise IPCException(f"Invalid handle to pipe: {err}")
+        else:
+            self.sock_directory = tempfile.mkdtemp()
+            sockfile = os.path.join(self.sock_directory, self.name)
+            self.sock = socket.socket(socket.AF_UNIX)
+            self.sock.bind(sockfile)
+            self.sock.listen(1)
+            if timeout is not None:
+                self.sock.settimeout(timeout)
+
+    def __enter__(self) -> IPCServer:
+        if sys.platform == "win32":
+            # NOTE: It is theoretically possible that this will hang forever if the
+            # client never connects, though this can be "solved" by killing the server
+            try:
+                ov = _winapi.ConnectNamedPipe(self.connection, overlapped=True)
+            except OSError as e:
+                # Don't raise if the client already exists, or the client already connected
+                if e.winerror not in (_winapi.ERROR_PIPE_CONNECTED, _winapi.ERROR_NO_DATA):
+                    raise
+            else:
+                try:
+                    timeout = int(self.timeout * 1000) if self.timeout else _winapi.INFINITE
+                    res = _winapi.WaitForSingleObject(ov.event, timeout)
+                    assert res == _winapi.WAIT_OBJECT_0
+                except BaseException:
+                    ov.cancel()
+                    _winapi.CloseHandle(self.connection)
+                    raise
+                _, err = ov.GetOverlappedResult(True)
+                assert err == 0
+        else:
+            try:
+                self.connection, _ = self.sock.accept()
+            except socket.timeout as e:
+                raise IPCException("The socket timed out") from e
+        return self
+
+    def __exit__(
+        self,
+        exc_ty: type[BaseException] | None = None,
+        exc_val: BaseException | None = None,
+        exc_tb: TracebackType | None = None,
+    ) -> None:
+        if sys.platform == "win32":
+            try:
+                # Wait for the client to finish reading the last write before disconnecting
+                if not FlushFileBuffers(self.connection):
+                    raise IPCException(
+                        "Failed to flush NamedPipe buffer, maybe the client hung up?"
+                    )
+            finally:
+                DisconnectNamedPipe(self.connection)
+        else:
+            self.close()
+
+    def cleanup(self) -> None:
+        if sys.platform == "win32":
+            self.close()
+        else:
+            shutil.rmtree(self.sock_directory)
+
+    @property
+    def connection_name(self) -> str:
+        if sys.platform == "win32":
+            return self.name
+        else:
+            name = self.sock.getsockname()
+            assert isinstance(name, str)
+            return name

二進制
venv/lib/python3.11/site-packages/mypy/join.cpython-311-x86_64-linux-gnu.so


+ 682 - 0
venv/lib/python3.11/site-packages/mypy/join.py

@@ -0,0 +1,682 @@
+"""Calculation of the least upper bound types (joins)."""
+
+from __future__ import annotations
+
+from typing import overload
+
+import mypy.typeops
+from mypy.maptype import map_instance_to_supertype
+from mypy.nodes import CONTRAVARIANT, COVARIANT, INVARIANT
+from mypy.state import state
+from mypy.subtypes import (
+    SubtypeContext,
+    find_member,
+    is_equivalent,
+    is_proper_subtype,
+    is_protocol_implementation,
+    is_subtype,
+)
+from mypy.types import (
+    AnyType,
+    CallableType,
+    DeletedType,
+    ErasedType,
+    FunctionLike,
+    Instance,
+    LiteralType,
+    NoneType,
+    Overloaded,
+    Parameters,
+    ParamSpecType,
+    PartialType,
+    ProperType,
+    TupleType,
+    Type,
+    TypeAliasType,
+    TypedDictType,
+    TypeOfAny,
+    TypeType,
+    TypeVarTupleType,
+    TypeVarType,
+    TypeVisitor,
+    UnboundType,
+    UninhabitedType,
+    UnionType,
+    UnpackType,
+    get_proper_type,
+    get_proper_types,
+)
+
+
+class InstanceJoiner:
+    def __init__(self) -> None:
+        self.seen_instances: list[tuple[Instance, Instance]] = []
+
+    def join_instances(self, t: Instance, s: Instance) -> ProperType:
+        if (t, s) in self.seen_instances or (s, t) in self.seen_instances:
+            return object_from_instance(t)
+
+        self.seen_instances.append((t, s))
+
+        # Calculate the join of two instance types
+        if t.type == s.type:
+            # Simplest case: join two types with the same base type (but
+            # potentially different arguments).
+
+            # Combine type arguments.
+            args: list[Type] = []
+            # N.B: We use zip instead of indexing because the lengths might have
+            # mismatches during daemon reprocessing.
+            for ta, sa, type_var in zip(t.args, s.args, t.type.defn.type_vars):
+                ta_proper = get_proper_type(ta)
+                sa_proper = get_proper_type(sa)
+                new_type: Type | None = None
+                if isinstance(ta_proper, AnyType):
+                    new_type = AnyType(TypeOfAny.from_another_any, ta_proper)
+                elif isinstance(sa_proper, AnyType):
+                    new_type = AnyType(TypeOfAny.from_another_any, sa_proper)
+                elif isinstance(type_var, TypeVarType):
+                    if type_var.variance == COVARIANT:
+                        new_type = join_types(ta, sa, self)
+                        if len(type_var.values) != 0 and new_type not in type_var.values:
+                            self.seen_instances.pop()
+                            return object_from_instance(t)
+                        if not is_subtype(new_type, type_var.upper_bound):
+                            self.seen_instances.pop()
+                            return object_from_instance(t)
+                    # TODO: contravariant case should use meet but pass seen instances as
+                    # an argument to keep track of recursive checks.
+                    elif type_var.variance in (INVARIANT, CONTRAVARIANT):
+                        if not is_equivalent(ta, sa):
+                            self.seen_instances.pop()
+                            return object_from_instance(t)
+                        # If the types are different but equivalent, then an Any is involved
+                        # so using a join in the contravariant case is also OK.
+                        new_type = join_types(ta, sa, self)
+                else:
+                    # ParamSpec type variables behave the same, independent of variance
+                    if not is_equivalent(ta, sa):
+                        return get_proper_type(type_var.upper_bound)
+                    new_type = join_types(ta, sa, self)
+                assert new_type is not None
+                args.append(new_type)
+            result: ProperType = Instance(t.type, args)
+        elif t.type.bases and is_proper_subtype(
+            t, s, subtype_context=SubtypeContext(ignore_type_params=True)
+        ):
+            result = self.join_instances_via_supertype(t, s)
+        else:
+            # Now t is not a subtype of s, and t != s. Now s could be a subtype
+            # of t; alternatively, we need to find a common supertype. This works
+            # in of the both cases.
+            result = self.join_instances_via_supertype(s, t)
+
+        self.seen_instances.pop()
+        return result
+
+    def join_instances_via_supertype(self, t: Instance, s: Instance) -> ProperType:
+        # Give preference to joins via duck typing relationship, so that
+        # join(int, float) == float, for example.
+        for p in t.type._promote:
+            if is_subtype(p, s):
+                return join_types(p, s, self)
+        for p in s.type._promote:
+            if is_subtype(p, t):
+                return join_types(t, p, self)
+
+        # Compute the "best" supertype of t when joined with s.
+        # The definition of "best" may evolve; for now it is the one with
+        # the longest MRO.  Ties are broken by using the earlier base.
+        best: ProperType | None = None
+        for base in t.type.bases:
+            mapped = map_instance_to_supertype(t, base.type)
+            res = self.join_instances(mapped, s)
+            if best is None or is_better(res, best):
+                best = res
+        assert best is not None
+        for promote in t.type._promote:
+            if isinstance(promote, Instance):
+                res = self.join_instances(promote, s)
+                if is_better(res, best):
+                    best = res
+        return best
+
+
+def join_simple(declaration: Type | None, s: Type, t: Type) -> ProperType:
+    """Return a simple least upper bound given the declared type.
+
+    This function should be only used by binder, and should not recurse.
+    For all other uses, use `join_types()`.
+    """
+    declaration = get_proper_type(declaration)
+    s = get_proper_type(s)
+    t = get_proper_type(t)
+
+    if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false):
+        # if types are restricted in different ways, use the more general versions
+        s = mypy.typeops.true_or_false(s)
+        t = mypy.typeops.true_or_false(t)
+
+    if isinstance(s, AnyType):
+        return s
+
+    if isinstance(s, ErasedType):
+        return t
+
+    if is_proper_subtype(s, t, ignore_promotions=True):
+        return t
+
+    if is_proper_subtype(t, s, ignore_promotions=True):
+        return s
+
+    if isinstance(declaration, UnionType):
+        return mypy.typeops.make_simplified_union([s, t])
+
+    if isinstance(s, NoneType) and not isinstance(t, NoneType):
+        s, t = t, s
+
+    if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType):
+        s, t = t, s
+
+    # Meets/joins require callable type normalization.
+    s, t = normalize_callables(s, t)
+
+    if isinstance(s, UnionType) and not isinstance(t, UnionType):
+        s, t = t, s
+
+    value = t.accept(TypeJoinVisitor(s))
+    if declaration is None or is_subtype(value, declaration):
+        return value
+
+    return declaration
+
+
+def trivial_join(s: Type, t: Type) -> Type:
+    """Return one of types (expanded) if it is a supertype of other, otherwise top type."""
+    if is_subtype(s, t):
+        return t
+    elif is_subtype(t, s):
+        return s
+    else:
+        return object_or_any_from_type(get_proper_type(t))
+
+
+@overload
+def join_types(
+    s: ProperType, t: ProperType, instance_joiner: InstanceJoiner | None = None
+) -> ProperType:
+    ...
+
+
+@overload
+def join_types(s: Type, t: Type, instance_joiner: InstanceJoiner | None = None) -> Type:
+    ...
+
+
+def join_types(s: Type, t: Type, instance_joiner: InstanceJoiner | None = None) -> Type:
+    """Return the least upper bound of s and t.
+
+    For example, the join of 'int' and 'object' is 'object'.
+    """
+    if mypy.typeops.is_recursive_pair(s, t):
+        # This case can trigger an infinite recursion, general support for this will be
+        # tricky so we use a trivial join (like for protocols).
+        return trivial_join(s, t)
+    s = get_proper_type(s)
+    t = get_proper_type(t)
+
+    if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false):
+        # if types are restricted in different ways, use the more general versions
+        s = mypy.typeops.true_or_false(s)
+        t = mypy.typeops.true_or_false(t)
+
+    if isinstance(s, UnionType) and not isinstance(t, UnionType):
+        s, t = t, s
+
+    if isinstance(s, AnyType):
+        return s
+
+    if isinstance(s, ErasedType):
+        return t
+
+    if isinstance(s, NoneType) and not isinstance(t, NoneType):
+        s, t = t, s
+
+    if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType):
+        s, t = t, s
+
+    # Meets/joins require callable type normalization.
+    s, t = normalize_callables(s, t)
+
+    # Use a visitor to handle non-trivial cases.
+    return t.accept(TypeJoinVisitor(s, instance_joiner))
+
+
+class TypeJoinVisitor(TypeVisitor[ProperType]):
+    """Implementation of the least upper bound algorithm.
+
+    Attributes:
+      s: The other (left) type operand.
+    """
+
+    def __init__(self, s: ProperType, instance_joiner: InstanceJoiner | None = None) -> None:
+        self.s = s
+        self.instance_joiner = instance_joiner
+
+    def visit_unbound_type(self, t: UnboundType) -> ProperType:
+        return AnyType(TypeOfAny.special_form)
+
+    def visit_union_type(self, t: UnionType) -> ProperType:
+        if is_proper_subtype(self.s, t):
+            return t
+        else:
+            return mypy.typeops.make_simplified_union([self.s, t])
+
+    def visit_any(self, t: AnyType) -> ProperType:
+        return t
+
+    def visit_none_type(self, t: NoneType) -> ProperType:
+        if state.strict_optional:
+            if isinstance(self.s, (NoneType, UninhabitedType)):
+                return t
+            elif isinstance(self.s, UnboundType):
+                return AnyType(TypeOfAny.special_form)
+            else:
+                return mypy.typeops.make_simplified_union([self.s, t])
+        else:
+            return self.s
+
+    def visit_uninhabited_type(self, t: UninhabitedType) -> ProperType:
+        return self.s
+
+    def visit_deleted_type(self, t: DeletedType) -> ProperType:
+        return self.s
+
+    def visit_erased_type(self, t: ErasedType) -> ProperType:
+        return self.s
+
+    def visit_type_var(self, t: TypeVarType) -> ProperType:
+        if isinstance(self.s, TypeVarType) and self.s.id == t.id:
+            return self.s
+        else:
+            return self.default(self.s)
+
+    def visit_param_spec(self, t: ParamSpecType) -> ProperType:
+        if self.s == t:
+            return t
+        return self.default(self.s)
+
+    def visit_type_var_tuple(self, t: TypeVarTupleType) -> ProperType:
+        if self.s == t:
+            return t
+        return self.default(self.s)
+
+    def visit_unpack_type(self, t: UnpackType) -> UnpackType:
+        raise NotImplementedError
+
+    def visit_parameters(self, t: Parameters) -> ProperType:
+        if self.s == t:
+            return t
+        else:
+            return self.default(self.s)
+
+    def visit_instance(self, t: Instance) -> ProperType:
+        if isinstance(self.s, Instance):
+            if self.instance_joiner is None:
+                self.instance_joiner = InstanceJoiner()
+            nominal = self.instance_joiner.join_instances(t, self.s)
+            structural: Instance | None = None
+            if t.type.is_protocol and is_protocol_implementation(self.s, t):
+                structural = t
+            elif self.s.type.is_protocol and is_protocol_implementation(t, self.s):
+                structural = self.s
+            # Structural join is preferred in the case where we have found both
+            # structural and nominal and they have same MRO length (see two comments
+            # in join_instances_via_supertype). Otherwise, just return the nominal join.
+            if not structural or is_better(nominal, structural):
+                return nominal
+            return structural
+        elif isinstance(self.s, FunctionLike):
+            if t.type.is_protocol:
+                call = unpack_callback_protocol(t)
+                if call:
+                    return join_types(call, self.s)
+            return join_types(t, self.s.fallback)
+        elif isinstance(self.s, TypeType):
+            return join_types(t, self.s)
+        elif isinstance(self.s, TypedDictType):
+            return join_types(t, self.s)
+        elif isinstance(self.s, TupleType):
+            return join_types(t, self.s)
+        elif isinstance(self.s, LiteralType):
+            return join_types(t, self.s)
+        else:
+            return self.default(self.s)
+
+    def visit_callable_type(self, t: CallableType) -> ProperType:
+        if isinstance(self.s, CallableType) and is_similar_callables(t, self.s):
+            if is_equivalent(t, self.s):
+                return combine_similar_callables(t, self.s)
+            result = join_similar_callables(t, self.s)
+            # We set the from_type_type flag to suppress error when a collection of
+            # concrete class objects gets inferred as their common abstract superclass.
+            if not (
+                (t.is_type_obj() and t.type_object().is_abstract)
+                or (self.s.is_type_obj() and self.s.type_object().is_abstract)
+            ):
+                result.from_type_type = True
+            if any(
+                isinstance(tp, (NoneType, UninhabitedType))
+                for tp in get_proper_types(result.arg_types)
+            ):
+                # We don't want to return unusable Callable, attempt fallback instead.
+                return join_types(t.fallback, self.s)
+            return result
+        elif isinstance(self.s, Overloaded):
+            # Switch the order of arguments to that we'll get to visit_overloaded.
+            return join_types(t, self.s)
+        elif isinstance(self.s, Instance) and self.s.type.is_protocol:
+            call = unpack_callback_protocol(self.s)
+            if call:
+                return join_types(t, call)
+        return join_types(t.fallback, self.s)
+
+    def visit_overloaded(self, t: Overloaded) -> ProperType:
+        # This is more complex than most other cases. Here are some
+        # examples that illustrate how this works.
+        #
+        # First let's define a concise notation:
+        #  - Cn are callable types (for n in 1, 2, ...)
+        #  - Ov(C1, C2, ...) is an overloaded type with items C1, C2, ...
+        #  - Callable[[T, ...], S] is written as [T, ...] -> S.
+        #
+        # We want some basic properties to hold (assume Cn are all
+        # unrelated via Any-similarity):
+        #
+        #   join(Ov(C1, C2), C1) == C1
+        #   join(Ov(C1, C2), Ov(C1, C2)) == Ov(C1, C2)
+        #   join(Ov(C1, C2), Ov(C1, C3)) == C1
+        #   join(Ov(C2, C2), C3) == join of fallback types
+        #
+        # The presence of Any types makes things more interesting. The join is the
+        # most general type we can get with respect to Any:
+        #
+        #   join(Ov([int] -> int, [str] -> str), [Any] -> str) == Any -> str
+        #
+        # We could use a simplification step that removes redundancies, but that's not
+        # implemented right now. Consider this example, where we get a redundancy:
+        #
+        #   join(Ov([int, Any] -> Any, [str, Any] -> Any), [Any, int] -> Any) ==
+        #       Ov([Any, int] -> Any, [Any, int] -> Any)
+        #
+        # TODO: Consider more cases of callable subtyping.
+        result: list[CallableType] = []
+        s = self.s
+        if isinstance(s, FunctionLike):
+            # The interesting case where both types are function types.
+            for t_item in t.items:
+                for s_item in s.items:
+                    if is_similar_callables(t_item, s_item):
+                        if is_equivalent(t_item, s_item):
+                            result.append(combine_similar_callables(t_item, s_item))
+                        elif is_subtype(t_item, s_item):
+                            result.append(s_item)
+            if result:
+                # TODO: Simplify redundancies from the result.
+                if len(result) == 1:
+                    return result[0]
+                else:
+                    return Overloaded(result)
+            return join_types(t.fallback, s.fallback)
+        elif isinstance(s, Instance) and s.type.is_protocol:
+            call = unpack_callback_protocol(s)
+            if call:
+                return join_types(t, call)
+        return join_types(t.fallback, s)
+
+    def visit_tuple_type(self, t: TupleType) -> ProperType:
+        # When given two fixed-length tuples:
+        # * If they have the same length, join their subtypes item-wise:
+        #   Tuple[int, bool] + Tuple[bool, bool] becomes Tuple[int, bool]
+        # * If lengths do not match, return a variadic tuple:
+        #   Tuple[bool, int] + Tuple[bool] becomes Tuple[int, ...]
+        #
+        # Otherwise, `t` is a fixed-length tuple but `self.s` is NOT:
+        # * Joining with a variadic tuple returns variadic tuple:
+        #   Tuple[int, bool] + Tuple[bool, ...] becomes Tuple[int, ...]
+        # * Joining with any Sequence also returns a Sequence:
+        #   Tuple[int, bool] + List[bool] becomes Sequence[int]
+        if isinstance(self.s, TupleType) and self.s.length() == t.length():
+            if self.instance_joiner is None:
+                self.instance_joiner = InstanceJoiner()
+            fallback = self.instance_joiner.join_instances(
+                mypy.typeops.tuple_fallback(self.s), mypy.typeops.tuple_fallback(t)
+            )
+            assert isinstance(fallback, Instance)
+            if self.s.length() == t.length():
+                items: list[Type] = []
+                for i in range(t.length()):
+                    items.append(join_types(t.items[i], self.s.items[i]))
+                return TupleType(items, fallback)
+            else:
+                return fallback
+        else:
+            return join_types(self.s, mypy.typeops.tuple_fallback(t))
+
+    def visit_typeddict_type(self, t: TypedDictType) -> ProperType:
+        if isinstance(self.s, TypedDictType):
+            items = {
+                item_name: s_item_type
+                for (item_name, s_item_type, t_item_type) in self.s.zip(t)
+                if (
+                    is_equivalent(s_item_type, t_item_type)
+                    and (item_name in t.required_keys) == (item_name in self.s.required_keys)
+                )
+            }
+            fallback = self.s.create_anonymous_fallback()
+            # We need to filter by items.keys() since some required keys present in both t and
+            # self.s might be missing from the join if the types are incompatible.
+            required_keys = set(items.keys()) & t.required_keys & self.s.required_keys
+            return TypedDictType(items, required_keys, fallback)
+        elif isinstance(self.s, Instance):
+            return join_types(self.s, t.fallback)
+        else:
+            return self.default(self.s)
+
+    def visit_literal_type(self, t: LiteralType) -> ProperType:
+        if isinstance(self.s, LiteralType):
+            if t == self.s:
+                return t
+            if self.s.fallback.type.is_enum and t.fallback.type.is_enum:
+                return mypy.typeops.make_simplified_union([self.s, t])
+            return join_types(self.s.fallback, t.fallback)
+        else:
+            return join_types(self.s, t.fallback)
+
+    def visit_partial_type(self, t: PartialType) -> ProperType:
+        # We only have partial information so we can't decide the join result. We should
+        # never get here.
+        assert False, "Internal error"
+
+    def visit_type_type(self, t: TypeType) -> ProperType:
+        if isinstance(self.s, TypeType):
+            return TypeType.make_normalized(join_types(t.item, self.s.item), line=t.line)
+        elif isinstance(self.s, Instance) and self.s.type.fullname == "builtins.type":
+            return self.s
+        else:
+            return self.default(self.s)
+
+    def visit_type_alias_type(self, t: TypeAliasType) -> ProperType:
+        assert False, f"This should be never called, got {t}"
+
+    def default(self, typ: Type) -> ProperType:
+        typ = get_proper_type(typ)
+        if isinstance(typ, Instance):
+            return object_from_instance(typ)
+        elif isinstance(typ, UnboundType):
+            return AnyType(TypeOfAny.special_form)
+        elif isinstance(typ, TupleType):
+            return self.default(mypy.typeops.tuple_fallback(typ))
+        elif isinstance(typ, TypedDictType):
+            return self.default(typ.fallback)
+        elif isinstance(typ, FunctionLike):
+            return self.default(typ.fallback)
+        elif isinstance(typ, TypeVarType):
+            return self.default(typ.upper_bound)
+        elif isinstance(typ, ParamSpecType):
+            return self.default(typ.upper_bound)
+        else:
+            return AnyType(TypeOfAny.special_form)
+
+
+def is_better(t: Type, s: Type) -> bool:
+    # Given two possible results from join_instances_via_supertype(),
+    # indicate whether t is the better one.
+    t = get_proper_type(t)
+    s = get_proper_type(s)
+
+    if isinstance(t, Instance):
+        if not isinstance(s, Instance):
+            return True
+        # Use len(mro) as a proxy for the better choice.
+        if len(t.type.mro) > len(s.type.mro):
+            return True
+    return False
+
+
+def normalize_callables(s: ProperType, t: ProperType) -> tuple[ProperType, ProperType]:
+    if isinstance(s, (CallableType, Overloaded)):
+        s = s.with_unpacked_kwargs()
+    if isinstance(t, (CallableType, Overloaded)):
+        t = t.with_unpacked_kwargs()
+    return s, t
+
+
+def is_similar_callables(t: CallableType, s: CallableType) -> bool:
+    """Return True if t and s have identical numbers of
+    arguments, default arguments and varargs.
+    """
+    return (
+        len(t.arg_types) == len(s.arg_types)
+        and t.min_args == s.min_args
+        and t.is_var_arg == s.is_var_arg
+    )
+
+
+def join_similar_callables(t: CallableType, s: CallableType) -> CallableType:
+    from mypy.meet import meet_types
+
+    arg_types: list[Type] = []
+    for i in range(len(t.arg_types)):
+        arg_types.append(meet_types(t.arg_types[i], s.arg_types[i]))
+    # TODO in combine_similar_callables also applies here (names and kinds; user metaclasses)
+    # The fallback type can be either 'function', 'type', or some user-provided metaclass.
+    # The result should always use 'function' as a fallback if either operands are using it.
+    if t.fallback.type.fullname == "builtins.function":
+        fallback = t.fallback
+    else:
+        fallback = s.fallback
+    return t.copy_modified(
+        arg_types=arg_types,
+        arg_names=combine_arg_names(t, s),
+        ret_type=join_types(t.ret_type, s.ret_type),
+        fallback=fallback,
+        name=None,
+    )
+
+
+def combine_similar_callables(t: CallableType, s: CallableType) -> CallableType:
+    arg_types: list[Type] = []
+    for i in range(len(t.arg_types)):
+        arg_types.append(join_types(t.arg_types[i], s.arg_types[i]))
+    # TODO kinds and argument names
+    # TODO what should happen if one fallback is 'type' and the other is a user-provided metaclass?
+    # The fallback type can be either 'function', 'type', or some user-provided metaclass.
+    # The result should always use 'function' as a fallback if either operands are using it.
+    if t.fallback.type.fullname == "builtins.function":
+        fallback = t.fallback
+    else:
+        fallback = s.fallback
+    return t.copy_modified(
+        arg_types=arg_types,
+        arg_names=combine_arg_names(t, s),
+        ret_type=join_types(t.ret_type, s.ret_type),
+        fallback=fallback,
+        name=None,
+    )
+
+
+def combine_arg_names(t: CallableType, s: CallableType) -> list[str | None]:
+    """Produces a list of argument names compatible with both callables.
+
+    For example, suppose 't' and 's' have the following signatures:
+
+    - t: (a: int, b: str, X: str) -> None
+    - s: (a: int, b: str, Y: str) -> None
+
+    This function would return ["a", "b", None]. This information
+    is then used above to compute the join of t and s, which results
+    in a signature of (a: int, b: str, str) -> None.
+
+    Note that the third argument's name is omitted and 't' and 's'
+    are both valid subtypes of this inferred signature.
+
+    Precondition: is_similar_types(t, s) is true.
+    """
+    num_args = len(t.arg_types)
+    new_names = []
+    for i in range(num_args):
+        t_name = t.arg_names[i]
+        s_name = s.arg_names[i]
+        if t_name == s_name or t.arg_kinds[i].is_named() or s.arg_kinds[i].is_named():
+            new_names.append(t_name)
+        else:
+            new_names.append(None)
+    return new_names
+
+
+def object_from_instance(instance: Instance) -> Instance:
+    """Construct the type 'builtins.object' from an instance type."""
+    # Use the fact that 'object' is always the last class in the mro.
+    res = Instance(instance.type.mro[-1], [])
+    return res
+
+
+def object_or_any_from_type(typ: ProperType) -> ProperType:
+    # Similar to object_from_instance() but tries hard for all types.
+    # TODO: find a better way to get object, or make this more reliable.
+    if isinstance(typ, Instance):
+        return object_from_instance(typ)
+    elif isinstance(typ, (CallableType, TypedDictType, LiteralType)):
+        return object_from_instance(typ.fallback)
+    elif isinstance(typ, TupleType):
+        return object_from_instance(typ.partial_fallback)
+    elif isinstance(typ, TypeType):
+        return object_or_any_from_type(typ.item)
+    elif isinstance(typ, TypeVarType) and isinstance(typ.upper_bound, ProperType):
+        return object_or_any_from_type(typ.upper_bound)
+    elif isinstance(typ, UnionType):
+        for item in typ.items:
+            if isinstance(item, ProperType):
+                candidate = object_or_any_from_type(item)
+                if isinstance(candidate, Instance):
+                    return candidate
+    return AnyType(TypeOfAny.implementation_artifact)
+
+
+def join_type_list(types: list[Type]) -> Type:
+    if not types:
+        # This is a little arbitrary but reasonable. Any empty tuple should be compatible
+        # with all variable length tuples, and this makes it possible.
+        return UninhabitedType()
+    joined = types[0]
+    for t in types[1:]:
+        joined = join_types(joined, t)
+    return joined
+
+
+def unpack_callback_protocol(t: Instance) -> ProperType | None:
+    assert t.type.is_protocol
+    if t.type.protocol_members == ["__call__"]:
+        return get_proper_type(find_member("__call__", t, t, is_operator=True))
+    return None

二進制
venv/lib/python3.11/site-packages/mypy/literals.cpython-311-x86_64-linux-gnu.so


+ 306 - 0
venv/lib/python3.11/site-packages/mypy/literals.py

@@ -0,0 +1,306 @@
+from __future__ import annotations
+
+from typing import Any, Final, Iterable, Optional, Tuple
+from typing_extensions import TypeAlias as _TypeAlias
+
+from mypy.nodes import (
+    LITERAL_NO,
+    LITERAL_TYPE,
+    LITERAL_YES,
+    AssertTypeExpr,
+    AssignmentExpr,
+    AwaitExpr,
+    BytesExpr,
+    CallExpr,
+    CastExpr,
+    ComparisonExpr,
+    ComplexExpr,
+    ConditionalExpr,
+    DictExpr,
+    DictionaryComprehension,
+    EllipsisExpr,
+    EnumCallExpr,
+    Expression,
+    FloatExpr,
+    GeneratorExpr,
+    IndexExpr,
+    IntExpr,
+    LambdaExpr,
+    ListComprehension,
+    ListExpr,
+    MemberExpr,
+    NamedTupleExpr,
+    NameExpr,
+    NewTypeExpr,
+    OpExpr,
+    ParamSpecExpr,
+    PromoteExpr,
+    RevealExpr,
+    SetComprehension,
+    SetExpr,
+    SliceExpr,
+    StarExpr,
+    StrExpr,
+    SuperExpr,
+    TempNode,
+    TupleExpr,
+    TypeAliasExpr,
+    TypeApplication,
+    TypedDictExpr,
+    TypeVarExpr,
+    TypeVarTupleExpr,
+    UnaryExpr,
+    Var,
+    YieldExpr,
+    YieldFromExpr,
+)
+from mypy.visitor import ExpressionVisitor
+
+# [Note Literals and literal_hash]
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Mypy uses the term "literal" to refer to any expression built out of
+# the following:
+#
+# * Plain literal expressions, like `1` (integer, float, string, etc.)
+#
+# * Compound literal expressions, like `(lit1, lit2)` (list, dict,
+#   set, or tuple)
+#
+# * Operator expressions, like `lit1 + lit2`
+#
+# * Variable references, like `x`
+#
+# * Member references, like `lit.m`
+#
+# * Index expressions, like `lit[0]`
+#
+# A typical "literal" looks like `x[(i,j+1)].m`.
+#
+# An expression that is a literal has a `literal_hash`, with the
+# following properties.
+#
+# * `literal_hash` is a Key: a tuple containing basic data types and
+#   possibly other Keys. So it can be used as a key in a dictionary
+#   that will be compared by value (as opposed to the Node itself,
+#   which is compared by identity).
+#
+# * Two expressions have equal `literal_hash`es if and only if they
+#   are syntactically equal expressions. (NB: Actually, we also
+#   identify as equal expressions like `3` and `3.0`; is this a good
+#   idea?)
+#
+# * The elements of `literal_hash` that are tuples are exactly the
+#   subexpressions of the original expression (e.g. the base and index
+#   of an index expression, or the operands of an operator expression).
+
+
+def literal(e: Expression) -> int:
+    if isinstance(e, ComparisonExpr):
+        return min(literal(o) for o in e.operands)
+
+    elif isinstance(e, OpExpr):
+        return min(literal(e.left), literal(e.right))
+
+    elif isinstance(e, (MemberExpr, UnaryExpr, StarExpr)):
+        return literal(e.expr)
+
+    elif isinstance(e, AssignmentExpr):
+        return literal(e.target)
+
+    elif isinstance(e, IndexExpr):
+        if literal(e.index) == LITERAL_YES:
+            return literal(e.base)
+        else:
+            return LITERAL_NO
+
+    elif isinstance(e, NameExpr):
+        if isinstance(e.node, Var) and e.node.is_final and e.node.final_value is not None:
+            return LITERAL_YES
+        return LITERAL_TYPE
+
+    if isinstance(e, (IntExpr, FloatExpr, ComplexExpr, StrExpr, BytesExpr)):
+        return LITERAL_YES
+
+    if literal_hash(e):
+        return LITERAL_YES
+
+    return LITERAL_NO
+
+
+Key: _TypeAlias = Tuple[Any, ...]
+
+
+def subkeys(key: Key) -> Iterable[Key]:
+    return [elt for elt in key if isinstance(elt, tuple)]
+
+
+def literal_hash(e: Expression) -> Key | None:
+    return e.accept(_hasher)
+
+
+def extract_var_from_literal_hash(key: Key) -> Var | None:
+    """If key refers to a Var node, return it.
+
+    Return None otherwise.
+    """
+    if len(key) == 2 and key[0] == "Var" and isinstance(key[1], Var):
+        return key[1]
+    return None
+
+
+class _Hasher(ExpressionVisitor[Optional[Key]]):
+    def visit_int_expr(self, e: IntExpr) -> Key:
+        return ("Literal", e.value)
+
+    def visit_str_expr(self, e: StrExpr) -> Key:
+        return ("Literal", e.value)
+
+    def visit_bytes_expr(self, e: BytesExpr) -> Key:
+        return ("Literal", e.value)
+
+    def visit_float_expr(self, e: FloatExpr) -> Key:
+        return ("Literal", e.value)
+
+    def visit_complex_expr(self, e: ComplexExpr) -> Key:
+        return ("Literal", e.value)
+
+    def visit_star_expr(self, e: StarExpr) -> Key:
+        return ("Star", literal_hash(e.expr))
+
+    def visit_name_expr(self, e: NameExpr) -> Key:
+        if isinstance(e.node, Var) and e.node.is_final and e.node.final_value is not None:
+            return ("Literal", e.node.final_value)
+        # N.B: We use the node itself as the key, and not the name,
+        # because using the name causes issues when there is shadowing
+        # (for example, in list comprehensions).
+        return ("Var", e.node)
+
+    def visit_member_expr(self, e: MemberExpr) -> Key:
+        return ("Member", literal_hash(e.expr), e.name)
+
+    def visit_op_expr(self, e: OpExpr) -> Key:
+        return ("Binary", e.op, literal_hash(e.left), literal_hash(e.right))
+
+    def visit_comparison_expr(self, e: ComparisonExpr) -> Key:
+        rest: tuple[str | Key | None, ...] = tuple(e.operators)
+        rest += tuple(literal_hash(o) for o in e.operands)
+        return ("Comparison",) + rest
+
+    def visit_unary_expr(self, e: UnaryExpr) -> Key:
+        return ("Unary", e.op, literal_hash(e.expr))
+
+    def seq_expr(self, e: ListExpr | TupleExpr | SetExpr, name: str) -> Key | None:
+        if all(literal(x) == LITERAL_YES for x in e.items):
+            rest: tuple[Key | None, ...] = tuple(literal_hash(x) for x in e.items)
+            return (name,) + rest
+        return None
+
+    def visit_list_expr(self, e: ListExpr) -> Key | None:
+        return self.seq_expr(e, "List")
+
+    def visit_dict_expr(self, e: DictExpr) -> Key | None:
+        if all(a and literal(a) == literal(b) == LITERAL_YES for a, b in e.items):
+            rest: tuple[Key | None, ...] = tuple(
+                (literal_hash(a) if a else None, literal_hash(b)) for a, b in e.items
+            )
+            return ("Dict",) + rest
+        return None
+
+    def visit_tuple_expr(self, e: TupleExpr) -> Key | None:
+        return self.seq_expr(e, "Tuple")
+
+    def visit_set_expr(self, e: SetExpr) -> Key | None:
+        return self.seq_expr(e, "Set")
+
+    def visit_index_expr(self, e: IndexExpr) -> Key | None:
+        if literal(e.index) == LITERAL_YES:
+            return ("Index", literal_hash(e.base), literal_hash(e.index))
+        return None
+
+    def visit_assignment_expr(self, e: AssignmentExpr) -> Key | None:
+        return literal_hash(e.target)
+
+    def visit_call_expr(self, e: CallExpr) -> None:
+        return None
+
+    def visit_slice_expr(self, e: SliceExpr) -> None:
+        return None
+
+    def visit_cast_expr(self, e: CastExpr) -> None:
+        return None
+
+    def visit_assert_type_expr(self, e: AssertTypeExpr) -> None:
+        return None
+
+    def visit_conditional_expr(self, e: ConditionalExpr) -> None:
+        return None
+
+    def visit_ellipsis(self, e: EllipsisExpr) -> None:
+        return None
+
+    def visit_yield_from_expr(self, e: YieldFromExpr) -> None:
+        return None
+
+    def visit_yield_expr(self, e: YieldExpr) -> None:
+        return None
+
+    def visit_reveal_expr(self, e: RevealExpr) -> None:
+        return None
+
+    def visit_super_expr(self, e: SuperExpr) -> None:
+        return None
+
+    def visit_type_application(self, e: TypeApplication) -> None:
+        return None
+
+    def visit_lambda_expr(self, e: LambdaExpr) -> None:
+        return None
+
+    def visit_list_comprehension(self, e: ListComprehension) -> None:
+        return None
+
+    def visit_set_comprehension(self, e: SetComprehension) -> None:
+        return None
+
+    def visit_dictionary_comprehension(self, e: DictionaryComprehension) -> None:
+        return None
+
+    def visit_generator_expr(self, e: GeneratorExpr) -> None:
+        return None
+
+    def visit_type_var_expr(self, e: TypeVarExpr) -> None:
+        return None
+
+    def visit_paramspec_expr(self, e: ParamSpecExpr) -> None:
+        return None
+
+    def visit_type_var_tuple_expr(self, e: TypeVarTupleExpr) -> None:
+        return None
+
+    def visit_type_alias_expr(self, e: TypeAliasExpr) -> None:
+        return None
+
+    def visit_namedtuple_expr(self, e: NamedTupleExpr) -> None:
+        return None
+
+    def visit_enum_call_expr(self, e: EnumCallExpr) -> None:
+        return None
+
+    def visit_typeddict_expr(self, e: TypedDictExpr) -> None:
+        return None
+
+    def visit_newtype_expr(self, e: NewTypeExpr) -> None:
+        return None
+
+    def visit__promote_expr(self, e: PromoteExpr) -> None:
+        return None
+
+    def visit_await_expr(self, e: AwaitExpr) -> None:
+        return None
+
+    def visit_temp_node(self, e: TempNode) -> None:
+        return None
+
+
+_hasher: Final = _Hasher()

二進制
venv/lib/python3.11/site-packages/mypy/lookup.cpython-311-x86_64-linux-gnu.so


+ 61 - 0
venv/lib/python3.11/site-packages/mypy/lookup.py

@@ -0,0 +1,61 @@
+"""
+This is a module for various lookup functions:
+functions that will find a semantic node by its name.
+"""
+
+from __future__ import annotations
+
+from mypy.nodes import MypyFile, SymbolTableNode, TypeInfo
+
+# TODO: gradually move existing lookup functions to this module.
+
+
+def lookup_fully_qualified(
+    name: str, modules: dict[str, MypyFile], *, raise_on_missing: bool = False
+) -> SymbolTableNode | None:
+    """Find a symbol using it fully qualified name.
+
+    The algorithm has two steps: first we try splitting the name on '.' to find
+    the module, then iteratively look for each next chunk after a '.' (e.g. for
+    nested classes).
+
+    This function should *not* be used to find a module. Those should be looked
+    in the modules dictionary.
+    """
+    head = name
+    rest = []
+    # 1. Find a module tree in modules dictionary.
+    while True:
+        if "." not in head:
+            if raise_on_missing:
+                assert "." in head, f"Cannot find module for {name}"
+            return None
+        head, tail = head.rsplit(".", maxsplit=1)
+        rest.append(tail)
+        mod = modules.get(head)
+        if mod is not None:
+            break
+    names = mod.names
+    # 2. Find the symbol in the module tree.
+    if not rest:
+        # Looks like a module, don't use this to avoid confusions.
+        if raise_on_missing:
+            assert rest, f"Cannot find {name}, got a module symbol"
+        return None
+    while True:
+        key = rest.pop()
+        if key not in names:
+            if raise_on_missing:
+                assert key in names, f"Cannot find component {key!r} for {name!r}"
+            return None
+        stnode = names[key]
+        if not rest:
+            return stnode
+        node = stnode.node
+        # In fine-grained mode, could be a cross-reference to a deleted module
+        # or a Var made up for a missing module.
+        if not isinstance(node, TypeInfo):
+            if raise_on_missing:
+                assert node, f"Cannot find {name}"
+            return None
+        names = node.names

二進制
venv/lib/python3.11/site-packages/mypy/main.cpython-311-x86_64-linux-gnu.so


+ 1550 - 0
venv/lib/python3.11/site-packages/mypy/main.py

@@ -0,0 +1,1550 @@
+"""Mypy type checker command line tool."""
+
+from __future__ import annotations
+
+import argparse
+import os
+import subprocess
+import sys
+import time
+from gettext import gettext
+from typing import IO, Any, Final, NoReturn, Sequence, TextIO
+
+from mypy import build, defaults, state, util
+from mypy.config_parser import get_config_module_names, parse_config_file, parse_version
+from mypy.errorcodes import error_codes
+from mypy.errors import CompileError
+from mypy.find_sources import InvalidSourceList, create_source_list
+from mypy.fscache import FileSystemCache
+from mypy.modulefinder import BuildSource, FindModuleCache, SearchPaths, get_search_dirs, mypy_path
+from mypy.options import INCOMPLETE_FEATURES, BuildType, Options
+from mypy.split_namespace import SplitNamespace
+from mypy.version import __version__
+
+orig_stat: Final = os.stat
+MEM_PROFILE: Final = False  # If True, dump memory profile
+
+
+def stat_proxy(path: str) -> os.stat_result:
+    try:
+        st = orig_stat(path)
+    except os.error as err:
+        print(f"stat({path!r}) -> {err}")
+        raise
+    else:
+        print(
+            "stat(%r) -> (st_mode=%o, st_mtime=%d, st_size=%d)"
+            % (path, st.st_mode, st.st_mtime, st.st_size)
+        )
+        return st
+
+
+def main(
+    *,
+    args: list[str] | None = None,
+    stdout: TextIO = sys.stdout,
+    stderr: TextIO = sys.stderr,
+    clean_exit: bool = False,
+) -> None:
+    """Main entry point to the type checker.
+
+    Args:
+        args: Custom command-line arguments.  If not given, sys.argv[1:] will
+            be used.
+        clean_exit: Don't hard kill the process on exit. This allows catching
+            SystemExit.
+    """
+    util.check_python_version("mypy")
+    t0 = time.time()
+    # To log stat() calls: os.stat = stat_proxy
+    sys.setrecursionlimit(2**14)
+    if args is None:
+        args = sys.argv[1:]
+
+    fscache = FileSystemCache()
+    sources, options = process_options(args, stdout=stdout, stderr=stderr, fscache=fscache)
+    if clean_exit:
+        options.fast_exit = False
+
+    formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes)
+
+    if options.install_types and (stdout is not sys.stdout or stderr is not sys.stderr):
+        # Since --install-types performs user input, we want regular stdout and stderr.
+        fail("error: --install-types not supported in this mode of running mypy", stderr, options)
+
+    if options.non_interactive and not options.install_types:
+        fail("error: --non-interactive is only supported with --install-types", stderr, options)
+
+    if options.install_types and not options.incremental:
+        fail(
+            "error: --install-types not supported with incremental mode disabled", stderr, options
+        )
+
+    if options.install_types and options.python_executable is None:
+        fail(
+            "error: --install-types not supported without python executable or site packages",
+            stderr,
+            options,
+        )
+
+    if options.install_types and not sources:
+        install_types(formatter, options, non_interactive=options.non_interactive)
+        return
+
+    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+
+    if options.non_interactive:
+        missing_pkgs = read_types_packages_to_install(options.cache_dir, after_run=True)
+        if missing_pkgs:
+            # Install missing type packages and rerun build.
+            install_types(formatter, options, after_run=True, non_interactive=True)
+            fscache.flush()
+            print()
+            res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
+        show_messages(messages, stderr, formatter, options)
+
+    if MEM_PROFILE:
+        from mypy.memprofile import print_memory_profile
+
+        print_memory_profile()
+
+    code = 0
+    n_errors, n_notes, n_files = util.count_stats(messages)
+    if messages and n_notes < len(messages):
+        code = 2 if blockers else 1
+    if options.error_summary:
+        if n_errors:
+            summary = formatter.format_error(
+                n_errors, n_files, len(sources), blockers=blockers, use_color=options.color_output
+            )
+            stdout.write(summary + "\n")
+        # Only notes should also output success
+        elif not messages or n_notes == len(messages):
+            stdout.write(formatter.format_success(len(sources), options.color_output) + "\n")
+        stdout.flush()
+
+    if options.install_types and not options.non_interactive:
+        result = install_types(formatter, options, after_run=True, non_interactive=False)
+        if result:
+            print()
+            print("note: Run mypy again for up-to-date results with installed types")
+            code = 2
+
+    if options.fast_exit:
+        # Exit without freeing objects -- it's faster.
+        #
+        # NOTE: We don't flush all open files on exit (or run other destructors)!
+        util.hard_exit(code)
+    elif code:
+        sys.exit(code)
+
+    # HACK: keep res alive so that mypyc won't free it before the hard_exit
+    list([res])
+
+
+def run_build(
+    sources: list[BuildSource],
+    options: Options,
+    fscache: FileSystemCache,
+    t0: float,
+    stdout: TextIO,
+    stderr: TextIO,
+) -> tuple[build.BuildResult | None, list[str], bool]:
+    formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes)
+
+    messages = []
+
+    def flush_errors(new_messages: list[str], serious: bool) -> None:
+        if options.pretty:
+            new_messages = formatter.fit_in_terminal(new_messages)
+        messages.extend(new_messages)
+        if options.non_interactive:
+            # Collect messages and possibly show them later.
+            return
+        f = stderr if serious else stdout
+        show_messages(new_messages, f, formatter, options)
+
+    serious = False
+    blockers = False
+    res = None
+    try:
+        # Keep a dummy reference (res) for memory profiling afterwards, as otherwise
+        # the result could be freed.
+        res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
+    except CompileError as e:
+        blockers = True
+        if not e.use_stdout:
+            serious = True
+    if (
+        options.warn_unused_configs
+        and options.unused_configs
+        and not options.incremental
+        and not options.non_interactive
+    ):
+        print(
+            "Warning: unused section(s) in %s: %s"
+            % (
+                options.config_file,
+                get_config_module_names(
+                    options.config_file,
+                    [
+                        glob
+                        for glob in options.per_module_options.keys()
+                        if glob in options.unused_configs
+                    ],
+                ),
+            ),
+            file=stderr,
+        )
+    maybe_write_junit_xml(time.time() - t0, serious, messages, options)
+    return res, messages, blockers
+
+
+def show_messages(
+    messages: list[str], f: TextIO, formatter: util.FancyFormatter, options: Options
+) -> None:
+    for msg in messages:
+        if options.color_output:
+            msg = formatter.colorize(msg)
+        f.write(msg + "\n")
+    f.flush()
+
+
+# Make the help output a little less jarring.
+class AugmentedHelpFormatter(argparse.RawDescriptionHelpFormatter):
+    def __init__(self, prog: str) -> None:
+        super().__init__(prog=prog, max_help_position=28)
+
+    def _fill_text(self, text: str, width: int, indent: str) -> str:
+        if "\n" in text:
+            # Assume we want to manually format the text
+            return super()._fill_text(text, width, indent)
+        else:
+            # Assume we want argparse to manage wrapping, indenting, and
+            # formatting the text for us.
+            return argparse.HelpFormatter._fill_text(self, text, width, indent)
+
+
+# Define pairs of flag prefixes with inverse meaning.
+flag_prefix_pairs: Final = [("allow", "disallow"), ("show", "hide")]
+flag_prefix_map: Final[dict[str, str]] = {}
+for a, b in flag_prefix_pairs:
+    flag_prefix_map[a] = b
+    flag_prefix_map[b] = a
+
+
+def invert_flag_name(flag: str) -> str:
+    split = flag[2:].split("-", 1)
+    if len(split) == 2:
+        prefix, rest = split
+        if prefix in flag_prefix_map:
+            return f"--{flag_prefix_map[prefix]}-{rest}"
+        elif prefix == "no":
+            return f"--{rest}"
+
+    return f"--no-{flag[2:]}"
+
+
+class PythonExecutableInferenceError(Exception):
+    """Represents a failure to infer the version or executable while searching."""
+
+
+def python_executable_prefix(v: str) -> list[str]:
+    if sys.platform == "win32":
+        # on Windows, all Python executables are named `python`. To handle this, there
+        # is the `py` launcher, which can be passed a version e.g. `py -3.8`, and it will
+        # execute an installed Python 3.8 interpreter. See also:
+        # https://docs.python.org/3/using/windows.html#python-launcher-for-windows
+        return ["py", f"-{v}"]
+    else:
+        return [f"python{v}"]
+
+
+def _python_executable_from_version(python_version: tuple[int, int]) -> str:
+    if sys.version_info[:2] == python_version:
+        return sys.executable
+    str_ver = ".".join(map(str, python_version))
+    try:
+        sys_exe = (
+            subprocess.check_output(
+                python_executable_prefix(str_ver) + ["-c", "import sys; print(sys.executable)"],
+                stderr=subprocess.STDOUT,
+            )
+            .decode()
+            .strip()
+        )
+        return sys_exe
+    except (subprocess.CalledProcessError, FileNotFoundError) as e:
+        raise PythonExecutableInferenceError(
+            "failed to find a Python executable matching version {},"
+            " perhaps try --python-executable, or --no-site-packages?".format(python_version)
+        ) from e
+
+
+def infer_python_executable(options: Options, special_opts: argparse.Namespace) -> None:
+    """Infer the Python executable from the given version.
+
+    This function mutates options based on special_opts to infer the correct Python executable
+    to use.
+    """
+    # TODO: (ethanhs) Look at folding these checks and the site packages subprocess calls into
+    # one subprocess call for speed.
+
+    # Use the command line specified executable, or fall back to one set in the
+    # config file. If an executable is not specified, infer it from the version
+    # (unless no_executable is set)
+    python_executable = special_opts.python_executable or options.python_executable
+
+    if python_executable is None:
+        if not special_opts.no_executable and not options.no_site_packages:
+            python_executable = _python_executable_from_version(options.python_version)
+    options.python_executable = python_executable
+
+
+HEADER: Final = """%(prog)s [-h] [-v] [-V] [more options; see below]
+            [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...]"""
+
+
+DESCRIPTION: Final = """
+Mypy is a program that will type check your Python code.
+
+Pass in any files or folders you want to type check. Mypy will
+recursively traverse any provided folders to find .py files:
+
+    $ mypy my_program.py my_src_folder
+
+For more information on getting started, see:
+
+- https://mypy.readthedocs.io/en/stable/getting_started.html
+
+For more details on both running mypy and using the flags below, see:
+
+- https://mypy.readthedocs.io/en/stable/running_mypy.html
+- https://mypy.readthedocs.io/en/stable/command_line.html
+
+You can also use a config file to configure mypy instead of using
+command line flags. For more details, see:
+
+- https://mypy.readthedocs.io/en/stable/config_file.html
+"""
+
+FOOTER: Final = """Environment variables:
+  Define MYPYPATH for additional module search path entries.
+  Define MYPY_CACHE_DIR to override configuration cache_dir path."""
+
+
+class CapturableArgumentParser(argparse.ArgumentParser):
+
+    """Override ArgumentParser methods that use sys.stdout/sys.stderr directly.
+
+    This is needed because hijacking sys.std* is not thread-safe,
+    yet output must be captured to properly support mypy.api.run.
+    """
+
+    def __init__(self, *args: Any, **kwargs: Any):
+        self.stdout = kwargs.pop("stdout", sys.stdout)
+        self.stderr = kwargs.pop("stderr", sys.stderr)
+        super().__init__(*args, **kwargs)
+
+    # =====================
+    # Help-printing methods
+    # =====================
+    def print_usage(self, file: IO[str] | None = None) -> None:
+        if file is None:
+            file = self.stdout
+        self._print_message(self.format_usage(), file)
+
+    def print_help(self, file: IO[str] | None = None) -> None:
+        if file is None:
+            file = self.stdout
+        self._print_message(self.format_help(), file)
+
+    def _print_message(self, message: str, file: IO[str] | None = None) -> None:
+        if message:
+            if file is None:
+                file = self.stderr
+            file.write(message)
+
+    # ===============
+    # Exiting methods
+    # ===============
+    def exit(self, status: int = 0, message: str | None = None) -> NoReturn:
+        if message:
+            self._print_message(message, self.stderr)
+        sys.exit(status)
+
+    def error(self, message: str) -> NoReturn:
+        """error(message: string)
+
+        Prints a usage message incorporating the message to stderr and
+        exits.
+
+        If you override this in a subclass, it should not return -- it
+        should either exit or raise an exception.
+        """
+        self.print_usage(self.stderr)
+        args = {"prog": self.prog, "message": message}
+        self.exit(2, gettext("%(prog)s: error: %(message)s\n") % args)
+
+
+class CapturableVersionAction(argparse.Action):
+
+    """Supplement CapturableArgumentParser to handle --version.
+
+    This is nearly identical to argparse._VersionAction except,
+    like CapturableArgumentParser, it allows output to be captured.
+
+    Another notable difference is that version is mandatory.
+    This allows removing a line in __call__ that falls back to parser.version
+    (which does not appear to exist).
+    """
+
+    def __init__(
+        self,
+        option_strings: Sequence[str],
+        version: str,
+        dest: str = argparse.SUPPRESS,
+        default: str = argparse.SUPPRESS,
+        help: str = "show program's version number and exit",
+        stdout: IO[str] | None = None,
+    ):
+        super().__init__(
+            option_strings=option_strings, dest=dest, default=default, nargs=0, help=help
+        )
+        self.version = version
+        self.stdout = stdout or sys.stdout
+
+    def __call__(
+        self,
+        parser: argparse.ArgumentParser,
+        namespace: argparse.Namespace,
+        values: str | Sequence[Any] | None,
+        option_string: str | None = None,
+    ) -> NoReturn:
+        formatter = parser._get_formatter()
+        formatter.add_text(self.version)
+        parser._print_message(formatter.format_help(), self.stdout)
+        parser.exit()
+
+
+def process_options(
+    args: list[str],
+    stdout: TextIO | None = None,
+    stderr: TextIO | None = None,
+    require_targets: bool = True,
+    server_options: bool = False,
+    fscache: FileSystemCache | None = None,
+    program: str = "mypy",
+    header: str = HEADER,
+) -> tuple[list[BuildSource], Options]:
+    """Parse command line arguments.
+
+    If a FileSystemCache is passed in, and package_root options are given,
+    call fscache.set_package_root() to set the cache's package root.
+    """
+    stdout = stdout or sys.stdout
+    stderr = stderr or sys.stderr
+
+    parser = CapturableArgumentParser(
+        prog=program,
+        usage=header,
+        description=DESCRIPTION,
+        epilog=FOOTER,
+        fromfile_prefix_chars="@",
+        formatter_class=AugmentedHelpFormatter,
+        add_help=False,
+        stdout=stdout,
+        stderr=stderr,
+    )
+
+    strict_flag_names: list[str] = []
+    strict_flag_assignments: list[tuple[str, bool]] = []
+
+    def add_invertible_flag(
+        flag: str,
+        *,
+        inverse: str | None = None,
+        default: bool,
+        dest: str | None = None,
+        help: str,
+        strict_flag: bool = False,
+        group: argparse._ActionsContainer | None = None,
+    ) -> None:
+        if inverse is None:
+            inverse = invert_flag_name(flag)
+        if group is None:
+            group = parser
+
+        if help is not argparse.SUPPRESS:
+            help += f" (inverse: {inverse})"
+
+        arg = group.add_argument(
+            flag, action="store_false" if default else "store_true", dest=dest, help=help
+        )
+        dest = arg.dest
+        group.add_argument(
+            inverse,
+            action="store_true" if default else "store_false",
+            dest=dest,
+            help=argparse.SUPPRESS,
+        )
+        if strict_flag:
+            assert dest is not None
+            strict_flag_names.append(flag)
+            strict_flag_assignments.append((dest, not default))
+
+    # Unless otherwise specified, arguments will be parsed directly onto an
+    # Options object.  Options that require further processing should have
+    # their `dest` prefixed with `special-opts:`, which will cause them to be
+    # parsed into the separate special_opts namespace object.
+
+    # Note: we have a style guide for formatting the mypy --help text. See
+    # https://github.com/python/mypy/wiki/Documentation-Conventions
+
+    general_group = parser.add_argument_group(title="Optional arguments")
+    general_group.add_argument(
+        "-h", "--help", action="help", help="Show this help message and exit"
+    )
+    general_group.add_argument(
+        "-v", "--verbose", action="count", dest="verbosity", help="More verbose messages"
+    )
+
+    compilation_status = "no" if __file__.endswith(".py") else "yes"
+    general_group.add_argument(
+        "-V",
+        "--version",
+        action=CapturableVersionAction,
+        version="%(prog)s " + __version__ + f" (compiled: {compilation_status})",
+        help="Show program's version number and exit",
+        stdout=stdout,
+    )
+
+    config_group = parser.add_argument_group(
+        title="Config file",
+        description="Use a config file instead of command line arguments. "
+        "This is useful if you are using many flags or want "
+        "to set different options per each module.",
+    )
+    config_group.add_argument(
+        "--config-file",
+        help="Configuration file, must have a [mypy] section "
+        "(defaults to {})".format(", ".join(defaults.CONFIG_FILES)),
+    )
+    add_invertible_flag(
+        "--warn-unused-configs",
+        default=False,
+        strict_flag=True,
+        help="Warn about unused '[mypy-<pattern>]' or '[[tool.mypy.overrides]]' "
+        "config sections",
+        group=config_group,
+    )
+
+    imports_group = parser.add_argument_group(
+        title="Import discovery", description="Configure how imports are discovered and followed."
+    )
+    add_invertible_flag(
+        "--no-namespace-packages",
+        dest="namespace_packages",
+        default=True,
+        help="Support namespace packages (PEP 420, __init__.py-less)",
+        group=imports_group,
+    )
+    imports_group.add_argument(
+        "--ignore-missing-imports",
+        action="store_true",
+        help="Silently ignore imports of missing modules",
+    )
+    imports_group.add_argument(
+        "--follow-imports",
+        choices=["normal", "silent", "skip", "error"],
+        default="normal",
+        help="How to treat imports (default normal)",
+    )
+    imports_group.add_argument(
+        "--python-executable",
+        action="store",
+        metavar="EXECUTABLE",
+        help="Python executable used for finding PEP 561 compliant installed"
+        " packages and stubs",
+        dest="special-opts:python_executable",
+    )
+    imports_group.add_argument(
+        "--no-site-packages",
+        action="store_true",
+        dest="special-opts:no_executable",
+        help="Do not search for installed PEP 561 compliant packages",
+    )
+    imports_group.add_argument(
+        "--no-silence-site-packages",
+        action="store_true",
+        help="Do not silence errors in PEP 561 compliant installed packages",
+    )
+
+    platform_group = parser.add_argument_group(
+        title="Platform configuration",
+        description="Type check code assuming it will be run under certain "
+        "runtime conditions. By default, mypy assumes your code "
+        "will be run using the same operating system and Python "
+        "version you are using to run mypy itself.",
+    )
+    platform_group.add_argument(
+        "--python-version",
+        type=parse_version,
+        metavar="x.y",
+        help="Type check code assuming it will be running on Python x.y",
+        dest="special-opts:python_version",
+    )
+    platform_group.add_argument(
+        "-2",
+        "--py2",
+        dest="special-opts:python_version",
+        action="store_const",
+        const=defaults.PYTHON2_VERSION,
+        help="Use Python 2 mode (same as --python-version 2.7)",
+    )
+    platform_group.add_argument(
+        "--platform",
+        action="store",
+        metavar="PLATFORM",
+        help="Type check special-cased code for the given OS platform "
+        "(defaults to sys.platform)",
+    )
+    platform_group.add_argument(
+        "--always-true",
+        metavar="NAME",
+        action="append",
+        default=[],
+        help="Additional variable to be considered True (may be repeated)",
+    )
+    platform_group.add_argument(
+        "--always-false",
+        metavar="NAME",
+        action="append",
+        default=[],
+        help="Additional variable to be considered False (may be repeated)",
+    )
+
+    disallow_any_group = parser.add_argument_group(
+        title="Disallow dynamic typing",
+        description="Disallow the use of the dynamic 'Any' type under certain conditions.",
+    )
+    disallow_any_group.add_argument(
+        "--disallow-any-unimported",
+        default=False,
+        action="store_true",
+        help="Disallow Any types resulting from unfollowed imports",
+    )
+    disallow_any_group.add_argument(
+        "--disallow-any-expr",
+        default=False,
+        action="store_true",
+        help="Disallow all expressions that have type Any",
+    )
+    disallow_any_group.add_argument(
+        "--disallow-any-decorated",
+        default=False,
+        action="store_true",
+        help="Disallow functions that have Any in their signature "
+        "after decorator transformation",
+    )
+    disallow_any_group.add_argument(
+        "--disallow-any-explicit",
+        default=False,
+        action="store_true",
+        help="Disallow explicit Any in type positions",
+    )
+    add_invertible_flag(
+        "--disallow-any-generics",
+        default=False,
+        strict_flag=True,
+        help="Disallow usage of generic types that do not specify explicit type parameters",
+        group=disallow_any_group,
+    )
+    add_invertible_flag(
+        "--disallow-subclassing-any",
+        default=False,
+        strict_flag=True,
+        help="Disallow subclassing values of type 'Any' when defining classes",
+        group=disallow_any_group,
+    )
+
+    untyped_group = parser.add_argument_group(
+        title="Untyped definitions and calls",
+        description="Configure how untyped definitions and calls are handled. "
+        "Note: by default, mypy ignores any untyped function definitions "
+        "and assumes any calls to such functions have a return "
+        "type of 'Any'.",
+    )
+    add_invertible_flag(
+        "--disallow-untyped-calls",
+        default=False,
+        strict_flag=True,
+        help="Disallow calling functions without type annotations"
+        " from functions with type annotations",
+        group=untyped_group,
+    )
+    add_invertible_flag(
+        "--disallow-untyped-defs",
+        default=False,
+        strict_flag=True,
+        help="Disallow defining functions without type annotations"
+        " or with incomplete type annotations",
+        group=untyped_group,
+    )
+    add_invertible_flag(
+        "--disallow-incomplete-defs",
+        default=False,
+        strict_flag=True,
+        help="Disallow defining functions with incomplete type annotations "
+        "(while still allowing entirely unannotated definitions)",
+        group=untyped_group,
+    )
+    add_invertible_flag(
+        "--check-untyped-defs",
+        default=False,
+        strict_flag=True,
+        help="Type check the interior of functions without type annotations",
+        group=untyped_group,
+    )
+    add_invertible_flag(
+        "--disallow-untyped-decorators",
+        default=False,
+        strict_flag=True,
+        help="Disallow decorating typed functions with untyped decorators",
+        group=untyped_group,
+    )
+
+    none_group = parser.add_argument_group(
+        title="None and Optional handling",
+        description="Adjust how values of type 'None' are handled. For more context on "
+        "how mypy handles values of type 'None', see: "
+        "https://mypy.readthedocs.io/en/stable/kinds_of_types.html#no-strict-optional",
+    )
+    add_invertible_flag(
+        "--implicit-optional",
+        default=False,
+        help="Assume arguments with default values of None are Optional",
+        group=none_group,
+    )
+    none_group.add_argument("--strict-optional", action="store_true", help=argparse.SUPPRESS)
+    none_group.add_argument(
+        "--no-strict-optional",
+        action="store_false",
+        dest="strict_optional",
+        help="Disable strict Optional checks (inverse: --strict-optional)",
+    )
+
+    add_invertible_flag(
+        "--force-uppercase-builtins", default=False, help=argparse.SUPPRESS, group=none_group
+    )
+
+    add_invertible_flag(
+        "--force-union-syntax", default=False, help=argparse.SUPPRESS, group=none_group
+    )
+
+    lint_group = parser.add_argument_group(
+        title="Configuring warnings",
+        description="Detect code that is sound but redundant or problematic.",
+    )
+    add_invertible_flag(
+        "--warn-redundant-casts",
+        default=False,
+        strict_flag=True,
+        help="Warn about casting an expression to its inferred type",
+        group=lint_group,
+    )
+    add_invertible_flag(
+        "--warn-unused-ignores",
+        default=False,
+        strict_flag=True,
+        help="Warn about unneeded '# type: ignore' comments",
+        group=lint_group,
+    )
+    add_invertible_flag(
+        "--no-warn-no-return",
+        dest="warn_no_return",
+        default=True,
+        help="Do not warn about functions that end without returning",
+        group=lint_group,
+    )
+    add_invertible_flag(
+        "--warn-return-any",
+        default=False,
+        strict_flag=True,
+        help="Warn about returning values of type Any from non-Any typed functions",
+        group=lint_group,
+    )
+    add_invertible_flag(
+        "--warn-unreachable",
+        default=False,
+        strict_flag=False,
+        help="Warn about statements or expressions inferred to be unreachable",
+        group=lint_group,
+    )
+
+    # Note: this group is intentionally added here even though we don't add
+    # --strict to this group near the end.
+    #
+    # That way, this group will appear after the various strictness groups
+    # but before the remaining flags.
+    # We add `--strict` near the end so we don't accidentally miss any strictness
+    # flags that are added after this group.
+    strictness_group = parser.add_argument_group(title="Miscellaneous strictness flags")
+
+    add_invertible_flag(
+        "--allow-untyped-globals",
+        default=False,
+        strict_flag=False,
+        help="Suppress toplevel errors caused by missing annotations",
+        group=strictness_group,
+    )
+
+    add_invertible_flag(
+        "--allow-redefinition",
+        default=False,
+        strict_flag=False,
+        help="Allow unconditional variable redefinition with a new type",
+        group=strictness_group,
+    )
+
+    add_invertible_flag(
+        "--no-implicit-reexport",
+        default=True,
+        strict_flag=True,
+        dest="implicit_reexport",
+        help="Treat imports as private unless aliased",
+        group=strictness_group,
+    )
+
+    add_invertible_flag(
+        "--strict-equality",
+        default=False,
+        strict_flag=True,
+        help="Prohibit equality, identity, and container checks for non-overlapping types",
+        group=strictness_group,
+    )
+
+    add_invertible_flag(
+        "--extra-checks",
+        default=False,
+        strict_flag=True,
+        help="Enable additional checks that are technically correct but may be impractical "
+        "in real code. For example, this prohibits partial overlap in TypedDict updates, "
+        "and makes arguments prepended via Concatenate positional-only",
+        group=strictness_group,
+    )
+
+    strict_help = "Strict mode; enables the following flags: {}".format(
+        ", ".join(strict_flag_names)
+    )
+    strictness_group.add_argument(
+        "--strict", action="store_true", dest="special-opts:strict", help=strict_help
+    )
+
+    strictness_group.add_argument(
+        "--disable-error-code",
+        metavar="NAME",
+        action="append",
+        default=[],
+        help="Disable a specific error code",
+    )
+    strictness_group.add_argument(
+        "--enable-error-code",
+        metavar="NAME",
+        action="append",
+        default=[],
+        help="Enable a specific error code",
+    )
+
+    error_group = parser.add_argument_group(
+        title="Configuring error messages",
+        description="Adjust the amount of detail shown in error messages.",
+    )
+    add_invertible_flag(
+        "--show-error-context",
+        default=False,
+        dest="show_error_context",
+        help='Precede errors with "note:" messages explaining context',
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--show-column-numbers",
+        default=False,
+        help="Show column numbers in error messages",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--show-error-end",
+        default=False,
+        help="Show end line/end column numbers in error messages."
+        " This implies --show-column-numbers",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--hide-error-codes",
+        default=False,
+        help="Hide error codes in error messages",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--show-error-code-links",
+        default=False,
+        help="Show links to error code documentation",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--pretty",
+        default=False,
+        help="Use visually nicer output in error messages:"
+        " Use soft word wrap, show source code snippets,"
+        " and show error location markers",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--no-color-output",
+        dest="color_output",
+        default=True,
+        help="Do not colorize error messages",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--no-error-summary",
+        dest="error_summary",
+        default=True,
+        help="Do not show error stats summary",
+        group=error_group,
+    )
+    add_invertible_flag(
+        "--show-absolute-path",
+        default=False,
+        help="Show absolute paths to files",
+        group=error_group,
+    )
+    error_group.add_argument(
+        "--soft-error-limit",
+        default=defaults.MANY_ERRORS_THRESHOLD,
+        type=int,
+        dest="many_errors_threshold",
+        help=argparse.SUPPRESS,
+    )
+
+    incremental_group = parser.add_argument_group(
+        title="Incremental mode",
+        description="Adjust how mypy incrementally type checks and caches modules. "
+        "Mypy caches type information about modules into a cache to "
+        "let you speed up future invocations of mypy. Also see "
+        "mypy's daemon mode: "
+        "mypy.readthedocs.io/en/stable/mypy_daemon.html#mypy-daemon",
+    )
+    incremental_group.add_argument(
+        "-i", "--incremental", action="store_true", help=argparse.SUPPRESS
+    )
+    incremental_group.add_argument(
+        "--no-incremental",
+        action="store_false",
+        dest="incremental",
+        help="Disable module cache (inverse: --incremental)",
+    )
+    incremental_group.add_argument(
+        "--cache-dir",
+        action="store",
+        metavar="DIR",
+        help="Store module cache info in the given folder in incremental mode "
+        "(defaults to '{}')".format(defaults.CACHE_DIR),
+    )
+    add_invertible_flag(
+        "--sqlite-cache",
+        default=False,
+        help="Use a sqlite database to store the cache",
+        group=incremental_group,
+    )
+    incremental_group.add_argument(
+        "--cache-fine-grained",
+        action="store_true",
+        help="Include fine-grained dependency information in the cache for the mypy daemon",
+    )
+    incremental_group.add_argument(
+        "--skip-version-check",
+        action="store_true",
+        help="Allow using cache written by older mypy version",
+    )
+    incremental_group.add_argument(
+        "--skip-cache-mtime-checks",
+        action="store_true",
+        help="Skip cache internal consistency checks based on mtime",
+    )
+
+    internals_group = parser.add_argument_group(
+        title="Advanced options", description="Debug and customize mypy internals."
+    )
+    internals_group.add_argument("--pdb", action="store_true", help="Invoke pdb on fatal error")
+    internals_group.add_argument(
+        "--show-traceback", "--tb", action="store_true", help="Show traceback on fatal error"
+    )
+    internals_group.add_argument(
+        "--raise-exceptions", action="store_true", help="Raise exception on fatal error"
+    )
+    internals_group.add_argument(
+        "--custom-typing-module",
+        metavar="MODULE",
+        dest="custom_typing_module",
+        help="Use a custom typing module",
+    )
+    internals_group.add_argument(
+        "--new-type-inference",
+        action="store_true",
+        help="Enable new experimental type inference algorithm",
+    )
+    internals_group.add_argument(
+        "--disable-recursive-aliases",
+        action="store_true",
+        help="Disable experimental support for recursive type aliases",
+    )
+    # Deprecated reverse variant of the above.
+    internals_group.add_argument(
+        "--enable-recursive-aliases", action="store_true", help=argparse.SUPPRESS
+    )
+    parser.add_argument(
+        "--enable-incomplete-feature",
+        action="append",
+        metavar="FEATURE",
+        help="Enable support of incomplete/experimental features for early preview",
+    )
+    internals_group.add_argument(
+        "--custom-typeshed-dir", metavar="DIR", help="Use the custom typeshed in DIR"
+    )
+    add_invertible_flag(
+        "--warn-incomplete-stub",
+        default=False,
+        help="Warn if missing type annotation in typeshed, only relevant with"
+        " --disallow-untyped-defs or --disallow-incomplete-defs enabled",
+        group=internals_group,
+    )
+    internals_group.add_argument(
+        "--shadow-file",
+        nargs=2,
+        metavar=("SOURCE_FILE", "SHADOW_FILE"),
+        dest="shadow_file",
+        action="append",
+        help="When encountering SOURCE_FILE, read and type check "
+        "the contents of SHADOW_FILE instead.",
+    )
+    internals_group.add_argument("--fast-exit", action="store_true", help=argparse.SUPPRESS)
+    internals_group.add_argument(
+        "--no-fast-exit", action="store_false", dest="fast_exit", help=argparse.SUPPRESS
+    )
+    # This flag is useful for mypy tests, where function bodies may be omitted. Plugin developers
+    # may want to use this as well in their tests.
+    add_invertible_flag(
+        "--allow-empty-bodies", default=False, help=argparse.SUPPRESS, group=internals_group
+    )
+    # This undocumented feature exports limited line-level dependency information.
+    internals_group.add_argument("--export-ref-info", action="store_true", help=argparse.SUPPRESS)
+
+    report_group = parser.add_argument_group(
+        title="Report generation", description="Generate a report in the specified format."
+    )
+    for report_type in sorted(defaults.REPORTER_NAMES):
+        if report_type not in {"memory-xml"}:
+            report_group.add_argument(
+                f"--{report_type.replace('_', '-')}-report",
+                metavar="DIR",
+                dest=f"special-opts:{report_type}_report",
+            )
+
+    other_group = parser.add_argument_group(title="Miscellaneous")
+    other_group.add_argument("--quickstart-file", help=argparse.SUPPRESS)
+    other_group.add_argument("--junit-xml", help="Write junit.xml to the given file")
+    other_group.add_argument(
+        "--find-occurrences",
+        metavar="CLASS.MEMBER",
+        dest="special-opts:find_occurrences",
+        help="Print out all usages of a class member (experimental)",
+    )
+    other_group.add_argument(
+        "--scripts-are-modules",
+        action="store_true",
+        help="Script x becomes module x instead of __main__",
+    )
+
+    add_invertible_flag(
+        "--install-types",
+        default=False,
+        strict_flag=False,
+        help="Install detected missing library stub packages using pip",
+        group=other_group,
+    )
+    add_invertible_flag(
+        "--non-interactive",
+        default=False,
+        strict_flag=False,
+        help=(
+            "Install stubs without asking for confirmation and hide "
+            + "errors, with --install-types"
+        ),
+        group=other_group,
+        inverse="--interactive",
+    )
+
+    if server_options:
+        # TODO: This flag is superfluous; remove after a short transition (2018-03-16)
+        other_group.add_argument(
+            "--experimental",
+            action="store_true",
+            dest="fine_grained_incremental",
+            help="Enable fine-grained incremental mode",
+        )
+        other_group.add_argument(
+            "--use-fine-grained-cache",
+            action="store_true",
+            help="Use the cache in fine-grained incremental mode",
+        )
+
+    # hidden options
+    parser.add_argument(
+        "--stats", action="store_true", dest="dump_type_stats", help=argparse.SUPPRESS
+    )
+    parser.add_argument(
+        "--inferstats", action="store_true", dest="dump_inference_stats", help=argparse.SUPPRESS
+    )
+    parser.add_argument("--dump-build-stats", action="store_true", help=argparse.SUPPRESS)
+    # Dump timing stats for each processed file into the given output file
+    parser.add_argument("--timing-stats", dest="timing_stats", help=argparse.SUPPRESS)
+    # Dump per line type checking timing stats for each processed file into the given
+    # output file. Only total time spent in each top level expression will be shown.
+    # Times are show in microseconds.
+    parser.add_argument(
+        "--line-checking-stats", dest="line_checking_stats", help=argparse.SUPPRESS
+    )
+    # --debug-cache will disable any cache-related compressions/optimizations,
+    # which will make the cache writing process output pretty-printed JSON (which
+    # is easier to debug).
+    parser.add_argument("--debug-cache", action="store_true", help=argparse.SUPPRESS)
+    # --dump-deps will dump all fine-grained dependencies to stdout
+    parser.add_argument("--dump-deps", action="store_true", help=argparse.SUPPRESS)
+    # --dump-graph will dump the contents of the graph of SCCs and exit.
+    parser.add_argument("--dump-graph", action="store_true", help=argparse.SUPPRESS)
+    # --semantic-analysis-only does exactly that.
+    parser.add_argument("--semantic-analysis-only", action="store_true", help=argparse.SUPPRESS)
+    # --local-partial-types disallows partial types spanning module top level and a function
+    # (implicitly defined in fine-grained incremental mode)
+    parser.add_argument("--local-partial-types", action="store_true", help=argparse.SUPPRESS)
+    # --logical-deps adds some more dependencies that are not semantically needed, but
+    # may be helpful to determine relative importance of classes and functions for overall
+    # type precision in a code base. It also _removes_ some deps, so this flag should be never
+    # used except for generating code stats. This also automatically enables --cache-fine-grained.
+    # NOTE: This is an experimental option that may be modified or removed at any time.
+    parser.add_argument("--logical-deps", action="store_true", help=argparse.SUPPRESS)
+    # --bazel changes some behaviors for use with Bazel (https://bazel.build).
+    parser.add_argument("--bazel", action="store_true", help=argparse.SUPPRESS)
+    # --package-root adds a directory below which directories are considered
+    # packages even without __init__.py.  May be repeated.
+    parser.add_argument(
+        "--package-root", metavar="ROOT", action="append", default=[], help=argparse.SUPPRESS
+    )
+    # --cache-map FILE ... gives a mapping from source files to cache files.
+    # Each triple of arguments is a source file, a cache meta file, and a cache data file.
+    # Modules not mentioned in the file will go through cache_dir.
+    # Must be followed by another flag or by '--' (and then only file args may follow).
+    parser.add_argument(
+        "--cache-map", nargs="+", dest="special-opts:cache_map", help=argparse.SUPPRESS
+    )
+    # --debug-serialize will run tree.serialize() even if cache generation is disabled.
+    # Useful for mypy_primer to detect serialize errors earlier.
+    parser.add_argument("--debug-serialize", action="store_true", help=argparse.SUPPRESS)
+    # This one is deprecated, but we will keep it for few releases.
+    parser.add_argument(
+        "--enable-incomplete-features", action="store_true", help=argparse.SUPPRESS
+    )
+    parser.add_argument(
+        "--disable-bytearray-promotion", action="store_true", help=argparse.SUPPRESS
+    )
+    parser.add_argument(
+        "--disable-memoryview-promotion", action="store_true", help=argparse.SUPPRESS
+    )
+    # This flag is deprecated, it has been moved to --extra-checks
+    parser.add_argument("--strict-concatenate", action="store_true", help=argparse.SUPPRESS)
+
+    # options specifying code to check
+    code_group = parser.add_argument_group(
+        title="Running code",
+        description="Specify the code you want to type check. For more details, see "
+        "mypy.readthedocs.io/en/stable/running_mypy.html#running-mypy",
+    )
+    add_invertible_flag(
+        "--explicit-package-bases",
+        default=False,
+        help="Use current directory and MYPYPATH to determine module names of files passed",
+        group=code_group,
+    )
+    add_invertible_flag(
+        "--fast-module-lookup", default=False, help=argparse.SUPPRESS, group=code_group
+    )
+    code_group.add_argument(
+        "--exclude",
+        action="append",
+        metavar="PATTERN",
+        default=[],
+        help=(
+            "Regular expression to match file names, directory names or paths which mypy should "
+            "ignore while recursively discovering files to check, e.g. --exclude '/setup\\.py$'. "
+            "May be specified more than once, eg. --exclude a --exclude b"
+        ),
+    )
+    code_group.add_argument(
+        "-m",
+        "--module",
+        action="append",
+        metavar="MODULE",
+        default=[],
+        dest="special-opts:modules",
+        help="Type-check module; can repeat for more modules",
+    )
+    code_group.add_argument(
+        "-p",
+        "--package",
+        action="append",
+        metavar="PACKAGE",
+        default=[],
+        dest="special-opts:packages",
+        help="Type-check package recursively; can be repeated",
+    )
+    code_group.add_argument(
+        "-c",
+        "--command",
+        action="append",
+        metavar="PROGRAM_TEXT",
+        dest="special-opts:command",
+        help="Type-check program passed in as string",
+    )
+    code_group.add_argument(
+        metavar="files",
+        nargs="*",
+        dest="special-opts:files",
+        help="Type-check given files or directories",
+    )
+
+    # Parse arguments once into a dummy namespace so we can get the
+    # filename for the config file and know if the user requested all strict options.
+    dummy = argparse.Namespace()
+    parser.parse_args(args, dummy)
+    config_file = dummy.config_file
+    # Don't explicitly test if "config_file is not None" for this check.
+    # This lets `--config-file=` (an empty string) be used to disable all config files.
+    if config_file and not os.path.exists(config_file):
+        parser.error(f"Cannot find config file '{config_file}'")
+
+    options = Options()
+    strict_option_set = False
+
+    def set_strict_flags() -> None:
+        nonlocal strict_option_set
+        strict_option_set = True
+        for dest, value in strict_flag_assignments:
+            setattr(options, dest, value)
+
+    # Parse config file first, so command line can override.
+    parse_config_file(options, set_strict_flags, config_file, stdout, stderr)
+
+    # Set strict flags before parsing (if strict mode enabled), so other command
+    # line options can override.
+    if getattr(dummy, "special-opts:strict"):
+        set_strict_flags()
+
+    # Override cache_dir if provided in the environment
+    environ_cache_dir = os.getenv("MYPY_CACHE_DIR", "")
+    if environ_cache_dir.strip():
+        options.cache_dir = environ_cache_dir
+    options.cache_dir = os.path.expanduser(options.cache_dir)
+
+    # Parse command line for real, using a split namespace.
+    special_opts = argparse.Namespace()
+    parser.parse_args(args, SplitNamespace(options, special_opts, "special-opts:"))
+
+    # The python_version is either the default, which can be overridden via a config file,
+    # or stored in special_opts and is passed via the command line.
+    options.python_version = special_opts.python_version or options.python_version
+    if options.python_version < (3,):
+        parser.error(
+            "Mypy no longer supports checking Python 2 code. "
+            "Consider pinning to mypy<0.980 if you need to check Python 2 code."
+        )
+    try:
+        infer_python_executable(options, special_opts)
+    except PythonExecutableInferenceError as e:
+        parser.error(str(e))
+
+    if special_opts.no_executable or options.no_site_packages:
+        options.python_executable = None
+
+    # Paths listed in the config file will be ignored if any paths, modules or packages
+    # are passed on the command line.
+    if not (special_opts.files or special_opts.packages or special_opts.modules):
+        if options.files:
+            special_opts.files = options.files
+        if options.packages:
+            special_opts.packages = options.packages
+        if options.modules:
+            special_opts.modules = options.modules
+
+    # Check for invalid argument combinations.
+    if require_targets:
+        code_methods = sum(
+            bool(c)
+            for c in [
+                special_opts.modules + special_opts.packages,
+                special_opts.command,
+                special_opts.files,
+            ]
+        )
+        if code_methods == 0 and not options.install_types:
+            parser.error("Missing target module, package, files, or command.")
+        elif code_methods > 1:
+            parser.error("May only specify one of: module/package, files, or command.")
+    if options.explicit_package_bases and not options.namespace_packages:
+        parser.error(
+            "Can only use --explicit-package-bases with --namespace-packages, since otherwise "
+            "examining __init__.py's is sufficient to determine module names for files"
+        )
+
+    # Check for overlapping `--always-true` and `--always-false` flags.
+    overlap = set(options.always_true) & set(options.always_false)
+    if overlap:
+        parser.error(
+            "You can't make a variable always true and always false (%s)"
+            % ", ".join(sorted(overlap))
+        )
+
+    # Process `--enable-error-code` and `--disable-error-code` flags
+    disabled_codes = set(options.disable_error_code)
+    enabled_codes = set(options.enable_error_code)
+
+    valid_error_codes = set(error_codes.keys())
+
+    invalid_codes = (enabled_codes | disabled_codes) - valid_error_codes
+    if invalid_codes:
+        parser.error(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}")
+
+    options.disabled_error_codes |= {error_codes[code] for code in disabled_codes}
+    options.enabled_error_codes |= {error_codes[code] for code in enabled_codes}
+
+    # Enabling an error code always overrides disabling
+    options.disabled_error_codes -= options.enabled_error_codes
+
+    # Validate incomplete features.
+    for feature in options.enable_incomplete_feature:
+        if feature not in INCOMPLETE_FEATURES:
+            parser.error(f"Unknown incomplete feature: {feature}")
+    if options.enable_incomplete_features:
+        print(
+            "Warning: --enable-incomplete-features is deprecated, use"
+            " --enable-incomplete-feature=FEATURE instead"
+        )
+        options.enable_incomplete_feature = list(INCOMPLETE_FEATURES)
+
+    # Compute absolute path for custom typeshed (if present).
+    if options.custom_typeshed_dir is not None:
+        options.abs_custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir)
+
+    # Set build flags.
+    if special_opts.find_occurrences:
+        _find_occurrences = tuple(special_opts.find_occurrences.split("."))
+        if len(_find_occurrences) < 2:
+            parser.error("Can only find occurrences of class members.")
+        if len(_find_occurrences) != 2:
+            parser.error("Can only find occurrences of non-nested class members.")
+        state.find_occurrences = _find_occurrences  # type: ignore[assignment]
+
+    # Set reports.
+    for flag, val in vars(special_opts).items():
+        if flag.endswith("_report") and val is not None:
+            report_type = flag[:-7].replace("_", "-")
+            report_dir = val
+            options.report_dirs[report_type] = report_dir
+
+    # Process --package-root.
+    if options.package_root:
+        process_package_roots(fscache, parser, options)
+
+    # Process --cache-map.
+    if special_opts.cache_map:
+        if options.sqlite_cache:
+            parser.error("--cache-map is incompatible with --sqlite-cache")
+
+        process_cache_map(parser, special_opts, options)
+
+    # An explicitly specified cache_fine_grained implies local_partial_types
+    # (because otherwise the cache is not compatible with dmypy)
+    if options.cache_fine_grained:
+        options.local_partial_types = True
+
+    #  Implicitly show column numbers if error location end is shown
+    if options.show_error_end:
+        options.show_column_numbers = True
+
+    # Let logical_deps imply cache_fine_grained (otherwise the former is useless).
+    if options.logical_deps:
+        options.cache_fine_grained = True
+
+    if options.enable_recursive_aliases:
+        print(
+            "Warning: --enable-recursive-aliases is deprecated;"
+            " recursive types are enabled by default"
+        )
+    if options.strict_concatenate and not strict_option_set:
+        print("Warning: --strict-concatenate is deprecated; use --extra-checks instead")
+
+    # Set target.
+    if special_opts.modules + special_opts.packages:
+        options.build_type = BuildType.MODULE
+        sys_path, _ = get_search_dirs(options.python_executable)
+        search_paths = SearchPaths(
+            (os.getcwd(),), tuple(mypy_path() + options.mypy_path), tuple(sys_path), ()
+        )
+        targets = []
+        # TODO: use the same cache that the BuildManager will
+        cache = FindModuleCache(search_paths, fscache, options)
+        for p in special_opts.packages:
+            if os.sep in p or os.altsep and os.altsep in p:
+                fail(f"Package name '{p}' cannot have a slash in it.", stderr, options)
+            p_targets = cache.find_modules_recursive(p)
+            if not p_targets:
+                fail(f"Can't find package '{p}'", stderr, options)
+            targets.extend(p_targets)
+        for m in special_opts.modules:
+            targets.append(BuildSource(None, m, None))
+        return targets, options
+    elif special_opts.command:
+        options.build_type = BuildType.PROGRAM_TEXT
+        targets = [BuildSource(None, None, "\n".join(special_opts.command))]
+        return targets, options
+    else:
+        try:
+            targets = create_source_list(special_opts.files, options, fscache)
+        # Variable named e2 instead of e to work around mypyc bug #620
+        # which causes issues when using the same variable to catch
+        # exceptions of different types.
+        except InvalidSourceList as e2:
+            fail(str(e2), stderr, options)
+        return targets, options
+
+
+def process_package_roots(
+    fscache: FileSystemCache | None, parser: argparse.ArgumentParser, options: Options
+) -> None:
+    """Validate and normalize package_root."""
+    if fscache is None:
+        parser.error("--package-root does not work here (no fscache)")
+    assert fscache is not None  # Since mypy doesn't know parser.error() raises.
+    # Do some stuff with drive letters to make Windows happy (esp. tests).
+    current_drive, _ = os.path.splitdrive(os.getcwd())
+    dot = os.curdir
+    dotslash = os.curdir + os.sep
+    dotdotslash = os.pardir + os.sep
+    trivial_paths = {dot, dotslash}
+    package_root = []
+    for root in options.package_root:
+        if os.path.isabs(root):
+            parser.error(f"Package root cannot be absolute: {root!r}")
+        drive, root = os.path.splitdrive(root)
+        if drive and drive != current_drive:
+            parser.error(f"Package root must be on current drive: {drive + root!r}")
+        # Empty package root is always okay.
+        if root:
+            root = os.path.relpath(root)  # Normalize the heck out of it.
+            if not root.endswith(os.sep):
+                root = root + os.sep
+            if root.startswith(dotdotslash):
+                parser.error(f"Package root cannot be above current directory: {root!r}")
+            if root in trivial_paths:
+                root = ""
+        package_root.append(root)
+    options.package_root = package_root
+    # Pass the package root on the the filesystem cache.
+    fscache.set_package_root(package_root)
+
+
+def process_cache_map(
+    parser: argparse.ArgumentParser, special_opts: argparse.Namespace, options: Options
+) -> None:
+    """Validate cache_map and copy into options.cache_map."""
+    n = len(special_opts.cache_map)
+    if n % 3 != 0:
+        parser.error("--cache-map requires one or more triples (see source)")
+    for i in range(0, n, 3):
+        source, meta_file, data_file = special_opts.cache_map[i : i + 3]
+        if source in options.cache_map:
+            parser.error(f"Duplicate --cache-map source {source})")
+        if not source.endswith(".py") and not source.endswith(".pyi"):
+            parser.error(f"Invalid --cache-map source {source} (triple[0] must be *.py[i])")
+        if not meta_file.endswith(".meta.json"):
+            parser.error(
+                "Invalid --cache-map meta_file %s (triple[1] must be *.meta.json)" % meta_file
+            )
+        if not data_file.endswith(".data.json"):
+            parser.error(
+                "Invalid --cache-map data_file %s (triple[2] must be *.data.json)" % data_file
+            )
+        options.cache_map[source] = (meta_file, data_file)
+
+
+def maybe_write_junit_xml(td: float, serious: bool, messages: list[str], options: Options) -> None:
+    if options.junit_xml:
+        py_version = f"{options.python_version[0]}_{options.python_version[1]}"
+        util.write_junit_xml(
+            td, serious, messages, options.junit_xml, py_version, options.platform
+        )
+
+
+def fail(msg: str, stderr: TextIO, options: Options) -> NoReturn:
+    """Fail with a serious error."""
+    stderr.write(f"{msg}\n")
+    maybe_write_junit_xml(0.0, serious=True, messages=[msg], options=options)
+    sys.exit(2)
+
+
+def read_types_packages_to_install(cache_dir: str, after_run: bool) -> list[str]:
+    if not os.path.isdir(cache_dir):
+        if not after_run:
+            sys.stderr.write(
+                "error: Can't determine which types to install with no files to check "
+                + "(and no cache from previous mypy run)\n"
+            )
+        else:
+            sys.stderr.write("error: --install-types failed (no mypy cache directory)\n")
+        sys.exit(2)
+    fnam = build.missing_stubs_file(cache_dir)
+    if not os.path.isfile(fnam):
+        # No missing stubs.
+        return []
+    with open(fnam) as f:
+        return [line.strip() for line in f]
+
+
+def install_types(
+    formatter: util.FancyFormatter,
+    options: Options,
+    *,
+    after_run: bool = False,
+    non_interactive: bool = False,
+) -> bool:
+    """Install stub packages using pip if some missing stubs were detected."""
+    packages = read_types_packages_to_install(options.cache_dir, after_run)
+    if not packages:
+        # If there are no missing stubs, generate no output.
+        return False
+    if after_run and not non_interactive:
+        print()
+    print("Installing missing stub packages:")
+    assert options.python_executable, "Python executable required to install types"
+    cmd = [options.python_executable, "-m", "pip", "install"] + packages
+    print(formatter.style(" ".join(cmd), "none", bold=True))
+    print()
+    if not non_interactive:
+        x = input("Install? [yN] ")
+        if not x.strip() or not x.lower().startswith("y"):
+            print(formatter.style("mypy: Skipping installation", "red", bold=True))
+            sys.exit(2)
+        print()
+    subprocess.run(cmd)
+    return True

Some files were not shown because too many files changed in this diff