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,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Numeric inference lattice helpers.
|
|
3
|
+
|
|
4
|
+
This module centralizes numeric family/rank logic used by reassignment-based
|
|
5
|
+
inference so future numeric types can be added in one place.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from ..typesys import (
|
|
13
|
+
TpyType, IntLiteralType, FloatLiteralType,
|
|
14
|
+
BIGINT, FLOAT, FLOAT32,
|
|
15
|
+
is_float_type,
|
|
16
|
+
)
|
|
17
|
+
from ..type_def_registry import (
|
|
18
|
+
is_fixed_int_type, is_big_int_type, is_bool_type,
|
|
19
|
+
is_float32_type, is_float64_type,
|
|
20
|
+
int_traits_of,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class NumericTypeInfo:
|
|
26
|
+
"""Classification metadata for numeric-like types."""
|
|
27
|
+
family: str # "int_literal" | "float_literal" | "int" | "float" | "bool"
|
|
28
|
+
rank: int
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def numeric_info(typ: TpyType) -> NumericTypeInfo | None:
|
|
32
|
+
"""Return numeric metadata for known numeric-like types."""
|
|
33
|
+
if isinstance(typ, IntLiteralType):
|
|
34
|
+
return NumericTypeInfo("int_literal", 0)
|
|
35
|
+
if isinstance(typ, FloatLiteralType):
|
|
36
|
+
return NumericTypeInfo("float_literal", 0)
|
|
37
|
+
if is_fixed_int_type(typ):
|
|
38
|
+
# Rank scales with bit width: Int8=8, Int16=9, Int32=10, Int64=11
|
|
39
|
+
tr = int_traits_of(typ)
|
|
40
|
+
assert tr is not None, f"fixed int without IntTraits: {typ}"
|
|
41
|
+
return NumericTypeInfo("int", tr.bits // 8 + 6)
|
|
42
|
+
if is_big_int_type(typ):
|
|
43
|
+
return NumericTypeInfo("int", 100)
|
|
44
|
+
if is_float32_type(typ):
|
|
45
|
+
return NumericTypeInfo("float", 190)
|
|
46
|
+
if is_float64_type(typ):
|
|
47
|
+
return NumericTypeInfo("float", 200)
|
|
48
|
+
if is_bool_type(typ):
|
|
49
|
+
return NumericTypeInfo("bool", 5)
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def fixed_int_range_contains(typ: TpyType, value: int) -> bool:
|
|
54
|
+
tr = int_traits_of(typ)
|
|
55
|
+
assert tr is not None, f"fixed_int_range_contains called on non-fixed-int {typ}"
|
|
56
|
+
return tr.min_value <= value <= tr.max_value
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def merge_literal_seed_target(
|
|
60
|
+
existing_type: TpyType,
|
|
61
|
+
init_type: TpyType,
|
|
62
|
+
literal_values: list[int],
|
|
63
|
+
) -> TpyType | None:
|
|
64
|
+
"""Infer target type for a literal-seeded variable.
|
|
65
|
+
|
|
66
|
+
A literal-seeded variable starts as ctx.default_int_type (`x = 0`) and may
|
|
67
|
+
be refined by later writes if safe.
|
|
68
|
+
"""
|
|
69
|
+
if isinstance(init_type, IntLiteralType):
|
|
70
|
+
if (
|
|
71
|
+
is_fixed_int_type(existing_type)
|
|
72
|
+
and init_type.value is not None
|
|
73
|
+
and not fixed_int_range_contains(existing_type, init_type.value)
|
|
74
|
+
):
|
|
75
|
+
return BIGINT
|
|
76
|
+
return existing_type
|
|
77
|
+
if is_fixed_int_type(init_type):
|
|
78
|
+
if all(fixed_int_range_contains(init_type, v) for v in literal_values):
|
|
79
|
+
return init_type
|
|
80
|
+
return existing_type
|
|
81
|
+
if is_big_int_type(init_type):
|
|
82
|
+
return BIGINT
|
|
83
|
+
if is_float32_type(init_type):
|
|
84
|
+
return FLOAT32
|
|
85
|
+
if is_float64_type(init_type):
|
|
86
|
+
return FLOAT
|
|
87
|
+
# bool is intentionally separate and should not merge with numeric literals.
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def widen_numeric_types(a: TpyType, b: TpyType) -> TpyType | None:
|
|
92
|
+
"""Return the widened type for two concrete numeric types, or None.
|
|
93
|
+
|
|
94
|
+
Used by reassignment inference when a variable is assigned a different
|
|
95
|
+
numeric type (e.g. Int32 then Int64 -> Int64, Int32 then float -> float).
|
|
96
|
+
|
|
97
|
+
Returns None when widening is not applicable (non-numeric, bool mixed
|
|
98
|
+
with numeric, same-width mixed sign).
|
|
99
|
+
"""
|
|
100
|
+
info_a = numeric_info(a)
|
|
101
|
+
info_b = numeric_info(b)
|
|
102
|
+
if info_a is None or info_b is None:
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
# Bool mixed with numeric -> refuse
|
|
106
|
+
if info_a.family == "bool" or info_b.family == "bool":
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
# Literal families are handled by merge_literal_seed_target, not here.
|
|
110
|
+
# Defensive: callers (local_deduction, _ternary_common_type) already
|
|
111
|
+
# resolve literals to concrete types before delegating; this guards
|
|
112
|
+
# against future callers that forget.
|
|
113
|
+
if info_a.family in ("int_literal", "float_literal"):
|
|
114
|
+
return None
|
|
115
|
+
if info_b.family in ("int_literal", "float_literal"):
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
# Both float-family -> widen to the higher-rank float
|
|
119
|
+
if is_float_type(a) and is_float_type(b):
|
|
120
|
+
if a == b:
|
|
121
|
+
return None
|
|
122
|
+
# Float64 wins over Float32
|
|
123
|
+
return a if is_float64_type(a) else b
|
|
124
|
+
|
|
125
|
+
# Either is float-family -> float-family wins over int
|
|
126
|
+
if is_float_type(a):
|
|
127
|
+
return a
|
|
128
|
+
if is_float_type(b):
|
|
129
|
+
return b
|
|
130
|
+
|
|
131
|
+
# Both BigInt -> same type, no widening
|
|
132
|
+
if is_big_int_type(a) and is_big_int_type(b):
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
# Either is BigInt -> BigInt wins
|
|
136
|
+
if is_big_int_type(a):
|
|
137
|
+
return a
|
|
138
|
+
if is_big_int_type(b):
|
|
139
|
+
return b
|
|
140
|
+
|
|
141
|
+
# Both FixedInt
|
|
142
|
+
a_tr = int_traits_of(a)
|
|
143
|
+
b_tr = int_traits_of(b)
|
|
144
|
+
assert a_tr is not None and b_tr is not None, f"expected fixed ints, got {a} and {b}"
|
|
145
|
+
if a_tr == b_tr:
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
if a_tr.signed == b_tr.signed:
|
|
149
|
+
return a if a_tr.bits > b_tr.bits else b
|
|
150
|
+
|
|
151
|
+
# Mixed sign: allow only if the wider type is signed with strictly more bits
|
|
152
|
+
if a_tr.bits > b_tr.bits:
|
|
153
|
+
wider, wider_traits, narrower_traits = a, a_tr, b_tr
|
|
154
|
+
else:
|
|
155
|
+
wider, wider_traits, narrower_traits = b, b_tr, a_tr
|
|
156
|
+
if wider_traits.signed and wider_traits.bits > narrower_traits.bits:
|
|
157
|
+
return wider
|
|
158
|
+
|
|
159
|
+
# Same width mixed sign (e.g. Int32 + UInt32) -> refuse
|
|
160
|
+
return None
|
tpyc/sema/operators.py
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Operator Resolution
|
|
3
|
+
|
|
4
|
+
Binary and unary operator resolution using the type registry.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from dataclasses import replace as dc_replace
|
|
9
|
+
from typing import TYPE_CHECKING, Callable
|
|
10
|
+
|
|
11
|
+
from ..typesys import (
|
|
12
|
+
TpyType, IntLiteralType, FloatLiteralType, LiteralType, TypeParamRef,
|
|
13
|
+
ResolvedBinop, ResolvedUnaryop, FunctionInfo, TypeParamKind,
|
|
14
|
+
INT32, FLOAT, PendingListType, make_list, OwnType, unwrap_ref_type,
|
|
15
|
+
unwrap_readonly,
|
|
16
|
+
)
|
|
17
|
+
from .overloads import type_matches_numeric, type_matches_strict
|
|
18
|
+
from tpyc import modules as builtin_modules
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from .context import SemanticContext
|
|
22
|
+
from .protocols import ProtocolChecker as ProtocolCheckerObj
|
|
23
|
+
from .type_ops import TypeOperations
|
|
24
|
+
ProtocolChecker = Callable[[TpyType, TpyType], bool]
|
|
25
|
+
|
|
26
|
+
from .bound_check import raise_if_class_param_bound_violated
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# C++ templates for user-defined dunder methods (used for unified operator resolution)
|
|
30
|
+
# These use C++ operator syntax which works for user types with operator overloads
|
|
31
|
+
DUNDER_CPP_TEMPLATES: dict[str, str] = {
|
|
32
|
+
# Binary operators
|
|
33
|
+
"__add__": "({self}) + ({0})",
|
|
34
|
+
"__sub__": "({self}) - ({0})",
|
|
35
|
+
"__mul__": "({self}) * ({0})",
|
|
36
|
+
"__truediv__": "({self}) / ({0})",
|
|
37
|
+
"__floordiv__": "({self}) / ({0})", # User types use regular division
|
|
38
|
+
"__mod__": "({self}) % ({0})",
|
|
39
|
+
"__pow__": "std::pow({self}, {0})",
|
|
40
|
+
"__lshift__": "({self}) << ({0})",
|
|
41
|
+
"__rshift__": "({self}) >> ({0})",
|
|
42
|
+
"__and__": "({self}) & ({0})",
|
|
43
|
+
"__or__": "({self}) | ({0})",
|
|
44
|
+
"__xor__": "({self}) ^ ({0})",
|
|
45
|
+
# Comparison operators
|
|
46
|
+
"__eq__": "({self}) == ({0})",
|
|
47
|
+
"__ne__": "({self}) != ({0})",
|
|
48
|
+
"__lt__": "({self}) < ({0})",
|
|
49
|
+
"__le__": "({self}) <= ({0})",
|
|
50
|
+
"__gt__": "({self}) > ({0})",
|
|
51
|
+
"__ge__": "({self}) >= ({0})",
|
|
52
|
+
# Reverse operators
|
|
53
|
+
"__radd__": "({0}) + ({self})",
|
|
54
|
+
"__rsub__": "({0}) - ({self})",
|
|
55
|
+
"__rmul__": "({0}) * ({self})",
|
|
56
|
+
"__rtruediv__": "({0}) / ({self})",
|
|
57
|
+
"__rfloordiv__": "({0}) / ({self})",
|
|
58
|
+
"__rmod__": "({0}) % ({self})",
|
|
59
|
+
"__rpow__": "std::pow({0}, {self})",
|
|
60
|
+
"__rlshift__": "({0}) << ({self})",
|
|
61
|
+
"__rrshift__": "({0}) >> ({self})",
|
|
62
|
+
"__rand__": "({0}) & ({self})",
|
|
63
|
+
"__ror__": "({0}) | ({self})",
|
|
64
|
+
"__rxor__": "({0}) ^ ({self})",
|
|
65
|
+
# Unary operators
|
|
66
|
+
"__pos__": "+({self})",
|
|
67
|
+
"__neg__": "-({self})",
|
|
68
|
+
"__invert__": "~({self})",
|
|
69
|
+
# Conversion methods (used for operator promotion)
|
|
70
|
+
"__int__": "({self}).__int__()",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _substitute_type_params(typ: TpyType, subst: dict[str, TpyType]) -> TpyType:
|
|
75
|
+
"""Substitute TypeParamRef instances in a type according to subst map."""
|
|
76
|
+
if isinstance(typ, TypeParamRef) and typ.name in subst:
|
|
77
|
+
return subst[typ.name]
|
|
78
|
+
return typ.map_inner_types(lambda t: _substitute_type_params(t, subst))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class OperatorResolver:
|
|
82
|
+
"""Resolves binary and unary operators using the type registry."""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self, ctx: SemanticContext,
|
|
86
|
+
type_ops: 'TypeOperations', protocols: 'ProtocolCheckerObj',
|
|
87
|
+
):
|
|
88
|
+
self.ctx = ctx
|
|
89
|
+
self.type_ops = type_ops
|
|
90
|
+
# Used to enforce class-shadowed method type-param bounds at dispatch.
|
|
91
|
+
self.protocols = protocols
|
|
92
|
+
|
|
93
|
+
def _check_class_bounds(
|
|
94
|
+
self, method: FunctionInfo, receiver_type: TpyType,
|
|
95
|
+
class_subst: dict[str, 'TpyType | int'], loc_node,
|
|
96
|
+
) -> None:
|
|
97
|
+
"""Raise if the receiver doesn't satisfy a class-shadowed method bound.
|
|
98
|
+
|
|
99
|
+
Operator dispatch bypasses `_analyze_generic_method_call` (which runs
|
|
100
|
+
the same check), so every resolve_* path must invoke this so the
|
|
101
|
+
sema-level error matches what codegen's `requires` clause catches at
|
|
102
|
+
C++ instantiation time.
|
|
103
|
+
"""
|
|
104
|
+
# Cheap method-level guard first: short-circuits the common case
|
|
105
|
+
# (every operator dispatch where the matched method has no bounds).
|
|
106
|
+
if not method.type_param_bounds:
|
|
107
|
+
return
|
|
108
|
+
# readonly[Box[T]] conforms to any protocol Box[T] does -- mirror that
|
|
109
|
+
# unwrap here so the bound check operates on the inner record.
|
|
110
|
+
record = self.ctx.registry.get_record_for_type(unwrap_readonly(receiver_type))
|
|
111
|
+
if record is None or not record.type_params:
|
|
112
|
+
return
|
|
113
|
+
raise_if_class_param_bound_violated(
|
|
114
|
+
method, record.type_params, class_subst,
|
|
115
|
+
self.protocols.type_conforms_to_protocol,
|
|
116
|
+
self.ctx.error, loc_node,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def _resolve_pending_types(self, tpy_type: TpyType) -> TpyType:
|
|
120
|
+
"""Resolve pending/structural types (PendingListType, TypeParamRef, LiteralType).
|
|
121
|
+
|
|
122
|
+
Preserves IntLiteralType for flexible overload matching.
|
|
123
|
+
"""
|
|
124
|
+
if isinstance(tpy_type, TypeParamRef) and tpy_type.kind == TypeParamKind.INT:
|
|
125
|
+
return INT32
|
|
126
|
+
if isinstance(tpy_type, PendingListType):
|
|
127
|
+
return make_list(tpy_type.element_type)
|
|
128
|
+
if isinstance(tpy_type, LiteralType):
|
|
129
|
+
return tpy_type.base_type
|
|
130
|
+
return tpy_type
|
|
131
|
+
|
|
132
|
+
def get_effective_type_for_binop(self, tpy_type: TpyType) -> TpyType:
|
|
133
|
+
"""Fully resolve type for registry lookup (also resolves IntLiteralType/FloatLiteralType)."""
|
|
134
|
+
tpy_type = unwrap_ref_type(tpy_type)
|
|
135
|
+
if isinstance(tpy_type, OwnType):
|
|
136
|
+
tpy_type = tpy_type.wrapped
|
|
137
|
+
if isinstance(tpy_type, IntLiteralType):
|
|
138
|
+
return self.ctx.default_int_for_literal(tpy_type)
|
|
139
|
+
if isinstance(tpy_type, FloatLiteralType):
|
|
140
|
+
return FLOAT
|
|
141
|
+
if isinstance(tpy_type, LiteralType):
|
|
142
|
+
return tpy_type.base_type
|
|
143
|
+
return self._resolve_pending_types(tpy_type)
|
|
144
|
+
|
|
145
|
+
def _build_type_subst(
|
|
146
|
+
self, receiver_type: TpyType, arg_effective: TpyType,
|
|
147
|
+
) -> dict[str, TpyType]:
|
|
148
|
+
"""Build type param substitution from a concrete receiver type.
|
|
149
|
+
|
|
150
|
+
When the receiver has IntLiteralType element(s), adapts to the arg's
|
|
151
|
+
concrete element type if available, otherwise resolves to default int.
|
|
152
|
+
"""
|
|
153
|
+
# Drop int-kind type args (e.g. N in Array[T, N]) --
|
|
154
|
+
# _substitute_type_params only acts on TypeParamRef -> TpyType.
|
|
155
|
+
subst: dict[str, TpyType] = {
|
|
156
|
+
k: v for k, v in self.type_ops.build_type_substitution(receiver_type).items()
|
|
157
|
+
if isinstance(v, TpyType)
|
|
158
|
+
}
|
|
159
|
+
if not subst:
|
|
160
|
+
return {}
|
|
161
|
+
arg_params = builtin_modules.extract_type_params(arg_effective)
|
|
162
|
+
for name, typ in list(subst.items()):
|
|
163
|
+
if isinstance(typ, IntLiteralType):
|
|
164
|
+
arg_val = arg_params.get(name)
|
|
165
|
+
if arg_val is not None and not isinstance(arg_val, IntLiteralType):
|
|
166
|
+
subst[name] = arg_val
|
|
167
|
+
else:
|
|
168
|
+
subst[name] = self.ctx.default_int_for_literal(typ)
|
|
169
|
+
return subst
|
|
170
|
+
|
|
171
|
+
def _find_matching_overload(
|
|
172
|
+
self, overloads: list[FunctionInfo], arg_type: TpyType,
|
|
173
|
+
type_subst: dict[str, TpyType],
|
|
174
|
+
protocol_checker: ProtocolChecker | None = None,
|
|
175
|
+
) -> FunctionInfo | None:
|
|
176
|
+
"""Find an overload matching arg_type, substituting type params first."""
|
|
177
|
+
for method in overloads:
|
|
178
|
+
if len(method.params) == 1:
|
|
179
|
+
_, param_type = method.params[0]
|
|
180
|
+
param_type = unwrap_ref_type(param_type)
|
|
181
|
+
if type_subst:
|
|
182
|
+
param_type = _substitute_type_params(param_type, type_subst)
|
|
183
|
+
if (type_matches_strict(arg_type, param_type, protocol_checker)
|
|
184
|
+
or type_matches_numeric(arg_type, param_type)):
|
|
185
|
+
return method
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
def _make_resolved(
|
|
189
|
+
self, method: FunctionInfo, type_subst: dict[str, TpyType],
|
|
190
|
+
receiver_type: TpyType, loc_node, left_wrapper: str = "{expr}",
|
|
191
|
+
right_wrapper: str = "{expr}", is_reverse: bool = False,
|
|
192
|
+
) -> ResolvedBinop:
|
|
193
|
+
"""Create ResolvedBinop with type params substituted in method signature."""
|
|
194
|
+
# Bound check before substitution rewrites `method` (bounds are on the
|
|
195
|
+
# original FunctionInfo and indexed by class-shadow names). Raises on
|
|
196
|
+
# violation -- the resolver never returns a result carrying one.
|
|
197
|
+
self._check_class_bounds(method, receiver_type, type_subst, loc_node)
|
|
198
|
+
if type_subst:
|
|
199
|
+
new_params = [
|
|
200
|
+
dc_replace(p, type=_substitute_type_params(p.type, type_subst))
|
|
201
|
+
for p in method.params
|
|
202
|
+
]
|
|
203
|
+
new_return = _substitute_type_params(method.return_type, type_subst)
|
|
204
|
+
method = dc_replace(method, params=new_params, return_type=new_return,
|
|
205
|
+
canonical_fi=method.root)
|
|
206
|
+
# Unwrap Ref from return type -- Ref is a codegen-level concern,
|
|
207
|
+
# sema expression types should not carry it.
|
|
208
|
+
ret = unwrap_ref_type(method.return_type)
|
|
209
|
+
if ret is not method.return_type:
|
|
210
|
+
method = dc_replace(method, return_type=ret, canonical_fi=method.root)
|
|
211
|
+
# Rebuild receiver_type from subst to resolve IntLiteralType elements.
|
|
212
|
+
# Use inner_types() as the source of truth for the reconstruction -- it
|
|
213
|
+
# defines exactly how many (and which) inner types the type has. params_map
|
|
214
|
+
# may have more entries (e.g. Tspan for PtrType), but with_inner_types only
|
|
215
|
+
# accepts len(inner_types()) values.
|
|
216
|
+
inner = receiver_type.inner_types()
|
|
217
|
+
if inner:
|
|
218
|
+
params_map = builtin_modules.extract_type_params(receiver_type)
|
|
219
|
+
param_names = list(params_map.keys())
|
|
220
|
+
new_inner = tuple(
|
|
221
|
+
type_subst.get(param_names[i], inner[i]) if i < len(param_names) else inner[i]
|
|
222
|
+
for i in range(len(inner))
|
|
223
|
+
)
|
|
224
|
+
receiver_type = receiver_type.with_inner_types(new_inner)
|
|
225
|
+
return ResolvedBinop(
|
|
226
|
+
method=method,
|
|
227
|
+
left_wrapper=left_wrapper,
|
|
228
|
+
right_wrapper=right_wrapper,
|
|
229
|
+
is_reverse=is_reverse,
|
|
230
|
+
receiver_type=receiver_type,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def resolve_binop(
|
|
234
|
+
self, left_type: TpyType, op: str, right_type: TpyType,
|
|
235
|
+
loc_node=None,
|
|
236
|
+
) -> ResolvedBinop | None:
|
|
237
|
+
"""Resolve binary operator using registry.
|
|
238
|
+
|
|
239
|
+
Handles both builtin types and user-defined types with dunder methods.
|
|
240
|
+
User-defined methods have cpp_template set to C++ operator syntax.
|
|
241
|
+
|
|
242
|
+
Generic methods (e.g. list[T].__add__) have their type params substituted
|
|
243
|
+
based on the receiver's concrete element type.
|
|
244
|
+
|
|
245
|
+
Tries in order:
|
|
246
|
+
1. left.__add__(right) - direct match
|
|
247
|
+
2. If left has __int__ returning right's type, promote left and use right's __add__
|
|
248
|
+
3. right.__radd__(left) - reverse operator
|
|
249
|
+
4. If right has __int__ returning left's type, promote right and use left's __add__
|
|
250
|
+
"""
|
|
251
|
+
method_name = builtin_modules.BINOP_TO_METHOD.get(op)
|
|
252
|
+
rmethod_name = builtin_modules.BINOP_TO_RMETHOD.get(op)
|
|
253
|
+
if not method_name:
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
# Get effective types (IntLiteralType -> configured default int type,
|
|
257
|
+
# PendingListType -> ListType)
|
|
258
|
+
left_effective = self.get_effective_type_for_binop(left_type)
|
|
259
|
+
right_effective = self.get_effective_type_for_binop(right_type)
|
|
260
|
+
|
|
261
|
+
left_record = self.ctx.registry.get_record_for_type(left_effective)
|
|
262
|
+
right_record = self.ctx.registry.get_record_for_type(right_effective)
|
|
263
|
+
|
|
264
|
+
# Build type substitution maps for generic types (e.g. list[T] -> list[Int32])
|
|
265
|
+
left_subst = self._build_type_subst(left_effective, right_effective)
|
|
266
|
+
right_subst = self._build_type_subst(right_effective, left_effective)
|
|
267
|
+
|
|
268
|
+
# For overload matching, resolve structural types but preserve
|
|
269
|
+
# IntLiteralType flexibility (matches any numeric type)
|
|
270
|
+
left_arg = unwrap_ref_type(self._resolve_pending_types(left_type))
|
|
271
|
+
right_arg = unwrap_ref_type(self._resolve_pending_types(right_type))
|
|
272
|
+
|
|
273
|
+
# 1. Try direct: left.__add__(right)
|
|
274
|
+
if left_record:
|
|
275
|
+
overloads = left_record.get_method_overloads(method_name)
|
|
276
|
+
if method := self._find_matching_overload(overloads, right_arg, left_subst):
|
|
277
|
+
return self._make_resolved(method, left_subst, left_effective, loc_node)
|
|
278
|
+
|
|
279
|
+
# 2. Try promoting left to right's type via __int__
|
|
280
|
+
if left_record and right_record:
|
|
281
|
+
int_overloads = left_record.get_method_overloads("__int__")
|
|
282
|
+
if int_overloads:
|
|
283
|
+
int_method = int_overloads[0]
|
|
284
|
+
promoted_type = int_method.return_type
|
|
285
|
+
# Check if promoted type matches right's type
|
|
286
|
+
if self.ctx.registry.get_record_for_type(promoted_type) == right_record:
|
|
287
|
+
right_overloads = right_record.get_method_overloads(method_name)
|
|
288
|
+
if method := self._find_matching_overload(right_overloads, right_arg, right_subst):
|
|
289
|
+
return self._make_resolved(
|
|
290
|
+
method, right_subst, right_effective, loc_node,
|
|
291
|
+
left_wrapper=int_method.cpp_template or "{expr}",
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# 3. Try reverse: right.__radd__(left)
|
|
295
|
+
if right_record and rmethod_name:
|
|
296
|
+
overloads = right_record.get_method_overloads(rmethod_name)
|
|
297
|
+
if method := self._find_matching_overload(overloads, left_arg, right_subst):
|
|
298
|
+
return self._make_resolved(
|
|
299
|
+
method, right_subst, right_effective, loc_node, is_reverse=True,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# 4. Try promoting right to left's type via __int__, then use left's operator
|
|
303
|
+
if right_record and left_record:
|
|
304
|
+
int_overloads = right_record.get_method_overloads("__int__")
|
|
305
|
+
if int_overloads:
|
|
306
|
+
int_method = int_overloads[0]
|
|
307
|
+
promoted_type = int_method.return_type
|
|
308
|
+
# Check if promoted type matches left's type
|
|
309
|
+
if self.ctx.registry.get_record_for_type(promoted_type) == left_record:
|
|
310
|
+
left_overloads = left_record.get_method_overloads(method_name)
|
|
311
|
+
if method := self._find_matching_overload(left_overloads, promoted_type, left_subst):
|
|
312
|
+
return self._make_resolved(
|
|
313
|
+
method, left_subst, left_effective, loc_node,
|
|
314
|
+
right_wrapper=int_method.cpp_template or "{expr}",
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
return None
|
|
318
|
+
|
|
319
|
+
def resolve_aug_inplace(
|
|
320
|
+
self, target_type: TpyType, op: str, value_type: TpyType,
|
|
321
|
+
protocol_checker: ProtocolChecker | None = None,
|
|
322
|
+
loc_node=None,
|
|
323
|
+
) -> ResolvedBinop | None:
|
|
324
|
+
"""Resolve in-place augmented assignment operator (e.g. __iadd__, __ior__).
|
|
325
|
+
|
|
326
|
+
Returns a ResolvedBinop whose method has a void return type and a cpp
|
|
327
|
+
template that mutates {self} in place (e.g. tpy::set_update({self}, {0})).
|
|
328
|
+
For user-defined methods, generates {self}.__iadd__({0}) call.
|
|
329
|
+
"""
|
|
330
|
+
method_name = builtin_modules.AUGOP_TO_IMETHOD.get(op)
|
|
331
|
+
if not method_name:
|
|
332
|
+
return None
|
|
333
|
+
|
|
334
|
+
target_effective = self.get_effective_type_for_binop(target_type)
|
|
335
|
+
record = self.ctx.registry.get_record_for_type(target_effective)
|
|
336
|
+
if not record:
|
|
337
|
+
return None
|
|
338
|
+
|
|
339
|
+
type_subst = self._build_type_subst(target_effective, value_type)
|
|
340
|
+
value_arg = unwrap_ref_type(self._resolve_pending_types(value_type))
|
|
341
|
+
|
|
342
|
+
overloads = record.get_method_overloads(method_name)
|
|
343
|
+
# Try builtin methods with cpp_template first
|
|
344
|
+
builtin_overloads = [m for m in overloads if m.cpp_template]
|
|
345
|
+
if method := self._find_matching_overload(builtin_overloads, value_arg, type_subst, protocol_checker):
|
|
346
|
+
return self._make_resolved(method, type_subst, target_effective, loc_node)
|
|
347
|
+
|
|
348
|
+
# Then try user-defined methods (no cpp_template)
|
|
349
|
+
user_overloads = [m for m in overloads if not m.cpp_template]
|
|
350
|
+
if method := self._find_matching_overload(user_overloads, value_arg, type_subst, protocol_checker):
|
|
351
|
+
return self._make_resolved(method, type_subst, target_effective, loc_node)
|
|
352
|
+
|
|
353
|
+
return None
|
|
354
|
+
|
|
355
|
+
def get_aug_inplace_param_type(
|
|
356
|
+
self, target_type: TpyType, op: str,
|
|
357
|
+
) -> TpyType | None:
|
|
358
|
+
"""Return the expected param type for an in-place operator, or None if not defined.
|
|
359
|
+
|
|
360
|
+
Used to produce precise type mismatch errors when resolve_aug_inplace fails:
|
|
361
|
+
the caller can pass the returned type to check_type_compatible to get a
|
|
362
|
+
specific "expected X, got Y" error instead of a generic "not supported" error.
|
|
363
|
+
"""
|
|
364
|
+
method_name = builtin_modules.AUGOP_TO_IMETHOD.get(op)
|
|
365
|
+
if not method_name:
|
|
366
|
+
return None
|
|
367
|
+
|
|
368
|
+
target_effective = self.get_effective_type_for_binop(target_type)
|
|
369
|
+
record = self.ctx.registry.get_record_for_type(target_effective)
|
|
370
|
+
if not record:
|
|
371
|
+
return None
|
|
372
|
+
|
|
373
|
+
overloads = record.get_method_overloads(method_name)
|
|
374
|
+
candidates = [m for m in overloads if m.params]
|
|
375
|
+
if not candidates:
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
type_subst = self._build_type_subst(target_effective, target_effective)
|
|
379
|
+
_, param_type = candidates[0].params[0]
|
|
380
|
+
if type_subst:
|
|
381
|
+
param_type = _substitute_type_params(param_type, type_subst)
|
|
382
|
+
return param_type
|
|
383
|
+
|
|
384
|
+
def resolve_unaryop(
|
|
385
|
+
self, operand_type: TpyType, op: str, loc_node=None,
|
|
386
|
+
) -> ResolvedUnaryop | None:
|
|
387
|
+
"""Resolve unary operator using registry."""
|
|
388
|
+
method_name = builtin_modules.UNARYOP_TO_METHOD.get(op)
|
|
389
|
+
if not method_name:
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
effective_type = self.get_effective_type_for_binop(operand_type)
|
|
393
|
+
record = self.ctx.registry.get_record_for_type(effective_type)
|
|
394
|
+
if record:
|
|
395
|
+
overloads = record.get_method_overloads(method_name)
|
|
396
|
+
if overloads and len(overloads[0].params) == 0:
|
|
397
|
+
method = overloads[0]
|
|
398
|
+
class_subst = self._build_type_subst(effective_type, effective_type)
|
|
399
|
+
self._check_class_bounds(method, effective_type, class_subst, loc_node)
|
|
400
|
+
return ResolvedUnaryop(method=method)
|
|
401
|
+
|
|
402
|
+
return None
|