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,160 @@
1
+ """
2
+ Numeric inference lattice helpers.
3
+
4
+ This module centralizes numeric family/rank logic used by reassignment-based
5
+ inference so future numeric types can be added in one place.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+ from ..typesys import (
13
+ TpyType, IntLiteralType, FloatLiteralType,
14
+ BIGINT, FLOAT, FLOAT32,
15
+ is_float_type,
16
+ )
17
+ from ..type_def_registry import (
18
+ is_fixed_int_type, is_big_int_type, is_bool_type,
19
+ is_float32_type, is_float64_type,
20
+ int_traits_of,
21
+ )
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class NumericTypeInfo:
26
+ """Classification metadata for numeric-like types."""
27
+ family: str # "int_literal" | "float_literal" | "int" | "float" | "bool"
28
+ rank: int
29
+
30
+
31
+ def numeric_info(typ: TpyType) -> NumericTypeInfo | None:
32
+ """Return numeric metadata for known numeric-like types."""
33
+ if isinstance(typ, IntLiteralType):
34
+ return NumericTypeInfo("int_literal", 0)
35
+ if isinstance(typ, FloatLiteralType):
36
+ return NumericTypeInfo("float_literal", 0)
37
+ if is_fixed_int_type(typ):
38
+ # Rank scales with bit width: Int8=8, Int16=9, Int32=10, Int64=11
39
+ tr = int_traits_of(typ)
40
+ assert tr is not None, f"fixed int without IntTraits: {typ}"
41
+ return NumericTypeInfo("int", tr.bits // 8 + 6)
42
+ if is_big_int_type(typ):
43
+ return NumericTypeInfo("int", 100)
44
+ if is_float32_type(typ):
45
+ return NumericTypeInfo("float", 190)
46
+ if is_float64_type(typ):
47
+ return NumericTypeInfo("float", 200)
48
+ if is_bool_type(typ):
49
+ return NumericTypeInfo("bool", 5)
50
+ return None
51
+
52
+
53
+ def fixed_int_range_contains(typ: TpyType, value: int) -> bool:
54
+ tr = int_traits_of(typ)
55
+ assert tr is not None, f"fixed_int_range_contains called on non-fixed-int {typ}"
56
+ return tr.min_value <= value <= tr.max_value
57
+
58
+
59
+ def merge_literal_seed_target(
60
+ existing_type: TpyType,
61
+ init_type: TpyType,
62
+ literal_values: list[int],
63
+ ) -> TpyType | None:
64
+ """Infer target type for a literal-seeded variable.
65
+
66
+ A literal-seeded variable starts as ctx.default_int_type (`x = 0`) and may
67
+ be refined by later writes if safe.
68
+ """
69
+ if isinstance(init_type, IntLiteralType):
70
+ if (
71
+ is_fixed_int_type(existing_type)
72
+ and init_type.value is not None
73
+ and not fixed_int_range_contains(existing_type, init_type.value)
74
+ ):
75
+ return BIGINT
76
+ return existing_type
77
+ if is_fixed_int_type(init_type):
78
+ if all(fixed_int_range_contains(init_type, v) for v in literal_values):
79
+ return init_type
80
+ return existing_type
81
+ if is_big_int_type(init_type):
82
+ return BIGINT
83
+ if is_float32_type(init_type):
84
+ return FLOAT32
85
+ if is_float64_type(init_type):
86
+ return FLOAT
87
+ # bool is intentionally separate and should not merge with numeric literals.
88
+ return None
89
+
90
+
91
+ def widen_numeric_types(a: TpyType, b: TpyType) -> TpyType | None:
92
+ """Return the widened type for two concrete numeric types, or None.
93
+
94
+ Used by reassignment inference when a variable is assigned a different
95
+ numeric type (e.g. Int32 then Int64 -> Int64, Int32 then float -> float).
96
+
97
+ Returns None when widening is not applicable (non-numeric, bool mixed
98
+ with numeric, same-width mixed sign).
99
+ """
100
+ info_a = numeric_info(a)
101
+ info_b = numeric_info(b)
102
+ if info_a is None or info_b is None:
103
+ return None
104
+
105
+ # Bool mixed with numeric -> refuse
106
+ if info_a.family == "bool" or info_b.family == "bool":
107
+ return None
108
+
109
+ # Literal families are handled by merge_literal_seed_target, not here.
110
+ # Defensive: callers (local_deduction, _ternary_common_type) already
111
+ # resolve literals to concrete types before delegating; this guards
112
+ # against future callers that forget.
113
+ if info_a.family in ("int_literal", "float_literal"):
114
+ return None
115
+ if info_b.family in ("int_literal", "float_literal"):
116
+ return None
117
+
118
+ # Both float-family -> widen to the higher-rank float
119
+ if is_float_type(a) and is_float_type(b):
120
+ if a == b:
121
+ return None
122
+ # Float64 wins over Float32
123
+ return a if is_float64_type(a) else b
124
+
125
+ # Either is float-family -> float-family wins over int
126
+ if is_float_type(a):
127
+ return a
128
+ if is_float_type(b):
129
+ return b
130
+
131
+ # Both BigInt -> same type, no widening
132
+ if is_big_int_type(a) and is_big_int_type(b):
133
+ return None
134
+
135
+ # Either is BigInt -> BigInt wins
136
+ if is_big_int_type(a):
137
+ return a
138
+ if is_big_int_type(b):
139
+ return b
140
+
141
+ # Both FixedInt
142
+ a_tr = int_traits_of(a)
143
+ b_tr = int_traits_of(b)
144
+ assert a_tr is not None and b_tr is not None, f"expected fixed ints, got {a} and {b}"
145
+ if a_tr == b_tr:
146
+ return None
147
+
148
+ if a_tr.signed == b_tr.signed:
149
+ return a if a_tr.bits > b_tr.bits else b
150
+
151
+ # Mixed sign: allow only if the wider type is signed with strictly more bits
152
+ if a_tr.bits > b_tr.bits:
153
+ wider, wider_traits, narrower_traits = a, a_tr, b_tr
154
+ else:
155
+ wider, wider_traits, narrower_traits = b, b_tr, a_tr
156
+ if wider_traits.signed and wider_traits.bits > narrower_traits.bits:
157
+ return wider
158
+
159
+ # Same width mixed sign (e.g. Int32 + UInt32) -> refuse
160
+ return None
tpyc/sema/operators.py ADDED
@@ -0,0 +1,402 @@
1
+ """
2
+ TurboPython Operator Resolution
3
+
4
+ Binary and unary operator resolution using the type registry.
5
+ """
6
+
7
+ from __future__ import annotations
8
+ from dataclasses import replace as dc_replace
9
+ from typing import TYPE_CHECKING, Callable
10
+
11
+ from ..typesys import (
12
+ TpyType, IntLiteralType, FloatLiteralType, LiteralType, TypeParamRef,
13
+ ResolvedBinop, ResolvedUnaryop, FunctionInfo, TypeParamKind,
14
+ INT32, FLOAT, PendingListType, make_list, OwnType, unwrap_ref_type,
15
+ unwrap_readonly,
16
+ )
17
+ from .overloads import type_matches_numeric, type_matches_strict
18
+ from tpyc import modules as builtin_modules
19
+
20
+ if TYPE_CHECKING:
21
+ from .context import SemanticContext
22
+ from .protocols import ProtocolChecker as ProtocolCheckerObj
23
+ from .type_ops import TypeOperations
24
+ ProtocolChecker = Callable[[TpyType, TpyType], bool]
25
+
26
+ from .bound_check import raise_if_class_param_bound_violated
27
+
28
+
29
+ # C++ templates for user-defined dunder methods (used for unified operator resolution)
30
+ # These use C++ operator syntax which works for user types with operator overloads
31
+ DUNDER_CPP_TEMPLATES: dict[str, str] = {
32
+ # Binary operators
33
+ "__add__": "({self}) + ({0})",
34
+ "__sub__": "({self}) - ({0})",
35
+ "__mul__": "({self}) * ({0})",
36
+ "__truediv__": "({self}) / ({0})",
37
+ "__floordiv__": "({self}) / ({0})", # User types use regular division
38
+ "__mod__": "({self}) % ({0})",
39
+ "__pow__": "std::pow({self}, {0})",
40
+ "__lshift__": "({self}) << ({0})",
41
+ "__rshift__": "({self}) >> ({0})",
42
+ "__and__": "({self}) & ({0})",
43
+ "__or__": "({self}) | ({0})",
44
+ "__xor__": "({self}) ^ ({0})",
45
+ # Comparison operators
46
+ "__eq__": "({self}) == ({0})",
47
+ "__ne__": "({self}) != ({0})",
48
+ "__lt__": "({self}) < ({0})",
49
+ "__le__": "({self}) <= ({0})",
50
+ "__gt__": "({self}) > ({0})",
51
+ "__ge__": "({self}) >= ({0})",
52
+ # Reverse operators
53
+ "__radd__": "({0}) + ({self})",
54
+ "__rsub__": "({0}) - ({self})",
55
+ "__rmul__": "({0}) * ({self})",
56
+ "__rtruediv__": "({0}) / ({self})",
57
+ "__rfloordiv__": "({0}) / ({self})",
58
+ "__rmod__": "({0}) % ({self})",
59
+ "__rpow__": "std::pow({0}, {self})",
60
+ "__rlshift__": "({0}) << ({self})",
61
+ "__rrshift__": "({0}) >> ({self})",
62
+ "__rand__": "({0}) & ({self})",
63
+ "__ror__": "({0}) | ({self})",
64
+ "__rxor__": "({0}) ^ ({self})",
65
+ # Unary operators
66
+ "__pos__": "+({self})",
67
+ "__neg__": "-({self})",
68
+ "__invert__": "~({self})",
69
+ # Conversion methods (used for operator promotion)
70
+ "__int__": "({self}).__int__()",
71
+ }
72
+
73
+
74
+ def _substitute_type_params(typ: TpyType, subst: dict[str, TpyType]) -> TpyType:
75
+ """Substitute TypeParamRef instances in a type according to subst map."""
76
+ if isinstance(typ, TypeParamRef) and typ.name in subst:
77
+ return subst[typ.name]
78
+ return typ.map_inner_types(lambda t: _substitute_type_params(t, subst))
79
+
80
+
81
+ class OperatorResolver:
82
+ """Resolves binary and unary operators using the type registry."""
83
+
84
+ def __init__(
85
+ self, ctx: SemanticContext,
86
+ type_ops: 'TypeOperations', protocols: 'ProtocolCheckerObj',
87
+ ):
88
+ self.ctx = ctx
89
+ self.type_ops = type_ops
90
+ # Used to enforce class-shadowed method type-param bounds at dispatch.
91
+ self.protocols = protocols
92
+
93
+ def _check_class_bounds(
94
+ self, method: FunctionInfo, receiver_type: TpyType,
95
+ class_subst: dict[str, 'TpyType | int'], loc_node,
96
+ ) -> None:
97
+ """Raise if the receiver doesn't satisfy a class-shadowed method bound.
98
+
99
+ Operator dispatch bypasses `_analyze_generic_method_call` (which runs
100
+ the same check), so every resolve_* path must invoke this so the
101
+ sema-level error matches what codegen's `requires` clause catches at
102
+ C++ instantiation time.
103
+ """
104
+ # Cheap method-level guard first: short-circuits the common case
105
+ # (every operator dispatch where the matched method has no bounds).
106
+ if not method.type_param_bounds:
107
+ return
108
+ # readonly[Box[T]] conforms to any protocol Box[T] does -- mirror that
109
+ # unwrap here so the bound check operates on the inner record.
110
+ record = self.ctx.registry.get_record_for_type(unwrap_readonly(receiver_type))
111
+ if record is None or not record.type_params:
112
+ return
113
+ raise_if_class_param_bound_violated(
114
+ method, record.type_params, class_subst,
115
+ self.protocols.type_conforms_to_protocol,
116
+ self.ctx.error, loc_node,
117
+ )
118
+
119
+ def _resolve_pending_types(self, tpy_type: TpyType) -> TpyType:
120
+ """Resolve pending/structural types (PendingListType, TypeParamRef, LiteralType).
121
+
122
+ Preserves IntLiteralType for flexible overload matching.
123
+ """
124
+ if isinstance(tpy_type, TypeParamRef) and tpy_type.kind == TypeParamKind.INT:
125
+ return INT32
126
+ if isinstance(tpy_type, PendingListType):
127
+ return make_list(tpy_type.element_type)
128
+ if isinstance(tpy_type, LiteralType):
129
+ return tpy_type.base_type
130
+ return tpy_type
131
+
132
+ def get_effective_type_for_binop(self, tpy_type: TpyType) -> TpyType:
133
+ """Fully resolve type for registry lookup (also resolves IntLiteralType/FloatLiteralType)."""
134
+ tpy_type = unwrap_ref_type(tpy_type)
135
+ if isinstance(tpy_type, OwnType):
136
+ tpy_type = tpy_type.wrapped
137
+ if isinstance(tpy_type, IntLiteralType):
138
+ return self.ctx.default_int_for_literal(tpy_type)
139
+ if isinstance(tpy_type, FloatLiteralType):
140
+ return FLOAT
141
+ if isinstance(tpy_type, LiteralType):
142
+ return tpy_type.base_type
143
+ return self._resolve_pending_types(tpy_type)
144
+
145
+ def _build_type_subst(
146
+ self, receiver_type: TpyType, arg_effective: TpyType,
147
+ ) -> dict[str, TpyType]:
148
+ """Build type param substitution from a concrete receiver type.
149
+
150
+ When the receiver has IntLiteralType element(s), adapts to the arg's
151
+ concrete element type if available, otherwise resolves to default int.
152
+ """
153
+ # Drop int-kind type args (e.g. N in Array[T, N]) --
154
+ # _substitute_type_params only acts on TypeParamRef -> TpyType.
155
+ subst: dict[str, TpyType] = {
156
+ k: v for k, v in self.type_ops.build_type_substitution(receiver_type).items()
157
+ if isinstance(v, TpyType)
158
+ }
159
+ if not subst:
160
+ return {}
161
+ arg_params = builtin_modules.extract_type_params(arg_effective)
162
+ for name, typ in list(subst.items()):
163
+ if isinstance(typ, IntLiteralType):
164
+ arg_val = arg_params.get(name)
165
+ if arg_val is not None and not isinstance(arg_val, IntLiteralType):
166
+ subst[name] = arg_val
167
+ else:
168
+ subst[name] = self.ctx.default_int_for_literal(typ)
169
+ return subst
170
+
171
+ def _find_matching_overload(
172
+ self, overloads: list[FunctionInfo], arg_type: TpyType,
173
+ type_subst: dict[str, TpyType],
174
+ protocol_checker: ProtocolChecker | None = None,
175
+ ) -> FunctionInfo | None:
176
+ """Find an overload matching arg_type, substituting type params first."""
177
+ for method in overloads:
178
+ if len(method.params) == 1:
179
+ _, param_type = method.params[0]
180
+ param_type = unwrap_ref_type(param_type)
181
+ if type_subst:
182
+ param_type = _substitute_type_params(param_type, type_subst)
183
+ if (type_matches_strict(arg_type, param_type, protocol_checker)
184
+ or type_matches_numeric(arg_type, param_type)):
185
+ return method
186
+ return None
187
+
188
+ def _make_resolved(
189
+ self, method: FunctionInfo, type_subst: dict[str, TpyType],
190
+ receiver_type: TpyType, loc_node, left_wrapper: str = "{expr}",
191
+ right_wrapper: str = "{expr}", is_reverse: bool = False,
192
+ ) -> ResolvedBinop:
193
+ """Create ResolvedBinop with type params substituted in method signature."""
194
+ # Bound check before substitution rewrites `method` (bounds are on the
195
+ # original FunctionInfo and indexed by class-shadow names). Raises on
196
+ # violation -- the resolver never returns a result carrying one.
197
+ self._check_class_bounds(method, receiver_type, type_subst, loc_node)
198
+ if type_subst:
199
+ new_params = [
200
+ dc_replace(p, type=_substitute_type_params(p.type, type_subst))
201
+ for p in method.params
202
+ ]
203
+ new_return = _substitute_type_params(method.return_type, type_subst)
204
+ method = dc_replace(method, params=new_params, return_type=new_return,
205
+ canonical_fi=method.root)
206
+ # Unwrap Ref from return type -- Ref is a codegen-level concern,
207
+ # sema expression types should not carry it.
208
+ ret = unwrap_ref_type(method.return_type)
209
+ if ret is not method.return_type:
210
+ method = dc_replace(method, return_type=ret, canonical_fi=method.root)
211
+ # Rebuild receiver_type from subst to resolve IntLiteralType elements.
212
+ # Use inner_types() as the source of truth for the reconstruction -- it
213
+ # defines exactly how many (and which) inner types the type has. params_map
214
+ # may have more entries (e.g. Tspan for PtrType), but with_inner_types only
215
+ # accepts len(inner_types()) values.
216
+ inner = receiver_type.inner_types()
217
+ if inner:
218
+ params_map = builtin_modules.extract_type_params(receiver_type)
219
+ param_names = list(params_map.keys())
220
+ new_inner = tuple(
221
+ type_subst.get(param_names[i], inner[i]) if i < len(param_names) else inner[i]
222
+ for i in range(len(inner))
223
+ )
224
+ receiver_type = receiver_type.with_inner_types(new_inner)
225
+ return ResolvedBinop(
226
+ method=method,
227
+ left_wrapper=left_wrapper,
228
+ right_wrapper=right_wrapper,
229
+ is_reverse=is_reverse,
230
+ receiver_type=receiver_type,
231
+ )
232
+
233
+ def resolve_binop(
234
+ self, left_type: TpyType, op: str, right_type: TpyType,
235
+ loc_node=None,
236
+ ) -> ResolvedBinop | None:
237
+ """Resolve binary operator using registry.
238
+
239
+ Handles both builtin types and user-defined types with dunder methods.
240
+ User-defined methods have cpp_template set to C++ operator syntax.
241
+
242
+ Generic methods (e.g. list[T].__add__) have their type params substituted
243
+ based on the receiver's concrete element type.
244
+
245
+ Tries in order:
246
+ 1. left.__add__(right) - direct match
247
+ 2. If left has __int__ returning right's type, promote left and use right's __add__
248
+ 3. right.__radd__(left) - reverse operator
249
+ 4. If right has __int__ returning left's type, promote right and use left's __add__
250
+ """
251
+ method_name = builtin_modules.BINOP_TO_METHOD.get(op)
252
+ rmethod_name = builtin_modules.BINOP_TO_RMETHOD.get(op)
253
+ if not method_name:
254
+ return None
255
+
256
+ # Get effective types (IntLiteralType -> configured default int type,
257
+ # PendingListType -> ListType)
258
+ left_effective = self.get_effective_type_for_binop(left_type)
259
+ right_effective = self.get_effective_type_for_binop(right_type)
260
+
261
+ left_record = self.ctx.registry.get_record_for_type(left_effective)
262
+ right_record = self.ctx.registry.get_record_for_type(right_effective)
263
+
264
+ # Build type substitution maps for generic types (e.g. list[T] -> list[Int32])
265
+ left_subst = self._build_type_subst(left_effective, right_effective)
266
+ right_subst = self._build_type_subst(right_effective, left_effective)
267
+
268
+ # For overload matching, resolve structural types but preserve
269
+ # IntLiteralType flexibility (matches any numeric type)
270
+ left_arg = unwrap_ref_type(self._resolve_pending_types(left_type))
271
+ right_arg = unwrap_ref_type(self._resolve_pending_types(right_type))
272
+
273
+ # 1. Try direct: left.__add__(right)
274
+ if left_record:
275
+ overloads = left_record.get_method_overloads(method_name)
276
+ if method := self._find_matching_overload(overloads, right_arg, left_subst):
277
+ return self._make_resolved(method, left_subst, left_effective, loc_node)
278
+
279
+ # 2. Try promoting left to right's type via __int__
280
+ if left_record and right_record:
281
+ int_overloads = left_record.get_method_overloads("__int__")
282
+ if int_overloads:
283
+ int_method = int_overloads[0]
284
+ promoted_type = int_method.return_type
285
+ # Check if promoted type matches right's type
286
+ if self.ctx.registry.get_record_for_type(promoted_type) == right_record:
287
+ right_overloads = right_record.get_method_overloads(method_name)
288
+ if method := self._find_matching_overload(right_overloads, right_arg, right_subst):
289
+ return self._make_resolved(
290
+ method, right_subst, right_effective, loc_node,
291
+ left_wrapper=int_method.cpp_template or "{expr}",
292
+ )
293
+
294
+ # 3. Try reverse: right.__radd__(left)
295
+ if right_record and rmethod_name:
296
+ overloads = right_record.get_method_overloads(rmethod_name)
297
+ if method := self._find_matching_overload(overloads, left_arg, right_subst):
298
+ return self._make_resolved(
299
+ method, right_subst, right_effective, loc_node, is_reverse=True,
300
+ )
301
+
302
+ # 4. Try promoting right to left's type via __int__, then use left's operator
303
+ if right_record and left_record:
304
+ int_overloads = right_record.get_method_overloads("__int__")
305
+ if int_overloads:
306
+ int_method = int_overloads[0]
307
+ promoted_type = int_method.return_type
308
+ # Check if promoted type matches left's type
309
+ if self.ctx.registry.get_record_for_type(promoted_type) == left_record:
310
+ left_overloads = left_record.get_method_overloads(method_name)
311
+ if method := self._find_matching_overload(left_overloads, promoted_type, left_subst):
312
+ return self._make_resolved(
313
+ method, left_subst, left_effective, loc_node,
314
+ right_wrapper=int_method.cpp_template or "{expr}",
315
+ )
316
+
317
+ return None
318
+
319
+ def resolve_aug_inplace(
320
+ self, target_type: TpyType, op: str, value_type: TpyType,
321
+ protocol_checker: ProtocolChecker | None = None,
322
+ loc_node=None,
323
+ ) -> ResolvedBinop | None:
324
+ """Resolve in-place augmented assignment operator (e.g. __iadd__, __ior__).
325
+
326
+ Returns a ResolvedBinop whose method has a void return type and a cpp
327
+ template that mutates {self} in place (e.g. tpy::set_update({self}, {0})).
328
+ For user-defined methods, generates {self}.__iadd__({0}) call.
329
+ """
330
+ method_name = builtin_modules.AUGOP_TO_IMETHOD.get(op)
331
+ if not method_name:
332
+ return None
333
+
334
+ target_effective = self.get_effective_type_for_binop(target_type)
335
+ record = self.ctx.registry.get_record_for_type(target_effective)
336
+ if not record:
337
+ return None
338
+
339
+ type_subst = self._build_type_subst(target_effective, value_type)
340
+ value_arg = unwrap_ref_type(self._resolve_pending_types(value_type))
341
+
342
+ overloads = record.get_method_overloads(method_name)
343
+ # Try builtin methods with cpp_template first
344
+ builtin_overloads = [m for m in overloads if m.cpp_template]
345
+ if method := self._find_matching_overload(builtin_overloads, value_arg, type_subst, protocol_checker):
346
+ return self._make_resolved(method, type_subst, target_effective, loc_node)
347
+
348
+ # Then try user-defined methods (no cpp_template)
349
+ user_overloads = [m for m in overloads if not m.cpp_template]
350
+ if method := self._find_matching_overload(user_overloads, value_arg, type_subst, protocol_checker):
351
+ return self._make_resolved(method, type_subst, target_effective, loc_node)
352
+
353
+ return None
354
+
355
+ def get_aug_inplace_param_type(
356
+ self, target_type: TpyType, op: str,
357
+ ) -> TpyType | None:
358
+ """Return the expected param type for an in-place operator, or None if not defined.
359
+
360
+ Used to produce precise type mismatch errors when resolve_aug_inplace fails:
361
+ the caller can pass the returned type to check_type_compatible to get a
362
+ specific "expected X, got Y" error instead of a generic "not supported" error.
363
+ """
364
+ method_name = builtin_modules.AUGOP_TO_IMETHOD.get(op)
365
+ if not method_name:
366
+ return None
367
+
368
+ target_effective = self.get_effective_type_for_binop(target_type)
369
+ record = self.ctx.registry.get_record_for_type(target_effective)
370
+ if not record:
371
+ return None
372
+
373
+ overloads = record.get_method_overloads(method_name)
374
+ candidates = [m for m in overloads if m.params]
375
+ if not candidates:
376
+ return None
377
+
378
+ type_subst = self._build_type_subst(target_effective, target_effective)
379
+ _, param_type = candidates[0].params[0]
380
+ if type_subst:
381
+ param_type = _substitute_type_params(param_type, type_subst)
382
+ return param_type
383
+
384
+ def resolve_unaryop(
385
+ self, operand_type: TpyType, op: str, loc_node=None,
386
+ ) -> ResolvedUnaryop | None:
387
+ """Resolve unary operator using registry."""
388
+ method_name = builtin_modules.UNARYOP_TO_METHOD.get(op)
389
+ if not method_name:
390
+ return None
391
+
392
+ effective_type = self.get_effective_type_for_binop(operand_type)
393
+ record = self.ctx.registry.get_record_for_type(effective_type)
394
+ if record:
395
+ overloads = record.get_method_overloads(method_name)
396
+ if overloads and len(overloads[0].params) == 0:
397
+ method = overloads[0]
398
+ class_subst = self._build_type_subst(effective_type, effective_type)
399
+ self._check_class_bounds(method, effective_type, class_subst, loc_node)
400
+ return ResolvedUnaryop(method=method)
401
+
402
+ return None