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,629 @@
|
|
|
1
|
+
"""Method resolution, iterator/span helpers, extends-arg parsing.
|
|
2
|
+
|
|
3
|
+
Shared utilities that don't belong on a single TpyType subclass:
|
|
4
|
+
extends-clause string parsing, type-param substitution for method
|
|
5
|
+
signatures, and the iter/span element-type discovery used by sema. The
|
|
6
|
+
generic-type-factory table that used to live here now lives on
|
|
7
|
+
`TypeDef`.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from tpyc.typesys import TypeRegistry, RecordInfo, FunctionInfo
|
|
17
|
+
|
|
18
|
+
from tpyc.typesys import (
|
|
19
|
+
TypeParamRef, NominalType, PtrType, TupleType,
|
|
20
|
+
TpyType, CHAR, OwnType, GenExprType,
|
|
21
|
+
is_any_str_type, is_protocol_type, unwrap_ref_type, unwrap_qualifiers,
|
|
22
|
+
)
|
|
23
|
+
from tpyc.type_def_registry import is_span, is_span_iter, is_copy_iter, is_own_iter, is_iterator_adapter, protocol_info_of
|
|
24
|
+
from tpyc.modules.defs import ParamDef, MethodDef
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _compose_parent_subst(
|
|
28
|
+
parent: "NominalType", parent_info: "RecordInfo",
|
|
29
|
+
type_subst: "dict[str, TpyType]",
|
|
30
|
+
) -> "dict[str, TpyType]":
|
|
31
|
+
"""Extend type_subst with parent's type-parameter bindings from parent.type_args.
|
|
32
|
+
|
|
33
|
+
Each parent_info.type_params[i] maps to parent.type_args[i], composed through
|
|
34
|
+
the existing subst so TypeParamRefs from the child level get resolved first.
|
|
35
|
+
"""
|
|
36
|
+
result = dict(type_subst)
|
|
37
|
+
if parent.type_args and parent_info.type_params:
|
|
38
|
+
for param_name, arg in zip(parent_info.type_params, parent.type_args):
|
|
39
|
+
if isinstance(arg, TypeParamRef) and arg.name in type_subst:
|
|
40
|
+
result[param_name] = type_subst[arg.name]
|
|
41
|
+
else:
|
|
42
|
+
result[param_name] = arg
|
|
43
|
+
return result
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Concrete type name resolution
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def _resolve_concrete_type_name(name: str) -> "TpyType | None":
|
|
51
|
+
"""Resolve a concrete type name (like 'Char', 'Int32') to its TpyType singleton.
|
|
52
|
+
|
|
53
|
+
Used for resolving extends declarations like extends=["NativeIterable[Char]"].
|
|
54
|
+
"""
|
|
55
|
+
from tpyc.typesys import (
|
|
56
|
+
CHAR, BOOL, STR, STRING, STRVIEW, VOID, BIGINT, FLOAT, FLOAT32,
|
|
57
|
+
BASIC_SLICE, SLICE, BYTES, BYTEARRAY, BYTESVIEW,
|
|
58
|
+
INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Map of simple type names to their singleton instances
|
|
62
|
+
type_map = {
|
|
63
|
+
"bool": BOOL,
|
|
64
|
+
"Char": CHAR,
|
|
65
|
+
"Int8": INT8, "Int16": INT16, "Int32": INT32, "Int64": INT64,
|
|
66
|
+
"UInt8": UINT8, "UInt16": UINT16, "UInt32": UINT32, "UInt64": UINT64,
|
|
67
|
+
"Float32": FLOAT32,
|
|
68
|
+
"str": STR, "String": STRING, "StrView": STRVIEW,
|
|
69
|
+
"int": BIGINT,
|
|
70
|
+
"float": FLOAT,
|
|
71
|
+
"bytes": BYTES, "bytearray": BYTEARRAY, "BytesView": BYTESVIEW,
|
|
72
|
+
"basic_slice": BASIC_SLICE,
|
|
73
|
+
"slice": SLICE,
|
|
74
|
+
"None": VOID,
|
|
75
|
+
}
|
|
76
|
+
return type_map.get(name)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _resolve_extends_type_arg(type_str: str, type_params: dict[str, "TpyType"]) -> "TpyType | None":
|
|
80
|
+
"""Resolve an extends type arg string to a TpyType.
|
|
81
|
+
|
|
82
|
+
Handles:
|
|
83
|
+
- Simple type param refs: "K", "V", "T"
|
|
84
|
+
- Concrete type names: "Char", "Int32"
|
|
85
|
+
- Tuple types: "tuple[K, V]"
|
|
86
|
+
"""
|
|
87
|
+
# Handle tuple[...] pattern
|
|
88
|
+
tuple_match = re.match(r"tuple\[(.+)\]$", type_str)
|
|
89
|
+
if tuple_match:
|
|
90
|
+
inner = tuple_match.group(1)
|
|
91
|
+
parts = [p.strip() for p in inner.split(",")]
|
|
92
|
+
resolved = []
|
|
93
|
+
for part in parts:
|
|
94
|
+
if part in type_params:
|
|
95
|
+
resolved.append(type_params[part])
|
|
96
|
+
else:
|
|
97
|
+
concrete = _resolve_concrete_type_name(part)
|
|
98
|
+
if concrete is None:
|
|
99
|
+
return None
|
|
100
|
+
resolved.append(concrete)
|
|
101
|
+
return TupleType(tuple(resolved))
|
|
102
|
+
|
|
103
|
+
# Simple name: type param or concrete type
|
|
104
|
+
if type_str in type_params:
|
|
105
|
+
return type_params[type_str]
|
|
106
|
+
return _resolve_concrete_type_name(type_str)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# Type param extraction and method resolution
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
def extract_type_params(tpy_type: "TpyType") -> dict[str, "TpyType"]:
|
|
114
|
+
"""Extract type parameters from a concrete type instance.
|
|
115
|
+
|
|
116
|
+
For list[Int32], returns {"T": Int32}.
|
|
117
|
+
For dict[str, Int32], returns {"K": str, "V": Int32}.
|
|
118
|
+
For Container[Point, 10], returns {"T": Point}.
|
|
119
|
+
For Ptr[Point], returns {"T": Point}.
|
|
120
|
+
|
|
121
|
+
Note: Only type parameters that are themselves types are extracted.
|
|
122
|
+
Integer parameters like N in Container[T, N] are not included.
|
|
123
|
+
"""
|
|
124
|
+
from tpyc.typesys import PtrType
|
|
125
|
+
from tpyc.type_def_registry import is_dict_view, is_dict
|
|
126
|
+
if is_dict(tpy_type) or is_dict_view(tpy_type):
|
|
127
|
+
return {"K": tpy_type.type_args[0], "V": tpy_type.type_args[1]}
|
|
128
|
+
# Pointer types: use the full pointee (preserving readonly if present).
|
|
129
|
+
# For Ptr[readonly[T]], T maps to readonly[T] so that methods like
|
|
130
|
+
# span() -> Span[T] correctly produce Span[readonly[T]].
|
|
131
|
+
# The deref chains in expressions.py and methods.py handle unwrapping
|
|
132
|
+
# ReadonlyType from __deref__() results for field/method access.
|
|
133
|
+
if isinstance(tpy_type, PtrType):
|
|
134
|
+
return {"T": tpy_type.pointee}
|
|
135
|
+
if (elem_type := tpy_type.get_element_type()) is not None:
|
|
136
|
+
return {"T": elem_type}
|
|
137
|
+
return {}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _resolve_type_or_param(t: "TpyType", type_params: dict[str, "TpyType"]) -> "TpyType":
|
|
141
|
+
"""Resolve TypeParamRef instances to concrete types.
|
|
142
|
+
|
|
143
|
+
Handles:
|
|
144
|
+
- TypeParamRef("T") -> type_params["T"]
|
|
145
|
+
- SelfType -> type_params["Self"] if available, else SELF
|
|
146
|
+
- NominalType (protocol) with TypeParamRef args -> resolved NominalType
|
|
147
|
+
- PtrType with TypeParamRef pointee -> resolved pointer type
|
|
148
|
+
- Other TpyType -> returned as-is (uses map_inner_types for nested resolution)
|
|
149
|
+
"""
|
|
150
|
+
from tpyc.typesys import SelfType, SELF
|
|
151
|
+
|
|
152
|
+
# Handle SelfType
|
|
153
|
+
if isinstance(t, SelfType):
|
|
154
|
+
if "Self" in type_params:
|
|
155
|
+
return type_params["Self"]
|
|
156
|
+
return SELF
|
|
157
|
+
|
|
158
|
+
# Handle TypeParamRef directly
|
|
159
|
+
if isinstance(t, TypeParamRef):
|
|
160
|
+
if t.name not in type_params:
|
|
161
|
+
raise ValueError(f"Unresolved type parameter: {t.name}")
|
|
162
|
+
return type_params[t.name]
|
|
163
|
+
|
|
164
|
+
# Handle NominalType (protocol) with TypeParamRef in type_args
|
|
165
|
+
if isinstance(t, NominalType) and t.is_protocol and t.type_args:
|
|
166
|
+
resolved_args = tuple(
|
|
167
|
+
_resolve_type_or_param(arg, type_params) for arg in t.type_args
|
|
168
|
+
)
|
|
169
|
+
return NominalType(t.name, resolved_args, is_protocol=True)
|
|
170
|
+
|
|
171
|
+
# Handle PtrType with TypeParamRef pointee
|
|
172
|
+
if isinstance(t, PtrType):
|
|
173
|
+
resolved_pointee = _resolve_type_or_param(t.pointee, type_params)
|
|
174
|
+
return PtrType(resolved_pointee, is_readonly=t.is_readonly)
|
|
175
|
+
|
|
176
|
+
# For other types, use map_inner_types for recursive substitution
|
|
177
|
+
return t.map_inner_types(lambda inner: _resolve_type_or_param(inner, type_params))
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def resolve_method(method: MethodDef, type_params: dict[str, "TpyType"]) -> MethodDef:
|
|
181
|
+
"""Resolve TypeParamRef instances in a method signature to concrete types.
|
|
182
|
+
|
|
183
|
+
Given a method with TypeParamRef placeholders and a dict mapping
|
|
184
|
+
param names to concrete types, returns a new MethodDef with all types resolved.
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
method = MethodDef(params=[ParamDef("value", TypeParamRef("T"))],
|
|
188
|
+
returns=TypeParamRef("T"), cpp=...)
|
|
189
|
+
resolved = resolve_method(method, {"T": Int32})
|
|
190
|
+
# resolved.params[0].type == Int32, resolved.returns == Int32
|
|
191
|
+
"""
|
|
192
|
+
resolved_params = [
|
|
193
|
+
ParamDef(name=p.name, type=_resolve_type_or_param(p.type, type_params),
|
|
194
|
+
requires_mutable_lvalue=p.requires_mutable_lvalue)
|
|
195
|
+
for p in method.params
|
|
196
|
+
]
|
|
197
|
+
resolved_returns = _resolve_type_or_param(method.returns, type_params)
|
|
198
|
+
return MethodDef(
|
|
199
|
+
params=resolved_params,
|
|
200
|
+
returns=resolved_returns,
|
|
201
|
+
cpp=method.cpp,
|
|
202
|
+
is_noalloc=method.is_noalloc,
|
|
203
|
+
is_readonly=method.is_readonly,
|
|
204
|
+
is_pure=method.is_pure,
|
|
205
|
+
type_params=method.type_params,
|
|
206
|
+
type_param_bounds=method.type_param_bounds,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# ---------------------------------------------------------------------------
|
|
211
|
+
# Iterator / span helpers
|
|
212
|
+
# ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
# Protocols whose single type argument is the iteration element type.
|
|
215
|
+
ITERABLE_PROTOCOL_QNAMES = frozenset({
|
|
216
|
+
"typing.Iterator", "typing.Iterable",
|
|
217
|
+
"tpy.NativeIterable", "tpy.Spannable",
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
def is_native_iterable(tpy_type: "TpyType", registry: "TypeRegistry") -> bool:
|
|
221
|
+
"""Check if type extends NativeIterable (uses range-based for in C++)."""
|
|
222
|
+
record = registry.get_record_for_type(tpy_type)
|
|
223
|
+
if record is None:
|
|
224
|
+
return False
|
|
225
|
+
# Builtin types: check extends_protocols strings
|
|
226
|
+
if record.extends_protocols:
|
|
227
|
+
if any(ext.startswith("NativeIterable") for ext in record.extends_protocols):
|
|
228
|
+
return True
|
|
229
|
+
# User records: check explicitly declared implemented_protocols
|
|
230
|
+
for proto in record.implemented_protocols:
|
|
231
|
+
if proto.name == "NativeIterable":
|
|
232
|
+
return True
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def get_extends_protocol_type_arg(
|
|
237
|
+
tpy_type: "TpyType", protocol_name: str,
|
|
238
|
+
registry: "TypeRegistry | None" = None,
|
|
239
|
+
) -> "TpyType | None":
|
|
240
|
+
"""Extract the first type arg from a type's extends declaration for a protocol.
|
|
241
|
+
|
|
242
|
+
For example, Ptr[Int32] extends Deref[T] with T=Int32, so
|
|
243
|
+
get_extends_protocol_type_arg(Ptr[Int32], "Deref") returns Int32.
|
|
244
|
+
|
|
245
|
+
Checks builtin type extends strings first, then user record
|
|
246
|
+
implemented_protocols if a registry is provided.
|
|
247
|
+
"""
|
|
248
|
+
from tpyc.typesys import impl_proto_matches_name, get_protocol_qname
|
|
249
|
+
|
|
250
|
+
# Mirror classify_protocol_conformance: conformance is on the
|
|
251
|
+
# underlying record, not its Ref/readonly/Own wrapper.
|
|
252
|
+
tpy_type = unwrap_qualifiers(tpy_type)
|
|
253
|
+
|
|
254
|
+
type_params = extract_type_params(tpy_type)
|
|
255
|
+
|
|
256
|
+
# Check RecordInfo extends_protocols
|
|
257
|
+
if registry is not None:
|
|
258
|
+
record_info = registry.get_record_for_type(tpy_type)
|
|
259
|
+
if record_info is not None:
|
|
260
|
+
for ext in record_info.extends_protocols:
|
|
261
|
+
match = re.match(r"(\w+)\[(.+)\]", ext)
|
|
262
|
+
if match and match.group(1) == protocol_name:
|
|
263
|
+
return _resolve_extends_type_arg(match.group(2), type_params)
|
|
264
|
+
|
|
265
|
+
# Fallback: check implemented_protocols (NominalType objects)
|
|
266
|
+
target_qname = get_protocol_qname(protocol_name)
|
|
267
|
+
for impl_proto in record_info.implemented_protocols:
|
|
268
|
+
if impl_proto_matches_name(impl_proto, protocol_name, target_qname) and impl_proto.type_args:
|
|
269
|
+
return impl_proto.type_args[0]
|
|
270
|
+
|
|
271
|
+
return None
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def get_error_return_next_element_type(tpy_type: "TpyType", registry: "TypeRegistry") -> "TpyType | None":
|
|
275
|
+
"""If type has __next__() with @error_return(StopIteration), return element type T."""
|
|
276
|
+
from tpyc.typesys import NominalType, unwrap_ref_type
|
|
277
|
+
|
|
278
|
+
tpy_type = unwrap_ref_type(tpy_type)
|
|
279
|
+
if not isinstance(tpy_type, NominalType) or not tpy_type.is_user_record:
|
|
280
|
+
return None
|
|
281
|
+
return _find_error_return_next_element(tpy_type.name, tpy_type.type_args, registry)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _find_error_return_next_element(
|
|
285
|
+
record_name: str, type_args: "list[TpyType] | None", registry: "TypeRegistry",
|
|
286
|
+
) -> "TpyType | None":
|
|
287
|
+
"""Walk a record's method table (and parent chain) looking for __next__() with error_return."""
|
|
288
|
+
from tpyc.typesys import NominalType, OwnType, TypeParamRef, unwrap_ref_type
|
|
289
|
+
|
|
290
|
+
record = registry.find_record(record_name)
|
|
291
|
+
if record is None:
|
|
292
|
+
return None
|
|
293
|
+
|
|
294
|
+
type_subst: dict[str, "TpyType"] = {}
|
|
295
|
+
if record.type_params and type_args:
|
|
296
|
+
type_subst = dict(zip(record.type_params, type_args))
|
|
297
|
+
|
|
298
|
+
for method in record.get_method_overloads("__next__"):
|
|
299
|
+
if method.error_return_type == "builtins.StopIteration" and len(method.params) == 0:
|
|
300
|
+
inner = unwrap_ref_type(method.return_type)
|
|
301
|
+
if isinstance(inner, OwnType):
|
|
302
|
+
inner = inner.wrapped
|
|
303
|
+
if isinstance(inner, TypeParamRef) and inner.name in type_subst:
|
|
304
|
+
return type_subst[inner.name]
|
|
305
|
+
return inner
|
|
306
|
+
|
|
307
|
+
# Walk each parent chain (first match wins; diamond-free guarantees uniqueness)
|
|
308
|
+
for parent in record.parents:
|
|
309
|
+
if not (isinstance(parent, NominalType) and parent.is_user_record):
|
|
310
|
+
continue
|
|
311
|
+
parent_args = list(parent.type_args) if parent.type_args else None
|
|
312
|
+
if type_subst and parent_args:
|
|
313
|
+
parent_args = [
|
|
314
|
+
type_subst[a.name] if isinstance(a, TypeParamRef) and a.name in type_subst else a
|
|
315
|
+
for a in parent_args
|
|
316
|
+
]
|
|
317
|
+
result = _find_error_return_next_element(parent.name, parent_args, registry)
|
|
318
|
+
if result is not None:
|
|
319
|
+
return result
|
|
320
|
+
|
|
321
|
+
return None
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def get_iter_element_type(tpy_type: "TpyType", registry: "TypeRegistry") -> "TpyType | None":
|
|
325
|
+
"""If type has __iter__() returning a concrete iterator, return element type T."""
|
|
326
|
+
from tpyc.typesys import NominalType, unwrap_ref_type
|
|
327
|
+
|
|
328
|
+
tpy_type = unwrap_ref_type(tpy_type)
|
|
329
|
+
# Try user records (walks parent chain).
|
|
330
|
+
# allow_protocol_return=True: user __iter__ returning Iterator[T] is recognized.
|
|
331
|
+
if isinstance(tpy_type, NominalType) and tpy_type.is_user_record:
|
|
332
|
+
record = registry.get_record(tpy_type.name)
|
|
333
|
+
if record is not None:
|
|
334
|
+
type_subst: dict[str, "TpyType"] = {"Self": tpy_type}
|
|
335
|
+
if record.type_params and tpy_type.type_args:
|
|
336
|
+
type_subst.update(zip(record.type_params, tpy_type.type_args))
|
|
337
|
+
result = _find_record_iter_element(record, type_subst, registry,
|
|
338
|
+
allow_protocol_return=True)
|
|
339
|
+
if result is not None:
|
|
340
|
+
return result
|
|
341
|
+
|
|
342
|
+
# Try builtin types via registry.
|
|
343
|
+
# allow_protocol_return=True: builtin __iter__() stubs return Iterator[T]
|
|
344
|
+
# (e.g. list, dict, set, Span, Array, Range, str) and sema recognizes them
|
|
345
|
+
# structurally -- this is the single iteration-protocol entry point (see
|
|
346
|
+
# docs/ITERATOR_DESIGN.md).
|
|
347
|
+
record = registry.get_record_for_type(tpy_type)
|
|
348
|
+
if record is not None:
|
|
349
|
+
# extract_type_params handles NominalType.type_args as well as
|
|
350
|
+
# structural wrappers (PtrType.pointee, etc.) via each type's
|
|
351
|
+
# get_element_type() hook.
|
|
352
|
+
# Include Self so that __iter__(self) -> Self substitutes to the
|
|
353
|
+
# record's own type (used by SpanIter and similar self-iterator types).
|
|
354
|
+
type_subst_b = extract_type_params(tpy_type)
|
|
355
|
+
type_subst_b["Self"] = tpy_type
|
|
356
|
+
result = _find_record_iter_element(record, type_subst_b, registry,
|
|
357
|
+
allow_protocol_return=True)
|
|
358
|
+
if result is not None:
|
|
359
|
+
return result
|
|
360
|
+
|
|
361
|
+
return None
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _ancestor_iter_element(
|
|
365
|
+
proto: "NominalType", visited: "set[str] | None" = None,
|
|
366
|
+
) -> "TpyType | None":
|
|
367
|
+
"""Walk parent protocols looking for an ancestor whose qname is in
|
|
368
|
+
ITERABLE_PROTOCOL_QNAMES; return the inherited element type with the
|
|
369
|
+
inheritance binding chain applied.
|
|
370
|
+
|
|
371
|
+
For `class Counted[T](Iterable[T], Protocol)` instantiated as
|
|
372
|
+
`Counted[Int32]`, the element type is `Int32` -- read off Iterable's
|
|
373
|
+
type_args after substituting Counted's own T->Int32 binding.
|
|
374
|
+
"""
|
|
375
|
+
if visited is None:
|
|
376
|
+
visited = set()
|
|
377
|
+
info = protocol_info_of(proto)
|
|
378
|
+
if info is None:
|
|
379
|
+
return None
|
|
380
|
+
qname = proto.qualified_name() or proto.name
|
|
381
|
+
if qname in visited:
|
|
382
|
+
return None
|
|
383
|
+
visited.add(qname)
|
|
384
|
+
|
|
385
|
+
self_subst: dict[str, TpyType] = {}
|
|
386
|
+
if info.type_params and proto.type_args:
|
|
387
|
+
for name, arg in zip(info.type_params, proto.type_args):
|
|
388
|
+
if isinstance(arg, TpyType):
|
|
389
|
+
self_subst[name] = arg
|
|
390
|
+
|
|
391
|
+
for parent in info.parent_protocols:
|
|
392
|
+
resolved_args = tuple(
|
|
393
|
+
self_subst.get(arg.name, arg) if isinstance(arg, TypeParamRef) else arg
|
|
394
|
+
for arg in parent.type_args
|
|
395
|
+
)
|
|
396
|
+
resolved_parent = NominalType(
|
|
397
|
+
name=parent.name,
|
|
398
|
+
type_args=resolved_args,
|
|
399
|
+
is_protocol=True,
|
|
400
|
+
_module_qname=parent._module_qname,
|
|
401
|
+
)
|
|
402
|
+
if resolved_parent.qualified_name() in ITERABLE_PROTOCOL_QNAMES:
|
|
403
|
+
if resolved_args:
|
|
404
|
+
first = resolved_args[0]
|
|
405
|
+
return first if isinstance(first, TpyType) else None
|
|
406
|
+
return None
|
|
407
|
+
result = _ancestor_iter_element(resolved_parent, visited)
|
|
408
|
+
if result is not None:
|
|
409
|
+
return result
|
|
410
|
+
return None
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def get_iterable_element_type(tpy_type: "TpyType", registry: "TypeRegistry") -> "TpyType | None":
|
|
414
|
+
"""Unified element-type accessor for any iterable type.
|
|
415
|
+
|
|
416
|
+
Single source of truth for "what element type does iterating this produce?"
|
|
417
|
+
Covers all iterable categories:
|
|
418
|
+
- Compiler-internal adapters (CopyIter, OwnIter, GenExpr, SpanIter)
|
|
419
|
+
- Protocol-typed params (Iterator[T], Iterable[T], NativeIterable[T], Spannable[T])
|
|
420
|
+
- String types -> Char
|
|
421
|
+
- error_return __next__ iterators
|
|
422
|
+
- __iter__() method (built-in containers + user records)
|
|
423
|
+
|
|
424
|
+
Returns None if the type is not iterable.
|
|
425
|
+
"""
|
|
426
|
+
tpy_type = unwrap_ref_type(tpy_type)
|
|
427
|
+
if isinstance(tpy_type, OwnType):
|
|
428
|
+
tpy_type = tpy_type.wrapped
|
|
429
|
+
|
|
430
|
+
# Compiler-internal iterator adapters (no stubs) plus SpanIter
|
|
431
|
+
if is_iterator_adapter(tpy_type) or isinstance(tpy_type, GenExprType):
|
|
432
|
+
return tpy_type.element_type if isinstance(tpy_type, GenExprType) else tpy_type.type_args[0]
|
|
433
|
+
|
|
434
|
+
# Protocol-typed iterables: single type_arg is T
|
|
435
|
+
if is_protocol_type(tpy_type) and tpy_type.qualified_name() in ITERABLE_PROTOCOL_QNAMES:
|
|
436
|
+
if tpy_type.type_args:
|
|
437
|
+
first = tpy_type.type_args[0]
|
|
438
|
+
return first if isinstance(first, TpyType) else None
|
|
439
|
+
return None
|
|
440
|
+
|
|
441
|
+
# Protocol-typed iterables that inherit from one of the above (e.g.
|
|
442
|
+
# `class Counted[T](Iterable[T], Protocol)`). Walks parent protocols and
|
|
443
|
+
# resolves the inherited element type via the inheritance binding chain.
|
|
444
|
+
if is_protocol_type(tpy_type) and isinstance(tpy_type, NominalType):
|
|
445
|
+
ancestor_elem = _ancestor_iter_element(tpy_type)
|
|
446
|
+
if ancestor_elem is not None:
|
|
447
|
+
return ancestor_elem
|
|
448
|
+
|
|
449
|
+
# String types -> Char
|
|
450
|
+
if is_any_str_type(tpy_type):
|
|
451
|
+
return CHAR
|
|
452
|
+
|
|
453
|
+
# error_return __next__ (user-defined iterators)
|
|
454
|
+
er_elem = get_error_return_next_element_type(tpy_type, registry)
|
|
455
|
+
if er_elem is not None:
|
|
456
|
+
return er_elem
|
|
457
|
+
|
|
458
|
+
# __iter__() method (built-in containers + user records)
|
|
459
|
+
iter_elem = get_iter_element_type(tpy_type, registry)
|
|
460
|
+
if iter_elem is not None:
|
|
461
|
+
return iter_elem
|
|
462
|
+
|
|
463
|
+
return None
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def _find_record_iter_element(
|
|
467
|
+
record: "RecordInfo", type_subst: "dict[str, TpyType]", registry: "TypeRegistry",
|
|
468
|
+
*, allow_protocol_return: bool = False,
|
|
469
|
+
) -> "TpyType | None":
|
|
470
|
+
"""Check if record (or its parents) has __iter__() returning a concrete iterator; return element type."""
|
|
471
|
+
from tpyc.typesys import NominalType, TypeParamRef
|
|
472
|
+
|
|
473
|
+
result = _find_iter_method_element(record.get_method_overloads("__iter__"), type_subst, registry,
|
|
474
|
+
allow_protocol_return=allow_protocol_return)
|
|
475
|
+
if result is not None:
|
|
476
|
+
return result
|
|
477
|
+
|
|
478
|
+
# Walk each parent chain (first match wins)
|
|
479
|
+
for parent in record.parents:
|
|
480
|
+
if not (isinstance(parent, NominalType) and parent.is_user_record):
|
|
481
|
+
continue
|
|
482
|
+
parent_info = registry.get_record(parent.name)
|
|
483
|
+
if parent_info is None:
|
|
484
|
+
continue
|
|
485
|
+
parent_subst = _compose_parent_subst(parent, parent_info, type_subst)
|
|
486
|
+
result = _find_record_iter_element(parent_info, parent_subst, registry,
|
|
487
|
+
allow_protocol_return=allow_protocol_return)
|
|
488
|
+
if result is not None:
|
|
489
|
+
return result
|
|
490
|
+
|
|
491
|
+
return None
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def _find_iter_method_element(
|
|
495
|
+
methods: "list[MethodDef | FunctionInfo]", type_subst: "dict[str, TpyType]", registry: "TypeRegistry",
|
|
496
|
+
*, allow_protocol_return: bool = False,
|
|
497
|
+
) -> "TpyType | None":
|
|
498
|
+
"""Check __iter__() methods for a concrete iterator return type and extract element type."""
|
|
499
|
+
from tpyc.typesys import FunctionInfo, NominalType, OwnType, SelfType, TypeParamRef, is_protocol_type, unwrap_ref_type
|
|
500
|
+
|
|
501
|
+
for method in methods:
|
|
502
|
+
if len(method.params) != 0:
|
|
503
|
+
continue
|
|
504
|
+
if isinstance(method, FunctionInfo):
|
|
505
|
+
ret = unwrap_ref_type(method.return_type)
|
|
506
|
+
else:
|
|
507
|
+
ret = method.returns
|
|
508
|
+
# __iter__(self) -> Self handling. SelfType returns substitute
|
|
509
|
+
# to the record's own type. User iterators with Self return
|
|
510
|
+
# resolve to their NominalType (is_user_record=True) and are
|
|
511
|
+
# handled by the error_return __next__ branch below.
|
|
512
|
+
# Note: builtins like SpanIter whose __iter__ returns Self end
|
|
513
|
+
# up as plain NominalType("SpanIter", ...) after parser resolution
|
|
514
|
+
# and are NOT matched here; they rely on the compiler-internal
|
|
515
|
+
# adapter list in IterableHelper. The parser doesn't resolve Self
|
|
516
|
+
# to the SpanIterType typesys subclass; low-priority follow-up
|
|
517
|
+
# while the adapter list stays tiny.
|
|
518
|
+
if isinstance(ret, SelfType) and "Self" in type_subst:
|
|
519
|
+
ret = type_subst["Self"]
|
|
520
|
+
if isinstance(ret, TypeParamRef) and ret.name in type_subst:
|
|
521
|
+
ret = type_subst[ret.name]
|
|
522
|
+
if isinstance(ret, OwnType):
|
|
523
|
+
ret = ret.wrapped
|
|
524
|
+
|
|
525
|
+
# SpanIter[T] -- known NativeIterable with element type T
|
|
526
|
+
if is_span_iter(ret):
|
|
527
|
+
elem = ret.type_args[0]
|
|
528
|
+
if isinstance(elem, TypeParamRef) and elem.name in type_subst:
|
|
529
|
+
elem = type_subst[elem.name]
|
|
530
|
+
return elem
|
|
531
|
+
|
|
532
|
+
# Iterator[T] protocol return type (not Iterable -- codegen emits
|
|
533
|
+
# .__next__() directly, which requires Iterator, not Iterable).
|
|
534
|
+
# Recursively substitute type params in compound element types so
|
|
535
|
+
# that e.g. dict_items.__iter__() -> Iterator[tuple[K, V]] yields
|
|
536
|
+
# tuple[str, Point] when instantiated as dict_items[str, Point].
|
|
537
|
+
if (allow_protocol_return
|
|
538
|
+
and is_protocol_type(ret) and isinstance(ret, NominalType)
|
|
539
|
+
and ret.qualified_name() == "typing.Iterator" and ret.type_args):
|
|
540
|
+
elem = ret.type_args[0]
|
|
541
|
+
if type_subst:
|
|
542
|
+
try:
|
|
543
|
+
# Successful resolution settles the element type even when
|
|
544
|
+
# it resolves to another type param: iterating Span[T] in
|
|
545
|
+
# a generic body yields T, a valid in-scope element type
|
|
546
|
+
# (parallel to args[0] indexing). Only an unresolved param
|
|
547
|
+
# (ValueError) means the element is genuinely unknown here.
|
|
548
|
+
return _resolve_type_or_param(elem, type_subst)
|
|
549
|
+
except ValueError:
|
|
550
|
+
pass
|
|
551
|
+
elif not isinstance(elem, TypeParamRef):
|
|
552
|
+
# No substitution context: a bare type param is meaningless.
|
|
553
|
+
return elem
|
|
554
|
+
|
|
555
|
+
# User-defined iterator with error_return __next__
|
|
556
|
+
if isinstance(ret, NominalType) and ret.is_user_record:
|
|
557
|
+
iter_type_args = ret.type_args
|
|
558
|
+
if iter_type_args and type_subst:
|
|
559
|
+
iter_type_args = [
|
|
560
|
+
type_subst.get(a.name, a) if isinstance(a, TypeParamRef) else a
|
|
561
|
+
for a in iter_type_args
|
|
562
|
+
]
|
|
563
|
+
elem = _find_error_return_next_element(ret.name, iter_type_args, registry)
|
|
564
|
+
if elem is not None:
|
|
565
|
+
return elem
|
|
566
|
+
|
|
567
|
+
return None
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def get_span_element_type(tpy_type: "TpyType", registry: "TypeRegistry") -> "TpyType | None":
|
|
571
|
+
"""If type has __span__() -> Span[T] or Span[readonly[T]], return element type T."""
|
|
572
|
+
span_type = get_span_return_type(tpy_type, registry)
|
|
573
|
+
if span_type is not None:
|
|
574
|
+
from tpyc.typesys import unwrap_readonly
|
|
575
|
+
return unwrap_readonly(span_type.type_args[0])
|
|
576
|
+
return None
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def get_span_return_type(tpy_type: "TpyType", registry: "TypeRegistry") -> "NominalType | None":
|
|
580
|
+
"""If type has __span__() -> Span[T] or Span[readonly[T]], return the full Span NominalType."""
|
|
581
|
+
from tpyc.typesys import NominalType, TypeParamRef
|
|
582
|
+
|
|
583
|
+
if isinstance(tpy_type, NominalType) and tpy_type.is_user_record:
|
|
584
|
+
record = registry.get_record(tpy_type.name)
|
|
585
|
+
else:
|
|
586
|
+
# Builtin types (list, Array, Span, etc.)
|
|
587
|
+
record = registry.get_record_for_type(tpy_type)
|
|
588
|
+
if record is None:
|
|
589
|
+
return None
|
|
590
|
+
type_subst: dict[str, "TpyType"] = {}
|
|
591
|
+
if record.type_params and isinstance(tpy_type, NominalType) and tpy_type.type_args:
|
|
592
|
+
type_subst = dict(zip(record.type_params, tpy_type.type_args))
|
|
593
|
+
return _find_span_method_return_type(record, type_subst, registry)
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
def _find_span_method_return_type(
|
|
597
|
+
record: "RecordInfo", type_subst: "dict[str, TpyType]", registry: "TypeRegistry",
|
|
598
|
+
) -> "NominalType | None":
|
|
599
|
+
"""Check if record has __span__() returning Span[T]/Span[readonly[T]], and return the Span NominalType."""
|
|
600
|
+
from tpyc.typesys import NominalType, TypeParamRef, make_span
|
|
601
|
+
|
|
602
|
+
for method in record.get_method_overloads("__span__"):
|
|
603
|
+
if len(method.params) != 0:
|
|
604
|
+
continue
|
|
605
|
+
ret = method.return_type
|
|
606
|
+
if isinstance(ret, TypeParamRef) and ret.name in type_subst:
|
|
607
|
+
ret = type_subst[ret.name]
|
|
608
|
+
if is_span(ret):
|
|
609
|
+
# Use inner element (unwrapped) for TypeParamRef resolution,
|
|
610
|
+
# then reconstruct with the original readonly-ness.
|
|
611
|
+
from tpyc.typesys import unwrap_readonly, is_readonly_span
|
|
612
|
+
elem = unwrap_readonly(ret.type_args[0])
|
|
613
|
+
if isinstance(elem, TypeParamRef) and elem.name in type_subst:
|
|
614
|
+
elem = type_subst[elem.name]
|
|
615
|
+
return make_span(elem, is_readonly=is_readonly_span(ret))
|
|
616
|
+
|
|
617
|
+
# Walk each parent chain (first match wins)
|
|
618
|
+
for parent in record.parents:
|
|
619
|
+
if not (isinstance(parent, NominalType) and parent.is_user_record):
|
|
620
|
+
continue
|
|
621
|
+
parent_info = registry.get_record(parent.name)
|
|
622
|
+
if parent_info is None:
|
|
623
|
+
continue
|
|
624
|
+
parent_subst = _compose_parent_subst(parent, parent_info, type_subst)
|
|
625
|
+
result = _find_span_method_return_type(parent_info, parent_subst, registry)
|
|
626
|
+
if result is not None:
|
|
627
|
+
return result
|
|
628
|
+
|
|
629
|
+
return None
|