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,1060 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TypeResolver -- name-to-TpyType resolution for parser-emitted TypeRefNodes.
|
|
3
|
+
|
|
4
|
+
Lives under `parse/` because it is a parser-internal concern: it binds
|
|
5
|
+
the names the walker emits to concrete `TpyType` values, using live
|
|
6
|
+
parser state (registry, imports, local_defs, ...) via a back-reference
|
|
7
|
+
to its owning `Parser`. Parse-time callers (@builtin_decorator stubs,
|
|
8
|
+
nested defs, type-param bounds, macro fragments) invoke `resolve()`
|
|
9
|
+
directly. The module-level walker `parse.resolve_refs.resolve_refs`
|
|
10
|
+
calls it once per annotation site after the parser finishes.
|
|
11
|
+
|
|
12
|
+
The 9 attributes and 2 methods read off the back-reference are
|
|
13
|
+
documented in the `TypeResolver` class docstring -- that coupling stays
|
|
14
|
+
intra-package (parser + resolver evolve together) and does not surface
|
|
15
|
+
in sema.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
import ast
|
|
19
|
+
from typing import TYPE_CHECKING, Callable
|
|
20
|
+
|
|
21
|
+
from ..typesys import (
|
|
22
|
+
TpyType, NominalType, AliasRef, PtrType, OwnType, ReadonlyType, AutoReadonlyType,
|
|
23
|
+
AutoOwnType, FinalType, ClassVarType, OptionalType, VoidType, UnionType, TupleType,
|
|
24
|
+
CallableType, make_union, make_fn_type,
|
|
25
|
+
TypeParamRef, TypeParamKind, LiteralType, LiteralTag,
|
|
26
|
+
INT32, VOID, NONE, STR, STRING, STRVIEW, CHAR, BYTES, BYTEARRAY, BYTESVIEW,
|
|
27
|
+
BOOL, FLOAT, FLOAT32, BIGINT, SELF, BASIC_SLICE, SLICE, ANY, AnyType,
|
|
28
|
+
ALL_FIXED_INTS,
|
|
29
|
+
substitute_type_params_structural,
|
|
30
|
+
)
|
|
31
|
+
from .. import qnames
|
|
32
|
+
from ..type_def_registry import (
|
|
33
|
+
TypeDef, get_type_def, find_factory_by_simple_name, find_factory_in_module,
|
|
34
|
+
)
|
|
35
|
+
from .nodes import (
|
|
36
|
+
ParseError, ResolutionFailure, SourceLocation,
|
|
37
|
+
TpyTypeRef, TpyUnionRef, TpyCallableRef, TpyLiteralRef, ResolverInputNode,
|
|
38
|
+
)
|
|
39
|
+
from .imports import _IMPLICIT_MODULES
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from .parser import Parser
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Map of fixed-int type names to their singleton instances. Used by
|
|
46
|
+
# the resolver for bare-name lookup and by sema's field-default inferrer
|
|
47
|
+
# (`analyzer._infer_field_type_from_default`). Parser-side callers that
|
|
48
|
+
# only need name membership use a local `_FIXED_INT_NAMES` frozenset
|
|
49
|
+
# instead of pulling in the singleton values.
|
|
50
|
+
_FIXED_INT_MAP: dict[str, TpyType] = {str(t): t for t in ALL_FIXED_INTS}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _is_ptr_shaped(t: TpyType) -> bool:
|
|
54
|
+
"""True when `t` already lowers to `T*` -- a `Ptr[T]` or a readonly-wrapped
|
|
55
|
+
`Ptr[T]`. Wrapping such a type in `Optional[...]` / `| None` is redundant
|
|
56
|
+
because `Ptr[T]` is already nullable. Used by the resolver to warn at the
|
|
57
|
+
user's spelling site, before `OptionalType.__new__` collapses the wrapper.
|
|
58
|
+
"""
|
|
59
|
+
if isinstance(t, PtrType):
|
|
60
|
+
return True
|
|
61
|
+
if isinstance(t, ReadonlyType) and isinstance(t.wrapped, PtrType):
|
|
62
|
+
return True
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TypeResolver:
|
|
67
|
+
"""Resolves TypeRefNode -> TpyType using live parser state.
|
|
68
|
+
|
|
69
|
+
Holds a back-reference to its owning `Parser` and reads nine
|
|
70
|
+
parser attributes each call so container growth during parse --
|
|
71
|
+
and per-parse re-assignment of mutable containers at the top of
|
|
72
|
+
each `parse()` -- stays visible:
|
|
73
|
+
|
|
74
|
+
registry, _imports, _type_param_scope, _module_class_names,
|
|
75
|
+
_module_type_alias_names, _reverse_module_aliases,
|
|
76
|
+
_nested_type_scope, _local_defs, _bare_module_imports
|
|
77
|
+
|
|
78
|
+
Plus two parser-owned helpers that FragmentParser can override
|
|
79
|
+
for lenient macro-fragment parsing:
|
|
80
|
+
|
|
81
|
+
_resolve_type_name(name)
|
|
82
|
+
_raise_unresolved_import_error(name, node=None, *, loc=None)
|
|
83
|
+
|
|
84
|
+
The coupling is intra-package (parser + resolver evolve together);
|
|
85
|
+
no sema code reaches through here.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self, parser: 'Parser'):
|
|
89
|
+
self._parser = parser
|
|
90
|
+
# Active alias-body context: set by sema's alias pass while resolving
|
|
91
|
+
# the RHS of `type X = ...`; consulted by `_resolve_registered_type`
|
|
92
|
+
# so same-body self-references (e.g. `list[X]` inside X's RHS)
|
|
93
|
+
# produce a NominalType(name) placeholder rather than an "Unknown
|
|
94
|
+
# type" error. Recursive calls inside resolve() inherit this naturally.
|
|
95
|
+
self._pending_alias: str | None = None
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def registry(self):
|
|
99
|
+
"""Expose the parser's TypeRegistry so sema can register resolved
|
|
100
|
+
aliases / read bookkeeping without reaching through `_parser`."""
|
|
101
|
+
return self._parser.registry
|
|
102
|
+
|
|
103
|
+
def canonicalize_import_table(
|
|
104
|
+
self, lookup: 'Callable[[str, str], tuple[str, str] | None]',
|
|
105
|
+
) -> None:
|
|
106
|
+
"""Canonicalize the parser's import table to (defining_module, name).
|
|
107
|
+
|
|
108
|
+
Called by the compiler between parse and sema so subsequent
|
|
109
|
+
`resolve()` calls see defining-module tuples for re-exported
|
|
110
|
+
symbols and can mint authoritative `_module_qname` on the first
|
|
111
|
+
pass.
|
|
112
|
+
"""
|
|
113
|
+
self._parser._imports.canonicalize_name_index(lookup)
|
|
114
|
+
|
|
115
|
+
def refresh_module_aliases(self) -> None:
|
|
116
|
+
"""Rebuild the reverse-alias cache from the current module_aliases.
|
|
117
|
+
|
|
118
|
+
Called by the compiler after promoting `from pkg import submod` to
|
|
119
|
+
a full submodule import (which appends to ``ast.module_aliases``);
|
|
120
|
+
the parser builds the reverse map once at parse time, so post-parse
|
|
121
|
+
promotions need an explicit refresh to stay visible to qualified-name
|
|
122
|
+
lookup.
|
|
123
|
+
"""
|
|
124
|
+
self._parser._reverse_module_aliases = {
|
|
125
|
+
alias: canonical
|
|
126
|
+
for canonical, alias in self._parser._module_aliases.items()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
def index_imported_name(
|
|
130
|
+
self, local_name: str, source_module: str, original_name: str,
|
|
131
|
+
) -> None:
|
|
132
|
+
"""Add a `(source_module, original_name)` entry to the parser's
|
|
133
|
+
name index for `local_name` if not already present.
|
|
134
|
+
|
|
135
|
+
Called by `Compiler._expand_star_imports_for_module` after
|
|
136
|
+
compile-time star-import expansion so the parser-level
|
|
137
|
+
`resolve_refs` pass sees star-imported names when resolving
|
|
138
|
+
type annotations.
|
|
139
|
+
"""
|
|
140
|
+
self._parser._imports.index_imported_name(
|
|
141
|
+
local_name, source_module, original_name)
|
|
142
|
+
|
|
143
|
+
# ------------------------------------------------------------------
|
|
144
|
+
# Public entry point
|
|
145
|
+
# ------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
def resolve(
|
|
148
|
+
self, ref: ResolverInputNode,
|
|
149
|
+
type_param_scope: dict[str, TypeParamKind] | None = None,
|
|
150
|
+
*, pending_alias: str | None = None,
|
|
151
|
+
is_type_arg: bool = False,
|
|
152
|
+
) -> TpyType:
|
|
153
|
+
"""Resolve a parser-walker-emitted type reference to a TpyType.
|
|
154
|
+
|
|
155
|
+
Accepts `ResolverInputNode` (the four walker outputs: TpyTypeRef,
|
|
156
|
+
TpyUnionRef, TpyCallableRef, TpyLiteralRef). `TpyInferFromDefaultRef`
|
|
157
|
+
is deliberately *not* a valid input -- it's a field-storage marker
|
|
158
|
+
that sema catches explicitly in its field loop and never routes
|
|
159
|
+
through the resolver.
|
|
160
|
+
|
|
161
|
+
`pending_alias`, when set (typically by sema's alias pass), enables
|
|
162
|
+
same-body self-ref placeholder behaviour for recursive aliases like
|
|
163
|
+
`type JsonValue = str | list[JsonValue]`. It is saved on the
|
|
164
|
+
resolver for the duration of this call so recursive re-entries
|
|
165
|
+
inherit the context, and restored on exit.
|
|
166
|
+
|
|
167
|
+
`is_type_arg=True` flips bare `None` resolution from `VoidType`
|
|
168
|
+
(the function-return-shape singleton) to `NoneType` (the value-
|
|
169
|
+
carrying unit type, lowered to `std::monostate`). True at every
|
|
170
|
+
annotation slot except the function-return slot (resolved via
|
|
171
|
+
`resolve_refs._resolve_return_slot`); union members and Optional/
|
|
172
|
+
Final/ClassVar inners also stay False so VoidType-marker semantics
|
|
173
|
+
(Union/Optional collapse, redundant `Any | None`) survive. The
|
|
174
|
+
flag name is historical and worth renaming to `is_value_position`
|
|
175
|
+
if/when this materializes as a THIR-level mark.
|
|
176
|
+
"""
|
|
177
|
+
if pending_alias is not None:
|
|
178
|
+
prev = self._pending_alias
|
|
179
|
+
self._pending_alias = pending_alias
|
|
180
|
+
try:
|
|
181
|
+
return self._resolve_ref(ref, type_param_scope, is_type_arg=is_type_arg)
|
|
182
|
+
finally:
|
|
183
|
+
self._pending_alias = prev
|
|
184
|
+
return self._resolve_ref(ref, type_param_scope, is_type_arg=is_type_arg)
|
|
185
|
+
|
|
186
|
+
def resolve_lenient(
|
|
187
|
+
self, ref: ResolverInputNode,
|
|
188
|
+
type_param_scope: dict[str, TypeParamKind] | None = None,
|
|
189
|
+
*, is_type_arg: bool = False,
|
|
190
|
+
) -> TpyType:
|
|
191
|
+
"""Resolve like `resolve()` but, on a name-resolution failure for a
|
|
192
|
+
bare `TpyTypeRef`, construct a `NominalType(name, args)` placeholder
|
|
193
|
+
instead of raising. Used by FragmentParser so macro fragments can
|
|
194
|
+
reference symbols not visible to the fragment-level resolver --
|
|
195
|
+
sema re-resolves them in the final context.
|
|
196
|
+
|
|
197
|
+
Failure identification is structural via the `ResolutionFailure`
|
|
198
|
+
subclass (raised only at the three bare/dotted/generic
|
|
199
|
+
unknown-name sites). Structural errors (Own-in-union, Callable
|
|
200
|
+
arity, etc.) surface as plain `ParseError` and still propagate.
|
|
201
|
+
Non-`TpyTypeRef` inputs are not leniency targets -- they delegate
|
|
202
|
+
to `resolve()` unchanged.
|
|
203
|
+
"""
|
|
204
|
+
try:
|
|
205
|
+
return self.resolve(ref, type_param_scope, is_type_arg=is_type_arg)
|
|
206
|
+
except ResolutionFailure:
|
|
207
|
+
if not isinstance(ref, TpyTypeRef):
|
|
208
|
+
raise
|
|
209
|
+
resolved_args: tuple = tuple(
|
|
210
|
+
a if isinstance(a, int)
|
|
211
|
+
else self.resolve_lenient(a, type_param_scope, is_type_arg=True)
|
|
212
|
+
for a in ref.args
|
|
213
|
+
)
|
|
214
|
+
return NominalType(ref.name, resolved_args)
|
|
215
|
+
|
|
216
|
+
def _resolve_ref(
|
|
217
|
+
self, ref: ResolverInputNode,
|
|
218
|
+
type_param_scope: dict[str, TypeParamKind] | None,
|
|
219
|
+
*, is_type_arg: bool = False,
|
|
220
|
+
) -> TpyType:
|
|
221
|
+
"""Internal resolver. Recursive calls to `self.resolve(...)` without
|
|
222
|
+
`pending_alias` re-enter the public method, which skips the
|
|
223
|
+
save/restore and forwards straight here.
|
|
224
|
+
|
|
225
|
+
`is_type_arg` see `resolve()` docstring -- forwarded into the
|
|
226
|
+
bare-`None` branch and into `_resolve_primitive_type`.
|
|
227
|
+
"""
|
|
228
|
+
parser = self._parser
|
|
229
|
+
if type_param_scope is None:
|
|
230
|
+
type_param_scope = parser._type_param_scope
|
|
231
|
+
|
|
232
|
+
# Union
|
|
233
|
+
if isinstance(ref, TpyUnionRef):
|
|
234
|
+
# Union members keep VoidType marker semantics (collapse to
|
|
235
|
+
# Optional, redundant-Any check, Ptr-already-nullable warning).
|
|
236
|
+
# If the outer context is a type-arg slot, the union as a whole
|
|
237
|
+
# is still the type at that slot, not each member individually.
|
|
238
|
+
parsed = [self.resolve(m, type_param_scope) for m in ref.members]
|
|
239
|
+
non_none = [t for t in parsed if not isinstance(t, VoidType)]
|
|
240
|
+
# Any is the universal supertype -- combining it with None or
|
|
241
|
+
# any other type is redundant.
|
|
242
|
+
for t in parsed:
|
|
243
|
+
if isinstance(t, AnyType):
|
|
244
|
+
has_none = any(isinstance(p, VoidType) for p in parsed)
|
|
245
|
+
if has_none:
|
|
246
|
+
raise ParseError(
|
|
247
|
+
"Any | None is redundant -- Any already accepts None",
|
|
248
|
+
loc=ref.loc,
|
|
249
|
+
)
|
|
250
|
+
if len(parsed) > 1:
|
|
251
|
+
raise ParseError(
|
|
252
|
+
"Any | T is redundant -- Any is the universal supertype",
|
|
253
|
+
loc=ref.loc,
|
|
254
|
+
)
|
|
255
|
+
if len(non_none) > 1:
|
|
256
|
+
for t in non_none:
|
|
257
|
+
if isinstance(t, OwnType):
|
|
258
|
+
unwrapped = [
|
|
259
|
+
p.wrapped if isinstance(p, OwnType) else p for p in non_none
|
|
260
|
+
]
|
|
261
|
+
raise ParseError(
|
|
262
|
+
f"Own[{t.wrapped}] cannot be a union member. "
|
|
263
|
+
f"Use Own[...] around the whole union instead: "
|
|
264
|
+
f"Own[{' | '.join(str(u) for u in unwrapped)}]",
|
|
265
|
+
loc=ref.loc,
|
|
266
|
+
)
|
|
267
|
+
readonly_count = sum(1 for t in parsed if isinstance(t, ReadonlyType))
|
|
268
|
+
non_none_count = sum(1 for t in parsed if not isinstance(t, VoidType))
|
|
269
|
+
if readonly_count > 0 and readonly_count < non_none_count:
|
|
270
|
+
raise ParseError(
|
|
271
|
+
"Cannot mix readonly and non-readonly types in a union",
|
|
272
|
+
loc=ref.loc,
|
|
273
|
+
)
|
|
274
|
+
# Redundant `Ptr[T] | None` (upstream #17). `Ptr[T]` is already
|
|
275
|
+
# nullable and the collapse rule erases the wrapper; warn at the
|
|
276
|
+
# user's spelling site so the redundant form doesn't drift back in.
|
|
277
|
+
if non_none_count == 1 and any(isinstance(t, VoidType) for t in parsed):
|
|
278
|
+
non_none = next(t for t in parsed if not isinstance(t, VoidType))
|
|
279
|
+
if _is_ptr_shaped(non_none):
|
|
280
|
+
parser._warn_at_loc(
|
|
281
|
+
f"`{non_none} | None` is redundant -- `{non_none}` is "
|
|
282
|
+
f"already nullable; drop the `| None`",
|
|
283
|
+
ref.loc,
|
|
284
|
+
)
|
|
285
|
+
if readonly_count > 0:
|
|
286
|
+
unwrapped = [
|
|
287
|
+
t.wrapped if isinstance(t, ReadonlyType) else t for t in parsed
|
|
288
|
+
]
|
|
289
|
+
return ReadonlyType(make_union(*unwrapped))
|
|
290
|
+
return make_union(*parsed)
|
|
291
|
+
|
|
292
|
+
# Callable / Fn
|
|
293
|
+
if isinstance(ref, TpyCallableRef):
|
|
294
|
+
param_types = tuple(
|
|
295
|
+
self.resolve(p, type_param_scope, is_type_arg=True) for p in ref.params
|
|
296
|
+
)
|
|
297
|
+
return_type = self.resolve(ref.return_type, type_param_scope)
|
|
298
|
+
if ref.kind == "Fn":
|
|
299
|
+
return make_fn_type(param_types, return_type)
|
|
300
|
+
return CallableType(param_types, return_type)
|
|
301
|
+
|
|
302
|
+
# Literal
|
|
303
|
+
if isinstance(ref, TpyLiteralRef):
|
|
304
|
+
tag = ref.values[0].tag
|
|
305
|
+
base_type = {
|
|
306
|
+
LiteralTag.STR: STR, LiteralTag.INT: INT32, LiteralTag.BOOL: BOOL,
|
|
307
|
+
}[tag]
|
|
308
|
+
return LiteralType(base_type, ref.values)
|
|
309
|
+
|
|
310
|
+
# TpyTypeRef
|
|
311
|
+
assert isinstance(ref, TpyTypeRef), f"Unknown ref kind: {type(ref).__name__}"
|
|
312
|
+
name = ref.name
|
|
313
|
+
|
|
314
|
+
# "None" (void) -- emitted by walker for ast.Constant(None)
|
|
315
|
+
if name == "None" and not ref.args:
|
|
316
|
+
return NONE if is_type_arg else VOID
|
|
317
|
+
|
|
318
|
+
# Structural wrappers (canonical `mod:Name` names set by the walker
|
|
319
|
+
# only when the source name actually resolved to the expected module).
|
|
320
|
+
# The `:` separator avoids any collision with raw user-source names
|
|
321
|
+
# (including dotted forms like "typing.Optional" written without
|
|
322
|
+
# `import typing`), so raw-name TpyTypeRefs fall through to the
|
|
323
|
+
# generic path where the resolver's unresolved-name error fires.
|
|
324
|
+
if ref.args and name in (
|
|
325
|
+
"tpy:Ptr", "tpy:Own", "tpy:readonly", "tpy:auto_readonly",
|
|
326
|
+
"tpy:auto_own", "typing:Optional", "typing:Final", "typing:ClassVar",
|
|
327
|
+
):
|
|
328
|
+
inner_arg = ref.args[0]
|
|
329
|
+
assert not isinstance(inner_arg, int), \
|
|
330
|
+
f"structural wrapper {name} cannot take int arg"
|
|
331
|
+
# Own/Ptr/readonly/auto_* are value-bearing slots (Own[None] etc.
|
|
332
|
+
# must produce NoneType). Optional/Final/ClassVar keep the outer
|
|
333
|
+
# context: Optional preserves the union-marker semantics, Final/
|
|
334
|
+
# ClassVar are annotation modifiers at whatever depth they appear.
|
|
335
|
+
inner_is_type_arg = name in (
|
|
336
|
+
"tpy:Ptr", "tpy:Own", "tpy:readonly",
|
|
337
|
+
"tpy:auto_readonly", "tpy:auto_own",
|
|
338
|
+
) or is_type_arg
|
|
339
|
+
inner = self.resolve(
|
|
340
|
+
inner_arg, type_param_scope, is_type_arg=inner_is_type_arg,
|
|
341
|
+
)
|
|
342
|
+
if name == "tpy:Ptr":
|
|
343
|
+
if isinstance(inner, ReadonlyType):
|
|
344
|
+
return PtrType(inner.wrapped, is_readonly=True)
|
|
345
|
+
return PtrType(inner)
|
|
346
|
+
if name == "tpy:Own":
|
|
347
|
+
if isinstance(inner, AnyType):
|
|
348
|
+
raise ParseError(
|
|
349
|
+
"Own[Any] is redundant -- Any is already owning",
|
|
350
|
+
loc=ref.loc,
|
|
351
|
+
)
|
|
352
|
+
return OwnType(inner)
|
|
353
|
+
if name == "tpy:readonly":
|
|
354
|
+
return ReadonlyType(inner)
|
|
355
|
+
if name == "tpy:auto_readonly":
|
|
356
|
+
return AutoReadonlyType(inner)
|
|
357
|
+
if name == "tpy:auto_own":
|
|
358
|
+
return AutoOwnType(inner)
|
|
359
|
+
if name == "typing:Optional":
|
|
360
|
+
if isinstance(inner, AnyType):
|
|
361
|
+
raise ParseError(
|
|
362
|
+
"Optional[Any] is redundant -- Any already accepts None",
|
|
363
|
+
loc=ref.loc,
|
|
364
|
+
)
|
|
365
|
+
if _is_ptr_shaped(inner):
|
|
366
|
+
parser._warn_at_loc(
|
|
367
|
+
f"`Optional[{inner}]` is redundant -- `{inner}` is "
|
|
368
|
+
f"already nullable; use `{inner}` directly",
|
|
369
|
+
ref.loc,
|
|
370
|
+
)
|
|
371
|
+
return OptionalType(inner)
|
|
372
|
+
if name == "typing:Final":
|
|
373
|
+
return FinalType(inner)
|
|
374
|
+
if name == "typing:ClassVar":
|
|
375
|
+
return ClassVarType(inner)
|
|
376
|
+
|
|
377
|
+
# tuple
|
|
378
|
+
if name == "builtins:tuple" and ref.args:
|
|
379
|
+
elements = tuple(
|
|
380
|
+
self.resolve(a, type_param_scope, is_type_arg=True)
|
|
381
|
+
for a in ref.args if not isinstance(a, int)
|
|
382
|
+
)
|
|
383
|
+
return TupleType(elements)
|
|
384
|
+
|
|
385
|
+
# Bare name (no args)
|
|
386
|
+
if not ref.args:
|
|
387
|
+
# Type param scope
|
|
388
|
+
if type_param_scope and name in type_param_scope:
|
|
389
|
+
kind = type_param_scope[name]
|
|
390
|
+
return TypeParamRef(name, kind=kind)
|
|
391
|
+
|
|
392
|
+
# Dotted (qualified or nested class)
|
|
393
|
+
if "." in name:
|
|
394
|
+
parts = name.split(".")
|
|
395
|
+
# 2-level qualified (mod.Attr)
|
|
396
|
+
if len(parts) == 2:
|
|
397
|
+
mod, attr = parts
|
|
398
|
+
resolved_q = self._resolve_qualified_type_name_str(mod, attr)
|
|
399
|
+
if resolved_q:
|
|
400
|
+
primitive = self._resolve_primitive_type(
|
|
401
|
+
*resolved_q, loc=ref.loc, is_type_arg=is_type_arg)
|
|
402
|
+
if primitive is not None:
|
|
403
|
+
return primitive
|
|
404
|
+
registered = self._resolve_registered_type(
|
|
405
|
+
resolved_q[1], loc=ref.loc, resolved=True)
|
|
406
|
+
if registered is not None:
|
|
407
|
+
return self._upgrade_from_type_def(
|
|
408
|
+
registered, resolved_q, loc=ref.loc)
|
|
409
|
+
# Submodule-import path (`from pkg import submod`):
|
|
410
|
+
# `attr` is not in the importer's local registry but
|
|
411
|
+
# is exported by the source module. Consult the source
|
|
412
|
+
# module directly so the type carries its cross-module
|
|
413
|
+
# qname.
|
|
414
|
+
cross = self._resolve_qualified_cross_module(
|
|
415
|
+
*resolved_q, loc=ref.loc)
|
|
416
|
+
if cross is not None:
|
|
417
|
+
return cross
|
|
418
|
+
# Nested dotted class: Outer.Inner, Outer.Mid.Inner, ...
|
|
419
|
+
dotted = self._resolve_dotted_class_name_str(name)
|
|
420
|
+
if dotted is not None:
|
|
421
|
+
rinfo = parser.registry.get_record(dotted)
|
|
422
|
+
if rinfo is not None:
|
|
423
|
+
qname = self._user_record_qname(dotted, None)
|
|
424
|
+
return NominalType(dotted, _module_qname=qname)
|
|
425
|
+
enum_type = parser.registry.get_enum(dotted)
|
|
426
|
+
if enum_type is not None:
|
|
427
|
+
return enum_type
|
|
428
|
+
# Helpful error for unimported implicit module
|
|
429
|
+
self._raise_unresolved_qualified_error_str(name, ref.loc)
|
|
430
|
+
raise ResolutionFailure(
|
|
431
|
+
f"Unsupported qualified type: {name}", loc=ref.loc,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
# Bare name resolution
|
|
435
|
+
resolved = parser._resolve_type_name(name)
|
|
436
|
+
if resolved:
|
|
437
|
+
primitive = self._resolve_primitive_type(
|
|
438
|
+
*resolved, loc=ref.loc, is_type_arg=is_type_arg)
|
|
439
|
+
if primitive is not None:
|
|
440
|
+
return primitive
|
|
441
|
+
resolved_name = resolved[1] if resolved else name
|
|
442
|
+
registered = self._resolve_registered_type(
|
|
443
|
+
resolved_name, loc=ref.loc, resolved=bool(resolved))
|
|
444
|
+
if registered is not None:
|
|
445
|
+
# Mint _module_qname for cross-module user refs. The
|
|
446
|
+
# builtin path handles type-factory-backed names (list,
|
|
447
|
+
# Array, ...); the canonical-import path covers user
|
|
448
|
+
# records / protocols / enums imported from other
|
|
449
|
+
# modules -- `canonicalize_import_table` has already
|
|
450
|
+
# rewritten the tuple to point at the defining module,
|
|
451
|
+
# so `{module}.{original}` is the authoritative qname.
|
|
452
|
+
# For canonical protocols we also upgrade is_protocol /
|
|
453
|
+
# is_dynamic_protocol from `TypeDef.protocol` (the dep
|
|
454
|
+
# module's sema has already attached it).
|
|
455
|
+
if (resolved and isinstance(registered, NominalType)
|
|
456
|
+
and not registered._module_qname):
|
|
457
|
+
module, original = resolved
|
|
458
|
+
candidate_qname = f"{module}.{original}"
|
|
459
|
+
candidate_td = get_type_def(candidate_qname)
|
|
460
|
+
is_builtin = (
|
|
461
|
+
parser.registry.get_builtin_type_key(registered.name) is not None
|
|
462
|
+
or (candidate_td is not None and candidate_td.type_factory is not None)
|
|
463
|
+
)
|
|
464
|
+
if is_builtin or parser._imports.is_canonical(name):
|
|
465
|
+
is_protocol = registered.is_protocol
|
|
466
|
+
is_dynamic_protocol = registered.is_dynamic_protocol
|
|
467
|
+
if candidate_td is not None and candidate_td.protocol is not None:
|
|
468
|
+
proto = candidate_td.protocol
|
|
469
|
+
if proto.type_params:
|
|
470
|
+
# Match sema block-3's original error class so
|
|
471
|
+
# diag.txt formats as `file:line: error: ...`
|
|
472
|
+
# (ParseError would go through the `Parse
|
|
473
|
+
# error: ...` CLI path instead).
|
|
474
|
+
from ..diagnostics import SemanticError
|
|
475
|
+
raise SemanticError(
|
|
476
|
+
f"Generic protocol '{registered.name}' requires type arguments: "
|
|
477
|
+
f"{registered.name}[{', '.join(proto.type_params)}]",
|
|
478
|
+
loc=ref.loc,
|
|
479
|
+
)
|
|
480
|
+
is_protocol = True
|
|
481
|
+
is_dynamic_protocol = proto.is_dynamic
|
|
482
|
+
registered = NominalType(
|
|
483
|
+
registered.name, registered.type_args,
|
|
484
|
+
is_protocol, candidate_qname, is_dynamic_protocol,
|
|
485
|
+
)
|
|
486
|
+
return registered
|
|
487
|
+
raise ResolutionFailure(f"Unknown type: {name}", loc=ref.loc)
|
|
488
|
+
|
|
489
|
+
# Generic form (name + args) -- bare or dotted
|
|
490
|
+
|
|
491
|
+
# Self-reference inside the body of the alias currently being
|
|
492
|
+
# resolved (`type Tree[T] = T | list[Tree[T]]` -- the inner
|
|
493
|
+
# `Tree[T]`). The alias isn't yet registered, so the normal
|
|
494
|
+
# lookup path would fail. Emit an `AliasRef` placeholder so
|
|
495
|
+
# `_contains_self_reference` detects it and tags the alias
|
|
496
|
+
# recursive. Resolve and carry the `[...]` args (restoring the
|
|
497
|
+
# "Unknown type" diagnostic for malformed args like
|
|
498
|
+
# `list[Tree[Undefined]]`) and arity-check against the alias's
|
|
499
|
+
# declared params; the same-args identity rule is enforced later
|
|
500
|
+
# by the recursive-union validator.
|
|
501
|
+
if self._pending_alias is not None and name == self._pending_alias:
|
|
502
|
+
expected = len(type_param_scope) if type_param_scope else 0
|
|
503
|
+
actual = len(ref.args)
|
|
504
|
+
if actual != expected:
|
|
505
|
+
raise ResolutionFailure(
|
|
506
|
+
f"Recursive alias '{name}' self-reference takes "
|
|
507
|
+
f"{expected} type argument{'s' if expected != 1 else ''}, "
|
|
508
|
+
f"got {actual}",
|
|
509
|
+
loc=ref.loc,
|
|
510
|
+
)
|
|
511
|
+
resolved_args = tuple(
|
|
512
|
+
a if isinstance(a, int)
|
|
513
|
+
else self.resolve(a, type_param_scope, is_type_arg=True)
|
|
514
|
+
for a in ref.args
|
|
515
|
+
)
|
|
516
|
+
return AliasRef(
|
|
517
|
+
name, module=parser._public_module(), args=resolved_args)
|
|
518
|
+
|
|
519
|
+
if "." in name:
|
|
520
|
+
parts = name.split(".")
|
|
521
|
+
if len(parts) == 2:
|
|
522
|
+
mod, attr = parts
|
|
523
|
+
resolved = self._resolve_qualified_type_name_str(mod, attr)
|
|
524
|
+
else:
|
|
525
|
+
resolved = None
|
|
526
|
+
else:
|
|
527
|
+
resolved = parser._resolve_type_name(name)
|
|
528
|
+
|
|
529
|
+
resolved_container = resolved[1] if resolved else name
|
|
530
|
+
|
|
531
|
+
# Module-defined generic types (list, Array, Span, ...)
|
|
532
|
+
if resolved_container and (td := find_factory_by_simple_name(resolved_container)):
|
|
533
|
+
if not resolved and td.qname.startswith("tpy."):
|
|
534
|
+
parser._raise_unresolved_import_error(name, loc=ref.loc)
|
|
535
|
+
return self._resolve_generic_type_from_ref(
|
|
536
|
+
ref, resolved_container, td, type_param_scope)
|
|
537
|
+
|
|
538
|
+
# Imported generic from a module
|
|
539
|
+
if resolved:
|
|
540
|
+
source_module, original_name = resolved
|
|
541
|
+
if td := find_factory_in_module(original_name, source_module):
|
|
542
|
+
return self._resolve_generic_type_from_ref(
|
|
543
|
+
ref, resolved_container, td, type_param_scope)
|
|
544
|
+
elif "." not in name and name:
|
|
545
|
+
if import_source := parser._imports.get_import_source(name):
|
|
546
|
+
source_module, original_name = import_source
|
|
547
|
+
if td := find_factory_in_module(original_name, source_module):
|
|
548
|
+
return self._resolve_generic_type_from_ref(
|
|
549
|
+
ref, resolved_container, td, type_param_scope)
|
|
550
|
+
|
|
551
|
+
# Qualified name with missing module import -- only for dotted subscripts
|
|
552
|
+
# where qualified resolution failed.
|
|
553
|
+
if "." in name and resolved is None:
|
|
554
|
+
self._raise_unresolved_qualified_error_str(name, ref.loc)
|
|
555
|
+
|
|
556
|
+
# User-defined generic protocols
|
|
557
|
+
if user_protocol := parser.registry.scan_by_short_name(resolved_container):
|
|
558
|
+
if user_protocol.type_params:
|
|
559
|
+
expected = len(user_protocol.type_params)
|
|
560
|
+
if len(ref.args) != expected:
|
|
561
|
+
raise ParseError(
|
|
562
|
+
f"{resolved_container} requires exactly {expected} type parameters",
|
|
563
|
+
loc=ref.loc,
|
|
564
|
+
)
|
|
565
|
+
type_args = tuple(
|
|
566
|
+
a if isinstance(a, int)
|
|
567
|
+
else self.resolve(a, type_param_scope, is_type_arg=True)
|
|
568
|
+
for a in ref.args
|
|
569
|
+
)
|
|
570
|
+
qname = (f"{user_protocol.module}.{resolved_container}"
|
|
571
|
+
if user_protocol.module else None)
|
|
572
|
+
return NominalType(
|
|
573
|
+
resolved_container, type_args, is_protocol=True,
|
|
574
|
+
_module_qname=qname,
|
|
575
|
+
is_dynamic_protocol=user_protocol.is_dynamic,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
# Generic type alias use site (`Pair[int]`). Phase 1 of generic
|
|
579
|
+
# recursive aliases (see docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md):
|
|
580
|
+
# substitute non-recursive generic aliases at use sites; recursive
|
|
581
|
+
# ones stay rejected for Phase 2. Handle local, short-name-imported,
|
|
582
|
+
# and dotted-qualified forms via one helper.
|
|
583
|
+
alias_info = self._lookup_generic_alias_info(name, resolved_container, resolved)
|
|
584
|
+
if alias_info is not None and alias_info.type_params:
|
|
585
|
+
return self._resolve_generic_alias_use(
|
|
586
|
+
ref, resolved_container, alias_info, type_param_scope,
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
# Unresolved bare (non-dotted) name -- helpful import hint
|
|
590
|
+
if not resolved and "." not in name and name:
|
|
591
|
+
parser._raise_unresolved_import_error(name, loc=ref.loc)
|
|
592
|
+
if (resolved or parser.registry.get_record(resolved_container) is not None
|
|
593
|
+
or resolved_container in parser._module_class_names):
|
|
594
|
+
type_args = self._resolve_record_type_args_from_ref(
|
|
595
|
+
ref, resolved_container, type_param_scope)
|
|
596
|
+
canonical = "." not in name and parser._imports.is_canonical(name)
|
|
597
|
+
qname = self._user_record_qname(
|
|
598
|
+
resolved_container, resolved, canonical=canonical)
|
|
599
|
+
# Upgrade is_protocol / is_dynamic_protocol for cross-module
|
|
600
|
+
# canonical protocol refs via TypeDef.protocol (replaces the
|
|
601
|
+
# old sema block-3 substitution).
|
|
602
|
+
is_protocol = False
|
|
603
|
+
is_dynamic_protocol = False
|
|
604
|
+
if canonical and qname:
|
|
605
|
+
td = get_type_def(qname)
|
|
606
|
+
if td is not None and td.protocol is not None:
|
|
607
|
+
is_protocol = True
|
|
608
|
+
is_dynamic_protocol = td.protocol.is_dynamic
|
|
609
|
+
return NominalType(
|
|
610
|
+
resolved_container, type_args, is_protocol,
|
|
611
|
+
qname, is_dynamic_protocol,
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
# Nested generic records (Outer.Inner[T])
|
|
615
|
+
if "." in name:
|
|
616
|
+
dotted = self._resolve_dotted_class_name_str(name)
|
|
617
|
+
if dotted is not None and parser.registry.get_record(dotted) is not None:
|
|
618
|
+
type_args = self._resolve_record_type_args_from_ref(
|
|
619
|
+
ref, dotted, type_param_scope)
|
|
620
|
+
qname = self._user_record_qname(dotted, None)
|
|
621
|
+
return NominalType(dotted, type_args, _module_qname=qname)
|
|
622
|
+
|
|
623
|
+
raise ResolutionFailure(f"Unknown generic type: {name}", loc=ref.loc)
|
|
624
|
+
|
|
625
|
+
def _lookup_generic_alias_info(
|
|
626
|
+
self, name: str, resolved_container: str,
|
|
627
|
+
resolved: 'tuple[str, str] | None',
|
|
628
|
+
) -> 'TypeAliasInfo | None':
|
|
629
|
+
"""Find a generic alias's TypeAliasInfo across local + imported forms.
|
|
630
|
+
|
|
631
|
+
Handles:
|
|
632
|
+
- Local: `type Pair[T] = ...` in the current module.
|
|
633
|
+
- Imported short name: `from lib_a import Pair` then `Pair[int]`.
|
|
634
|
+
- Dotted qualified: `lib_a.Pair[int]` (resolved is the
|
|
635
|
+
(source_module, original_name) tuple).
|
|
636
|
+
|
|
637
|
+
Returns None if the name isn't a registered alias anywhere; the
|
|
638
|
+
caller then continues with the record / unknown-name fallback.
|
|
639
|
+
"""
|
|
640
|
+
parser = self._parser
|
|
641
|
+
# Local registry first -- covers same-module aliases and aliases
|
|
642
|
+
# whose import was already materialised into the parser registry.
|
|
643
|
+
local = parser.registry.get_type_alias_info(name)
|
|
644
|
+
if local is not None:
|
|
645
|
+
return local
|
|
646
|
+
# Cross-module: consult the source module's ModuleInfo for the
|
|
647
|
+
# original-named alias. Works for both short-name imports
|
|
648
|
+
# (`resolved == (source_module, original_name)`) and dotted
|
|
649
|
+
# qualification.
|
|
650
|
+
if resolved is not None:
|
|
651
|
+
source_module, original_name = resolved
|
|
652
|
+
mod_info = parser.registry.modules.get(source_module)
|
|
653
|
+
if mod_info is not None and mod_info.type_aliases:
|
|
654
|
+
return mod_info.type_aliases.get(original_name)
|
|
655
|
+
return None
|
|
656
|
+
|
|
657
|
+
def _resolve_generic_alias_use(
|
|
658
|
+
self, ref: 'TpyTypeRef', name: str, alias_info: 'TypeAliasInfo',
|
|
659
|
+
type_param_scope: 'dict[str, TypeParamKind] | None',
|
|
660
|
+
) -> TpyType:
|
|
661
|
+
"""Expand a use of a generic type alias at the use site.
|
|
662
|
+
|
|
663
|
+
Two outcomes:
|
|
664
|
+
- Non-recursive aliases (`type Pair[T] = tuple[T, T]`): build
|
|
665
|
+
`{T_i: arg_i}` and apply structural substitution to the body.
|
|
666
|
+
The alias name disappears from the type tree downstream.
|
|
667
|
+
- Recursive aliases (`type Tree[T] = T | list[Tree[T]]`): emit an
|
|
668
|
+
`AliasRef(name, args)` placeholder (parse-resolve runs against a
|
|
669
|
+
separate registry and cannot mint the semantic
|
|
670
|
+
`RecursiveAliasInstanceType`). Sema's finalize pass converts it
|
|
671
|
+
using the sema-registry alias_info. See
|
|
672
|
+
docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md.
|
|
673
|
+
"""
|
|
674
|
+
expected = len(alias_info.type_params)
|
|
675
|
+
actual = len(ref.args)
|
|
676
|
+
if actual != expected:
|
|
677
|
+
raise ResolutionFailure(
|
|
678
|
+
f"Type alias '{name}' takes {expected} type "
|
|
679
|
+
f"argument{'s' if expected != 1 else ''}, got {actual}",
|
|
680
|
+
loc=ref.loc,
|
|
681
|
+
)
|
|
682
|
+
# Resolve each type arg. int args (Array's N slot) shouldn't
|
|
683
|
+
# appear here -- v1 aliases reject int-kind type params at parse
|
|
684
|
+
# time -- but pass them through unchanged for forward compatibility.
|
|
685
|
+
resolved_args: list[TpyType | int] = []
|
|
686
|
+
for arg in ref.args:
|
|
687
|
+
if isinstance(arg, int):
|
|
688
|
+
resolved_args.append(arg)
|
|
689
|
+
else:
|
|
690
|
+
resolved_args.append(
|
|
691
|
+
self.resolve(arg, type_param_scope, is_type_arg=True)
|
|
692
|
+
)
|
|
693
|
+
if alias_info.is_recursive:
|
|
694
|
+
return AliasRef(
|
|
695
|
+
name, module=self._parser._public_module(),
|
|
696
|
+
args=tuple(resolved_args),
|
|
697
|
+
)
|
|
698
|
+
subst: dict[str, TpyType] = {}
|
|
699
|
+
for tp_name, arg in zip(alias_info.type_params, resolved_args):
|
|
700
|
+
if isinstance(arg, TpyType):
|
|
701
|
+
subst[tp_name] = arg
|
|
702
|
+
return substitute_type_params_structural(alias_info.body, subst)
|
|
703
|
+
|
|
704
|
+
# ------------------------------------------------------------------
|
|
705
|
+
# Helpers
|
|
706
|
+
# ------------------------------------------------------------------
|
|
707
|
+
|
|
708
|
+
def _upgrade_from_type_def(
|
|
709
|
+
self, registered: TpyType, resolved: tuple[str, str],
|
|
710
|
+
*, loc: SourceLocation | None = None,
|
|
711
|
+
) -> TpyType:
|
|
712
|
+
"""Mint `_module_qname` / upgrade protocol flags on a qualified
|
|
713
|
+
(`typing.Sized`) or canonical bare-name resolution using the
|
|
714
|
+
resolved `(module, name)` tuple's `TypeDef`.
|
|
715
|
+
|
|
716
|
+
Only NominalTypes without a qname are upgraded. For TypeDefs
|
|
717
|
+
carrying a ProtocolInfo payload, `is_protocol` /
|
|
718
|
+
`is_dynamic_protocol` are also upgraded, and a bare generic
|
|
719
|
+
protocol raises `SemanticError` (with `loc` attached so the
|
|
720
|
+
diagnostic formats as `file:line: error: ...`). Enum-registered
|
|
721
|
+
NominalTypes come back from `_resolve_registered_type` already
|
|
722
|
+
qname-bearing and fall through unchanged.
|
|
723
|
+
"""
|
|
724
|
+
if not isinstance(registered, NominalType) or registered._module_qname:
|
|
725
|
+
return registered
|
|
726
|
+
module, original = resolved
|
|
727
|
+
candidate_qname = f"{module}.{original}"
|
|
728
|
+
td = get_type_def(candidate_qname)
|
|
729
|
+
if td is None:
|
|
730
|
+
return registered
|
|
731
|
+
if td.protocol is None and td.record is None and td.enum is None \
|
|
732
|
+
and td.type_factory is None:
|
|
733
|
+
return registered
|
|
734
|
+
is_protocol = registered.is_protocol
|
|
735
|
+
is_dynamic_protocol = registered.is_dynamic_protocol
|
|
736
|
+
if td.protocol is not None:
|
|
737
|
+
if td.protocol.type_params and not registered.type_args:
|
|
738
|
+
from ..diagnostics import SemanticError
|
|
739
|
+
raise SemanticError(
|
|
740
|
+
f"Generic protocol '{registered.name}' requires type arguments: "
|
|
741
|
+
f"{registered.name}[{', '.join(td.protocol.type_params)}]",
|
|
742
|
+
loc=loc,
|
|
743
|
+
)
|
|
744
|
+
is_protocol = True
|
|
745
|
+
is_dynamic_protocol = td.protocol.is_dynamic
|
|
746
|
+
return NominalType(
|
|
747
|
+
registered.name, registered.type_args,
|
|
748
|
+
is_protocol, candidate_qname, is_dynamic_protocol,
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
def _user_record_qname(
|
|
752
|
+
self, container: str, resolved: tuple[str, str] | None,
|
|
753
|
+
*, canonical: bool = False,
|
|
754
|
+
) -> str | None:
|
|
755
|
+
"""Mint `_module_qname` for a user-record reference.
|
|
756
|
+
|
|
757
|
+
Cross-module refs use the canonicalized import tuple when
|
|
758
|
+
`canonical=True`; same-module refs pull from
|
|
759
|
+
`parser.registry.get_record().module`. Returns None when
|
|
760
|
+
neither source supplies a module (bare placeholders that later
|
|
761
|
+
passes will resolve) or the tuple is not canonicalized.
|
|
762
|
+
"""
|
|
763
|
+
rinfo = self._parser.registry.get_record(container)
|
|
764
|
+
# @builtin_type-with-body records (no factory entry, e.g.
|
|
765
|
+
# asyncio._executor.Task with @builtin_type("tpy.Task")) carry
|
|
766
|
+
# their canonical qname in `builtin_type_key`. It wins over both
|
|
767
|
+
# the canonical-import tuple and the defining-module form so
|
|
768
|
+
# the resulting NominalType's _module_qname matches the static
|
|
769
|
+
# TypeDef key regardless of how the type was imported.
|
|
770
|
+
# `RecordInfo.qualified_name()` short-circuits on builtin_type_key.
|
|
771
|
+
if rinfo is not None and rinfo.builtin_type_key:
|
|
772
|
+
return rinfo.qualified_name()
|
|
773
|
+
if resolved is not None and canonical:
|
|
774
|
+
return f"{resolved[0]}.{resolved[1]}"
|
|
775
|
+
if rinfo is not None and rinfo.module:
|
|
776
|
+
return f"{rinfo.module}.{container}"
|
|
777
|
+
return None
|
|
778
|
+
|
|
779
|
+
def _resolve_primitive_type(
|
|
780
|
+
self, module: str, original: str,
|
|
781
|
+
node: ast.expr | None = None, *, loc: SourceLocation | None = None,
|
|
782
|
+
is_type_arg: bool = False,
|
|
783
|
+
) -> TpyType | None:
|
|
784
|
+
"""Resolve a (module, original_name) pair to a primitive type.
|
|
785
|
+
|
|
786
|
+
Returns the type if it's a directly-mapped primitive (int -> BIGINT, etc.),
|
|
787
|
+
or None if it should fall through to registry lookups.
|
|
788
|
+
Raises ParseError for names that can't be used as types (Protocol).
|
|
789
|
+
Either `node` (ast-based) or `loc` (ref-based) may be passed for
|
|
790
|
+
error reporting.
|
|
791
|
+
"""
|
|
792
|
+
if module == "builtins":
|
|
793
|
+
if original == "int": return BIGINT
|
|
794
|
+
elif original == "float": return FLOAT
|
|
795
|
+
elif original == "bool": return BOOL
|
|
796
|
+
elif original == "str": return STR
|
|
797
|
+
elif original == "bytes": return BYTES
|
|
798
|
+
elif original == "bytearray": return BYTEARRAY
|
|
799
|
+
elif original == "basic_slice": return BASIC_SLICE
|
|
800
|
+
elif original == "slice": return SLICE
|
|
801
|
+
elif original == "None": return NONE if is_type_arg else VOID
|
|
802
|
+
elif original == "type": return NominalType("type", _module_qname=qnames.TYPE)
|
|
803
|
+
elif original == "tuple":
|
|
804
|
+
raise ParseError("tuple requires type arguments: tuple[T1, T2, ...]", node, loc=loc)
|
|
805
|
+
elif module == "tpy":
|
|
806
|
+
if (fixed_int := _FIXED_INT_MAP.get(original)) is not None:
|
|
807
|
+
return fixed_int
|
|
808
|
+
elif original == "Char":
|
|
809
|
+
return CHAR
|
|
810
|
+
elif original == "Float32":
|
|
811
|
+
return FLOAT32
|
|
812
|
+
elif original == "String":
|
|
813
|
+
return STRING
|
|
814
|
+
elif original == "StrView":
|
|
815
|
+
return STRVIEW
|
|
816
|
+
elif original == "BytesView":
|
|
817
|
+
return BYTESVIEW
|
|
818
|
+
elif original == "basic_slice":
|
|
819
|
+
return BASIC_SLICE
|
|
820
|
+
elif original == "slice":
|
|
821
|
+
return SLICE
|
|
822
|
+
elif module == "typing":
|
|
823
|
+
if original == "Self":
|
|
824
|
+
return SELF
|
|
825
|
+
elif original == "Any":
|
|
826
|
+
return ANY
|
|
827
|
+
elif original == "Protocol":
|
|
828
|
+
raise ParseError("'Protocol' cannot be used as a type annotation", node, loc=loc)
|
|
829
|
+
return None
|
|
830
|
+
|
|
831
|
+
def _resolve_registered_type(
|
|
832
|
+
self, name: str, node: ast.expr | None = None,
|
|
833
|
+
*, resolved: bool = False, loc: SourceLocation | None = None,
|
|
834
|
+
) -> TpyType | None:
|
|
835
|
+
"""Look up a name in the type registry (protocols, aliases, records).
|
|
836
|
+
|
|
837
|
+
Raises SemanticError for generic protocols used without type arguments
|
|
838
|
+
(matches the cross-module canonical path in `_resolve_ref` so diag
|
|
839
|
+
output is uniform), or ParseError for completely unknown names.
|
|
840
|
+
Either `node` or `loc` may be passed for error reporting.
|
|
841
|
+
"""
|
|
842
|
+
parser = self._parser
|
|
843
|
+
# Self-reference in a recursive type alias (e.g. list[JsonValue] inside
|
|
844
|
+
# the definition of JsonValue). Return an AliasRef placeholder that
|
|
845
|
+
# survives inside container types and is detected by an
|
|
846
|
+
# `isinstance(typ, AliasRef)` check rather than a name-set lookup.
|
|
847
|
+
if self._pending_alias is not None and name == self._pending_alias:
|
|
848
|
+
return AliasRef(name, module=parser._public_module())
|
|
849
|
+
# Resolve short nested type names: Kind -> Message.Kind
|
|
850
|
+
if name in parser._nested_type_scope:
|
|
851
|
+
dotted = parser._nested_type_scope[name]
|
|
852
|
+
if (enum_type := parser.registry.get_enum(dotted)) is not None:
|
|
853
|
+
return enum_type
|
|
854
|
+
if parser.registry.get_record(dotted) is not None:
|
|
855
|
+
qname = self._user_record_qname(dotted, None)
|
|
856
|
+
return NominalType(dotted, _module_qname=qname)
|
|
857
|
+
if (user_protocol := parser.registry.scan_by_short_name(name)) is not None:
|
|
858
|
+
if user_protocol.type_params:
|
|
859
|
+
from ..diagnostics import SemanticError
|
|
860
|
+
raise SemanticError(
|
|
861
|
+
f"Generic protocol '{name}' requires type arguments: "
|
|
862
|
+
f"{name}[{', '.join(user_protocol.type_params)}]",
|
|
863
|
+
loc=loc,
|
|
864
|
+
)
|
|
865
|
+
qname = f"{user_protocol.module}.{name}" if user_protocol.module else None
|
|
866
|
+
return NominalType(
|
|
867
|
+
name, is_protocol=True, _module_qname=qname,
|
|
868
|
+
is_dynamic_protocol=user_protocol.is_dynamic,
|
|
869
|
+
)
|
|
870
|
+
elif (enum_type := parser.registry.get_enum(name)) is not None:
|
|
871
|
+
return enum_type
|
|
872
|
+
elif (alias_info := parser.registry.get_type_alias_info(name)) is not None:
|
|
873
|
+
if alias_info.type_params:
|
|
874
|
+
# Bare reference to a generic alias -- mirror the protocol
|
|
875
|
+
# arm above: require type arguments at the use site rather
|
|
876
|
+
# than letting the body's TypeParamRefs leak into the
|
|
877
|
+
# annotation. See docs/GENERIC_RECURSIVE_ALIASES_DESIGN.md.
|
|
878
|
+
from ..diagnostics import SemanticError
|
|
879
|
+
raise SemanticError(
|
|
880
|
+
f"Generic type alias '{name}' requires type arguments: "
|
|
881
|
+
f"{name}[{', '.join(alias_info.type_params)}]",
|
|
882
|
+
loc=loc,
|
|
883
|
+
)
|
|
884
|
+
return alias_info.body
|
|
885
|
+
elif not resolved:
|
|
886
|
+
parser._raise_unresolved_import_error(name, node, loc=loc)
|
|
887
|
+
if (resolved or parser.registry.is_known_type(name)
|
|
888
|
+
or name in parser._module_class_names
|
|
889
|
+
or name in parser._module_type_alias_names):
|
|
890
|
+
# Mint qname for same-module user records from parser.registry.
|
|
891
|
+
# Cross-module refs get their qname minted in `_resolve_ref` from
|
|
892
|
+
# the canonicalized import tuple. Builtin-type stubs carry their
|
|
893
|
+
# qname in `builtin_type_key`; leave them bare so the downstream
|
|
894
|
+
# builtin-path minting (is_builtin gate) stays authoritative.
|
|
895
|
+
rinfo = parser.registry.get_record(name)
|
|
896
|
+
if rinfo is not None and rinfo.module and not rinfo.builtin_type_key:
|
|
897
|
+
return NominalType(name, _module_qname=f"{rinfo.module}.{name}")
|
|
898
|
+
return NominalType(name)
|
|
899
|
+
return None
|
|
900
|
+
|
|
901
|
+
def _resolve_qualified_cross_module(
|
|
902
|
+
self, source_module: str, attr: str,
|
|
903
|
+
*, loc: SourceLocation | None = None,
|
|
904
|
+
) -> TpyType | None:
|
|
905
|
+
"""Resolve `attr` against the named source module's exports.
|
|
906
|
+
|
|
907
|
+
Used when ``submod.X`` qualifies a type from a submodule that the
|
|
908
|
+
importing module has bound (via `from pkg import submod`) but
|
|
909
|
+
whose individual records / enums / type aliases are not in the
|
|
910
|
+
importer's local registry. Returns a NominalType / enum_type /
|
|
911
|
+
alias type with the correct cross-module qname, or None.
|
|
912
|
+
"""
|
|
913
|
+
parser = self._parser
|
|
914
|
+
mod_info = parser.registry.get_module(source_module)
|
|
915
|
+
if mod_info is None:
|
|
916
|
+
return None
|
|
917
|
+
if mod_info.records and attr in mod_info.records:
|
|
918
|
+
rinfo = mod_info.records[attr]
|
|
919
|
+
qname = f"{rinfo.module}.{attr}" if rinfo.module else f"{source_module}.{attr}"
|
|
920
|
+
return NominalType(attr, _module_qname=qname)
|
|
921
|
+
if mod_info.enums and attr in mod_info.enums:
|
|
922
|
+
return mod_info.enums[attr]
|
|
923
|
+
if mod_info.type_aliases and attr in mod_info.type_aliases:
|
|
924
|
+
alias_info = mod_info.type_aliases[attr]
|
|
925
|
+
if alias_info.type_params:
|
|
926
|
+
# Cross-module bare reference to a generic alias --
|
|
927
|
+
# require type arguments rather than leaking
|
|
928
|
+
# TypeParamRefs into the annotation.
|
|
929
|
+
from ..diagnostics import SemanticError
|
|
930
|
+
raise SemanticError(
|
|
931
|
+
f"Generic type alias '{attr}' requires type arguments: "
|
|
932
|
+
f"{attr}[{', '.join(alias_info.type_params)}]",
|
|
933
|
+
loc=ref.loc,
|
|
934
|
+
)
|
|
935
|
+
return alias_info.body
|
|
936
|
+
if mod_info.protocols and attr in mod_info.protocols:
|
|
937
|
+
proto = mod_info.protocols[attr]
|
|
938
|
+
if proto.type_params:
|
|
939
|
+
from ..diagnostics import SemanticError
|
|
940
|
+
raise SemanticError(
|
|
941
|
+
f"Generic protocol '{attr}' requires type arguments: "
|
|
942
|
+
f"{attr}[{', '.join(proto.type_params)}]",
|
|
943
|
+
loc=loc,
|
|
944
|
+
)
|
|
945
|
+
qname = f"{source_module}.{attr}"
|
|
946
|
+
return NominalType(
|
|
947
|
+
attr, is_protocol=True, _module_qname=qname,
|
|
948
|
+
is_dynamic_protocol=proto.is_dynamic,
|
|
949
|
+
)
|
|
950
|
+
return None
|
|
951
|
+
|
|
952
|
+
def _resolve_qualified_type_name_str(
|
|
953
|
+
self, local_module: str, attr: str,
|
|
954
|
+
) -> tuple[str, str] | None:
|
|
955
|
+
"""Loc-agnostic variant of _resolve_qualified_type_name: takes
|
|
956
|
+
the module-local name and attribute directly."""
|
|
957
|
+
parser = self._parser
|
|
958
|
+
if local_module in parser._local_defs:
|
|
959
|
+
return None
|
|
960
|
+
canonical = parser._reverse_module_aliases.get(local_module, local_module)
|
|
961
|
+
imports = parser._imports.imports
|
|
962
|
+
if imports is None or canonical not in imports:
|
|
963
|
+
return None
|
|
964
|
+
entry = imports[canonical]
|
|
965
|
+
if entry is not None and not (
|
|
966
|
+
isinstance(entry, set) and canonical in parser._bare_module_imports):
|
|
967
|
+
return None
|
|
968
|
+
return (canonical, attr)
|
|
969
|
+
|
|
970
|
+
def _resolve_dotted_class_name_str(self, dotted: str) -> str | None:
|
|
971
|
+
"""Loc-agnostic variant of _resolve_dotted_class_name: check if a
|
|
972
|
+
dotted-name string resolves to a known module class."""
|
|
973
|
+
parts = dotted.split(".")
|
|
974
|
+
if parts and parts[0] in self._parser._module_class_names:
|
|
975
|
+
return dotted
|
|
976
|
+
return None
|
|
977
|
+
|
|
978
|
+
def _raise_unresolved_qualified_error_str(
|
|
979
|
+
self, dotted: str, loc: SourceLocation | None,
|
|
980
|
+
) -> None:
|
|
981
|
+
"""Loc-based variant of _raise_unresolved_qualified_error for a
|
|
982
|
+
dotted name like 'mod.attr'. Only fires for 2-level dotted names
|
|
983
|
+
(mirrors the original which dispatches on ast.Attribute with a
|
|
984
|
+
Name base)."""
|
|
985
|
+
parts = dotted.split(".")
|
|
986
|
+
if len(parts) == 2:
|
|
987
|
+
mod, attr = parts
|
|
988
|
+
canonical = self._parser._reverse_module_aliases.get(mod, mod)
|
|
989
|
+
if canonical in _IMPLICIT_MODULES:
|
|
990
|
+
raise ParseError(
|
|
991
|
+
f"'{dotted}' requires: import {canonical}", loc=loc,
|
|
992
|
+
)
|
|
993
|
+
|
|
994
|
+
def _resolve_generic_type_from_ref(
|
|
995
|
+
self, ref: TpyTypeRef, name: str, type_def: TypeDef,
|
|
996
|
+
type_param_scope: dict[str, TypeParamKind] | None,
|
|
997
|
+
) -> TpyType:
|
|
998
|
+
"""Resolve a generic reference (name + args) using a TypeDef factory."""
|
|
999
|
+
param_kinds = type_def.param_kinds
|
|
1000
|
+
expected_count = len(param_kinds)
|
|
1001
|
+
|
|
1002
|
+
if len(ref.args) != expected_count:
|
|
1003
|
+
raise ParseError(
|
|
1004
|
+
f"{name} requires exactly {expected_count} type parameters",
|
|
1005
|
+
loc=ref.loc,
|
|
1006
|
+
)
|
|
1007
|
+
|
|
1008
|
+
parsed_args: list[TpyType | int] = []
|
|
1009
|
+
for i, (arg, kind) in enumerate(zip(ref.args, param_kinds)):
|
|
1010
|
+
if kind == TypeParamKind.TYPE:
|
|
1011
|
+
assert not isinstance(arg, int), f"type slot {i} got int literal"
|
|
1012
|
+
parsed_args.append(
|
|
1013
|
+
self.resolve(arg, type_param_scope, is_type_arg=True))
|
|
1014
|
+
elif kind == TypeParamKind.INT:
|
|
1015
|
+
if isinstance(arg, int):
|
|
1016
|
+
parsed_args.append(arg)
|
|
1017
|
+
elif (isinstance(arg, TpyTypeRef) and type_param_scope
|
|
1018
|
+
and arg.name in type_param_scope):
|
|
1019
|
+
param_name = arg.name
|
|
1020
|
+
param_kind = type_param_scope[param_name]
|
|
1021
|
+
if param_kind == TypeParamKind.INT:
|
|
1022
|
+
parsed_args.append(
|
|
1023
|
+
TypeParamRef(param_name, kind=TypeParamKind.INT))
|
|
1024
|
+
else:
|
|
1025
|
+
raise ParseError(
|
|
1026
|
+
f"{name} parameter {i + 1} requires an integer, "
|
|
1027
|
+
f"got type parameter '{param_name}'",
|
|
1028
|
+
loc=ref.loc,
|
|
1029
|
+
)
|
|
1030
|
+
else:
|
|
1031
|
+
raise ParseError(
|
|
1032
|
+
f"{name} parameter {i + 1} must be an integer literal or int type parameter",
|
|
1033
|
+
loc=ref.loc,
|
|
1034
|
+
)
|
|
1035
|
+
|
|
1036
|
+
assert type_def.type_factory is not None
|
|
1037
|
+
try:
|
|
1038
|
+
return type_def.type_factory(*parsed_args)
|
|
1039
|
+
except ParseError:
|
|
1040
|
+
raise
|
|
1041
|
+
except Exception as e:
|
|
1042
|
+
raise ParseError(f"Failed to construct type {name}: {e}", loc=ref.loc) from e
|
|
1043
|
+
|
|
1044
|
+
def _resolve_record_type_args_from_ref(
|
|
1045
|
+
self, ref: TpyTypeRef, name: str,
|
|
1046
|
+
type_param_scope: dict[str, TypeParamKind] | None,
|
|
1047
|
+
) -> tuple[TpyType | int, ...]:
|
|
1048
|
+
"""Resolve record type arguments (type-args for a user record generic)."""
|
|
1049
|
+
type_args: list[TpyType | int] = []
|
|
1050
|
+
for arg in ref.args:
|
|
1051
|
+
if isinstance(arg, int):
|
|
1052
|
+
type_args.append(arg)
|
|
1053
|
+
elif (isinstance(arg, TpyTypeRef) and type_param_scope
|
|
1054
|
+
and arg.name in type_param_scope):
|
|
1055
|
+
kind = type_param_scope[arg.name]
|
|
1056
|
+
type_args.append(TypeParamRef(arg.name, kind=kind))
|
|
1057
|
+
else:
|
|
1058
|
+
type_args.append(
|
|
1059
|
+
self.resolve(arg, type_param_scope, is_type_arg=True))
|
|
1060
|
+
return tuple(type_args)
|