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.
- tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
- tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
- tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
- tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
- tpyc/__init__.py +104 -0
- tpyc/__main__.py +6 -0
- tpyc/_buildinfo.py +1 -0
- tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
- tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
- tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
- tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
- tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
- tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
- tpyc/_data/lib/tpy/_functools_macros.py +80 -0
- tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
- tpyc/_data/lib/tpy/argparse.py +2062 -0
- tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
- tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
- tpyc/_data/lib/tpy/base64.py +410 -0
- tpyc/_data/lib/tpy/bisect.py +39 -0
- tpyc/_data/lib/tpy/builtins.py +38 -0
- tpyc/_data/lib/tpy/dataclasses.py +354 -0
- tpyc/_data/lib/tpy/enum.py +23 -0
- tpyc/_data/lib/tpy/functools.py +33 -0
- tpyc/_data/lib/tpy/hashlib.py +206 -0
- tpyc/_data/lib/tpy/heapq.py +118 -0
- tpyc/_data/lib/tpy/io.py +395 -0
- tpyc/_data/lib/tpy/json.py +221 -0
- tpyc/_data/lib/tpy/math.py +406 -0
- tpyc/_data/lib/tpy/random.py +597 -0
- tpyc/_data/lib/tpy/re.py +467 -0
- tpyc/_data/lib/tpy/socket.py +379 -0
- tpyc/_data/lib/tpy/struct.py +178 -0
- tpyc/_data/lib/tpy/sys.py +40 -0
- tpyc/_data/lib/tpy/time.py +39 -0
- tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
- tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
- tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
- tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
- tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
- tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
- tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
- tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
- tpyc/_data/lib/tpy/tpy/_version.py +29 -0
- tpyc/_data/lib/tpy/tpy/bits.py +28 -0
- tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
- tpyc/_data/lib/tpy/tpy/extern.py +8 -0
- tpyc/_data/lib/tpy/tpy/mem.py +49 -0
- tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
- tpyc/_data/lib/tpy/tpy/version.py +21 -0
- tpyc/_data/lib/tpy/typing.py +13 -0
- tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
- tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
- tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
- tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
- tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
- tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
- tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
- tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
- tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
- tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
- tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
- tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
- tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
- tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
- tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
- tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
- tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
- tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
- tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
- tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
- tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
- tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
- tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
- tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
- tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
- tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
- tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
- tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
- tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
- tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
- tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
- tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
- tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
- tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
- tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
- tpyc/_data/runtime/cpp/third_party/README.md +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
- tpyc/build/__init__.py +7 -0
- tpyc/build/pcre2.py +122 -0
- tpyc/build/third_party.py +413 -0
- tpyc/cli.py +822 -0
- tpyc/codegen_cpp/__init__.py +18 -0
- tpyc/codegen_cpp/builtins.py +484 -0
- tpyc/codegen_cpp/context.py +2064 -0
- tpyc/codegen_cpp/expressions.py +5940 -0
- tpyc/codegen_cpp/functions.py +1913 -0
- tpyc/codegen_cpp/gen_async.py +3258 -0
- tpyc/codegen_cpp/gen_generators.py +657 -0
- tpyc/codegen_cpp/generator.py +2258 -0
- tpyc/codegen_cpp/match.py +1997 -0
- tpyc/codegen_cpp/param_const.py +172 -0
- tpyc/codegen_cpp/protocols.py +907 -0
- tpyc/codegen_cpp/records.py +1654 -0
- tpyc/codegen_cpp/resumable_cfg.py +1651 -0
- tpyc/codegen_cpp/statements.py +4963 -0
- tpyc/codegen_cpp/string_dispatch.py +76 -0
- tpyc/codegen_cpp/test_context.py +46 -0
- tpyc/codegen_cpp/test_param_const.py +113 -0
- tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
- tpyc/codegen_cpp/type_resolution.py +53 -0
- tpyc/codegen_cpp/types.py +436 -0
- tpyc/codegen_cpp/variant_access.py +135 -0
- tpyc/coercions.py +749 -0
- tpyc/compilation_context.py +57 -0
- tpyc/compiler.py +3945 -0
- tpyc/cycle_detection.py +358 -0
- tpyc/diagnostics.py +135 -0
- tpyc/dump_types.py +353 -0
- tpyc/frontend_diagnostics.py +47 -0
- tpyc/frontend_ir/__init__.py +140 -0
- tpyc/frontend_ir/lower.py +1098 -0
- tpyc/frontend_ir/nodes.py +718 -0
- tpyc/frontend_ir/resolver_adapter.py +151 -0
- tpyc/frontend_plugin.py +209 -0
- tpyc/install_docs.py +81 -0
- tpyc/liveness.py +756 -0
- tpyc/macro_api.py +1724 -0
- tpyc/macro_loader.py +497 -0
- tpyc/module_names.py +64 -0
- tpyc/modules/__init__.py +31 -0
- tpyc/modules/defs.py +89 -0
- tpyc/modules/registry.py +36 -0
- tpyc/modules/resolver.py +192 -0
- tpyc/modules/type_resolution.py +629 -0
- tpyc/namespace.py +172 -0
- tpyc/parse/__init__.py +84 -0
- tpyc/parse/imports.py +490 -0
- tpyc/parse/nodes.py +1732 -0
- tpyc/parse/parser.py +4043 -0
- tpyc/parse/resolve_refs.py +466 -0
- tpyc/parse/type_resolver.py +1060 -0
- tpyc/prescan.py +254 -0
- tpyc/qnames.py +149 -0
- tpyc/repl.py +529 -0
- tpyc/repl_backends.py +848 -0
- tpyc/sema/__init__.py +21 -0
- tpyc/sema/analyzer.py +3625 -0
- tpyc/sema/bound_check.py +72 -0
- tpyc/sema/builder_trace.py +684 -0
- tpyc/sema/calls.py +5406 -0
- tpyc/sema/compatibility.py +2107 -0
- tpyc/sema/context.py +1243 -0
- tpyc/sema/expressions.py +3737 -0
- tpyc/sema/flow_facts.py +199 -0
- tpyc/sema/init_tracker.py +150 -0
- tpyc/sema/list_literals.py +69 -0
- tpyc/sema/literal_utils.py +27 -0
- tpyc/sema/local_deduction.py +1088 -0
- tpyc/sema/macros.py +179 -0
- tpyc/sema/match.py +1177 -0
- tpyc/sema/method_expansion.py +347 -0
- tpyc/sema/methods.py +2197 -0
- tpyc/sema/mutation_propagation.py +268 -0
- tpyc/sema/narrowing.py +857 -0
- tpyc/sema/numeric_lattice.py +160 -0
- tpyc/sema/operators.py +402 -0
- tpyc/sema/overloads.py +841 -0
- tpyc/sema/protocols.py +1209 -0
- tpyc/sema/reach_analysis.py +202 -0
- tpyc/sema/registration.py +3156 -0
- tpyc/sema/scope_tracker.py +193 -0
- tpyc/sema/statements.py +4426 -0
- tpyc/sema/type_ops.py +1879 -0
- tpyc/sema/value_range.py +181 -0
- tpyc/symbol_binding.py +259 -0
- tpyc/test_c3_mro.py +208 -0
- tpyc/test_cli_argv.py +52 -0
- tpyc/test_compiler.py +559 -0
- tpyc/test_contains_type_param.py +101 -0
- tpyc/test_cycle_detection.py +221 -0
- tpyc/test_dump_types.py +225 -0
- tpyc/test_install_docs.py +65 -0
- tpyc/test_local_cpp_form.py +135 -0
- tpyc/test_macro_loader.py +76 -0
- tpyc/test_method_expansion.py +254 -0
- tpyc/test_nominal_identity.py +182 -0
- tpyc/test_overloads.py +410 -0
- tpyc/test_parse.py +303 -0
- tpyc/test_parse_type_ref.py +506 -0
- tpyc/test_parse_version_info.py +58 -0
- tpyc/test_reach_analysis.py +72 -0
- tpyc/test_ref_type.py +216 -0
- tpyc/test_send_sync_substitution.py +276 -0
- tpyc/test_tuple_mutation_propagation.py +206 -0
- tpyc/test_type_def_registry.py +1729 -0
- tpyc/test_union_types.py +195 -0
- tpyc/type_def_registry.py +975 -0
- tpyc/typesys.py +5104 -0
tpyc/test_ref_type.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Tests for RefType and make_ref."""
|
|
2
|
+
|
|
3
|
+
from .typesys import (
|
|
4
|
+
RefType, make_ref, unwrap_ref_type, is_ref_type,
|
|
5
|
+
OwnType, ReadonlyType, OptionalType, UnionType,
|
|
6
|
+
VoidType, NoneType, TypeParamRef, TypeParamKind,
|
|
7
|
+
INT32, STR, BOOL, VOID, FLOAT,
|
|
8
|
+
NominalType, make_list,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestRefTypeConstruction:
|
|
13
|
+
def test_basic(self):
|
|
14
|
+
point = NominalType("Point")
|
|
15
|
+
ref = RefType(point)
|
|
16
|
+
assert ref.wrapped is point
|
|
17
|
+
assert str(ref) == "Ref[Point]"
|
|
18
|
+
|
|
19
|
+
def test_is_value_type(self):
|
|
20
|
+
ref = RefType(NominalType("Point"))
|
|
21
|
+
assert not ref.is_value_type()
|
|
22
|
+
|
|
23
|
+
def test_is_ref_param(self):
|
|
24
|
+
ref = RefType(NominalType("Point"))
|
|
25
|
+
assert ref.is_ref_param()
|
|
26
|
+
|
|
27
|
+
def test_inner_types(self):
|
|
28
|
+
point = NominalType("Point")
|
|
29
|
+
ref = RefType(point)
|
|
30
|
+
assert ref.inner_types() == (point,)
|
|
31
|
+
|
|
32
|
+
def test_with_inner_types(self):
|
|
33
|
+
point = NominalType("Point")
|
|
34
|
+
dog = NominalType("Dog")
|
|
35
|
+
ref = RefType(point)
|
|
36
|
+
ref2 = ref.with_inner_types((dog,))
|
|
37
|
+
assert isinstance(ref2, RefType)
|
|
38
|
+
assert ref2.wrapped is dog
|
|
39
|
+
|
|
40
|
+
def test_equality(self):
|
|
41
|
+
a = RefType(NominalType("Point"))
|
|
42
|
+
b = RefType(NominalType("Point"))
|
|
43
|
+
assert a == b
|
|
44
|
+
|
|
45
|
+
def test_inequality(self):
|
|
46
|
+
a = RefType(NominalType("Point"))
|
|
47
|
+
b = RefType(NominalType("Dog"))
|
|
48
|
+
assert a != b
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TestRefTypeToCpp:
|
|
52
|
+
"""Verify RefType produces the same C++ as the current non-value type methods."""
|
|
53
|
+
|
|
54
|
+
def test_to_cpp_concrete(self):
|
|
55
|
+
ref = RefType(NominalType("Point"))
|
|
56
|
+
assert ref.to_cpp() == "Point&"
|
|
57
|
+
|
|
58
|
+
def test_to_cpp_return(self):
|
|
59
|
+
ref = RefType(NominalType("Point"))
|
|
60
|
+
assert ref.to_cpp_return() == "Point&"
|
|
61
|
+
|
|
62
|
+
def test_to_cpp_return_const(self):
|
|
63
|
+
ref = RefType(NominalType("Point"))
|
|
64
|
+
assert ref.to_cpp_return_const() == "const Point&"
|
|
65
|
+
|
|
66
|
+
def test_to_cpp_param_type(self):
|
|
67
|
+
ref = RefType(NominalType("Point"))
|
|
68
|
+
assert ref.to_cpp_param_type() == "Point&"
|
|
69
|
+
|
|
70
|
+
def test_to_cpp_param(self):
|
|
71
|
+
ref = RefType(NominalType("Point"))
|
|
72
|
+
assert ref.to_cpp_param("x") == "Point& x"
|
|
73
|
+
|
|
74
|
+
def test_to_cpp_const_param(self):
|
|
75
|
+
ref = RefType(NominalType("Point"))
|
|
76
|
+
assert ref.to_cpp_const_param("x") == "const Point& x"
|
|
77
|
+
|
|
78
|
+
def test_to_cpp_stored(self):
|
|
79
|
+
ref = RefType(NominalType("Point"))
|
|
80
|
+
assert ref.to_cpp_stored() == "::tpy::val_or_ref<Point>"
|
|
81
|
+
|
|
82
|
+
def test_to_cpp_stored_list(self):
|
|
83
|
+
ref = RefType(make_list(INT32))
|
|
84
|
+
assert ref.to_cpp_stored() == "::tpy::val_or_ref<std::vector<int32_t>>"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class TestRefTypeParamRef:
|
|
88
|
+
"""Verify RefType with TypeParamRef uses C++ trait aliases."""
|
|
89
|
+
|
|
90
|
+
def test_to_cpp(self):
|
|
91
|
+
ref = RefType(TypeParamRef("T"))
|
|
92
|
+
assert ref.to_cpp() == "::tpy::val_or_ref_t<T>"
|
|
93
|
+
|
|
94
|
+
def test_to_cpp_return(self):
|
|
95
|
+
ref = RefType(TypeParamRef("T"))
|
|
96
|
+
assert ref.to_cpp_return() == "::tpy::val_or_ref_t<T>"
|
|
97
|
+
|
|
98
|
+
def test_to_cpp_return_const(self):
|
|
99
|
+
ref = RefType(TypeParamRef("T"))
|
|
100
|
+
assert ref.to_cpp_return_const() == "::tpy::val_or_cref_t<T>"
|
|
101
|
+
|
|
102
|
+
def test_to_cpp_param_type(self):
|
|
103
|
+
ref = RefType(TypeParamRef("T"))
|
|
104
|
+
assert ref.to_cpp_param_type() == "::tpy::param_val_or_ref_t<T>"
|
|
105
|
+
|
|
106
|
+
def test_to_cpp_stored(self):
|
|
107
|
+
ref = RefType(TypeParamRef("T"))
|
|
108
|
+
assert ref.to_cpp_stored() == "::tpy::val_or_ref<T>"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class TestMakeRef:
|
|
112
|
+
"""Test the smart constructor that decides when to wrap."""
|
|
113
|
+
|
|
114
|
+
def test_non_value_type_wrapped(self):
|
|
115
|
+
point = NominalType("Point")
|
|
116
|
+
result = make_ref(point)
|
|
117
|
+
assert isinstance(result, RefType)
|
|
118
|
+
assert result.wrapped is point
|
|
119
|
+
|
|
120
|
+
def test_list_wrapped(self):
|
|
121
|
+
lst = make_list(INT32)
|
|
122
|
+
result = make_ref(lst)
|
|
123
|
+
assert isinstance(result, RefType)
|
|
124
|
+
assert result.wrapped is lst
|
|
125
|
+
|
|
126
|
+
def test_value_type_not_wrapped(self):
|
|
127
|
+
assert make_ref(INT32) is INT32
|
|
128
|
+
assert make_ref(STR) is STR
|
|
129
|
+
assert make_ref(BOOL) is BOOL
|
|
130
|
+
assert make_ref(FLOAT) is FLOAT
|
|
131
|
+
|
|
132
|
+
def test_own_not_wrapped(self):
|
|
133
|
+
own = OwnType(NominalType("Point"))
|
|
134
|
+
assert make_ref(own) is own
|
|
135
|
+
|
|
136
|
+
def test_readonly_not_wrapped(self):
|
|
137
|
+
ro = ReadonlyType(NominalType("Point"))
|
|
138
|
+
assert make_ref(ro) is ro
|
|
139
|
+
|
|
140
|
+
def test_optional_not_wrapped(self):
|
|
141
|
+
opt = OptionalType(NominalType("Point"))
|
|
142
|
+
assert make_ref(opt) is opt
|
|
143
|
+
|
|
144
|
+
def test_union_not_wrapped(self):
|
|
145
|
+
union = UnionType((NominalType("Dog"), NominalType("Cat")))
|
|
146
|
+
assert make_ref(union) is union
|
|
147
|
+
|
|
148
|
+
def test_void_not_wrapped(self):
|
|
149
|
+
assert make_ref(VOID) is VOID
|
|
150
|
+
|
|
151
|
+
def test_none_not_wrapped(self):
|
|
152
|
+
none = NoneType()
|
|
153
|
+
assert make_ref(none) is none
|
|
154
|
+
|
|
155
|
+
def test_ref_not_double_wrapped(self):
|
|
156
|
+
ref = RefType(NominalType("Point"))
|
|
157
|
+
assert make_ref(ref) is ref
|
|
158
|
+
|
|
159
|
+
def test_type_param_ref_wrapped(self):
|
|
160
|
+
tpr = TypeParamRef("T")
|
|
161
|
+
result = make_ref(tpr)
|
|
162
|
+
assert isinstance(result, RefType)
|
|
163
|
+
assert result.wrapped is tpr
|
|
164
|
+
|
|
165
|
+
def test_type_param_ref_int_kind_not_wrapped(self):
|
|
166
|
+
tpr = TypeParamRef("N", kind=TypeParamKind.INT)
|
|
167
|
+
assert make_ref(tpr) is tpr
|
|
168
|
+
|
|
169
|
+
def test_type_param_ref_value_bound_not_wrapped(self):
|
|
170
|
+
bound = NominalType("ValueType", is_protocol=True,
|
|
171
|
+
_module_qname="tpy.ValueType")
|
|
172
|
+
tpr = TypeParamRef("T", bound=bound)
|
|
173
|
+
# is_value_type() returns True when bounded to tpy.ValueType
|
|
174
|
+
assert tpr.is_value_type()
|
|
175
|
+
assert make_ref(tpr) is tpr
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class TestUnwrapRefType:
|
|
179
|
+
def test_unwrap_ref(self):
|
|
180
|
+
point = NominalType("Point")
|
|
181
|
+
ref = RefType(point)
|
|
182
|
+
assert unwrap_ref_type(ref) is point
|
|
183
|
+
|
|
184
|
+
def test_unwrap_non_ref(self):
|
|
185
|
+
point = NominalType("Point")
|
|
186
|
+
assert unwrap_ref_type(point) is point
|
|
187
|
+
|
|
188
|
+
def test_unwrap_value_type(self):
|
|
189
|
+
assert unwrap_ref_type(INT32) is INT32
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class TestIsRefType:
|
|
193
|
+
def test_ref(self):
|
|
194
|
+
assert is_ref_type(RefType(NominalType("Point")))
|
|
195
|
+
|
|
196
|
+
def test_non_ref(self):
|
|
197
|
+
assert not is_ref_type(NominalType("Point"))
|
|
198
|
+
assert not is_ref_type(INT32)
|
|
199
|
+
assert not is_ref_type(OwnType(NominalType("Point")))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class TestToCppStored:
|
|
203
|
+
"""Test base class to_cpp_stored() default behavior."""
|
|
204
|
+
|
|
205
|
+
def test_value_type_stored_same_as_to_cpp(self):
|
|
206
|
+
assert INT32.to_cpp_stored() == INT32.to_cpp()
|
|
207
|
+
assert STR.to_cpp_stored() == STR.to_cpp()
|
|
208
|
+
|
|
209
|
+
def test_non_value_type_stored_same_as_to_cpp(self):
|
|
210
|
+
point = NominalType("Point")
|
|
211
|
+
assert point.to_cpp_stored() == point.to_cpp()
|
|
212
|
+
|
|
213
|
+
def test_ref_type_stored_uses_val_or_ref(self):
|
|
214
|
+
ref = RefType(NominalType("Point"))
|
|
215
|
+
assert ref.to_cpp_stored() == "::tpy::val_or_ref<Point>"
|
|
216
|
+
assert ref.to_cpp_stored() != ref.to_cpp()
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""Unit tests for NominalType.is_send / is_sync substitution at use sites.
|
|
2
|
+
|
|
3
|
+
`RecordInfo.is_send` / `is_sync` are computed at registration with any
|
|
4
|
+
field whose type mentions a TypeParamRef treated as conservatively-OK.
|
|
5
|
+
The use site re-walks fields and parents under concrete `type_args`,
|
|
6
|
+
so the answer is correct in both directions: types wrapping a non-Send
|
|
7
|
+
concrete arg report False, and types wrapping a Send concrete arg
|
|
8
|
+
report True even when the registration-time bool was conservative.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from .typesys import (
|
|
14
|
+
INT32, FieldInfo, NominalType, OptionalType, PtrType, RecordInfo,
|
|
15
|
+
TypeParamRef, make_list,
|
|
16
|
+
)
|
|
17
|
+
from .type_def_registry import (
|
|
18
|
+
TypeCategory, attach_dynamic_type_def, clear_dynamic_type_defs,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def _box_recordinfo():
|
|
24
|
+
"""Register Box[T] with `data: T` (a bare TypeParamRef field).
|
|
25
|
+
|
|
26
|
+
At registration, the disjunction in sema/registration.py accepts the
|
|
27
|
+
TypeParamRef-typed field as conservatively-OK, so `is_send` /
|
|
28
|
+
`is_sync` would be True. We set those flags manually here because
|
|
29
|
+
the unit test bypasses sema.
|
|
30
|
+
"""
|
|
31
|
+
info = RecordInfo(
|
|
32
|
+
name="Box",
|
|
33
|
+
fields=[FieldInfo(name="data", type=TypeParamRef("T"))],
|
|
34
|
+
type_params=["T"],
|
|
35
|
+
is_send=True,
|
|
36
|
+
is_sync=True,
|
|
37
|
+
)
|
|
38
|
+
attach_dynamic_type_def("Box", TypeCategory.RECORD, record=info)
|
|
39
|
+
try:
|
|
40
|
+
yield info
|
|
41
|
+
finally:
|
|
42
|
+
clear_dynamic_type_defs()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.fixture
|
|
46
|
+
def _wrapper_with_send_int_field():
|
|
47
|
+
"""Register Wrapper[T] with a `tag: Int32` field plus `data: T`.
|
|
48
|
+
|
|
49
|
+
Exercises that concrete-typed fields keep their definition-time
|
|
50
|
+
answer (Int32 is Send) while the TypeParamRef field is re-checked
|
|
51
|
+
under substitution.
|
|
52
|
+
"""
|
|
53
|
+
info = RecordInfo(
|
|
54
|
+
name="Wrapper",
|
|
55
|
+
fields=[
|
|
56
|
+
FieldInfo(name="tag", type=INT32),
|
|
57
|
+
FieldInfo(name="data", type=TypeParamRef("T")),
|
|
58
|
+
],
|
|
59
|
+
type_params=["T"],
|
|
60
|
+
is_send=True,
|
|
61
|
+
is_sync=True,
|
|
62
|
+
)
|
|
63
|
+
attach_dynamic_type_def("Wrapper", TypeCategory.RECORD, record=info)
|
|
64
|
+
try:
|
|
65
|
+
yield info
|
|
66
|
+
finally:
|
|
67
|
+
clear_dynamic_type_defs()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _box(arg) -> NominalType:
|
|
71
|
+
return NominalType("Box", type_args=(arg,), _module_qname="Box")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _wrapper(arg) -> NominalType:
|
|
75
|
+
return NominalType("Wrapper", type_args=(arg,), _module_qname="Wrapper")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _buf() -> NominalType:
|
|
79
|
+
# Stand-in for a user record. No registration needed -- its is_send /
|
|
80
|
+
# is_sync defaults (value-type fallback returning False for an
|
|
81
|
+
# unregistered nominal) are fine; PtrType.is_send is unconditionally
|
|
82
|
+
# False which is the only fact this test relies on.
|
|
83
|
+
return NominalType("Buf", _module_qname="user.Buf")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class TestGenericRecordSendSync:
|
|
87
|
+
def test_box_of_int_is_send(self, _box_recordinfo) -> None:
|
|
88
|
+
"""Int32 is Send -> Box[Int32] is Send (record bool stays True)."""
|
|
89
|
+
assert _box(INT32).is_send() is True
|
|
90
|
+
assert _box(INT32).is_sync() is True
|
|
91
|
+
|
|
92
|
+
def test_box_of_ptr_is_not_send(self, _box_recordinfo) -> None:
|
|
93
|
+
"""Ptr[Buf] is not Send -> Box[Ptr[Buf]] is not Send despite the
|
|
94
|
+
registration-time bool being True."""
|
|
95
|
+
ptr_buf = PtrType(_buf())
|
|
96
|
+
assert ptr_buf.is_send() is False
|
|
97
|
+
assert _box(ptr_buf).is_send() is False
|
|
98
|
+
|
|
99
|
+
def test_box_of_ptr_is_not_sync(self, _box_recordinfo) -> None:
|
|
100
|
+
"""Same shape for is_sync."""
|
|
101
|
+
ptr_buf = PtrType(_buf())
|
|
102
|
+
assert ptr_buf.is_sync() is False
|
|
103
|
+
assert _box(ptr_buf).is_sync() is False
|
|
104
|
+
|
|
105
|
+
def test_wrapper_concrete_field_preserved(
|
|
106
|
+
self, _wrapper_with_send_int_field,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Concrete-typed fields that were Send at registration stay Send;
|
|
109
|
+
only the TypeParamRef-typed field flips under substitution."""
|
|
110
|
+
assert _wrapper(INT32).is_send() is True
|
|
111
|
+
assert _wrapper(PtrType(_buf())).is_send() is False
|
|
112
|
+
|
|
113
|
+
def test_concrete_non_send_field_stays_false(self) -> None:
|
|
114
|
+
"""A generic record whose concrete-typed field is non-Send fails
|
|
115
|
+
the walker regardless of the type_args. The cached bool from
|
|
116
|
+
registration is False, but the walker reproduces the same answer
|
|
117
|
+
by walking the concrete field and finding it non-Send."""
|
|
118
|
+
info = RecordInfo(
|
|
119
|
+
name="Holder",
|
|
120
|
+
fields=[FieldInfo(name="p", type=PtrType(_buf()))],
|
|
121
|
+
type_params=["T"],
|
|
122
|
+
is_send=False,
|
|
123
|
+
is_sync=False,
|
|
124
|
+
)
|
|
125
|
+
attach_dynamic_type_def("Holder", TypeCategory.RECORD, record=info)
|
|
126
|
+
try:
|
|
127
|
+
holder = NominalType("Holder", type_args=(INT32,),
|
|
128
|
+
_module_qname="Holder")
|
|
129
|
+
assert holder.is_send() is False
|
|
130
|
+
assert holder.is_sync() is False
|
|
131
|
+
finally:
|
|
132
|
+
clear_dynamic_type_defs()
|
|
133
|
+
|
|
134
|
+
def test_non_generic_record_unaffected(self) -> None:
|
|
135
|
+
"""Non-generic records (no type_params) take the same path but
|
|
136
|
+
the substitution helper no-ops; the record-level bool wins."""
|
|
137
|
+
info = RecordInfo(
|
|
138
|
+
name="Plain",
|
|
139
|
+
fields=[FieldInfo(name="x", type=INT32)],
|
|
140
|
+
is_send=True,
|
|
141
|
+
is_sync=True,
|
|
142
|
+
)
|
|
143
|
+
attach_dynamic_type_def("Plain", TypeCategory.RECORD, record=info)
|
|
144
|
+
try:
|
|
145
|
+
plain = NominalType("Plain", _module_qname="Plain")
|
|
146
|
+
assert plain.is_send() is True
|
|
147
|
+
assert plain.is_sync() is True
|
|
148
|
+
finally:
|
|
149
|
+
clear_dynamic_type_defs()
|
|
150
|
+
|
|
151
|
+
def test_list_of_typeparam_flips_true(self) -> None:
|
|
152
|
+
"""`class W[T]: c: list[T]` -- at registration `list[T].is_send()`
|
|
153
|
+
evaluates to False because the TypeDef callable propagates
|
|
154
|
+
`T.is_send() == False`. The use-site walker substitutes the
|
|
155
|
+
concrete `type_args`, so W[Int32] correctly reports True."""
|
|
156
|
+
info = RecordInfo(
|
|
157
|
+
name="W",
|
|
158
|
+
fields=[FieldInfo(
|
|
159
|
+
name="c", type=make_list(element_type=TypeParamRef("T")),
|
|
160
|
+
)],
|
|
161
|
+
type_params=["T"],
|
|
162
|
+
)
|
|
163
|
+
attach_dynamic_type_def("W", TypeCategory.RECORD, record=info)
|
|
164
|
+
try:
|
|
165
|
+
assert NominalType(
|
|
166
|
+
"W", type_args=(INT32,), _module_qname="W",
|
|
167
|
+
).is_send() is True
|
|
168
|
+
assert NominalType(
|
|
169
|
+
"W", type_args=(PtrType(_buf()),), _module_qname="W",
|
|
170
|
+
).is_send() is False
|
|
171
|
+
# Mirror for is_sync to exercise _evaluating_sync.
|
|
172
|
+
# `list[T].is_sync()` is always False (mutable container), so
|
|
173
|
+
# the answer for W[anything] is False regardless of the arg.
|
|
174
|
+
assert NominalType(
|
|
175
|
+
"W", type_args=(INT32,), _module_qname="W",
|
|
176
|
+
).is_sync() is False
|
|
177
|
+
finally:
|
|
178
|
+
clear_dynamic_type_defs()
|
|
179
|
+
|
|
180
|
+
def test_self_recursive_generic(self) -> None:
|
|
181
|
+
"""`class Tree[T]: value: T; children: list[Tree[T]]` is the
|
|
182
|
+
canonical self-recursive generic. The cycle guard returns True
|
|
183
|
+
(greatest fixed point) on re-entry, so the answer is decided by
|
|
184
|
+
the non-recursive value field: Tree[Int32] is Send (Int32 is
|
|
185
|
+
Send), Tree[Ptr[Buf]] is not."""
|
|
186
|
+
info = RecordInfo(
|
|
187
|
+
name="Tree",
|
|
188
|
+
fields=[
|
|
189
|
+
FieldInfo(name="value", type=TypeParamRef("T")),
|
|
190
|
+
FieldInfo(
|
|
191
|
+
name="children",
|
|
192
|
+
type=make_list(element_type=NominalType(
|
|
193
|
+
"Tree", type_args=(TypeParamRef("T"),),
|
|
194
|
+
_module_qname="Tree",
|
|
195
|
+
)),
|
|
196
|
+
),
|
|
197
|
+
],
|
|
198
|
+
type_params=["T"],
|
|
199
|
+
)
|
|
200
|
+
attach_dynamic_type_def("Tree", TypeCategory.RECORD, record=info)
|
|
201
|
+
try:
|
|
202
|
+
assert NominalType(
|
|
203
|
+
"Tree", type_args=(INT32,), _module_qname="Tree",
|
|
204
|
+
).is_send() is True
|
|
205
|
+
assert NominalType(
|
|
206
|
+
"Tree", type_args=(PtrType(_buf()),), _module_qname="Tree",
|
|
207
|
+
).is_send() is False
|
|
208
|
+
finally:
|
|
209
|
+
clear_dynamic_type_defs()
|
|
210
|
+
|
|
211
|
+
def test_self_recursive_generic_sync_via_optional(self) -> None:
|
|
212
|
+
"""Counterpart to test_self_recursive_generic for is_sync.
|
|
213
|
+
|
|
214
|
+
`list[T]` short-circuits is_sync to False (mutable container), so
|
|
215
|
+
the prior test never re-enters the walker for is_sync and
|
|
216
|
+
`_evaluating_sync` never fires. Optional[T] passes is_sync
|
|
217
|
+
through to T, so a Tree whose recursive field is Optional[Tree[T]]
|
|
218
|
+
forces the walker to re-enter Tree[Int32].is_sync() recursively,
|
|
219
|
+
exercising the greatest-fixed-point branch."""
|
|
220
|
+
info = RecordInfo(
|
|
221
|
+
name="Tree",
|
|
222
|
+
fields=[
|
|
223
|
+
FieldInfo(name="value", type=TypeParamRef("T")),
|
|
224
|
+
FieldInfo(
|
|
225
|
+
name="child",
|
|
226
|
+
type=OptionalType(NominalType(
|
|
227
|
+
"Tree", type_args=(TypeParamRef("T"),),
|
|
228
|
+
_module_qname="Tree",
|
|
229
|
+
)),
|
|
230
|
+
),
|
|
231
|
+
],
|
|
232
|
+
type_params=["T"],
|
|
233
|
+
)
|
|
234
|
+
attach_dynamic_type_def("Tree", TypeCategory.RECORD, record=info)
|
|
235
|
+
try:
|
|
236
|
+
assert NominalType(
|
|
237
|
+
"Tree", type_args=(INT32,), _module_qname="Tree",
|
|
238
|
+
).is_sync() is True
|
|
239
|
+
assert NominalType(
|
|
240
|
+
"Tree", type_args=(PtrType(_buf()),), _module_qname="Tree",
|
|
241
|
+
).is_sync() is False
|
|
242
|
+
finally:
|
|
243
|
+
clear_dynamic_type_defs()
|
|
244
|
+
|
|
245
|
+
def test_generic_parent_substituted(self) -> None:
|
|
246
|
+
"""A child record inheriting from a generic parent must also have
|
|
247
|
+
its parent re-walked under substitution -- otherwise Child[T]'s
|
|
248
|
+
registration True latches in even when Parent[T] would be False
|
|
249
|
+
at the use site."""
|
|
250
|
+
parent = RecordInfo(
|
|
251
|
+
name="Parent",
|
|
252
|
+
fields=[FieldInfo(name="val", type=TypeParamRef("U"))],
|
|
253
|
+
type_params=["U"],
|
|
254
|
+
is_send=True,
|
|
255
|
+
is_sync=True,
|
|
256
|
+
)
|
|
257
|
+
attach_dynamic_type_def("Parent", TypeCategory.RECORD, record=parent)
|
|
258
|
+
child = RecordInfo(
|
|
259
|
+
name="Child",
|
|
260
|
+
fields=[],
|
|
261
|
+
type_params=["T"],
|
|
262
|
+
parents=[NominalType("Parent", type_args=(TypeParamRef("T"),),
|
|
263
|
+
_module_qname="Parent")],
|
|
264
|
+
is_send=True,
|
|
265
|
+
is_sync=True,
|
|
266
|
+
)
|
|
267
|
+
attach_dynamic_type_def("Child", TypeCategory.RECORD, record=child)
|
|
268
|
+
try:
|
|
269
|
+
assert NominalType(
|
|
270
|
+
"Child", type_args=(INT32,), _module_qname="Child",
|
|
271
|
+
).is_send() is True
|
|
272
|
+
assert NominalType(
|
|
273
|
+
"Child", type_args=(PtrType(_buf()),), _module_qname="Child",
|
|
274
|
+
).is_send() is False
|
|
275
|
+
finally:
|
|
276
|
+
clear_dynamic_type_defs()
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""Phase 0 RED tests: mutation propagation through tuple destructure
|
|
2
|
+
and through call edges where the param is a tuple/Optional.
|
|
3
|
+
|
|
4
|
+
These pin the prerequisite facts that the const-inference work depends on.
|
|
5
|
+
They were RED before the Phase 0 fixes (predicate at calls.py:2470 +
|
|
6
|
+
borrow-tracker edges in _analyze_tuple_unpack).
|
|
7
|
+
|
|
8
|
+
If any of these regresses, the const-inference downstream becomes unsound:
|
|
9
|
+
a body that mutates through a slot would be silently inferred read-only
|
|
10
|
+
and emitted with const slots.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from . import get_lib_dir
|
|
14
|
+
from .compiler import Compiler
|
|
15
|
+
|
|
16
|
+
_STDLIB_DIRS = [get_lib_dir() / "tpy"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _compile(source: str):
|
|
20
|
+
compiler = Compiler.from_source(source, lib_dirs=_STDLIB_DIRS)
|
|
21
|
+
modules = compiler.compile()
|
|
22
|
+
entry = [m for m in modules if m.is_entry_point][0]
|
|
23
|
+
return entry
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _get_func(module, name: str):
|
|
27
|
+
fi_list = module.exports.functions[name]
|
|
28
|
+
assert len(fi_list) == 1, f"expected single overload of {name}, got {len(fi_list)}"
|
|
29
|
+
return fi_list[0]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestTupleDestructureMutationPropagation:
|
|
33
|
+
"""`a, b = p; a.x = ...` must mark `p` mutated."""
|
|
34
|
+
|
|
35
|
+
def test_tuple_of_record_destructure_field_write(self):
|
|
36
|
+
source = """
|
|
37
|
+
from tpy import Int32
|
|
38
|
+
|
|
39
|
+
class T:
|
|
40
|
+
x: Int32
|
|
41
|
+
def __init__(self, x: Int32) -> None:
|
|
42
|
+
self.x = x
|
|
43
|
+
|
|
44
|
+
def f(p: tuple[T, T]) -> None:
|
|
45
|
+
a, b = p
|
|
46
|
+
a.x = Int32(1)
|
|
47
|
+
"""
|
|
48
|
+
module = _compile(source)
|
|
49
|
+
f = _get_func(module, "f")
|
|
50
|
+
assert f.mutated_params is not None
|
|
51
|
+
assert 0 in f.mutated_params, (
|
|
52
|
+
f"`p` should be marked mutated after destructure+field-write, "
|
|
53
|
+
f"got mutated_params={f.mutated_params}"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def test_tuple_of_optional_record_destructure_narrowing_field_write(self):
|
|
57
|
+
source = """
|
|
58
|
+
from tpy import Int32
|
|
59
|
+
|
|
60
|
+
class T:
|
|
61
|
+
x: Int32
|
|
62
|
+
def __init__(self, x: Int32) -> None:
|
|
63
|
+
self.x = x
|
|
64
|
+
|
|
65
|
+
def f(p: tuple[T | None, T | None]) -> None:
|
|
66
|
+
a, b = p
|
|
67
|
+
if a is not None:
|
|
68
|
+
a.x = Int32(1)
|
|
69
|
+
"""
|
|
70
|
+
module = _compile(source)
|
|
71
|
+
f = _get_func(module, "f")
|
|
72
|
+
assert f.mutated_params is not None
|
|
73
|
+
assert 0 in f.mutated_params, (
|
|
74
|
+
f"`p` should be marked mutated after destructure+narrowing+field-write, "
|
|
75
|
+
f"got mutated_params={f.mutated_params}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def test_tuple_of_record_destructure_no_write_not_mutated(self):
|
|
79
|
+
"""Negative: pure read through destructure must not mark mutated."""
|
|
80
|
+
source = """
|
|
81
|
+
from tpy import Int32
|
|
82
|
+
|
|
83
|
+
class T:
|
|
84
|
+
x: Int32
|
|
85
|
+
def __init__(self, x: Int32) -> None:
|
|
86
|
+
self.x = x
|
|
87
|
+
|
|
88
|
+
def f(p: tuple[T, T]) -> Int32:
|
|
89
|
+
a, b = p
|
|
90
|
+
return a.x + b.x
|
|
91
|
+
"""
|
|
92
|
+
module = _compile(source)
|
|
93
|
+
f = _get_func(module, "f")
|
|
94
|
+
assert f.mutated_params is not None
|
|
95
|
+
assert 0 not in f.mutated_params, (
|
|
96
|
+
f"`p` should NOT be marked mutated for pure read access, "
|
|
97
|
+
f"got mutated_params={f.mutated_params}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class TestTupleTransitiveMutationPropagation:
|
|
102
|
+
"""Phase-2 propagation: if inner mutates a tuple param, outer's matching
|
|
103
|
+
param must also be marked mutated when it forwards through inner."""
|
|
104
|
+
|
|
105
|
+
def test_transitive_through_tuple_param(self):
|
|
106
|
+
source = """
|
|
107
|
+
from tpy import Int32
|
|
108
|
+
|
|
109
|
+
class T:
|
|
110
|
+
x: Int32
|
|
111
|
+
def __init__(self, x: Int32) -> None:
|
|
112
|
+
self.x = x
|
|
113
|
+
|
|
114
|
+
def inner(p: tuple[T, T]) -> None:
|
|
115
|
+
a, b = p
|
|
116
|
+
a.x = Int32(1)
|
|
117
|
+
|
|
118
|
+
def outer(p: tuple[T, T]) -> None:
|
|
119
|
+
inner(p)
|
|
120
|
+
"""
|
|
121
|
+
module = _compile(source)
|
|
122
|
+
inner = _get_func(module, "inner")
|
|
123
|
+
outer = _get_func(module, "outer")
|
|
124
|
+
assert inner.mutated_params is not None and 0 in inner.mutated_params
|
|
125
|
+
assert outer.mutated_params is not None and 0 in outer.mutated_params, (
|
|
126
|
+
f"outer's `p` should be transitively marked mutated, "
|
|
127
|
+
f"got mutated_params={outer.mutated_params}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def test_transitive_through_optional_tuple_param(self):
|
|
131
|
+
source = """
|
|
132
|
+
from tpy import Int32
|
|
133
|
+
|
|
134
|
+
class T:
|
|
135
|
+
x: Int32
|
|
136
|
+
def __init__(self, x: Int32) -> None:
|
|
137
|
+
self.x = x
|
|
138
|
+
|
|
139
|
+
def inner(p: tuple[T | None, T | None]) -> None:
|
|
140
|
+
a, b = p
|
|
141
|
+
if a is not None:
|
|
142
|
+
a.x = Int32(1)
|
|
143
|
+
|
|
144
|
+
def outer(p: tuple[T | None, T | None]) -> None:
|
|
145
|
+
inner(p)
|
|
146
|
+
"""
|
|
147
|
+
module = _compile(source)
|
|
148
|
+
inner = _get_func(module, "inner")
|
|
149
|
+
outer = _get_func(module, "outer")
|
|
150
|
+
assert inner.mutated_params is not None and 0 in inner.mutated_params
|
|
151
|
+
assert outer.mutated_params is not None and 0 in outer.mutated_params, (
|
|
152
|
+
f"outer's `p` should be transitively marked mutated, "
|
|
153
|
+
f"got mutated_params={outer.mutated_params}"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def test_no_propagation_when_inner_does_not_mutate(self):
|
|
157
|
+
"""Negative: if inner only reads the tuple, outer is not marked."""
|
|
158
|
+
source = """
|
|
159
|
+
from tpy import Int32
|
|
160
|
+
|
|
161
|
+
class T:
|
|
162
|
+
x: Int32
|
|
163
|
+
def __init__(self, x: Int32) -> None:
|
|
164
|
+
self.x = x
|
|
165
|
+
|
|
166
|
+
def inner(p: tuple[T, T]) -> Int32:
|
|
167
|
+
a, b = p
|
|
168
|
+
return a.x + b.x
|
|
169
|
+
|
|
170
|
+
def outer(p: tuple[T, T]) -> Int32:
|
|
171
|
+
return inner(p)
|
|
172
|
+
"""
|
|
173
|
+
module = _compile(source)
|
|
174
|
+
outer = _get_func(module, "outer")
|
|
175
|
+
assert outer.mutated_params is not None
|
|
176
|
+
assert 0 not in outer.mutated_params
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class TestTupleLiteralRhsDestructure:
|
|
180
|
+
"""`a, b = (x, y)` should also propagate mutation through the borrow
|
|
181
|
+
edges from x/y to a/b."""
|
|
182
|
+
|
|
183
|
+
def test_tuple_literal_rhs_propagates(self):
|
|
184
|
+
source = """
|
|
185
|
+
from tpy import Int32
|
|
186
|
+
|
|
187
|
+
class T:
|
|
188
|
+
x: Int32
|
|
189
|
+
def __init__(self, x: Int32) -> None:
|
|
190
|
+
self.x = x
|
|
191
|
+
|
|
192
|
+
def f(x: T, y: T) -> None:
|
|
193
|
+
a, b = (x, y)
|
|
194
|
+
a.x = Int32(1)
|
|
195
|
+
"""
|
|
196
|
+
module = _compile(source)
|
|
197
|
+
f = _get_func(module, "f")
|
|
198
|
+
assert f.mutated_params is not None
|
|
199
|
+
assert 0 in f.mutated_params, (
|
|
200
|
+
f"`x` should be marked mutated through tuple-literal destructure, "
|
|
201
|
+
f"got mutated_params={f.mutated_params}"
|
|
202
|
+
)
|
|
203
|
+
# `y` is destructured into b but b is never written through.
|
|
204
|
+
assert 1 not in f.mutated_params, (
|
|
205
|
+
f"`y` should NOT be marked mutated, got mutated_params={f.mutated_params}"
|
|
206
|
+
)
|