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,76 @@
|
|
|
1
|
+
"""Tests for macro_loader.validate_and_call_macro."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from .macro_loader import validate_and_call_macro
|
|
6
|
+
from .diagnostics import SemanticError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class _FakeLoc:
|
|
10
|
+
"""Minimal loc object for test errors."""
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.lineno = 1
|
|
13
|
+
self.col_offset = 0
|
|
14
|
+
self.end_lineno = 1
|
|
15
|
+
self.end_col_offset = 0
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_LOC = _FakeLoc()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _make_macro(fn):
|
|
22
|
+
fn._is_class_macro = True
|
|
23
|
+
return fn
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class TestValidateAndCallMacro:
|
|
27
|
+
def test_unknown_kwarg(self):
|
|
28
|
+
def my_macro(cls, *, x: int = 0):
|
|
29
|
+
pass
|
|
30
|
+
with pytest.raises(SemanticError, match="unknown keyword argument 'y'"):
|
|
31
|
+
validate_and_call_macro(my_macro, None, {"y": 1}, "test.my_macro", _LOC)
|
|
32
|
+
|
|
33
|
+
def test_unknown_kwarg_no_params(self):
|
|
34
|
+
def my_macro(cls):
|
|
35
|
+
pass
|
|
36
|
+
with pytest.raises(SemanticError, match="takes no keyword arguments"):
|
|
37
|
+
validate_and_call_macro(my_macro, None, {"x": 1}, "test.my_macro", _LOC)
|
|
38
|
+
|
|
39
|
+
def test_missing_required_kwarg(self):
|
|
40
|
+
def my_macro(cls, *, required: str):
|
|
41
|
+
pass
|
|
42
|
+
with pytest.raises(SemanticError, match="missing required keyword argument 'required'"):
|
|
43
|
+
validate_and_call_macro(my_macro, None, {}, "test.my_macro", _LOC)
|
|
44
|
+
|
|
45
|
+
def test_type_mismatch(self):
|
|
46
|
+
def my_macro(cls, *, flag: bool = False):
|
|
47
|
+
pass
|
|
48
|
+
with pytest.raises(SemanticError, match="'flag' must be bool, got str"):
|
|
49
|
+
validate_and_call_macro(my_macro, None, {"flag": "yes"}, "test.my_macro", _LOC)
|
|
50
|
+
|
|
51
|
+
def test_unexpected_exception_wrapped(self):
|
|
52
|
+
def my_macro(cls):
|
|
53
|
+
raise ValueError("something broke")
|
|
54
|
+
with pytest.raises(SemanticError, match="macro raised ValueError: something broke"):
|
|
55
|
+
validate_and_call_macro(my_macro, None, {}, "test.my_macro", _LOC)
|
|
56
|
+
|
|
57
|
+
def test_semantic_error_not_wrapped(self):
|
|
58
|
+
def my_macro(cls):
|
|
59
|
+
raise SemanticError("custom error", _LOC)
|
|
60
|
+
with pytest.raises(SemanticError, match="custom error"):
|
|
61
|
+
validate_and_call_macro(my_macro, None, {}, "test.my_macro", _LOC)
|
|
62
|
+
|
|
63
|
+
def test_var_keyword_allows_unknown(self):
|
|
64
|
+
received = {}
|
|
65
|
+
def my_macro(cls, **kw):
|
|
66
|
+
received.update(kw)
|
|
67
|
+
validate_and_call_macro(my_macro, None, {"anything": 42}, "test.my_macro", _LOC)
|
|
68
|
+
assert received == {"anything": 42}
|
|
69
|
+
|
|
70
|
+
def test_valid_call(self):
|
|
71
|
+
results = {}
|
|
72
|
+
def my_macro(cls, *, frozen: bool = False, order: bool = False):
|
|
73
|
+
results["frozen"] = frozen
|
|
74
|
+
results["order"] = order
|
|
75
|
+
validate_and_call_macro(my_macro, "fake_cls", {"frozen": True}, "test.my_macro", _LOC)
|
|
76
|
+
assert results == {"frozen": True, "order": False}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""Tests for sema.method_expansion.
|
|
2
|
+
|
|
3
|
+
The per-record entry point (`expand_methods_for_record`) is invoked from
|
|
4
|
+
`register_record` after macros run, so macro-added methods flow through
|
|
5
|
+
the same self-flag derivation / wrapping / cloning pipeline as
|
|
6
|
+
source-authored methods (Phase F.3b.6.5). These tests pin the
|
|
7
|
+
idempotency contract that the per-record call relies on.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from .parse.nodes import TpyFunction, TpyRecord, RecordLinkage
|
|
15
|
+
from .diagnostics import SemanticError
|
|
16
|
+
from .sema.method_expansion import expand_methods_for_record
|
|
17
|
+
from .typesys import (
|
|
18
|
+
AutoReadonlyType,
|
|
19
|
+
AutoOwnType,
|
|
20
|
+
OwnType,
|
|
21
|
+
SelfType,
|
|
22
|
+
NominalType,
|
|
23
|
+
SELF,
|
|
24
|
+
VOID,
|
|
25
|
+
INT32,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _make_record(methods: list[TpyFunction]) -> TpyRecord:
|
|
30
|
+
return TpyRecord(
|
|
31
|
+
name="R",
|
|
32
|
+
fields=[],
|
|
33
|
+
methods=methods,
|
|
34
|
+
bases=[],
|
|
35
|
+
linkage=RecordLinkage.DEFAULT,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _make_method(**kwargs) -> TpyFunction:
|
|
40
|
+
return TpyFunction(
|
|
41
|
+
name=kwargs.pop("name", "m"),
|
|
42
|
+
params=kwargs.pop("params", []),
|
|
43
|
+
return_type=kwargs.pop("return_type", VOID),
|
|
44
|
+
body=[],
|
|
45
|
+
is_method=True,
|
|
46
|
+
**kwargs,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class TestAutoReadonlyDecoratorExpansion:
|
|
51
|
+
def test_decorator_expands_to_mutable_and_const_clones(self):
|
|
52
|
+
method = _make_method(
|
|
53
|
+
name="get",
|
|
54
|
+
return_type=INT32,
|
|
55
|
+
has_auto_readonly_decorator=True,
|
|
56
|
+
)
|
|
57
|
+
record = _make_record([method])
|
|
58
|
+
|
|
59
|
+
expand_methods_for_record(record)
|
|
60
|
+
|
|
61
|
+
assert len(record.methods) == 2
|
|
62
|
+
mutable, const = record.methods
|
|
63
|
+
assert mutable.is_auto_readonly_mutable_clone
|
|
64
|
+
assert not mutable.is_readonly
|
|
65
|
+
assert not const.is_auto_readonly_mutable_clone
|
|
66
|
+
assert const.is_readonly
|
|
67
|
+
# Both clones are "expansion done" and carry no derivation source.
|
|
68
|
+
assert mutable.self_annotation is None
|
|
69
|
+
assert const.self_annotation is None
|
|
70
|
+
assert not mutable.has_auto_readonly_decorator
|
|
71
|
+
assert not const.has_auto_readonly_decorator
|
|
72
|
+
|
|
73
|
+
def test_decorator_expansion_is_idempotent(self):
|
|
74
|
+
method = _make_method(
|
|
75
|
+
name="get",
|
|
76
|
+
return_type=INT32,
|
|
77
|
+
has_auto_readonly_decorator=True,
|
|
78
|
+
)
|
|
79
|
+
record = _make_record([method])
|
|
80
|
+
|
|
81
|
+
expand_methods_for_record(record)
|
|
82
|
+
first_count = len(record.methods)
|
|
83
|
+
expand_methods_for_record(record)
|
|
84
|
+
assert len(record.methods) == first_count
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class TestAutoReadonlySelfExpansion:
|
|
88
|
+
def test_self_auto_readonly_clones_and_strips_annotation(self):
|
|
89
|
+
method = _make_method(
|
|
90
|
+
name="m",
|
|
91
|
+
self_annotation=AutoReadonlyType(SELF),
|
|
92
|
+
)
|
|
93
|
+
record = _make_record([method])
|
|
94
|
+
|
|
95
|
+
expand_methods_for_record(record)
|
|
96
|
+
|
|
97
|
+
assert len(record.methods) == 2
|
|
98
|
+
# A second expansion must not re-clone -- self_annotation is nulled
|
|
99
|
+
# on both halves so _derive_self_flags doesn't re-set auto_readonly.
|
|
100
|
+
expand_methods_for_record(record)
|
|
101
|
+
assert len(record.methods) == 2
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TestAutoOwnSelfExpansion:
|
|
105
|
+
def test_self_auto_own_clones_and_strips_annotation(self):
|
|
106
|
+
method = _make_method(
|
|
107
|
+
name="take",
|
|
108
|
+
self_annotation=AutoOwnType(SELF),
|
|
109
|
+
return_type=AutoOwnType(NominalType("R")),
|
|
110
|
+
)
|
|
111
|
+
record = _make_record([method])
|
|
112
|
+
|
|
113
|
+
expand_methods_for_record(record)
|
|
114
|
+
|
|
115
|
+
assert len(record.methods) == 2
|
|
116
|
+
borrowing, consuming = record.methods
|
|
117
|
+
assert borrowing.is_auto_own_borrowing_clone
|
|
118
|
+
assert not borrowing.is_consuming
|
|
119
|
+
assert consuming.is_consuming
|
|
120
|
+
assert borrowing.self_annotation is None
|
|
121
|
+
assert consuming.self_annotation is None
|
|
122
|
+
|
|
123
|
+
expand_methods_for_record(record)
|
|
124
|
+
assert len(record.methods) == 2
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class TestConsumingSelfNotCloned:
|
|
128
|
+
def test_own_self_sets_is_consuming_no_clone(self):
|
|
129
|
+
method = _make_method(
|
|
130
|
+
name="take",
|
|
131
|
+
self_annotation=OwnType(SELF),
|
|
132
|
+
)
|
|
133
|
+
record = _make_record([method])
|
|
134
|
+
|
|
135
|
+
expand_methods_for_record(record)
|
|
136
|
+
|
|
137
|
+
assert len(record.methods) == 1
|
|
138
|
+
assert record.methods[0].is_consuming
|
|
139
|
+
# self_annotation is cleared after derivation so a second pass
|
|
140
|
+
# doesn't re-fire `_derive_self_flags` on it (symmetric with the
|
|
141
|
+
# clone paths).
|
|
142
|
+
assert record.methods[0].self_annotation is None
|
|
143
|
+
|
|
144
|
+
expand_methods_for_record(record)
|
|
145
|
+
assert len(record.methods) == 1
|
|
146
|
+
assert record.methods[0].is_consuming
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class TestSelfAnnotationValidation:
|
|
150
|
+
def test_own_self_on_init_raises_semantic_error(self):
|
|
151
|
+
method = _make_method(
|
|
152
|
+
name="__init__",
|
|
153
|
+
self_annotation=OwnType(SELF),
|
|
154
|
+
)
|
|
155
|
+
record = _make_record([method])
|
|
156
|
+
|
|
157
|
+
with pytest.raises(SemanticError, match="Own\\[Self\\] is not allowed on '__init__'"):
|
|
158
|
+
expand_methods_for_record(record)
|
|
159
|
+
|
|
160
|
+
def test_own_self_on_del_raises_semantic_error(self):
|
|
161
|
+
method = _make_method(
|
|
162
|
+
name="__del__",
|
|
163
|
+
self_annotation=OwnType(SELF),
|
|
164
|
+
)
|
|
165
|
+
record = _make_record([method])
|
|
166
|
+
|
|
167
|
+
with pytest.raises(SemanticError, match="Own\\[Self\\] is not allowed on '__del__'"):
|
|
168
|
+
expand_methods_for_record(record)
|
|
169
|
+
|
|
170
|
+
def test_auto_readonly_self_on_init_raises_semantic_error(self):
|
|
171
|
+
method = _make_method(
|
|
172
|
+
name="__init__",
|
|
173
|
+
self_annotation=AutoReadonlyType(SELF),
|
|
174
|
+
)
|
|
175
|
+
record = _make_record([method])
|
|
176
|
+
|
|
177
|
+
with pytest.raises(SemanticError, match="auto_readonly\\[Self\\] is not allowed on '__init__'"):
|
|
178
|
+
expand_methods_for_record(record)
|
|
179
|
+
|
|
180
|
+
def test_own_self_with_readonly_raises_semantic_error(self):
|
|
181
|
+
method = _make_method(
|
|
182
|
+
name="m",
|
|
183
|
+
self_annotation=OwnType(SELF),
|
|
184
|
+
is_readonly=True,
|
|
185
|
+
)
|
|
186
|
+
record = _make_record([method])
|
|
187
|
+
|
|
188
|
+
with pytest.raises(SemanticError, match="Own\\[Self\\] cannot be combined with @readonly"):
|
|
189
|
+
expand_methods_for_record(record)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class TestPerParamAutoReadonlyTriggersCloning:
|
|
193
|
+
"""Per-param `auto_readonly[T]` annotation alone (no decorator, no self:
|
|
194
|
+
auto_readonly[Self]) must still set `auto_readonly=True` in sema and
|
|
195
|
+
trigger cloning. Regression path for F.3b.6.2 which moved the per-param
|
|
196
|
+
detection out of the parser.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
def test_per_param_auto_readonly_clones(self):
|
|
200
|
+
# Method with a param whose type carries AutoReadonlyType.
|
|
201
|
+
method = _make_method(
|
|
202
|
+
name="pick",
|
|
203
|
+
params=[("x", AutoReadonlyType(NominalType("T")))],
|
|
204
|
+
return_type=INT32,
|
|
205
|
+
)
|
|
206
|
+
record = _make_record([method])
|
|
207
|
+
|
|
208
|
+
expand_methods_for_record(record)
|
|
209
|
+
|
|
210
|
+
# Cloned into mutable + const halves.
|
|
211
|
+
assert len(record.methods) == 2
|
|
212
|
+
mutable, const = record.methods
|
|
213
|
+
assert mutable.is_auto_readonly_mutable_clone
|
|
214
|
+
assert not mutable.is_readonly
|
|
215
|
+
assert not const.is_auto_readonly_mutable_clone
|
|
216
|
+
assert const.is_readonly
|
|
217
|
+
# Mutable clone strips the AutoReadonlyType; const clone applies it.
|
|
218
|
+
from .typesys import ReadonlyType, strip_auto_readonly, apply_auto_readonly
|
|
219
|
+
_, mut_ptype = mutable.params[0]
|
|
220
|
+
_, const_ptype = const.params[0]
|
|
221
|
+
assert not isinstance(mut_ptype, AutoReadonlyType)
|
|
222
|
+
assert isinstance(const_ptype, ReadonlyType)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class TestMacroAddedMethodExpansion:
|
|
226
|
+
"""Simulates the macro-added method flow: add a method post-parse and
|
|
227
|
+
verify it flows through the same pipeline when the per-record entry
|
|
228
|
+
point runs. This is the regression the F.3b.6.5 change protects.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def test_method_added_after_initial_expansion_gets_expanded(self):
|
|
232
|
+
# First method: already expanded form (simulates parser output
|
|
233
|
+
# that the module-level caller might have processed before
|
|
234
|
+
# macros add theirs). It stays put.
|
|
235
|
+
existing = _make_method(name="existing", return_type=INT32)
|
|
236
|
+
record = _make_record([existing])
|
|
237
|
+
expand_methods_for_record(record)
|
|
238
|
+
assert len(record.methods) == 1
|
|
239
|
+
|
|
240
|
+
# Macro adds a new method with @auto_readonly decorator flag.
|
|
241
|
+
new_method = _make_method(
|
|
242
|
+
name="new_method",
|
|
243
|
+
return_type=INT32,
|
|
244
|
+
has_auto_readonly_decorator=True,
|
|
245
|
+
)
|
|
246
|
+
record.methods.append(new_method)
|
|
247
|
+
|
|
248
|
+
expand_methods_for_record(record)
|
|
249
|
+
|
|
250
|
+
# existing stays as 1 method; new_method cloned into 2. Total 3.
|
|
251
|
+
assert len(record.methods) == 3
|
|
252
|
+
names = [m.name for m in record.methods]
|
|
253
|
+
assert names.count("existing") == 1
|
|
254
|
+
assert names.count("new_method") == 2
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Pin the qname-aware nominal identity invariants.
|
|
2
|
+
|
|
3
|
+
Three concerns the test guards against:
|
|
4
|
+
|
|
5
|
+
1. `NominalType` equality + hash includes `_module_qname` -- two
|
|
6
|
+
records with the same short name from different modules are
|
|
7
|
+
distinct in sets / dicts / unions, and set dedup is insertion-
|
|
8
|
+
order independent (proper equivalence relation).
|
|
9
|
+
2. `TypeRegistry.get_record_for_type` is qname-first -- when the
|
|
10
|
+
NominalType carries a qname, the lookup routes to the matching
|
|
11
|
+
record even if a locally-registered record shadows the short name.
|
|
12
|
+
Covers both records registered via `register_record(info, name)`
|
|
13
|
+
and records that land in the registry only via `register_module`.
|
|
14
|
+
3. `TypeRegistry.is_subclass_of` works for cross-module child/base
|
|
15
|
+
pairs whose short names are shadowed by local records.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from tpyc.typesys import (
|
|
22
|
+
ModuleInfo, NominalType, RecordInfo, TypeRegistry,
|
|
23
|
+
make_union, UnionType, same_nominal_symbol_loose,
|
|
24
|
+
)
|
|
25
|
+
from tpyc.type_def_registry import (
|
|
26
|
+
attach_dynamic_type_def, TypeCategory, clear_dynamic_type_defs,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture(autouse=True)
|
|
31
|
+
def _cleanup():
|
|
32
|
+
yield
|
|
33
|
+
clear_dynamic_type_defs()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _attach_record_td(info: RecordInfo) -> None:
|
|
37
|
+
"""Attach a TypeDef.record entry so `is_user_record` resolves --
|
|
38
|
+
mirrors what sema's `register_record` does in production."""
|
|
39
|
+
attach_dynamic_type_def(
|
|
40
|
+
info.qualified_name(),
|
|
41
|
+
TypeCategory.RECORD,
|
|
42
|
+
record=info,
|
|
43
|
+
is_value_type=False,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# 1. Equality / hash invariant
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
class TestNominalEquality:
|
|
52
|
+
def test_cross_module_same_name_unequal(self) -> None:
|
|
53
|
+
a = NominalType("Foo", _module_qname="pkg_a.Foo")
|
|
54
|
+
b = NominalType("Foo", _module_qname="pkg_b.Foo")
|
|
55
|
+
assert a != b
|
|
56
|
+
assert hash(a) != hash(b) or a != b # hashes may collide, equality must not
|
|
57
|
+
|
|
58
|
+
def test_bare_and_qname_bearing_unequal(self) -> None:
|
|
59
|
+
# Strict contract: bare != qname-bearing. Transitional sites
|
|
60
|
+
# that want the loose bridge must call
|
|
61
|
+
# `same_nominal_symbol_loose` explicitly.
|
|
62
|
+
bare = NominalType("Foo")
|
|
63
|
+
qn = NominalType("Foo", _module_qname="mod.Foo")
|
|
64
|
+
assert bare != qn
|
|
65
|
+
|
|
66
|
+
def test_set_dedup_order_independent(self) -> None:
|
|
67
|
+
a = NominalType("Foo", _module_qname="pkg_a.Foo")
|
|
68
|
+
b = NominalType("Foo", _module_qname="pkg_b.Foo")
|
|
69
|
+
c = NominalType("Foo")
|
|
70
|
+
# Three pairwise-unequal elements -> always 3 in the set
|
|
71
|
+
# regardless of insertion order (guards against the non-
|
|
72
|
+
# transitive-equality trap).
|
|
73
|
+
assert len({a, b, c}) == 3
|
|
74
|
+
assert len({c, a, b}) == 3
|
|
75
|
+
assert len({b, c, a}) == 3
|
|
76
|
+
|
|
77
|
+
def test_make_union_keeps_cross_module_distinct(self) -> None:
|
|
78
|
+
a = NominalType("Foo", _module_qname="pkg_a.Foo")
|
|
79
|
+
b = NominalType("Foo", _module_qname="pkg_b.Foo")
|
|
80
|
+
u = make_union(a, b)
|
|
81
|
+
assert isinstance(u, UnionType)
|
|
82
|
+
assert len(u.members) == 2
|
|
83
|
+
|
|
84
|
+
def test_same_qname_equal(self) -> None:
|
|
85
|
+
a = NominalType("Foo", _module_qname="mod.Foo")
|
|
86
|
+
b = NominalType("Foo", _module_qname="mod.Foo")
|
|
87
|
+
assert a == b
|
|
88
|
+
assert hash(a) == hash(b)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# 2. same_nominal_symbol_loose -- transitional bridging helper
|
|
93
|
+
# ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
class TestLooseBridging:
|
|
96
|
+
def test_bare_matches_qname_bearing(self) -> None:
|
|
97
|
+
bare = NominalType("Foo")
|
|
98
|
+
qn = NominalType("Foo", _module_qname="mod.Foo")
|
|
99
|
+
assert same_nominal_symbol_loose(bare, qn)
|
|
100
|
+
assert same_nominal_symbol_loose(qn, bare)
|
|
101
|
+
|
|
102
|
+
def test_different_qnames_still_unequal(self) -> None:
|
|
103
|
+
# loose must NOT paper over cross-module collisions.
|
|
104
|
+
a = NominalType("Foo", _module_qname="pkg_a.Foo")
|
|
105
|
+
b = NominalType("Foo", _module_qname="pkg_b.Foo")
|
|
106
|
+
assert not same_nominal_symbol_loose(a, b)
|
|
107
|
+
|
|
108
|
+
def test_rejects_structural_differences(self) -> None:
|
|
109
|
+
# Different name / type_args / is_protocol -> False regardless
|
|
110
|
+
# of qname state.
|
|
111
|
+
bare_a = NominalType("Foo")
|
|
112
|
+
bare_b = NominalType("Bar")
|
|
113
|
+
assert not same_nominal_symbol_loose(bare_a, bare_b)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# 3. Qname-aware lookup on TypeRegistry
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
class TestRegistryLookup:
|
|
121
|
+
def _make_registry_with_shadow(self) -> tuple[TypeRegistry, RecordInfo, RecordInfo]:
|
|
122
|
+
"""A registry where short name "Foo" is shadowed:
|
|
123
|
+
- `__main__.Foo` registered via `register_record` (local).
|
|
124
|
+
- `pkg.Foo` registered via `register_module` (import-only).
|
|
125
|
+
"""
|
|
126
|
+
reg = TypeRegistry()
|
|
127
|
+
main_foo = RecordInfo(name="Foo", fields=[], module="__main__")
|
|
128
|
+
pkg_foo = RecordInfo(name="Foo", fields=[], module="pkg")
|
|
129
|
+
reg.register_record(main_foo)
|
|
130
|
+
reg.register_module(ModuleInfo(name="pkg", records={"Foo": pkg_foo}))
|
|
131
|
+
_attach_record_td(main_foo)
|
|
132
|
+
_attach_record_td(pkg_foo)
|
|
133
|
+
return reg, main_foo, pkg_foo
|
|
134
|
+
|
|
135
|
+
def test_qname_routes_to_cross_module_record(self) -> None:
|
|
136
|
+
reg, main_foo, pkg_foo = self._make_registry_with_shadow()
|
|
137
|
+
n = NominalType("Foo", _module_qname="pkg.Foo")
|
|
138
|
+
assert reg.get_record_for_type(n) is pkg_foo
|
|
139
|
+
|
|
140
|
+
def test_qname_routes_to_local_record(self) -> None:
|
|
141
|
+
reg, main_foo, pkg_foo = self._make_registry_with_shadow()
|
|
142
|
+
n = NominalType("Foo", _module_qname="__main__.Foo")
|
|
143
|
+
assert reg.get_record_for_type(n) is main_foo
|
|
144
|
+
|
|
145
|
+
def test_bare_falls_back_to_short_name(self) -> None:
|
|
146
|
+
reg, main_foo, pkg_foo = self._make_registry_with_shadow()
|
|
147
|
+
# Bare placeholder still resolves to whatever is in
|
|
148
|
+
# `self.records[name]` (here: the local __main__.Foo). This
|
|
149
|
+
# is the transient parse/resolve behavior; callers that need
|
|
150
|
+
# stricter semantics should pass a qname-bearing NominalType.
|
|
151
|
+
n = NominalType("Foo")
|
|
152
|
+
assert reg.get_record_for_type(n) is main_foo
|
|
153
|
+
|
|
154
|
+
def test_is_subclass_of_cross_module(self) -> None:
|
|
155
|
+
# Local `Base` shadows `pkg.Base`, and `pkg.Child` extends
|
|
156
|
+
# `pkg.Base`. Qname-aware lookup must walk the pkg chain
|
|
157
|
+
# rather than the locally-registered `Base`.
|
|
158
|
+
reg = TypeRegistry()
|
|
159
|
+
main_base = RecordInfo(name="Base", fields=[], module="__main__")
|
|
160
|
+
reg.register_record(main_base)
|
|
161
|
+
_attach_record_td(main_base)
|
|
162
|
+
|
|
163
|
+
pkg_base = RecordInfo(name="Base", fields=[], module="pkg")
|
|
164
|
+
base_ref = NominalType("Base", _module_qname="pkg.Base")
|
|
165
|
+
pkg_child = RecordInfo(
|
|
166
|
+
name="Child", fields=[], module="pkg",
|
|
167
|
+
parents=[base_ref],
|
|
168
|
+
mro_ancestors=[base_ref],
|
|
169
|
+
)
|
|
170
|
+
reg.register_module(ModuleInfo(
|
|
171
|
+
name="pkg", records={"Base": pkg_base, "Child": pkg_child},
|
|
172
|
+
))
|
|
173
|
+
_attach_record_td(pkg_base)
|
|
174
|
+
_attach_record_td(pkg_child)
|
|
175
|
+
|
|
176
|
+
child_n = NominalType("Child", _module_qname="pkg.Child")
|
|
177
|
+
base_n = NominalType("Base", _module_qname="pkg.Base")
|
|
178
|
+
assert reg.is_subclass_of(child_n, base_n)
|
|
179
|
+
|
|
180
|
+
# Sanity: local __main__.Base is NOT a parent of pkg.Child.
|
|
181
|
+
main_base_n = NominalType("Base", _module_qname="__main__.Base")
|
|
182
|
+
assert not reg.is_subclass_of(child_n, main_base_n)
|