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
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Code Generation Type Helpers
|
|
3
|
+
|
|
4
|
+
Type resolution and C++ type mapping utilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from ..typesys import (
|
|
11
|
+
TpyType, IntLiteralType, FloatLiteralType,
|
|
12
|
+
PendingListType, PendingDictType, PendingSetType, PendingViewType, ViewTypeFamily, make_list, make_dict, make_set, TypeParamRef, NominalType,
|
|
13
|
+
UnionType, NoneType, VoidType, TupleType, ReadonlyType,
|
|
14
|
+
unwrap_readonly, is_protocol_type, resolve_int_literals,
|
|
15
|
+
is_integer_type, is_float_type, is_void_like_type,
|
|
16
|
+
INT32, BIGINT, FLOAT, FLOAT32, STR, BYTES,
|
|
17
|
+
)
|
|
18
|
+
from ..parse import TpyExpr, TpyName, TpyBinOp, TpyUnaryOp, TpyCoerce, TpyCall, TpyMethodCall, TpyIntLiteral, TpyIfExpr
|
|
19
|
+
from ..sema.context import PENDING_CONTAINER_TYPES
|
|
20
|
+
from .context import qualified_cpp_name, enum_cpp_name
|
|
21
|
+
from ..compilation_context import get_current_compiler
|
|
22
|
+
from ..type_def_registry import (
|
|
23
|
+
is_list,
|
|
24
|
+
is_fixed_int_type, is_big_int_type, is_bool_type, is_float64_type, is_float32_type,
|
|
25
|
+
is_enum_type, protocol_info_of,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from .context import CodeGenContext
|
|
30
|
+
from .protocols import ProtocolGenerator
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TypeResolver:
|
|
34
|
+
"""Type resolution and C++ type mapping utilities."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, ctx: CodeGenContext, protocols: ProtocolGenerator):
|
|
37
|
+
self.ctx = ctx
|
|
38
|
+
self.protocols = protocols
|
|
39
|
+
|
|
40
|
+
def get_resolved_type(self, expr: TpyExpr, target_type: TpyType | None = None) -> TpyType:
|
|
41
|
+
"""Get the resolved type of an expression, handling PendingListType.
|
|
42
|
+
|
|
43
|
+
PendingListType is used during semantic analysis but should be resolved
|
|
44
|
+
to concrete Array or list types before codegen. This method looks up
|
|
45
|
+
the resolved type if needed.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
expr: The expression to get the type of.
|
|
49
|
+
target_type: Optional hint for what type the expression will be coerced to.
|
|
50
|
+
Used to determine if literal+literal should be Int32 or BigInt.
|
|
51
|
+
"""
|
|
52
|
+
# Protocol isinstance narrowing: `if isinstance(x, SomeProtocol):`
|
|
53
|
+
# narrows x from a union parameter to the protocol type within the
|
|
54
|
+
# branch. Surface the narrower type so for-loop dispatch, `in`
|
|
55
|
+
# operator, etc. pick the right peephole.
|
|
56
|
+
if isinstance(expr, TpyName) and expr.name in self.ctx.protocol_narrowings:
|
|
57
|
+
return unwrap_readonly(self.ctx.protocol_narrowings[expr.name])
|
|
58
|
+
# Check for codegen-overridden types (e.g., loop variables)
|
|
59
|
+
if isinstance(expr, TpyName) and expr.name in self.ctx.var_types:
|
|
60
|
+
return unwrap_readonly(self.ctx.var_types[expr.name])
|
|
61
|
+
if isinstance(expr, TpyCoerce):
|
|
62
|
+
return expr.expected_type
|
|
63
|
+
|
|
64
|
+
# Ternary: if both branches resolve to the same codegen type, use it
|
|
65
|
+
# so deductions like string_view propagate through (e.g. a if c else b).
|
|
66
|
+
if isinstance(expr, TpyIfExpr):
|
|
67
|
+
typ = self.ctx.analyzer.get_expr_type(expr)
|
|
68
|
+
then_resolved = self.get_resolved_type(expr.then_expr)
|
|
69
|
+
else_resolved = self.get_resolved_type(expr.else_expr)
|
|
70
|
+
if then_resolved == else_resolved:
|
|
71
|
+
return then_resolved
|
|
72
|
+
# Branches differ -- resolve pending view types so the view->owned
|
|
73
|
+
# wrapping check in statement codegen sees a concrete type.
|
|
74
|
+
ret = unwrap_readonly(typ) if typ else typ
|
|
75
|
+
if isinstance(ret, PendingViewType):
|
|
76
|
+
ret = self._resolve_pending_view(ret)
|
|
77
|
+
return ret
|
|
78
|
+
|
|
79
|
+
# For binary operations, compute type using resolved operand types
|
|
80
|
+
if isinstance(expr, TpyBinOp):
|
|
81
|
+
# Comparisons: skip arithmetic type logic, use sema type directly.
|
|
82
|
+
if expr.op in ("==", "!=", "<", ">", "<=", ">="):
|
|
83
|
+
typ = self.ctx.analyzer.get_expr_type(expr)
|
|
84
|
+
return unwrap_readonly(typ) if typ else typ
|
|
85
|
+
# Logical and/or: for operand-return semantics, resolve via
|
|
86
|
+
# operand types so codegen-level deductions (e.g. string_view)
|
|
87
|
+
# propagate correctly. Bool-result falls through to sema type.
|
|
88
|
+
if expr.op in ("&&", "||"):
|
|
89
|
+
typ = self.ctx.analyzer.get_expr_type(expr)
|
|
90
|
+
if is_bool_type(typ):
|
|
91
|
+
return unwrap_readonly(typ)
|
|
92
|
+
left_resolved = self.get_resolved_type(expr.left)
|
|
93
|
+
right_resolved = self.get_resolved_type(expr.right)
|
|
94
|
+
if left_resolved == right_resolved:
|
|
95
|
+
return left_resolved
|
|
96
|
+
# Operands differ (e.g. one is string_view, other is string).
|
|
97
|
+
# Resolve pending view types so callers like the view->owned
|
|
98
|
+
# wrapping check in statement codegen see a concrete type.
|
|
99
|
+
ret = unwrap_readonly(typ) if typ else typ
|
|
100
|
+
if isinstance(ret, PendingViewType):
|
|
101
|
+
ret = self._resolve_pending_view(ret)
|
|
102
|
+
return ret
|
|
103
|
+
|
|
104
|
+
# First pass without context to detect Int32 operands
|
|
105
|
+
left_raw = self.get_resolved_type(expr.left)
|
|
106
|
+
right_raw = self.get_resolved_type(expr.right)
|
|
107
|
+
left_analyzer_type = self.ctx.analyzer.get_expr_type(expr.left)
|
|
108
|
+
right_analyzer_type = self.ctx.analyzer.get_expr_type(expr.right)
|
|
109
|
+
left_is_literal = isinstance(left_analyzer_type, IntLiteralType) and not isinstance(expr.left, TpyName)
|
|
110
|
+
right_is_literal = isinstance(right_analyzer_type, IntLiteralType) and not isinstance(expr.right, TpyName)
|
|
111
|
+
|
|
112
|
+
# If either operand is float-family, result is float (float takes precedence)
|
|
113
|
+
if is_float_type(left_raw) or is_float_type(right_raw):
|
|
114
|
+
if expr.op == "div" or expr.op in ("+", "-", "*", "//", "%", "**"):
|
|
115
|
+
# Float64 wins over Float32
|
|
116
|
+
if is_float64_type(left_raw) or is_float64_type(right_raw):
|
|
117
|
+
return FLOAT
|
|
118
|
+
return left_raw if is_float32_type(left_raw) else right_raw
|
|
119
|
+
|
|
120
|
+
# True division always returns float
|
|
121
|
+
if expr.op == "div":
|
|
122
|
+
return FLOAT
|
|
123
|
+
|
|
124
|
+
# Determine fixed-int context: explicit target or operand is a fixed-width int
|
|
125
|
+
fixed_ctx = target_type if is_fixed_int_type(target_type) else None
|
|
126
|
+
if is_fixed_int_type(left_raw) and not left_is_literal:
|
|
127
|
+
fixed_ctx = left_raw
|
|
128
|
+
elif is_fixed_int_type(right_raw) and not right_is_literal:
|
|
129
|
+
fixed_ctx = right_raw
|
|
130
|
+
# Second pass with context for proper literal resolution
|
|
131
|
+
left_type = self.get_resolved_type(expr.left, fixed_ctx)
|
|
132
|
+
right_type = self.get_resolved_type(expr.right, fixed_ctx)
|
|
133
|
+
# If target is fixed-int and both operands are literals, result is that type
|
|
134
|
+
if is_fixed_int_type(fixed_ctx) and left_is_literal and right_is_literal:
|
|
135
|
+
return fixed_ctx
|
|
136
|
+
# Pure literal binops without fixed context use configured default-int,
|
|
137
|
+
# with range-safe fallback for out-of-range results.
|
|
138
|
+
if left_is_literal and right_is_literal:
|
|
139
|
+
analyzed = self.ctx.analyzer.get_expr_type(expr)
|
|
140
|
+
if isinstance(analyzed, IntLiteralType):
|
|
141
|
+
return self.ctx.analyzer.ctx.default_int_for_literal(analyzed)
|
|
142
|
+
return self.ctx.analyzer.ctx.default_int_type
|
|
143
|
+
# If either operand is a fixed-width int (and other is compatible), result is that type
|
|
144
|
+
if is_fixed_int_type(left_type) and (is_fixed_int_type(right_type) or isinstance(right_type, IntLiteralType)):
|
|
145
|
+
return left_type
|
|
146
|
+
if is_fixed_int_type(right_type) and (is_fixed_int_type(left_type) or isinstance(left_type, IntLiteralType)):
|
|
147
|
+
return right_type
|
|
148
|
+
# Otherwise, result is BigInt if either operand is BigInt.
|
|
149
|
+
# For literal-literal arithmetic without stronger context, use the
|
|
150
|
+
# configured default integer type.
|
|
151
|
+
is_bigint_op = is_big_int_type(left_type) or is_big_int_type(right_type)
|
|
152
|
+
if is_bigint_op and expr.op in ("+", "-", "*", "//", "%", "**", "&", "|", "^", "<<", ">>"):
|
|
153
|
+
return BIGINT
|
|
154
|
+
if (
|
|
155
|
+
isinstance(left_type, IntLiteralType)
|
|
156
|
+
and isinstance(right_type, IntLiteralType)
|
|
157
|
+
and expr.op in ("+", "-", "*", "//", "%", "**", "&", "|", "^", "<<", ">>")
|
|
158
|
+
):
|
|
159
|
+
analyzed = self.ctx.analyzer.get_expr_type(expr)
|
|
160
|
+
if isinstance(analyzed, IntLiteralType):
|
|
161
|
+
return self.ctx.analyzer.ctx.default_int_for_literal(analyzed)
|
|
162
|
+
return self.ctx.analyzer.ctx.default_int_type
|
|
163
|
+
|
|
164
|
+
typ = self.ctx.analyzer.get_expr_type(expr)
|
|
165
|
+
# Strip ReadonlyType -- C++ doesn't use it
|
|
166
|
+
typ = unwrap_readonly(typ) if typ else typ
|
|
167
|
+
resolved = self._resolve_pending_container(typ) if typ else None
|
|
168
|
+
if resolved is not None:
|
|
169
|
+
return resolved
|
|
170
|
+
if isinstance(typ, PendingViewType):
|
|
171
|
+
return self._resolve_pending_view(typ)
|
|
172
|
+
# Resolve IntLiteralType based on context (FixedInt/BigInt if target, else
|
|
173
|
+
# configured default int type).
|
|
174
|
+
if isinstance(typ, IntLiteralType):
|
|
175
|
+
if target_type is not None and is_integer_type(target_type):
|
|
176
|
+
return target_type
|
|
177
|
+
return self.ctx.analyzer.ctx.default_int_for_literal(typ)
|
|
178
|
+
# Resolve FloatLiteralType based on context (Float32 if target, else float64).
|
|
179
|
+
if isinstance(typ, FloatLiteralType):
|
|
180
|
+
if is_float32_type(target_type):
|
|
181
|
+
return FLOAT32
|
|
182
|
+
return FLOAT
|
|
183
|
+
# Resolve IntLiteralType in container element types
|
|
184
|
+
if is_list(typ) and isinstance(typ.type_args[0], IntLiteralType):
|
|
185
|
+
elem = self.ctx.analyzer.ctx.default_int_for_literal(typ.type_args[0])
|
|
186
|
+
return make_list(elem)
|
|
187
|
+
# Resolve IntLiteralType in tuple element types (recursively for nesting)
|
|
188
|
+
if isinstance(typ, TupleType):
|
|
189
|
+
resolve_lit = self.ctx.analyzer.ctx.default_int_for_literal
|
|
190
|
+
resolved_elems = []
|
|
191
|
+
changed = False
|
|
192
|
+
for i, et in enumerate(typ.element_types):
|
|
193
|
+
if isinstance(et, IntLiteralType):
|
|
194
|
+
# Use target_type's element if it's a FixedInt annotation
|
|
195
|
+
tt_elem = None
|
|
196
|
+
if isinstance(target_type, TupleType) and i < len(target_type.element_types):
|
|
197
|
+
tt_elem = target_type.element_types[i]
|
|
198
|
+
if tt_elem is not None and is_integer_type(tt_elem):
|
|
199
|
+
resolved_elems.append(tt_elem)
|
|
200
|
+
else:
|
|
201
|
+
resolved_elems.append(resolve_lit(et))
|
|
202
|
+
changed = True
|
|
203
|
+
elif isinstance(et, PendingViewType):
|
|
204
|
+
resolved_elems.append(self._resolve_pending_view(et))
|
|
205
|
+
changed = True
|
|
206
|
+
else:
|
|
207
|
+
resolved = resolve_int_literals(et, resolve_lit)
|
|
208
|
+
if resolved is not et:
|
|
209
|
+
changed = True
|
|
210
|
+
resolved_elems.append(resolved)
|
|
211
|
+
if changed:
|
|
212
|
+
return TupleType(tuple(resolved_elems))
|
|
213
|
+
return typ
|
|
214
|
+
|
|
215
|
+
def _resolve_view_storage(self, family: ViewTypeFamily, var_id: int) -> TpyType:
|
|
216
|
+
"""Resolve a view-vars entry to its storage form (view or owned)."""
|
|
217
|
+
info = self.ctx.analyzer.ctx.view_vars(family).get(var_id)
|
|
218
|
+
return info.resolved_type if info and info.resolved_type else family.owned_type
|
|
219
|
+
|
|
220
|
+
def _resolve_pending_view(self, typ: PendingViewType) -> TpyType:
|
|
221
|
+
"""Resolve a PendingViewType to its concrete type."""
|
|
222
|
+
return self._resolve_view_storage(typ.family, typ.var_id)
|
|
223
|
+
|
|
224
|
+
def _resolve_pending_container(self, typ: TpyType) -> TpyType | None:
|
|
225
|
+
"""Resolve a pending container type via unified lookup.
|
|
226
|
+
|
|
227
|
+
Returns the resolved type, or None if not a pending container.
|
|
228
|
+
Falls back to a best-effort concrete type if resolution hasn't run
|
|
229
|
+
(e.g. list -> ListType with resolved element type).
|
|
230
|
+
"""
|
|
231
|
+
if not isinstance(typ, PENDING_CONTAINER_TYPES):
|
|
232
|
+
return None
|
|
233
|
+
info = self.ctx.analyzer.ctx.get_container_info(typ.literal_id)
|
|
234
|
+
if info and info.resolved_type:
|
|
235
|
+
return info.resolved_type
|
|
236
|
+
# Fallback for unresolved containers
|
|
237
|
+
if isinstance(typ, PendingListType):
|
|
238
|
+
elem_type = typ.element_type
|
|
239
|
+
if isinstance(elem_type, IntLiteralType):
|
|
240
|
+
elem_type = self.ctx.analyzer.ctx.default_int_for_literal(elem_type)
|
|
241
|
+
return make_list(elem_type)
|
|
242
|
+
if isinstance(typ, PendingDictType):
|
|
243
|
+
return make_dict(typ.key_type, typ.value_type)
|
|
244
|
+
if isinstance(typ, PendingSetType):
|
|
245
|
+
return make_set(typ.element_type)
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
def resolve_type(self, typ: TpyType) -> TpyType:
|
|
249
|
+
"""Resolve deferred types (PendingViewType, PendingListType, etc.) to concrete C++ types."""
|
|
250
|
+
if isinstance(typ, PendingViewType):
|
|
251
|
+
return self._resolve_pending_view(typ)
|
|
252
|
+
resolved = self._resolve_pending_container(typ)
|
|
253
|
+
if resolved is not None:
|
|
254
|
+
return resolved
|
|
255
|
+
return typ
|
|
256
|
+
|
|
257
|
+
def substitute_type_params(self, typ: TpyType, subst: dict[str, TpyType]) -> TpyType:
|
|
258
|
+
"""Substitute type parameters with concrete types for codegen.
|
|
259
|
+
|
|
260
|
+
This is simpler than the sema version - just applies the substitution.
|
|
261
|
+
"""
|
|
262
|
+
if isinstance(typ, TypeParamRef):
|
|
263
|
+
return subst.get(typ.name, typ)
|
|
264
|
+
return typ.map_inner_types(lambda t: self.substitute_type_params(t, subst))
|
|
265
|
+
|
|
266
|
+
def involves_variables(self, expr: TpyExpr) -> bool:
|
|
267
|
+
"""Check if an expression involves any variable references."""
|
|
268
|
+
if isinstance(expr, TpyCoerce):
|
|
269
|
+
return self.involves_variables(expr.expr)
|
|
270
|
+
if isinstance(expr, TpyName):
|
|
271
|
+
return True
|
|
272
|
+
if isinstance(expr, TpyIntLiteral):
|
|
273
|
+
return False
|
|
274
|
+
if isinstance(expr, TpyBinOp):
|
|
275
|
+
return self.involves_variables(expr.left) or self.involves_variables(expr.right)
|
|
276
|
+
if isinstance(expr, TpyUnaryOp):
|
|
277
|
+
return self.involves_variables(expr.operand)
|
|
278
|
+
if isinstance(expr, TpyCall):
|
|
279
|
+
return True # Function calls may return BigInt
|
|
280
|
+
if isinstance(expr, TpyMethodCall):
|
|
281
|
+
return True
|
|
282
|
+
# Default to True for safety
|
|
283
|
+
return True
|
|
284
|
+
|
|
285
|
+
def is_fixed_int_arithmetic(self, left_type: TpyType, right_type: TpyType, op: str) -> bool:
|
|
286
|
+
"""Check if binary op produces fixed-int result (needs checked arithmetic).
|
|
287
|
+
|
|
288
|
+
Only applies when at least one operand is explicitly a fixed-width int.
|
|
289
|
+
IntLiteralType alone uses the configured default integer type.
|
|
290
|
+
"""
|
|
291
|
+
if op not in ("+", "-", "*", "//", "%", "**"):
|
|
292
|
+
return False
|
|
293
|
+
has_fixed = is_fixed_int_type(left_type) or is_fixed_int_type(right_type)
|
|
294
|
+
if not has_fixed:
|
|
295
|
+
return False
|
|
296
|
+
def is_fixed_compatible(t: TpyType) -> bool:
|
|
297
|
+
return is_fixed_int_type(t) or isinstance(t, IntLiteralType)
|
|
298
|
+
return is_fixed_compatible(left_type) and is_fixed_compatible(right_type)
|
|
299
|
+
|
|
300
|
+
def is_runtime_bigint(self, expr: TpyExpr, expr_type: TpyType) -> bool:
|
|
301
|
+
"""Check if expression is stored as BigInt at runtime."""
|
|
302
|
+
resolved = self.get_resolved_type(expr)
|
|
303
|
+
if is_big_int_type(resolved):
|
|
304
|
+
return True
|
|
305
|
+
if isinstance(resolved, IntLiteralType):
|
|
306
|
+
resolved_default = self.ctx.analyzer.ctx.default_int_for_literal(resolved)
|
|
307
|
+
return is_big_int_type(resolved_default)
|
|
308
|
+
return False
|
|
309
|
+
|
|
310
|
+
def varargs_elem_cpp(self, elem: TpyType) -> str:
|
|
311
|
+
"""C++ element type for a `*args` parameter's `varargs<...>`.
|
|
312
|
+
|
|
313
|
+
`const T` for a readonly slot element (`*xs: readonly[T]` -> readonly
|
|
314
|
+
vararg with const element access), else `T`. Mirrors the Span cpp
|
|
315
|
+
formatter's `std::span<const T>` rendering and keeps the param-emit and
|
|
316
|
+
call-site pack-emit in lockstep (both must produce the same string).
|
|
317
|
+
"""
|
|
318
|
+
if isinstance(elem, ReadonlyType):
|
|
319
|
+
return f"const {self.type_to_cpp(elem.wrapped)}"
|
|
320
|
+
return self.type_to_cpp(elem)
|
|
321
|
+
|
|
322
|
+
def type_to_cpp(self, typ: TpyType) -> str:
|
|
323
|
+
"""Convert a type to its C++ representation, qualifying imported types.
|
|
324
|
+
|
|
325
|
+
For imported record types from user modules, generates fully qualified names
|
|
326
|
+
like tpyapp::utils::Point or tpyapp::pkg::mod::Point for packages.
|
|
327
|
+
Native records use their native C++ name directly (no namespace qualification).
|
|
328
|
+
@dynamic protocol types map to the base class name.
|
|
329
|
+
"""
|
|
330
|
+
if isinstance(typ, NominalType) and is_protocol_type(typ):
|
|
331
|
+
protocol_info = protocol_info_of(typ)
|
|
332
|
+
if protocol_info and protocol_info.is_dynamic:
|
|
333
|
+
return self.protocols.get_dynamic_base_name(typ)
|
|
334
|
+
if isinstance(typ, NominalType) and typ.is_user_record:
|
|
335
|
+
# Native records use their native C++ name directly (globally visible)
|
|
336
|
+
record_info = self.ctx.analyzer.registry.get_record_for_type(typ)
|
|
337
|
+
if record_info and record_info.is_native:
|
|
338
|
+
return typ.to_cpp() # to_cpp() already resolves via Compiler.native_cpp_names
|
|
339
|
+
# Cross-module user record: qualify to the declaring module (canonical identity).
|
|
340
|
+
# Use the type-aware variant so records reachable only via an inferred
|
|
341
|
+
# cross-module return type (e.g. `import mod; p = mod.f()` where
|
|
342
|
+
# `f() -> Own[Pattern]`) still qualify -- short-name lookup would
|
|
343
|
+
# miss because `Pattern` isn't in the caller's local registry.
|
|
344
|
+
qual = self.ctx.analyzer.registry.imported_record_qualification_for_type(
|
|
345
|
+
typ, self.ctx.analyzer.ctx.module_name)
|
|
346
|
+
if qual is not None:
|
|
347
|
+
source_module, original_name = qual
|
|
348
|
+
qualified = qualified_cpp_name(source_module, original_name)
|
|
349
|
+
if typ.type_args:
|
|
350
|
+
args = ", ".join(
|
|
351
|
+
self.type_to_cpp(t) if isinstance(t, TpyType) else str(t)
|
|
352
|
+
for t in typ.type_args
|
|
353
|
+
)
|
|
354
|
+
return f"{qualified}<{args}>"
|
|
355
|
+
return qualified
|
|
356
|
+
# Enum type-position spelling. Routes through enum_cpp_name so
|
|
357
|
+
# @native enums render as their user-supplied qname rather than
|
|
358
|
+
# tpyapp::<module>::E. For local non-native enums this falls
|
|
359
|
+
# through to the local-name return below.
|
|
360
|
+
if is_enum_type(typ):
|
|
361
|
+
cur_module = self.ctx.analyzer.ctx.module_name
|
|
362
|
+
spelled = enum_cpp_name(typ, cur_module)
|
|
363
|
+
# Only return early if the helper produced something other
|
|
364
|
+
# than the bare local name (otherwise let the normal type
|
|
365
|
+
# rendering path continue, which uses Compiler.native_cpp_names).
|
|
366
|
+
if spelled != typ.name:
|
|
367
|
+
return spelled
|
|
368
|
+
# Tuple types: qualify element types for imported members
|
|
369
|
+
if isinstance(typ, TupleType):
|
|
370
|
+
args = ", ".join(self.type_to_cpp(t) for t in typ.element_types)
|
|
371
|
+
return f"std::tuple<{args}>"
|
|
372
|
+
# Union types: use alias name if registered, otherwise qualify member names
|
|
373
|
+
if isinstance(typ, UnionType):
|
|
374
|
+
compiler = get_current_compiler()
|
|
375
|
+
alias = compiler.union_alias_names.get(typ.members) if compiler is not None else None
|
|
376
|
+
if alias is not None:
|
|
377
|
+
return alias
|
|
378
|
+
cpp_members = [
|
|
379
|
+
"std::monostate" if is_void_like_type(m) else self.type_to_cpp(m)
|
|
380
|
+
for m in typ.members
|
|
381
|
+
]
|
|
382
|
+
return f"std::variant<{', '.join(cpp_members)}>"
|
|
383
|
+
# Resolve PendingViewType to concrete types before codegen
|
|
384
|
+
if isinstance(typ, PendingViewType):
|
|
385
|
+
return self._resolve_pending_view(typ).to_cpp()
|
|
386
|
+
# For plain NominalType (not subclasses like ListType/ArrayType) with
|
|
387
|
+
# type_args, recursively resolve args to handle @dynamic protocols.
|
|
388
|
+
# Skip this branch when the TypeDef registry provides a custom
|
|
389
|
+
# cpp_formatter (e.g. CopyIter/OwnIter -> "auto", dict_keys ->
|
|
390
|
+
# ::tpy::dict_keys_view<...>) -- fall through to typ.to_cpp() so the
|
|
391
|
+
# formatter wins.
|
|
392
|
+
if type(typ) is NominalType and typ.type_args:
|
|
393
|
+
from tpyc.type_def_registry import type_def_of
|
|
394
|
+
td = type_def_of(typ)
|
|
395
|
+
if td is None or td.cpp_formatter is None:
|
|
396
|
+
base = typ.to_cpp_base_name()
|
|
397
|
+
args = ", ".join(
|
|
398
|
+
self.type_to_cpp(t) if isinstance(t, TpyType) else str(t)
|
|
399
|
+
for t in typ.type_args
|
|
400
|
+
)
|
|
401
|
+
return f"{base}<{args}>"
|
|
402
|
+
# Default: use the type's built-in to_cpp() method
|
|
403
|
+
return typ.to_cpp()
|
|
404
|
+
|
|
405
|
+
def type_to_cpp_stored(self, typ: TpyType) -> str:
|
|
406
|
+
"""Convert a type to its stored C++ representation.
|
|
407
|
+
|
|
408
|
+
Like type_to_cpp but uses to_cpp_stored() (val_or_ref<T> for Ref types).
|
|
409
|
+
Resolves PendingViewType before conversion.
|
|
410
|
+
"""
|
|
411
|
+
if isinstance(typ, PendingViewType):
|
|
412
|
+
return self._resolve_pending_view(typ).to_cpp_stored()
|
|
413
|
+
return typ.to_cpp_stored()
|
|
414
|
+
|
|
415
|
+
def type_to_cpp_ptr_variant(self, typ: 'UnionType') -> str:
|
|
416
|
+
"""Return the pointer-variant type with qualified member names.
|
|
417
|
+
|
|
418
|
+
For non-value unions: std::variant<Dog*, Cat*> with cross-module
|
|
419
|
+
qualification on member types. Monostate members pass through.
|
|
420
|
+
"""
|
|
421
|
+
cpp_members = [
|
|
422
|
+
"std::monostate" if is_void_like_type(m)
|
|
423
|
+
else f"{self.type_to_cpp(m)}*"
|
|
424
|
+
for m in typ.members
|
|
425
|
+
]
|
|
426
|
+
return f"std::variant<{', '.join(cpp_members)}>"
|
|
427
|
+
|
|
428
|
+
def type_to_cpp_const_ptr_variant(self, typ: 'UnionType') -> str:
|
|
429
|
+
"""Return the const pointer-variant type with qualified member names."""
|
|
430
|
+
cpp_members = [
|
|
431
|
+
"std::monostate" if is_void_like_type(m)
|
|
432
|
+
else f"const {self.type_to_cpp(m)}*"
|
|
433
|
+
for m in typ.members
|
|
434
|
+
]
|
|
435
|
+
return f"std::variant<{', '.join(cpp_members)}>"
|
|
436
|
+
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Codegen helper for std::variant access patterns.
|
|
2
|
+
|
|
3
|
+
TurboPython unions lower to one of four C++ shapes:
|
|
4
|
+
|
|
5
|
+
- **Value variant**: `std::variant<A, B, ...>` -- members are value-typed,
|
|
6
|
+
variant stores them by value. Field / container / Own slot form.
|
|
7
|
+
- **Pointer variant**: `std::variant<A*, B*, ...>` -- members are non-value
|
|
8
|
+
reference types; the variant carries borrowed pointers. Param / local /
|
|
9
|
+
return form.
|
|
10
|
+
- **Wrapper struct**: `struct Tree { std::variant<...> value; }` -- emitted
|
|
11
|
+
for recursive union aliases (`type Tree = int | list[Tree]`) because
|
|
12
|
+
a plain `using` alias isn't forward-declarable in C++. The inner
|
|
13
|
+
`std::variant` is accessed via `.value`.
|
|
14
|
+
- **Optional-wrapped variant**: `std::optional<Tree>` where `Tree` is a
|
|
15
|
+
wrapper-struct alias, narrowed from `Tree | None`. The deref'd value
|
|
16
|
+
is itself a wrapper struct, so its `std::variant` is reached via
|
|
17
|
+
`(*opt).value`.
|
|
18
|
+
|
|
19
|
+
Each access site -- `std::holds_alternative<...>(...)`, `std::get<...>(...)`,
|
|
20
|
+
`.index()` switch dispatch -- has to make four decisions: deref prefix
|
|
21
|
+
(`*` for ptr-variant), type suffix (`*` for ptr-variant), `.value`
|
|
22
|
+
indirection (wrapper struct), and const propagation (`const T*` for
|
|
23
|
+
const-indirect locals). `VariantAccess` captures those decisions once at
|
|
24
|
+
construction and emits the right expressions through its methods, so
|
|
25
|
+
call sites stop re-deriving the same shape facts inline.
|
|
26
|
+
|
|
27
|
+
This module is the canonical source for variant access strings. Direct
|
|
28
|
+
`std::get` / `std::holds_alternative` formatting elsewhere in codegen
|
|
29
|
+
should be migrated here over time.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
from dataclasses import dataclass
|
|
34
|
+
|
|
35
|
+
from ..typesys import TpyType, OptionalType, AliasRef, unwrap_qualifiers, unwrap_ref_type
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _needs_value_indirection(typ: TpyType | None) -> bool:
|
|
39
|
+
"""True if the type's C++ form is a wrapper struct whose `std::variant`
|
|
40
|
+
is reached via `.value`. Covers recursive-union wrappers and
|
|
41
|
+
OptionalType wrapping a recursive-alias placeholder (the narrowed
|
|
42
|
+
deref'd value is itself a wrapper struct). Qualifiers (`readonly`,
|
|
43
|
+
`Own`, `Ref`) are peeled before testing -- a `readonly[Tree]` param
|
|
44
|
+
still resolves to its wrapper struct at the variant access site."""
|
|
45
|
+
if typ is None:
|
|
46
|
+
return False
|
|
47
|
+
peeled = unwrap_ref_type(unwrap_qualifiers(typ))
|
|
48
|
+
if peeled.needs_wrapper():
|
|
49
|
+
return True
|
|
50
|
+
if isinstance(peeled, OptionalType) and isinstance(peeled.inner, AliasRef):
|
|
51
|
+
return True
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class VariantAccess:
|
|
57
|
+
"""Codegen helper for emitting std::variant access patterns.
|
|
58
|
+
|
|
59
|
+
Construct once per access site with the base C++ expression, its
|
|
60
|
+
TPy type, and the shape flags (`is_ptr_variant`, `is_const`), then
|
|
61
|
+
call `index_expr()`, `holds(member)`, `get_by_type(member)`, or
|
|
62
|
+
`get_by_index(idx)` to produce the C++ access string.
|
|
63
|
+
"""
|
|
64
|
+
base_expr: str # C++ expression that yields the variant or its wrapper
|
|
65
|
+
typ: TpyType | None # TPy type of `base_expr`; None disables wrapper indirection
|
|
66
|
+
is_ptr_variant: bool # runtime form is `std::variant<T*, U*, ...>`
|
|
67
|
+
is_const: bool = False # const propagation for ptr-variant get (`std::get<const T*>(...)`)
|
|
68
|
+
|
|
69
|
+
# --- Access expressions --------------------------------------------
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def variant_expr(self) -> str:
|
|
73
|
+
"""C++ expression yielding the underlying `std::variant`.
|
|
74
|
+
|
|
75
|
+
Adds `.value` when the base type is a wrapper struct (recursive
|
|
76
|
+
alias) or an Optional wrapping a recursive-alias placeholder.
|
|
77
|
+
"""
|
|
78
|
+
if _needs_value_indirection(self.typ):
|
|
79
|
+
return f"{self.base_expr}.value"
|
|
80
|
+
return self.base_expr
|
|
81
|
+
|
|
82
|
+
def index_expr(self) -> str:
|
|
83
|
+
"""`variant.index()` -- for switch dispatch on the active tag."""
|
|
84
|
+
return f"{self.variant_expr}.index()"
|
|
85
|
+
|
|
86
|
+
def holds(self, member_cpp: str) -> str:
|
|
87
|
+
"""`std::holds_alternative<member>(variant)` -- type test for a
|
|
88
|
+
specific alternative. Adds `*` suffix for ptr-variant and `const`
|
|
89
|
+
prefix for const-indirect borrows."""
|
|
90
|
+
type_arg = self._type_arg(member_cpp)
|
|
91
|
+
return f"std::holds_alternative<{type_arg}>({self.variant_expr})"
|
|
92
|
+
|
|
93
|
+
def get_by_type(self, member_cpp: str, *, lvalue: bool = False) -> str:
|
|
94
|
+
"""`std::get<member>(variant)` extracting the typed alternative.
|
|
95
|
+
|
|
96
|
+
For ptr-variant, the result is dereferenced so the form is the
|
|
97
|
+
same value shape as for value-variant. `lvalue=False` (default)
|
|
98
|
+
wraps in outer parens for safe embedding in larger expressions
|
|
99
|
+
(`(*std::get<T*>(v))`). `lvalue=True` omits the parens, suitable
|
|
100
|
+
for direct binding sites like `auto& local = expr;`."""
|
|
101
|
+
type_arg = self._type_arg(member_cpp)
|
|
102
|
+
if self.is_ptr_variant:
|
|
103
|
+
inner = f"*std::get<{type_arg}>({self.variant_expr})"
|
|
104
|
+
return inner if lvalue else f"({inner})"
|
|
105
|
+
return f"std::get<{type_arg}>({self.variant_expr})"
|
|
106
|
+
|
|
107
|
+
def get_by_index(self, idx: int) -> str:
|
|
108
|
+
"""`std::get<I>(variant)` -- match-arm extraction by tag index.
|
|
109
|
+
|
|
110
|
+
For ptr-variant: emits `*std::get<I>(variant)` (without outer
|
|
111
|
+
parens; match-arm sites consume the expression as an lvalue and
|
|
112
|
+
bind via `auto&`)."""
|
|
113
|
+
if self.is_ptr_variant:
|
|
114
|
+
return f"*std::get<{idx}>({self.variant_expr})"
|
|
115
|
+
return f"std::get<{idx}>({self.variant_expr})"
|
|
116
|
+
|
|
117
|
+
# Boundary conversions (`::tpy::to_ptr_variant` / `to_const_ptr_variant`
|
|
118
|
+
# / `to_value_variant`) are not exposed here because every call site
|
|
119
|
+
# has different surrounding context (template arg for value form,
|
|
120
|
+
# mutability for ptr form). Keeping them open-coded at the call site
|
|
121
|
+
# has proven clearer than a partial-uniformity API.
|
|
122
|
+
|
|
123
|
+
# --- Internal ------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
def _type_arg(self, member_cpp: str) -> str:
|
|
126
|
+
"""Build the template argument for `std::get<...>` /
|
|
127
|
+
`std::holds_alternative<...>`. Adds `*` suffix and `const` prefix
|
|
128
|
+
when the runtime form is ptr-variant. `std::monostate` (the None
|
|
129
|
+
tag) is form-invariant -- ptr-variants carry it verbatim as a
|
|
130
|
+
monostate alternative, not a `std::monostate*` -- so it passes
|
|
131
|
+
through unchanged."""
|
|
132
|
+
if self.is_ptr_variant and member_cpp != "std::monostate":
|
|
133
|
+
const = "const " if self.is_const else ""
|
|
134
|
+
return f"{const}{member_cpp}*"
|
|
135
|
+
return member_cpp
|