tpy-lang 0.3.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
- tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
- tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
- tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
- tpyc/__init__.py +104 -0
- tpyc/__main__.py +6 -0
- tpyc/_buildinfo.py +1 -0
- tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
- tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
- tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
- tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
- tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
- tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
- tpyc/_data/lib/tpy/_functools_macros.py +80 -0
- tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
- tpyc/_data/lib/tpy/argparse.py +2062 -0
- tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
- tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
- tpyc/_data/lib/tpy/base64.py +410 -0
- tpyc/_data/lib/tpy/bisect.py +39 -0
- tpyc/_data/lib/tpy/builtins.py +38 -0
- tpyc/_data/lib/tpy/dataclasses.py +354 -0
- tpyc/_data/lib/tpy/enum.py +23 -0
- tpyc/_data/lib/tpy/functools.py +33 -0
- tpyc/_data/lib/tpy/hashlib.py +206 -0
- tpyc/_data/lib/tpy/heapq.py +118 -0
- tpyc/_data/lib/tpy/io.py +395 -0
- tpyc/_data/lib/tpy/json.py +221 -0
- tpyc/_data/lib/tpy/math.py +406 -0
- tpyc/_data/lib/tpy/random.py +597 -0
- tpyc/_data/lib/tpy/re.py +467 -0
- tpyc/_data/lib/tpy/socket.py +379 -0
- tpyc/_data/lib/tpy/struct.py +178 -0
- tpyc/_data/lib/tpy/sys.py +40 -0
- tpyc/_data/lib/tpy/time.py +39 -0
- tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
- tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
- tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
- tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
- tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
- tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
- tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
- tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
- tpyc/_data/lib/tpy/tpy/_version.py +29 -0
- tpyc/_data/lib/tpy/tpy/bits.py +28 -0
- tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
- tpyc/_data/lib/tpy/tpy/extern.py +8 -0
- tpyc/_data/lib/tpy/tpy/mem.py +49 -0
- tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
- tpyc/_data/lib/tpy/tpy/version.py +21 -0
- tpyc/_data/lib/tpy/typing.py +13 -0
- tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
- tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
- tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
- tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
- tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
- tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
- tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
- tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
- tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
- tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
- tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
- tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
- tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
- tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
- tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
- tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
- tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
- tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
- tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
- tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
- tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
- tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
- tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
- tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
- tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
- tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
- tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
- tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
- tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
- tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
- tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
- tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
- tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
- tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
- tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
- tpyc/_data/runtime/cpp/third_party/README.md +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
- tpyc/build/__init__.py +7 -0
- tpyc/build/pcre2.py +122 -0
- tpyc/build/third_party.py +413 -0
- tpyc/cli.py +822 -0
- tpyc/codegen_cpp/__init__.py +18 -0
- tpyc/codegen_cpp/builtins.py +484 -0
- tpyc/codegen_cpp/context.py +2064 -0
- tpyc/codegen_cpp/expressions.py +5940 -0
- tpyc/codegen_cpp/functions.py +1913 -0
- tpyc/codegen_cpp/gen_async.py +3258 -0
- tpyc/codegen_cpp/gen_generators.py +657 -0
- tpyc/codegen_cpp/generator.py +2258 -0
- tpyc/codegen_cpp/match.py +1997 -0
- tpyc/codegen_cpp/param_const.py +172 -0
- tpyc/codegen_cpp/protocols.py +907 -0
- tpyc/codegen_cpp/records.py +1654 -0
- tpyc/codegen_cpp/resumable_cfg.py +1651 -0
- tpyc/codegen_cpp/statements.py +4963 -0
- tpyc/codegen_cpp/string_dispatch.py +76 -0
- tpyc/codegen_cpp/test_context.py +46 -0
- tpyc/codegen_cpp/test_param_const.py +113 -0
- tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
- tpyc/codegen_cpp/type_resolution.py +53 -0
- tpyc/codegen_cpp/types.py +436 -0
- tpyc/codegen_cpp/variant_access.py +135 -0
- tpyc/coercions.py +749 -0
- tpyc/compilation_context.py +57 -0
- tpyc/compiler.py +3945 -0
- tpyc/cycle_detection.py +358 -0
- tpyc/diagnostics.py +135 -0
- tpyc/dump_types.py +353 -0
- tpyc/frontend_diagnostics.py +47 -0
- tpyc/frontend_ir/__init__.py +140 -0
- tpyc/frontend_ir/lower.py +1098 -0
- tpyc/frontend_ir/nodes.py +718 -0
- tpyc/frontend_ir/resolver_adapter.py +151 -0
- tpyc/frontend_plugin.py +209 -0
- tpyc/install_docs.py +81 -0
- tpyc/liveness.py +756 -0
- tpyc/macro_api.py +1724 -0
- tpyc/macro_loader.py +497 -0
- tpyc/module_names.py +64 -0
- tpyc/modules/__init__.py +31 -0
- tpyc/modules/defs.py +89 -0
- tpyc/modules/registry.py +36 -0
- tpyc/modules/resolver.py +192 -0
- tpyc/modules/type_resolution.py +629 -0
- tpyc/namespace.py +172 -0
- tpyc/parse/__init__.py +84 -0
- tpyc/parse/imports.py +490 -0
- tpyc/parse/nodes.py +1732 -0
- tpyc/parse/parser.py +4043 -0
- tpyc/parse/resolve_refs.py +466 -0
- tpyc/parse/type_resolver.py +1060 -0
- tpyc/prescan.py +254 -0
- tpyc/qnames.py +149 -0
- tpyc/repl.py +529 -0
- tpyc/repl_backends.py +848 -0
- tpyc/sema/__init__.py +21 -0
- tpyc/sema/analyzer.py +3625 -0
- tpyc/sema/bound_check.py +72 -0
- tpyc/sema/builder_trace.py +684 -0
- tpyc/sema/calls.py +5406 -0
- tpyc/sema/compatibility.py +2107 -0
- tpyc/sema/context.py +1243 -0
- tpyc/sema/expressions.py +3737 -0
- tpyc/sema/flow_facts.py +199 -0
- tpyc/sema/init_tracker.py +150 -0
- tpyc/sema/list_literals.py +69 -0
- tpyc/sema/literal_utils.py +27 -0
- tpyc/sema/local_deduction.py +1088 -0
- tpyc/sema/macros.py +179 -0
- tpyc/sema/match.py +1177 -0
- tpyc/sema/method_expansion.py +347 -0
- tpyc/sema/methods.py +2197 -0
- tpyc/sema/mutation_propagation.py +268 -0
- tpyc/sema/narrowing.py +857 -0
- tpyc/sema/numeric_lattice.py +160 -0
- tpyc/sema/operators.py +402 -0
- tpyc/sema/overloads.py +841 -0
- tpyc/sema/protocols.py +1209 -0
- tpyc/sema/reach_analysis.py +202 -0
- tpyc/sema/registration.py +3156 -0
- tpyc/sema/scope_tracker.py +193 -0
- tpyc/sema/statements.py +4426 -0
- tpyc/sema/type_ops.py +1879 -0
- tpyc/sema/value_range.py +181 -0
- tpyc/symbol_binding.py +259 -0
- tpyc/test_c3_mro.py +208 -0
- tpyc/test_cli_argv.py +52 -0
- tpyc/test_compiler.py +559 -0
- tpyc/test_contains_type_param.py +101 -0
- tpyc/test_cycle_detection.py +221 -0
- tpyc/test_dump_types.py +225 -0
- tpyc/test_install_docs.py +65 -0
- tpyc/test_local_cpp_form.py +135 -0
- tpyc/test_macro_loader.py +76 -0
- tpyc/test_method_expansion.py +254 -0
- tpyc/test_nominal_identity.py +182 -0
- tpyc/test_overloads.py +410 -0
- tpyc/test_parse.py +303 -0
- tpyc/test_parse_type_ref.py +506 -0
- tpyc/test_parse_version_info.py +58 -0
- tpyc/test_reach_analysis.py +72 -0
- tpyc/test_ref_type.py +216 -0
- tpyc/test_send_sync_substitution.py +276 -0
- tpyc/test_tuple_mutation_propagation.py +206 -0
- tpyc/test_type_def_registry.py +1729 -0
- tpyc/test_union_types.py +195 -0
- tpyc/type_def_registry.py +975 -0
- tpyc/typesys.py +5104 -0
tpyc/sema/overloads.py
ADDED
|
@@ -0,0 +1,841 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Shared Overload Resolution
|
|
3
|
+
|
|
4
|
+
Unified type matching and overload resolution used across
|
|
5
|
+
operators, calls, methods, and module infrastructure.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from dataclasses import replace as dc_replace
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import TYPE_CHECKING, Callable
|
|
12
|
+
|
|
13
|
+
from ..typesys import (
|
|
14
|
+
TpyType, IntLiteralType, FloatLiteralType, BIGINT,
|
|
15
|
+
TypeParamRef, TypeParamKind, FunctionInfo, is_protocol_type, unwrap_readonly,
|
|
16
|
+
PendingStrType, PendingViewType, LiteralType, LiteralTag,
|
|
17
|
+
PendingBytesType, TupleType, UnknownElementType,
|
|
18
|
+
NominalType, PtrType, OwnType, ReadonlyType, RefType, CallableType, is_fn_type, VoidType, NoneType,
|
|
19
|
+
OptionalType,
|
|
20
|
+
unwrap_ref_type,
|
|
21
|
+
is_callable_type, is_float_type, is_integer_type, is_any_float_type,
|
|
22
|
+
contains_type_param,
|
|
23
|
+
)
|
|
24
|
+
from ..type_def_registry import (
|
|
25
|
+
is_fixed_int_type, is_big_int_type, is_bool_type,
|
|
26
|
+
is_str_type, is_bytes_type, is_str_category, is_bytes_category,
|
|
27
|
+
int_traits_of,
|
|
28
|
+
)
|
|
29
|
+
from ..coercions import resolve_coercion, CoercionContext
|
|
30
|
+
from .protocols import ProtocolConformanceKind
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from .type_ops import TypeOperations
|
|
34
|
+
ProtocolChecker = Callable[[TpyType, TpyType], bool]
|
|
35
|
+
ProtocolClassifier = Callable[[TpyType, TpyType], 'ProtocolConformanceKind | None']
|
|
36
|
+
DerefChecker = Callable[[TpyType], TpyType | None]
|
|
37
|
+
SubclassChecker = Callable[['NominalType', 'NominalType'], bool]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MatchTier(Enum):
|
|
41
|
+
"""Specificity of a strict-pass overload match.
|
|
42
|
+
|
|
43
|
+
The integer ``value`` is the rank (lower = more specific) and doubles as
|
|
44
|
+
an index into the per-tier count array in ``_score``. Not an ``IntEnum``
|
|
45
|
+
so that stray int arithmetic or ``tier == 1`` comparisons don't silently
|
|
46
|
+
type-check.
|
|
47
|
+
"""
|
|
48
|
+
EXACT_CONCRETE = 1 # arg_inner == param_inner (or nominal-adjacent: IntLit->FixedInt, NoneType->Void, Callable->Fn, ...)
|
|
49
|
+
EXACT_GENERIC_SHAPE = 2 # generic param with concrete outer shape: list[T] vs list[Int32]
|
|
50
|
+
PROTOCOL_EXPLICIT = 3 # protocol conformance via classify_protocol_conformance -> EXPLICIT
|
|
51
|
+
PROTOCOL_STRUCTURAL = 4 # protocol conformance via classify_protocol_conformance -> STRUCTURAL
|
|
52
|
+
GENERIC_PROTOCOL_EXPLICIT = 5 # generic over protocol param, explicit conformance
|
|
53
|
+
GENERIC_PROTOCOL_STRUCTURAL = 6 # generic over protocol param, structural conformance
|
|
54
|
+
GENERIC_WILDCARD = 7 # bare T / unconstrained generic
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_NUM_MATCH_TIERS = len(MatchTier)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# MatchTier enum is 1-indexed (EXACT_CONCRETE = 1), so score vectors drop slot 0.
|
|
61
|
+
_TIER_COUNTS_SIZE = _NUM_MATCH_TIERS + 1
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class OverloadAmbiguityError(Exception):
|
|
65
|
+
"""Raised by ``resolve_overload`` when multiple candidates tie at the top
|
|
66
|
+
of first-pass ranking (same tier counts, same widening cost, distinct
|
|
67
|
+
signatures).
|
|
68
|
+
|
|
69
|
+
Callers with source-location context should catch this and re-raise as a
|
|
70
|
+
proper ``SemanticError`` so the user sees the call site, not a bare
|
|
71
|
+
traceback. Uncaught, the exception still carries the tied candidates so
|
|
72
|
+
the default message is actionable.
|
|
73
|
+
"""
|
|
74
|
+
def __init__(self, candidates: tuple[FunctionInfo, ...]):
|
|
75
|
+
self.candidates = candidates
|
|
76
|
+
sigs = ", ".join(
|
|
77
|
+
f"{c.name}({', '.join(str(p.type) for p in c.params)})"
|
|
78
|
+
for c in candidates
|
|
79
|
+
)
|
|
80
|
+
super().__init__(f"Ambiguous overload: {sigs}")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _always_false_checker(arg: 'TpyType', param: 'TpyType') -> bool:
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _score(per_arg: tuple[tuple[MatchTier, int], ...]) -> tuple[tuple[int, ...], int]:
|
|
88
|
+
"""Score a per-arg tier vector: lower is better.
|
|
89
|
+
|
|
90
|
+
Primary key is aggregate tier counts (higher tier-count at the strongest
|
|
91
|
+
tier wins); secondary key is total widening cost so same-tier candidates
|
|
92
|
+
prefer the narrowest widening.
|
|
93
|
+
"""
|
|
94
|
+
counts = [0] * _TIER_COUNTS_SIZE
|
|
95
|
+
total_cost = 0
|
|
96
|
+
for tier, cost in per_arg:
|
|
97
|
+
counts[tier.value] += 1
|
|
98
|
+
total_cost += cost
|
|
99
|
+
return (tuple(-c for c in counts[1:]), total_cost)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _structural_match(arg: TpyType, param: TpyType) -> bool:
|
|
103
|
+
"""Structural match with TypeParamRef as wildcard."""
|
|
104
|
+
if isinstance(param, TypeParamRef):
|
|
105
|
+
return True
|
|
106
|
+
# Unwrap Ref, Own, Readonly from both sides (transparent for matching)
|
|
107
|
+
arg = unwrap_ref_type(arg)
|
|
108
|
+
param = unwrap_ref_type(param)
|
|
109
|
+
if isinstance(param, TypeParamRef):
|
|
110
|
+
return True
|
|
111
|
+
if isinstance(arg, OwnType):
|
|
112
|
+
arg = arg.wrapped
|
|
113
|
+
if isinstance(param, ReadonlyType):
|
|
114
|
+
return _structural_match(unwrap_readonly(arg), param.wrapped)
|
|
115
|
+
arg = unwrap_readonly(arg)
|
|
116
|
+
# Callable -> Fn: structurally compatible callable types
|
|
117
|
+
if isinstance(arg, CallableType) and is_fn_type(param):
|
|
118
|
+
if len(arg.param_types) != len(param.param_types):
|
|
119
|
+
return False
|
|
120
|
+
return (all(_structural_match(a, p) for a, p in zip(arg.param_types, param.param_types))
|
|
121
|
+
and _structural_match(arg.return_type, param.return_type))
|
|
122
|
+
# None literal (NoneType) matches None annotation (VoidType)
|
|
123
|
+
if isinstance(arg, NoneType) and isinstance(param, VoidType):
|
|
124
|
+
return True
|
|
125
|
+
if type(arg) != type(param):
|
|
126
|
+
return False
|
|
127
|
+
# Post-Phase-D all containers/primitives/records are NominalType; type()
|
|
128
|
+
# equality alone passes list[Int32] vs set[Int32]. Require matching name
|
|
129
|
+
# so structural recursion only fires for same-kind NominalType pairs.
|
|
130
|
+
if isinstance(arg, NominalType) and arg.name != param.name:
|
|
131
|
+
return False
|
|
132
|
+
# PtrType: readonly arg cannot match mutable param (would drop const)
|
|
133
|
+
if isinstance(arg, PtrType) and isinstance(param, PtrType):
|
|
134
|
+
if arg.is_readonly and not param.is_readonly:
|
|
135
|
+
return False
|
|
136
|
+
arg_inners = list(arg.inner_types())
|
|
137
|
+
param_inners = list(param.inner_types())
|
|
138
|
+
if len(arg_inners) != len(param_inners):
|
|
139
|
+
return False
|
|
140
|
+
if not arg_inners:
|
|
141
|
+
return arg == param
|
|
142
|
+
return all(_structural_match(a, p) for a, p in zip(arg_inners, param_inners))
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _scalar_widening_cost(
|
|
146
|
+
actual: TpyType,
|
|
147
|
+
expected: TpyType,
|
|
148
|
+
default_int_type: TpyType | None = None,
|
|
149
|
+
) -> int:
|
|
150
|
+
"""Cost of widening ``actual`` to ``expected`` for a single type slot.
|
|
151
|
+
|
|
152
|
+
Returns 0 when the types are identical and a positive distance when
|
|
153
|
+
``actual`` widens to ``expected``. Used as a secondary sort key inside a
|
|
154
|
+
match tier so that e.g. ``list[Int32]`` prefers ``Iterable[Int32]`` over
|
|
155
|
+
``Iterable[Int64]`` / ``Iterable[int]`` / ``Iterable[float]``.
|
|
156
|
+
|
|
157
|
+
``IntLiteralType`` ranks as the ``default_int_type`` would (so a list of
|
|
158
|
+
``int`` literals under ``default_int=Int32`` scores ``Iterable[Int32]``
|
|
159
|
+
exactly like ``list[Int32]`` does). When ``default_int_type`` is None,
|
|
160
|
+
IntLiteral comparisons fall back to the generic cross-type distance.
|
|
161
|
+
"""
|
|
162
|
+
if actual == expected:
|
|
163
|
+
return 0
|
|
164
|
+
# IntLiteralType and UnknownElementType (empty-list literal): compute cost
|
|
165
|
+
# as if widening from default_int_type. This matches the CPython
|
|
166
|
+
# convention that ``sum([]) == 0`` (int) regardless of which numeric
|
|
167
|
+
# overload is declared first in the stdlib.
|
|
168
|
+
if isinstance(actual, (IntLiteralType, UnknownElementType)):
|
|
169
|
+
if default_int_type is None:
|
|
170
|
+
return 1
|
|
171
|
+
if expected == default_int_type:
|
|
172
|
+
return 0
|
|
173
|
+
return _scalar_widening_cost(default_int_type, expected, default_int_type)
|
|
174
|
+
a_tr = int_traits_of(actual)
|
|
175
|
+
e_tr = int_traits_of(expected)
|
|
176
|
+
if a_tr is not None and e_tr is not None:
|
|
177
|
+
# Fixed-int -> fixed-int: bit-width gap, plus a small sign-flip penalty
|
|
178
|
+
# so e.g. Int32 -> Int64 beats Int32 -> UInt64.
|
|
179
|
+
gap = max(0, (e_tr.bits - a_tr.bits)) // 8
|
|
180
|
+
sign_penalty = 1 if a_tr.signed != e_tr.signed else 0
|
|
181
|
+
return max(1, gap) + sign_penalty
|
|
182
|
+
if a_tr is not None and is_big_int_type(expected):
|
|
183
|
+
return 8
|
|
184
|
+
if a_tr is not None and is_any_float_type(expected):
|
|
185
|
+
return 16
|
|
186
|
+
if is_any_float_type(actual) and is_any_float_type(expected):
|
|
187
|
+
return 1
|
|
188
|
+
# Unknown shape -- treat as a single widening step.
|
|
189
|
+
return 1
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _type_args_widening_cost(
|
|
193
|
+
actual: TpyType,
|
|
194
|
+
param: NominalType,
|
|
195
|
+
default_int_type: TpyType | None = None,
|
|
196
|
+
) -> int:
|
|
197
|
+
"""Aggregate widening cost between ``actual``'s and ``param``'s type args.
|
|
198
|
+
|
|
199
|
+
Caller has already confirmed ``actual`` conforms to ``param``. Walks the
|
|
200
|
+
type-arg tuples pairwise when they line up; for single-element protocols
|
|
201
|
+
also falls back to ``actual.get_element_type()`` so non-parameterised
|
|
202
|
+
containers (``bytes``/``bytearray`` -> ``Iterable[UInt8]``) can be scored
|
|
203
|
+
by their baked-in element type. Returns 0 when no type-arg information
|
|
204
|
+
is available.
|
|
205
|
+
"""
|
|
206
|
+
if not isinstance(param, NominalType) or not param.type_args:
|
|
207
|
+
return 0
|
|
208
|
+
actual_args: tuple[TpyType, ...] = ()
|
|
209
|
+
if isinstance(actual, NominalType):
|
|
210
|
+
actual_args = tuple(a for a in actual.type_args if isinstance(a, TpyType))
|
|
211
|
+
elif isinstance(actual, TupleType):
|
|
212
|
+
# Tuples collapse to a protocol over a single element type only when
|
|
213
|
+
# all elements are identical; otherwise element-level widening is
|
|
214
|
+
# not well-defined here.
|
|
215
|
+
if actual.element_types and all(t == actual.element_types[0] for t in actual.element_types):
|
|
216
|
+
actual_args = (actual.element_types[0],)
|
|
217
|
+
# Fallback for single-element protocols where the actual's element type
|
|
218
|
+
# isn't directly visible in type_args -- non-parameterised containers
|
|
219
|
+
# (bytes/bytearray -> UInt8) and PendingListType expose it via
|
|
220
|
+
# get_element_type().
|
|
221
|
+
if not actual_args and len(param.type_args) == 1 and hasattr(actual, 'get_element_type'):
|
|
222
|
+
elem = actual.get_element_type()
|
|
223
|
+
if elem is not None:
|
|
224
|
+
actual_args = (elem,)
|
|
225
|
+
if len(actual_args) != len(param.type_args):
|
|
226
|
+
return 0
|
|
227
|
+
total = 0
|
|
228
|
+
for a, p in zip(actual_args, param.type_args):
|
|
229
|
+
if not isinstance(p, TpyType):
|
|
230
|
+
continue
|
|
231
|
+
total += _scalar_widening_cost(a, p, default_int_type)
|
|
232
|
+
return total
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _classify_strict_match(
|
|
236
|
+
arg_type: TpyType,
|
|
237
|
+
param_type: TpyType,
|
|
238
|
+
protocol_classifier: ProtocolClassifier | None = None,
|
|
239
|
+
default_int_type: TpyType | None = None,
|
|
240
|
+
) -> tuple[MatchTier, int] | None:
|
|
241
|
+
"""Strict (no-coercion) match with specificity tier + widening cost.
|
|
242
|
+
|
|
243
|
+
Returns ``(tier, cost)`` on success, ``None`` otherwise. ``cost`` is 0
|
|
244
|
+
for exact element-type matches and grows with widening distance (used as
|
|
245
|
+
a secondary sort key by ``resolve_overload_result``).
|
|
246
|
+
"""
|
|
247
|
+
# Unwrap ReadonlyType, OwnType, RefType -- these are ownership/ref
|
|
248
|
+
# qualifiers transparent for overload matching.
|
|
249
|
+
arg_inner = unwrap_ref_type(unwrap_readonly(arg_type))
|
|
250
|
+
if isinstance(arg_inner, OwnType):
|
|
251
|
+
arg_inner = arg_inner.wrapped
|
|
252
|
+
param_inner = unwrap_ref_type(unwrap_readonly(param_type))
|
|
253
|
+
if isinstance(param_inner, OwnType):
|
|
254
|
+
param_inner = param_inner.wrapped
|
|
255
|
+
if arg_inner == param_inner:
|
|
256
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
257
|
+
# CallableType (Fn and Callable): compare with qualifier unwrapping on inner
|
|
258
|
+
# types. The arg callable may have Own/Ref on param/return types from FI,
|
|
259
|
+
# while the resolved overload's callable has bare types from substitution.
|
|
260
|
+
if (is_callable_type(arg_inner)
|
|
261
|
+
and is_callable_type(param_inner)
|
|
262
|
+
and len(arg_inner.param_types) == len(param_inner.param_types)):
|
|
263
|
+
def _strip(t: TpyType) -> TpyType:
|
|
264
|
+
t = unwrap_ref_type(t)
|
|
265
|
+
if isinstance(t, OwnType): t = t.wrapped
|
|
266
|
+
if isinstance(t, PendingViewType): t = t.family.owned_type
|
|
267
|
+
return t
|
|
268
|
+
if (all(_strip(a) == _strip(p) for a, p in zip(arg_inner.param_types, param_inner.param_types))
|
|
269
|
+
and _strip(arg_inner.return_type) == _strip(param_inner.return_type)):
|
|
270
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
271
|
+
# IntLiteralType matches the specific fixed-width int it was inferred to (from
|
|
272
|
+
# generic resolution). This allows resolved-generic overloads like
|
|
273
|
+
# range(stop: Int32) to match IntLiteralType(5) in the first pass.
|
|
274
|
+
# Cost ranks by widening distance from default_int_type so str(IntLiteralType)
|
|
275
|
+
# picks the default-width overload (Int32) over the smallest-fitting one
|
|
276
|
+
# (Int8) when multiple fixed-int overloads accept the value.
|
|
277
|
+
if isinstance(arg_inner, IntLiteralType) and is_fixed_int_type(param_inner):
|
|
278
|
+
tr = int_traits_of(param_inner)
|
|
279
|
+
if arg_inner.value is None or tr.min_value <= arg_inner.value <= tr.max_value:
|
|
280
|
+
return (MatchTier.EXACT_CONCRETE,
|
|
281
|
+
_scalar_widening_cost(arg_inner, param_inner, default_int_type))
|
|
282
|
+
# None literal (NoneType) matches None type annotation (VoidType)
|
|
283
|
+
if isinstance(arg_inner, NoneType) and isinstance(param_inner, VoidType):
|
|
284
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
285
|
+
# T -> Optional[T] and None -> Optional[T]
|
|
286
|
+
if isinstance(param_inner, OptionalType):
|
|
287
|
+
if isinstance(arg_inner, NoneType):
|
|
288
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
289
|
+
return _classify_strict_match(arg_inner, param_inner.inner, protocol_classifier, default_int_type)
|
|
290
|
+
# Callable -> Fn: std::function satisfies template requires clauses
|
|
291
|
+
if (isinstance(arg_inner, CallableType) and is_fn_type(param_inner)
|
|
292
|
+
and arg_inner.param_types == param_inner.param_types
|
|
293
|
+
and (arg_inner.return_type == param_inner.return_type
|
|
294
|
+
or isinstance(param_inner.return_type, VoidType))):
|
|
295
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
296
|
+
# PendingViewType: same-family pending types match each other and their resolved types
|
|
297
|
+
if isinstance(arg_inner, PendingViewType) and isinstance(param_inner, PendingViewType):
|
|
298
|
+
if arg_inner.family is param_inner.family:
|
|
299
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
300
|
+
if isinstance(arg_inner, PendingStrType) and is_str_type(param_inner):
|
|
301
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
302
|
+
# Single-value LiteralType matches multi-value LiteralType if value is in the set.
|
|
303
|
+
# Only in strict pass -- LiteralType -> base type is deferred to coercion pass
|
|
304
|
+
# so that Literal stubs are preferred over plain stubs regardless of order.
|
|
305
|
+
if isinstance(arg_inner, LiteralType) and isinstance(param_inner, LiteralType):
|
|
306
|
+
return ((MatchTier.EXACT_CONCRETE, 0)
|
|
307
|
+
if all(v in param_inner.values for v in arg_inner.values) else None)
|
|
308
|
+
# IntLiteralType matches LiteralType with int base if value is in the set.
|
|
309
|
+
if isinstance(arg_inner, IntLiteralType) and isinstance(param_inner, LiteralType) and param_inner.is_int_base():
|
|
310
|
+
if arg_inner.value is not None and param_inner.contains(LiteralTag.INT, arg_inner.value):
|
|
311
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
312
|
+
return None
|
|
313
|
+
# PendingBytesType (unresolved bytes local) matches bytes params
|
|
314
|
+
if isinstance(arg_inner, PendingBytesType) and is_bytes_type(param_inner):
|
|
315
|
+
return (MatchTier.EXACT_CONCRETE, 0)
|
|
316
|
+
if protocol_classifier is not None and is_protocol_type(param_inner):
|
|
317
|
+
# Unwrap Own[T] from arg -- copy()-wrapped return values should still match
|
|
318
|
+
# plain protocol params (Own is a caller-side ownership marker, not a new type).
|
|
319
|
+
check_arg = arg_inner.wrapped if isinstance(arg_inner, OwnType) else arg_inner
|
|
320
|
+
# Strip Own[T] wrappers from protocol type args so that e.g.
|
|
321
|
+
# list[Node] matches Iterable[Own[Node]] for protocol conformance.
|
|
322
|
+
check_param = param_inner
|
|
323
|
+
if (isinstance(param_inner, NominalType) and param_inner.type_args
|
|
324
|
+
and any(isinstance(a, OwnType) for a in param_inner.type_args)):
|
|
325
|
+
stripped = tuple(a.wrapped if isinstance(a, OwnType) else a for a in param_inner.type_args)
|
|
326
|
+
check_param = dc_replace(param_inner, type_args=stripped)
|
|
327
|
+
kind = protocol_classifier(check_arg, check_param)
|
|
328
|
+
if kind is ProtocolConformanceKind.EXPLICIT:
|
|
329
|
+
return (MatchTier.PROTOCOL_EXPLICIT,
|
|
330
|
+
_type_args_widening_cost(check_arg, check_param, default_int_type))
|
|
331
|
+
if kind is ProtocolConformanceKind.STRUCTURAL:
|
|
332
|
+
return (MatchTier.PROTOCOL_STRUCTURAL, 0)
|
|
333
|
+
return None
|
|
334
|
+
# Non-protocol NominalType with Own[T] in type args: strip Own for overload matching.
|
|
335
|
+
# Applies to any concrete container (e.g. dict[K, Own[V]]) not just DictType.
|
|
336
|
+
# Copy warnings are emitted later by check_type_compatible.
|
|
337
|
+
if (isinstance(param_inner, NominalType) and not is_protocol_type(param_inner)
|
|
338
|
+
and any(isinstance(a, OwnType) for a in param_inner.inner_types())):
|
|
339
|
+
stripped_inner = tuple(a.wrapped if isinstance(a, OwnType) else a for a in param_inner.inner_types())
|
|
340
|
+
stripped_param = param_inner.with_inner_types(stripped_inner)
|
|
341
|
+
return (MatchTier.EXACT_CONCRETE, 0) if arg_inner == stripped_param else None
|
|
342
|
+
return None
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _bool_checker_to_classifier(
|
|
346
|
+
protocol_checker: ProtocolChecker | None,
|
|
347
|
+
) -> ProtocolClassifier | None:
|
|
348
|
+
"""Wrap a bool ``protocol_checker`` as a classifier.
|
|
349
|
+
|
|
350
|
+
Callers outside ``resolve_overload`` only have the bool API; conservatively
|
|
351
|
+
report STRUCTURAL on a hit so tier info is never fabricated as EXPLICIT.
|
|
352
|
+
"""
|
|
353
|
+
if protocol_checker is None:
|
|
354
|
+
return None
|
|
355
|
+
def _adapter(arg: TpyType, param: TpyType) -> ProtocolConformanceKind | None:
|
|
356
|
+
return ProtocolConformanceKind.STRUCTURAL if protocol_checker(arg, param) else None
|
|
357
|
+
return _adapter
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def type_matches_strict(
|
|
361
|
+
arg_type: TpyType,
|
|
362
|
+
param_type: TpyType,
|
|
363
|
+
protocol_checker: ProtocolChecker | None = None,
|
|
364
|
+
) -> bool:
|
|
365
|
+
"""Strict type matching: exact equality or protocol conformance.
|
|
366
|
+
|
|
367
|
+
Used for first-pass overload resolution where no coercions are desired.
|
|
368
|
+
"""
|
|
369
|
+
result = _classify_strict_match(
|
|
370
|
+
arg_type, param_type, _bool_checker_to_classifier(protocol_checker)
|
|
371
|
+
)
|
|
372
|
+
return result is not None
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _classify_generic_param_match(
|
|
376
|
+
param_type: TpyType,
|
|
377
|
+
arg_type: TpyType,
|
|
378
|
+
inferred: dict[str, TpyType],
|
|
379
|
+
type_ops: 'TypeOperations',
|
|
380
|
+
protocol_classifier: ProtocolClassifier | None,
|
|
381
|
+
default_int_type: TpyType | None = None,
|
|
382
|
+
) -> tuple[MatchTier, int]:
|
|
383
|
+
"""Tier + widening cost for a generic-overload param with ``TypeParamRef``.
|
|
384
|
+
|
|
385
|
+
Must be called only for params where ``contains_type_param(param_type)``
|
|
386
|
+
is True and ``infer_type_params_for_function`` has already succeeded for the
|
|
387
|
+
whole overload (guaranteeing this param's own inference consistency).
|
|
388
|
+
|
|
389
|
+
Shape taxonomy:
|
|
390
|
+
- Bare ``TypeParamRef`` (possibly wrapped in Ref/Readonly) -> GENERIC_WILDCARD.
|
|
391
|
+
- Protocol with ``TypeParamRef`` in type args -> GENERIC_PROTOCOL_EXPLICIT
|
|
392
|
+
or GENERIC_PROTOCOL_STRUCTURAL (fall back to STRUCTURAL if no classifier).
|
|
393
|
+
- Anything else (concrete outer shape: ``list[T]``, ``tuple[T, T]``,
|
|
394
|
+
``Ptr[T]``, user record with T slot, ...) -> EXACT_GENERIC_SHAPE.
|
|
395
|
+
|
|
396
|
+
Cost is 0 except for protocol matches where arg type args widen to the
|
|
397
|
+
substituted protocol type args.
|
|
398
|
+
"""
|
|
399
|
+
inspect = param_type
|
|
400
|
+
while isinstance(inspect, (RefType, ReadonlyType)):
|
|
401
|
+
inspect = inspect.wrapped
|
|
402
|
+
if isinstance(inspect, TypeParamRef):
|
|
403
|
+
return (MatchTier.GENERIC_WILDCARD, 0)
|
|
404
|
+
if is_protocol_type(inspect) and contains_type_param(inspect):
|
|
405
|
+
substituted = type_ops.substitute_types(inspect, inferred)
|
|
406
|
+
check_arg = unwrap_ref_type(unwrap_readonly(arg_type))
|
|
407
|
+
if isinstance(check_arg, OwnType):
|
|
408
|
+
check_arg = check_arg.wrapped
|
|
409
|
+
if protocol_classifier is not None and is_protocol_type(substituted):
|
|
410
|
+
kind = protocol_classifier(check_arg, substituted)
|
|
411
|
+
if kind is ProtocolConformanceKind.EXPLICIT:
|
|
412
|
+
return (MatchTier.GENERIC_PROTOCOL_EXPLICIT,
|
|
413
|
+
_type_args_widening_cost(check_arg, substituted, default_int_type))
|
|
414
|
+
if kind is ProtocolConformanceKind.STRUCTURAL:
|
|
415
|
+
return (MatchTier.GENERIC_PROTOCOL_STRUCTURAL, 0)
|
|
416
|
+
return (MatchTier.GENERIC_PROTOCOL_STRUCTURAL, 0)
|
|
417
|
+
return (MatchTier.EXACT_GENERIC_SHAPE, 0)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def type_matches_numeric(
|
|
421
|
+
arg_type: TpyType,
|
|
422
|
+
param_type: TpyType,
|
|
423
|
+
) -> bool:
|
|
424
|
+
"""Type matching for numeric operators and constructors.
|
|
425
|
+
|
|
426
|
+
Handles IntLiteralType and TypeParamRef(INT) flexibility without
|
|
427
|
+
triggering general type coercions (e.g., Int32->BigInt promotion).
|
|
428
|
+
|
|
429
|
+
- Exact equality
|
|
430
|
+
- IntLiteralType matches IntLiteralType, any fixed-width int, BigInt, float, or Float32
|
|
431
|
+
- INT TypeParamRef matches any fixed-width int or BigInt
|
|
432
|
+
"""
|
|
433
|
+
if arg_type == param_type:
|
|
434
|
+
return True
|
|
435
|
+
if isinstance(arg_type, IntLiteralType):
|
|
436
|
+
if is_fixed_int_type(param_type):
|
|
437
|
+
if arg_type.value is None:
|
|
438
|
+
return True # Unknown value -- can't range-check, allow match
|
|
439
|
+
tr = int_traits_of(param_type)
|
|
440
|
+
return tr.min_value <= arg_type.value <= tr.max_value
|
|
441
|
+
if is_big_int_type(param_type) or isinstance(param_type, IntLiteralType):
|
|
442
|
+
return True
|
|
443
|
+
if is_float_type(param_type):
|
|
444
|
+
return True
|
|
445
|
+
if isinstance(arg_type, FloatLiteralType):
|
|
446
|
+
if is_any_float_type(param_type):
|
|
447
|
+
return True
|
|
448
|
+
if isinstance(arg_type, TypeParamRef) and arg_type.kind == TypeParamKind.INT:
|
|
449
|
+
if is_integer_type(param_type):
|
|
450
|
+
return True
|
|
451
|
+
# T -> Optional[T]: unwrap Optional param and match inner type
|
|
452
|
+
if isinstance(param_type, OptionalType):
|
|
453
|
+
return type_matches_numeric(arg_type, param_type.inner)
|
|
454
|
+
# Recursive container matching: e.g. make_list(IntLiteralType) vs make_list(Int32).
|
|
455
|
+
# Post-Phase-D all builtin containers share the NominalType class, so also
|
|
456
|
+
# require matching name (list vs set etc. would otherwise both pass type()
|
|
457
|
+
# equality and fall into the element-only check).
|
|
458
|
+
if type(arg_type) == type(param_type):
|
|
459
|
+
if isinstance(arg_type, NominalType):
|
|
460
|
+
if arg_type.name != param_type.name:
|
|
461
|
+
return False
|
|
462
|
+
arg_elem = arg_type.get_element_type()
|
|
463
|
+
param_elem = param_type.get_element_type()
|
|
464
|
+
if arg_elem is not None and param_elem is not None:
|
|
465
|
+
return type_matches_numeric(arg_elem, param_elem)
|
|
466
|
+
return False
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def type_matches_with_coercion(
|
|
470
|
+
arg_type: TpyType,
|
|
471
|
+
param_type: TpyType,
|
|
472
|
+
protocol_checker: ProtocolChecker | None = None,
|
|
473
|
+
deref_checker: DerefChecker | None = None,
|
|
474
|
+
subclass_checker: SubclassChecker | None = None,
|
|
475
|
+
) -> bool:
|
|
476
|
+
"""Type matching allowing IntLiteral flexibility, protocols, and registered coercions.
|
|
477
|
+
|
|
478
|
+
Used for overload resolution second pass and constructor matching.
|
|
479
|
+
"""
|
|
480
|
+
# Unwrap ReadonlyType, OwnType, RefType from args -- mutable values match
|
|
481
|
+
# readonly params, Own[T] variables match T params, and Ref[T] is transparent.
|
|
482
|
+
arg_inner = unwrap_ref_type(unwrap_readonly(arg_type))
|
|
483
|
+
if isinstance(arg_inner, OwnType):
|
|
484
|
+
arg_inner = arg_inner.wrapped
|
|
485
|
+
param_inner = unwrap_ref_type(unwrap_readonly(param_type))
|
|
486
|
+
# Own[T] param accepts T values (ownership marker, not a distinct type)
|
|
487
|
+
if isinstance(param_inner, OwnType):
|
|
488
|
+
param_inner = param_inner.wrapped
|
|
489
|
+
if type_matches_numeric(arg_inner, param_inner):
|
|
490
|
+
return True
|
|
491
|
+
# None -> Optional[T]
|
|
492
|
+
if isinstance(arg_inner, NoneType) and isinstance(param_inner, OptionalType):
|
|
493
|
+
return True
|
|
494
|
+
# PendingStrType matches any string type (str, String, StrView)
|
|
495
|
+
if isinstance(arg_inner, PendingStrType) and is_str_category(param_inner):
|
|
496
|
+
return True
|
|
497
|
+
# Single-value LiteralType matches multi-value LiteralType if value is in the set
|
|
498
|
+
if isinstance(arg_inner, LiteralType) and isinstance(param_inner, LiteralType):
|
|
499
|
+
return all(v in param_inner.values for v in arg_inner.values)
|
|
500
|
+
# LiteralType falls back to matching its base type
|
|
501
|
+
if isinstance(arg_inner, LiteralType):
|
|
502
|
+
if arg_inner.is_str_base() and is_str_category(param_inner):
|
|
503
|
+
return True
|
|
504
|
+
if arg_inner.is_int_base() and is_integer_type(param_inner):
|
|
505
|
+
return True
|
|
506
|
+
if arg_inner.is_bool_base() and is_bool_type(param_inner):
|
|
507
|
+
return True
|
|
508
|
+
# IntLiteralType matches LiteralType with int base if value is in the set
|
|
509
|
+
if isinstance(arg_inner, IntLiteralType) and isinstance(param_inner, LiteralType) and param_inner.is_int_base():
|
|
510
|
+
if arg_inner.value is not None:
|
|
511
|
+
return param_inner.contains(LiteralTag.INT, arg_inner.value)
|
|
512
|
+
return False
|
|
513
|
+
# PendingBytesType matches any bytes type (bytes, bytearray, BytesView)
|
|
514
|
+
if isinstance(arg_inner, PendingBytesType) and is_bytes_category(param_inner):
|
|
515
|
+
return True
|
|
516
|
+
if protocol_checker and is_protocol_type(param_inner):
|
|
517
|
+
# Unwrap Own[T] -- ownership marker, not a distinct type.
|
|
518
|
+
# Mirrors the unwrapping in type_matches_strict.
|
|
519
|
+
check_arg = arg_inner.wrapped if isinstance(arg_inner, OwnType) else arg_inner
|
|
520
|
+
return protocol_checker(check_arg, param_inner)
|
|
521
|
+
# Callable -> Fn: std::function satisfies template requires clauses
|
|
522
|
+
if (isinstance(arg_inner, CallableType) and is_fn_type(param_inner)
|
|
523
|
+
and arg_inner.param_types == param_inner.param_types
|
|
524
|
+
and (arg_inner.return_type == param_inner.return_type
|
|
525
|
+
or isinstance(param_inner.return_type, VoidType))):
|
|
526
|
+
return True
|
|
527
|
+
if resolve_coercion(arg_inner, param_inner, CoercionContext.ARG) is not None:
|
|
528
|
+
return True
|
|
529
|
+
if deref_checker:
|
|
530
|
+
deref_target = deref_checker(arg_inner)
|
|
531
|
+
if deref_target is not None and deref_target == param_inner:
|
|
532
|
+
return True
|
|
533
|
+
# Inheritance: Child -> Parent (value upcast and pointer coercions)
|
|
534
|
+
if subclass_checker:
|
|
535
|
+
if isinstance(arg_inner, NominalType) and arg_inner.is_user_record:
|
|
536
|
+
if isinstance(param_inner, NominalType) and param_inner.is_user_record:
|
|
537
|
+
if subclass_checker(arg_inner, param_inner):
|
|
538
|
+
return True
|
|
539
|
+
pointee = getattr(param_inner, 'pointee', None)
|
|
540
|
+
if isinstance(pointee, NominalType) and pointee.is_user_record:
|
|
541
|
+
if subclass_checker(arg_inner, pointee):
|
|
542
|
+
return True
|
|
543
|
+
if isinstance(arg_inner, PtrType) and isinstance(arg_inner.pointee, NominalType):
|
|
544
|
+
if isinstance(param_inner, PtrType) and isinstance(param_inner.pointee, NominalType):
|
|
545
|
+
# Ptr[readonly[T]] cannot coerce to mutable Ptr (would drop const)
|
|
546
|
+
if not (arg_inner.is_readonly and not param_inner.is_readonly):
|
|
547
|
+
if subclass_checker(arg_inner.pointee, param_inner.pointee):
|
|
548
|
+
return True
|
|
549
|
+
# Non-protocol NominalType with Own[T] in type args: strip Own for overload matching.
|
|
550
|
+
# Symmetric with the same block in type_matches_strict.
|
|
551
|
+
if (isinstance(param_inner, NominalType) and not is_protocol_type(param_inner)
|
|
552
|
+
and any(isinstance(a, OwnType) for a in param_inner.inner_types())):
|
|
553
|
+
stripped_inner = tuple(a.wrapped if isinstance(a, OwnType) else a for a in param_inner.inner_types())
|
|
554
|
+
stripped_param = param_inner.with_inner_types(stripped_inner)
|
|
555
|
+
return arg_inner == stripped_param
|
|
556
|
+
return False
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def _expand_arg_types_with_kwargs(
|
|
560
|
+
arg_types: list[TpyType],
|
|
561
|
+
kwarg_types: dict[str, TpyType],
|
|
562
|
+
overload: FunctionInfo,
|
|
563
|
+
) -> list[TpyType] | None:
|
|
564
|
+
"""Expand positional arg_types by inserting kwarg types at their param slots.
|
|
565
|
+
|
|
566
|
+
Mirrors ``resolve_kwargs`` index-mapping logic but operates on types so
|
|
567
|
+
``resolve_overload`` can score kwargs-disambiguated candidates. Returns
|
|
568
|
+
``None`` when the overload cannot accept the given kwargs (unknown name,
|
|
569
|
+
duplicate of a positional, or missing required param); the overload is
|
|
570
|
+
then rejected at the candidate level.
|
|
571
|
+
|
|
572
|
+
Defaulted positional gaps between the last positional arg and the rightmost
|
|
573
|
+
kwarg are filled with the param's own type -- trivially matches itself and
|
|
574
|
+
does not skew cross-overload scoring.
|
|
575
|
+
"""
|
|
576
|
+
name_to_index = {p.name: i for i, p in enumerate(overload.params) if not p.is_variadic}
|
|
577
|
+
|
|
578
|
+
# One pass over kwargs: validate name, reject positional collisions,
|
|
579
|
+
# and track the rightmost explicitly-provided slot.
|
|
580
|
+
rightmost = len(arg_types) - 1
|
|
581
|
+
for kw_name in kwarg_types:
|
|
582
|
+
idx = name_to_index.get(kw_name)
|
|
583
|
+
if idx is None:
|
|
584
|
+
return None
|
|
585
|
+
if idx < len(arg_types) and not overload.params[idx].keyword_only:
|
|
586
|
+
return None
|
|
587
|
+
if idx > rightmost:
|
|
588
|
+
rightmost = idx
|
|
589
|
+
|
|
590
|
+
# Variadic: positional args feed *args; kwargs feed kwonly slots.
|
|
591
|
+
# Append kwonly types in declaration order so _classify_overload can
|
|
592
|
+
# score them at the right positions. Defensive: the parser currently
|
|
593
|
+
# blocks `*args` on `@overload` (parser.py raises "*args is not supported
|
|
594
|
+
# on @overload stubs"), so this branch is unreachable from user code
|
|
595
|
+
# today. Kept correct in case that gate ever opens.
|
|
596
|
+
if overload.has_variadic:
|
|
597
|
+
result = list(arg_types)
|
|
598
|
+
for p in overload.params:
|
|
599
|
+
if not p.keyword_only:
|
|
600
|
+
continue
|
|
601
|
+
if p.name in kwarg_types:
|
|
602
|
+
result.append(kwarg_types[p.name])
|
|
603
|
+
elif not p.has_default:
|
|
604
|
+
return None
|
|
605
|
+
return result
|
|
606
|
+
|
|
607
|
+
result: list[TpyType] = []
|
|
608
|
+
for i in range(rightmost + 1):
|
|
609
|
+
p = overload.params[i]
|
|
610
|
+
if i < len(arg_types):
|
|
611
|
+
result.append(arg_types[i])
|
|
612
|
+
elif p.name in kwarg_types:
|
|
613
|
+
result.append(kwarg_types[p.name])
|
|
614
|
+
elif p.has_default:
|
|
615
|
+
result.append(p.type)
|
|
616
|
+
else:
|
|
617
|
+
return None
|
|
618
|
+
|
|
619
|
+
# Required kwonly beyond rightmost must be in kwargs
|
|
620
|
+
for i, p in enumerate(overload.params):
|
|
621
|
+
if i > rightmost and p.keyword_only and not p.has_default and p.name not in kwarg_types:
|
|
622
|
+
return None
|
|
623
|
+
|
|
624
|
+
return result
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def _classify_overload(
|
|
628
|
+
overload: FunctionInfo,
|
|
629
|
+
arg_types: list[TpyType],
|
|
630
|
+
protocol_checker: ProtocolChecker | None,
|
|
631
|
+
classifier: ProtocolClassifier | None,
|
|
632
|
+
default_int_type: TpyType | None,
|
|
633
|
+
type_ops: 'TypeOperations | None',
|
|
634
|
+
kwarg_types: dict[str, TpyType] | None = None,
|
|
635
|
+
) -> tuple[tuple[MatchTier, int], ...] | None:
|
|
636
|
+
"""Classify every arg against ``overload``'s params, returning a
|
|
637
|
+
per-arg tier vector on match or ``None`` if any arg rejects.
|
|
638
|
+
|
|
639
|
+
For generic overloads (``TypeParamRef`` in params), inference runs first
|
|
640
|
+
(using ``protocol_checker`` to validate type-parameter bounds) and
|
|
641
|
+
``_classify_generic_param_match`` is used for the TPR params; other
|
|
642
|
+
params fall through to the regular strict classifier.
|
|
643
|
+
"""
|
|
644
|
+
if kwarg_types:
|
|
645
|
+
expanded = _expand_arg_types_with_kwargs(arg_types, kwarg_types, overload)
|
|
646
|
+
if expanded is None:
|
|
647
|
+
return None
|
|
648
|
+
arg_types = expanded
|
|
649
|
+
if len(arg_types) < overload.min_args or len(arg_types) > overload.max_args:
|
|
650
|
+
return None
|
|
651
|
+
has_tpr = overload.is_generic() and any(
|
|
652
|
+
contains_type_param(p.type) for p in overload.params)
|
|
653
|
+
inferred: dict[str, TpyType] | None = None
|
|
654
|
+
if has_tpr:
|
|
655
|
+
if type_ops is None:
|
|
656
|
+
return None
|
|
657
|
+
inferred = type_ops.infer_type_params_for_function(
|
|
658
|
+
overload, arg_types, protocol_checker or _always_false_checker,
|
|
659
|
+
)
|
|
660
|
+
if inferred is None:
|
|
661
|
+
return None
|
|
662
|
+
per_arg: list[tuple[MatchTier, int]] = []
|
|
663
|
+
for arg_t, (_, ptype) in zip(arg_types, overload.params):
|
|
664
|
+
if has_tpr and contains_type_param(ptype):
|
|
665
|
+
cell = _classify_generic_param_match(
|
|
666
|
+
ptype, arg_t, inferred, type_ops, classifier, default_int_type,
|
|
667
|
+
)
|
|
668
|
+
else:
|
|
669
|
+
cell = _classify_strict_match(arg_t, ptype, classifier, default_int_type)
|
|
670
|
+
if cell is None:
|
|
671
|
+
return None
|
|
672
|
+
per_arg.append(cell)
|
|
673
|
+
return tuple(per_arg)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def resolve_overload(
|
|
677
|
+
overloads: list[FunctionInfo],
|
|
678
|
+
arg_types: list[TpyType],
|
|
679
|
+
protocol_checker: ProtocolChecker | None = None,
|
|
680
|
+
deref_checker: DerefChecker | None = None,
|
|
681
|
+
default_int_type: TpyType | None = None,
|
|
682
|
+
subclass_checker: SubclassChecker | None = None,
|
|
683
|
+
is_readonly_receiver: bool | None = None,
|
|
684
|
+
is_consuming_receiver: bool | None = None,
|
|
685
|
+
protocol_classifier: ProtocolClassifier | None = None,
|
|
686
|
+
type_ops: 'TypeOperations | None' = None,
|
|
687
|
+
kwarg_types: dict[str, TpyType] | None = None,
|
|
688
|
+
) -> FunctionInfo | None:
|
|
689
|
+
"""Two-pass overload resolution: strict tier-ranked match, then coercions.
|
|
690
|
+
|
|
691
|
+
``protocol_classifier`` enables explicit-vs-structural tier discrimination;
|
|
692
|
+
when omitted, protocol hits are conservatively scored as STRUCTURAL.
|
|
693
|
+
``type_ops`` enables the generic first-pass path (inference + tier
|
|
694
|
+
ranking); when omitted, generic overloads fall back to the legacy
|
|
695
|
+
structural match (first-match-wins in declaration order).
|
|
696
|
+
|
|
697
|
+
``kwarg_types`` maps kwarg names to their analyzed types; per-overload
|
|
698
|
+
expansion inserts them at the matching param slots so kwargs can
|
|
699
|
+
disambiguate overloads that positional args tie on.
|
|
700
|
+
|
|
701
|
+
Returns the winning ``FunctionInfo`` or ``None`` (no match, or ambiguous
|
|
702
|
+
-- genuine ties at the top of the first-pass score are refused rather
|
|
703
|
+
than broken by declaration order).
|
|
704
|
+
"""
|
|
705
|
+
# Pre-filter consuming vs borrowing overloads by receiver ownership.
|
|
706
|
+
# Must run BEFORE readonly filter: consuming overloads are non-readonly,
|
|
707
|
+
# so the readonly filter would drop the borrowing (readonly) overload
|
|
708
|
+
# and leave only the consuming one for mutable receivers.
|
|
709
|
+
if is_consuming_receiver is not None and any(m.is_consuming for m in overloads):
|
|
710
|
+
if is_consuming_receiver:
|
|
711
|
+
consuming = [m for m in overloads if m.is_consuming]
|
|
712
|
+
if consuming:
|
|
713
|
+
overloads = consuming
|
|
714
|
+
else:
|
|
715
|
+
borrowing = [m for m in overloads if not m.is_consuming]
|
|
716
|
+
if borrowing:
|
|
717
|
+
overloads = borrowing
|
|
718
|
+
|
|
719
|
+
if is_readonly_receiver is not None:
|
|
720
|
+
if is_readonly_receiver:
|
|
721
|
+
ro = [m for m in overloads if m.is_readonly]
|
|
722
|
+
if ro:
|
|
723
|
+
overloads = ro
|
|
724
|
+
else:
|
|
725
|
+
mut = [m for m in overloads if not m.is_readonly]
|
|
726
|
+
if mut:
|
|
727
|
+
overloads = mut
|
|
728
|
+
|
|
729
|
+
classifier = protocol_classifier or _bool_checker_to_classifier(protocol_checker)
|
|
730
|
+
|
|
731
|
+
first_generic_match_fallback: FunctionInfo | None = None
|
|
732
|
+
scored_candidates: list[tuple[tuple[tuple[int, ...], int], FunctionInfo]] = []
|
|
733
|
+
for overload in overloads:
|
|
734
|
+
if type_ops is None and overload.is_generic() and any(
|
|
735
|
+
contains_type_param(p.type) for p in overload.params):
|
|
736
|
+
# Legacy structural-match fallback for generic overloads when the
|
|
737
|
+
# caller hasn't plumbed type_ops (e.g. the error-message-preservation
|
|
738
|
+
# path in calls.py). Kwargs aren't supported on this fallback path
|
|
739
|
+
# because it uses raw structural matching without arity expansion.
|
|
740
|
+
if kwarg_types:
|
|
741
|
+
continue
|
|
742
|
+
if (first_generic_match_fallback is None
|
|
743
|
+
and len(arg_types) >= overload.min_args
|
|
744
|
+
and len(arg_types) <= overload.max_args
|
|
745
|
+
and all(_structural_match(arg_t, ptype)
|
|
746
|
+
for arg_t, (_, ptype) in zip(arg_types, overload.params))):
|
|
747
|
+
first_generic_match_fallback = overload
|
|
748
|
+
continue
|
|
749
|
+
per_arg = _classify_overload(
|
|
750
|
+
overload, arg_types, protocol_checker, classifier, default_int_type, type_ops,
|
|
751
|
+
kwarg_types=kwarg_types,
|
|
752
|
+
)
|
|
753
|
+
if per_arg is not None:
|
|
754
|
+
scored_candidates.append((_score(per_arg), overload))
|
|
755
|
+
|
|
756
|
+
if scored_candidates:
|
|
757
|
+
if len(scored_candidates) == 1:
|
|
758
|
+
return scored_candidates[0][1]
|
|
759
|
+
scored_candidates.sort(key=lambda c: c[0])
|
|
760
|
+
best_score = scored_candidates[0][0]
|
|
761
|
+
# Functionally-identical signatures aren't genuine ambiguity: a
|
|
762
|
+
# substituted generic and its concrete twin (both appended by
|
|
763
|
+
# calls.py's unified pool) match identically. Dedupe by param-type
|
|
764
|
+
# sequence; stable sort keeps the first-declared.
|
|
765
|
+
seen: set[tuple[TpyType, ...]] = set()
|
|
766
|
+
unique_tied: list[FunctionInfo] = []
|
|
767
|
+
for score, ov in scored_candidates:
|
|
768
|
+
if score != best_score:
|
|
769
|
+
break
|
|
770
|
+
key = tuple(p.type for p in ov.params)
|
|
771
|
+
if key not in seen:
|
|
772
|
+
seen.add(key)
|
|
773
|
+
unique_tied.append(ov)
|
|
774
|
+
if len(unique_tied) > 1:
|
|
775
|
+
raise OverloadAmbiguityError(tuple(unique_tied))
|
|
776
|
+
return unique_tied[0]
|
|
777
|
+
|
|
778
|
+
if first_generic_match_fallback is not None:
|
|
779
|
+
return first_generic_match_fallback
|
|
780
|
+
|
|
781
|
+
# Second pass: allow coercions, prefer overload with most non-coercion
|
|
782
|
+
# matches and fewest narrowing conversions (BigInt->Int32 is lossy).
|
|
783
|
+
candidates: list[tuple[int, int, FunctionInfo, list[TpyType]]] = []
|
|
784
|
+
for overload in overloads:
|
|
785
|
+
effective_args = arg_types
|
|
786
|
+
if kwarg_types:
|
|
787
|
+
expanded = _expand_arg_types_with_kwargs(arg_types, kwarg_types, overload)
|
|
788
|
+
if expanded is None:
|
|
789
|
+
continue
|
|
790
|
+
effective_args = expanded
|
|
791
|
+
if len(effective_args) < overload.min_args or len(effective_args) > overload.max_args:
|
|
792
|
+
continue
|
|
793
|
+
if all(type_matches_with_coercion(arg_t, ptype, protocol_checker, deref_checker, subclass_checker)
|
|
794
|
+
for arg_t, (_, ptype) in zip(effective_args, overload.params)):
|
|
795
|
+
score = sum(1 for arg_t, (_, ptype) in zip(effective_args, overload.params)
|
|
796
|
+
if type_matches_numeric(arg_t, ptype))
|
|
797
|
+
narrowing = sum(1 for arg_t, (_, ptype) in zip(effective_args, overload.params)
|
|
798
|
+
if is_big_int_type(arg_t) and is_fixed_int_type(unwrap_ref_type(ptype)))
|
|
799
|
+
candidates.append((score, narrowing, overload, effective_args))
|
|
800
|
+
|
|
801
|
+
if candidates:
|
|
802
|
+
if default_int_type is None:
|
|
803
|
+
default_int_type = BIGINT
|
|
804
|
+
|
|
805
|
+
def _int_literal_penalty(arg_t: TpyType, ptype: TpyType) -> int:
|
|
806
|
+
if not isinstance(arg_t, IntLiteralType):
|
|
807
|
+
return 0
|
|
808
|
+
ptype = unwrap_ref_type(ptype)
|
|
809
|
+
# Prefer the configured default integer type for integer literals.
|
|
810
|
+
if ptype == default_int_type:
|
|
811
|
+
return 0
|
|
812
|
+
default_tr = int_traits_of(default_int_type)
|
|
813
|
+
if default_tr is not None:
|
|
814
|
+
ptype_tr = int_traits_of(ptype)
|
|
815
|
+
if ptype_tr is not None:
|
|
816
|
+
# Keep preference stable around configured width/signedness.
|
|
817
|
+
width_gap = abs(ptype_tr.bits - default_tr.bits) // 8
|
|
818
|
+
sign_penalty = 1 if ptype_tr.signed != default_tr.signed else 0
|
|
819
|
+
return 1 + width_gap + sign_penalty
|
|
820
|
+
if is_big_int_type(ptype):
|
|
821
|
+
return 8
|
|
822
|
+
if is_big_int_type(default_int_type):
|
|
823
|
+
if is_fixed_int_type(ptype):
|
|
824
|
+
return 2
|
|
825
|
+
return 1
|
|
826
|
+
|
|
827
|
+
# Apply literal penalty to break ties deterministically.
|
|
828
|
+
# Covers both same-return (e.g. range(IntLiteral) over many fixed-int
|
|
829
|
+
# overloads) and different-return cases (IntLiteral->FixedInt narrowing).
|
|
830
|
+
if len(candidates) > 1:
|
|
831
|
+
for i, (score, narrowing, overload, effective_args) in enumerate(candidates):
|
|
832
|
+
extra = sum(
|
|
833
|
+
_int_literal_penalty(arg_t, ptype)
|
|
834
|
+
for arg_t, (_, ptype) in zip(effective_args, overload.params)
|
|
835
|
+
)
|
|
836
|
+
candidates[i] = (score, narrowing + extra, overload, effective_args)
|
|
837
|
+
# Best: most numeric matches, then fewest narrowing conversions
|
|
838
|
+
candidates.sort(key=lambda x: (-x[0], x[1]))
|
|
839
|
+
return candidates[0][2]
|
|
840
|
+
|
|
841
|
+
return None
|