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/test_ref_type.py ADDED
@@ -0,0 +1,216 @@
1
+ """Tests for RefType and make_ref."""
2
+
3
+ from .typesys import (
4
+ RefType, make_ref, unwrap_ref_type, is_ref_type,
5
+ OwnType, ReadonlyType, OptionalType, UnionType,
6
+ VoidType, NoneType, TypeParamRef, TypeParamKind,
7
+ INT32, STR, BOOL, VOID, FLOAT,
8
+ NominalType, make_list,
9
+ )
10
+
11
+
12
+ class TestRefTypeConstruction:
13
+ def test_basic(self):
14
+ point = NominalType("Point")
15
+ ref = RefType(point)
16
+ assert ref.wrapped is point
17
+ assert str(ref) == "Ref[Point]"
18
+
19
+ def test_is_value_type(self):
20
+ ref = RefType(NominalType("Point"))
21
+ assert not ref.is_value_type()
22
+
23
+ def test_is_ref_param(self):
24
+ ref = RefType(NominalType("Point"))
25
+ assert ref.is_ref_param()
26
+
27
+ def test_inner_types(self):
28
+ point = NominalType("Point")
29
+ ref = RefType(point)
30
+ assert ref.inner_types() == (point,)
31
+
32
+ def test_with_inner_types(self):
33
+ point = NominalType("Point")
34
+ dog = NominalType("Dog")
35
+ ref = RefType(point)
36
+ ref2 = ref.with_inner_types((dog,))
37
+ assert isinstance(ref2, RefType)
38
+ assert ref2.wrapped is dog
39
+
40
+ def test_equality(self):
41
+ a = RefType(NominalType("Point"))
42
+ b = RefType(NominalType("Point"))
43
+ assert a == b
44
+
45
+ def test_inequality(self):
46
+ a = RefType(NominalType("Point"))
47
+ b = RefType(NominalType("Dog"))
48
+ assert a != b
49
+
50
+
51
+ class TestRefTypeToCpp:
52
+ """Verify RefType produces the same C++ as the current non-value type methods."""
53
+
54
+ def test_to_cpp_concrete(self):
55
+ ref = RefType(NominalType("Point"))
56
+ assert ref.to_cpp() == "Point&"
57
+
58
+ def test_to_cpp_return(self):
59
+ ref = RefType(NominalType("Point"))
60
+ assert ref.to_cpp_return() == "Point&"
61
+
62
+ def test_to_cpp_return_const(self):
63
+ ref = RefType(NominalType("Point"))
64
+ assert ref.to_cpp_return_const() == "const Point&"
65
+
66
+ def test_to_cpp_param_type(self):
67
+ ref = RefType(NominalType("Point"))
68
+ assert ref.to_cpp_param_type() == "Point&"
69
+
70
+ def test_to_cpp_param(self):
71
+ ref = RefType(NominalType("Point"))
72
+ assert ref.to_cpp_param("x") == "Point& x"
73
+
74
+ def test_to_cpp_const_param(self):
75
+ ref = RefType(NominalType("Point"))
76
+ assert ref.to_cpp_const_param("x") == "const Point& x"
77
+
78
+ def test_to_cpp_stored(self):
79
+ ref = RefType(NominalType("Point"))
80
+ assert ref.to_cpp_stored() == "::tpy::val_or_ref<Point>"
81
+
82
+ def test_to_cpp_stored_list(self):
83
+ ref = RefType(make_list(INT32))
84
+ assert ref.to_cpp_stored() == "::tpy::val_or_ref<std::vector<int32_t>>"
85
+
86
+
87
+ class TestRefTypeParamRef:
88
+ """Verify RefType with TypeParamRef uses C++ trait aliases."""
89
+
90
+ def test_to_cpp(self):
91
+ ref = RefType(TypeParamRef("T"))
92
+ assert ref.to_cpp() == "::tpy::val_or_ref_t<T>"
93
+
94
+ def test_to_cpp_return(self):
95
+ ref = RefType(TypeParamRef("T"))
96
+ assert ref.to_cpp_return() == "::tpy::val_or_ref_t<T>"
97
+
98
+ def test_to_cpp_return_const(self):
99
+ ref = RefType(TypeParamRef("T"))
100
+ assert ref.to_cpp_return_const() == "::tpy::val_or_cref_t<T>"
101
+
102
+ def test_to_cpp_param_type(self):
103
+ ref = RefType(TypeParamRef("T"))
104
+ assert ref.to_cpp_param_type() == "::tpy::param_val_or_ref_t<T>"
105
+
106
+ def test_to_cpp_stored(self):
107
+ ref = RefType(TypeParamRef("T"))
108
+ assert ref.to_cpp_stored() == "::tpy::val_or_ref<T>"
109
+
110
+
111
+ class TestMakeRef:
112
+ """Test the smart constructor that decides when to wrap."""
113
+
114
+ def test_non_value_type_wrapped(self):
115
+ point = NominalType("Point")
116
+ result = make_ref(point)
117
+ assert isinstance(result, RefType)
118
+ assert result.wrapped is point
119
+
120
+ def test_list_wrapped(self):
121
+ lst = make_list(INT32)
122
+ result = make_ref(lst)
123
+ assert isinstance(result, RefType)
124
+ assert result.wrapped is lst
125
+
126
+ def test_value_type_not_wrapped(self):
127
+ assert make_ref(INT32) is INT32
128
+ assert make_ref(STR) is STR
129
+ assert make_ref(BOOL) is BOOL
130
+ assert make_ref(FLOAT) is FLOAT
131
+
132
+ def test_own_not_wrapped(self):
133
+ own = OwnType(NominalType("Point"))
134
+ assert make_ref(own) is own
135
+
136
+ def test_readonly_not_wrapped(self):
137
+ ro = ReadonlyType(NominalType("Point"))
138
+ assert make_ref(ro) is ro
139
+
140
+ def test_optional_not_wrapped(self):
141
+ opt = OptionalType(NominalType("Point"))
142
+ assert make_ref(opt) is opt
143
+
144
+ def test_union_not_wrapped(self):
145
+ union = UnionType((NominalType("Dog"), NominalType("Cat")))
146
+ assert make_ref(union) is union
147
+
148
+ def test_void_not_wrapped(self):
149
+ assert make_ref(VOID) is VOID
150
+
151
+ def test_none_not_wrapped(self):
152
+ none = NoneType()
153
+ assert make_ref(none) is none
154
+
155
+ def test_ref_not_double_wrapped(self):
156
+ ref = RefType(NominalType("Point"))
157
+ assert make_ref(ref) is ref
158
+
159
+ def test_type_param_ref_wrapped(self):
160
+ tpr = TypeParamRef("T")
161
+ result = make_ref(tpr)
162
+ assert isinstance(result, RefType)
163
+ assert result.wrapped is tpr
164
+
165
+ def test_type_param_ref_int_kind_not_wrapped(self):
166
+ tpr = TypeParamRef("N", kind=TypeParamKind.INT)
167
+ assert make_ref(tpr) is tpr
168
+
169
+ def test_type_param_ref_value_bound_not_wrapped(self):
170
+ bound = NominalType("ValueType", is_protocol=True,
171
+ _module_qname="tpy.ValueType")
172
+ tpr = TypeParamRef("T", bound=bound)
173
+ # is_value_type() returns True when bounded to tpy.ValueType
174
+ assert tpr.is_value_type()
175
+ assert make_ref(tpr) is tpr
176
+
177
+
178
+ class TestUnwrapRefType:
179
+ def test_unwrap_ref(self):
180
+ point = NominalType("Point")
181
+ ref = RefType(point)
182
+ assert unwrap_ref_type(ref) is point
183
+
184
+ def test_unwrap_non_ref(self):
185
+ point = NominalType("Point")
186
+ assert unwrap_ref_type(point) is point
187
+
188
+ def test_unwrap_value_type(self):
189
+ assert unwrap_ref_type(INT32) is INT32
190
+
191
+
192
+ class TestIsRefType:
193
+ def test_ref(self):
194
+ assert is_ref_type(RefType(NominalType("Point")))
195
+
196
+ def test_non_ref(self):
197
+ assert not is_ref_type(NominalType("Point"))
198
+ assert not is_ref_type(INT32)
199
+ assert not is_ref_type(OwnType(NominalType("Point")))
200
+
201
+
202
+ class TestToCppStored:
203
+ """Test base class to_cpp_stored() default behavior."""
204
+
205
+ def test_value_type_stored_same_as_to_cpp(self):
206
+ assert INT32.to_cpp_stored() == INT32.to_cpp()
207
+ assert STR.to_cpp_stored() == STR.to_cpp()
208
+
209
+ def test_non_value_type_stored_same_as_to_cpp(self):
210
+ point = NominalType("Point")
211
+ assert point.to_cpp_stored() == point.to_cpp()
212
+
213
+ def test_ref_type_stored_uses_val_or_ref(self):
214
+ ref = RefType(NominalType("Point"))
215
+ assert ref.to_cpp_stored() == "::tpy::val_or_ref<Point>"
216
+ assert ref.to_cpp_stored() != ref.to_cpp()
@@ -0,0 +1,276 @@
1
+ """Unit tests for NominalType.is_send / is_sync substitution at use sites.
2
+
3
+ `RecordInfo.is_send` / `is_sync` are computed at registration with any
4
+ field whose type mentions a TypeParamRef treated as conservatively-OK.
5
+ The use site re-walks fields and parents under concrete `type_args`,
6
+ so the answer is correct in both directions: types wrapping a non-Send
7
+ concrete arg report False, and types wrapping a Send concrete arg
8
+ report True even when the registration-time bool was conservative.
9
+ """
10
+
11
+ import pytest
12
+
13
+ from .typesys import (
14
+ INT32, FieldInfo, NominalType, OptionalType, PtrType, RecordInfo,
15
+ TypeParamRef, make_list,
16
+ )
17
+ from .type_def_registry import (
18
+ TypeCategory, attach_dynamic_type_def, clear_dynamic_type_defs,
19
+ )
20
+
21
+
22
+ @pytest.fixture
23
+ def _box_recordinfo():
24
+ """Register Box[T] with `data: T` (a bare TypeParamRef field).
25
+
26
+ At registration, the disjunction in sema/registration.py accepts the
27
+ TypeParamRef-typed field as conservatively-OK, so `is_send` /
28
+ `is_sync` would be True. We set those flags manually here because
29
+ the unit test bypasses sema.
30
+ """
31
+ info = RecordInfo(
32
+ name="Box",
33
+ fields=[FieldInfo(name="data", type=TypeParamRef("T"))],
34
+ type_params=["T"],
35
+ is_send=True,
36
+ is_sync=True,
37
+ )
38
+ attach_dynamic_type_def("Box", TypeCategory.RECORD, record=info)
39
+ try:
40
+ yield info
41
+ finally:
42
+ clear_dynamic_type_defs()
43
+
44
+
45
+ @pytest.fixture
46
+ def _wrapper_with_send_int_field():
47
+ """Register Wrapper[T] with a `tag: Int32` field plus `data: T`.
48
+
49
+ Exercises that concrete-typed fields keep their definition-time
50
+ answer (Int32 is Send) while the TypeParamRef field is re-checked
51
+ under substitution.
52
+ """
53
+ info = RecordInfo(
54
+ name="Wrapper",
55
+ fields=[
56
+ FieldInfo(name="tag", type=INT32),
57
+ FieldInfo(name="data", type=TypeParamRef("T")),
58
+ ],
59
+ type_params=["T"],
60
+ is_send=True,
61
+ is_sync=True,
62
+ )
63
+ attach_dynamic_type_def("Wrapper", TypeCategory.RECORD, record=info)
64
+ try:
65
+ yield info
66
+ finally:
67
+ clear_dynamic_type_defs()
68
+
69
+
70
+ def _box(arg) -> NominalType:
71
+ return NominalType("Box", type_args=(arg,), _module_qname="Box")
72
+
73
+
74
+ def _wrapper(arg) -> NominalType:
75
+ return NominalType("Wrapper", type_args=(arg,), _module_qname="Wrapper")
76
+
77
+
78
+ def _buf() -> NominalType:
79
+ # Stand-in for a user record. No registration needed -- its is_send /
80
+ # is_sync defaults (value-type fallback returning False for an
81
+ # unregistered nominal) are fine; PtrType.is_send is unconditionally
82
+ # False which is the only fact this test relies on.
83
+ return NominalType("Buf", _module_qname="user.Buf")
84
+
85
+
86
+ class TestGenericRecordSendSync:
87
+ def test_box_of_int_is_send(self, _box_recordinfo) -> None:
88
+ """Int32 is Send -> Box[Int32] is Send (record bool stays True)."""
89
+ assert _box(INT32).is_send() is True
90
+ assert _box(INT32).is_sync() is True
91
+
92
+ def test_box_of_ptr_is_not_send(self, _box_recordinfo) -> None:
93
+ """Ptr[Buf] is not Send -> Box[Ptr[Buf]] is not Send despite the
94
+ registration-time bool being True."""
95
+ ptr_buf = PtrType(_buf())
96
+ assert ptr_buf.is_send() is False
97
+ assert _box(ptr_buf).is_send() is False
98
+
99
+ def test_box_of_ptr_is_not_sync(self, _box_recordinfo) -> None:
100
+ """Same shape for is_sync."""
101
+ ptr_buf = PtrType(_buf())
102
+ assert ptr_buf.is_sync() is False
103
+ assert _box(ptr_buf).is_sync() is False
104
+
105
+ def test_wrapper_concrete_field_preserved(
106
+ self, _wrapper_with_send_int_field,
107
+ ) -> None:
108
+ """Concrete-typed fields that were Send at registration stay Send;
109
+ only the TypeParamRef-typed field flips under substitution."""
110
+ assert _wrapper(INT32).is_send() is True
111
+ assert _wrapper(PtrType(_buf())).is_send() is False
112
+
113
+ def test_concrete_non_send_field_stays_false(self) -> None:
114
+ """A generic record whose concrete-typed field is non-Send fails
115
+ the walker regardless of the type_args. The cached bool from
116
+ registration is False, but the walker reproduces the same answer
117
+ by walking the concrete field and finding it non-Send."""
118
+ info = RecordInfo(
119
+ name="Holder",
120
+ fields=[FieldInfo(name="p", type=PtrType(_buf()))],
121
+ type_params=["T"],
122
+ is_send=False,
123
+ is_sync=False,
124
+ )
125
+ attach_dynamic_type_def("Holder", TypeCategory.RECORD, record=info)
126
+ try:
127
+ holder = NominalType("Holder", type_args=(INT32,),
128
+ _module_qname="Holder")
129
+ assert holder.is_send() is False
130
+ assert holder.is_sync() is False
131
+ finally:
132
+ clear_dynamic_type_defs()
133
+
134
+ def test_non_generic_record_unaffected(self) -> None:
135
+ """Non-generic records (no type_params) take the same path but
136
+ the substitution helper no-ops; the record-level bool wins."""
137
+ info = RecordInfo(
138
+ name="Plain",
139
+ fields=[FieldInfo(name="x", type=INT32)],
140
+ is_send=True,
141
+ is_sync=True,
142
+ )
143
+ attach_dynamic_type_def("Plain", TypeCategory.RECORD, record=info)
144
+ try:
145
+ plain = NominalType("Plain", _module_qname="Plain")
146
+ assert plain.is_send() is True
147
+ assert plain.is_sync() is True
148
+ finally:
149
+ clear_dynamic_type_defs()
150
+
151
+ def test_list_of_typeparam_flips_true(self) -> None:
152
+ """`class W[T]: c: list[T]` -- at registration `list[T].is_send()`
153
+ evaluates to False because the TypeDef callable propagates
154
+ `T.is_send() == False`. The use-site walker substitutes the
155
+ concrete `type_args`, so W[Int32] correctly reports True."""
156
+ info = RecordInfo(
157
+ name="W",
158
+ fields=[FieldInfo(
159
+ name="c", type=make_list(element_type=TypeParamRef("T")),
160
+ )],
161
+ type_params=["T"],
162
+ )
163
+ attach_dynamic_type_def("W", TypeCategory.RECORD, record=info)
164
+ try:
165
+ assert NominalType(
166
+ "W", type_args=(INT32,), _module_qname="W",
167
+ ).is_send() is True
168
+ assert NominalType(
169
+ "W", type_args=(PtrType(_buf()),), _module_qname="W",
170
+ ).is_send() is False
171
+ # Mirror for is_sync to exercise _evaluating_sync.
172
+ # `list[T].is_sync()` is always False (mutable container), so
173
+ # the answer for W[anything] is False regardless of the arg.
174
+ assert NominalType(
175
+ "W", type_args=(INT32,), _module_qname="W",
176
+ ).is_sync() is False
177
+ finally:
178
+ clear_dynamic_type_defs()
179
+
180
+ def test_self_recursive_generic(self) -> None:
181
+ """`class Tree[T]: value: T; children: list[Tree[T]]` is the
182
+ canonical self-recursive generic. The cycle guard returns True
183
+ (greatest fixed point) on re-entry, so the answer is decided by
184
+ the non-recursive value field: Tree[Int32] is Send (Int32 is
185
+ Send), Tree[Ptr[Buf]] is not."""
186
+ info = RecordInfo(
187
+ name="Tree",
188
+ fields=[
189
+ FieldInfo(name="value", type=TypeParamRef("T")),
190
+ FieldInfo(
191
+ name="children",
192
+ type=make_list(element_type=NominalType(
193
+ "Tree", type_args=(TypeParamRef("T"),),
194
+ _module_qname="Tree",
195
+ )),
196
+ ),
197
+ ],
198
+ type_params=["T"],
199
+ )
200
+ attach_dynamic_type_def("Tree", TypeCategory.RECORD, record=info)
201
+ try:
202
+ assert NominalType(
203
+ "Tree", type_args=(INT32,), _module_qname="Tree",
204
+ ).is_send() is True
205
+ assert NominalType(
206
+ "Tree", type_args=(PtrType(_buf()),), _module_qname="Tree",
207
+ ).is_send() is False
208
+ finally:
209
+ clear_dynamic_type_defs()
210
+
211
+ def test_self_recursive_generic_sync_via_optional(self) -> None:
212
+ """Counterpart to test_self_recursive_generic for is_sync.
213
+
214
+ `list[T]` short-circuits is_sync to False (mutable container), so
215
+ the prior test never re-enters the walker for is_sync and
216
+ `_evaluating_sync` never fires. Optional[T] passes is_sync
217
+ through to T, so a Tree whose recursive field is Optional[Tree[T]]
218
+ forces the walker to re-enter Tree[Int32].is_sync() recursively,
219
+ exercising the greatest-fixed-point branch."""
220
+ info = RecordInfo(
221
+ name="Tree",
222
+ fields=[
223
+ FieldInfo(name="value", type=TypeParamRef("T")),
224
+ FieldInfo(
225
+ name="child",
226
+ type=OptionalType(NominalType(
227
+ "Tree", type_args=(TypeParamRef("T"),),
228
+ _module_qname="Tree",
229
+ )),
230
+ ),
231
+ ],
232
+ type_params=["T"],
233
+ )
234
+ attach_dynamic_type_def("Tree", TypeCategory.RECORD, record=info)
235
+ try:
236
+ assert NominalType(
237
+ "Tree", type_args=(INT32,), _module_qname="Tree",
238
+ ).is_sync() is True
239
+ assert NominalType(
240
+ "Tree", type_args=(PtrType(_buf()),), _module_qname="Tree",
241
+ ).is_sync() is False
242
+ finally:
243
+ clear_dynamic_type_defs()
244
+
245
+ def test_generic_parent_substituted(self) -> None:
246
+ """A child record inheriting from a generic parent must also have
247
+ its parent re-walked under substitution -- otherwise Child[T]'s
248
+ registration True latches in even when Parent[T] would be False
249
+ at the use site."""
250
+ parent = RecordInfo(
251
+ name="Parent",
252
+ fields=[FieldInfo(name="val", type=TypeParamRef("U"))],
253
+ type_params=["U"],
254
+ is_send=True,
255
+ is_sync=True,
256
+ )
257
+ attach_dynamic_type_def("Parent", TypeCategory.RECORD, record=parent)
258
+ child = RecordInfo(
259
+ name="Child",
260
+ fields=[],
261
+ type_params=["T"],
262
+ parents=[NominalType("Parent", type_args=(TypeParamRef("T"),),
263
+ _module_qname="Parent")],
264
+ is_send=True,
265
+ is_sync=True,
266
+ )
267
+ attach_dynamic_type_def("Child", TypeCategory.RECORD, record=child)
268
+ try:
269
+ assert NominalType(
270
+ "Child", type_args=(INT32,), _module_qname="Child",
271
+ ).is_send() is True
272
+ assert NominalType(
273
+ "Child", type_args=(PtrType(_buf()),), _module_qname="Child",
274
+ ).is_send() is False
275
+ finally:
276
+ clear_dynamic_type_defs()
@@ -0,0 +1,206 @@
1
+ """Phase 0 RED tests: mutation propagation through tuple destructure
2
+ and through call edges where the param is a tuple/Optional.
3
+
4
+ These pin the prerequisite facts that the const-inference work depends on.
5
+ They were RED before the Phase 0 fixes (predicate at calls.py:2470 +
6
+ borrow-tracker edges in _analyze_tuple_unpack).
7
+
8
+ If any of these regresses, the const-inference downstream becomes unsound:
9
+ a body that mutates through a slot would be silently inferred read-only
10
+ and emitted with const slots.
11
+ """
12
+
13
+ from . import get_lib_dir
14
+ from .compiler import Compiler
15
+
16
+ _STDLIB_DIRS = [get_lib_dir() / "tpy"]
17
+
18
+
19
+ def _compile(source: str):
20
+ compiler = Compiler.from_source(source, lib_dirs=_STDLIB_DIRS)
21
+ modules = compiler.compile()
22
+ entry = [m for m in modules if m.is_entry_point][0]
23
+ return entry
24
+
25
+
26
+ def _get_func(module, name: str):
27
+ fi_list = module.exports.functions[name]
28
+ assert len(fi_list) == 1, f"expected single overload of {name}, got {len(fi_list)}"
29
+ return fi_list[0]
30
+
31
+
32
+ class TestTupleDestructureMutationPropagation:
33
+ """`a, b = p; a.x = ...` must mark `p` mutated."""
34
+
35
+ def test_tuple_of_record_destructure_field_write(self):
36
+ source = """
37
+ from tpy import Int32
38
+
39
+ class T:
40
+ x: Int32
41
+ def __init__(self, x: Int32) -> None:
42
+ self.x = x
43
+
44
+ def f(p: tuple[T, T]) -> None:
45
+ a, b = p
46
+ a.x = Int32(1)
47
+ """
48
+ module = _compile(source)
49
+ f = _get_func(module, "f")
50
+ assert f.mutated_params is not None
51
+ assert 0 in f.mutated_params, (
52
+ f"`p` should be marked mutated after destructure+field-write, "
53
+ f"got mutated_params={f.mutated_params}"
54
+ )
55
+
56
+ def test_tuple_of_optional_record_destructure_narrowing_field_write(self):
57
+ source = """
58
+ from tpy import Int32
59
+
60
+ class T:
61
+ x: Int32
62
+ def __init__(self, x: Int32) -> None:
63
+ self.x = x
64
+
65
+ def f(p: tuple[T | None, T | None]) -> None:
66
+ a, b = p
67
+ if a is not None:
68
+ a.x = Int32(1)
69
+ """
70
+ module = _compile(source)
71
+ f = _get_func(module, "f")
72
+ assert f.mutated_params is not None
73
+ assert 0 in f.mutated_params, (
74
+ f"`p` should be marked mutated after destructure+narrowing+field-write, "
75
+ f"got mutated_params={f.mutated_params}"
76
+ )
77
+
78
+ def test_tuple_of_record_destructure_no_write_not_mutated(self):
79
+ """Negative: pure read through destructure must not mark mutated."""
80
+ source = """
81
+ from tpy import Int32
82
+
83
+ class T:
84
+ x: Int32
85
+ def __init__(self, x: Int32) -> None:
86
+ self.x = x
87
+
88
+ def f(p: tuple[T, T]) -> Int32:
89
+ a, b = p
90
+ return a.x + b.x
91
+ """
92
+ module = _compile(source)
93
+ f = _get_func(module, "f")
94
+ assert f.mutated_params is not None
95
+ assert 0 not in f.mutated_params, (
96
+ f"`p` should NOT be marked mutated for pure read access, "
97
+ f"got mutated_params={f.mutated_params}"
98
+ )
99
+
100
+
101
+ class TestTupleTransitiveMutationPropagation:
102
+ """Phase-2 propagation: if inner mutates a tuple param, outer's matching
103
+ param must also be marked mutated when it forwards through inner."""
104
+
105
+ def test_transitive_through_tuple_param(self):
106
+ source = """
107
+ from tpy import Int32
108
+
109
+ class T:
110
+ x: Int32
111
+ def __init__(self, x: Int32) -> None:
112
+ self.x = x
113
+
114
+ def inner(p: tuple[T, T]) -> None:
115
+ a, b = p
116
+ a.x = Int32(1)
117
+
118
+ def outer(p: tuple[T, T]) -> None:
119
+ inner(p)
120
+ """
121
+ module = _compile(source)
122
+ inner = _get_func(module, "inner")
123
+ outer = _get_func(module, "outer")
124
+ assert inner.mutated_params is not None and 0 in inner.mutated_params
125
+ assert outer.mutated_params is not None and 0 in outer.mutated_params, (
126
+ f"outer's `p` should be transitively marked mutated, "
127
+ f"got mutated_params={outer.mutated_params}"
128
+ )
129
+
130
+ def test_transitive_through_optional_tuple_param(self):
131
+ source = """
132
+ from tpy import Int32
133
+
134
+ class T:
135
+ x: Int32
136
+ def __init__(self, x: Int32) -> None:
137
+ self.x = x
138
+
139
+ def inner(p: tuple[T | None, T | None]) -> None:
140
+ a, b = p
141
+ if a is not None:
142
+ a.x = Int32(1)
143
+
144
+ def outer(p: tuple[T | None, T | None]) -> None:
145
+ inner(p)
146
+ """
147
+ module = _compile(source)
148
+ inner = _get_func(module, "inner")
149
+ outer = _get_func(module, "outer")
150
+ assert inner.mutated_params is not None and 0 in inner.mutated_params
151
+ assert outer.mutated_params is not None and 0 in outer.mutated_params, (
152
+ f"outer's `p` should be transitively marked mutated, "
153
+ f"got mutated_params={outer.mutated_params}"
154
+ )
155
+
156
+ def test_no_propagation_when_inner_does_not_mutate(self):
157
+ """Negative: if inner only reads the tuple, outer is not marked."""
158
+ source = """
159
+ from tpy import Int32
160
+
161
+ class T:
162
+ x: Int32
163
+ def __init__(self, x: Int32) -> None:
164
+ self.x = x
165
+
166
+ def inner(p: tuple[T, T]) -> Int32:
167
+ a, b = p
168
+ return a.x + b.x
169
+
170
+ def outer(p: tuple[T, T]) -> Int32:
171
+ return inner(p)
172
+ """
173
+ module = _compile(source)
174
+ outer = _get_func(module, "outer")
175
+ assert outer.mutated_params is not None
176
+ assert 0 not in outer.mutated_params
177
+
178
+
179
+ class TestTupleLiteralRhsDestructure:
180
+ """`a, b = (x, y)` should also propagate mutation through the borrow
181
+ edges from x/y to a/b."""
182
+
183
+ def test_tuple_literal_rhs_propagates(self):
184
+ source = """
185
+ from tpy import Int32
186
+
187
+ class T:
188
+ x: Int32
189
+ def __init__(self, x: Int32) -> None:
190
+ self.x = x
191
+
192
+ def f(x: T, y: T) -> None:
193
+ a, b = (x, y)
194
+ a.x = Int32(1)
195
+ """
196
+ module = _compile(source)
197
+ f = _get_func(module, "f")
198
+ assert f.mutated_params is not None
199
+ assert 0 in f.mutated_params, (
200
+ f"`x` should be marked mutated through tuple-literal destructure, "
201
+ f"got mutated_params={f.mutated_params}"
202
+ )
203
+ # `y` is destructured into b but b is never written through.
204
+ assert 1 not in f.mutated_params, (
205
+ f"`y` should NOT be marked mutated, got mutated_params={f.mutated_params}"
206
+ )