tpy-lang 0.3.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
- tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
- tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
- tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
- tpyc/__init__.py +104 -0
- tpyc/__main__.py +6 -0
- tpyc/_buildinfo.py +1 -0
- tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
- tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
- tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
- tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
- tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
- tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
- tpyc/_data/lib/tpy/_functools_macros.py +80 -0
- tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
- tpyc/_data/lib/tpy/argparse.py +2062 -0
- tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
- tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
- tpyc/_data/lib/tpy/base64.py +410 -0
- tpyc/_data/lib/tpy/bisect.py +39 -0
- tpyc/_data/lib/tpy/builtins.py +38 -0
- tpyc/_data/lib/tpy/dataclasses.py +354 -0
- tpyc/_data/lib/tpy/enum.py +23 -0
- tpyc/_data/lib/tpy/functools.py +33 -0
- tpyc/_data/lib/tpy/hashlib.py +206 -0
- tpyc/_data/lib/tpy/heapq.py +118 -0
- tpyc/_data/lib/tpy/io.py +395 -0
- tpyc/_data/lib/tpy/json.py +221 -0
- tpyc/_data/lib/tpy/math.py +406 -0
- tpyc/_data/lib/tpy/random.py +597 -0
- tpyc/_data/lib/tpy/re.py +467 -0
- tpyc/_data/lib/tpy/socket.py +379 -0
- tpyc/_data/lib/tpy/struct.py +178 -0
- tpyc/_data/lib/tpy/sys.py +40 -0
- tpyc/_data/lib/tpy/time.py +39 -0
- tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
- tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
- tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
- tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
- tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
- tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
- tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
- tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
- tpyc/_data/lib/tpy/tpy/_version.py +29 -0
- tpyc/_data/lib/tpy/tpy/bits.py +28 -0
- tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
- tpyc/_data/lib/tpy/tpy/extern.py +8 -0
- tpyc/_data/lib/tpy/tpy/mem.py +49 -0
- tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
- tpyc/_data/lib/tpy/tpy/version.py +21 -0
- tpyc/_data/lib/tpy/typing.py +13 -0
- tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
- tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
- tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
- tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
- tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
- tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
- tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
- tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
- tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
- tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
- tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
- tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
- tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
- tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
- tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
- tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
- tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
- tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
- tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
- tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
- tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
- tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
- tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
- tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
- tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
- tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
- tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
- tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
- tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
- tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
- tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
- tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
- tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
- tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
- tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
- tpyc/_data/runtime/cpp/third_party/README.md +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
- tpyc/build/__init__.py +7 -0
- tpyc/build/pcre2.py +122 -0
- tpyc/build/third_party.py +413 -0
- tpyc/cli.py +822 -0
- tpyc/codegen_cpp/__init__.py +18 -0
- tpyc/codegen_cpp/builtins.py +484 -0
- tpyc/codegen_cpp/context.py +2064 -0
- tpyc/codegen_cpp/expressions.py +5940 -0
- tpyc/codegen_cpp/functions.py +1913 -0
- tpyc/codegen_cpp/gen_async.py +3258 -0
- tpyc/codegen_cpp/gen_generators.py +657 -0
- tpyc/codegen_cpp/generator.py +2258 -0
- tpyc/codegen_cpp/match.py +1997 -0
- tpyc/codegen_cpp/param_const.py +172 -0
- tpyc/codegen_cpp/protocols.py +907 -0
- tpyc/codegen_cpp/records.py +1654 -0
- tpyc/codegen_cpp/resumable_cfg.py +1651 -0
- tpyc/codegen_cpp/statements.py +4963 -0
- tpyc/codegen_cpp/string_dispatch.py +76 -0
- tpyc/codegen_cpp/test_context.py +46 -0
- tpyc/codegen_cpp/test_param_const.py +113 -0
- tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
- tpyc/codegen_cpp/type_resolution.py +53 -0
- tpyc/codegen_cpp/types.py +436 -0
- tpyc/codegen_cpp/variant_access.py +135 -0
- tpyc/coercions.py +749 -0
- tpyc/compilation_context.py +57 -0
- tpyc/compiler.py +3945 -0
- tpyc/cycle_detection.py +358 -0
- tpyc/diagnostics.py +135 -0
- tpyc/dump_types.py +353 -0
- tpyc/frontend_diagnostics.py +47 -0
- tpyc/frontend_ir/__init__.py +140 -0
- tpyc/frontend_ir/lower.py +1098 -0
- tpyc/frontend_ir/nodes.py +718 -0
- tpyc/frontend_ir/resolver_adapter.py +151 -0
- tpyc/frontend_plugin.py +209 -0
- tpyc/install_docs.py +81 -0
- tpyc/liveness.py +756 -0
- tpyc/macro_api.py +1724 -0
- tpyc/macro_loader.py +497 -0
- tpyc/module_names.py +64 -0
- tpyc/modules/__init__.py +31 -0
- tpyc/modules/defs.py +89 -0
- tpyc/modules/registry.py +36 -0
- tpyc/modules/resolver.py +192 -0
- tpyc/modules/type_resolution.py +629 -0
- tpyc/namespace.py +172 -0
- tpyc/parse/__init__.py +84 -0
- tpyc/parse/imports.py +490 -0
- tpyc/parse/nodes.py +1732 -0
- tpyc/parse/parser.py +4043 -0
- tpyc/parse/resolve_refs.py +466 -0
- tpyc/parse/type_resolver.py +1060 -0
- tpyc/prescan.py +254 -0
- tpyc/qnames.py +149 -0
- tpyc/repl.py +529 -0
- tpyc/repl_backends.py +848 -0
- tpyc/sema/__init__.py +21 -0
- tpyc/sema/analyzer.py +3625 -0
- tpyc/sema/bound_check.py +72 -0
- tpyc/sema/builder_trace.py +684 -0
- tpyc/sema/calls.py +5406 -0
- tpyc/sema/compatibility.py +2107 -0
- tpyc/sema/context.py +1243 -0
- tpyc/sema/expressions.py +3737 -0
- tpyc/sema/flow_facts.py +199 -0
- tpyc/sema/init_tracker.py +150 -0
- tpyc/sema/list_literals.py +69 -0
- tpyc/sema/literal_utils.py +27 -0
- tpyc/sema/local_deduction.py +1088 -0
- tpyc/sema/macros.py +179 -0
- tpyc/sema/match.py +1177 -0
- tpyc/sema/method_expansion.py +347 -0
- tpyc/sema/methods.py +2197 -0
- tpyc/sema/mutation_propagation.py +268 -0
- tpyc/sema/narrowing.py +857 -0
- tpyc/sema/numeric_lattice.py +160 -0
- tpyc/sema/operators.py +402 -0
- tpyc/sema/overloads.py +841 -0
- tpyc/sema/protocols.py +1209 -0
- tpyc/sema/reach_analysis.py +202 -0
- tpyc/sema/registration.py +3156 -0
- tpyc/sema/scope_tracker.py +193 -0
- tpyc/sema/statements.py +4426 -0
- tpyc/sema/type_ops.py +1879 -0
- tpyc/sema/value_range.py +181 -0
- tpyc/symbol_binding.py +259 -0
- tpyc/test_c3_mro.py +208 -0
- tpyc/test_cli_argv.py +52 -0
- tpyc/test_compiler.py +559 -0
- tpyc/test_contains_type_param.py +101 -0
- tpyc/test_cycle_detection.py +221 -0
- tpyc/test_dump_types.py +225 -0
- tpyc/test_install_docs.py +65 -0
- tpyc/test_local_cpp_form.py +135 -0
- tpyc/test_macro_loader.py +76 -0
- tpyc/test_method_expansion.py +254 -0
- tpyc/test_nominal_identity.py +182 -0
- tpyc/test_overloads.py +410 -0
- tpyc/test_parse.py +303 -0
- tpyc/test_parse_type_ref.py +506 -0
- tpyc/test_parse_version_info.py +58 -0
- tpyc/test_reach_analysis.py +72 -0
- tpyc/test_ref_type.py +216 -0
- tpyc/test_send_sync_substitution.py +276 -0
- tpyc/test_tuple_mutation_propagation.py +206 -0
- tpyc/test_type_def_registry.py +1729 -0
- tpyc/test_union_types.py +195 -0
- tpyc/type_def_registry.py +975 -0
- tpyc/typesys.py +5104 -0
tpyc/cycle_detection.py
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type dependency cycle detection.
|
|
3
|
+
|
|
4
|
+
Detects mutual recursion between records and type aliases by building
|
|
5
|
+
a directed type-reference graph and finding cycles via DFS. Validates
|
|
6
|
+
that every cycle is broken by at least one indirecting container
|
|
7
|
+
(Optional, Ptr, plus types whose TypeDef carries is_indirecting=True --
|
|
8
|
+
list, dict, set, plus user @native records that opt in).
|
|
9
|
+
|
|
10
|
+
User TPy records (e.g. tplib.Box, tplib.Rc) provide indirection
|
|
11
|
+
structurally: the walker expands a non-indirecting nominal's fields
|
|
12
|
+
after type-parameter substitution, so a `_ptr: Ptr[T]` field signals
|
|
13
|
+
indirection without the compiler hard-coding the record's name.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
from .typesys import substitute_type_params_structural, AliasRef, TypeParamRef
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from .typesys import NominalType, RecordInfo, TpyType, UnionType
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ---- Indirection helpers ------------------------------------------------
|
|
28
|
+
|
|
29
|
+
def _is_indirecting_type(typ: TpyType) -> bool:
|
|
30
|
+
"""True if the type provides pointer indirection that breaks a recursive
|
|
31
|
+
size cycle. Two sources:
|
|
32
|
+
- OptionalType / PtrType structural wrappers (isinstance dispatch).
|
|
33
|
+
- TypeDef.is_indirecting (declared via `@native(..., indirecting=True)`;
|
|
34
|
+
covers list/dict/set + user opt-ins).
|
|
35
|
+
"""
|
|
36
|
+
from .typesys import OptionalType, PtrType
|
|
37
|
+
from .type_def_registry import type_def_of
|
|
38
|
+
if isinstance(typ, (OptionalType, PtrType)):
|
|
39
|
+
return True
|
|
40
|
+
td = type_def_of(typ)
|
|
41
|
+
return td is not None and td.is_indirecting
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _collect_type_refs(
|
|
45
|
+
typ: TpyType,
|
|
46
|
+
target_names: frozenset[str],
|
|
47
|
+
expanded_aliases: dict[frozenset[TpyType], str] | None = None,
|
|
48
|
+
) -> list[tuple[str, bool]]:
|
|
49
|
+
"""Walk a type tree and collect references to any of `target_names`.
|
|
50
|
+
|
|
51
|
+
Also detects expanded union types that match a known alias (the parser
|
|
52
|
+
expands `Box[Expr]` to `Box[UnionType(Lit, BinOp)]`, so we match the
|
|
53
|
+
expanded UnionType back to the alias by comparing member name sets).
|
|
54
|
+
|
|
55
|
+
Returns list of (referenced_name, has_indirection) pairs.
|
|
56
|
+
"""
|
|
57
|
+
results: list[tuple[str, bool]] = []
|
|
58
|
+
_walk(typ, target_names, False, results, expanded_aliases, set())
|
|
59
|
+
return results
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _walk(
|
|
63
|
+
typ: TpyType,
|
|
64
|
+
target_names: frozenset[str],
|
|
65
|
+
inside_indirection: bool,
|
|
66
|
+
out: list[tuple[str, bool]],
|
|
67
|
+
expanded_aliases: dict[frozenset[TpyType], str] | None,
|
|
68
|
+
expanding: set[str],
|
|
69
|
+
) -> None:
|
|
70
|
+
from .typesys import NominalType, AliasRef, UnionType
|
|
71
|
+
from .type_def_registry import record_info_of
|
|
72
|
+
# Recursive-alias self-reference: parser-emitted AliasRef placeholder.
|
|
73
|
+
if isinstance(typ, AliasRef) and typ.name in target_names:
|
|
74
|
+
out.append((typ.name, inside_indirection))
|
|
75
|
+
return
|
|
76
|
+
if isinstance(typ, NominalType) and typ.name in target_names and not typ.is_protocol:
|
|
77
|
+
out.append((typ.name, inside_indirection))
|
|
78
|
+
return
|
|
79
|
+
# The parser expands `Box[Expr]` into `Box[UnionType(Lit, BinOp)]`, so a
|
|
80
|
+
# union encountered here may be an already-expanded alias body; match it
|
|
81
|
+
# back by its member set.
|
|
82
|
+
if expanded_aliases and isinstance(typ, UnionType):
|
|
83
|
+
alias_name = expanded_aliases.get(frozenset(typ.members))
|
|
84
|
+
if alias_name is not None:
|
|
85
|
+
out.append((alias_name, inside_indirection))
|
|
86
|
+
return
|
|
87
|
+
if _is_indirecting_type(typ):
|
|
88
|
+
for inner in typ.inner_types():
|
|
89
|
+
_walk(inner, target_names, True, out, expanded_aliases, expanding)
|
|
90
|
+
return
|
|
91
|
+
if isinstance(typ, NominalType) and not typ.is_protocol:
|
|
92
|
+
info = record_info_of(typ)
|
|
93
|
+
if info is not None and info.fields:
|
|
94
|
+
_walk_record_fields(typ, info, target_names, inside_indirection,
|
|
95
|
+
out, expanded_aliases, expanding)
|
|
96
|
+
return
|
|
97
|
+
# Fallback for parser placeholders without a RecordInfo, primitives, and
|
|
98
|
+
# any structural type not covered above.
|
|
99
|
+
for inner in typ.inner_types():
|
|
100
|
+
_walk(inner, target_names, inside_indirection, out,
|
|
101
|
+
expanded_aliases, expanding)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _walk_record_fields(
|
|
105
|
+
typ: 'NominalType',
|
|
106
|
+
info: 'RecordInfo',
|
|
107
|
+
target_names: frozenset[str],
|
|
108
|
+
inside_indirection: bool,
|
|
109
|
+
out: list[tuple[str, bool]],
|
|
110
|
+
expanded_aliases: dict[frozenset[TpyType], str] | None,
|
|
111
|
+
expanding: set[str],
|
|
112
|
+
) -> None:
|
|
113
|
+
"""Walk a non-indirecting record's fields under type-parameter substitution.
|
|
114
|
+
|
|
115
|
+
Lets `Box[Foo]` reveal indirection through its `_ptr: Ptr[T]` field
|
|
116
|
+
without hard-coding the record's name. Recursion guard keys on the
|
|
117
|
+
qualified name (falling back to bare name for unregistered placeholders),
|
|
118
|
+
so structurally self-referential records like `class Wrapper[T]: inner:
|
|
119
|
+
Wrapper[T]` terminate.
|
|
120
|
+
"""
|
|
121
|
+
guard_key = info.qualified_name() or info.name
|
|
122
|
+
if guard_key in expanding:
|
|
123
|
+
return
|
|
124
|
+
subst: dict[str, TpyType] = {}
|
|
125
|
+
if info.type_params and typ.type_args:
|
|
126
|
+
for param_name, arg in zip(info.type_params, typ.type_args):
|
|
127
|
+
# Array[T, N]'s int slot lands here as a raw int; skip it.
|
|
128
|
+
if hasattr(arg, "map_inner_types"):
|
|
129
|
+
subst[param_name] = arg
|
|
130
|
+
expanding.add(guard_key)
|
|
131
|
+
try:
|
|
132
|
+
for fld in info.fields:
|
|
133
|
+
field_type = (substitute_type_params_structural(fld.type, subst)
|
|
134
|
+
if subst else fld.type)
|
|
135
|
+
_walk(field_type, target_names, inside_indirection,
|
|
136
|
+
out, expanded_aliases, expanding)
|
|
137
|
+
finally:
|
|
138
|
+
expanding.discard(guard_key)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# ---- Graph + cycle detection -------------------------------------------
|
|
142
|
+
|
|
143
|
+
@dataclass
|
|
144
|
+
class _Edge:
|
|
145
|
+
"""A directed edge in the type dependency graph."""
|
|
146
|
+
source: str
|
|
147
|
+
target: str
|
|
148
|
+
has_indirection: bool
|
|
149
|
+
field_name: str | None = None
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _collect_self_refs(
|
|
153
|
+
typ: TpyType, alias_name: str, out: list,
|
|
154
|
+
) -> None:
|
|
155
|
+
"""Collect `AliasRef` self-reference nodes (to `alias_name`) in a type
|
|
156
|
+
tree, including those nested inside the args of an outer self-ref
|
|
157
|
+
(`Tree[Tree[T]]`), so the identity-recursion check sees every one."""
|
|
158
|
+
if isinstance(typ, AliasRef) and typ.name == alias_name:
|
|
159
|
+
out.append(typ)
|
|
160
|
+
for arg in typ.args:
|
|
161
|
+
_collect_self_refs(arg, alias_name, out)
|
|
162
|
+
return
|
|
163
|
+
for inner in typ.inner_types():
|
|
164
|
+
_collect_self_refs(inner, alias_name, out)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def validate_recursive_union_paths(
|
|
168
|
+
alias_name: str, members: tuple[TpyType, ...],
|
|
169
|
+
type_params: list[str] | None = None,
|
|
170
|
+
) -> str | None:
|
|
171
|
+
"""Validate that all self-references in a recursive union alias go
|
|
172
|
+
through an indirecting container, and -- for generic aliases -- that
|
|
173
|
+
every self-reference is identity recursion.
|
|
174
|
+
|
|
175
|
+
Returns an error message if a non-indirected self-reference exists,
|
|
176
|
+
or None when the alias is well-formed. Indirection sources are the
|
|
177
|
+
same as the wider cycle walker (`_is_indirecting_type` + the
|
|
178
|
+
structural field walk via `_walk` over non-indirecting nominals).
|
|
179
|
+
|
|
180
|
+
`type_params` is the alias's declared generic parameters (empty/None
|
|
181
|
+
for non-generic aliases). When non-empty, each self-reference
|
|
182
|
+
(`Tree[...]`) must reuse the declared parameters positionally as bare
|
|
183
|
+
`TypeParamRef`s -- v1 supports identity recursion only, so growing
|
|
184
|
+
(`Tree[list[T]]`), swapped (`Pair[V, K]`), and constant (`Bad[int]`)
|
|
185
|
+
recursive args are rejected.
|
|
186
|
+
|
|
187
|
+
Called from sema's `_validate_recursive_union_paths` after record /
|
|
188
|
+
protocol registration so the field walk can see same-module RecordInfo /
|
|
189
|
+
TypeDef entries for user indirecting records.
|
|
190
|
+
"""
|
|
191
|
+
target = frozenset([alias_name])
|
|
192
|
+
error_msg = (
|
|
193
|
+
f"direct recursion in type alias '{alias_name}' -- "
|
|
194
|
+
f"every recursive path must go through an indirecting "
|
|
195
|
+
f"container (list, dict, set, Optional, Ptr, or a "
|
|
196
|
+
f"record providing pointer indirection)"
|
|
197
|
+
)
|
|
198
|
+
for member in members:
|
|
199
|
+
results: list[tuple[str, bool]] = []
|
|
200
|
+
_walk(member, target, False, results, None, set())
|
|
201
|
+
for _ref_name, has_indirection in results:
|
|
202
|
+
if not has_indirection:
|
|
203
|
+
return error_msg
|
|
204
|
+
|
|
205
|
+
if type_params:
|
|
206
|
+
arity = len(type_params)
|
|
207
|
+
self_refs: list = []
|
|
208
|
+
for member in members:
|
|
209
|
+
_collect_self_refs(member, alias_name, self_refs)
|
|
210
|
+
for ref in self_refs:
|
|
211
|
+
# Arity normally caught earlier at the parse-resolution self-ref
|
|
212
|
+
# site; kept here as a backstop so the positional check below is
|
|
213
|
+
# index-safe.
|
|
214
|
+
if len(ref.args) != arity:
|
|
215
|
+
plural = "s" if arity != 1 else ""
|
|
216
|
+
return (
|
|
217
|
+
f"recursive position of alias '{alias_name}' takes "
|
|
218
|
+
f"{arity} type argument{plural}, got {len(ref.args)}"
|
|
219
|
+
)
|
|
220
|
+
for i, (arg, param) in enumerate(zip(ref.args, type_params)):
|
|
221
|
+
if not (isinstance(arg, TypeParamRef) and arg.name == param):
|
|
222
|
+
return (
|
|
223
|
+
f"recursive position of alias '{alias_name}' must "
|
|
224
|
+
f"reuse type parameter '{param}' at position {i}; "
|
|
225
|
+
f"got '{arg}'. v1 supports identity recursion only."
|
|
226
|
+
)
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@dataclass
|
|
231
|
+
class TypeCycle:
|
|
232
|
+
"""A cycle found in the type dependency graph."""
|
|
233
|
+
# Ordered list of type names in the cycle: path[0] -> path[1] -> ... -> path[0]
|
|
234
|
+
path: list[str]
|
|
235
|
+
# Edges parallel to path: edges[i] = path[i] -> path[(i+1) % len]
|
|
236
|
+
edges: list[_Edge]
|
|
237
|
+
# Union alias names participating in this cycle
|
|
238
|
+
alias_names: list[str] = field(default_factory=list)
|
|
239
|
+
|
|
240
|
+
def is_fully_unindirected(self) -> bool:
|
|
241
|
+
"""True if NO edge has indirection -- infinite size, can't compile."""
|
|
242
|
+
return all(not e.has_indirection for e in self.edges)
|
|
243
|
+
|
|
244
|
+
def has_any_indirection(self) -> bool:
|
|
245
|
+
"""True if at least one edge has indirection (cycle can be broken)."""
|
|
246
|
+
return any(e.has_indirection for e in self.edges)
|
|
247
|
+
|
|
248
|
+
def first_unindirected_edge(self) -> _Edge | None:
|
|
249
|
+
for e in self.edges:
|
|
250
|
+
if not e.has_indirection:
|
|
251
|
+
return e
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def detect_type_cycles(
|
|
256
|
+
record_fields: dict[str, list[tuple[str, TpyType]]],
|
|
257
|
+
union_aliases: dict[str, tuple[TpyType, ...]],
|
|
258
|
+
) -> list[TypeCycle]:
|
|
259
|
+
"""Detect cycles in the type dependency graph.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
record_fields: record_name -> [(field_name, field_type)]
|
|
263
|
+
union_aliases: alias_name -> member types (only non-recursive UnionType aliases)
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
List of TypeCycle objects describing each cycle found.
|
|
267
|
+
"""
|
|
268
|
+
all_names = frozenset(record_fields.keys()) | frozenset(union_aliases.keys())
|
|
269
|
+
if not all_names:
|
|
270
|
+
return []
|
|
271
|
+
|
|
272
|
+
# Build expanded_aliases map: frozenset of member types -> alias name.
|
|
273
|
+
# The parser expands `Box[Expr]` to `Box[UnionType(Lit, BinOp)]`, so we
|
|
274
|
+
# need to match expanded UnionType instances back to their alias.
|
|
275
|
+
expanded_aliases: dict[frozenset[TpyType], str] = {}
|
|
276
|
+
for alias_name, members in union_aliases.items():
|
|
277
|
+
expanded_aliases[frozenset(members)] = alias_name
|
|
278
|
+
|
|
279
|
+
# Build adjacency list
|
|
280
|
+
adj: dict[str, list[_Edge]] = {name: [] for name in all_names}
|
|
281
|
+
|
|
282
|
+
# Record edges: record -> types referenced in fields
|
|
283
|
+
for rec_name, fields in record_fields.items():
|
|
284
|
+
for field_name, field_type in fields:
|
|
285
|
+
refs = _collect_type_refs(field_type, all_names, expanded_aliases)
|
|
286
|
+
for ref_name, has_indirection in refs:
|
|
287
|
+
if ref_name != rec_name:
|
|
288
|
+
adj[rec_name].append(_Edge(
|
|
289
|
+
source=rec_name, target=ref_name,
|
|
290
|
+
has_indirection=has_indirection,
|
|
291
|
+
field_name=field_name,
|
|
292
|
+
))
|
|
293
|
+
|
|
294
|
+
# Alias edges: alias -> its union member types (by value in the variant)
|
|
295
|
+
for alias_name, members in union_aliases.items():
|
|
296
|
+
for member in members:
|
|
297
|
+
refs = _collect_type_refs(member, all_names)
|
|
298
|
+
for ref_name, _has_indirection in refs:
|
|
299
|
+
if ref_name != alias_name:
|
|
300
|
+
adj[alias_name].append(_Edge(
|
|
301
|
+
source=alias_name, target=ref_name,
|
|
302
|
+
has_indirection=False,
|
|
303
|
+
))
|
|
304
|
+
|
|
305
|
+
# DFS cycle detection with gray-node back-edge detection
|
|
306
|
+
class _Color(Enum):
|
|
307
|
+
WHITE = 0
|
|
308
|
+
GRAY = 1
|
|
309
|
+
BLACK = 2
|
|
310
|
+
WHITE, GRAY, BLACK = _Color.WHITE, _Color.GRAY, _Color.BLACK
|
|
311
|
+
color: dict[str, _Color] = {name: WHITE for name in all_names}
|
|
312
|
+
# For each node, the edge that brought us there in the DFS tree
|
|
313
|
+
parent_edge: dict[str, _Edge | None] = {name: None for name in all_names}
|
|
314
|
+
cycles: list[TypeCycle] = []
|
|
315
|
+
seen_cycles: set[frozenset[str]] = set()
|
|
316
|
+
alias_name_set = frozenset(union_aliases.keys())
|
|
317
|
+
|
|
318
|
+
def dfs(u: str) -> None:
|
|
319
|
+
color[u] = GRAY
|
|
320
|
+
for edge in adj[u]:
|
|
321
|
+
v = edge.target
|
|
322
|
+
if color[v] == GRAY:
|
|
323
|
+
# Back-edge: cycle is v -> ... -> u -> v
|
|
324
|
+
# Reconstruct by tracing parent_edge from u back to v
|
|
325
|
+
path: list[str] = []
|
|
326
|
+
edge_list: list[_Edge] = []
|
|
327
|
+
cur = u
|
|
328
|
+
while cur != v:
|
|
329
|
+
path.append(cur)
|
|
330
|
+
pe = parent_edge[cur]
|
|
331
|
+
assert pe is not None
|
|
332
|
+
edge_list.append(pe)
|
|
333
|
+
cur = pe.source
|
|
334
|
+
path.append(v)
|
|
335
|
+
path.reverse()
|
|
336
|
+
edge_list.reverse()
|
|
337
|
+
edge_list.append(edge) # closing edge: u -> v
|
|
338
|
+
# Deduplicate: multi-edge graphs (e.g. BinOp with two
|
|
339
|
+
# Box[Expr] fields) can produce the same structural cycle
|
|
340
|
+
key = frozenset(path)
|
|
341
|
+
if key in seen_cycles:
|
|
342
|
+
return
|
|
343
|
+
seen_cycles.add(key)
|
|
344
|
+
cycle = TypeCycle(
|
|
345
|
+
path=path, edges=edge_list,
|
|
346
|
+
alias_names=[n for n in path if n in alias_name_set],
|
|
347
|
+
)
|
|
348
|
+
cycles.append(cycle)
|
|
349
|
+
elif color[v] == WHITE:
|
|
350
|
+
parent_edge[v] = edge
|
|
351
|
+
dfs(v)
|
|
352
|
+
color[u] = BLACK
|
|
353
|
+
|
|
354
|
+
for name in sorted(all_names):
|
|
355
|
+
if color[name] == WHITE:
|
|
356
|
+
dfs(name)
|
|
357
|
+
|
|
358
|
+
return cycles
|
tpyc/diagnostics.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Compiler Diagnostics
|
|
3
|
+
|
|
4
|
+
Neutral diagnostics module used by both the parse/resolve and sema/analyze
|
|
5
|
+
phases. Sits upstream of both so neither layer needs to reach into the
|
|
6
|
+
other for error classes.
|
|
7
|
+
|
|
8
|
+
Only depends on `.typesys` (for `TpyType` in `Scope`) and `.parse` (for
|
|
9
|
+
`TpyExpr`, `SourceLocation` in `Diagnostic` / `SemanticError`). Both are
|
|
10
|
+
base modules; no reverse dependencies.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
from .typesys import TpyType
|
|
19
|
+
from .parse import TpyExpr, SourceLocation
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DiagnosticLevel(Enum):
|
|
23
|
+
"""Severity level of a compiler diagnostic."""
|
|
24
|
+
ERROR = "error"
|
|
25
|
+
WARNING = "warning"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
OPTIONAL_NONE_ACCESS_WARNING = (
|
|
29
|
+
"Potential None access on optional value; generated code adds runtime null check. "
|
|
30
|
+
"Use 'if x is not None' or 'assert x is not None' to prove safety and remove this warning."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
OPTIONAL_VALUE_TRUTHINESS_WARNING = (
|
|
34
|
+
"Truthiness check on optional value may also exclude falsy non-None values; "
|
|
35
|
+
"use 'is not None' for None-only checks."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Remediation hint appended to "copies X into field/container/owned storage,
|
|
39
|
+
# but X is non-copyable" errors. Listed in preference order: the idiomatic
|
|
40
|
+
# fix (Own for ownership transfer), then explicit copy() for the rare case
|
|
41
|
+
# a copy is genuinely wanted, then a reminder that last-use is already moved.
|
|
42
|
+
NOCOPY_REMEDIATION_HINT = (
|
|
43
|
+
" (use Own[...] to transfer ownership, copy() if a copy is truly intended, "
|
|
44
|
+
"or let auto-move apply at last use)"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def nocopy_container_elem_error(typ: object, kind: str) -> str:
|
|
49
|
+
"""Error message for `@nocopy` types used as set elements or dict keys.
|
|
50
|
+
|
|
51
|
+
`kind` is "set element" or "dict key". Hash-table-backed `ordered_set` /
|
|
52
|
+
`ordered_map` index entries via `std::pair<const K, ...>`, which requires
|
|
53
|
+
copy-constructible K -- @nocopy types can't satisfy that.
|
|
54
|
+
"""
|
|
55
|
+
return (
|
|
56
|
+
f"Type '{typ}' is non-copyable and cannot be used as a {kind}; "
|
|
57
|
+
f"{kind}s must be copy-constructible"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class Diagnostic:
|
|
63
|
+
"""A compiler diagnostic (error or warning)."""
|
|
64
|
+
level: DiagnosticLevel
|
|
65
|
+
message: str
|
|
66
|
+
loc: SourceLocation | None = None
|
|
67
|
+
|
|
68
|
+
def format(self, filename: str = "<unknown>") -> str:
|
|
69
|
+
"""Format diagnostic with file:line prefix."""
|
|
70
|
+
if self.loc:
|
|
71
|
+
return f"{filename}:{self.loc.line}: {self.level.value}: {self.message}"
|
|
72
|
+
return f"{filename}: {self.level.value}: {self.message}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SemanticError(Exception):
|
|
76
|
+
"""Error raised during resolve or sema phases."""
|
|
77
|
+
def __init__(self, message: str, loc: SourceLocation | None = None,
|
|
78
|
+
filename: str | None = None):
|
|
79
|
+
self.message = message
|
|
80
|
+
self.loc = loc
|
|
81
|
+
self.filename = filename
|
|
82
|
+
super().__init__(message)
|
|
83
|
+
|
|
84
|
+
def format(self, filename: str = "<unknown>") -> str:
|
|
85
|
+
"""Format error with file:line prefix."""
|
|
86
|
+
name = self.filename or filename
|
|
87
|
+
if self.loc:
|
|
88
|
+
return f"{name}:{self.loc.line}: error: {self.message}"
|
|
89
|
+
return f"{name}: error: {self.message}"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class Scope:
|
|
94
|
+
"""A scope containing variable bindings."""
|
|
95
|
+
parent: Optional[Scope] = None
|
|
96
|
+
bindings: dict[str, TpyType] = field(default_factory=dict)
|
|
97
|
+
depth: int = field(init=False)
|
|
98
|
+
|
|
99
|
+
def __post_init__(self) -> None:
|
|
100
|
+
self.depth = (self.parent.depth + 1) if self.parent else 0
|
|
101
|
+
|
|
102
|
+
def lookup(self, name: str) -> Optional[TpyType]:
|
|
103
|
+
if name in self.bindings:
|
|
104
|
+
return self.bindings[name]
|
|
105
|
+
if self.parent:
|
|
106
|
+
return self.parent.lookup(name)
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
def define(self, name: str, typ: TpyType) -> None:
|
|
110
|
+
self.bindings[name] = typ
|
|
111
|
+
|
|
112
|
+
def set_existing(self, name: str, typ: TpyType) -> bool:
|
|
113
|
+
"""Update an existing binding at the level where it was defined.
|
|
114
|
+
|
|
115
|
+
Walks up the parent chain and rewrites the binding in-place at the
|
|
116
|
+
owning scope. Returns True on update, False if the name was not bound.
|
|
117
|
+
"""
|
|
118
|
+
scope: Optional[Scope] = self
|
|
119
|
+
while scope is not None:
|
|
120
|
+
if name in scope.bindings:
|
|
121
|
+
scope.bindings[name] = typ
|
|
122
|
+
return True
|
|
123
|
+
scope = scope.parent
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def all(self) -> dict[str, TpyType]:
|
|
127
|
+
"""Return all bindings in this scope (not including parent)."""
|
|
128
|
+
return dict(self.bindings)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class TypedExpr:
|
|
132
|
+
"""Expression annotated with its type."""
|
|
133
|
+
def __init__(self, expr: TpyExpr, typ: TpyType):
|
|
134
|
+
self.expr = expr
|
|
135
|
+
self.type = typ
|