tpy-lang 0.3.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
  2. tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
  3. tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
  4. tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
  5. tpyc/__init__.py +104 -0
  6. tpyc/__main__.py +6 -0
  7. tpyc/_buildinfo.py +1 -0
  8. tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
  9. tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
  10. tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
  11. tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
  12. tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
  13. tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
  14. tpyc/_data/lib/tpy/_functools_macros.py +80 -0
  15. tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
  16. tpyc/_data/lib/tpy/argparse.py +2062 -0
  17. tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
  18. tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
  19. tpyc/_data/lib/tpy/base64.py +410 -0
  20. tpyc/_data/lib/tpy/bisect.py +39 -0
  21. tpyc/_data/lib/tpy/builtins.py +38 -0
  22. tpyc/_data/lib/tpy/dataclasses.py +354 -0
  23. tpyc/_data/lib/tpy/enum.py +23 -0
  24. tpyc/_data/lib/tpy/functools.py +33 -0
  25. tpyc/_data/lib/tpy/hashlib.py +206 -0
  26. tpyc/_data/lib/tpy/heapq.py +118 -0
  27. tpyc/_data/lib/tpy/io.py +395 -0
  28. tpyc/_data/lib/tpy/json.py +221 -0
  29. tpyc/_data/lib/tpy/math.py +406 -0
  30. tpyc/_data/lib/tpy/random.py +597 -0
  31. tpyc/_data/lib/tpy/re.py +467 -0
  32. tpyc/_data/lib/tpy/socket.py +379 -0
  33. tpyc/_data/lib/tpy/struct.py +178 -0
  34. tpyc/_data/lib/tpy/sys.py +40 -0
  35. tpyc/_data/lib/tpy/time.py +39 -0
  36. tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
  37. tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
  38. tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
  39. tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
  40. tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
  41. tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
  42. tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
  43. tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
  44. tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
  45. tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
  46. tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
  47. tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
  48. tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
  49. tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
  50. tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
  51. tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
  52. tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
  53. tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
  54. tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
  55. tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
  56. tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
  57. tpyc/_data/lib/tpy/tpy/_version.py +29 -0
  58. tpyc/_data/lib/tpy/tpy/bits.py +28 -0
  59. tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
  60. tpyc/_data/lib/tpy/tpy/extern.py +8 -0
  61. tpyc/_data/lib/tpy/tpy/mem.py +49 -0
  62. tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
  63. tpyc/_data/lib/tpy/tpy/version.py +21 -0
  64. tpyc/_data/lib/tpy/typing.py +13 -0
  65. tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
  66. tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
  67. tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
  68. tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
  69. tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
  70. tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
  71. tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
  72. tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
  73. tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
  74. tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
  75. tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
  76. tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
  77. tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
  78. tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
  79. tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
  80. tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
  81. tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
  82. tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
  83. tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
  84. tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
  85. tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
  86. tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
  87. tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
  88. tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
  89. tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
  90. tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
  91. tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
  92. tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
  93. tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
  94. tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
  95. tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
  96. tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
  97. tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
  98. tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
  99. tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
  100. tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
  101. tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
  102. tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
  103. tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
  104. tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
  105. tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
  106. tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
  107. tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
  108. tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
  109. tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
  110. tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
  111. tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
  112. tpyc/_data/runtime/cpp/third_party/README.md +58 -0
  113. tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
  114. tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
  115. tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
  116. tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
  117. tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
  118. tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
  119. tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
  120. tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
  121. tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
  122. tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
  123. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
  124. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
  125. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
  126. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
  127. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
  128. tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
  129. tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
  130. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
  131. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
  132. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
  133. tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
  134. tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
  135. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
  136. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
  137. tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
  138. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
  139. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
  140. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
  141. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
  142. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
  143. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
  144. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
  145. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
  146. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
  147. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
  148. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
  149. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
  150. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
  151. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
  152. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
  153. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
  154. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
  155. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
  156. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
  157. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
  158. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
  159. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
  160. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
  161. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
  162. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
  163. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
  164. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
  165. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
  166. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
  167. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
  168. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
  169. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
  170. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
  171. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
  172. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
  173. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
  174. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
  175. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
  176. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
  177. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
  178. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
  179. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
  180. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
  181. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
  182. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
  183. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
  184. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
  185. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
  186. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
  187. tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
  188. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
  189. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
  190. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
  191. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
  192. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
  193. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
  194. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
  195. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
  196. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
  197. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
  198. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
  199. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
  200. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
  201. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
  202. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
  203. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
  204. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
  205. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
  206. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
  207. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
  208. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
  209. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
  210. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
  211. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
  212. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
  213. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
  214. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
  215. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
  216. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
  217. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
  218. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
  219. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
  220. tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
  221. tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
  222. tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
  223. tpyc/build/__init__.py +7 -0
  224. tpyc/build/pcre2.py +122 -0
  225. tpyc/build/third_party.py +413 -0
  226. tpyc/cli.py +822 -0
  227. tpyc/codegen_cpp/__init__.py +18 -0
  228. tpyc/codegen_cpp/builtins.py +484 -0
  229. tpyc/codegen_cpp/context.py +2064 -0
  230. tpyc/codegen_cpp/expressions.py +5940 -0
  231. tpyc/codegen_cpp/functions.py +1913 -0
  232. tpyc/codegen_cpp/gen_async.py +3258 -0
  233. tpyc/codegen_cpp/gen_generators.py +657 -0
  234. tpyc/codegen_cpp/generator.py +2258 -0
  235. tpyc/codegen_cpp/match.py +1997 -0
  236. tpyc/codegen_cpp/param_const.py +172 -0
  237. tpyc/codegen_cpp/protocols.py +907 -0
  238. tpyc/codegen_cpp/records.py +1654 -0
  239. tpyc/codegen_cpp/resumable_cfg.py +1651 -0
  240. tpyc/codegen_cpp/statements.py +4963 -0
  241. tpyc/codegen_cpp/string_dispatch.py +76 -0
  242. tpyc/codegen_cpp/test_context.py +46 -0
  243. tpyc/codegen_cpp/test_param_const.py +113 -0
  244. tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
  245. tpyc/codegen_cpp/type_resolution.py +53 -0
  246. tpyc/codegen_cpp/types.py +436 -0
  247. tpyc/codegen_cpp/variant_access.py +135 -0
  248. tpyc/coercions.py +749 -0
  249. tpyc/compilation_context.py +57 -0
  250. tpyc/compiler.py +3945 -0
  251. tpyc/cycle_detection.py +358 -0
  252. tpyc/diagnostics.py +135 -0
  253. tpyc/dump_types.py +353 -0
  254. tpyc/frontend_diagnostics.py +47 -0
  255. tpyc/frontend_ir/__init__.py +140 -0
  256. tpyc/frontend_ir/lower.py +1098 -0
  257. tpyc/frontend_ir/nodes.py +718 -0
  258. tpyc/frontend_ir/resolver_adapter.py +151 -0
  259. tpyc/frontend_plugin.py +209 -0
  260. tpyc/install_docs.py +81 -0
  261. tpyc/liveness.py +756 -0
  262. tpyc/macro_api.py +1724 -0
  263. tpyc/macro_loader.py +497 -0
  264. tpyc/module_names.py +64 -0
  265. tpyc/modules/__init__.py +31 -0
  266. tpyc/modules/defs.py +89 -0
  267. tpyc/modules/registry.py +36 -0
  268. tpyc/modules/resolver.py +192 -0
  269. tpyc/modules/type_resolution.py +629 -0
  270. tpyc/namespace.py +172 -0
  271. tpyc/parse/__init__.py +84 -0
  272. tpyc/parse/imports.py +490 -0
  273. tpyc/parse/nodes.py +1732 -0
  274. tpyc/parse/parser.py +4043 -0
  275. tpyc/parse/resolve_refs.py +466 -0
  276. tpyc/parse/type_resolver.py +1060 -0
  277. tpyc/prescan.py +254 -0
  278. tpyc/qnames.py +149 -0
  279. tpyc/repl.py +529 -0
  280. tpyc/repl_backends.py +848 -0
  281. tpyc/sema/__init__.py +21 -0
  282. tpyc/sema/analyzer.py +3625 -0
  283. tpyc/sema/bound_check.py +72 -0
  284. tpyc/sema/builder_trace.py +684 -0
  285. tpyc/sema/calls.py +5406 -0
  286. tpyc/sema/compatibility.py +2107 -0
  287. tpyc/sema/context.py +1243 -0
  288. tpyc/sema/expressions.py +3737 -0
  289. tpyc/sema/flow_facts.py +199 -0
  290. tpyc/sema/init_tracker.py +150 -0
  291. tpyc/sema/list_literals.py +69 -0
  292. tpyc/sema/literal_utils.py +27 -0
  293. tpyc/sema/local_deduction.py +1088 -0
  294. tpyc/sema/macros.py +179 -0
  295. tpyc/sema/match.py +1177 -0
  296. tpyc/sema/method_expansion.py +347 -0
  297. tpyc/sema/methods.py +2197 -0
  298. tpyc/sema/mutation_propagation.py +268 -0
  299. tpyc/sema/narrowing.py +857 -0
  300. tpyc/sema/numeric_lattice.py +160 -0
  301. tpyc/sema/operators.py +402 -0
  302. tpyc/sema/overloads.py +841 -0
  303. tpyc/sema/protocols.py +1209 -0
  304. tpyc/sema/reach_analysis.py +202 -0
  305. tpyc/sema/registration.py +3156 -0
  306. tpyc/sema/scope_tracker.py +193 -0
  307. tpyc/sema/statements.py +4426 -0
  308. tpyc/sema/type_ops.py +1879 -0
  309. tpyc/sema/value_range.py +181 -0
  310. tpyc/symbol_binding.py +259 -0
  311. tpyc/test_c3_mro.py +208 -0
  312. tpyc/test_cli_argv.py +52 -0
  313. tpyc/test_compiler.py +559 -0
  314. tpyc/test_contains_type_param.py +101 -0
  315. tpyc/test_cycle_detection.py +221 -0
  316. tpyc/test_dump_types.py +225 -0
  317. tpyc/test_install_docs.py +65 -0
  318. tpyc/test_local_cpp_form.py +135 -0
  319. tpyc/test_macro_loader.py +76 -0
  320. tpyc/test_method_expansion.py +254 -0
  321. tpyc/test_nominal_identity.py +182 -0
  322. tpyc/test_overloads.py +410 -0
  323. tpyc/test_parse.py +303 -0
  324. tpyc/test_parse_type_ref.py +506 -0
  325. tpyc/test_parse_version_info.py +58 -0
  326. tpyc/test_reach_analysis.py +72 -0
  327. tpyc/test_ref_type.py +216 -0
  328. tpyc/test_send_sync_substitution.py +276 -0
  329. tpyc/test_tuple_mutation_propagation.py +206 -0
  330. tpyc/test_type_def_registry.py +1729 -0
  331. tpyc/test_union_types.py +195 -0
  332. tpyc/type_def_registry.py +975 -0
  333. tpyc/typesys.py +5104 -0
@@ -0,0 +1,1060 @@
1
+ """
2
+ TypeResolver -- name-to-TpyType resolution for parser-emitted TypeRefNodes.
3
+
4
+ Lives under `parse/` because it is a parser-internal concern: it binds
5
+ the names the walker emits to concrete `TpyType` values, using live
6
+ parser state (registry, imports, local_defs, ...) via a back-reference
7
+ to its owning `Parser`. Parse-time callers (@builtin_decorator stubs,
8
+ nested defs, type-param bounds, macro fragments) invoke `resolve()`
9
+ directly. The module-level walker `parse.resolve_refs.resolve_refs`
10
+ calls it once per annotation site after the parser finishes.
11
+
12
+ The 9 attributes and 2 methods read off the back-reference are
13
+ documented in the `TypeResolver` class docstring -- that coupling stays
14
+ intra-package (parser + resolver evolve together) and does not surface
15
+ in sema.
16
+ """
17
+ from __future__ import annotations
18
+ import ast
19
+ from typing import TYPE_CHECKING, Callable
20
+
21
+ from ..typesys import (
22
+ TpyType, NominalType, AliasRef, PtrType, OwnType, ReadonlyType, AutoReadonlyType,
23
+ AutoOwnType, FinalType, ClassVarType, OptionalType, VoidType, UnionType, TupleType,
24
+ CallableType, make_union, make_fn_type,
25
+ TypeParamRef, TypeParamKind, LiteralType, LiteralTag,
26
+ INT32, VOID, NONE, STR, STRING, STRVIEW, CHAR, BYTES, BYTEARRAY, BYTESVIEW,
27
+ BOOL, FLOAT, FLOAT32, BIGINT, SELF, BASIC_SLICE, SLICE, ANY, AnyType,
28
+ ALL_FIXED_INTS,
29
+ substitute_type_params_structural,
30
+ )
31
+ from .. import qnames
32
+ from ..type_def_registry import (
33
+ TypeDef, get_type_def, find_factory_by_simple_name, find_factory_in_module,
34
+ )
35
+ from .nodes import (
36
+ ParseError, ResolutionFailure, SourceLocation,
37
+ TpyTypeRef, TpyUnionRef, TpyCallableRef, TpyLiteralRef, ResolverInputNode,
38
+ )
39
+ from .imports import _IMPLICIT_MODULES
40
+
41
+ if TYPE_CHECKING:
42
+ from .parser import Parser
43
+
44
+
45
+ # Map of fixed-int type names to their singleton instances. Used by
46
+ # the resolver for bare-name lookup and by sema's field-default inferrer
47
+ # (`analyzer._infer_field_type_from_default`). Parser-side callers that
48
+ # only need name membership use a local `_FIXED_INT_NAMES` frozenset
49
+ # instead of pulling in the singleton values.
50
+ _FIXED_INT_MAP: dict[str, TpyType] = {str(t): t for t in ALL_FIXED_INTS}
51
+
52
+
53
+ def _is_ptr_shaped(t: TpyType) -> bool:
54
+ """True when `t` already lowers to `T*` -- a `Ptr[T]` or a readonly-wrapped
55
+ `Ptr[T]`. Wrapping such a type in `Optional[...]` / `| None` is redundant
56
+ because `Ptr[T]` is already nullable. Used by the resolver to warn at the
57
+ user's spelling site, before `OptionalType.__new__` collapses the wrapper.
58
+ """
59
+ if isinstance(t, PtrType):
60
+ return True
61
+ if isinstance(t, ReadonlyType) and isinstance(t.wrapped, PtrType):
62
+ return True
63
+ return False
64
+
65
+
66
+ class TypeResolver:
67
+ """Resolves TypeRefNode -> TpyType using live parser state.
68
+
69
+ Holds a back-reference to its owning `Parser` and reads nine
70
+ parser attributes each call so container growth during parse --
71
+ and per-parse re-assignment of mutable containers at the top of
72
+ each `parse()` -- stays visible:
73
+
74
+ registry, _imports, _type_param_scope, _module_class_names,
75
+ _module_type_alias_names, _reverse_module_aliases,
76
+ _nested_type_scope, _local_defs, _bare_module_imports
77
+
78
+ Plus two parser-owned helpers that FragmentParser can override
79
+ for lenient macro-fragment parsing:
80
+
81
+ _resolve_type_name(name)
82
+ _raise_unresolved_import_error(name, node=None, *, loc=None)
83
+
84
+ The coupling is intra-package (parser + resolver evolve together);
85
+ no sema code reaches through here.
86
+ """
87
+
88
+ def __init__(self, parser: 'Parser'):
89
+ self._parser = parser
90
+ # Active alias-body context: set by sema's alias pass while resolving
91
+ # the RHS of `type X = ...`; consulted by `_resolve_registered_type`
92
+ # so same-body self-references (e.g. `list[X]` inside X's RHS)
93
+ # produce a NominalType(name) placeholder rather than an "Unknown
94
+ # type" error. Recursive calls inside resolve() inherit this naturally.
95
+ self._pending_alias: str | None = None
96
+
97
+ @property
98
+ def registry(self):
99
+ """Expose the parser's TypeRegistry so sema can register resolved
100
+ aliases / read bookkeeping without reaching through `_parser`."""
101
+ return self._parser.registry
102
+
103
+ def canonicalize_import_table(
104
+ self, lookup: 'Callable[[str, str], tuple[str, str] | None]',
105
+ ) -> None:
106
+ """Canonicalize the parser's import table to (defining_module, name).
107
+
108
+ Called by the compiler between parse and sema so subsequent
109
+ `resolve()` calls see defining-module tuples for re-exported
110
+ symbols and can mint authoritative `_module_qname` on the first
111
+ pass.
112
+ """
113
+ self._parser._imports.canonicalize_name_index(lookup)
114
+
115
+ def refresh_module_aliases(self) -> None:
116
+ """Rebuild the reverse-alias cache from the current module_aliases.
117
+
118
+ Called by the compiler after promoting `from pkg import submod` to
119
+ a full submodule import (which appends to ``ast.module_aliases``);
120
+ the parser builds the reverse map once at parse time, so post-parse
121
+ promotions need an explicit refresh to stay visible to qualified-name
122
+ lookup.
123
+ """
124
+ self._parser._reverse_module_aliases = {
125
+ alias: canonical
126
+ for canonical, alias in self._parser._module_aliases.items()
127
+ }
128
+
129
+ def index_imported_name(
130
+ self, local_name: str, source_module: str, original_name: str,
131
+ ) -> None:
132
+ """Add a `(source_module, original_name)` entry to the parser's
133
+ name index for `local_name` if not already present.
134
+
135
+ Called by `Compiler._expand_star_imports_for_module` after
136
+ compile-time star-import expansion so the parser-level
137
+ `resolve_refs` pass sees star-imported names when resolving
138
+ type annotations.
139
+ """
140
+ self._parser._imports.index_imported_name(
141
+ local_name, source_module, original_name)
142
+
143
+ # ------------------------------------------------------------------
144
+ # Public entry point
145
+ # ------------------------------------------------------------------
146
+
147
+ def resolve(
148
+ self, ref: ResolverInputNode,
149
+ type_param_scope: dict[str, TypeParamKind] | None = None,
150
+ *, pending_alias: str | None = None,
151
+ is_type_arg: bool = False,
152
+ ) -> TpyType:
153
+ """Resolve a parser-walker-emitted type reference to a TpyType.
154
+
155
+ Accepts `ResolverInputNode` (the four walker outputs: TpyTypeRef,
156
+ TpyUnionRef, TpyCallableRef, TpyLiteralRef). `TpyInferFromDefaultRef`
157
+ is deliberately *not* a valid input -- it's a field-storage marker
158
+ that sema catches explicitly in its field loop and never routes
159
+ through the resolver.
160
+
161
+ `pending_alias`, when set (typically by sema's alias pass), enables
162
+ same-body self-ref placeholder behaviour for recursive aliases like
163
+ `type JsonValue = str | list[JsonValue]`. It is saved on the
164
+ resolver for the duration of this call so recursive re-entries
165
+ inherit the context, and restored on exit.
166
+
167
+ `is_type_arg=True` flips bare `None` resolution from `VoidType`
168
+ (the function-return-shape singleton) to `NoneType` (the value-
169
+ carrying unit type, lowered to `std::monostate`). True at every
170
+ annotation slot except the function-return slot (resolved via
171
+ `resolve_refs._resolve_return_slot`); union members and Optional/
172
+ Final/ClassVar inners also stay False so VoidType-marker semantics
173
+ (Union/Optional collapse, redundant `Any | None`) survive. The
174
+ flag name is historical and worth renaming to `is_value_position`
175
+ if/when this materializes as a THIR-level mark.
176
+ """
177
+ if pending_alias is not None:
178
+ prev = self._pending_alias
179
+ self._pending_alias = pending_alias
180
+ try:
181
+ return self._resolve_ref(ref, type_param_scope, is_type_arg=is_type_arg)
182
+ finally:
183
+ self._pending_alias = prev
184
+ return self._resolve_ref(ref, type_param_scope, is_type_arg=is_type_arg)
185
+
186
+ def resolve_lenient(
187
+ self, ref: ResolverInputNode,
188
+ type_param_scope: dict[str, TypeParamKind] | None = None,
189
+ *, is_type_arg: bool = False,
190
+ ) -> TpyType:
191
+ """Resolve like `resolve()` but, on a name-resolution failure for a
192
+ bare `TpyTypeRef`, construct a `NominalType(name, args)` placeholder
193
+ instead of raising. Used by FragmentParser so macro fragments can
194
+ reference symbols not visible to the fragment-level resolver --
195
+ sema re-resolves them in the final context.
196
+
197
+ Failure identification is structural via the `ResolutionFailure`
198
+ subclass (raised only at the three bare/dotted/generic
199
+ unknown-name sites). Structural errors (Own-in-union, Callable
200
+ arity, etc.) surface as plain `ParseError` and still propagate.
201
+ Non-`TpyTypeRef` inputs are not leniency targets -- they delegate
202
+ to `resolve()` unchanged.
203
+ """
204
+ try:
205
+ return self.resolve(ref, type_param_scope, is_type_arg=is_type_arg)
206
+ except ResolutionFailure:
207
+ if not isinstance(ref, TpyTypeRef):
208
+ raise
209
+ resolved_args: tuple = tuple(
210
+ a if isinstance(a, int)
211
+ else self.resolve_lenient(a, type_param_scope, is_type_arg=True)
212
+ for a in ref.args
213
+ )
214
+ return NominalType(ref.name, resolved_args)
215
+
216
+ def _resolve_ref(
217
+ self, ref: ResolverInputNode,
218
+ type_param_scope: dict[str, TypeParamKind] | None,
219
+ *, is_type_arg: bool = False,
220
+ ) -> TpyType:
221
+ """Internal resolver. Recursive calls to `self.resolve(...)` without
222
+ `pending_alias` re-enter the public method, which skips the
223
+ save/restore and forwards straight here.
224
+
225
+ `is_type_arg` see `resolve()` docstring -- forwarded into the
226
+ bare-`None` branch and into `_resolve_primitive_type`.
227
+ """
228
+ parser = self._parser
229
+ if type_param_scope is None:
230
+ type_param_scope = parser._type_param_scope
231
+
232
+ # Union
233
+ if isinstance(ref, TpyUnionRef):
234
+ # Union members keep VoidType marker semantics (collapse to
235
+ # Optional, redundant-Any check, Ptr-already-nullable warning).
236
+ # If the outer context is a type-arg slot, the union as a whole
237
+ # is still the type at that slot, not each member individually.
238
+ parsed = [self.resolve(m, type_param_scope) for m in ref.members]
239
+ non_none = [t for t in parsed if not isinstance(t, VoidType)]
240
+ # Any is the universal supertype -- combining it with None or
241
+ # any other type is redundant.
242
+ for t in parsed:
243
+ if isinstance(t, AnyType):
244
+ has_none = any(isinstance(p, VoidType) for p in parsed)
245
+ if has_none:
246
+ raise ParseError(
247
+ "Any | None is redundant -- Any already accepts None",
248
+ loc=ref.loc,
249
+ )
250
+ if len(parsed) > 1:
251
+ raise ParseError(
252
+ "Any | T is redundant -- Any is the universal supertype",
253
+ loc=ref.loc,
254
+ )
255
+ if len(non_none) > 1:
256
+ for t in non_none:
257
+ if isinstance(t, OwnType):
258
+ unwrapped = [
259
+ p.wrapped if isinstance(p, OwnType) else p for p in non_none
260
+ ]
261
+ raise ParseError(
262
+ f"Own[{t.wrapped}] cannot be a union member. "
263
+ f"Use Own[...] around the whole union instead: "
264
+ f"Own[{' | '.join(str(u) for u in unwrapped)}]",
265
+ loc=ref.loc,
266
+ )
267
+ readonly_count = sum(1 for t in parsed if isinstance(t, ReadonlyType))
268
+ non_none_count = sum(1 for t in parsed if not isinstance(t, VoidType))
269
+ if readonly_count > 0 and readonly_count < non_none_count:
270
+ raise ParseError(
271
+ "Cannot mix readonly and non-readonly types in a union",
272
+ loc=ref.loc,
273
+ )
274
+ # Redundant `Ptr[T] | None` (upstream #17). `Ptr[T]` is already
275
+ # nullable and the collapse rule erases the wrapper; warn at the
276
+ # user's spelling site so the redundant form doesn't drift back in.
277
+ if non_none_count == 1 and any(isinstance(t, VoidType) for t in parsed):
278
+ non_none = next(t for t in parsed if not isinstance(t, VoidType))
279
+ if _is_ptr_shaped(non_none):
280
+ parser._warn_at_loc(
281
+ f"`{non_none} | None` is redundant -- `{non_none}` is "
282
+ f"already nullable; drop the `| None`",
283
+ ref.loc,
284
+ )
285
+ if readonly_count > 0:
286
+ unwrapped = [
287
+ t.wrapped if isinstance(t, ReadonlyType) else t for t in parsed
288
+ ]
289
+ return ReadonlyType(make_union(*unwrapped))
290
+ return make_union(*parsed)
291
+
292
+ # Callable / Fn
293
+ if isinstance(ref, TpyCallableRef):
294
+ param_types = tuple(
295
+ self.resolve(p, type_param_scope, is_type_arg=True) for p in ref.params
296
+ )
297
+ return_type = self.resolve(ref.return_type, type_param_scope)
298
+ if ref.kind == "Fn":
299
+ return make_fn_type(param_types, return_type)
300
+ return CallableType(param_types, return_type)
301
+
302
+ # Literal
303
+ if isinstance(ref, TpyLiteralRef):
304
+ tag = ref.values[0].tag
305
+ base_type = {
306
+ LiteralTag.STR: STR, LiteralTag.INT: INT32, LiteralTag.BOOL: BOOL,
307
+ }[tag]
308
+ return LiteralType(base_type, ref.values)
309
+
310
+ # TpyTypeRef
311
+ assert isinstance(ref, TpyTypeRef), f"Unknown ref kind: {type(ref).__name__}"
312
+ name = ref.name
313
+
314
+ # "None" (void) -- emitted by walker for ast.Constant(None)
315
+ if name == "None" and not ref.args:
316
+ return NONE if is_type_arg else VOID
317
+
318
+ # Structural wrappers (canonical `mod:Name` names set by the walker
319
+ # only when the source name actually resolved to the expected module).
320
+ # The `:` separator avoids any collision with raw user-source names
321
+ # (including dotted forms like "typing.Optional" written without
322
+ # `import typing`), so raw-name TpyTypeRefs fall through to the
323
+ # generic path where the resolver's unresolved-name error fires.
324
+ if ref.args and name in (
325
+ "tpy:Ptr", "tpy:Own", "tpy:readonly", "tpy:auto_readonly",
326
+ "tpy:auto_own", "typing:Optional", "typing:Final", "typing:ClassVar",
327
+ ):
328
+ inner_arg = ref.args[0]
329
+ assert not isinstance(inner_arg, int), \
330
+ f"structural wrapper {name} cannot take int arg"
331
+ # Own/Ptr/readonly/auto_* are value-bearing slots (Own[None] etc.
332
+ # must produce NoneType). Optional/Final/ClassVar keep the outer
333
+ # context: Optional preserves the union-marker semantics, Final/
334
+ # ClassVar are annotation modifiers at whatever depth they appear.
335
+ inner_is_type_arg = name in (
336
+ "tpy:Ptr", "tpy:Own", "tpy:readonly",
337
+ "tpy:auto_readonly", "tpy:auto_own",
338
+ ) or is_type_arg
339
+ inner = self.resolve(
340
+ inner_arg, type_param_scope, is_type_arg=inner_is_type_arg,
341
+ )
342
+ if name == "tpy:Ptr":
343
+ if isinstance(inner, ReadonlyType):
344
+ return PtrType(inner.wrapped, is_readonly=True)
345
+ return PtrType(inner)
346
+ if name == "tpy:Own":
347
+ if isinstance(inner, AnyType):
348
+ raise ParseError(
349
+ "Own[Any] is redundant -- Any is already owning",
350
+ loc=ref.loc,
351
+ )
352
+ return OwnType(inner)
353
+ if name == "tpy:readonly":
354
+ return ReadonlyType(inner)
355
+ if name == "tpy:auto_readonly":
356
+ return AutoReadonlyType(inner)
357
+ if name == "tpy:auto_own":
358
+ return AutoOwnType(inner)
359
+ if name == "typing:Optional":
360
+ if isinstance(inner, AnyType):
361
+ raise ParseError(
362
+ "Optional[Any] is redundant -- Any already accepts None",
363
+ loc=ref.loc,
364
+ )
365
+ if _is_ptr_shaped(inner):
366
+ parser._warn_at_loc(
367
+ f"`Optional[{inner}]` is redundant -- `{inner}` is "
368
+ f"already nullable; use `{inner}` directly",
369
+ ref.loc,
370
+ )
371
+ return OptionalType(inner)
372
+ if name == "typing:Final":
373
+ return FinalType(inner)
374
+ if name == "typing:ClassVar":
375
+ return ClassVarType(inner)
376
+
377
+ # tuple
378
+ if name == "builtins:tuple" and ref.args:
379
+ elements = tuple(
380
+ self.resolve(a, type_param_scope, is_type_arg=True)
381
+ for a in ref.args if not isinstance(a, int)
382
+ )
383
+ return TupleType(elements)
384
+
385
+ # Bare name (no args)
386
+ if not ref.args:
387
+ # Type param scope
388
+ if type_param_scope and name in type_param_scope:
389
+ kind = type_param_scope[name]
390
+ return TypeParamRef(name, kind=kind)
391
+
392
+ # Dotted (qualified or nested class)
393
+ if "." in name:
394
+ parts = name.split(".")
395
+ # 2-level qualified (mod.Attr)
396
+ if len(parts) == 2:
397
+ mod, attr = parts
398
+ resolved_q = self._resolve_qualified_type_name_str(mod, attr)
399
+ if resolved_q:
400
+ primitive = self._resolve_primitive_type(
401
+ *resolved_q, loc=ref.loc, is_type_arg=is_type_arg)
402
+ if primitive is not None:
403
+ return primitive
404
+ registered = self._resolve_registered_type(
405
+ resolved_q[1], loc=ref.loc, resolved=True)
406
+ if registered is not None:
407
+ return self._upgrade_from_type_def(
408
+ registered, resolved_q, loc=ref.loc)
409
+ # Submodule-import path (`from pkg import submod`):
410
+ # `attr` is not in the importer's local registry but
411
+ # is exported by the source module. Consult the source
412
+ # module directly so the type carries its cross-module
413
+ # qname.
414
+ cross = self._resolve_qualified_cross_module(
415
+ *resolved_q, loc=ref.loc)
416
+ if cross is not None:
417
+ return cross
418
+ # Nested dotted class: Outer.Inner, Outer.Mid.Inner, ...
419
+ dotted = self._resolve_dotted_class_name_str(name)
420
+ if dotted is not None:
421
+ rinfo = parser.registry.get_record(dotted)
422
+ if rinfo is not None:
423
+ qname = self._user_record_qname(dotted, None)
424
+ return NominalType(dotted, _module_qname=qname)
425
+ enum_type = parser.registry.get_enum(dotted)
426
+ if enum_type is not None:
427
+ return enum_type
428
+ # Helpful error for unimported implicit module
429
+ self._raise_unresolved_qualified_error_str(name, ref.loc)
430
+ raise ResolutionFailure(
431
+ f"Unsupported qualified type: {name}", loc=ref.loc,
432
+ )
433
+
434
+ # Bare name resolution
435
+ resolved = parser._resolve_type_name(name)
436
+ if resolved:
437
+ primitive = self._resolve_primitive_type(
438
+ *resolved, loc=ref.loc, is_type_arg=is_type_arg)
439
+ if primitive is not None:
440
+ return primitive
441
+ resolved_name = resolved[1] if resolved else name
442
+ registered = self._resolve_registered_type(
443
+ resolved_name, loc=ref.loc, resolved=bool(resolved))
444
+ if registered is not None:
445
+ # Mint _module_qname for cross-module user refs. The
446
+ # builtin path handles type-factory-backed names (list,
447
+ # Array, ...); the canonical-import path covers user
448
+ # records / protocols / enums imported from other
449
+ # modules -- `canonicalize_import_table` has already
450
+ # rewritten the tuple to point at the defining module,
451
+ # so `{module}.{original}` is the authoritative qname.
452
+ # For canonical protocols we also upgrade is_protocol /
453
+ # is_dynamic_protocol from `TypeDef.protocol` (the dep
454
+ # module's sema has already attached it).
455
+ if (resolved and isinstance(registered, NominalType)
456
+ and not registered._module_qname):
457
+ module, original = resolved
458
+ candidate_qname = f"{module}.{original}"
459
+ candidate_td = get_type_def(candidate_qname)
460
+ is_builtin = (
461
+ parser.registry.get_builtin_type_key(registered.name) is not None
462
+ or (candidate_td is not None and candidate_td.type_factory is not None)
463
+ )
464
+ if is_builtin or parser._imports.is_canonical(name):
465
+ is_protocol = registered.is_protocol
466
+ is_dynamic_protocol = registered.is_dynamic_protocol
467
+ if candidate_td is not None and candidate_td.protocol is not None:
468
+ proto = candidate_td.protocol
469
+ if proto.type_params:
470
+ # Match sema block-3's original error class so
471
+ # diag.txt formats as `file:line: error: ...`
472
+ # (ParseError would go through the `Parse
473
+ # error: ...` CLI path instead).
474
+ from ..diagnostics import SemanticError
475
+ raise SemanticError(
476
+ f"Generic protocol '{registered.name}' requires type arguments: "
477
+ f"{registered.name}[{', '.join(proto.type_params)}]",
478
+ loc=ref.loc,
479
+ )
480
+ is_protocol = True
481
+ is_dynamic_protocol = proto.is_dynamic
482
+ registered = NominalType(
483
+ registered.name, registered.type_args,
484
+ is_protocol, candidate_qname, is_dynamic_protocol,
485
+ )
486
+ return registered
487
+ raise ResolutionFailure(f"Unknown type: {name}", loc=ref.loc)
488
+
489
+ # Generic form (name + args) -- bare or dotted
490
+
491
+ # Self-reference inside the body of the alias currently being
492
+ # resolved (`type Tree[T] = T | list[Tree[T]]` -- the inner
493
+ # `Tree[T]`). The alias isn't yet registered, so the normal
494
+ # lookup path would fail. Emit an `AliasRef` placeholder so
495
+ # `_contains_self_reference` detects it and tags the alias
496
+ # recursive. Resolve and carry the `[...]` args (restoring the
497
+ # "Unknown type" diagnostic for malformed args like
498
+ # `list[Tree[Undefined]]`) and arity-check against the alias's
499
+ # declared params; the same-args identity rule is enforced later
500
+ # by the recursive-union validator.
501
+ if self._pending_alias is not None and name == self._pending_alias:
502
+ expected = len(type_param_scope) if type_param_scope else 0
503
+ actual = len(ref.args)
504
+ if actual != expected:
505
+ raise ResolutionFailure(
506
+ f"Recursive alias '{name}' self-reference takes "
507
+ f"{expected} type argument{'s' if expected != 1 else ''}, "
508
+ f"got {actual}",
509
+ loc=ref.loc,
510
+ )
511
+ resolved_args = tuple(
512
+ a if isinstance(a, int)
513
+ else self.resolve(a, type_param_scope, is_type_arg=True)
514
+ for a in ref.args
515
+ )
516
+ return AliasRef(
517
+ name, module=parser._public_module(), args=resolved_args)
518
+
519
+ if "." in name:
520
+ parts = name.split(".")
521
+ if len(parts) == 2:
522
+ mod, attr = parts
523
+ resolved = self._resolve_qualified_type_name_str(mod, attr)
524
+ else:
525
+ resolved = None
526
+ else:
527
+ resolved = parser._resolve_type_name(name)
528
+
529
+ resolved_container = resolved[1] if resolved else name
530
+
531
+ # Module-defined generic types (list, Array, Span, ...)
532
+ if resolved_container and (td := find_factory_by_simple_name(resolved_container)):
533
+ if not resolved and td.qname.startswith("tpy."):
534
+ parser._raise_unresolved_import_error(name, loc=ref.loc)
535
+ return self._resolve_generic_type_from_ref(
536
+ ref, resolved_container, td, type_param_scope)
537
+
538
+ # Imported generic from a module
539
+ if resolved:
540
+ source_module, original_name = resolved
541
+ if td := find_factory_in_module(original_name, source_module):
542
+ return self._resolve_generic_type_from_ref(
543
+ ref, resolved_container, td, type_param_scope)
544
+ elif "." not in name and name:
545
+ if import_source := parser._imports.get_import_source(name):
546
+ source_module, original_name = import_source
547
+ if td := find_factory_in_module(original_name, source_module):
548
+ return self._resolve_generic_type_from_ref(
549
+ ref, resolved_container, td, type_param_scope)
550
+
551
+ # Qualified name with missing module import -- only for dotted subscripts
552
+ # where qualified resolution failed.
553
+ if "." in name and resolved is None:
554
+ self._raise_unresolved_qualified_error_str(name, ref.loc)
555
+
556
+ # User-defined generic protocols
557
+ if user_protocol := parser.registry.scan_by_short_name(resolved_container):
558
+ if user_protocol.type_params:
559
+ expected = len(user_protocol.type_params)
560
+ if len(ref.args) != expected:
561
+ raise ParseError(
562
+ f"{resolved_container} requires exactly {expected} type parameters",
563
+ loc=ref.loc,
564
+ )
565
+ type_args = tuple(
566
+ a if isinstance(a, int)
567
+ else self.resolve(a, type_param_scope, is_type_arg=True)
568
+ for a in ref.args
569
+ )
570
+ qname = (f"{user_protocol.module}.{resolved_container}"
571
+ if user_protocol.module else None)
572
+ return NominalType(
573
+ resolved_container, type_args, is_protocol=True,
574
+ _module_qname=qname,
575
+ is_dynamic_protocol=user_protocol.is_dynamic,
576
+ )
577
+
578
+ # Generic type alias use site (`Pair[int]`). Phase 1 of generic
579
+ # recursive aliases (see docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md):
580
+ # substitute non-recursive generic aliases at use sites; recursive
581
+ # ones stay rejected for Phase 2. Handle local, short-name-imported,
582
+ # and dotted-qualified forms via one helper.
583
+ alias_info = self._lookup_generic_alias_info(name, resolved_container, resolved)
584
+ if alias_info is not None and alias_info.type_params:
585
+ return self._resolve_generic_alias_use(
586
+ ref, resolved_container, alias_info, type_param_scope,
587
+ )
588
+
589
+ # Unresolved bare (non-dotted) name -- helpful import hint
590
+ if not resolved and "." not in name and name:
591
+ parser._raise_unresolved_import_error(name, loc=ref.loc)
592
+ if (resolved or parser.registry.get_record(resolved_container) is not None
593
+ or resolved_container in parser._module_class_names):
594
+ type_args = self._resolve_record_type_args_from_ref(
595
+ ref, resolved_container, type_param_scope)
596
+ canonical = "." not in name and parser._imports.is_canonical(name)
597
+ qname = self._user_record_qname(
598
+ resolved_container, resolved, canonical=canonical)
599
+ # Upgrade is_protocol / is_dynamic_protocol for cross-module
600
+ # canonical protocol refs via TypeDef.protocol (replaces the
601
+ # old sema block-3 substitution).
602
+ is_protocol = False
603
+ is_dynamic_protocol = False
604
+ if canonical and qname:
605
+ td = get_type_def(qname)
606
+ if td is not None and td.protocol is not None:
607
+ is_protocol = True
608
+ is_dynamic_protocol = td.protocol.is_dynamic
609
+ return NominalType(
610
+ resolved_container, type_args, is_protocol,
611
+ qname, is_dynamic_protocol,
612
+ )
613
+
614
+ # Nested generic records (Outer.Inner[T])
615
+ if "." in name:
616
+ dotted = self._resolve_dotted_class_name_str(name)
617
+ if dotted is not None and parser.registry.get_record(dotted) is not None:
618
+ type_args = self._resolve_record_type_args_from_ref(
619
+ ref, dotted, type_param_scope)
620
+ qname = self._user_record_qname(dotted, None)
621
+ return NominalType(dotted, type_args, _module_qname=qname)
622
+
623
+ raise ResolutionFailure(f"Unknown generic type: {name}", loc=ref.loc)
624
+
625
+ def _lookup_generic_alias_info(
626
+ self, name: str, resolved_container: str,
627
+ resolved: 'tuple[str, str] | None',
628
+ ) -> 'TypeAliasInfo | None':
629
+ """Find a generic alias's TypeAliasInfo across local + imported forms.
630
+
631
+ Handles:
632
+ - Local: `type Pair[T] = ...` in the current module.
633
+ - Imported short name: `from lib_a import Pair` then `Pair[int]`.
634
+ - Dotted qualified: `lib_a.Pair[int]` (resolved is the
635
+ (source_module, original_name) tuple).
636
+
637
+ Returns None if the name isn't a registered alias anywhere; the
638
+ caller then continues with the record / unknown-name fallback.
639
+ """
640
+ parser = self._parser
641
+ # Local registry first -- covers same-module aliases and aliases
642
+ # whose import was already materialised into the parser registry.
643
+ local = parser.registry.get_type_alias_info(name)
644
+ if local is not None:
645
+ return local
646
+ # Cross-module: consult the source module's ModuleInfo for the
647
+ # original-named alias. Works for both short-name imports
648
+ # (`resolved == (source_module, original_name)`) and dotted
649
+ # qualification.
650
+ if resolved is not None:
651
+ source_module, original_name = resolved
652
+ mod_info = parser.registry.modules.get(source_module)
653
+ if mod_info is not None and mod_info.type_aliases:
654
+ return mod_info.type_aliases.get(original_name)
655
+ return None
656
+
657
+ def _resolve_generic_alias_use(
658
+ self, ref: 'TpyTypeRef', name: str, alias_info: 'TypeAliasInfo',
659
+ type_param_scope: 'dict[str, TypeParamKind] | None',
660
+ ) -> TpyType:
661
+ """Expand a use of a generic type alias at the use site.
662
+
663
+ Two outcomes:
664
+ - Non-recursive aliases (`type Pair[T] = tuple[T, T]`): build
665
+ `{T_i: arg_i}` and apply structural substitution to the body.
666
+ The alias name disappears from the type tree downstream.
667
+ - Recursive aliases (`type Tree[T] = T | list[Tree[T]]`): emit an
668
+ `AliasRef(name, args)` placeholder (parse-resolve runs against a
669
+ separate registry and cannot mint the semantic
670
+ `RecursiveAliasInstanceType`). Sema's finalize pass converts it
671
+ using the sema-registry alias_info. See
672
+ docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md.
673
+ """
674
+ expected = len(alias_info.type_params)
675
+ actual = len(ref.args)
676
+ if actual != expected:
677
+ raise ResolutionFailure(
678
+ f"Type alias '{name}' takes {expected} type "
679
+ f"argument{'s' if expected != 1 else ''}, got {actual}",
680
+ loc=ref.loc,
681
+ )
682
+ # Resolve each type arg. int args (Array's N slot) shouldn't
683
+ # appear here -- v1 aliases reject int-kind type params at parse
684
+ # time -- but pass them through unchanged for forward compatibility.
685
+ resolved_args: list[TpyType | int] = []
686
+ for arg in ref.args:
687
+ if isinstance(arg, int):
688
+ resolved_args.append(arg)
689
+ else:
690
+ resolved_args.append(
691
+ self.resolve(arg, type_param_scope, is_type_arg=True)
692
+ )
693
+ if alias_info.is_recursive:
694
+ return AliasRef(
695
+ name, module=self._parser._public_module(),
696
+ args=tuple(resolved_args),
697
+ )
698
+ subst: dict[str, TpyType] = {}
699
+ for tp_name, arg in zip(alias_info.type_params, resolved_args):
700
+ if isinstance(arg, TpyType):
701
+ subst[tp_name] = arg
702
+ return substitute_type_params_structural(alias_info.body, subst)
703
+
704
+ # ------------------------------------------------------------------
705
+ # Helpers
706
+ # ------------------------------------------------------------------
707
+
708
+ def _upgrade_from_type_def(
709
+ self, registered: TpyType, resolved: tuple[str, str],
710
+ *, loc: SourceLocation | None = None,
711
+ ) -> TpyType:
712
+ """Mint `_module_qname` / upgrade protocol flags on a qualified
713
+ (`typing.Sized`) or canonical bare-name resolution using the
714
+ resolved `(module, name)` tuple's `TypeDef`.
715
+
716
+ Only NominalTypes without a qname are upgraded. For TypeDefs
717
+ carrying a ProtocolInfo payload, `is_protocol` /
718
+ `is_dynamic_protocol` are also upgraded, and a bare generic
719
+ protocol raises `SemanticError` (with `loc` attached so the
720
+ diagnostic formats as `file:line: error: ...`). Enum-registered
721
+ NominalTypes come back from `_resolve_registered_type` already
722
+ qname-bearing and fall through unchanged.
723
+ """
724
+ if not isinstance(registered, NominalType) or registered._module_qname:
725
+ return registered
726
+ module, original = resolved
727
+ candidate_qname = f"{module}.{original}"
728
+ td = get_type_def(candidate_qname)
729
+ if td is None:
730
+ return registered
731
+ if td.protocol is None and td.record is None and td.enum is None \
732
+ and td.type_factory is None:
733
+ return registered
734
+ is_protocol = registered.is_protocol
735
+ is_dynamic_protocol = registered.is_dynamic_protocol
736
+ if td.protocol is not None:
737
+ if td.protocol.type_params and not registered.type_args:
738
+ from ..diagnostics import SemanticError
739
+ raise SemanticError(
740
+ f"Generic protocol '{registered.name}' requires type arguments: "
741
+ f"{registered.name}[{', '.join(td.protocol.type_params)}]",
742
+ loc=loc,
743
+ )
744
+ is_protocol = True
745
+ is_dynamic_protocol = td.protocol.is_dynamic
746
+ return NominalType(
747
+ registered.name, registered.type_args,
748
+ is_protocol, candidate_qname, is_dynamic_protocol,
749
+ )
750
+
751
+ def _user_record_qname(
752
+ self, container: str, resolved: tuple[str, str] | None,
753
+ *, canonical: bool = False,
754
+ ) -> str | None:
755
+ """Mint `_module_qname` for a user-record reference.
756
+
757
+ Cross-module refs use the canonicalized import tuple when
758
+ `canonical=True`; same-module refs pull from
759
+ `parser.registry.get_record().module`. Returns None when
760
+ neither source supplies a module (bare placeholders that later
761
+ passes will resolve) or the tuple is not canonicalized.
762
+ """
763
+ rinfo = self._parser.registry.get_record(container)
764
+ # @builtin_type-with-body records (no factory entry, e.g.
765
+ # asyncio._executor.Task with @builtin_type("tpy.Task")) carry
766
+ # their canonical qname in `builtin_type_key`. It wins over both
767
+ # the canonical-import tuple and the defining-module form so
768
+ # the resulting NominalType's _module_qname matches the static
769
+ # TypeDef key regardless of how the type was imported.
770
+ # `RecordInfo.qualified_name()` short-circuits on builtin_type_key.
771
+ if rinfo is not None and rinfo.builtin_type_key:
772
+ return rinfo.qualified_name()
773
+ if resolved is not None and canonical:
774
+ return f"{resolved[0]}.{resolved[1]}"
775
+ if rinfo is not None and rinfo.module:
776
+ return f"{rinfo.module}.{container}"
777
+ return None
778
+
779
+ def _resolve_primitive_type(
780
+ self, module: str, original: str,
781
+ node: ast.expr | None = None, *, loc: SourceLocation | None = None,
782
+ is_type_arg: bool = False,
783
+ ) -> TpyType | None:
784
+ """Resolve a (module, original_name) pair to a primitive type.
785
+
786
+ Returns the type if it's a directly-mapped primitive (int -> BIGINT, etc.),
787
+ or None if it should fall through to registry lookups.
788
+ Raises ParseError for names that can't be used as types (Protocol).
789
+ Either `node` (ast-based) or `loc` (ref-based) may be passed for
790
+ error reporting.
791
+ """
792
+ if module == "builtins":
793
+ if original == "int": return BIGINT
794
+ elif original == "float": return FLOAT
795
+ elif original == "bool": return BOOL
796
+ elif original == "str": return STR
797
+ elif original == "bytes": return BYTES
798
+ elif original == "bytearray": return BYTEARRAY
799
+ elif original == "basic_slice": return BASIC_SLICE
800
+ elif original == "slice": return SLICE
801
+ elif original == "None": return NONE if is_type_arg else VOID
802
+ elif original == "type": return NominalType("type", _module_qname=qnames.TYPE)
803
+ elif original == "tuple":
804
+ raise ParseError("tuple requires type arguments: tuple[T1, T2, ...]", node, loc=loc)
805
+ elif module == "tpy":
806
+ if (fixed_int := _FIXED_INT_MAP.get(original)) is not None:
807
+ return fixed_int
808
+ elif original == "Char":
809
+ return CHAR
810
+ elif original == "Float32":
811
+ return FLOAT32
812
+ elif original == "String":
813
+ return STRING
814
+ elif original == "StrView":
815
+ return STRVIEW
816
+ elif original == "BytesView":
817
+ return BYTESVIEW
818
+ elif original == "basic_slice":
819
+ return BASIC_SLICE
820
+ elif original == "slice":
821
+ return SLICE
822
+ elif module == "typing":
823
+ if original == "Self":
824
+ return SELF
825
+ elif original == "Any":
826
+ return ANY
827
+ elif original == "Protocol":
828
+ raise ParseError("'Protocol' cannot be used as a type annotation", node, loc=loc)
829
+ return None
830
+
831
+ def _resolve_registered_type(
832
+ self, name: str, node: ast.expr | None = None,
833
+ *, resolved: bool = False, loc: SourceLocation | None = None,
834
+ ) -> TpyType | None:
835
+ """Look up a name in the type registry (protocols, aliases, records).
836
+
837
+ Raises SemanticError for generic protocols used without type arguments
838
+ (matches the cross-module canonical path in `_resolve_ref` so diag
839
+ output is uniform), or ParseError for completely unknown names.
840
+ Either `node` or `loc` may be passed for error reporting.
841
+ """
842
+ parser = self._parser
843
+ # Self-reference in a recursive type alias (e.g. list[JsonValue] inside
844
+ # the definition of JsonValue). Return an AliasRef placeholder that
845
+ # survives inside container types and is detected by an
846
+ # `isinstance(typ, AliasRef)` check rather than a name-set lookup.
847
+ if self._pending_alias is not None and name == self._pending_alias:
848
+ return AliasRef(name, module=parser._public_module())
849
+ # Resolve short nested type names: Kind -> Message.Kind
850
+ if name in parser._nested_type_scope:
851
+ dotted = parser._nested_type_scope[name]
852
+ if (enum_type := parser.registry.get_enum(dotted)) is not None:
853
+ return enum_type
854
+ if parser.registry.get_record(dotted) is not None:
855
+ qname = self._user_record_qname(dotted, None)
856
+ return NominalType(dotted, _module_qname=qname)
857
+ if (user_protocol := parser.registry.scan_by_short_name(name)) is not None:
858
+ if user_protocol.type_params:
859
+ from ..diagnostics import SemanticError
860
+ raise SemanticError(
861
+ f"Generic protocol '{name}' requires type arguments: "
862
+ f"{name}[{', '.join(user_protocol.type_params)}]",
863
+ loc=loc,
864
+ )
865
+ qname = f"{user_protocol.module}.{name}" if user_protocol.module else None
866
+ return NominalType(
867
+ name, is_protocol=True, _module_qname=qname,
868
+ is_dynamic_protocol=user_protocol.is_dynamic,
869
+ )
870
+ elif (enum_type := parser.registry.get_enum(name)) is not None:
871
+ return enum_type
872
+ elif (alias_info := parser.registry.get_type_alias_info(name)) is not None:
873
+ if alias_info.type_params:
874
+ # Bare reference to a generic alias -- mirror the protocol
875
+ # arm above: require type arguments at the use site rather
876
+ # than letting the body's TypeParamRefs leak into the
877
+ # annotation. See docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md.
878
+ from ..diagnostics import SemanticError
879
+ raise SemanticError(
880
+ f"Generic type alias '{name}' requires type arguments: "
881
+ f"{name}[{', '.join(alias_info.type_params)}]",
882
+ loc=loc,
883
+ )
884
+ return alias_info.body
885
+ elif not resolved:
886
+ parser._raise_unresolved_import_error(name, node, loc=loc)
887
+ if (resolved or parser.registry.is_known_type(name)
888
+ or name in parser._module_class_names
889
+ or name in parser._module_type_alias_names):
890
+ # Mint qname for same-module user records from parser.registry.
891
+ # Cross-module refs get their qname minted in `_resolve_ref` from
892
+ # the canonicalized import tuple. Builtin-type stubs carry their
893
+ # qname in `builtin_type_key`; leave them bare so the downstream
894
+ # builtin-path minting (is_builtin gate) stays authoritative.
895
+ rinfo = parser.registry.get_record(name)
896
+ if rinfo is not None and rinfo.module and not rinfo.builtin_type_key:
897
+ return NominalType(name, _module_qname=f"{rinfo.module}.{name}")
898
+ return NominalType(name)
899
+ return None
900
+
901
+ def _resolve_qualified_cross_module(
902
+ self, source_module: str, attr: str,
903
+ *, loc: SourceLocation | None = None,
904
+ ) -> TpyType | None:
905
+ """Resolve `attr` against the named source module's exports.
906
+
907
+ Used when ``submod.X`` qualifies a type from a submodule that the
908
+ importing module has bound (via `from pkg import submod`) but
909
+ whose individual records / enums / type aliases are not in the
910
+ importer's local registry. Returns a NominalType / enum_type /
911
+ alias type with the correct cross-module qname, or None.
912
+ """
913
+ parser = self._parser
914
+ mod_info = parser.registry.get_module(source_module)
915
+ if mod_info is None:
916
+ return None
917
+ if mod_info.records and attr in mod_info.records:
918
+ rinfo = mod_info.records[attr]
919
+ qname = f"{rinfo.module}.{attr}" if rinfo.module else f"{source_module}.{attr}"
920
+ return NominalType(attr, _module_qname=qname)
921
+ if mod_info.enums and attr in mod_info.enums:
922
+ return mod_info.enums[attr]
923
+ if mod_info.type_aliases and attr in mod_info.type_aliases:
924
+ alias_info = mod_info.type_aliases[attr]
925
+ if alias_info.type_params:
926
+ # Cross-module bare reference to a generic alias --
927
+ # require type arguments rather than leaking
928
+ # TypeParamRefs into the annotation.
929
+ from ..diagnostics import SemanticError
930
+ raise SemanticError(
931
+ f"Generic type alias '{attr}' requires type arguments: "
932
+ f"{attr}[{', '.join(alias_info.type_params)}]",
933
+ loc=ref.loc,
934
+ )
935
+ return alias_info.body
936
+ if mod_info.protocols and attr in mod_info.protocols:
937
+ proto = mod_info.protocols[attr]
938
+ if proto.type_params:
939
+ from ..diagnostics import SemanticError
940
+ raise SemanticError(
941
+ f"Generic protocol '{attr}' requires type arguments: "
942
+ f"{attr}[{', '.join(proto.type_params)}]",
943
+ loc=loc,
944
+ )
945
+ qname = f"{source_module}.{attr}"
946
+ return NominalType(
947
+ attr, is_protocol=True, _module_qname=qname,
948
+ is_dynamic_protocol=proto.is_dynamic,
949
+ )
950
+ return None
951
+
952
+ def _resolve_qualified_type_name_str(
953
+ self, local_module: str, attr: str,
954
+ ) -> tuple[str, str] | None:
955
+ """Loc-agnostic variant of _resolve_qualified_type_name: takes
956
+ the module-local name and attribute directly."""
957
+ parser = self._parser
958
+ if local_module in parser._local_defs:
959
+ return None
960
+ canonical = parser._reverse_module_aliases.get(local_module, local_module)
961
+ imports = parser._imports.imports
962
+ if imports is None or canonical not in imports:
963
+ return None
964
+ entry = imports[canonical]
965
+ if entry is not None and not (
966
+ isinstance(entry, set) and canonical in parser._bare_module_imports):
967
+ return None
968
+ return (canonical, attr)
969
+
970
+ def _resolve_dotted_class_name_str(self, dotted: str) -> str | None:
971
+ """Loc-agnostic variant of _resolve_dotted_class_name: check if a
972
+ dotted-name string resolves to a known module class."""
973
+ parts = dotted.split(".")
974
+ if parts and parts[0] in self._parser._module_class_names:
975
+ return dotted
976
+ return None
977
+
978
+ def _raise_unresolved_qualified_error_str(
979
+ self, dotted: str, loc: SourceLocation | None,
980
+ ) -> None:
981
+ """Loc-based variant of _raise_unresolved_qualified_error for a
982
+ dotted name like 'mod.attr'. Only fires for 2-level dotted names
983
+ (mirrors the original which dispatches on ast.Attribute with a
984
+ Name base)."""
985
+ parts = dotted.split(".")
986
+ if len(parts) == 2:
987
+ mod, attr = parts
988
+ canonical = self._parser._reverse_module_aliases.get(mod, mod)
989
+ if canonical in _IMPLICIT_MODULES:
990
+ raise ParseError(
991
+ f"'{dotted}' requires: import {canonical}", loc=loc,
992
+ )
993
+
994
+ def _resolve_generic_type_from_ref(
995
+ self, ref: TpyTypeRef, name: str, type_def: TypeDef,
996
+ type_param_scope: dict[str, TypeParamKind] | None,
997
+ ) -> TpyType:
998
+ """Resolve a generic reference (name + args) using a TypeDef factory."""
999
+ param_kinds = type_def.param_kinds
1000
+ expected_count = len(param_kinds)
1001
+
1002
+ if len(ref.args) != expected_count:
1003
+ raise ParseError(
1004
+ f"{name} requires exactly {expected_count} type parameters",
1005
+ loc=ref.loc,
1006
+ )
1007
+
1008
+ parsed_args: list[TpyType | int] = []
1009
+ for i, (arg, kind) in enumerate(zip(ref.args, param_kinds)):
1010
+ if kind == TypeParamKind.TYPE:
1011
+ assert not isinstance(arg, int), f"type slot {i} got int literal"
1012
+ parsed_args.append(
1013
+ self.resolve(arg, type_param_scope, is_type_arg=True))
1014
+ elif kind == TypeParamKind.INT:
1015
+ if isinstance(arg, int):
1016
+ parsed_args.append(arg)
1017
+ elif (isinstance(arg, TpyTypeRef) and type_param_scope
1018
+ and arg.name in type_param_scope):
1019
+ param_name = arg.name
1020
+ param_kind = type_param_scope[param_name]
1021
+ if param_kind == TypeParamKind.INT:
1022
+ parsed_args.append(
1023
+ TypeParamRef(param_name, kind=TypeParamKind.INT))
1024
+ else:
1025
+ raise ParseError(
1026
+ f"{name} parameter {i + 1} requires an integer, "
1027
+ f"got type parameter '{param_name}'",
1028
+ loc=ref.loc,
1029
+ )
1030
+ else:
1031
+ raise ParseError(
1032
+ f"{name} parameter {i + 1} must be an integer literal or int type parameter",
1033
+ loc=ref.loc,
1034
+ )
1035
+
1036
+ assert type_def.type_factory is not None
1037
+ try:
1038
+ return type_def.type_factory(*parsed_args)
1039
+ except ParseError:
1040
+ raise
1041
+ except Exception as e:
1042
+ raise ParseError(f"Failed to construct type {name}: {e}", loc=ref.loc) from e
1043
+
1044
+ def _resolve_record_type_args_from_ref(
1045
+ self, ref: TpyTypeRef, name: str,
1046
+ type_param_scope: dict[str, TypeParamKind] | None,
1047
+ ) -> tuple[TpyType | int, ...]:
1048
+ """Resolve record type arguments (type-args for a user record generic)."""
1049
+ type_args: list[TpyType | int] = []
1050
+ for arg in ref.args:
1051
+ if isinstance(arg, int):
1052
+ type_args.append(arg)
1053
+ elif (isinstance(arg, TpyTypeRef) and type_param_scope
1054
+ and arg.name in type_param_scope):
1055
+ kind = type_param_scope[arg.name]
1056
+ type_args.append(TypeParamRef(arg.name, kind=kind))
1057
+ else:
1058
+ type_args.append(
1059
+ self.resolve(arg, type_param_scope, is_type_arg=True))
1060
+ return tuple(type_args)