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,744 @@
1
+ # tpy: cpp_namespace("tpystd::asyncio")
2
+ """asyncio v1 -- minimum viable async runtime.
3
+
4
+ `run` / `sleep` / `create_task` / `Task[T]` / `Future[T]` / `Event` /
5
+ `CancelledError`. Lowers to `runtime/cpp/include/tpy/async.hpp` and
6
+ the TPy Executor in `_executor.py`. See `docs/ASYNC_DESIGN.md`.
7
+ """
8
+ from builtins import BaseException, Exception, TimeoutError
9
+ from tpy import Own, Int32, CancelledError, Throwable, nocopy
10
+ from tpy.coro import (
11
+ Waker, Poll, Cancellable,
12
+ poll_ready, poll_pending, poll_ready_none,
13
+ )
14
+ from tpy.mem import UninitArrayStorage
15
+ from tplib import Box
16
+ from time import monotonic
17
+ from ._executor import (
18
+ Task, AnyTask,
19
+ task_from_coro, make_executor_owned_task, task_to_any_box,
20
+ Executor, _ExecutorScope,
21
+ _get_current_executor,
22
+ )
23
+
24
+
25
+ def run[T](coro: Own[Cancellable[T]]) -> T:
26
+ if _get_current_executor() is not None:
27
+ raise RuntimeError(
28
+ "asyncio.run() cannot be called from a running event loop")
29
+ task = make_executor_owned_task[T](coro)
30
+ box = task_to_any_box[T](task)
31
+ _run_drain_main_task(box)
32
+ return task.__poll__(Waker()).value()
33
+
34
+
35
+ # Lives here (not _executor.py): C++ function using-decls in
36
+ # asyncio.hpp require the source namespace already opened, which
37
+ # breaks under the parent-package include cycle.
38
+ def _run_drain_main_task(box: Own[Box[AnyTask]]) -> None:
39
+ executor = Executor()
40
+ scope = _ExecutorScope(executor)
41
+ main_id = executor.spawn(box)
42
+ try:
43
+ executor.run_until(main_id)
44
+ finally:
45
+ # Swallow drain-time exceptions; v1 has no place to surface them.
46
+ try:
47
+ executor.drain_spawned_with_cancel(main_id)
48
+ except BaseException:
49
+ pass
50
+
51
+
52
+ # No-op if no executor is running, so hand-rolled awaitables polled
53
+ # from a test harness without `asyncio.run` don't crash.
54
+ def _register_timer_at(deadline_seconds: float, waker: Waker) -> None:
55
+ handle = _get_current_executor()
56
+ if handle is None:
57
+ return
58
+ handle.register_timer(deadline_seconds, waker)
59
+
60
+
61
+ class SleepFuture:
62
+ """Awaits a steady-clock deadline. Registers a timer with the
63
+ current executor on first poll and returns Pending until the
64
+ deadline elapses; conforms to the Awaitable[None] shape (poll +
65
+ `_cancel_pending` field that the runtime's `Task::cancel` flips).
66
+ """
67
+
68
+ deadline: float
69
+ registered: bool
70
+ _cancel_pending: bool
71
+
72
+ def __init__(self, seconds: float) -> None:
73
+ self.deadline = monotonic() + seconds
74
+ self.registered = False
75
+ self._cancel_pending = False
76
+
77
+ # Required for structural conformance to `@dynamic Cancellable[T]`
78
+ # (in `tpy.coro`). Mirrors the codegen-emitted `cancel()` on
79
+ # every generated coro struct.
80
+ def cancel(self) -> None:
81
+ self._cancel_pending = True
82
+
83
+ def __poll__(self, waker: Waker) -> Own[Poll[None]]:
84
+ if self._cancel_pending:
85
+ self._cancel_pending = False
86
+ # TODO: cancelling a registered SleepFuture leaves its timer
87
+ # entry in the executor's timer_heap + _timer_wakers. The
88
+ # generation guard makes the eventual wake a silent no-op,
89
+ # so it's harmless per-cancel, but the heap grows unbounded
90
+ # under cancel-heavy workloads. Fix: track the (timer_id,
91
+ # waker) pair on self at registration time and remove it
92
+ # from the executor here before throwing. Needs an executor
93
+ # `cancel_timer(timer_id)` primitive.
94
+ raise CancelledError()
95
+ if monotonic() >= self.deadline:
96
+ return poll_ready_none()
97
+ if not self.registered:
98
+ _register_timer_at(self.deadline, waker)
99
+ self.registered = True
100
+ return poll_pending()
101
+
102
+
103
+ # Park the calling coroutine for `seconds` seconds. Returns an
104
+ # Own[Task[None]] whose underlying SleepFuture registers a timer with
105
+ # the current executor on first poll; the run loop wakes when the
106
+ # deadline arrives.
107
+ def sleep(seconds: float) -> Own[Task[None]]:
108
+ return task_from_coro[None](SleepFuture(seconds))
109
+
110
+
111
+ # Spawn `coro` on the current executor and return an Own[Task[T]]
112
+ # handle. The task is registered with the executor's slot table so
113
+ # it runs concurrently with the spawning task. Raises RuntimeError if
114
+ # no event loop is running.
115
+ def create_task[T](coro: Own[Cancellable[T]]) -> Own[Task[T]]:
116
+ handle = _get_current_executor()
117
+ if handle is None:
118
+ raise RuntimeError(
119
+ "asyncio.create_task: no running event loop "
120
+ "(call asyncio.run(coro) to drive it)")
121
+ task = make_executor_owned_task[T](coro)
122
+ box = task_to_any_box[T](task)
123
+ slot_id = handle.spawn(box)
124
+ # Stamp a Waker for the slot onto the Task so `Task.cancel()` can
125
+ # mark the slot runnable promptly. Read the freshly-spawned slot's
126
+ # generation directly rather than hardcoding 0, so this stays
127
+ # correct if `Slot.__init__` ever changes its starting generation
128
+ # (e.g. for slot recycling). If the slot completes (generation
129
+ # bumps) before cancel fires, Waker.wake's generation guard
130
+ # silently drops the wake. Non-executor-owned tasks (built via
131
+ # `task_from_coro`) keep the default null-awaker Waker assigned in
132
+ # Task.__init__, and wake() is a safe no-op on those.
133
+ task._waker = handle.make_waker_for_slot(
134
+ slot_id, handle.slots[slot_id].generation)
135
+ return task
136
+
137
+
138
+ @nocopy
139
+ class _WaitForFuture[T]:
140
+ """Drives an inner Cancellable[T] against a steady-clock deadline.
141
+
142
+ Registers a one-shot timer with the current executor on first
143
+ poll. When the deadline elapses, propagates `cancel()` to the
144
+ inner frame and keeps polling it until it returns -- translating
145
+ the resulting `CancelledError` into `TimeoutError`. An external
146
+ cancel (outer task cancellation) propagates to the inner unchanged
147
+ and re-raises `CancelledError`. The deadline timer can fire after
148
+ the inner already completed; the generation guard in
149
+ `Executor.mark_runnable` swallows the late wake.
150
+ """
151
+
152
+ _inner: Box[Cancellable[T]]
153
+ _deadline: float
154
+ _registered: bool
155
+ _cleanup: bool
156
+ _timed_out: bool
157
+ _cancel_pending: bool
158
+
159
+ def __init__(self, coro: Own[Cancellable[T]], timeout: float) -> None:
160
+ self._inner = Box[Cancellable[T]](coro)
161
+ self._deadline = monotonic() + timeout
162
+ self._registered = False
163
+ self._cleanup = False
164
+ self._timed_out = False
165
+ self._cancel_pending = False
166
+
167
+ # Required for `@dynamic Cancellable[T]` conformance. Flips the
168
+ # cancel flag; the next __poll__ propagates to the inner. Matches
169
+ # the SleepFuture / Future / Event pattern.
170
+ def cancel(self) -> None:
171
+ self._cancel_pending = True
172
+
173
+ def __poll__(self, waker: Waker) -> Own[Poll[T]]:
174
+ # Consume the cancel signal up front so a re-cancel arriving
175
+ # after `_cleanup=True` doesn't accumulate (cleanup is already
176
+ # in flight; the second cancel adds nothing). Mirrors the
177
+ # "consumed each poll" invariant SleepFuture maintains.
178
+ was_canceling = self._cancel_pending
179
+ self._cancel_pending = False
180
+
181
+ # Outer cancel wins over a pending timeout. Mark cleanup so
182
+ # an in-flight inner cancel observed below re-raises as
183
+ # CancelledError, not TimeoutError.
184
+ if was_canceling and not self._cleanup:
185
+ self._cleanup = True
186
+ self._inner.get().cancel()
187
+
188
+ if not self._registered:
189
+ _register_timer_at(self._deadline, waker)
190
+ self._registered = True
191
+
192
+ # Deadline elapsed and we have not started cleanup yet:
193
+ # propagate cancel to the inner and pump it until it returns.
194
+ # A non-positive timeout takes this branch on the first poll.
195
+ if not self._cleanup and monotonic() >= self._deadline:
196
+ self._cleanup = True
197
+ self._timed_out = True
198
+ self._inner.get().cancel()
199
+
200
+ try:
201
+ return self._inner.get().__poll__(waker)
202
+ except CancelledError:
203
+ if self._timed_out:
204
+ raise TimeoutError()
205
+ raise
206
+
207
+
208
+ # Await `coro` with a steady-clock deadline of `timeout` seconds.
209
+ # Returns the coroutine's value if it completes before the deadline.
210
+ # Otherwise propagates `cancel()` to the coroutine, pumps it until it
211
+ # observes the cancellation, then raises `TimeoutError`. A non-
212
+ # positive `timeout` triggers the deadline on the first poll (matches
213
+ # CPython).
214
+ #
215
+ # Outer cancellation of a task awaiting `wait_for` propagates through
216
+ # to the inner coroutine: the resume-case cancel-check (in every
217
+ # async-def coro frame) calls `cancel()` on the in-flight sub-coro
218
+ # before polling, so the inner observes `CancelledError` at its
219
+ # suspension point and can run `finally`-with-await cleanup before
220
+ # the cancellation surfaces to the caller.
221
+ async def wait_for[T](coro: Own[Cancellable[T]], timeout: float) -> T:
222
+ return await _WaitForFuture[T](coro, timeout)
223
+
224
+
225
+ @nocopy
226
+ class _GatherFuture[T]:
227
+ """Drives N already-spawned `Task[T]`s concurrently and harvests
228
+ their results in input order.
229
+
230
+ Each `__poll__` cycle polls every still-unsettled task with the
231
+ awaiter's waker. When a sub-task completes, its TaskState wakes
232
+ that waker, scheduling another gather poll. On the first failure
233
+ (or outer cancel), transitions to cleanup mode: propagates
234
+ `cancel()` to remaining sub-tasks and discards their values as
235
+ they settle. Re-raises the first exception once every sub-task
236
+ has settled.
237
+
238
+ Cancel propagation is prompt for `create_task`-built sub-tasks:
239
+ `Task.cancel()` (since M10) fires a per-Task `Waker` stamped at
240
+ `create_task` time, marking the slot runnable so the in-flight
241
+ frame observes its `__cancel_pending` on its next poll rather
242
+ than waiting on a natural wake. Sub-tasks built via
243
+ `task_from_coro` (not registered with the executor) carry the
244
+ default null-awaker Waker, so cancel-wake is a no-op for them and
245
+ observation reverts to the sub-task's next natural progress --
246
+ the same latency that pre-M10 gather had.
247
+ """
248
+
249
+ _tasks: list[Task[T]]
250
+ _completion_indices: list[Int32]
251
+ _completion_boxes: list[Box[T]]
252
+ _settled: list[bool]
253
+ _exc: Box[Throwable] | None
254
+ _completed: Int32
255
+ _cleanup: bool
256
+ _cancel_pending: bool
257
+
258
+ def __init__(self, tasks: list[Task[T]]) -> None:
259
+ # tasks is borrowed from the caller. Rc-clone each Task into
260
+ # our owned list so the future is self-contained -- avoids the
261
+ # codegen gap on passing a named-local Own[list[T]] arg into a
262
+ # sub-coro emplace (cheap: each clone is one refcount bump on
263
+ # the underlying TaskState).
264
+ self._tasks = []
265
+ self._completion_indices = []
266
+ self._completion_boxes = []
267
+ self._settled = []
268
+ self._exc = None
269
+ self._completed = 0
270
+ self._cleanup = False
271
+ self._cancel_pending = False
272
+ for t in tasks:
273
+ self._tasks.append(t.clone())
274
+ self._settled.append(False)
275
+
276
+ # Required for structural conformance to `@dynamic Cancellable[T]`.
277
+ # Mirrors the SleepFuture / _WaitForFuture pattern: just flips the
278
+ # signal; the next __poll__ propagates to sub-tasks.
279
+ def cancel(self) -> None:
280
+ self._cancel_pending = True
281
+
282
+ def __poll__(self, waker: Waker) -> Own[Poll[list[T]]]:
283
+ # Empty gather is trivially complete on every poll, including
284
+ # the first one after an outer cancel. Matches CPython's
285
+ # "gather() with no args returns []".
286
+ n = len(self._tasks)
287
+ if n == 0:
288
+ empty: list[T] = []
289
+ return poll_ready(empty)
290
+
291
+ # Consume cancel signal up front so a re-cancel arriving after
292
+ # cleanup is already in flight doesn't accumulate (mirrors
293
+ # _WaitForFuture). Propagate cancel into sub-tasks now; defer
294
+ # claiming `_exc` until AFTER the per-task loop so a freshly
295
+ # observable inner exception this cycle wins over the cancel
296
+ # (avoids silently dropping a real failure under racing-cancel).
297
+ was_canceling = self._cancel_pending
298
+ self._cancel_pending = False
299
+ if was_canceling and not self._cleanup:
300
+ self._cleanup = True
301
+ self._propagate_cancel()
302
+
303
+ # Poll every unsettled task with the shared waker. Multiple
304
+ # wakes between polls coalesce at the executor (one runnable
305
+ # flag per slot), so the O(N) re-poll per cycle is bounded.
306
+ i: Int32 = 0
307
+ while i < n:
308
+ if not self._settled[i]:
309
+ try:
310
+ p = self._tasks[i].__poll__(waker)
311
+ if p.is_ready():
312
+ self._settled[i] = True
313
+ self._completed += 1
314
+ if self._cleanup:
315
+ # Cleanup mode: discard value; `p` drops
316
+ # at end of block and the destructor
317
+ # disposes the contained T.
318
+ pass
319
+ else:
320
+ self._completion_indices.append(i)
321
+ self._completion_boxes.append(Box(p.value()))
322
+ except BaseException as e:
323
+ self._settled[i] = True
324
+ self._completed += 1
325
+ if self._exc is None:
326
+ self._exc = Box(e.clone())
327
+ if not self._cleanup:
328
+ self._cleanup = True
329
+ self._propagate_cancel()
330
+ i += 1
331
+
332
+ # Outer-cancel fallback: only claim `_exc` for CancelledError
333
+ # if nothing real fired this cycle (or any prior one).
334
+ if was_canceling and self._exc is None:
335
+ self._exc = Box(CancelledError())
336
+
337
+ if self._completed < n:
338
+ return poll_pending()
339
+
340
+ if self._exc is not None:
341
+ raise self._exc
342
+
343
+ # All sub-tasks succeeded. Reorder completions into input
344
+ # order. O(n^2) walk -- n is typically small (handful of
345
+ # concurrent operations); fine for v1.5.
346
+ result: list[T] = []
347
+ orig_i: Int32 = 0
348
+ while orig_i < n:
349
+ k: Int32 = 0
350
+ kn = len(self._completion_indices)
351
+ while k < kn:
352
+ if self._completion_indices[k] == orig_i:
353
+ box = self._completion_boxes.pop(k)
354
+ self._completion_indices.pop(k)
355
+ result.append(box.take())
356
+ break
357
+ k += 1
358
+ orig_i += 1
359
+ return poll_ready(result)
360
+
361
+ def _propagate_cancel(self) -> None:
362
+ i: Int32 = 0
363
+ n = len(self._tasks)
364
+ while i < n:
365
+ if not self._settled[i]:
366
+ self._tasks[i].cancel()
367
+ i += 1
368
+
369
+
370
+ # Run `tasks` concurrently and return their results in input order.
371
+ # On the first sub-task exception (or outer cancellation), propagates
372
+ # `cancel()` to the remaining sub-tasks, waits for them to settle, then
373
+ # re-raises the first exception encountered.
374
+ #
375
+ # Two homogeneous entrypoints share the same `_GatherFuture[T]` engine:
376
+ # - `gather(*tasks)` -- variadic-positional form.
377
+ # - `gather_list(tasks)` -- list-shaped form.
378
+ # Both require all tasks to share return type `T`. The CPython-shape
379
+ # heterogeneous variadic form `gather[*Ts](*coros) -> tuple[*Ts]`
380
+ # remains deferred (needs variadic generics + the async-def `*args`
381
+ # codegen fix; see TODO.md / BUGS.md).
382
+ async def gather_list[T](tasks: list[Task[T]]) -> list[T]:
383
+ return await _GatherFuture[T](tasks)
384
+
385
+
386
+ def gather[T](*tasks: Task[T]) -> Own[_GatherFuture[T]]:
387
+ # Sync factory returning the awaitable as Own[...] -- same shape as
388
+ # the hand-written `_WaitForFuture(coro, timeout)` / `SleepFuture(t)`
389
+ # awaitables, not the executor-registered `create_task` (gather does
390
+ # not spawn on the executor; the caller awaits the returned future
391
+ # directly). Each Task is Rc-cloned into an owned list so the
392
+ # awaitable is self-contained across the await point. _GatherFuture
393
+ # also re-clones internally; both bumps are O(1) refcount-only,
394
+ # kept for code simplicity.
395
+ #
396
+ # The explicit `for ... append` loop (not a list comprehension) is
397
+ # deliberate: iterating `tpy::varargs<Task[T]>` (non-value generic
398
+ # vararg) goes through codegen surface that BUGS.md notes as
399
+ # fragile in the comp/slicing form. Keep this shape.
400
+ task_list: list[Task[T]] = []
401
+ for t in tasks:
402
+ task_list.append(t.clone())
403
+ return _GatherFuture[T](task_list)
404
+
405
+
406
+ @nocopy
407
+ class Settled[T]:
408
+ """One slot in `gather_list_settled`'s output. Exactly one of
409
+ `value` / `exception` is populated; the other is `None`. The
410
+ record shape sidesteps two TPy/CPython mismatches around the
411
+ natural `T | BaseException` form: (1) TPy lowers union elements
412
+ in containers to a value-variant, and the exception root is a
413
+ polymorphic owner (slicing risk on by-value moves); (2) TPy
414
+ `isinstance(x, Box[Throwable])` against a union member of
415
+ that exact shape is not yet supported. Field access is a clean
416
+ discriminator on either side.
417
+
418
+ Callers inspect:
419
+ if entry.exception is not None:
420
+ raise entry.exception # recover dynamic type via except
421
+ elif entry.value is not None:
422
+ handle_ok(entry.value.get())
423
+
424
+ Both fields are wrapped in `Box` so the record stays trivially
425
+ movable inside `list[Settled[T]]` regardless of T's value/non-value
426
+ shape. The exception is stored as `Box[Throwable]` (the polymorphic
427
+ root); re-raise it to recover the concrete subclass.
428
+ """
429
+
430
+ value: Box[T] | None
431
+ exception: Box[Throwable] | None
432
+
433
+ # Users normally don't construct Settled directly --
434
+ # `gather_list_settled` is the only producer and assigns the
435
+ # `value` / `exception` fields directly post-init.
436
+ def __init__(self) -> None:
437
+ self.value = None
438
+ self.exception = None
439
+
440
+
441
+ @nocopy
442
+ class _GatherSettledFuture[T]:
443
+ """Drives N already-spawned `Task[T]`s concurrently and harvests
444
+ every result -- value OR exception -- into a `list[Settled[T]]`
445
+ in input order. Variant of CPython
446
+ `gather(*coros, return_exceptions=True)`.
447
+
448
+ Unlike `_GatherFuture`, a sub-task exception does NOT cancel its
449
+ siblings: each task runs to completion and contributes either its
450
+ value or its raised exception to the result list. A sub-task that
451
+ is cancelled independently (via its own handle) raises
452
+ `CancelledError`, which is collected as a `Settled` entry like any
453
+ other exception -- matching CPython's `return_exceptions=True`
454
+ rule that a cancelled submitted task is treated as having raised.
455
+
456
+ Cancelling the gather itself (the task awaiting it) is different:
457
+ `cancel()` propagates cancel to every still-unsettled sub-task
458
+ (so they don't leak), but the `CancelledError` then propagates UP
459
+ to the awaiting caller -- it is NOT swallowed into the result
460
+ list. This also matches CPython: cancelling `gather()` cancels
461
+ it. (The collected-result path is therefore only observable for
462
+ independently-cancelled sub-tasks, not for cancelling the gather
463
+ caller.)
464
+
465
+ Storage uses arrival-order parallel arrays for both values and
466
+ exceptions (mirroring `_GatherFuture`'s shape). Boxes are
467
+ `@nocopy`; the assembly loop ownership-transfers each entry out
468
+ of its arrival array via `list.pop`, then assigns to the
469
+ appropriate `Settled` field. Per-input-index storage is rejected
470
+ here because `list[Box[T] | None]` element slots have no
471
+ take-and-clear primitive that satisfies the borrow checker.
472
+ """
473
+
474
+ _tasks: list[Task[T]]
475
+ _settled: list[bool]
476
+ _result_indices: list[Int32]
477
+ _result_boxes: list[Box[T]]
478
+ _exc_indices: list[Int32]
479
+ _exc_boxes: list[Box[Throwable]]
480
+ _completed: Int32
481
+ _cancel_pending: bool
482
+
483
+ def __init__(self, tasks: list[Task[T]]) -> None:
484
+ # `tasks` is borrowed from the caller -- Rc-clone each entry as
485
+ # in `_GatherFuture` (avoids the named-local Own[list[T]] arg
486
+ # codegen gap; each clone is one refcount bump on TaskState).
487
+ self._tasks = []
488
+ self._settled = []
489
+ self._result_indices = []
490
+ self._result_boxes = []
491
+ self._exc_indices = []
492
+ self._exc_boxes = []
493
+ self._completed = 0
494
+ self._cancel_pending = False
495
+ for t in tasks:
496
+ self._tasks.append(t.clone())
497
+ self._settled.append(False)
498
+
499
+ # Required for structural conformance to `@dynamic Cancellable[T]`.
500
+ def cancel(self) -> None:
501
+ self._cancel_pending = True
502
+
503
+ def __poll__(self, waker: Waker) -> Own[Poll[list[Settled[T]]]]:
504
+ n = len(self._tasks)
505
+ if n == 0:
506
+ empty: list[Settled[T]] = []
507
+ return poll_ready(empty)
508
+
509
+ # Outer cancel: mark every unsettled sub-task's slot runnable
510
+ # via Task.cancel. Subs will raise CancelledError at their
511
+ # next suspension; we collect it as an entry rather than
512
+ # bubbling it out (CPython's return_exceptions semantics).
513
+ was_canceling = self._cancel_pending
514
+ self._cancel_pending = False
515
+ if was_canceling:
516
+ i: Int32 = 0
517
+ while i < n:
518
+ if not self._settled[i]:
519
+ self._tasks[i].cancel()
520
+ i += 1
521
+
522
+ i: Int32 = 0
523
+ while i < n:
524
+ if not self._settled[i]:
525
+ try:
526
+ p = self._tasks[i].__poll__(waker)
527
+ if p.is_ready():
528
+ self._settled[i] = True
529
+ self._completed += 1
530
+ self._result_indices.append(i)
531
+ self._result_boxes.append(Box(p.value()))
532
+ except BaseException as e:
533
+ self._settled[i] = True
534
+ self._completed += 1
535
+ self._exc_indices.append(i)
536
+ self._exc_boxes.append(Box(e.clone()))
537
+ i += 1
538
+
539
+ if self._completed < n:
540
+ return poll_pending()
541
+
542
+ # Assemble in input order. For each input slot, scan the
543
+ # arrival-order arrays for a matching index, then `pop` to
544
+ # transfer ownership of the Box out of the list. O(n^2)
545
+ # walk -- N is typically small (handful of concurrent
546
+ # operations); fine for v1.5.
547
+ result: list[Settled[T]] = []
548
+ orig_i: Int32 = 0
549
+ while orig_i < n:
550
+ settled_via_value = False
551
+ k: Int32 = 0
552
+ kn = len(self._result_indices)
553
+ while k < kn:
554
+ if self._result_indices[k] == orig_i:
555
+ self._result_indices.pop(k)
556
+ box = self._result_boxes.pop(k)
557
+ entry = Settled[T]()
558
+ entry.value = box
559
+ result.append(entry)
560
+ settled_via_value = True
561
+ break
562
+ k += 1
563
+ if not settled_via_value:
564
+ k = 0
565
+ kn = len(self._exc_indices)
566
+ while k < kn:
567
+ if self._exc_indices[k] == orig_i:
568
+ self._exc_indices.pop(k)
569
+ ebox = self._exc_boxes.pop(k)
570
+ entry = Settled[T]()
571
+ entry.exception = ebox
572
+ result.append(entry)
573
+ break
574
+ k += 1
575
+ orig_i += 1
576
+ return poll_ready(result)
577
+
578
+
579
+ # Run `tasks` concurrently and harvest every result -- value OR
580
+ # exception -- into `list[Settled[T]]` in input order. Variant of
581
+ # CPython `asyncio.gather(*coros, return_exceptions=True)`: a sub-task
582
+ # failure does NOT cancel siblings (each runs to completion); a
583
+ # sub-task cancelled independently is collected as a `Settled` entry
584
+ # with `exception` populated (its `CancelledError`). Cancelling the
585
+ # gather caller itself propagates cancel into the sub-tasks for
586
+ # cleanup and then re-raises `CancelledError` to the caller -- it is
587
+ # NOT swallowed into the result list (matching CPython: cancelling
588
+ # gather() cancels it).
589
+ #
590
+ # TPy-specific shape: returns `list[Settled[T]]` rather than CPython's
591
+ # `list[T | BaseException]`. Two reasons: (1) TPy lowers union
592
+ # elements in containers to a value-variant and the exception root is
593
+ # a polymorphic owner (slicing risk); (2) `isinstance` against
594
+ # `Box[Throwable]` as a union member isn't yet supported. The
595
+ # `Settled[T]` record gives clean field-based discrimination; the
596
+ # exception is a `Box[Throwable]` (re-raise to recover the subclass).
597
+ #
598
+ # Sibling of `gather_list` / `gather` (cancel-and-re-raise variants).
599
+ async def gather_list_settled[T](
600
+ tasks: list[Task[T]]) -> list[Settled[T]]:
601
+ return await _GatherSettledFuture[T](tasks)
602
+
603
+
604
+ class InvalidStateError(Exception):
605
+ """Raised when set_result / set_exception is called on a Future
606
+ that is already done."""
607
+ pass
608
+
609
+
610
+ class Future[T]:
611
+ """Single-awaiter, manual-completion awaitable.
612
+
613
+ Construct, await it from a coroutine, then call `set_result(value)`
614
+ (or `set_exception(exc)`) from another context to complete it.
615
+
616
+ v1 limitations:
617
+ - Single-awaiter: a second waiter raises ValueError.
618
+ - poll() consumes the result: a second poll after Ready panics
619
+ (or wakes a future poll on the empty storage). Multi-awaiter v2
620
+ will keep the result around.
621
+ """
622
+
623
+ _done: bool
624
+ _has_waiter: bool
625
+ _has_result: bool
626
+ _exception: Box[Throwable] | None
627
+ _waiter: Waker
628
+ _result: UninitArrayStorage[T, 1]
629
+
630
+ def __init__(self) -> None:
631
+ self._done = False
632
+ self._has_waiter = False
633
+ self._has_result = False
634
+ self._exception = None
635
+ self._waiter = Waker()
636
+ self._result = UninitArrayStorage[T, 1]()
637
+
638
+ def __del__(self) -> None:
639
+ if self._has_result:
640
+ self._result.take0()
641
+ self._has_result = False
642
+
643
+ def done(self) -> bool:
644
+ return self._done
645
+
646
+ def set_result(self, value: Own[T]) -> None:
647
+ # Takes ownership of `value` so nocopy types work without a
648
+ # `__copy__` opt-in. Callers passing a named local must use
649
+ # `tpy.copy(x)` explicitly to keep their reference alive.
650
+ if self._done:
651
+ raise InvalidStateError("Future already done")
652
+ self._result.init0(value)
653
+ self._has_result = True
654
+ self._done = True
655
+ if self._has_waiter:
656
+ self._waiter.wake()
657
+ self._has_waiter = False
658
+
659
+ def set_exception(self, exc: Own[Throwable]) -> None:
660
+ if self._done:
661
+ raise InvalidStateError("Future already done")
662
+ self._exception = Box(exc)
663
+ self._done = True
664
+ if self._has_waiter:
665
+ self._waiter.wake()
666
+ self._has_waiter = False
667
+
668
+ # Required for structural conformance to `@dynamic Cancellable[T]`
669
+ # (in `tpy.coro`). Future cancellation is task-level: the
670
+ # awaiting Task throws CancelledError before re-polling the Future,
671
+ # so the Future itself has no inner state to flip. This is the
672
+ # protocol hook called via the type-erased Adapter; the body is
673
+ # intentionally a no-op.
674
+ def cancel(self) -> None:
675
+ pass
676
+
677
+ def __poll__(self, waker: Waker) -> Own[Poll[T]]:
678
+ if self._done:
679
+ if self._exception is not None:
680
+ raise self._exception
681
+ if not self._has_result:
682
+ raise ValueError(
683
+ "Future done with no result and no exception")
684
+ self._has_result = False
685
+ # take0() returns Own[T] -- pass directly as rvalue so
686
+ # nocopy types (T with __del__ but no __copy__) flow through
687
+ # without requiring a copy ctor.
688
+ return poll_ready(self._result.take0())
689
+ if self._has_waiter:
690
+ raise ValueError(
691
+ "Future already has a waiter (single-awaiter v1)")
692
+ self._waiter = waker
693
+ self._has_waiter = True
694
+ return poll_pending()
695
+
696
+
697
+ class Event:
698
+ """Boolean completion signal -- the no-payload analog of Future.
699
+ Single-awaiter v1.
700
+
701
+ `set` / `clear` / `is_set` match CPython. Divergence: TPy's Event
702
+ is directly awaitable (`await event`) where CPython requires
703
+ `await event.wait()` -- TPy classes can't yet define `async def`
704
+ methods, so tests using Event need `no_cpython.txt`.
705
+ """
706
+
707
+ _is_set: bool
708
+ _has_waiter: bool
709
+ _waiter: Waker
710
+
711
+ def __init__(self) -> None:
712
+ self._is_set = False
713
+ self._has_waiter = False
714
+ self._waiter = Waker()
715
+
716
+ def is_set(self) -> bool:
717
+ return self._is_set
718
+
719
+ def set(self) -> None:
720
+ if self._is_set:
721
+ return
722
+ self._is_set = True
723
+ if self._has_waiter:
724
+ self._waiter.wake()
725
+ self._has_waiter = False
726
+
727
+ def clear(self) -> None:
728
+ self._is_set = False
729
+
730
+ # Required for structural conformance to `@dynamic Cancellable[T]`
731
+ # (in `tpy.coro`). Event cancellation is task-level (see
732
+ # Future.cancel above for the rationale); body is a no-op.
733
+ def cancel(self) -> None:
734
+ pass
735
+
736
+ def __poll__(self, waker: Waker) -> Own[Poll[None]]:
737
+ if self._is_set:
738
+ return poll_ready_none()
739
+ if self._has_waiter:
740
+ raise ValueError(
741
+ "Event already has a waiter (single-awaiter v1)")
742
+ self._waiter = waker
743
+ self._has_waiter = True
744
+ return poll_pending()