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_compiler.py ADDED
@@ -0,0 +1,559 @@
1
+ """Tests for compiler and build layout."""
2
+
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+
7
+ from . import get_lib_dir, get_runtime_dir
8
+ from .compiler import Compiler, BuildLayout
9
+ from .compilation_context import activate_compiler
10
+ from .diagnostics import SemanticError
11
+ from .typesys import (
12
+ INT32, INT64, BIGINT, BOOL, FLOAT, STR, STRVIEW, CHAR, VOID,
13
+ PtrType, make_span, make_list, make_dict, make_array, OptionalType,
14
+ TupleType, UnionType, OwnType, ReadonlyType, NominalType,
15
+ )
16
+
17
+ # Stdlib path needed for from_source when code uses primitive type methods
18
+ _STDLIB_DIRS = [get_lib_dir() / "tpy"]
19
+
20
+
21
+ class TestCompilerFromSource:
22
+ def test_simple_program(self):
23
+ source = 'print("hello")'
24
+ compiler = Compiler.from_source(source)
25
+ modules = compiler.compile()
26
+ assert len(modules) == 1
27
+ assert modules[0].name == "main"
28
+ assert modules[0].is_entry_point
29
+
30
+ def test_custom_module_name(self):
31
+ source = 'x: int = 1\nprint(x)'
32
+ compiler = Compiler.from_source(source, module_name="test_mod")
33
+ modules = compiler.compile()
34
+ assert modules[0].name == "test_mod"
35
+
36
+ def test_matches_file_compilation(self, tmp_path):
37
+ """Verify that from_source and file-based compilation produce the same AST structure."""
38
+ source = 'def add(a: int, b: int) -> int:\n return a + b\nprint(add(1, 2))'
39
+ src_file = tmp_path / "check.py"
40
+ src_file.write_text(source)
41
+
42
+ file_compiler = Compiler(src_file, lib_dirs=_STDLIB_DIRS)
43
+ file_modules = file_compiler.compile()
44
+
45
+ source_compiler = Compiler.from_source(source, lib_dirs=_STDLIB_DIRS)
46
+ source_modules = source_compiler.compile()
47
+
48
+ assert len(file_modules) == len(source_modules)
49
+ file_ast = file_modules[0].ast
50
+ source_ast = source_modules[0].ast
51
+ assert len(file_ast.functions) == len(source_ast.functions)
52
+ assert len(file_ast.top_level_stmts) == len(source_ast.top_level_stmts)
53
+
54
+ @pytest.mark.parametrize(
55
+ ("default_int", "expected"),
56
+ [
57
+ ("Int32", INT32),
58
+ ("Int64", INT64),
59
+ ("BigInt", BIGINT),
60
+ ],
61
+ )
62
+ def test_default_int_setting_controls_unannotated_literals(self, default_int, expected):
63
+ source = "x = 1\n"
64
+ compiler = Compiler.from_source(source, default_int=default_int)
65
+ modules = compiler.compile()
66
+ hpp, _ = compiler.generate_code_to_strings(modules[0])
67
+ expected_cpp = expected.to_cpp()
68
+ assert f"extern {expected_cpp} x;" in hpp
69
+
70
+ def test_reassignment_from_bigint_widens_default_int(self):
71
+ source = "x = 0\nx = int(5)\n"
72
+ compiler = Compiler.from_source(source, default_int="Int32", lib_dirs=_STDLIB_DIRS)
73
+ modules = compiler.compile()
74
+ entry = [m for m in modules if m.is_entry_point][0]
75
+ hpp, _ = compiler.generate_code_to_strings(entry)
76
+ assert "extern ::tpy::BigInt x;" in hpp
77
+
78
+ def test_invalid_default_int_setting_rejected(self):
79
+ with pytest.raises(ValueError, match="Unsupported default int type"):
80
+ Compiler.from_source("x = 1\n", default_int="Int128")
81
+
82
+ def test_native_module_propagation(self):
83
+ """builtins._list inherits native_module from builtins/__init__."""
84
+ lib_dir = get_lib_dir() / "tpy"
85
+ compiler = Compiler.from_source("x = [1]\n", lib_dirs=[lib_dir])
86
+ compiler.compile()
87
+ mod = compiler.modules.get("builtins._list")
88
+ if mod is not None:
89
+ assert mod.ast.directives.native_module
90
+ _, cpp = compiler.generate_code_to_strings(mod)
91
+ assert cpp == ""
92
+
93
+
94
+
95
+ class TestCodegenRegression:
96
+ def test_generic_ctor_invalid_arg_rejected(self, tmp_path):
97
+ """Invalid generic constructor arg (Int32 for Span[T] param) must be rejected by sema."""
98
+ source = (
99
+ 'from tpy import Span, Int32\n'
100
+ 'x: Span[Int32] = Span[Int32](Int32(1))\n'
101
+ )
102
+ src_file = tmp_path / "test.py"
103
+ src_file.write_text(source)
104
+ compiler = Compiler(src_file, lib_dirs=[get_lib_dir() / "tpy"])
105
+ with pytest.raises(SemanticError, match="cannot be constructed from"):
106
+ compiler.compile()
107
+
108
+
109
+ class TestSendSync:
110
+ """Test Send/Sync auto-derivation on built-in types."""
111
+
112
+ # -- Primitive value types: all Send + Sync --
113
+
114
+ @pytest.mark.parametrize("typ", [INT32, INT64, BIGINT, BOOL, FLOAT, STR, CHAR])
115
+ def test_primitives_are_send_and_sync(self, typ):
116
+ assert typ.is_send()
117
+ assert typ.is_sync()
118
+
119
+ # -- StrView: borrows, not Send, but Sync (read-only) --
120
+
121
+ def test_strview_not_send(self):
122
+ assert not STRVIEW.is_send()
123
+
124
+ def test_strview_is_sync(self):
125
+ assert STRVIEW.is_sync()
126
+
127
+ # -- Ptr: not Send; Sync only if readonly --
128
+
129
+ def test_ptr_not_send(self):
130
+ assert not PtrType(INT32).is_send()
131
+ assert not PtrType(INT32, is_readonly=True).is_send()
132
+
133
+ def test_mutable_ptr_not_sync(self):
134
+ assert not PtrType(INT32).is_sync()
135
+
136
+ def test_readonly_ptr_sync_if_pointee_sync(self):
137
+ assert PtrType(INT32, is_readonly=True).is_sync()
138
+ # Ptr[readonly[list[T]]]: list is not Sync
139
+ assert not PtrType(make_list(INT32), is_readonly=True).is_sync()
140
+
141
+ # -- Span: not Send; Sync only if readonly --
142
+
143
+ def test_span_not_send(self):
144
+ assert not make_span(INT32).is_send()
145
+ assert not make_span(INT32, is_readonly=True).is_send()
146
+
147
+ def test_mutable_span_not_sync(self):
148
+ assert not make_span(INT32).is_sync()
149
+
150
+ def test_readonly_span_sync_if_element_sync(self):
151
+ assert make_span(INT32, is_readonly=True).is_sync()
152
+
153
+ # -- list: Send if element Send, never Sync --
154
+
155
+ def test_list_send_if_element_send(self):
156
+ assert make_list(INT32).is_send()
157
+ assert not make_list(PtrType(INT32)).is_send()
158
+
159
+ def test_list_not_sync(self):
160
+ assert not make_list(INT32).is_sync()
161
+
162
+ # -- dict: Send if elements Send, never Sync --
163
+
164
+ def test_dict_send_if_elements_send(self):
165
+ assert make_dict(STR, INT32).is_send()
166
+ assert not make_dict(STR, PtrType(INT32)).is_send()
167
+
168
+ def test_dict_not_sync(self):
169
+ assert not make_dict(STR, INT32).is_sync()
170
+
171
+ # -- Array: Send/Sync based on element --
172
+
173
+ def test_array_send_sync_based_on_element(self):
174
+ assert make_array(INT32, 10).is_send()
175
+ assert make_array(INT32, 10).is_sync()
176
+ assert not make_array(PtrType(INT32), 10).is_send()
177
+
178
+ # -- Tuple: Send/Sync if all elements are --
179
+
180
+ def test_tuple_send_sync(self):
181
+ assert TupleType((INT32, STR)).is_send()
182
+ assert TupleType((INT32, STR)).is_sync()
183
+ assert not TupleType((INT32, PtrType(STR))).is_send()
184
+
185
+ # -- Optional: delegates to inner --
186
+
187
+ def test_optional_delegates(self):
188
+ assert OptionalType(INT32).is_send()
189
+ # OptionalType inner = NominalType (non-Send record) -- delegates through.
190
+ # We can't use OptionalType(PtrType(...)) here because the __new__ collapse
191
+ # would return a bare PtrType (Ptr[T] is already nullable), so the test
192
+ # would exercise PtrType, not OptionalType's delegation.
193
+ record = NominalType("R", (), _module_qname="__main__.R")
194
+ assert not OptionalType(record).is_send()
195
+
196
+ # -- Union: all members --
197
+
198
+ def test_union_all_members(self):
199
+ assert UnionType((INT32, STR)).is_send()
200
+ assert not UnionType((INT32, PtrType(STR))).is_send()
201
+
202
+ # -- Own: delegates to wrapped --
203
+
204
+ def test_own_delegates(self):
205
+ assert OwnType(make_list(INT32)).is_send()
206
+ assert not OwnType(make_list(INT32)).is_sync()
207
+
208
+ # -- readonly: makes mutable containers Sync --
209
+
210
+ def test_readonly_makes_sync(self):
211
+ assert not make_list(INT32).is_sync()
212
+ assert ReadonlyType(make_list(INT32)).is_sync()
213
+
214
+ def test_readonly_of_readonly_ptr_is_sync(self):
215
+ rop = PtrType(INT32, is_readonly=True)
216
+ assert not rop.is_send()
217
+ assert rop.is_sync()
218
+ assert ReadonlyType(rop).is_sync()
219
+
220
+ def test_readonly_of_non_send_not_sync(self):
221
+ # readonly[list[Ptr[T]]]: Ptr not Send, so list not Send, not Sync
222
+ assert not ReadonlyType(make_list(PtrType(INT32))).is_sync()
223
+
224
+
225
+ class TestSendSyncRecordDerivation:
226
+ """Test Send/Sync auto-derivation on user-defined records."""
227
+
228
+ def test_record_with_value_fields_is_send_sync(self):
229
+ source = (
230
+ "from tpy import Int32\n"
231
+ "class Point:\n"
232
+ " x: Int32\n"
233
+ " y: Int32\n"
234
+ " def __init__(self, x: Int32, y: Int32) -> None:\n"
235
+ " self.x = x\n"
236
+ " self.y = y\n"
237
+ "def main() -> None:\n"
238
+ " p = Point(Int32(1), Int32(2))\n"
239
+ " print(p.x)\n"
240
+ "main()\n"
241
+ )
242
+ compiler = Compiler.from_source(source, lib_dirs=_STDLIB_DIRS)
243
+ compiler.compile()
244
+ point_type = NominalType("Point", (), _module_qname="__main__.Point")
245
+ with activate_compiler(compiler):
246
+ assert point_type.is_send()
247
+ assert point_type.is_sync()
248
+
249
+ def test_record_with_ptr_field_not_send(self, tmp_path):
250
+ source = (
251
+ "from tpy import Ptr, Int32, take_ptr\n"
252
+ "class Wrapper:\n"
253
+ " x: Int32\n"
254
+ " def __init__(self, x: Int32) -> None:\n"
255
+ " self.x = x\n"
256
+ "class Holder:\n"
257
+ " p: Ptr[Wrapper]\n"
258
+ " def __init__(self, p: Ptr[Wrapper]) -> None:\n"
259
+ " self.p = p\n"
260
+ "def main() -> None:\n"
261
+ " w = Wrapper(Int32(1))\n"
262
+ " h = Holder(take_ptr(w))\n"
263
+ " print(h.p.x)\n"
264
+ "main()\n"
265
+ )
266
+ src_file = tmp_path / "test.py"
267
+ src_file.write_text(source)
268
+ compiler = Compiler(src_file, lib_dirs=[get_lib_dir() / "tpy"])
269
+ compiler.compile()
270
+ holder_type = NominalType("Holder", (), _module_qname="__main__.Holder")
271
+ with activate_compiler(compiler):
272
+ assert not holder_type.is_send()
273
+ assert not holder_type.is_sync()
274
+
275
+ def test_record_with_list_field_send_not_sync(self):
276
+ source = (
277
+ "from tpy import Int32\n"
278
+ "class Container:\n"
279
+ " items: list[Int32]\n"
280
+ " def __init__(self) -> None:\n"
281
+ " self.items = [Int32(1)]\n"
282
+ "def main() -> None:\n"
283
+ " c = Container()\n"
284
+ " print(len(c.items))\n"
285
+ "main()\n"
286
+ )
287
+ from . import get_lib_dir
288
+ lib_dirs = [get_lib_dir() / "tpy"]
289
+ compiler = Compiler.from_source(source, lib_dirs=lib_dirs)
290
+ compiler.compile()
291
+ container_type = NominalType("Container", (), _module_qname="__main__.Container")
292
+ with activate_compiler(compiler):
293
+ assert container_type.is_send()
294
+ assert not container_type.is_sync()
295
+
296
+
297
+ class TestBuildLayout:
298
+ def setup_method(self):
299
+ self.layout = BuildLayout(Path("/out"), "main")
300
+
301
+ def test_simple_module_hpp(self):
302
+ assert self.layout.hpp_path("main") == Path("/out/main.d/include/main.hpp")
303
+
304
+ def test_simple_module_cpp(self):
305
+ assert self.layout.cpp_path("main") == Path("/out/main.d/src/main.cpp")
306
+
307
+ def test_dotted_module_hpp(self):
308
+ assert self.layout.hpp_path("pkg.mod") == Path("/out/main.d/include/pkg/mod.hpp")
309
+
310
+ def test_dotted_module_cpp(self):
311
+ assert self.layout.cpp_path("pkg.mod") == Path("/out/main.d/src/pkg/mod.cpp")
312
+
313
+ def test_deeply_nested_hpp(self):
314
+ assert self.layout.hpp_path("a.b.c.d") == Path("/out/main.d/include/a/b/c/d.hpp")
315
+
316
+ def test_deeply_nested_cpp(self):
317
+ assert self.layout.cpp_path("a.b.c.d") == Path("/out/main.d/src/a/b/c/d.cpp")
318
+
319
+ def test_binary_path(self):
320
+ assert self.layout.binary_path() == Path("/out/main.d/main")
321
+
322
+ def test_binary_path_with_variant(self):
323
+ layout = BuildLayout(Path("/out"), "main", build_variant="debug")
324
+ assert layout.binary_path() == Path("/out/main.d/debug/main")
325
+
326
+ def test_binary_path_release_variant(self):
327
+ layout = BuildLayout(Path("/out"), "main", build_variant="release")
328
+ assert layout.binary_path() == Path("/out/main.d/release/main")
329
+
330
+ def test_build_dir_no_variant(self):
331
+ assert self.layout.build_dir == Path("/out/main.d")
332
+
333
+ def test_build_dir_with_variant(self):
334
+ layout = BuildLayout(Path("/out"), "main", build_variant="debug")
335
+ assert layout.build_dir == Path("/out/main.d/debug")
336
+
337
+
338
+ class TestGenerateCmake:
339
+ """Tests for sources.cmake generation and runtime bundling."""
340
+
341
+ def _make_layout(self, tmp_path: Path) -> BuildLayout:
342
+ layout = BuildLayout(tmp_path, "app")
343
+ layout.include_dir.mkdir(parents=True)
344
+ layout.src_dir.mkdir(parents=True)
345
+ return layout
346
+
347
+ def _dummy_cpp(self, layout: BuildLayout) -> list[Path]:
348
+ cpp = layout.src_dir / "app.cpp"
349
+ cpp.write_text("// generated")
350
+ return [cpp]
351
+
352
+ def test_bundle_runtime_copies_headers(self, tmp_path: Path):
353
+ layout = self._make_layout(tmp_path)
354
+ runtime_inc = get_runtime_dir() / "cpp" / "include"
355
+ layout.generate_cmake(
356
+ runtime_include_dir=runtime_inc,
357
+ cpp_files=self._dummy_cpp(layout),
358
+ bundle_runtime=True,
359
+ )
360
+ bundled = layout.root_dir / "runtime" / "include" / "tpy"
361
+ assert bundled.is_dir()
362
+ assert (bundled / "tpy.hpp").is_file()
363
+
364
+ def test_bundle_runtime_cmake_uses_local_path(self, tmp_path: Path):
365
+ layout = self._make_layout(tmp_path)
366
+ runtime_inc = get_runtime_dir() / "cpp" / "include"
367
+ cmake_path = layout.generate_cmake(
368
+ runtime_include_dir=runtime_inc,
369
+ cpp_files=self._dummy_cpp(layout),
370
+ bundle_runtime=True,
371
+ )
372
+ content = cmake_path.read_text()
373
+ assert "${CMAKE_CURRENT_LIST_DIR}/runtime/include" in content
374
+ # No absolute or parent-traversal paths to the runtime
375
+ assert "../../" not in content.split("TPYC_INCLUDE_DIRS")[1].split(")")[0]
376
+
377
+ def test_no_bundle_runtime_uses_relative_path(self, tmp_path: Path):
378
+ layout = self._make_layout(tmp_path)
379
+ runtime_inc = get_runtime_dir() / "cpp" / "include"
380
+ cmake_path = layout.generate_cmake(
381
+ runtime_include_dir=runtime_inc,
382
+ cpp_files=self._dummy_cpp(layout),
383
+ bundle_runtime=False,
384
+ )
385
+ content = cmake_path.read_text()
386
+ bundled = layout.root_dir / "runtime" / "include"
387
+ assert not bundled.exists()
388
+ assert "runtime/include" not in content
389
+ # Should reference the runtime via a relative or absolute path
390
+ lines = content.splitlines()
391
+ inc_lines = []
392
+ in_inc = False
393
+ for line in lines:
394
+ if line.startswith("set(TPYC_INCLUDE_DIRS"):
395
+ in_inc = True
396
+ continue
397
+ if in_inc:
398
+ if line.strip() == ")":
399
+ break
400
+ inc_lines.append(line.strip())
401
+ assert len(inc_lines) == 2
402
+ assert "../" in inc_lines[1] or str(runtime_inc) in inc_lines[1]
403
+
404
+ def test_bundle_runtime_idempotent(self, tmp_path: Path):
405
+ """Repeated calls with bundle_runtime=True succeed."""
406
+ layout = self._make_layout(tmp_path)
407
+ runtime_inc = get_runtime_dir() / "cpp" / "include"
408
+ cpp_files = self._dummy_cpp(layout)
409
+ layout.generate_cmake(
410
+ runtime_include_dir=runtime_inc,
411
+ cpp_files=cpp_files,
412
+ bundle_runtime=True,
413
+ )
414
+ cmake_path = layout.generate_cmake(
415
+ runtime_include_dir=runtime_inc,
416
+ cpp_files=cpp_files,
417
+ bundle_runtime=True,
418
+ )
419
+ content = cmake_path.read_text()
420
+ assert "${CMAKE_CURRENT_LIST_DIR}/runtime/include" in content
421
+ assert (layout.root_dir / "runtime" / "include" / "tpy" / "tpy.hpp").is_file()
422
+
423
+
424
+ def _make_skeleton_module(records=(), protocols=(), functions=(), enums=()):
425
+ """Build a minimal CompiledModule with given exports populated
426
+ and a matching `_skeleton_ids` snapshot, as if pre-populate had
427
+ just run on it. No sema needed -- the verifier only consults the
428
+ snapshot and the exports.
429
+ """
430
+ from .compiler import CompiledModule, ModuleExports, _SkeletonSnapshot
431
+ from .parse import TpyModule
432
+ from .parse.nodes import ModuleDirectives
433
+
434
+ ast = TpyModule(
435
+ records=[], functions=[], protocols=[], enums=[],
436
+ top_level_stmts=[], source_lines=[], imports={},
437
+ tpy_star_import=False, star_imports=set(), user_module_imports={},
438
+ module_aliases={}, bare_module_imports=set(), type_aliases={},
439
+ directives=ModuleDirectives(),
440
+ )
441
+ exports = ModuleExports()
442
+ for r in records:
443
+ exports.records[r.name] = r
444
+ for p in protocols:
445
+ exports.protocols[p.name] = p
446
+ for name, fi_list in functions:
447
+ exports.functions[name] = list(fi_list)
448
+ for name, nominal in enums:
449
+ exports.enums[name] = nominal
450
+
451
+ snap = _SkeletonSnapshot(
452
+ records={n: id(o) for n, o in exports.records.items()},
453
+ protocols={n: id(o) for n, o in exports.protocols.items()},
454
+ functions={n: (id(lst), id(lst[0])) if lst else (0, 0)
455
+ for n, lst in exports.functions.items()},
456
+ )
457
+ return CompiledModule(
458
+ name="m", path=Path("<test>"), ast=ast, exports=exports,
459
+ is_entry_point=True, _skeleton_ids=snap,
460
+ )
461
+
462
+
463
+ class TestSkeletonAdoptionAssertion:
464
+ """Pins the `_verify_skeleton_adoption` invariant: every
465
+ pre-populated skeleton object/list must be adopted in place by
466
+ its registration entrypoint, so peer registries that captured a
467
+ reference at bind_imports time see freshly-finalized data.
468
+
469
+ Five of these tests use `_make_skeleton_module` to hand-build a
470
+ minimal CompiledModule + matching snapshot and exercise the
471
+ verifier directly, with no sema involved. The first test does a
472
+ full real compile to confirm the production path passes the
473
+ assertion in normal use (no false positives).
474
+ """
475
+
476
+ def test_correctly_adopted_real_compile(self):
477
+ """A normal compile passes the assertion (smoke-test against
478
+ false positives in the production pipeline)."""
479
+ source = (
480
+ "class A:\n"
481
+ " val: int\n"
482
+ " def __init__(self, v: int) -> None:\n"
483
+ " self.val = v\n"
484
+ "def helper() -> int:\n"
485
+ " return 42\n"
486
+ )
487
+ Compiler.from_source(source).compile() # raises if violated
488
+
489
+ def test_record_identity_mismatch_fires(self):
490
+ from .typesys import RecordInfo
491
+ rec = RecordInfo(name="A", fields=[], module="m", defining_module="m")
492
+ compiled = _make_skeleton_module(records=[rec])
493
+ compiled.exports.records["A"] = RecordInfo(
494
+ name="A", fields=[], module="m", defining_module="m",
495
+ )
496
+ with pytest.raises(AssertionError, match=r"record 'A'"):
497
+ Compiler._verify_skeleton_adoption(compiled)
498
+
499
+ def test_protocol_identity_mismatch_fires(self):
500
+ from .typesys import ProtocolInfo
501
+ proto = ProtocolInfo(name="P", methods=[], type_params=[],
502
+ module="m", is_dynamic=False)
503
+ compiled = _make_skeleton_module(protocols=[proto])
504
+ compiled.exports.protocols["P"] = ProtocolInfo(
505
+ name="P", methods=[], type_params=[],
506
+ module="m", is_dynamic=False,
507
+ )
508
+ with pytest.raises(AssertionError, match=r"protocol 'P'"):
509
+ Compiler._verify_skeleton_adoption(compiled)
510
+
511
+ def test_function_with_neither_list_nor_fi_identity_fires(self):
512
+ from .typesys import FunctionInfo, VOID
513
+ original = FunctionInfo(name="f", params=[], return_type=VOID,
514
+ qualified_name="m.f", originating_module="m")
515
+ compiled = _make_skeleton_module(functions=[("f", [original])])
516
+ compiled.exports.functions["f"] = [
517
+ FunctionInfo(name="f", params=[], return_type=VOID,
518
+ qualified_name="m.f", originating_module="m"),
519
+ ]
520
+ with pytest.raises(AssertionError, match=r"function 'f'"):
521
+ Compiler._verify_skeleton_adoption(compiled)
522
+
523
+ def test_function_inner_fi_preserved_passes(self):
524
+ # register_function adoption shape: fresh list, skeleton FI inside.
525
+ from .typesys import FunctionInfo, VOID
526
+ original = FunctionInfo(name="f", params=[], return_type=VOID,
527
+ qualified_name="m.f", originating_module="m")
528
+ compiled = _make_skeleton_module(functions=[("f", [original])])
529
+ compiled.exports.functions["f"] = [original]
530
+ Compiler._verify_skeleton_adoption(compiled)
531
+
532
+ def test_function_list_mutated_in_place_passes(self):
533
+ # register_overload_group adoption shape: skeleton list cleared
534
+ # and re-extended with fresh FIs; list identity preserved even
535
+ # though the inner FI identity is gone.
536
+ from .typesys import FunctionInfo, VOID
537
+ original = FunctionInfo(name="g", params=[], return_type=VOID,
538
+ qualified_name="m.g", originating_module="m")
539
+ compiled = _make_skeleton_module(functions=[("g", [original])])
540
+ skeleton_list = compiled.exports.functions["g"]
541
+ skeleton_list.clear()
542
+ skeleton_list.extend([
543
+ FunctionInfo(name="g", params=[], return_type=VOID,
544
+ qualified_name="m.g", originating_module="m"),
545
+ FunctionInfo(name="g", params=[], return_type=VOID,
546
+ qualified_name="m.g", originating_module="m"),
547
+ ])
548
+ Compiler._verify_skeleton_adoption(compiled)
549
+
550
+ def test_enum_not_checked(self):
551
+ from .typesys import NominalType
552
+ compiled = _make_skeleton_module(
553
+ enums=[("Color", NominalType(name="Color", type_args=(),
554
+ _module_qname="m.Color"))],
555
+ )
556
+ compiled.exports.enums["Color"] = NominalType(
557
+ name="Color", type_args=(), _module_qname="m.Color",
558
+ )
559
+ Compiler._verify_skeleton_adoption(compiled)
@@ -0,0 +1,101 @@
1
+ """Unit tests for typesys.contains_type_param.
2
+
3
+ Canonical "does this type tree mention a type parameter" predicate used
4
+ at sema gates (overload resolution, protocol arg matching, value-type
5
+ field validation, generic method registration). Supports an optional
6
+ `names` filter.
7
+ """
8
+
9
+ from .typesys import (
10
+ INT32, NominalType, OptionalType, PtrType, TupleType, TypeParamKind,
11
+ TypeParamRef, UnionType, contains_type_param, make_list,
12
+ )
13
+
14
+
15
+ class TestUnfiltered:
16
+ """`names=None` -- any TypeParamRef counts."""
17
+
18
+ def test_bare_type_param(self) -> None:
19
+ assert contains_type_param(TypeParamRef("T")) is True
20
+
21
+ def test_concrete_type(self) -> None:
22
+ assert contains_type_param(INT32) is False
23
+
24
+ def test_nested_in_optional(self) -> None:
25
+ assert contains_type_param(OptionalType(TypeParamRef("T"))) is True
26
+
27
+ def test_nested_in_list(self) -> None:
28
+ assert contains_type_param(make_list(element_type=TypeParamRef("T"))) is True
29
+
30
+ def test_nested_in_tuple(self) -> None:
31
+ assert contains_type_param(TupleType((INT32, TypeParamRef("T")))) is True
32
+
33
+ def test_nested_in_union(self) -> None:
34
+ assert contains_type_param(UnionType((INT32, TypeParamRef("T")))) is True
35
+
36
+
37
+ class TestNamesFilter:
38
+ """`names={"T"}` -- only TypeParamRefs whose name is in the set count."""
39
+
40
+ def test_match_hit(self) -> None:
41
+ assert contains_type_param(TypeParamRef("T"), names={"T"}) is True
42
+
43
+ def test_match_miss(self) -> None:
44
+ assert contains_type_param(TypeParamRef("U"), names={"T"}) is False
45
+
46
+ def test_nested_match_hit(self) -> None:
47
+ assert contains_type_param(
48
+ OptionalType(TypeParamRef("T")), names={"T"},
49
+ ) is True
50
+
51
+ def test_nested_match_miss(self) -> None:
52
+ assert contains_type_param(
53
+ OptionalType(TypeParamRef("U")), names={"T"},
54
+ ) is False
55
+
56
+ def test_one_of_many(self) -> None:
57
+ # Type tree contains both T and U; filter on {"T"} matches via T.
58
+ assert contains_type_param(
59
+ TupleType((TypeParamRef("U"), TypeParamRef("T"))),
60
+ names={"T"},
61
+ ) is True
62
+
63
+
64
+ class TestIntKindHandling:
65
+ """INT-kind TypeParamRefs (e.g. `N` in `Array[T, N: int]`) live in
66
+ `NominalType.type_args` but `inner_types()` filters them out for
67
+ substitution traversals. `contains_type_param` walks `type_args`
68
+ directly so INT-kind refs still count."""
69
+
70
+ def test_bare_int_kind_param(self) -> None:
71
+ n = TypeParamRef("N", kind=TypeParamKind.INT)
72
+ assert contains_type_param(n) is True
73
+
74
+ def test_int_kind_inside_nominal(self) -> None:
75
+ n = TypeParamRef("N", kind=TypeParamKind.INT)
76
+ # NominalType wrapping an INT-kind param. inner_types() would
77
+ # filter N out; type_args walk catches it.
78
+ wrapper = NominalType("SomeArr", type_args=(INT32, n))
79
+ assert contains_type_param(wrapper) is True
80
+
81
+ def test_int_kind_with_names_filter(self) -> None:
82
+ n = TypeParamRef("N", kind=TypeParamKind.INT)
83
+ wrapper = NominalType("SomeArr", type_args=(INT32, n))
84
+ assert contains_type_param(wrapper, names={"N"}) is True
85
+ assert contains_type_param(wrapper, names={"T"}) is False
86
+
87
+
88
+ class TestCompositeWrappers:
89
+ """Multi-level wrapper chains."""
90
+
91
+ def test_optional_of_list_of_param(self) -> None:
92
+ t = OptionalType(make_list(element_type=TypeParamRef("T")))
93
+ assert contains_type_param(t) is True
94
+
95
+ def test_ptr_of_optional_of_param(self) -> None:
96
+ t = PtrType(OptionalType(TypeParamRef("T")))
97
+ assert contains_type_param(t) is True
98
+
99
+ def test_deep_concrete(self) -> None:
100
+ t = PtrType(OptionalType(make_list(element_type=INT32)))
101
+ assert contains_type_param(t) is False