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,684 @@
1
+ """Builder-trace macro expansion sub-pass.
2
+
3
+ Function-body and record-method-body expansion runs in pass 5.5
4
+ (``SemanticAnalyzer._expand_builder_traces``), after class-constants
5
+ analysis (pass 5) and before record-method-body analysis (pass 6), so
6
+ synthesized records / functions are first-class participants in passes
7
+ 6 and 7. Top-level expansion runs inside ``_analyze_top_level`` (pass
8
+ 4 is itself the body-analysis pass for module-level code, so expansion
9
+ has to run there). Detects @builder_macro constructor calls, walks the
10
+ body linearly, dispatches builder methods to user handlers, and splices
11
+ synthesized declarations + a rewritten call site back into the body.
12
+ See docs/MACRO_DESIGN.md (Phase 7) for the design.
13
+
14
+ Phase A (current): the happy path -- ctor, methods, terminal -- without
15
+ the full v1 hard-error rules around tracked-symbol misuse, conditionals,
16
+ loops, or multiple terminals. Those land in phase B.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from dataclasses import dataclass, field
21
+ from typing import TYPE_CHECKING, Any, Callable
22
+
23
+ from ..parse.nodes import (
24
+ TpyAssign, TpyCall, TpyMethodCall, TpyExprStmt, TpyVarDecl,
25
+ TpyName, TpyStmt, TpyExpr, TpyFunction, TpyRecord, TpyLambda,
26
+ TpyNestedDef,
27
+ TpyStrLiteral, TpyIntLiteral, TpyFloatLiteral, TpyBoolLiteral,
28
+ TpyNoneLiteral, TpyUnaryOp,
29
+ )
30
+ from ..typesys import (
31
+ FieldInfo, NominalType, OwnType, TpyType, VOID, STR, STRVIEW, BOOL, BIGINT,
32
+ FLOAT, FLOAT32,
33
+ INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64,
34
+ make_list,
35
+ )
36
+ from ..diagnostics import SemanticError
37
+ from ..symbol_binding import SymbolKind, is_kind, walk_attribute_chain
38
+ from ..macro_api import (
39
+ MacroArg, MacroArgs, BuilderContext, TypeInfo, MacroError,
40
+ )
41
+
42
+ if TYPE_CHECKING:
43
+ from .context import SemanticContext
44
+ from .registration import TypeRegistrar
45
+
46
+
47
+ # Synthesized records and functions get a private prefix so they aren't
48
+ # treated as user-exported names. Matches the compiler-internal naming
49
+ # convention used elsewhere (e.g. __tpy_init, __tpy_main).
50
+ _SYNTH_PREFIX = "__tpy_builder_"
51
+
52
+
53
+ # Kind tags for handlers discovered on a @builder_macro class.
54
+ _KIND_METHOD = "method"
55
+ _KIND_RETURNS = "returns"
56
+ _KIND_TERMINAL = "terminal"
57
+
58
+
59
+ @dataclass
60
+ class _HandlerSpec:
61
+ fn: Callable
62
+ kind: str
63
+ child_class: type | None = None # only for kind == _KIND_RETURNS
64
+
65
+
66
+ @dataclass
67
+ class _TrackedSymbol:
68
+ """A live tracked symbol bound by a @builder_macro ctor or sub-builder."""
69
+ var_name: str
70
+ state: object
71
+ macro_qname: str
72
+ handlers: dict[str, _HandlerSpec]
73
+ # var_name of the @builder_returns parent that spawned this symbol,
74
+ # or None for top-level (ctor-bound) symbols. Used to cascade
75
+ # close-on-terminal: when the root @builder_terminal fires, every
76
+ # descendant sub-builder is closed too. Sub-builders don't have
77
+ # their own terminal -- they contribute to the root's terminal.
78
+ parent_var: str | None = None
79
+
80
+
81
+ @dataclass
82
+ class _PendingReplacement:
83
+ fn_name: str
84
+ args: MacroArgs
85
+
86
+
87
+ def _scan_handlers(macro_cls: type) -> dict[str, _HandlerSpec]:
88
+ """Collect @builder_method / @builder_returns / @builder_terminal
89
+ handlers declared on a builder class.
90
+ """
91
+ out: dict[str, _HandlerSpec] = {}
92
+ for attr in dir(macro_cls):
93
+ if attr.startswith("__") and attr.endswith("__"):
94
+ continue
95
+ fn = getattr(macro_cls, attr, None)
96
+ if not callable(fn):
97
+ continue
98
+ if getattr(fn, "_is_builder_terminal", False):
99
+ out[attr] = _HandlerSpec(fn, _KIND_TERMINAL)
100
+ elif getattr(fn, "_is_builder_returns", False):
101
+ child = getattr(fn, "_builder_child_class", None)
102
+ out[attr] = _HandlerSpec(fn, _KIND_RETURNS, child_class=child)
103
+ elif getattr(fn, "_is_builder_method", False):
104
+ out[attr] = _HandlerSpec(fn, _KIND_METHOD)
105
+ return out
106
+
107
+
108
+ def _macro_arg_from_expr(expr: TpyExpr) -> MacroArg:
109
+ """Wrap an expression as a MacroArg with a best-effort literal type.
110
+
111
+ Builder-trace runs before body analysis, so resolved types aren't
112
+ on expressions yet. We synthesize a minimal TypeInfo from the literal
113
+ kind when possible. Macros generally only need MacroArg.expr (for
114
+ literal evaluation); the type field is provided so kwarg_macroarg
115
+ callers see something sensible for the common cases.
116
+ """
117
+ return MacroArg(expr=expr, type=_typeinfo_from_literal(expr))
118
+
119
+
120
+ # Bare-name builtins recognized as ``type=`` references in builder
121
+ # macros. Mapping these to their real TpyType lets macros use
122
+ # TypeInfo's category helpers (``is_int``, ``is_bigint``, ``is_float``,
123
+ # ...) instead of name-string comparisons. User-defined types still
124
+ # fall through to a placeholder until full type-name resolution lands
125
+ # in builder-trace.
126
+ _BUILTIN_TYPE_NAMES: dict[str, TpyType] = {
127
+ "str": STR, "int": BIGINT, "float": FLOAT, "bool": BOOL,
128
+ "Int8": INT8, "Int16": INT16, "Int32": INT32, "Int64": INT64,
129
+ "UInt8": UINT8, "UInt16": UINT16, "UInt32": UINT32, "UInt64": UINT64,
130
+ "Float32": FLOAT32,
131
+ }
132
+
133
+
134
+ def _typeinfo_from_literal(expr: TpyExpr) -> TypeInfo:
135
+ if isinstance(expr, TpyBoolLiteral):
136
+ return TypeInfo.from_tpy_type(BOOL)
137
+ if isinstance(expr, TpyIntLiteral):
138
+ return TypeInfo.from_tpy_type(BIGINT)
139
+ if isinstance(expr, TpyFloatLiteral):
140
+ return TypeInfo.from_tpy_type(FLOAT)
141
+ if isinstance(expr, TpyStrLiteral):
142
+ return TypeInfo.from_tpy_type(STRVIEW)
143
+ if isinstance(expr, TpyNoneLiteral):
144
+ return TypeInfo("None", _tpy_type=None)
145
+ if isinstance(expr, TpyName):
146
+ builtin = _BUILTIN_TYPE_NAMES.get(expr.name)
147
+ if builtin is not None:
148
+ return TypeInfo.from_tpy_type(builtin)
149
+ # User-defined types stay as placeholders until full type-name
150
+ # resolution lands in builder-trace.
151
+ return TypeInfo(expr.name, _tpy_type=None)
152
+ return TypeInfo("?", _tpy_type=None)
153
+
154
+
155
+ def _build_macro_args(args: list[TpyExpr], kwargs: dict[str, TpyExpr]) -> MacroArgs:
156
+ return MacroArgs(
157
+ positional=[_macro_arg_from_expr(a) for a in args],
158
+ kwargs={k: _macro_arg_from_expr(v) for k, v in kwargs.items()},
159
+ )
160
+
161
+
162
+ def _extract_binding(stmt: TpyStmt) -> tuple[str | None, TpyExpr | None]:
163
+ """If ``stmt`` binds a single name to an RHS expression, return
164
+ ``(name, rhs)``. Otherwise return ``(None, None)``.
165
+
166
+ Handles both first-time declarations (``TpyVarDecl``) and reassignments
167
+ (``TpyAssign`` with a ``TpyName`` target).
168
+ """
169
+ if isinstance(stmt, TpyVarDecl):
170
+ return stmt.name, stmt.init
171
+ if isinstance(stmt, TpyAssign) and isinstance(stmt.target, TpyName):
172
+ return stmt.target.name, stmt.value
173
+ return None, None
174
+
175
+
176
+ class BuilderTraceExpander:
177
+ """Expand a function body containing @builder_macro constructor calls.
178
+
179
+ Construct one expander per body. Call ``expand(body)`` to get a
180
+ rewritten body. The expander mutates ``ctx.registry`` and ``module``
181
+ directly via the registrar to register synthesized declarations.
182
+
183
+ No-op when the body contains no builder constructors.
184
+ """
185
+
186
+ def __init__(
187
+ self,
188
+ ctx: 'SemanticContext',
189
+ registrar: 'TypeRegistrar',
190
+ module: Any, # TpyModule -- imported lazily to avoid cycle
191
+ function_being_traced: str,
192
+ ) -> None:
193
+ self.ctx = ctx
194
+ self.registrar = registrar
195
+ self.module = module
196
+ self.function_being_traced = function_being_traced
197
+ self._tracked: dict[str, _TrackedSymbol] = {}
198
+ self._pending_replacement: _PendingReplacement | None = None
199
+ # Trace-rule bookkeeping (Phase B).
200
+ self._all_tracked_names: set[str] = set()
201
+ self._open_traces: dict[str, Any] = {} # name -> ctor loc
202
+
203
+ # ------------------------------------------------------------------
204
+ # Body walk
205
+ # ------------------------------------------------------------------
206
+
207
+ def expand(self, body: list[TpyStmt] | None) -> list[TpyStmt] | None:
208
+ if body is None:
209
+ return body
210
+ macro_reg = self.ctx.macro_registry
211
+ if macro_reg is None or not macro_reg.has_builder_macros():
212
+ return body
213
+ new_body: list[TpyStmt] = []
214
+ for stmt in body:
215
+ replacement = self._process_stmt(stmt)
216
+ if replacement is _DROP:
217
+ continue
218
+ if replacement is None:
219
+ new_body.append(stmt)
220
+ else:
221
+ new_body.append(replacement)
222
+ # Trace-rule validation (Phase B). Order matters: leaks fire
223
+ # before "trace never closed" so that a symbol used illegally
224
+ # gets the more specific error rather than a generic missing-
225
+ # terminal one.
226
+ if self._all_tracked_names:
227
+ self._validate_no_tracked_leaks(new_body)
228
+ self._check_no_open_traces()
229
+ return new_body
230
+
231
+ def _reject_active_reassignment(self, name: str, loc: Any) -> None:
232
+ """Raise if ``name`` is currently bound as an active tracked
233
+ builder symbol. Shared between ctor binding, ``@builder_returns``
234
+ rebinding, and the post-dispatch fall-through reassignment check.
235
+ Closed names are not rejected -- the trace has finished, the
236
+ name is free to take on any other meaning.
237
+ """
238
+ if name in self._tracked:
239
+ raise SemanticError(
240
+ f"builder-trace symbol '{name}' cannot be reassigned",
241
+ loc,
242
+ )
243
+
244
+ def _check_no_open_traces(self) -> None:
245
+ if not self._open_traces:
246
+ return
247
+ name, loc = next(iter(self._open_traces.items()))
248
+ raise SemanticError(
249
+ f"builder-trace symbol '{name}' was never closed by a "
250
+ f"@builder_terminal call before the end of "
251
+ f"'{self.function_being_traced}'",
252
+ loc,
253
+ )
254
+
255
+ def _validate_no_tracked_leaks(self, body: list[TpyStmt]) -> None:
256
+ tracked = self._all_tracked_names
257
+ for stmt in body:
258
+ self._validate_stmt(stmt, tracked, in_control_flow=False)
259
+
260
+ def _validate_stmt(
261
+ self, stmt: TpyStmt, tracked: set[str], *, in_control_flow: bool,
262
+ ) -> None:
263
+ for expr in stmt.exprs():
264
+ if expr is not None:
265
+ self._validate_expr(expr, tracked, stmt,
266
+ in_control_flow=in_control_flow)
267
+ for nested in stmt.sub_bodies():
268
+ for inner in nested:
269
+ self._validate_stmt(inner, tracked, in_control_flow=True)
270
+ # TpyNestedDef.sub_bodies() returns []; recurse into its
271
+ # function body explicitly so a tracked symbol captured by a
272
+ # nested def is flagged.
273
+ if isinstance(stmt, TpyNestedDef):
274
+ for inner in stmt.func.body:
275
+ self._validate_stmt(inner, tracked, in_control_flow=True)
276
+
277
+ def _validate_expr(
278
+ self, expr: TpyExpr, tracked: set[str], stmt: TpyStmt,
279
+ *, in_control_flow: bool,
280
+ ) -> None:
281
+ if isinstance(expr, TpyName) and expr.name in tracked:
282
+ loc = getattr(expr, "loc", None) or getattr(stmt, "loc", None)
283
+ if in_control_flow:
284
+ raise SemanticError(
285
+ f"builder-trace symbol '{expr.name}' may not be used "
286
+ f"inside a control-flow block, lambda, or nested def",
287
+ loc,
288
+ )
289
+ raise SemanticError(
290
+ f"builder-trace symbol '{expr.name}' may only appear as "
291
+ f"the receiver of a registered @builder_method call",
292
+ loc,
293
+ )
294
+ # TpyLambda.children() returns [] to keep generic walks out of
295
+ # closure bodies; recurse explicitly so a tracked symbol
296
+ # captured by a lambda is flagged. The lambda body is itself
297
+ # an expression.
298
+ if isinstance(expr, TpyLambda):
299
+ self._validate_expr(expr.body, tracked, stmt,
300
+ in_control_flow=True)
301
+ return
302
+ for child in expr.children():
303
+ self._validate_expr(child, tracked, stmt,
304
+ in_control_flow=in_control_flow)
305
+
306
+ def _process_stmt(self, stmt: TpyStmt) -> Any:
307
+ # x = BuilderClass(...) -- start a new trace.
308
+ # Both TpyAssign (rebinding) and TpyVarDecl (first declaration)
309
+ # can carry the binding RHS, and the ctor itself can appear
310
+ # either as a bare-name call (``ArgumentParser()`` after
311
+ # ``from argparse import ArgumentParser``) or as a qualified
312
+ # method call (``argparse.ArgumentParser()`` after
313
+ # ``import argparse``). Both forms carry resolved_import.
314
+ target_name, rhs = _extract_binding(stmt)
315
+ if target_name is not None and rhs is not None:
316
+ if isinstance(rhs, (TpyCall, TpyMethodCall)):
317
+ builder_cls = self._lookup_builder_macro(rhs)
318
+ if builder_cls is not None:
319
+ self._handle_ctor(target_name, rhs, builder_cls)
320
+ return _DROP
321
+ if isinstance(rhs, TpyMethodCall):
322
+ rep = self._handle_method_call(stmt, rhs, lhs=target_name)
323
+ if rep is not _NOT_HANDLED:
324
+ return rep
325
+ # Reassignment to an actively tracked builder symbol --
326
+ # forbidden because the leak validator wouldn't catch this on
327
+ # its own (the RHS may not reference the tracked name). Once
328
+ # the trace has been closed by a terminal, the name is fair
329
+ # game for any rebinding.
330
+ self._reject_active_reassignment(target_name, getattr(stmt, "loc", None))
331
+ # bare method call: parser.method(...)
332
+ if isinstance(stmt, TpyExprStmt) and isinstance(stmt.expr, TpyMethodCall):
333
+ rep = self._handle_method_call(stmt, stmt.expr, lhs=None)
334
+ if rep is not _NOT_HANDLED:
335
+ return rep
336
+ return None
337
+
338
+ # ------------------------------------------------------------------
339
+ # Constructor handling
340
+ # ------------------------------------------------------------------
341
+
342
+ def _lookup_builder_macro(self, call: TpyCall | TpyMethodCall) -> type | None:
343
+ """Return the @builder_macro state class targeted by this call,
344
+ or None. Works for both ``Builder()`` (TpyCall after
345
+ ``from mod import Builder``) and ``mod.Builder()`` (TpyMethodCall
346
+ after ``import mod``); both carry ``resolved_import`` (immediate
347
+ import source). The chain walk recovers the registry's canonical
348
+ (ultimate_module, name) key for re-exports through plain modules.
349
+ """
350
+ macro_reg = self.ctx.macro_registry
351
+ if macro_reg is None or call.resolved_import is None:
352
+ return None
353
+ mod_name, obj_name = call.resolved_import
354
+ macro_cls = macro_reg.get_builder_macro(mod_name, obj_name)
355
+ if macro_cls is not None:
356
+ return macro_cls
357
+ result = walk_attribute_chain(
358
+ self.ctx.registry, mod_name, obj_name,
359
+ is_kind(SymbolKind.BUILDER_MACRO))
360
+ if result is None:
361
+ return None
362
+ ult_mod, ult_name, _bd = result
363
+ return macro_reg.get_builder_macro(ult_mod, ult_name)
364
+
365
+ def _handle_ctor(
366
+ self, var_name: str, call: TpyCall, macro_cls: type,
367
+ ) -> None:
368
+ from ..macro_loader import validate_builder_macro
369
+
370
+ self._reject_active_reassignment(var_name, call.loc)
371
+ qname = f"{call.resolved_import[0]}.{call.resolved_import[1]}"
372
+ args = _build_macro_args(call.args, call.kwargs)
373
+ ctx_obj = BuilderContext(
374
+ expander=self, ctx=self.ctx,
375
+ call_loc=call.loc, function_being_traced=self.function_being_traced,
376
+ )
377
+ state = validate_builder_macro(macro_cls, ctx_obj, args, qname, call.loc)
378
+ handlers = _scan_handlers(macro_cls)
379
+ self._tracked[var_name] = _TrackedSymbol(
380
+ var_name=var_name, state=state, macro_qname=qname,
381
+ handlers=handlers,
382
+ )
383
+ self._all_tracked_names.add(var_name)
384
+ self._open_traces[var_name] = call.loc
385
+
386
+ # ------------------------------------------------------------------
387
+ # Method-call handling
388
+ # ------------------------------------------------------------------
389
+
390
+ def _handle_method_call(
391
+ self, stmt: TpyStmt, mcall: TpyMethodCall, lhs: str | None,
392
+ ) -> Any:
393
+ if not isinstance(mcall.obj, TpyName):
394
+ return _NOT_HANDLED
395
+ sym = self._tracked.get(mcall.obj.name)
396
+ if sym is None:
397
+ return _NOT_HANDLED
398
+ spec = sym.handlers.get(mcall.method)
399
+ if spec is None:
400
+ raise SemanticError(
401
+ f"no @builder_method handler for '{sym.macro_qname}.{mcall.method}'",
402
+ mcall.loc,
403
+ )
404
+
405
+ from ..macro_loader import expand_builder_method
406
+
407
+ args = _build_macro_args(mcall.args, mcall.kwargs)
408
+ ctx_obj = BuilderContext(
409
+ expander=self, ctx=self.ctx,
410
+ call_loc=mcall.loc, function_being_traced=self.function_being_traced,
411
+ )
412
+ bound = spec.fn.__get__(sym.state, type(sym.state))
413
+ qname = f"{sym.macro_qname}.{mcall.method}"
414
+
415
+ if spec.kind == _KIND_METHOD:
416
+ expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
417
+ return _DROP
418
+
419
+ if spec.kind == _KIND_RETURNS:
420
+ if lhs is None:
421
+ raise SemanticError(
422
+ f"@builder_returns method '{qname}' must be assigned to a name",
423
+ mcall.loc,
424
+ )
425
+ # Run the reassignment check before invoking the handler so
426
+ # the diagnostic fires even when the handler would itself
427
+ # crash -- and so the parent's trace state isn't silently
428
+ # overwritten before the user-visible error.
429
+ self._reject_active_reassignment(lhs, mcall.loc)
430
+ child_state = expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
431
+ child_cls = spec.child_class
432
+ if child_cls is None or not isinstance(child_state, child_cls):
433
+ raise SemanticError(
434
+ f"@builder_returns({getattr(child_cls, '__name__', '?')}) "
435
+ f"method '{qname}' returned {type(child_state).__name__}",
436
+ mcall.loc,
437
+ )
438
+ child_handlers = _scan_handlers(child_cls)
439
+ self._tracked[lhs] = _TrackedSymbol(
440
+ var_name=lhs, state=child_state,
441
+ macro_qname=f"{sym.macro_qname}::{child_cls.__name__}",
442
+ handlers=child_handlers,
443
+ parent_var=sym.var_name,
444
+ )
445
+ self._all_tracked_names.add(lhs)
446
+ self._open_traces[lhs] = mcall.loc
447
+ return _DROP
448
+
449
+ # _KIND_TERMINAL: handler should call ctx.replace_call.
450
+ self._pending_replacement = None
451
+ result = expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
452
+ replacement = self._pending_replacement
453
+ self._pending_replacement = None
454
+ if replacement is None:
455
+ raise SemanticError(
456
+ f"@builder_terminal handler '{qname}' did not call "
457
+ f"ctx.replace_call(); the call site cannot be rewritten",
458
+ mcall.loc,
459
+ )
460
+ # Tracked symbol's trace is finished; remove from active tracking.
461
+ # Sub-builders spawned via @builder_returns from this symbol (or
462
+ # from any of those descendants) are closed alongside the root --
463
+ # they don't have their own terminal and contribute their state
464
+ # to the root's terminal handler. Walk the parent_var chain to
465
+ # find every descendant before mutating the dicts.
466
+ #
467
+ # Cost is O(D * N) where D is chain depth and N is the number of
468
+ # tracked symbols still alive: each iteration extends ``closing``
469
+ # by one depth level. Fine for argparse (max depth 3: parser ->
470
+ # subparsers_action -> sub_builder); a reverse parent->children
471
+ # map would flatten this to O(N) if deeper builder chains land.
472
+ closing = {sym.var_name}
473
+ changed = True
474
+ while changed:
475
+ changed = False
476
+ for name, ts in self._tracked.items():
477
+ if name in closing:
478
+ continue
479
+ if ts.parent_var in closing:
480
+ closing.add(name)
481
+ changed = True
482
+ for name in closing:
483
+ self._tracked.pop(name, None)
484
+ self._open_traces.pop(name, None)
485
+ rewritten = self._build_replacement_call(replacement, mcall.loc)
486
+ if isinstance(stmt, TpyAssign):
487
+ stmt.value = rewritten
488
+ return stmt
489
+ if isinstance(stmt, TpyVarDecl):
490
+ stmt.init = rewritten
491
+ return stmt
492
+ # bare call statement
493
+ new_stmt = TpyExprStmt(expr=rewritten)
494
+ new_stmt.loc = stmt.loc
495
+ return new_stmt
496
+
497
+ def _build_replacement_call(
498
+ self, rep: _PendingReplacement, loc: Any,
499
+ ) -> TpyCall:
500
+ positional_exprs = [ma.expr for ma in rep.args.positional]
501
+ kwarg_exprs = {k: ma.expr for k, ma in rep.args.kwargs.items()}
502
+ call = TpyCall(
503
+ func=TpyName(rep.fn_name),
504
+ args=positional_exprs,
505
+ kwargs=kwarg_exprs,
506
+ )
507
+ call.loc = loc
508
+ return call
509
+
510
+ # ------------------------------------------------------------------
511
+ # BuilderContext-facing hooks
512
+ # ------------------------------------------------------------------
513
+
514
+ def fresh_module_name(self, hint: str) -> str:
515
+ """Allocate a unique module-private name for a synthesized decl.
516
+
517
+ Counters live on SemanticContext so they're shared across all
518
+ builder-trace expansions in the same module -- otherwise two
519
+ functions both opening an ArgumentParser trace would each mint
520
+ the same suffix-1 record/function name and collide at codegen.
521
+ """
522
+ counters = self.ctx.builder_trace_fresh_counters
523
+ n = counters.get(hint, 0) + 1
524
+ counters[hint] = n
525
+ return f"{_SYNTH_PREFIX}{hint}_{n}"
526
+
527
+ def emit_record(
528
+ self, name: str, fields: list[tuple[str, TpyType]],
529
+ methods: list[TpyFunction], loc: Any,
530
+ ) -> TypeInfo:
531
+ """Caveats: ``validate_record_inheritance`` and
532
+ ``validate_value_type_fields`` run before any builder-trace
533
+ expansion, so synthesized records skip those passes -- inheritance
534
+ and ValueType-conformance constraints on emitted records are
535
+ currently unchecked. The current argparse use case (plain data
536
+ structs) doesn't hit either.
537
+
538
+ ``methods`` may include any combination of methods; a default
539
+ positional ``__init__`` is auto-injected unless one is already
540
+ present in the list. This lets builder-trace macros emit
541
+ property forwarders / helper methods alongside the default init
542
+ without having to re-implement the init shape themselves.
543
+ """
544
+ methods = list(methods)
545
+ if not any(m.name == "__init__" for m in methods):
546
+ methods.insert(0, _build_default_init(fields, loc))
547
+ record = _build_record(name, fields, methods, loc)
548
+ # Append to module so codegen sees it; register with the registrar
549
+ # so subsequent sema lookups find it.
550
+ self.module.records.append(record)
551
+ self.registrar.register_record(record)
552
+ # Promote the bare NominalType to qname-bearing form so type
553
+ # equality with the registered RecordInfo holds in compatibility
554
+ # checks (otherwise references via the bare type and via the
555
+ # registered type compare unequal even though both name "name").
556
+ from ..parse.resolve_refs import promote_bare_nominals
557
+ promoted = promote_bare_nominals(NominalType(name), self.ctx.registry)
558
+ return TypeInfo.from_tpy_type(promoted)
559
+
560
+ def emit_function(
561
+ self, name: str, params: list[tuple[str, TpyType]],
562
+ return_type: TpyType, body: list[TpyStmt], loc: Any,
563
+ ) -> str:
564
+ """Caveat: ``_normalize_function_info_refs`` runs in pass 2 of
565
+ analyze(); synthesized functions are added in passes 4 / 5.5
566
+ and skip that normalization, so ``FunctionInfo.params`` are
567
+ not wrapped with ``RefType`` for non-value parameter types.
568
+ Masked today because overload resolution unwraps refs on both
569
+ sides; any future check that distinguishes ``ListType`` from
570
+ ``RefType(ListType)`` on registered params would expose this.
571
+ """
572
+ # Returning a freshly constructed reference type requires Own[T] --
573
+ # synthesized parse functions always move ownership to the caller.
574
+ if not return_type.is_value_type() and not isinstance(return_type, OwnType):
575
+ return_type = OwnType(return_type)
576
+ body = list(body)
577
+ # Stmts coming from ast.quote() carry locs anchored to the
578
+ # fragment source, not the user module. Clear them so codegen
579
+ # doesn't try to look up the fragment's line numbers in main.py.
580
+ _strip_fragment_locs(body)
581
+ # Quoted-statement fragments leave TypeRefNodes on annotated
582
+ # decls / generic call_type / etc.; sema's pre-pass already ran
583
+ # by the time we're here, so resolve them now using the module's
584
+ # parser resolver. Mirrors what _finalize_function_refs does for
585
+ # quote_fun-produced functions.
586
+ resolver = getattr(self.ctx, "parser_resolver", None)
587
+ if resolver is not None:
588
+ from ..parse.resolve_refs import _walk_body
589
+ _walk_body(body, None, resolver)
590
+ func = TpyFunction(
591
+ name=name, params=list(params), return_type=return_type,
592
+ body=body,
593
+ )
594
+ func.loc = loc
595
+ self.module.functions.append(func)
596
+ self.registrar.register_function(func)
597
+ return name
598
+
599
+ def replace_call(
600
+ self, fn_name: str, args: MacroArgs, loc: Any,
601
+ ) -> None:
602
+ if self._pending_replacement is not None:
603
+ raise SemanticError(
604
+ "ctx.replace_call() called more than once during a single "
605
+ "@builder_terminal expansion",
606
+ loc,
607
+ )
608
+ self._pending_replacement = _PendingReplacement(fn_name=fn_name, args=args)
609
+
610
+
611
+ def _build_record(
612
+ name: str, fields: list[tuple[str, TpyType]],
613
+ methods: list[TpyFunction], loc: Any,
614
+ ) -> TpyRecord:
615
+ field_infos = [FieldInfo(name=fname, type=ftype) for fname, ftype in fields]
616
+ record = TpyRecord(name=name, fields=field_infos, methods=list(methods))
617
+ record.loc = loc
618
+ return record
619
+
620
+
621
+ def _strip_fragment_locs(stmts: list[TpyStmt]) -> None:
622
+ """Recursively clear ``loc`` on stmts produced by ``ast.quote()``.
623
+
624
+ Quoted-fragment stmts carry locs whose line numbers index the
625
+ fragment source, not the user module's source -- if those flow
626
+ through to codegen unchanged, ``emit_inline_comments`` indexes
627
+ out of bounds. Clearing matches the implicit contract for
628
+ ``ast.*``-built stmts (which never set loc in the first place).
629
+ """
630
+ for stmt in stmts:
631
+ stmt.loc = None
632
+ for nested in stmt.sub_bodies():
633
+ _strip_fragment_locs(nested)
634
+
635
+
636
+ def _build_default_init(
637
+ fields: list[tuple[str, TpyType]], loc: Any,
638
+ ) -> TpyFunction:
639
+ """Build a positional ``__init__`` that assigns each field from a
640
+ same-named parameter.
641
+
642
+ Used by ``emit_record`` when the caller doesn't supply methods.
643
+ """
644
+ from ..parse.nodes import TpyAssign, TpyFieldAccess, TpyName
645
+ from ..typesys import OwnType, UnionType
646
+
647
+ params: list[tuple[str, TpyType]] = []
648
+ body: list[Any] = []
649
+ for fname, ftype in fields:
650
+ # Union[A, B] non-value fields use the bare type as the param
651
+ # (pointer-variant convention) -- codegen expects the body's
652
+ # implicit assignment to lower through `to_value_variant`,
653
+ # which assumes a pointer-variant input. Wrapping in OwnType
654
+ # here renders the param as `value_variant&&` and breaks that
655
+ # body lowering. Mirrors how user-written ctors for Union-
656
+ # typed fields are spelled (`s: A | B`, not `s: Own[A | B]`).
657
+ if ftype.is_value_type() or isinstance(ftype, UnionType):
658
+ param_type = ftype
659
+ else:
660
+ param_type = OwnType(ftype)
661
+ params.append((fname, param_type))
662
+ body.append(TpyAssign(
663
+ target=TpyFieldAccess(obj=TpyName("self"), field=fname),
664
+ value=TpyName(fname),
665
+ ))
666
+ func = TpyFunction(
667
+ name="__init__", params=params, return_type=VOID, body=body,
668
+ is_method=True, is_macro_generated=True, macro_origin="builder-trace",
669
+ )
670
+ func.loc = loc
671
+ return func
672
+
673
+
674
+ # Sentinel objects for _process_stmt return values.
675
+ class _DropMarker:
676
+ pass
677
+
678
+
679
+ class _NotHandledMarker:
680
+ pass
681
+
682
+
683
+ _DROP = _DropMarker()
684
+ _NOT_HANDLED = _NotHandledMarker()