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,515 @@
1
+ # tpy: cpp_namespace("tpystd::asyncio::_executor")
2
+ # tpy: include("<tpy/async.hpp>")
3
+ # tpy: include("<tpy/stdlib/time.hpp>")
4
+ """Internal asyncio scaffolding -- the TPy executor and the small
5
+ helpers it needs. Not part of the public asyncio API; imported only
6
+ by `lib/tpy/asyncio/` modules. See `docs/ASYNC_DESIGN.md` for the
7
+ dispatch model and `docs/ASYNC_PROGRESS.md` for port history.
8
+
9
+ `Waker` (defined in `tpy.coro`) holds a `Ptr[Awaker]` to the running
10
+ executor; `Waker.wake()` dispatches `mark_runnable` through the
11
+ `@dynamic Awaker` vtable. `Executor` inherits `Awaker` so it provides
12
+ the vtable slot directly -- no C++ ExecutorOps table, no templated
13
+ thunks, no thread-local handle.
14
+ """
15
+ import heapq
16
+
17
+ from typing import Protocol
18
+ from builtins import BaseException
19
+ from time import monotonic, sleep_until_steady
20
+ from tpy import Int32, Own, Ptr, Throwable, dynamic, nocopy, readonly
21
+ from tpy.extern import builtin_type, cpp_template
22
+ from tpy.coro import Awaker, Cancellable, Poll, Waker, poll_ready, poll_pending
23
+ from tpy.mem import UninitArrayStorage
24
+ from tplib import Box
25
+ from tplib.rc import Rc
26
+
27
+
28
+ # Type-erased task machinery is co-located with the executor (rather
29
+ # than split into a sibling submodule) to avoid the parent-package
30
+ # auto-include cycle in `tpyc/codegen_cpp/generator.py:1530+`; see
31
+ # BUGS.md.
32
+
33
+
34
+ # `Cancellable[T]` (`__poll__` + `cancel`) lives in `tpy.coro` now;
35
+ # we re-export it from `asyncio` for user-facing API typing.
36
+
37
+
38
+ # T-erased view of a task for the executor's slot table. TaskState[T]
39
+ # structurally conforms via its poll_any / cancel_any methods; the
40
+ # slot table holds Box[AnyTask] without parameterization on T.
41
+ @dynamic
42
+ class AnyTask(Protocol):
43
+ def poll_any(self, waker: Waker) -> bool: ...
44
+ def cancel_any(self) -> None: ...
45
+
46
+
47
+ @nocopy
48
+ class TaskState[T]:
49
+ """Shared backing for a `Task[T]`.
50
+
51
+ Owns a `Box[Cancellable[T]]` (the type-erased coroutine frame) and
52
+ caches result/exception once the frame completes. Single-awaiter
53
+ for v1: a second `__poll__` after Ready panics.
54
+ """
55
+
56
+ frame: Box[Cancellable[T]] | None
57
+ result: UninitArrayStorage[T, 1]
58
+ exc: Box[Throwable] | None
59
+ awaiter: Waker
60
+ done: bool
61
+ has_result: bool
62
+ executor_owned: bool
63
+
64
+ def __init__(self, frame: Own[Box[Cancellable[T]]]) -> None:
65
+ self.frame = frame
66
+ self.result = UninitArrayStorage[T, 1]()
67
+ self.exc = None
68
+ self.awaiter = Waker()
69
+ self.done = False
70
+ self.has_result = False
71
+ self.executor_owned = False
72
+
73
+ def __del__(self) -> None:
74
+ if self.has_result:
75
+ self.result.take0()
76
+ self.has_result = False
77
+
78
+ # User-facing poll. Drives the frame for non-executor-owned tasks;
79
+ # for executor-owned tasks, parks (the executor's poll_any drives).
80
+ def __poll__(self, w: Waker) -> Own[Poll[T]]:
81
+ if self.done:
82
+ exc = self.exc
83
+ if exc is not None:
84
+ raise exc
85
+ if not self.has_result:
86
+ raise RuntimeError(
87
+ "Task: __poll__ after Ready was already consumed")
88
+ self.has_result = False
89
+ return poll_ready(self.result.take0())
90
+ if self.executor_owned:
91
+ self.awaiter = w
92
+ return poll_pending()
93
+ # Non-executor-owned: drive the frame directly.
94
+ frame = self.frame
95
+ if frame is None:
96
+ raise RuntimeError("Task: __poll__ on empty TaskState")
97
+ try:
98
+ p = frame.get().__poll__(w)
99
+ if p.is_ready():
100
+ self.done = True
101
+ return p
102
+ except BaseException as e:
103
+ self.done = True
104
+ self.exc = Box(e.clone())
105
+ raise
106
+
107
+ # AnyTask interface: drives the frame and caches result/exc. Used
108
+ # by the executor's slot table via the TaskStateView adapter.
109
+ def poll_any(self, w: Waker) -> bool:
110
+ if self.done:
111
+ return True
112
+ frame = self.frame
113
+ if frame is None:
114
+ return True
115
+ try:
116
+ p = frame.get().__poll__(w)
117
+ if p.is_ready():
118
+ self.done = True
119
+ self.result.init0(p.value())
120
+ self.has_result = True
121
+ self.awaiter.wake()
122
+ return True
123
+ return False
124
+ except BaseException as e:
125
+ self.done = True
126
+ self.exc = Box(e.clone())
127
+ self.awaiter.wake()
128
+ return True
129
+
130
+ def cancel_any(self) -> None:
131
+ if self.done:
132
+ return
133
+ frame = self.frame
134
+ if frame is not None:
135
+ frame.get().cancel()
136
+
137
+
138
+ # Adapter that exposes a TaskState[T] through the non-generic AnyTask
139
+ # protocol. Holds an Rc clone of the same TaskState; the executor's
140
+ # slot table holds Box[AnyTask] wrapping this view.
141
+ @nocopy
142
+ class TaskStateView[T]:
143
+ state: Rc[TaskState[T]]
144
+
145
+ def __init__(self, state: Own[Rc[TaskState[T]]]) -> None:
146
+ self.state = state
147
+
148
+ def poll_any(self, w: Waker) -> bool:
149
+ return self.state.get().poll_any(w)
150
+
151
+ def cancel_any(self) -> None:
152
+ self.state.get().cancel_any()
153
+
154
+
155
+ @nocopy
156
+ class Task[T]:
157
+ """Type-erased async task. Holds a `Rc[TaskState[T]]` shared with
158
+ the executor's slot table for spawned tasks.
159
+
160
+ Regular @nocopy generic-class machinery: the C++ name
161
+ (`::tpystd::asyncio::_executor::Task<T>`) is derived from this
162
+ module's `# tpy: cpp_namespace` directive through
163
+ `NominalType._fallback_cpp_base_name`, and awaitability comes from
164
+ the `__poll__(self, w: Waker) -> Poll[T]` method below being
165
+ structurally matched by `_extract_awaitable_inner` in
166
+ `tpyc/sema/expressions.py`.
167
+ """
168
+
169
+ _state: Rc[TaskState[T]]
170
+ # Default-constructed (null awaker) for non-executor-owned tasks
171
+ # (`task_from_coro`); reassigned by `create_task` to a Waker stamped
172
+ # with the spawn slot's (slot_id, generation). `cancel()` calls
173
+ # `wake()` on it so the slot is marked runnable promptly -- the
174
+ # in-flight frame observes the cancel flag on its next poll instead
175
+ # of waiting on a timer / IO wake. Wake on a null-awaker Waker is a
176
+ # safe no-op (see Waker.wake in tpy.coro), so the non-executor-
177
+ # owned case stays unchanged.
178
+ #
179
+ # Lifetime: this Waker holds a raw `Ptr[Awaker]` into the running
180
+ # `Executor`. A Task[T] handle that survives `asyncio.run`'s scope
181
+ # and is later cancel()'d will dispatch through a dangling pointer
182
+ # -- same invariant `_ExecutorScope` (below) documents for every
183
+ # other stamped Waker. v1 asyncio.run drains spawned tasks during
184
+ # teardown to make this case unreachable in practice.
185
+ _waker: Waker
186
+
187
+ def __init__(self, state: Own[Rc[TaskState[T]]]) -> None:
188
+ self._state = state
189
+ self._waker = Waker()
190
+
191
+ def __poll__(self, w: Waker) -> Own[Poll[T]]:
192
+ return self._state.get().__poll__(w)
193
+
194
+ def cancel(self) -> None:
195
+ self._state.get().cancel_any()
196
+ # Wake routes through the @dynamic Awaker vtable to the
197
+ # executor's mark_runnable. The generation guard there filters
198
+ # late wakes against a completed slot, so this is safe even
199
+ # after the underlying task has already finished.
200
+ self._waker.wake()
201
+
202
+ # Cheap duplication: Task is an Rc handle into the shared TaskState,
203
+ # so clone() just bumps the refcount. Used by asyncio.gather and
204
+ # asyncio.gather_list to take owned task handles without consuming
205
+ # the caller's list/varargs.
206
+ #
207
+ # WARNING (v1.5): the clone aliases the SAME TaskState as `self`.
208
+ # TaskState is single-awaiter (one `awaiter: Waker` slot, one cached
209
+ # result slot consumed on first __poll__ that observes Ready). Two
210
+ # live handles must not be awaited concurrently and must not both
211
+ # consume the result -- only one consumer survives, the other's
212
+ # poll panics or its waker is overwritten. Likewise `cancel()` on
213
+ # either handle propagates through the shared TaskState to BOTH;
214
+ # the clone ALSO inherits the parent's stamped `_waker` (see field
215
+ # comment above), so cancel-via-clone marks the same executor slot
216
+ # runnable -- load-bearing for `_GatherFuture._propagate_cancel`,
217
+ # which cancels its Rc-cloned tasks and relies on the wake landing
218
+ # on the user's original spawn slot. `gather` and `gather_list` are
219
+ # the only safe internal users today: each drives its clones
220
+ # exclusively, and the user is expected to drop their original
221
+ # `tasks[i]` (gather_list) or stop using each positional Task arg
222
+ # (gather) once they've handed off to either entrypoint. A multi-
223
+ # awaiter TaskState is filed in TODO.md.
224
+ def clone(self) -> Own[Task[T]]:
225
+ t = Task[T](self._state.clone())
226
+ t._waker = self._waker
227
+ return t
228
+
229
+
230
+ def task_from_coro[T](coro: Own[Cancellable[T]]) -> Own[Task[T]]:
231
+ """Box an awaitable into a heap-allocated Task[T] without
232
+ registering with an executor (no `asyncio.run` required).
233
+ """
234
+ return _build_task[T](coro, False)
235
+
236
+
237
+ def make_executor_owned_task[T](coro: Own[Cancellable[T]]) -> Own[Task[T]]:
238
+ """Build a Task[T] flagged `executor_owned=True` (ready to be
239
+ spawned via the executor's slot table)."""
240
+ return _build_task[T](coro, True)
241
+
242
+
243
+ def _build_task[T](coro: Own[Cancellable[T]], executor_owned: bool) -> Own[Task[T]]:
244
+ frame = Box[Cancellable[T]](coro)
245
+ state = TaskState[T](frame)
246
+ state.executor_owned = executor_owned
247
+ return Task[T](Rc.new(state))
248
+
249
+
250
+ def task_to_any_box[T](task: Task[T]) -> Own[Box[AnyTask]]:
251
+ """Mirror a `Task[T]`'s shared state into a `Box[AnyTask]` for the
252
+ executor's slot table."""
253
+ return Box[AnyTask](TaskStateView[T](task._state.clone()))
254
+
255
+
256
+ # --- Awaker-side helpers (call sites inside Executor) -------------------
257
+
258
+
259
+ def _make_waker(handle: Awaker, task_id: Int32,
260
+ generation: Int32) -> Waker:
261
+ w = Waker()
262
+ w.awaker = handle
263
+ w.task_id = task_id
264
+ w.generation = generation
265
+ return w
266
+
267
+
268
+ class TimerEntry:
269
+ """One entry in the executor's timer min-heap. Ordered by deadline."""
270
+ deadline: float
271
+ waker: Waker
272
+
273
+ def __init__(self, deadline: float, waker: Waker) -> None:
274
+ self.deadline = deadline
275
+ self.waker = waker
276
+
277
+ def __lt__(self, other: 'TimerEntry') -> bool:
278
+ return self.deadline < other.deadline
279
+
280
+
281
+ @nocopy
282
+ class Slot:
283
+ """One entry in the executor's slot table.
284
+
285
+ Holds a `Box[AnyTask]` driving a spawned task (None once the task
286
+ completes). The generation counter advances when the slot
287
+ completes, invalidating any stale wakers that were handed out
288
+ before completion -- `Waker.wake()` (in `tpy.coro`) and the
289
+ runnable-drain loop in `Executor.drain_runnable` both check the
290
+ slot's generation and silently drop late wakes.
291
+
292
+ `runnable` mirrors the slot's presence in the executor's runnable
293
+ deque: set true when `mark_runnable` adds the slot's id to the
294
+ queue, cleared when the executor pops it to poll.
295
+ """
296
+
297
+ box: Box[AnyTask] | None
298
+ generation: Int32
299
+ runnable: bool
300
+
301
+ def __init__(self) -> None:
302
+ self.box = None
303
+ self.generation = 0
304
+ self.runnable = False
305
+
306
+ @readonly
307
+ def is_done(self) -> bool:
308
+ return self.box is None
309
+
310
+
311
+ @nocopy
312
+ class Executor(Awaker):
313
+ """v1 asyncio executor: runnable-queue + timer-heap driver.
314
+
315
+ Spawned tasks live in indexed slots; `Waker.wake()` marks a slot
316
+ runnable if the slot is still live and the generation matches.
317
+ Timers store the parked task's waker so a fired timer wakes only
318
+ the task that registered it.
319
+
320
+ Inherits `Awaker` so a `Ptr[Awaker]` stamped on each handed-out
321
+ Waker dispatches `mark_runnable` / `register_timer` back to this
322
+ instance through the @dynamic vtable. See `docs/ASYNC_PROGRESS.md`
323
+ for the v1.2 step 7 pivot history.
324
+ """
325
+
326
+ slots: list[Slot]
327
+ runnable_q: list[Int32]
328
+ timer_heap: list[TimerEntry]
329
+
330
+ def __init__(self) -> None:
331
+ # Backstop for `asyncio.run`'s nested-loop check: a non-null
332
+ # current_executor means a `_ExecutorScope` is already active.
333
+ # Bare `Executor()` in unit tests is unaffected because those
334
+ # tests never set the global.
335
+ if _get_current_executor() is not None:
336
+ raise RuntimeError(
337
+ "Executor: another executor is already running "
338
+ "(nested asyncio.run or leaked _ExecutorScope)")
339
+ self.slots = []
340
+ self.runnable_q = []
341
+ self.timer_heap = []
342
+
343
+ def register_timer(self, deadline_seconds: float, waker: Waker) -> None:
344
+ heapq.heappush(self.timer_heap, TimerEntry(deadline_seconds, waker))
345
+
346
+ # Mint a Waker stamped with the given slot identity. Used by
347
+ # `asyncio.create_task` to stash a wake-handle on the Task so its
348
+ # `cancel()` can mark the slot runnable promptly. Lives on Executor
349
+ # rather than as a free function so the call site can pass a
350
+ # method receiver instead of trying to coerce `Ptr[Executor]` to
351
+ # the `Awaker` protocol param of `_make_waker`.
352
+ def make_waker_for_slot(self, slot_id: Int32, generation: Int32) -> Waker:
353
+ return _make_waker(self, slot_id, generation)
354
+
355
+ def spawn(self, box: Own[Box[AnyTask]]) -> Int32:
356
+ new_id = len(self.slots)
357
+ slot = Slot()
358
+ slot.box = box
359
+ slot.runnable = True
360
+ self.slots.append(slot)
361
+ self.runnable_q.append(new_id)
362
+ return new_id
363
+
364
+ def mark_runnable(self, slot_id: Int32, generation: Int32) -> None:
365
+ if slot_id >= len(self.slots):
366
+ return
367
+ slot = self.slots[slot_id]
368
+ if slot.is_done() or slot.generation != generation or slot.runnable:
369
+ return
370
+ slot.runnable = True
371
+ self.runnable_q.append(slot_id)
372
+
373
+ def poll_slot(self, slot_id: Int32) -> bool:
374
+ if slot_id >= len(self.slots):
375
+ return False
376
+ if not self.slots[slot_id].runnable or self.slots[slot_id].is_done():
377
+ return False
378
+ self.slots[slot_id].runnable = False
379
+ gen = self.slots[slot_id].generation
380
+ waker = _make_waker(self, slot_id, gen)
381
+ # poll_any may recursively spawn new tasks which can reallocate
382
+ # the slots vector. Hold no Slot reference across the call --
383
+ # re-index after it returns. The AnyTask object lives on the
384
+ # heap and is stable; only the vector storage moves.
385
+ box = self.slots[slot_id].box
386
+ if box is None:
387
+ return False
388
+ if box.get().poll_any(waker):
389
+ self.slots[slot_id].box = None
390
+ self.slots[slot_id].generation += 1
391
+ return True
392
+
393
+ def drain_runnable(self) -> bool:
394
+ any_polled = False
395
+ # TODO(async-v1.2): `list.pop(0)` is O(n); draining N runnable tasks costs
396
+ # O(N^2). Swap `runnable_q` to `collections.deque[Int32]` and use
397
+ # `popleft()` once deque lands in TPy stdlib. See BUGS.md entry on
398
+ # runnable_q O(n) pop.
399
+ while len(self.runnable_q) > 0:
400
+ slot_id = self.runnable_q.pop(0)
401
+ if self.poll_slot(slot_id):
402
+ any_polled = True
403
+ return any_polled
404
+
405
+ @readonly
406
+ def slot_done(self, slot_id: Int32) -> bool:
407
+ if slot_id >= len(self.slots):
408
+ return False
409
+ return self.slots[slot_id].is_done()
410
+
411
+ @readonly
412
+ def has_live_tasks(self, skip_id: Int32) -> bool:
413
+ n = len(self.slots)
414
+ i: Int32 = 0
415
+ while i < n:
416
+ if i != skip_id and not self.slots[i].is_done():
417
+ return True
418
+ i += 1
419
+ return False
420
+
421
+ def wait_for_event(self) -> bool:
422
+ if len(self.timer_heap) == 0:
423
+ return False
424
+ sleep_until_steady(self.timer_heap[0].deadline)
425
+ now = monotonic()
426
+ while len(self.timer_heap) > 0 and self.timer_heap[0].deadline <= now:
427
+ entry = heapq.heappop(self.timer_heap)
428
+ entry.waker.wake()
429
+ return True
430
+
431
+ def run_until(self, main_id: Int32) -> None:
432
+ while True:
433
+ if self.slot_done(main_id):
434
+ return
435
+ if self.drain_runnable():
436
+ continue
437
+ if self.slot_done(main_id):
438
+ return
439
+ if not self.wait_for_event():
440
+ raise RuntimeError(
441
+ "asyncio.run: no progress possible (coroutine "
442
+ "returned Pending with no pending timers; v1 has "
443
+ "no I/O reactor)")
444
+
445
+ def drain_spawned_with_cancel(self, skip_id: Int32,
446
+ max_polls: Int32 = 8) -> None:
447
+ n = len(self.slots)
448
+ i: Int32 = 0
449
+ while i < n:
450
+ if i != skip_id and not self.slots[i].is_done():
451
+ box = self.slots[i].box
452
+ if box is not None:
453
+ box.get().cancel_any()
454
+ i += 1
455
+ attempt: Int32 = 0
456
+ while attempt < max_polls and self.has_live_tasks(skip_id):
457
+ j: Int32 = 0
458
+ n2 = len(self.slots)
459
+ while j < n2:
460
+ if j != skip_id and not self.slots[j].is_done():
461
+ self.mark_runnable(j, self.slots[j].generation)
462
+ j += 1
463
+ if not self.drain_runnable():
464
+ break
465
+ attempt += 1
466
+
467
+
468
+ # --- Current-executor global + helpers ---------------------------------
469
+ # Defined after `Executor` so signatures can spell the concrete
470
+ # `Ptr[Executor]` without a forward-reference string. Plain (non-
471
+ # thread-local) global; v1 asyncio is single-executor per process.
472
+
473
+
474
+ _current_executor: Ptr[Executor] = None
475
+
476
+
477
+ def _get_current_executor() -> Ptr[Executor]:
478
+ return _current_executor
479
+
480
+
481
+ def _set_current_executor(handle: Ptr[Executor]) -> None:
482
+ global _current_executor
483
+ _current_executor = handle
484
+
485
+
486
+ def _clear_current_executor() -> None:
487
+ global _current_executor
488
+ _current_executor = None
489
+
490
+
491
+ # Test-only Box[AnyTask] factory: builds a TaskState[T] without
492
+ # executor registration so tests can drive the executor directly.
493
+ def _make_any_task_for_test[T](coro: Own[Cancellable[T]]) -> Own[Box[AnyTask]]:
494
+ task = make_executor_owned_task[T](coro)
495
+ return task_to_any_box[T](task)
496
+
497
+
498
+ @nocopy
499
+ class _ExecutorScope:
500
+ """RAII guard for the `_current_executor` module global. Stores
501
+ the executor pointer on construction; clears it on `__del__`.
502
+
503
+ Wakers stamped against this executor that fire after teardown still
504
+ hold a (now-stale) `Ptr[Awaker]` -- that's a use-after-free at the
505
+ raw-pointer level. v1 asyncio.run drains all spawned tasks during
506
+ teardown to make this case unreachable in practice; multi-threaded
507
+ async (v3+) would need a per-Waker generation guard or a refcounted
508
+ Awaker handle.
509
+ """
510
+
511
+ def __init__(self, executor: Executor) -> None:
512
+ _set_current_executor(executor)
513
+
514
+ def __del__(self) -> None:
515
+ _clear_current_executor()