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
tpyc/coercions.py ADDED
@@ -0,0 +1,749 @@
1
+ """Type coercion registry for TurboPython."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+ from typing import Callable, Optional
8
+
9
+ from .typesys import (
10
+ TpyType, IntLiteralType, FloatLiteralType, LiteralType,
11
+ NominalType, PtrType, OptionalType, OwnType, is_readonly_ptr,
12
+ is_readonly_span, PendingListType, TypeParamRef, TypeParamKind, ReadonlyType,
13
+ is_integer_type, unwrap_readonly, AnyType,
14
+ )
15
+ from .type_def_registry import (
16
+ is_array, is_span, is_list, is_dict, is_set, int_traits_of,
17
+ is_fixed_int_type, is_big_int_type, is_float64_type, is_float32_type,
18
+ is_char_type, is_str_type, is_string_type, is_str_view_type,
19
+ is_bytes_type, is_bytearray_type, is_bytes_view_type,
20
+ is_basic_slice_type, is_slice_type,
21
+ )
22
+
23
+
24
+ class CoercionContext(Enum):
25
+ """Context in which a type coercion is being applied."""
26
+ ASSIGN = "assign"
27
+ INIT = "init"
28
+ ARG = "arg"
29
+ RETURN = "return"
30
+
31
+
32
+ # A type-side matcher: predicate that identifies the actual/expected side.
33
+ # Used by `Coercion.from_type` / `Coercion.to_type` as a coarse pre-filter;
34
+ # finer discrimination (e.g. element equality, readonly-ness) belongs in
35
+ # `Coercion.type_match`.
36
+ TypeMatcher = Callable[[TpyType], bool]
37
+
38
+
39
+ def _is(cls: type) -> TypeMatcher:
40
+ """Build a TypeMatcher that checks isinstance against a class."""
41
+ return lambda t: isinstance(t, cls)
42
+
43
+
44
+ def _match_any_side(_: TpyType) -> bool:
45
+ return True
46
+
47
+
48
+ def _match_any(_: TpyType, __: TpyType) -> bool:
49
+ return True
50
+
51
+
52
+ def _int_type_param_match(actual: TpyType, expected: TpyType) -> bool:
53
+ """Check if actual is an INT TypeParamRef."""
54
+ return isinstance(actual, TypeParamRef) and actual.kind == TypeParamKind.INT
55
+
56
+
57
+ def _int_literal_fits_fixed_int(lit: TpyType, target: TpyType) -> bool:
58
+ """check_range for int_literal_to_fixed_int: literal value (if known) must
59
+ fit in the target fixed-int's range."""
60
+ if not isinstance(lit, IntLiteralType):
61
+ return False
62
+ tr = int_traits_of(target)
63
+ if tr is None:
64
+ return False
65
+ return lit.value is None or (tr.min_value <= lit.value <= tr.max_value)
66
+
67
+
68
+ def _is_safe_widening(actual: TpyType, expected: TpyType) -> bool:
69
+ """Check if actual fixed-int can safely widen to expected fixed-int."""
70
+ a = int_traits_of(actual)
71
+ b = int_traits_of(expected)
72
+ if a is None or b is None:
73
+ return False
74
+ if a == b:
75
+ return False
76
+ if a.signed == b.signed:
77
+ return a.bits < b.bits
78
+ # Unsigned -> signed: need strictly more bits (e.g. UInt8 -> Int16)
79
+ if not a.signed and b.signed:
80
+ return a.bits < b.bits
81
+ return False
82
+
83
+
84
+ def _spanlike_to_span_match(actual: TpyType, expected: TpyType) -> bool:
85
+ """Check if actual type (extending Spannable[T]) can coerce to Span[T]/ReadOnlySpan[T]."""
86
+ if not is_span(expected):
87
+ return False
88
+ # Span[readonly[T]] and readonly[container] cannot coerce to mutable Span (const violation)
89
+ expected_is_readonly = is_readonly_span(expected)
90
+ if is_span(actual) and is_readonly_span(actual) and not expected_is_readonly:
91
+ return False
92
+ if isinstance(actual, ReadonlyType) and not expected_is_readonly:
93
+ return False
94
+ actual_elem = actual.get_element_type()
95
+ if actual_elem is None:
96
+ return False
97
+ expected_elem = unwrap_readonly(expected.type_args[0])
98
+
99
+ # PendingListType is an internal compiler type that resolves to list (which extends Spannable).
100
+ # Handle it directly since it's not in the module system.
101
+ if isinstance(actual, PendingListType):
102
+ if actual_elem == expected_elem:
103
+ return True
104
+ # IntLiteral elements coerce to any fixed-width int or BigInt
105
+ if isinstance(actual_elem, IntLiteralType) and is_integer_type(expected_elem):
106
+ return True
107
+ return False
108
+
109
+ # Check if actual is a builtin type that implements Spannable[T].
110
+ # These are compiler-internal types with known span coercion support.
111
+ if not (is_array(actual) or is_list(actual)):
112
+ return False
113
+ if actual_elem == expected_elem:
114
+ return True
115
+ if isinstance(actual_elem, IntLiteralType) and is_integer_type(expected_elem):
116
+ return True
117
+ return False
118
+
119
+
120
+ # Convenience matchers for the Ptr-shape rules (kept readable as helpers).
121
+ def _is_user_record(t: TpyType) -> bool:
122
+ return isinstance(t, NominalType) and t.is_user_record
123
+
124
+
125
+ def _is_mutable_ptr(t: TpyType) -> bool:
126
+ return isinstance(t, PtrType) and not is_readonly_ptr(t)
127
+
128
+
129
+ def _is_readonly_ptr_match(t: TpyType) -> bool:
130
+ return isinstance(t, PtrType) and is_readonly_ptr(t)
131
+
132
+
133
+ @dataclass(frozen=True)
134
+ class Coercion:
135
+ """A type coercion rule.
136
+
137
+ `from_type` / `to_type` are predicates on a single type (coarse pre-filter).
138
+ `type_match` is an optional finer two-sided predicate.
139
+ """
140
+ name: str
141
+ from_type: TypeMatcher
142
+ to_type: TypeMatcher
143
+ type_match: Callable[[TpyType, TpyType], bool] = _match_any
144
+ contexts: Optional[set[CoercionContext]] = None
145
+ requires_lvalue: bool = False
146
+ requires_mutable_lvalue: bool = False
147
+ forbid_return_local: bool = False
148
+ # Lossless coercion safe for protocol return type matching.
149
+ protocol_safe: bool = False
150
+ # Lossless widening (actual->expected) at a container element position:
151
+ # iterating actual yields values that widen implicitly into expected.
152
+ # "Lossless" follows Python/CPython's informal notion: large fixed-ints
153
+ # to Float32 and BigInt to float/Float32 lose mantissa precision but are
154
+ # still considered widenings at this position (same as implicit int->float
155
+ # promotion in Python arithmetic).
156
+ widening_safe: bool = False
157
+ check_range: Optional[Callable[[TpyType, TpyType], bool]] = None
158
+ # Address-taking coercions (`&{expr}`) produce a Ptr that is unconditionally
159
+ # non-null. Consumers can elide the deref null-check, same as for `take_ptr`.
160
+ produces_non_null_ptr: bool = False
161
+ codegen: Callable[[str, TpyType, TpyType, CoercionContext], str] = lambda expr, _a, _e, _c: expr
162
+
163
+
164
+ # NOTE: Order matters; higher priority first for overlapping rules.
165
+ COERCIONS: list[Coercion] = [
166
+ # INT type parameter coercions (compile-time constants)
167
+ Coercion(
168
+ name="int_type_param_to_fixed_int",
169
+ from_type=_is(TypeParamRef),
170
+ to_type=is_fixed_int_type,
171
+ type_match=_int_type_param_match,
172
+ codegen=lambda e, _a, b, _c: f"static_cast<{b.to_cpp()}>({e})",
173
+ ),
174
+ Coercion(
175
+ name="int_type_param_to_bigint",
176
+ from_type=_is(TypeParamRef),
177
+ to_type=is_big_int_type,
178
+ type_match=_int_type_param_match,
179
+ codegen=lambda e, _a, _b, _c: f"::tpy::BigInt(static_cast<int64_t>({e}))",
180
+ ),
181
+
182
+ # Integer literal to any fixed-width integer (range-checked)
183
+ Coercion(
184
+ name="int_literal_to_fixed_int",
185
+ from_type=_is(IntLiteralType),
186
+ to_type=is_fixed_int_type,
187
+ check_range=_int_literal_fits_fixed_int,
188
+ ),
189
+
190
+ # Integer literal to BigInt (always valid)
191
+ Coercion(
192
+ name="int_literal_to_bigint",
193
+ from_type=_is(IntLiteralType),
194
+ to_type=is_big_int_type,
195
+ ),
196
+
197
+ # Widening between fixed-width integers (e.g. Int8 -> Int32, UInt8 -> Int16)
198
+ Coercion(
199
+ name="fixed_int_widening",
200
+ from_type=is_fixed_int_type,
201
+ to_type=is_fixed_int_type,
202
+ type_match=_is_safe_widening,
203
+ widening_safe=True,
204
+ codegen=lambda e, _a, b, _c: f"static_cast<{b.to_cpp()}>({e})",
205
+ ),
206
+
207
+ # Fixed-width integer to BigInt
208
+ Coercion(
209
+ name="fixed_int_to_bigint",
210
+ from_type=is_fixed_int_type,
211
+ to_type=is_big_int_type,
212
+ widening_safe=True,
213
+ codegen=lambda e, _a, _b, _c: f"::tpy::BigInt({e})",
214
+ ),
215
+ # BigInt to fixed-width integer (narrowing, runtime checked)
216
+ Coercion(
217
+ name="bigint_to_fixed_int",
218
+ from_type=is_big_int_type,
219
+ to_type=is_fixed_int_type,
220
+ codegen=lambda e, _a, b, _c: f"({e}).to_fixed_check<{b.to_cpp()}>()",
221
+ ),
222
+
223
+ # Float coercions
224
+ Coercion(
225
+ name="int_literal_to_float",
226
+ from_type=_is(IntLiteralType),
227
+ to_type=is_float64_type,
228
+ codegen=lambda e, _a, _b, _c: f"static_cast<double>({e})",
229
+ ),
230
+ Coercion(
231
+ name="fixed_int_to_float",
232
+ from_type=is_fixed_int_type,
233
+ to_type=is_float64_type,
234
+ widening_safe=True,
235
+ codegen=lambda e, _a, _b, _c: f"static_cast<double>({e})",
236
+ ),
237
+ Coercion(
238
+ name="bigint_to_float",
239
+ from_type=is_big_int_type,
240
+ to_type=is_float64_type,
241
+ widening_safe=True,
242
+ codegen=lambda e, _a, _b, _c: f"static_cast<double>({e})",
243
+ ),
244
+
245
+ # Float literal coercions (adapts to context)
246
+ Coercion(
247
+ name="float_literal_to_float",
248
+ from_type=_is(FloatLiteralType),
249
+ to_type=is_float64_type,
250
+ codegen=lambda e, _a, _b, _c: e,
251
+ ),
252
+ Coercion(
253
+ name="float_literal_to_float32",
254
+ from_type=_is(FloatLiteralType),
255
+ to_type=is_float32_type,
256
+ codegen=lambda e, _a, _b, _c: e, # identity: gen_expr provides 'f' suffix
257
+ ),
258
+
259
+ # Float32 coercions (widening to Float32)
260
+ Coercion(
261
+ name="int_literal_to_float32",
262
+ from_type=_is(IntLiteralType),
263
+ to_type=is_float32_type,
264
+ codegen=lambda e, _a, _b, _c: f"static_cast<float>({e})",
265
+ ),
266
+ Coercion(
267
+ name="fixed_int_to_float32",
268
+ from_type=is_fixed_int_type,
269
+ to_type=is_float32_type,
270
+ widening_safe=True,
271
+ codegen=lambda e, _a, _b, _c: f"static_cast<float>({e})",
272
+ ),
273
+ Coercion(
274
+ name="bigint_to_float32",
275
+ from_type=is_big_int_type,
276
+ to_type=is_float32_type,
277
+ widening_safe=True,
278
+ codegen=lambda e, _a, _b, _c: f"static_cast<float>({e})",
279
+ ),
280
+ # Float32 -> float (widening, lossless)
281
+ Coercion(
282
+ name="float32_to_float",
283
+ from_type=is_float32_type,
284
+ to_type=is_float64_type,
285
+ widening_safe=True,
286
+ codegen=lambda e, _a, _b, _c: f"static_cast<double>({e})",
287
+ ),
288
+ # float -> Float32 (narrowing, but allowed for convenience -- matches C++ behavior)
289
+ Coercion(
290
+ name="float_to_float32",
291
+ from_type=is_float64_type,
292
+ to_type=is_float32_type,
293
+ codegen=lambda e, _a, _b, _c: f"static_cast<float>({e})",
294
+ ),
295
+
296
+ # Char to str coercion
297
+ Coercion(
298
+ name="char_to_str",
299
+ from_type=is_char_type,
300
+ to_type=is_str_type,
301
+ codegen=lambda e, _a, _b, _c: f"std::string(::tpy::char_to_str({e}))",
302
+ ),
303
+ # Char to String coercion
304
+ Coercion(
305
+ name="char_to_string",
306
+ from_type=is_char_type,
307
+ to_type=is_string_type,
308
+ codegen=lambda e, _a, _b, _c: f"std::string(1, {e})",
309
+ ),
310
+ # Char to StrView coercion
311
+ Coercion(
312
+ name="char_to_strview",
313
+ from_type=is_char_type,
314
+ to_type=is_str_view_type,
315
+ codegen=lambda e, _a, _b, _c: f"::tpy::char_to_str({e})",
316
+ ),
317
+
318
+ # String <-> str (both lower to std::string in non-ARG contexts, but `str`
319
+ # params lower to std::string_view at ARG). string -> str is always safe
320
+ # (std::string implicitly converts to std::string_view). str -> String
321
+ # materializes at ARG (where str is string_view and String is const
322
+ # std::string& / std::string) and is identity elsewhere (both std::string).
323
+ # The ARG wrap skips plain string literals -- `"foo"` is const char* which
324
+ # binds to const std::string& directly, so `std::string("foo")` is only a
325
+ # cosmetic change. Non-literal sources (names, calls, slices) need the wrap.
326
+ Coercion(
327
+ name="string_to_str",
328
+ from_type=is_string_type,
329
+ to_type=is_str_type,
330
+ protocol_safe=True,
331
+ ),
332
+ Coercion(
333
+ name="str_to_string",
334
+ from_type=is_str_type,
335
+ to_type=is_string_type,
336
+ codegen=lambda e, _a, _b, c: (
337
+ e if c != CoercionContext.ARG or (e.startswith('"') and e.endswith('"'))
338
+ else f"std::string({e})"
339
+ ),
340
+ ),
341
+
342
+ # String -> StrView (safe implicit, C++ handles std::string -> string_view)
343
+ Coercion(
344
+ name="string_to_strview",
345
+ from_type=is_string_type,
346
+ to_type=is_str_view_type,
347
+ ),
348
+ # str -> StrView (safe implicit, C++ handles std::string -> string_view)
349
+ Coercion(
350
+ name="str_to_strview",
351
+ from_type=is_str_type,
352
+ to_type=is_str_view_type,
353
+ ),
354
+
355
+ # StrView -> String (allocates)
356
+ Coercion(
357
+ name="strview_to_string",
358
+ from_type=is_str_view_type,
359
+ to_type=is_string_type,
360
+ codegen=lambda e, _a, _b, _c: f"std::string({e})",
361
+ protocol_safe=True,
362
+ ),
363
+ # StrView -> str. At ARG position plain `str` params lower to
364
+ # std::string_view, so the transfer is identity; but `Own[str]` params
365
+ # (e.g. list[str].append's value) lower to std::string by value, and
366
+ # INIT/ASSIGN/RETURN targets are also owned std::string -- both need
367
+ # materialization.
368
+ Coercion(
369
+ name="strview_to_str",
370
+ from_type=is_str_view_type,
371
+ to_type=is_str_type,
372
+ codegen=lambda e, _a, b, c: (
373
+ e if c == CoercionContext.ARG and not isinstance(b, OwnType)
374
+ else f"std::string({e})"
375
+ ),
376
+ protocol_safe=True,
377
+ ),
378
+ # Optional[StrView] <-> Optional[str]: plain `Optional[str]` params at ARG
379
+ # lower to `std::optional<std::string_view>`, so the transfer is identity;
380
+ # but `Own[Optional[str]]` params (e.g. list[Optional[str]].append) and
381
+ # non-ARG contexts (INIT/ASSIGN/RETURN) target `std::optional<std::string>`
382
+ # and need per-element materialization. Statement-expression pattern hoists
383
+ # the source into a local so the conditional evaluates the expression
384
+ # exactly once.
385
+ Coercion(
386
+ name="optional_strview_to_str",
387
+ from_type=lambda t: isinstance(t, OptionalType) and is_str_view_type(t.inner),
388
+ to_type=lambda t: isinstance(t, OptionalType) and is_str_type(t.inner),
389
+ codegen=lambda e, _a, b, c: (
390
+ e if c == CoercionContext.ARG and not isinstance(b, OwnType)
391
+ else (f"({{ auto __ov = ({e}); "
392
+ f"__ov ? std::make_optional(std::string(*__ov)) : std::nullopt; }})")
393
+ ),
394
+ ),
395
+ Coercion(
396
+ name="optional_str_to_strview",
397
+ from_type=lambda t: isinstance(t, OptionalType) and is_str_type(t.inner),
398
+ to_type=lambda t: isinstance(t, OptionalType) and is_str_view_type(t.inner),
399
+ codegen=lambda e, _a, b, c: (
400
+ e if c == CoercionContext.ARG and not isinstance(b, OwnType)
401
+ else (f"({{ auto __ov = ({e}); "
402
+ f"__ov ? std::make_optional(std::string_view(*__ov)) : std::nullopt; }})")
403
+ ),
404
+ ),
405
+
406
+ # bytearray <-> bytes identity coercions (both map to std::vector<uint8_t>)
407
+ Coercion(
408
+ name="bytearray_to_bytes",
409
+ from_type=is_bytearray_type,
410
+ to_type=is_bytes_type,
411
+ protocol_safe=True,
412
+ ),
413
+ Coercion(
414
+ name="bytes_to_bytearray",
415
+ from_type=is_bytes_type,
416
+ to_type=is_bytearray_type,
417
+ ),
418
+
419
+ # bytes/bytearray -> BytesView (safe implicit, vector -> span)
420
+ Coercion(
421
+ name="bytes_to_bytesview",
422
+ from_type=is_bytes_type,
423
+ to_type=is_bytes_view_type,
424
+ ),
425
+ Coercion(
426
+ name="bytearray_to_bytesview",
427
+ from_type=is_bytearray_type,
428
+ to_type=is_bytes_view_type,
429
+ ),
430
+
431
+ # BytesView -> bytes/bytearray (allocates)
432
+ Coercion(
433
+ name="bytesview_to_bytes",
434
+ from_type=is_bytes_view_type,
435
+ to_type=is_bytes_type,
436
+ codegen=lambda e, _a, _b, _c: f"std::vector<uint8_t>({e}.begin(), {e}.end())",
437
+ protocol_safe=True,
438
+ ),
439
+ Coercion(
440
+ name="bytesview_to_bytearray",
441
+ from_type=is_bytes_view_type,
442
+ to_type=is_bytearray_type,
443
+ codegen=lambda e, _a, _b, _c: f"std::vector<uint8_t>({e}.begin(), {e}.end())",
444
+ protocol_safe=True,
445
+ ),
446
+
447
+ # Pointer coercions
448
+ Coercion(
449
+ name="record_to_ptr",
450
+ from_type=_is_user_record,
451
+ to_type=_is_mutable_ptr,
452
+ type_match=lambda rec, ptr: (
453
+ isinstance(ptr.pointee, NominalType) and ptr.pointee.is_user_record
454
+ and rec.name == ptr.pointee.name
455
+ ),
456
+ requires_lvalue=True,
457
+ requires_mutable_lvalue=True,
458
+ forbid_return_local=True,
459
+ produces_non_null_ptr=True,
460
+ codegen=lambda e, _a, _b, _c: f"&{e}",
461
+ ),
462
+ Coercion(
463
+ name="record_to_const_ptr",
464
+ from_type=_is_user_record,
465
+ to_type=_is_readonly_ptr_match,
466
+ type_match=lambda rec, ptr: (
467
+ isinstance(ptr.inner_pointee, NominalType) and ptr.inner_pointee.is_user_record
468
+ and rec.name == ptr.inner_pointee.name
469
+ ),
470
+ requires_lvalue=True,
471
+ forbid_return_local=True,
472
+ produces_non_null_ptr=True,
473
+ codegen=lambda e, _a, _b, _c: f"&{e}",
474
+ ),
475
+ Coercion(
476
+ name="ptr_to_const_ptr",
477
+ from_type=_is_mutable_ptr,
478
+ to_type=_is_readonly_ptr_match,
479
+ type_match=lambda p1, p2: p1.inner_pointee == p2.inner_pointee,
480
+ ),
481
+ Coercion(
482
+ name="span_to_readonly_span",
483
+ from_type=_is(NominalType),
484
+ to_type=_is(NominalType),
485
+ type_match=lambda s1, s2: (
486
+ is_span(s1) and is_span(s2)
487
+ and not is_readonly_span(s1) and is_readonly_span(s2)
488
+ and unwrap_readonly(s1.type_args[0]) == unwrap_readonly(s2.type_args[0])
489
+ ),
490
+ protocol_safe=True,
491
+ ),
492
+ # basic_slice -> slice (adds step=nullopt). C++ implicit via Slice(BasicSlice) ctor.
493
+ Coercion(
494
+ name="basic_slice_to_slice",
495
+ from_type=is_basic_slice_type,
496
+ to_type=is_slice_type,
497
+ ),
498
+ # Span coercions: any Spannable[T] type can coerce to Span[T]
499
+ # Arg context allows temporaries
500
+ Coercion(
501
+ name="spanlike_to_span_arg",
502
+ from_type=_match_any_side, # Matches any type; _spanlike_to_span_match filters by protocol
503
+ to_type=_is(NominalType),
504
+ type_match=_spanlike_to_span_match,
505
+ contexts={CoercionContext.ARG},
506
+ ),
507
+ # Non-arg contexts require lvalue (can't take span of temporary)
508
+ Coercion(
509
+ name="spanlike_to_span",
510
+ from_type=_match_any_side, # Matches any type; _spanlike_to_span_match filters by protocol
511
+ to_type=_is(NominalType),
512
+ type_match=_spanlike_to_span_match,
513
+ contexts={CoercionContext.INIT, CoercionContext.ASSIGN, CoercionContext.RETURN},
514
+ requires_lvalue=True,
515
+ forbid_return_local=True,
516
+ ),
517
+ ]
518
+
519
+
520
+ def resolve_coercion(actual: TpyType, expected: TpyType, ctx: CoercionContext) -> Optional[Coercion]:
521
+ """Find a coercion rule that converts actual to expected in the given context."""
522
+ # PERF TODO: linear scan over ~39 rules, each evaluating two Python-level
523
+ # predicates (from_type / to_type) plus an optional type_match. When primitive
524
+ # subclasses were collapsed to NominalType singletons, from_type / to_type
525
+ # changed from C-level isinstance checks to Python calls that do a
526
+ # type_def_of dict lookup. Most rules are indexable by (from_qname, to_qname) --
527
+ # a hash-table dispatch with a fallback linear scan for wildcard-side rules
528
+ # (spanlike_to_span_arg, DEREF_COERCION) would cut per-call cost >10x.
529
+ # Not worth doing until a profile shows dispatch in the top costs.
530
+ for coercion in COERCIONS:
531
+ if coercion.contexts is not None and ctx not in coercion.contexts:
532
+ continue
533
+ if coercion.from_type(actual) and coercion.to_type(expected):
534
+ if coercion.type_match(actual, expected):
535
+ return coercion
536
+ return None
537
+
538
+
539
+ def is_protocol_safe_coercion(actual: TpyType, expected: TpyType) -> bool:
540
+ """Check if actual can coerce to expected in a protocol return type context.
541
+
542
+ Only lossless coercions marked protocol_safe=True are considered.
543
+ """
544
+ for coercion in COERCIONS:
545
+ if not coercion.protocol_safe:
546
+ continue
547
+ if coercion.from_type(actual) and coercion.to_type(expected):
548
+ if coercion.type_match(actual, expected):
549
+ return True
550
+ return False
551
+
552
+
553
+ def is_protocol_type_arg_widening(
554
+ actual: TpyType, expected: TpyType, default_int_type: TpyType,
555
+ ) -> bool:
556
+ """Check if actual->expected is a lossless widening at a protocol type-arg position.
557
+
558
+ Used for container conformance (e.g. list[A] satisfies Iterable[B]) where
559
+ the caller iterates actual and each element implicitly widens into expected.
560
+ Narrowing is rejected (list[Int32] must NOT satisfy Iterable[UInt8]).
561
+
562
+ At this position `actual` is an element type of a container, never a scalar.
563
+ IntLiteralType's concrete value is therefore meaningless (it describes the
564
+ first element only, not the whole sequence), so we treat it as the compiler's
565
+ default int type and fall through to the standard int->int widening rules.
566
+ """
567
+ # readonly is a container-level qualifier at element positions.
568
+ actual = unwrap_readonly(actual)
569
+ expected = unwrap_readonly(expected)
570
+ if isinstance(actual, IntLiteralType):
571
+ actual = default_int_type
572
+ elif isinstance(actual, FloatLiteralType):
573
+ # No default_float concept: any float target is a lossless widening
574
+ # of an abstract float literal.
575
+ return is_float64_type(expected) or is_float32_type(expected)
576
+ if actual == expected:
577
+ return True
578
+ for c in COERCIONS:
579
+ if (c.widening_safe and c.from_type(actual) and c.to_type(expected)
580
+ and c.type_match(actual, expected)):
581
+ return True
582
+ return False
583
+
584
+
585
+ def _deref_codegen(e: str, actual: TpyType, _expected: TpyType, _ctx: CoercionContext) -> str:
586
+ if isinstance(actual, PtrType):
587
+ return f"::tpy::deref_check({e})"
588
+ return f"{e}.__deref__()"
589
+
590
+
591
+ DEREF_COERCION = Coercion(
592
+ name="deref_to_target",
593
+ from_type=_match_any_side,
594
+ to_type=_match_any_side,
595
+ codegen=_deref_codegen,
596
+ )
597
+
598
+ # @value_ptr_coercion: T -> Ptr[T] coercion for any type (not in COERCIONS list).
599
+ # Applied explicitly by calls.py for functions with @value_ptr_coercion.
600
+ VALUE_TO_PTR = Coercion(
601
+ name="value_to_ptr",
602
+ from_type=_match_any_side,
603
+ to_type=_is(PtrType),
604
+ requires_lvalue=True,
605
+ requires_mutable_lvalue=True,
606
+ forbid_return_local=True,
607
+ produces_non_null_ptr=True,
608
+ codegen=lambda e, _a, _b, _c: f"&{e}",
609
+ )
610
+
611
+ # Pre-built coercions for inheritance-based upcasts (not in COERCIONS list --
612
+ # requires TypeRegistry access that type_match lambdas don't have).
613
+ # Used directly by compatibility.py.
614
+ UPCAST_TO_PTR = Coercion(
615
+ name="upcast_to_ptr",
616
+ from_type=_is(NominalType),
617
+ to_type=_is(PtrType),
618
+ requires_lvalue=True,
619
+ requires_mutable_lvalue=True,
620
+ forbid_return_local=True,
621
+ produces_non_null_ptr=True,
622
+ codegen=lambda e, _a, _b, _c: f"&{e}",
623
+ )
624
+
625
+ # Pre-built coercions for __span__() and Spannable[T] protocol coercion to ReadOnlySpan.
626
+ # Used directly by compatibility.py (not in COERCIONS list); from_type is not consulted.
627
+ # Codegen is handled in expressions.py _gen_span_coercion.
628
+ # Arg context: temporaries allowed.
629
+ SPAN_METHOD_TO_SPAN_ARG = Coercion(
630
+ name="span_method_to_span_arg",
631
+ from_type=_match_any_side,
632
+ to_type=_is(NominalType),
633
+ )
634
+
635
+ # Non-arg contexts: lvalue required, no returning locals.
636
+ SPAN_METHOD_TO_SPAN = Coercion(
637
+ name="span_method_to_span",
638
+ from_type=_match_any_side,
639
+ to_type=_is(NominalType),
640
+ requires_lvalue=True,
641
+ forbid_return_local=True,
642
+ )
643
+
644
+ UPCAST_TO_CONST_PTR = Coercion(
645
+ name="upcast_to_const_ptr",
646
+ from_type=_is(NominalType),
647
+ to_type=_is(PtrType),
648
+ requires_lvalue=True,
649
+ forbid_return_local=True,
650
+ produces_non_null_ptr=True,
651
+ codegen=lambda e, _a, _b, _c: f"&{e}",
652
+ )
653
+
654
+
655
+ # T -> Any: type-erased storage. View types are converted to their owning
656
+ # equivalent at the storage site so the Any cell owns its contents (the
657
+ # typeid stored in std::any is the owning type, not the view type). All
658
+ # other copyable types are stored as-is. Sema (compatibility.py) gates
659
+ # move-only sources before this coercion is reached.
660
+ def _any_storage_form(
661
+ e: str, actual: TpyType, c: CoercionContext,
662
+ ) -> str:
663
+ """Return the C++ expression to pass to `::tpy::make_any(...)` for
664
+ storing `e` (statically typed `actual`) inside a tpy::Any.
665
+
666
+ The expression must produce a value whose decayed C++ type is the
667
+ intended storage typeid -- argument deduction in `make_any<T>(value)`
668
+ picks T from this expression. Three flavours of conversion happen
669
+ here:
670
+
671
+ - Literal-typed sources (IntLiteralType / FloatLiteralType /
672
+ LiteralType) resolve to their canonical storage type so the typeid
673
+ is stable regardless of which literal value triggered the coercion
674
+ (`x: Any = 42` and `[42]: list[Any]` both store BigInt).
675
+
676
+ - str-like sources are always wrapped in `std::string{...}` because
677
+ string-literal expressions lower to `const char*`. Without this,
678
+ argument deduction would pick `const char*` and the cell's typeid
679
+ would mismatch the canonical `std::string`. The redundant
680
+ std::string copy when the source is already a std::string variable
681
+ is accepted; correctness over micro-efficiency.
682
+
683
+ - Bytes-like view/span sources are converted to the owning
684
+ `std::vector<uint8_t>`; bytes/bytearray at value positions are
685
+ already vectors and pass through.
686
+
687
+ - Container literals reach codegen as raw brace-init expressions
688
+ (`{1, 2, 3}`); make_any's argument deduction can't pick a type
689
+ from a braced-init, so we prefix with the explicit C++ container
690
+ type. For non-literal sources the same prefix is just a copy ctor.
691
+ """
692
+ if isinstance(actual, IntLiteralType):
693
+ # TPy's `int` annotation is BigInt; storing IntLiteral sources as
694
+ # BigInt makes `cast(int, x)` work for the natural pattern
695
+ # `x: Any = 42; cast(int, x)`.
696
+ return f"::tpy::BigInt({e})"
697
+ if isinstance(actual, FloatLiteralType):
698
+ return f"static_cast<double>({e})"
699
+ if isinstance(actual, LiteralType):
700
+ return _any_storage_form(e, actual.base_type, c)
701
+ if is_str_view_type(actual) or is_str_type(actual) or is_string_type(actual):
702
+ return f"std::string({e})"
703
+ if is_bytes_view_type(actual):
704
+ return f"std::vector<uint8_t>({e}.begin(), {e}.end())"
705
+ if is_bytes_type(actual) or is_bytearray_type(actual):
706
+ if c == CoercionContext.ARG:
707
+ return f"std::vector<uint8_t>({e}.begin(), {e}.end())"
708
+ return e
709
+ if is_list(actual) or is_dict(actual) or is_set(actual):
710
+ cpp = actual.to_cpp()
711
+ return f"{cpp}{e}" if e.startswith("{") else f"{cpp}({e})"
712
+ return e
713
+
714
+
715
+ def wrap_into_any(
716
+ e: str, actual: TpyType,
717
+ ctx: CoercionContext = CoercionContext.INIT,
718
+ ) -> str:
719
+ """Build the C++ expression that wraps `e` (typed `actual`) as a tpy::Any.
720
+ Shared by the INTO_ANY coercion and by container-element codegen sites
721
+ where the element slot type is Any (list[Any], dict[K, Any], ...).
722
+ """
723
+ return f"::tpy::make_any({_any_storage_form(e, actual, ctx)})"
724
+
725
+
726
+ def _into_any_codegen(
727
+ e: str, actual: TpyType, _expected: TpyType, c: CoercionContext,
728
+ ) -> str:
729
+ return wrap_into_any(e, actual, c)
730
+
731
+
732
+ INTO_ANY = Coercion(
733
+ name="into_any",
734
+ from_type=_match_any_side,
735
+ to_type=_is(AnyType),
736
+ codegen=_into_any_codegen,
737
+ )
738
+
739
+
740
+ # Any -> T auto-coerce: runtime checked extraction. Target T must be a
741
+ # concrete type (sema gates Union / Optional / generic-type-param targets
742
+ # before reaching this codegen). When the typeid mismatches at runtime,
743
+ # any_cast_or_panic delivers the documented panic message.
744
+ FROM_ANY = Coercion(
745
+ name="from_any",
746
+ from_type=_is(AnyType),
747
+ to_type=_match_any_side,
748
+ codegen=lambda e, _a, b, _c: f"::tpy::any_cast_or_panic<{b.to_cpp()}>({e})",
749
+ )