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,436 @@
1
+ """
2
+ TurboPython Code Generation Type Helpers
3
+
4
+ Type resolution and C++ type mapping utilities.
5
+ """
6
+
7
+ from __future__ import annotations
8
+ from typing import TYPE_CHECKING
9
+
10
+ from ..typesys import (
11
+ TpyType, IntLiteralType, FloatLiteralType,
12
+ PendingListType, PendingDictType, PendingSetType, PendingViewType, ViewTypeFamily, make_list, make_dict, make_set, TypeParamRef, NominalType,
13
+ UnionType, NoneType, VoidType, TupleType, ReadonlyType,
14
+ unwrap_readonly, is_protocol_type, resolve_int_literals,
15
+ is_integer_type, is_float_type, is_void_like_type,
16
+ INT32, BIGINT, FLOAT, FLOAT32, STR, BYTES,
17
+ )
18
+ from ..parse import TpyExpr, TpyName, TpyBinOp, TpyUnaryOp, TpyCoerce, TpyCall, TpyMethodCall, TpyIntLiteral, TpyIfExpr
19
+ from ..sema.context import PENDING_CONTAINER_TYPES
20
+ from .context import qualified_cpp_name, enum_cpp_name
21
+ from ..compilation_context import get_current_compiler
22
+ from ..type_def_registry import (
23
+ is_list,
24
+ is_fixed_int_type, is_big_int_type, is_bool_type, is_float64_type, is_float32_type,
25
+ is_enum_type, protocol_info_of,
26
+ )
27
+
28
+ if TYPE_CHECKING:
29
+ from .context import CodeGenContext
30
+ from .protocols import ProtocolGenerator
31
+
32
+
33
+ class TypeResolver:
34
+ """Type resolution and C++ type mapping utilities."""
35
+
36
+ def __init__(self, ctx: CodeGenContext, protocols: ProtocolGenerator):
37
+ self.ctx = ctx
38
+ self.protocols = protocols
39
+
40
+ def get_resolved_type(self, expr: TpyExpr, target_type: TpyType | None = None) -> TpyType:
41
+ """Get the resolved type of an expression, handling PendingListType.
42
+
43
+ PendingListType is used during semantic analysis but should be resolved
44
+ to concrete Array or list types before codegen. This method looks up
45
+ the resolved type if needed.
46
+
47
+ Args:
48
+ expr: The expression to get the type of.
49
+ target_type: Optional hint for what type the expression will be coerced to.
50
+ Used to determine if literal+literal should be Int32 or BigInt.
51
+ """
52
+ # Protocol isinstance narrowing: `if isinstance(x, SomeProtocol):`
53
+ # narrows x from a union parameter to the protocol type within the
54
+ # branch. Surface the narrower type so for-loop dispatch, `in`
55
+ # operator, etc. pick the right peephole.
56
+ if isinstance(expr, TpyName) and expr.name in self.ctx.protocol_narrowings:
57
+ return unwrap_readonly(self.ctx.protocol_narrowings[expr.name])
58
+ # Check for codegen-overridden types (e.g., loop variables)
59
+ if isinstance(expr, TpyName) and expr.name in self.ctx.var_types:
60
+ return unwrap_readonly(self.ctx.var_types[expr.name])
61
+ if isinstance(expr, TpyCoerce):
62
+ return expr.expected_type
63
+
64
+ # Ternary: if both branches resolve to the same codegen type, use it
65
+ # so deductions like string_view propagate through (e.g. a if c else b).
66
+ if isinstance(expr, TpyIfExpr):
67
+ typ = self.ctx.analyzer.get_expr_type(expr)
68
+ then_resolved = self.get_resolved_type(expr.then_expr)
69
+ else_resolved = self.get_resolved_type(expr.else_expr)
70
+ if then_resolved == else_resolved:
71
+ return then_resolved
72
+ # Branches differ -- resolve pending view types so the view->owned
73
+ # wrapping check in statement codegen sees a concrete type.
74
+ ret = unwrap_readonly(typ) if typ else typ
75
+ if isinstance(ret, PendingViewType):
76
+ ret = self._resolve_pending_view(ret)
77
+ return ret
78
+
79
+ # For binary operations, compute type using resolved operand types
80
+ if isinstance(expr, TpyBinOp):
81
+ # Comparisons: skip arithmetic type logic, use sema type directly.
82
+ if expr.op in ("==", "!=", "<", ">", "<=", ">="):
83
+ typ = self.ctx.analyzer.get_expr_type(expr)
84
+ return unwrap_readonly(typ) if typ else typ
85
+ # Logical and/or: for operand-return semantics, resolve via
86
+ # operand types so codegen-level deductions (e.g. string_view)
87
+ # propagate correctly. Bool-result falls through to sema type.
88
+ if expr.op in ("&&", "||"):
89
+ typ = self.ctx.analyzer.get_expr_type(expr)
90
+ if is_bool_type(typ):
91
+ return unwrap_readonly(typ)
92
+ left_resolved = self.get_resolved_type(expr.left)
93
+ right_resolved = self.get_resolved_type(expr.right)
94
+ if left_resolved == right_resolved:
95
+ return left_resolved
96
+ # Operands differ (e.g. one is string_view, other is string).
97
+ # Resolve pending view types so callers like the view->owned
98
+ # wrapping check in statement codegen see a concrete type.
99
+ ret = unwrap_readonly(typ) if typ else typ
100
+ if isinstance(ret, PendingViewType):
101
+ ret = self._resolve_pending_view(ret)
102
+ return ret
103
+
104
+ # First pass without context to detect Int32 operands
105
+ left_raw = self.get_resolved_type(expr.left)
106
+ right_raw = self.get_resolved_type(expr.right)
107
+ left_analyzer_type = self.ctx.analyzer.get_expr_type(expr.left)
108
+ right_analyzer_type = self.ctx.analyzer.get_expr_type(expr.right)
109
+ left_is_literal = isinstance(left_analyzer_type, IntLiteralType) and not isinstance(expr.left, TpyName)
110
+ right_is_literal = isinstance(right_analyzer_type, IntLiteralType) and not isinstance(expr.right, TpyName)
111
+
112
+ # If either operand is float-family, result is float (float takes precedence)
113
+ if is_float_type(left_raw) or is_float_type(right_raw):
114
+ if expr.op == "div" or expr.op in ("+", "-", "*", "//", "%", "**"):
115
+ # Float64 wins over Float32
116
+ if is_float64_type(left_raw) or is_float64_type(right_raw):
117
+ return FLOAT
118
+ return left_raw if is_float32_type(left_raw) else right_raw
119
+
120
+ # True division always returns float
121
+ if expr.op == "div":
122
+ return FLOAT
123
+
124
+ # Determine fixed-int context: explicit target or operand is a fixed-width int
125
+ fixed_ctx = target_type if is_fixed_int_type(target_type) else None
126
+ if is_fixed_int_type(left_raw) and not left_is_literal:
127
+ fixed_ctx = left_raw
128
+ elif is_fixed_int_type(right_raw) and not right_is_literal:
129
+ fixed_ctx = right_raw
130
+ # Second pass with context for proper literal resolution
131
+ left_type = self.get_resolved_type(expr.left, fixed_ctx)
132
+ right_type = self.get_resolved_type(expr.right, fixed_ctx)
133
+ # If target is fixed-int and both operands are literals, result is that type
134
+ if is_fixed_int_type(fixed_ctx) and left_is_literal and right_is_literal:
135
+ return fixed_ctx
136
+ # Pure literal binops without fixed context use configured default-int,
137
+ # with range-safe fallback for out-of-range results.
138
+ if left_is_literal and right_is_literal:
139
+ analyzed = self.ctx.analyzer.get_expr_type(expr)
140
+ if isinstance(analyzed, IntLiteralType):
141
+ return self.ctx.analyzer.ctx.default_int_for_literal(analyzed)
142
+ return self.ctx.analyzer.ctx.default_int_type
143
+ # If either operand is a fixed-width int (and other is compatible), result is that type
144
+ if is_fixed_int_type(left_type) and (is_fixed_int_type(right_type) or isinstance(right_type, IntLiteralType)):
145
+ return left_type
146
+ if is_fixed_int_type(right_type) and (is_fixed_int_type(left_type) or isinstance(left_type, IntLiteralType)):
147
+ return right_type
148
+ # Otherwise, result is BigInt if either operand is BigInt.
149
+ # For literal-literal arithmetic without stronger context, use the
150
+ # configured default integer type.
151
+ is_bigint_op = is_big_int_type(left_type) or is_big_int_type(right_type)
152
+ if is_bigint_op and expr.op in ("+", "-", "*", "//", "%", "**", "&", "|", "^", "<<", ">>"):
153
+ return BIGINT
154
+ if (
155
+ isinstance(left_type, IntLiteralType)
156
+ and isinstance(right_type, IntLiteralType)
157
+ and expr.op in ("+", "-", "*", "//", "%", "**", "&", "|", "^", "<<", ">>")
158
+ ):
159
+ analyzed = self.ctx.analyzer.get_expr_type(expr)
160
+ if isinstance(analyzed, IntLiteralType):
161
+ return self.ctx.analyzer.ctx.default_int_for_literal(analyzed)
162
+ return self.ctx.analyzer.ctx.default_int_type
163
+
164
+ typ = self.ctx.analyzer.get_expr_type(expr)
165
+ # Strip ReadonlyType -- C++ doesn't use it
166
+ typ = unwrap_readonly(typ) if typ else typ
167
+ resolved = self._resolve_pending_container(typ) if typ else None
168
+ if resolved is not None:
169
+ return resolved
170
+ if isinstance(typ, PendingViewType):
171
+ return self._resolve_pending_view(typ)
172
+ # Resolve IntLiteralType based on context (FixedInt/BigInt if target, else
173
+ # configured default int type).
174
+ if isinstance(typ, IntLiteralType):
175
+ if target_type is not None and is_integer_type(target_type):
176
+ return target_type
177
+ return self.ctx.analyzer.ctx.default_int_for_literal(typ)
178
+ # Resolve FloatLiteralType based on context (Float32 if target, else float64).
179
+ if isinstance(typ, FloatLiteralType):
180
+ if is_float32_type(target_type):
181
+ return FLOAT32
182
+ return FLOAT
183
+ # Resolve IntLiteralType in container element types
184
+ if is_list(typ) and isinstance(typ.type_args[0], IntLiteralType):
185
+ elem = self.ctx.analyzer.ctx.default_int_for_literal(typ.type_args[0])
186
+ return make_list(elem)
187
+ # Resolve IntLiteralType in tuple element types (recursively for nesting)
188
+ if isinstance(typ, TupleType):
189
+ resolve_lit = self.ctx.analyzer.ctx.default_int_for_literal
190
+ resolved_elems = []
191
+ changed = False
192
+ for i, et in enumerate(typ.element_types):
193
+ if isinstance(et, IntLiteralType):
194
+ # Use target_type's element if it's a FixedInt annotation
195
+ tt_elem = None
196
+ if isinstance(target_type, TupleType) and i < len(target_type.element_types):
197
+ tt_elem = target_type.element_types[i]
198
+ if tt_elem is not None and is_integer_type(tt_elem):
199
+ resolved_elems.append(tt_elem)
200
+ else:
201
+ resolved_elems.append(resolve_lit(et))
202
+ changed = True
203
+ elif isinstance(et, PendingViewType):
204
+ resolved_elems.append(self._resolve_pending_view(et))
205
+ changed = True
206
+ else:
207
+ resolved = resolve_int_literals(et, resolve_lit)
208
+ if resolved is not et:
209
+ changed = True
210
+ resolved_elems.append(resolved)
211
+ if changed:
212
+ return TupleType(tuple(resolved_elems))
213
+ return typ
214
+
215
+ def _resolve_view_storage(self, family: ViewTypeFamily, var_id: int) -> TpyType:
216
+ """Resolve a view-vars entry to its storage form (view or owned)."""
217
+ info = self.ctx.analyzer.ctx.view_vars(family).get(var_id)
218
+ return info.resolved_type if info and info.resolved_type else family.owned_type
219
+
220
+ def _resolve_pending_view(self, typ: PendingViewType) -> TpyType:
221
+ """Resolve a PendingViewType to its concrete type."""
222
+ return self._resolve_view_storage(typ.family, typ.var_id)
223
+
224
+ def _resolve_pending_container(self, typ: TpyType) -> TpyType | None:
225
+ """Resolve a pending container type via unified lookup.
226
+
227
+ Returns the resolved type, or None if not a pending container.
228
+ Falls back to a best-effort concrete type if resolution hasn't run
229
+ (e.g. list -> ListType with resolved element type).
230
+ """
231
+ if not isinstance(typ, PENDING_CONTAINER_TYPES):
232
+ return None
233
+ info = self.ctx.analyzer.ctx.get_container_info(typ.literal_id)
234
+ if info and info.resolved_type:
235
+ return info.resolved_type
236
+ # Fallback for unresolved containers
237
+ if isinstance(typ, PendingListType):
238
+ elem_type = typ.element_type
239
+ if isinstance(elem_type, IntLiteralType):
240
+ elem_type = self.ctx.analyzer.ctx.default_int_for_literal(elem_type)
241
+ return make_list(elem_type)
242
+ if isinstance(typ, PendingDictType):
243
+ return make_dict(typ.key_type, typ.value_type)
244
+ if isinstance(typ, PendingSetType):
245
+ return make_set(typ.element_type)
246
+ return None
247
+
248
+ def resolve_type(self, typ: TpyType) -> TpyType:
249
+ """Resolve deferred types (PendingViewType, PendingListType, etc.) to concrete C++ types."""
250
+ if isinstance(typ, PendingViewType):
251
+ return self._resolve_pending_view(typ)
252
+ resolved = self._resolve_pending_container(typ)
253
+ if resolved is not None:
254
+ return resolved
255
+ return typ
256
+
257
+ def substitute_type_params(self, typ: TpyType, subst: dict[str, TpyType]) -> TpyType:
258
+ """Substitute type parameters with concrete types for codegen.
259
+
260
+ This is simpler than the sema version - just applies the substitution.
261
+ """
262
+ if isinstance(typ, TypeParamRef):
263
+ return subst.get(typ.name, typ)
264
+ return typ.map_inner_types(lambda t: self.substitute_type_params(t, subst))
265
+
266
+ def involves_variables(self, expr: TpyExpr) -> bool:
267
+ """Check if an expression involves any variable references."""
268
+ if isinstance(expr, TpyCoerce):
269
+ return self.involves_variables(expr.expr)
270
+ if isinstance(expr, TpyName):
271
+ return True
272
+ if isinstance(expr, TpyIntLiteral):
273
+ return False
274
+ if isinstance(expr, TpyBinOp):
275
+ return self.involves_variables(expr.left) or self.involves_variables(expr.right)
276
+ if isinstance(expr, TpyUnaryOp):
277
+ return self.involves_variables(expr.operand)
278
+ if isinstance(expr, TpyCall):
279
+ return True # Function calls may return BigInt
280
+ if isinstance(expr, TpyMethodCall):
281
+ return True
282
+ # Default to True for safety
283
+ return True
284
+
285
+ def is_fixed_int_arithmetic(self, left_type: TpyType, right_type: TpyType, op: str) -> bool:
286
+ """Check if binary op produces fixed-int result (needs checked arithmetic).
287
+
288
+ Only applies when at least one operand is explicitly a fixed-width int.
289
+ IntLiteralType alone uses the configured default integer type.
290
+ """
291
+ if op not in ("+", "-", "*", "//", "%", "**"):
292
+ return False
293
+ has_fixed = is_fixed_int_type(left_type) or is_fixed_int_type(right_type)
294
+ if not has_fixed:
295
+ return False
296
+ def is_fixed_compatible(t: TpyType) -> bool:
297
+ return is_fixed_int_type(t) or isinstance(t, IntLiteralType)
298
+ return is_fixed_compatible(left_type) and is_fixed_compatible(right_type)
299
+
300
+ def is_runtime_bigint(self, expr: TpyExpr, expr_type: TpyType) -> bool:
301
+ """Check if expression is stored as BigInt at runtime."""
302
+ resolved = self.get_resolved_type(expr)
303
+ if is_big_int_type(resolved):
304
+ return True
305
+ if isinstance(resolved, IntLiteralType):
306
+ resolved_default = self.ctx.analyzer.ctx.default_int_for_literal(resolved)
307
+ return is_big_int_type(resolved_default)
308
+ return False
309
+
310
+ def varargs_elem_cpp(self, elem: TpyType) -> str:
311
+ """C++ element type for a `*args` parameter's `varargs<...>`.
312
+
313
+ `const T` for a readonly slot element (`*xs: readonly[T]` -> readonly
314
+ vararg with const element access), else `T`. Mirrors the Span cpp
315
+ formatter's `std::span<const T>` rendering and keeps the param-emit and
316
+ call-site pack-emit in lockstep (both must produce the same string).
317
+ """
318
+ if isinstance(elem, ReadonlyType):
319
+ return f"const {self.type_to_cpp(elem.wrapped)}"
320
+ return self.type_to_cpp(elem)
321
+
322
+ def type_to_cpp(self, typ: TpyType) -> str:
323
+ """Convert a type to its C++ representation, qualifying imported types.
324
+
325
+ For imported record types from user modules, generates fully qualified names
326
+ like tpyapp::utils::Point or tpyapp::pkg::mod::Point for packages.
327
+ Native records use their native C++ name directly (no namespace qualification).
328
+ @dynamic protocol types map to the base class name.
329
+ """
330
+ if isinstance(typ, NominalType) and is_protocol_type(typ):
331
+ protocol_info = protocol_info_of(typ)
332
+ if protocol_info and protocol_info.is_dynamic:
333
+ return self.protocols.get_dynamic_base_name(typ)
334
+ if isinstance(typ, NominalType) and typ.is_user_record:
335
+ # Native records use their native C++ name directly (globally visible)
336
+ record_info = self.ctx.analyzer.registry.get_record_for_type(typ)
337
+ if record_info and record_info.is_native:
338
+ return typ.to_cpp() # to_cpp() already resolves via Compiler.native_cpp_names
339
+ # Cross-module user record: qualify to the declaring module (canonical identity).
340
+ # Use the type-aware variant so records reachable only via an inferred
341
+ # cross-module return type (e.g. `import mod; p = mod.f()` where
342
+ # `f() -> Own[Pattern]`) still qualify -- short-name lookup would
343
+ # miss because `Pattern` isn't in the caller's local registry.
344
+ qual = self.ctx.analyzer.registry.imported_record_qualification_for_type(
345
+ typ, self.ctx.analyzer.ctx.module_name)
346
+ if qual is not None:
347
+ source_module, original_name = qual
348
+ qualified = qualified_cpp_name(source_module, original_name)
349
+ if typ.type_args:
350
+ args = ", ".join(
351
+ self.type_to_cpp(t) if isinstance(t, TpyType) else str(t)
352
+ for t in typ.type_args
353
+ )
354
+ return f"{qualified}<{args}>"
355
+ return qualified
356
+ # Enum type-position spelling. Routes through enum_cpp_name so
357
+ # @native enums render as their user-supplied qname rather than
358
+ # tpyapp::<module>::E. For local non-native enums this falls
359
+ # through to the local-name return below.
360
+ if is_enum_type(typ):
361
+ cur_module = self.ctx.analyzer.ctx.module_name
362
+ spelled = enum_cpp_name(typ, cur_module)
363
+ # Only return early if the helper produced something other
364
+ # than the bare local name (otherwise let the normal type
365
+ # rendering path continue, which uses Compiler.native_cpp_names).
366
+ if spelled != typ.name:
367
+ return spelled
368
+ # Tuple types: qualify element types for imported members
369
+ if isinstance(typ, TupleType):
370
+ args = ", ".join(self.type_to_cpp(t) for t in typ.element_types)
371
+ return f"std::tuple<{args}>"
372
+ # Union types: use alias name if registered, otherwise qualify member names
373
+ if isinstance(typ, UnionType):
374
+ compiler = get_current_compiler()
375
+ alias = compiler.union_alias_names.get(typ.members) if compiler is not None else None
376
+ if alias is not None:
377
+ return alias
378
+ cpp_members = [
379
+ "std::monostate" if is_void_like_type(m) else self.type_to_cpp(m)
380
+ for m in typ.members
381
+ ]
382
+ return f"std::variant<{', '.join(cpp_members)}>"
383
+ # Resolve PendingViewType to concrete types before codegen
384
+ if isinstance(typ, PendingViewType):
385
+ return self._resolve_pending_view(typ).to_cpp()
386
+ # For plain NominalType (not subclasses like ListType/ArrayType) with
387
+ # type_args, recursively resolve args to handle @dynamic protocols.
388
+ # Skip this branch when the TypeDef registry provides a custom
389
+ # cpp_formatter (e.g. CopyIter/OwnIter -> "auto", dict_keys ->
390
+ # ::tpy::dict_keys_view<...>) -- fall through to typ.to_cpp() so the
391
+ # formatter wins.
392
+ if type(typ) is NominalType and typ.type_args:
393
+ from tpyc.type_def_registry import type_def_of
394
+ td = type_def_of(typ)
395
+ if td is None or td.cpp_formatter is None:
396
+ base = typ.to_cpp_base_name()
397
+ args = ", ".join(
398
+ self.type_to_cpp(t) if isinstance(t, TpyType) else str(t)
399
+ for t in typ.type_args
400
+ )
401
+ return f"{base}<{args}>"
402
+ # Default: use the type's built-in to_cpp() method
403
+ return typ.to_cpp()
404
+
405
+ def type_to_cpp_stored(self, typ: TpyType) -> str:
406
+ """Convert a type to its stored C++ representation.
407
+
408
+ Like type_to_cpp but uses to_cpp_stored() (val_or_ref<T> for Ref types).
409
+ Resolves PendingViewType before conversion.
410
+ """
411
+ if isinstance(typ, PendingViewType):
412
+ return self._resolve_pending_view(typ).to_cpp_stored()
413
+ return typ.to_cpp_stored()
414
+
415
+ def type_to_cpp_ptr_variant(self, typ: 'UnionType') -> str:
416
+ """Return the pointer-variant type with qualified member names.
417
+
418
+ For non-value unions: std::variant<Dog*, Cat*> with cross-module
419
+ qualification on member types. Monostate members pass through.
420
+ """
421
+ cpp_members = [
422
+ "std::monostate" if is_void_like_type(m)
423
+ else f"{self.type_to_cpp(m)}*"
424
+ for m in typ.members
425
+ ]
426
+ return f"std::variant<{', '.join(cpp_members)}>"
427
+
428
+ def type_to_cpp_const_ptr_variant(self, typ: 'UnionType') -> str:
429
+ """Return the const pointer-variant type with qualified member names."""
430
+ cpp_members = [
431
+ "std::monostate" if is_void_like_type(m)
432
+ else f"const {self.type_to_cpp(m)}*"
433
+ for m in typ.members
434
+ ]
435
+ return f"std::variant<{', '.join(cpp_members)}>"
436
+
@@ -0,0 +1,135 @@
1
+ """Codegen helper for std::variant access patterns.
2
+
3
+ TurboPython unions lower to one of four C++ shapes:
4
+
5
+ - **Value variant**: `std::variant<A, B, ...>` -- members are value-typed,
6
+ variant stores them by value. Field / container / Own slot form.
7
+ - **Pointer variant**: `std::variant<A*, B*, ...>` -- members are non-value
8
+ reference types; the variant carries borrowed pointers. Param / local /
9
+ return form.
10
+ - **Wrapper struct**: `struct Tree { std::variant<...> value; }` -- emitted
11
+ for recursive union aliases (`type Tree = int | list[Tree]`) because
12
+ a plain `using` alias isn't forward-declarable in C++. The inner
13
+ `std::variant` is accessed via `.value`.
14
+ - **Optional-wrapped variant**: `std::optional<Tree>` where `Tree` is a
15
+ wrapper-struct alias, narrowed from `Tree | None`. The deref'd value
16
+ is itself a wrapper struct, so its `std::variant` is reached via
17
+ `(*opt).value`.
18
+
19
+ Each access site -- `std::holds_alternative<...>(...)`, `std::get<...>(...)`,
20
+ `.index()` switch dispatch -- has to make four decisions: deref prefix
21
+ (`*` for ptr-variant), type suffix (`*` for ptr-variant), `.value`
22
+ indirection (wrapper struct), and const propagation (`const T*` for
23
+ const-indirect locals). `VariantAccess` captures those decisions once at
24
+ construction and emits the right expressions through its methods, so
25
+ call sites stop re-deriving the same shape facts inline.
26
+
27
+ This module is the canonical source for variant access strings. Direct
28
+ `std::get` / `std::holds_alternative` formatting elsewhere in codegen
29
+ should be migrated here over time.
30
+ """
31
+
32
+ from __future__ import annotations
33
+ from dataclasses import dataclass
34
+
35
+ from ..typesys import TpyType, OptionalType, AliasRef, unwrap_qualifiers, unwrap_ref_type
36
+
37
+
38
+ def _needs_value_indirection(typ: TpyType | None) -> bool:
39
+ """True if the type's C++ form is a wrapper struct whose `std::variant`
40
+ is reached via `.value`. Covers recursive-union wrappers and
41
+ OptionalType wrapping a recursive-alias placeholder (the narrowed
42
+ deref'd value is itself a wrapper struct). Qualifiers (`readonly`,
43
+ `Own`, `Ref`) are peeled before testing -- a `readonly[Tree]` param
44
+ still resolves to its wrapper struct at the variant access site."""
45
+ if typ is None:
46
+ return False
47
+ peeled = unwrap_ref_type(unwrap_qualifiers(typ))
48
+ if peeled.needs_wrapper():
49
+ return True
50
+ if isinstance(peeled, OptionalType) and isinstance(peeled.inner, AliasRef):
51
+ return True
52
+ return False
53
+
54
+
55
+ @dataclass
56
+ class VariantAccess:
57
+ """Codegen helper for emitting std::variant access patterns.
58
+
59
+ Construct once per access site with the base C++ expression, its
60
+ TPy type, and the shape flags (`is_ptr_variant`, `is_const`), then
61
+ call `index_expr()`, `holds(member)`, `get_by_type(member)`, or
62
+ `get_by_index(idx)` to produce the C++ access string.
63
+ """
64
+ base_expr: str # C++ expression that yields the variant or its wrapper
65
+ typ: TpyType | None # TPy type of `base_expr`; None disables wrapper indirection
66
+ is_ptr_variant: bool # runtime form is `std::variant<T*, U*, ...>`
67
+ is_const: bool = False # const propagation for ptr-variant get (`std::get<const T*>(...)`)
68
+
69
+ # --- Access expressions --------------------------------------------
70
+
71
+ @property
72
+ def variant_expr(self) -> str:
73
+ """C++ expression yielding the underlying `std::variant`.
74
+
75
+ Adds `.value` when the base type is a wrapper struct (recursive
76
+ alias) or an Optional wrapping a recursive-alias placeholder.
77
+ """
78
+ if _needs_value_indirection(self.typ):
79
+ return f"{self.base_expr}.value"
80
+ return self.base_expr
81
+
82
+ def index_expr(self) -> str:
83
+ """`variant.index()` -- for switch dispatch on the active tag."""
84
+ return f"{self.variant_expr}.index()"
85
+
86
+ def holds(self, member_cpp: str) -> str:
87
+ """`std::holds_alternative<member>(variant)` -- type test for a
88
+ specific alternative. Adds `*` suffix for ptr-variant and `const`
89
+ prefix for const-indirect borrows."""
90
+ type_arg = self._type_arg(member_cpp)
91
+ return f"std::holds_alternative<{type_arg}>({self.variant_expr})"
92
+
93
+ def get_by_type(self, member_cpp: str, *, lvalue: bool = False) -> str:
94
+ """`std::get<member>(variant)` extracting the typed alternative.
95
+
96
+ For ptr-variant, the result is dereferenced so the form is the
97
+ same value shape as for value-variant. `lvalue=False` (default)
98
+ wraps in outer parens for safe embedding in larger expressions
99
+ (`(*std::get<T*>(v))`). `lvalue=True` omits the parens, suitable
100
+ for direct binding sites like `auto& local = expr;`."""
101
+ type_arg = self._type_arg(member_cpp)
102
+ if self.is_ptr_variant:
103
+ inner = f"*std::get<{type_arg}>({self.variant_expr})"
104
+ return inner if lvalue else f"({inner})"
105
+ return f"std::get<{type_arg}>({self.variant_expr})"
106
+
107
+ def get_by_index(self, idx: int) -> str:
108
+ """`std::get<I>(variant)` -- match-arm extraction by tag index.
109
+
110
+ For ptr-variant: emits `*std::get<I>(variant)` (without outer
111
+ parens; match-arm sites consume the expression as an lvalue and
112
+ bind via `auto&`)."""
113
+ if self.is_ptr_variant:
114
+ return f"*std::get<{idx}>({self.variant_expr})"
115
+ return f"std::get<{idx}>({self.variant_expr})"
116
+
117
+ # Boundary conversions (`::tpy::to_ptr_variant` / `to_const_ptr_variant`
118
+ # / `to_value_variant`) are not exposed here because every call site
119
+ # has different surrounding context (template arg for value form,
120
+ # mutability for ptr form). Keeping them open-coded at the call site
121
+ # has proven clearer than a partial-uniformity API.
122
+
123
+ # --- Internal ------------------------------------------------------
124
+
125
+ def _type_arg(self, member_cpp: str) -> str:
126
+ """Build the template argument for `std::get<...>` /
127
+ `std::holds_alternative<...>`. Adds `*` suffix and `const` prefix
128
+ when the runtime form is ptr-variant. `std::monostate` (the None
129
+ tag) is form-invariant -- ptr-variants carry it verbatim as a
130
+ monostate alternative, not a `std::monostate*` -- so it passes
131
+ through unchanged."""
132
+ if self.is_ptr_variant and member_cpp != "std::monostate":
133
+ const = "const " if self.is_const else ""
134
+ return f"{const}{member_cpp}*"
135
+ return member_cpp