Commit Graph
746 Commits
Author SHA1 Message Date
TermiNexus 4bf04c2452 feat(vpc): binary .vpb stub companion and str->char* migration in call gen
- add VpiStub: fixed-layout blob written next to every .vpi (dual write at all
  writers, Ensure() backfills a missing or stale companion on cache reuse)
- serve arity/signature queries for top-level functions from the blob, with a
  silent fallback to the text scanner (methods, varargs, duplicates, corrupt file)
- prefer the injected declare over the text arity in the cross-module check
- CDefine/type text indexes and in-place SSA renumbering and bulk appends
- WIP: char* conversion in CallGenBase and CallGenLeafKit
2026-10-31 16:25:18 +08:00
TermiNexus 91e188c539 feat(vpc): vprofile instrumentation (--spend-file/--vpf) + verbatim --build-self forwarding
--spend-file <path> instruments every compiled function with
vpf_enter(id, name) / vpf_leave(id); main additionally calls
vpf_install(path, level). includes/vprofile.vp keeps the tables (no
allocation on the hot path), times with QPC and writes the report from
atexit, so normal return and exit() both produce it.

  --vpf 0 off | 1 call counts | 2 +per-function time (default) |
  3 +caller/callee edges

*A report path is resolved against the output exe directory, so
  ../prof.txt and absolute paths behave as documented regardless of the
  process cwd.
*Instrumented include objects use their own cache suffix
  (.binary.vpf<N>, stacked with the asan/traceback suffixes) and that
  cache is cleared once when profiling is enabled.
*StubMergerBuild force-adds the vprofile runtime to the reachable set;
  FuncGenBase emits a declare on demand because the instrumented module
  usually does not import vprofile.
*--repl is rejected: the fragment DLL is loaded at runtime and does not
  link the runtime.

--build-self no longer keeps a whitelist: SelfBuild.CollectForwardedArgs
drops only --build-self / --project / --build-dir and forwards every
other argument verbatim, so a self-build can enable the same modes as a
normal build.
2026-10-30 22:24:01 +08:00
TermiNexus eda8e4465f refactor(codegen): one body pipeline for module functions and class methods
Module-level functions and class methods each carried their own copy of "resolve the
return type", "create the parameter allocas" and "emit the implicit epilogue". The copies
drifted: an unannotated method was still typed i32 by the class-method body path while its
declaration said void, so the epilogue emitted `llvm.return 0 : i32` inside a void function
and the MLIR verifier rejected it ("'llvm.return' op expected no operands", Scheduler._yield).

- FuncGenBase.resolve_func_ret_ty: the single return-type policy (annotation -> storage
  marker -> __init__/__new__ hooks -> unannotated = procedure void -> fail-fast). Used by
  the forward-declare pass, the body pass, class methods and generic specializations
- FuncGenBase.param_llvm_ty: the single parameter mapping (CVoid skipped, bare class ->
  Ptr(struct), ArrayT -> element pointer), used by every signature and alloca site
- FuncGenBase.emit_func_epilogue: the single implicit-return implementation (procedure ->
  ret void, unreachable merge, fail-fast for an annotated fall-through), shared by module
  functions, methods and nested functions
- FuncGenBase.translate_func_body: the shared body pipeline (scope entry, self/parameter
  storage, *args va_list, try/except out-params, pre-scan, capture preparation, slife,
  statements, epilogue, state restore). ClassGenVTable._translate_method now only handles
  method naming, vtable/overload registration and add_param
- the same policy reaches cross-module and generic declares: unannotated vpi functions and
  methods declare void, generic specialization declares use the shared resolver, and the
  list.append call sites emit a void call
- method parameters now carry the const / volatile / pointee-volatile / pure markers that
  the module-level path always had
- FuncGenMixin: the two dry-run helpers that return ints are annotated, as the language
  now requires (an unannotated def is a procedure)

Verified: 41 Test projects pass (MethodProcTest, CrossModuleSigTest, RawPtrParamTest,
AstTest, ListTest, OopInheritTest, ...), ViperC self-hosts with the new compiler, and the
6 tests that still fail reproduce identically with the previous compiler.
2026-10-29 19:37:55 +08:00
TermiNexus 3b3cd42d1c fix(codegen): a procedure never emits a value return
Unannotated functions were typed by scanning the body, which inferred i32, so falling off
the end emitted `llvm.return 0 : i32` inside a function declared void. The MLIR verifier
rejects that ("expected no operands"), which is what broke Scheduler._yield.

- an unannotated `def` is void in both the forward declare and the body, so the implicit
  epilogue emits `ret void`
- translate_return treats a procedure (no annotation, `-> None`, or a void-typed function) as
  void: the expression is evaluated for its side effects and `ret void` is emitted. Bare
  `return`, `return f()` where f is void, and `return <None value>` are legal and never carry
  a value
- body_has_value_return accepts `return f()` and `return <None define>` in a procedure
- `define X = None` is a named None: registered as the string sentinel None, materialized as
  a None value at use sites, and exported through the vpi
2026-10-29 18:13:06 +08:00
TermiNexus ffe31cc6e3 fix(call): pass the class segment when resolving a cross-module method return type
The cross-module return-type resolution derived only {sha} and the last segment from {sha}.Class.method, then queried the vpi cache and the dependency text.ll with no class name. Both key methods by class, so a class-level function without a return annotation (Scheduler._yield) missed both lookups and hit the fail-fast 'Cannot obtain the cross-module function return type precisely' path. Derive the middle segment and pass it as the class when it names a registered class; module functions ({sha}.submod.func) keep the bare-name lookup.
2026-10-29 17:48:59 +08:00
TermiNexus f5c5e068ae fix(vpi): keep the bare ExportT declare when another module has the same name
Injecting a dependency's module function deduped through a suffix match, so {other_sha}.init already in the module suppressed the bare @init declare of this module's export. Calls to tty.init(...) then suffix-matched the other module's init (1 parameter) and failed the arity check; the call-site module check also accepted a mangled symbol from another module whenever this module exported any function with that name.

- dedup a bare ExportT/State symbol by exact name only (VpiReader._inject_module_declare)

- accept a foreign-module binding only for bare symbols (the export/state form) or a re-export owner (CallGenMixin)
2026-10-29 17:33:31 +08:00
TermiNexus 8effc94827 fix(call): bind mod.func() to the module function, not a same-named static method
A suffix lookup for func() also matches {sha}.Class.func symbols. The no-self exception added for sched.Scheduler._yield() was too broad: it kept such a method hit for a module-qualified call like proc.current(), returning Process* where ProcessManager.current() -> int is meant (proc.current() is a module-level function). Keep the namespaced-function exception only when the receiver path itself names the class (mod.Class.func()); bare and module-qualified calls reject method-shaped suffix hits and resolve the module symbol through the vpi.
2026-10-29 17:10:17 +08:00
TermiNexus 1f067aa58f fix(call): accept void methods and rawptr arguments at the call boundary
Two follow-ups to the cross-module signature check:

- A method without a return annotation is void, like a module-level `def`. The vpi
  return-annotation cache recorded it as a hardcoded i32, so callers invented an i32 return
  for a void method. It now records `void` for non-extern declarations (methods included).
- A class-level function declared without `self` (`Class.func()`) is a namespaced plain
  function, not a method bound to a receiver. The module-qualified call path rejected such
  symbols as method bindings, which then fell through to the external-C whitelist and failed
  on a void return (`Scheduler._yield`).
- A pointer argument passed to an integer-typed parameter is converted at the call boundary
  instead of failing the implicit pointer-to-integer rule. A `rawptr` value whose callee
  parameter degraded to uint64 (stale/mis-typed stub) now reaches the callee with its address
  instead of aborting with a CastError.
2026-10-29 16:43:35 +08:00
TermiNexus 4c34e396a4 fix(call): align cross-module calls with the callee symbol's signature
mlirlite.build_call composes the llvm.call function type from the argument values and the
caller-supplied return type; it never consults the callee. Declares are synthesized the same
way (_ensure_method_declare appends missing params from the caller's own argument values and
never compares return types), so nothing verified that a call site agreed with the definition.
Two modules could therefore emit incompatible calls for the same symbol, which only the MLIR
verifier rejected later:

    llvm.func @MapHHDM(i64, i64, i64)                 (definition, void)
    llvm.call @MapHHDM(i64, i64, i32) -> i32          (caller)

- after the declare/definition exists, conform every fixed argument to its parameter type and
  emit the call with the symbol's return type (_conform_call_args / _call_symbol_ret_ty)
- fail fast when a cross-module call site resolves a return type the symbol disagrees with,
  instead of emitting both and letting mlir-opt report an operand type mismatch
- record a module-level `def` without a return annotation as `void` in the vpi return-annotation
  cache (previously a hardcoded i32, so callers invented an i32 return for void exports);
  extern/state C declarations and methods keep the legacy default
2026-10-29 15:53:43 +08:00
TermiNexus a5284f9ce5 fix(codegen): keep float DefineT initializers floating
`define GW_F = double(GW)` was registered as an integer constant: the DefineT
registration only took the float path when the initializer contained a float
literal, and the cast was unwrapped before the value was read. A float cast
produces a float even without a literal, so the define became an i16 640 and

    define GW_F = double(GW)
    define GH_F = double(GH)
    aspect: double = GW_F / GH_F

folded with integer division to 1 instead of 16/9, which broke Gargantua's
projection (and any aspect/scale ratio derived the same way).

- decide the constant kind from the original initializer (a cast to a float
  type, a float literal, or a reference to a float define) and evaluate it as
  a double, keeping the f32/f64 choice from the annotation or `float(...)`
- resolve DefineT names inside float expressions, so `double(GW)` and
  `double(A) / double(B)` evaluate at compile time
- .vpi generation writes such defines as float literals (`= 640.0`) instead of
  running the integer evaluator, which also fixes a SIGFPE when that evaluator
  hit `0 / 0` for a float expression; integer division/modulo now guard a zero
  right operand instead of trapping the compiler
2026-10-29 02:28:55 +08:00
TermiNexus d5d05ec11e fix(codegen): widen from the value expression, not the enclosing statement
should_zext_widen decides the widening direction from the narrow side's AST
node, but the return and assignment coercions passed the statement node.
A statement has no type of its own, so the literal rule and the annotated
variable rule were skipped and the value fell through to sext:
`def f() -> uint64: return 0xDEADBEEF` produced 0xFFFFFFFFDEADBEEF and the
caller compared against 0xDEADBEEF and failed.

Unwrap Return/Assign/AnnAssign/AugAssign/Expr to their value expression
before the direction rules run, so a non-negative literal wider than
INT32_MAX zero-extends (0xDEADBEEF -> 0xDEADBEEF) and a negative one keeps
its sign (-1 -> 0xFFFFFFFFFFFFFFFF).
2026-10-28 23:15:07 +08:00
TermiNexus 19f9c53a5f fix(codegen): zero-extend unsigned 16-bit widening in every coercion path
A uint16 value that is widened to int/uint32/uint64 must be zero-extended
(movzwl), and an int16 value must be sign-extended (movswl). coerce_to_type
picks the direction from the source AST node's declared signedness, which
requires the translator; several call sites omitted it and therefore fell
back to sext, so a big-endian uint16 such as 0xDCBC became 0xFFFF...DCBC
(numGlyphs 56508 read as -9028 and every glyph range collapsed to zero).

- pass trans at the assignment, annotated-assignment, augmented-assignment,
  global-array initializer, index, element-store, constructor-argument,
  conditional-expression and return coercion sites
- printf argument promotion now receives the argument expression and trans,
  so uint16/uint8 promote with zext like any other widening
- print selects the format token and extension from the source signedness
  (%u/%llu + zext for unsigned, %d/%lld + sext for signed) instead of a
  hardcoded %d + sext for 8/16-bit values
2026-10-28 23:06:17 +08:00
TermiNexus 79d53e691c fix(codegen): keep module-level DefineT initializers 2026-10-28 21:45:38 +08:00
TermiNexus 9d298b5ae9 feat(types): 宽度事实表共享给编译器与 LSP
新增 lib/types/IntFacts.vp:显式宽度范围检查、最小可存宽度、最小二幂宽度统一到一张表。ExprGenConst 与 define_min_width 改用它;LSP hover 的位宽推荐/后缀适配判定也改用它,任意 _iN/_uN 后缀可显示,但推荐宽度仍只给二幂值。gate10 增加 128_u8、1_u100、128_u7 与数字分隔符 hover 断言;计划文档记录 Pylance 式诊断等级等决策。
2026-10-28 14:42:25 +08:00
TermiNexus 8e86eea159 fix(codegen): keep unary constant folding within the operand width 2026-10-27 21:33:48 +08:00
TermiNexus e63fc34057 fix(codegen): reject out-of-range field defaults at declaration 2026-10-27 21:23:01 +08:00
TermiNexus 002a98f3f4 fix(codegen): widen method calls by the declared return signedness 2026-10-27 19:56:56 +08:00
TermiNexus 7cbe4e93dc fix(codegen): widen calls by the declared return signedness 2026-10-27 19:51:46 +08:00
TermiNexus 425d3f2120 fix(codegen): widen int() casts by the source signedness 2026-10-27 19:35:56 +08:00
TermiNexus 8215476020 fix(codegen): widen unsigned integers with zext in assignments 2026-10-27 19:27:32 +08:00
TermiNexus 6a15adbad0 feat(codegen): inline arbitrary LLVM IR and raw MLIR blocks 2026-10-27 14:13:38 +08:00
TermiNexus 645e193729 feat(gen): []T 值类型按初始化器推断定长数组
声明位置(全局/局部/字段)的 []T 依据初始化器推断为 [N x T]:字符串按 strlen+1、列表按元素个数;函数参数仍保持 T* ABI。全局与字段的 .vpi 类型写入推断长度,跨模块声明与定义布局一致;字段默认值支持字符串/列表数组的逐字节/逐元素初始化。V_VPC_VERSION 改为定长数组,使 .PRVERSN 内联真实版本号。
2026-10-27 13:59:28 +08:00
TermiNexus 8367b5f65b fix(defines): resolve chained define references in vpi stubs 2026-10-27 12:49:00 +08:00
TermiNexus edd9b1c151 fix(defines): resolve package-level from-import symbols to the package module 2026-10-26 18:11:51 +08:00
TermiNexus a2e9b1848e fix(defines): isolate same-name cross-module DefineT lookups 2026-10-26 17:40:06 +08:00
TermiNexus 3f54946af9 fix(pure): format pure_str in print, printf and f-strings 2026-10-26 13:52:09 +08:00
TermiNexus d88cafa12c feat(pure): integrate pure_str with lifetime and NLL 2026-10-26 13:52:00 +08:00
TermiNexus 782b4d63ff feat(build): 增加 --build-self 与 copyself
- 新增 copyself:延迟后删除目标并复制文件/目录
- ViperC 新增 --build-self:自举到 __vpcbuild_2__ 后由 copyself 替换 __vpcbuild__
- 同步当前 ViperC 工作区已有的 Gen/Diag/Stub 改动
- .gitignore 忽略 __vpcbuild_* 与 _sha1_map.txt
2026-10-26 02:09:45 +08:00
TermiNexus da636a5422 fix(cif): 平台宏按目标 triple 求值,属性形式不再依赖跨模块 define
- _cif_attr_value 先查平台内建宏(triple 是唯一真相源),再查本地/跨模块 DefineT:
  跨模块查不到时会静默得到 0,曾把 platmacro.IS_WINDOWS 判成 0,
  导致 Windows 构建误走非 Windows 分支(_io 选了 posix.fileio)
- _get_platform_macro_value 补齐 platmacro 的平台名:IS_WINDOWS/IS_WIN64/IS_LINUX/
  IS_MACOS/IS_X86_64/IS_ARM64

注:本文件含此前未提交的既有改动,按整文件一并提交。
2026-10-25 13:05:51 +08:00
TermiNexus 3febb87abf refactor(app): 改为直接 import io,用 io.File / io.MODE
不再用 'import io as fileio' 别名:20 个文件统一 'import io',
所有 fileio.X 调用点改为 io.X(win32.fileio 等模块路径出现在注释里的保持原样)。
2026-10-25 12:51:28 +08:00
TermiNexus 94515ddf12 refactor(app): win32.fileio 全部切换到跨平台 io
20 个文件把 'import win32.fileio as fileio' 改为 'import io as fileio',
文件 IO 统一走 includes/io.vp(编译期 cif 选择 win32.fileio / posix.fileio)。
依赖编译器新增的模块级 cif 条件 import(a282918)。

注:这些文件中存在此前未提交的既有改动,按整文件一并提交。
2026-10-25 12:45:49 +08:00
TermiNexus a2829182b8 feat(imports): 支持模块级 cif 条件 import
- ImportsGenMixin 新增 translate_cif_imports / _collect_cif_imports_in:
  用 cif 求值只收集选中分支的 Import/ImportFrom,celif 的 orelse 递归求值,
  celse 按普通语句收集;普通模块级 if 原样忽略
- Translator._translate_module_level 的 import 预扫描新增 If 分支(mode 0)
- TranslatorGenMixin.translate_children 在 declare/import-scan 模式补收集(mode != 0),
  避免与预扫描重复写入 from_imports
- GenApi 增加 translate_cif_imports 转发

未选中分支的模块不进入依赖闭包,因此不会被编译/链接,
可用于在平台专有模块之间二选一(如 win32.fileio / posix.fileio)。
2026-10-25 12:28:29 +08:00
TermiNexus a20bc312ab docs(classgen): 声明前置注释示例 FileW -> File
FileW 已在 includes/win32/fileio.vp 中删除,示例改用 File.__init__(同样在 self.seek 之前定义)。
2026-10-25 12:07:59 +08:00
TermiNexus 9c3ebc8a2c fix(ffilib): 为 runtime CDLL thunk 创建 entry block 并移除失败静默返回
- new_builder 的 CurBlock 初值为 None,_emit 会静默丢弃指令,导致 thunk 生成空函数体(mlir-opt: empty block)
- 补 create_block + position_at_end,随后再把全部静默 return None 改为 fatal_error
- 移除两处 [ffiprobe] 调试探针
2026-10-24 23:57:09 +08:00
TermiNexus 2caf6f0795 fix(ffilib): runtime=True 时把 _ffilib 登记为导入模块,进入可达性扫描
Pass 0 的 _AddPending 只影响 viperbuild 的闭包 BFS,不影响 Phase1/Phase2 的 includes 可达性扫描(后者由 tr._imported_modules 驱动),所以 _ffilib 仍然没被收录、拿不到 SHA1。改为在 translate_import 里判断:若存在 runtime=True 的句柄(ViperBuild.HasRuntimeFfiHandle),则随 import ffilib 一并 NotePlainImport("_ffilib")。
2026-10-24 23:20:14 +08:00
TermiNexus 2411ceff8c fix(ffilib): 把 _ffilib 拉进依赖闭包(Pass 0 pending + import 白名单)
thunk 生成时报 module _ffilib 未在 includes 扫描中:includes 是按需可达性扫描,没有任何文件 import _ffilib 就不会收录它。Pass 0 的 import 处理里对 ffilib 追加 pending(_ffilib);_check_import_sha1 也放行 _ffilib(防止显式 import 时报无 SHA1)。若可达性仍不生效,改用方案 B:thunk 直接调 LoadLibraryA/GetProcAddress(裸名、无需模块 SHA1),去掉对 _ffilib 的依赖。
2026-10-24 23:15:31 +08:00
TermiNexus ecd4a0b14a fix(ffilib): thunk 复用已有 declare,而不是遇到同名就跳过
探针显示 ffi_lib=add_c2 / rt=1 都已正确,说明断点在去重守卫:@add 在 declaration 阶段/vpi 注入已存在为 declare,find_func_in_module 命中后跳过了 thunk,最终留下普通 declare 导致 undefined symbol。改为按状态区分:已存在 declare -> IsDeclared 置 0 并复用(形参类型与名称沿用它的,否则函数体引用不到入参);已是指令体 define 才跳过;不存在则新建 define。
2026-10-24 23:03:14 +08:00
TermiNexus 1508563f1c chore(ffilib): 临时探针(CDLL 抽取 + extern 分支的 ffi_lib/runtime)
现象与"exe 已含最新提交"矛盾:add_c2 仍生成全局、@add 无 thunk、无 _ffilib 引用。加两处 printf 定位断点:_HandleCDLL 入口打印句柄名;translate_function_def 的 extern 分支打印 fd.ffi_lib 与 FfiHandleRuntime 结果。定位后立即移除。
2026-10-24 22:51:31 +08:00
TermiNexus c765cfa9d4 fix(ffilib): 模块级 ffilib.CDLL(...) 赋值不再生成全局变量
现场 main.vp 的 text.ll 里出现 @"<sha1>.add_c2"() : i32 全局,说明纯编译期配置的 CDLL 声明被当成普通模块级变量翻译了。ViperBuild 增加 IsCdlLDeclCall(复用 _IsCDLLCall,认别名与全名);TranslatorGenMixin 的模块级 Assign 分支先判它,命中则整条跳过 Pass 0 已抽取的声明。
2026-10-24 22:34:54 +08:00
TermiNexus 522075097e fix(ffilib): translate_function_def 的 extern 分支也生成 runtime thunk
现场 temp/02/029af3a930989beb.text.ll 里 @add 是普通直接调用、没有 _ffilib 引用,说明 App 文件的 extern 走的是 translate_function_def 而不是 forward_declare_functions,thunk 校验挂错了地方。两处都挂:各自先查 find_func_in_module 去重;runtime=True 生成 thunk,runtime=False 保持原 declare 路径。
2026-10-24 22:33:14 +08:00
TermiNexus 0acbefafd8 feat(ffilib): runtime CDLL 生成 thunk(绝对路径 LoadLibraryA + 间接调用)
_emit_runtime_ffi_thunk 生成 define <name>(%p0..): Load(path) -> Sym(h,name) -> bitcast 成 <ret>(<params>)* -> call_indirect -> ret;符号名与普通 extern 一致(裸名),调用点零改动。路径与符号名用 ExprGenConst.create_global_string 落成常量操作数(GEP 由该助手处理)。约束:仅标量参数/返回值,结构体按值与变参 fail-fast;declare-only 阶段仍走普通 declare,避免同模块 define/declare 同名并存。
2026-10-24 22:20:55 +08:00
TermiNexus 74a9d96d3c feat(ffilib): extern <lib> name(...) 校验库句柄并按 runtime 决定行为
Pass 0 新增 CDLL 句柄表(变量名 -> runtime):_HandleCDLL 接收赋值目标名,_RegisterFfiHandle 登记,FfiHandleRuntime 提供查询(1=运行时/0=链接期/-1=未登记)。FuncGenDef 在前置声明阶段校验 ffi_lib:未绑定 ffilib.CDLL 报 NameError;runtime=True 报 NotImplementedError(需要 _ffilib 运行时符号绑定,绝不静默退化为静态链接);runtime=False 照常生成裸名 declare。
2026-10-24 21:12:55 +08:00
TermiNexus 1885370920 feat(ffilib): import 白名单登记 ffilib 宏模块
_check_import_sha1 对宏库有一份硬编码白名单(ctraits / viperbuild),宏库不产生代码也就没有模块 SHA1。ffilib 走同一条路,加入白名单后 import ffilib 不再报 has no registered SHA1;配置仍由 Pass 0 抽取。
2026-10-24 20:00:31 +08:00
TermiNexus af445058b4 fix(overload): _translate_method 补传 ClassDef,修复 undefined name cd
方法重载需要在类体内统计同名 def 才能决定是否追加 _v{hash},但 _translate_method 之前没有 ClassDef 参数。改为从 _translate_oop_methods 把 cd 传下去(两处调用点:sig_only 预扫描与正式翻译),未传时 _method_slot_name 退回原方法名,保持非重载路径行为不变。
2026-10-24 19:34:22 +08:00
TermiNexus 850bad4e8a feat(overload): 跨模块调用 Mod.f(...) 接入重载决议
模块限定调用分支先按接收者路径解析目标模块 SHA1(含 from-import 别名),再以 prefix 模式在同名候选集里决议;vpi 注入的重载符号 {sha1}.f_v{hash} 与函数表项名 f_v{hash} 均能命中。单候选/非重载保持原 find_func_in_module 路径。至此模块级、实例方法、Class.m、静态方法、跨模块五条调用路径全部接入同一套 C++ 部分序决议。
2026-10-24 18:00:18 +08:00
TermiNexus f54c365b20 feat(overload): vpi 写入端把签名后缀写进 def 名,签名 hash 与上下文无关
_overload_sig_text 算 hash 时固定传 imported_modules/from_imports/trans = None,只靠全局结构体表解析,使定义端、vpi 写入端(translator 尚未创建)、读取端天然算出同一个 hash,无需跨阶段搬运 import 上下文;解析不到即 fail-fast。Converter 新增 _PyiOverloadSuffix:同一作用域同名 def >=2 时追加 _v{hash}(方法跳过 self,@staticmethod 不跳;extern/state/export/main 不加)。读取端 _inject_function_declare 用 fd.name 拼符号,自动与定义端一致,返回/形参注解缓存也按后缀分组不再互相覆盖。
2026-10-24 17:29:51 +08:00
TermiNexus 20e31b8dbd refactor(overload): 抽出不依赖 translator 的签名后缀计算(vpi 两端复用)
_overload_sig_text 拆成 _overload_sig_text_ctx(显式传 imported_modules/from_imports/trans)与薄包装;新增 _overload_sig_suffix_ctx 只返回 _v{16位签名hash}。GenApi.overload_sig_suffix 提供无 translator 的入口,供 vpi 写入端(写 def 名)与读取端(核对注入名)共用同一 hash,避免三处各算一套导致跨模块符号对不上。行为不变(尚无调用方)。注:本提交含此前未提交的既有改动。
2026-10-24 17:18:23 +08:00
TermiNexus 246d70f2fb feat(overload): 静态方法与类方法的 Class.m(...) 调用接入重载决议
_translate_property_call 在候选 >=2 时用同一套决议:prefix 模式匹配 Class.m / Class.m_v{hash},静态方法 param_base=0(无 self/cls),类方法 param_base=1;新增 arg_start 参数让 cargs 跳过前 start_idx 个预置接收者(obj/cls)。call_name 仍由决议出的 Function 名生成,保证调用目标符号与定义一致。
2026-10-24 17:14:15 +08:00
TermiNexus faea680116 feat(overload): 类方法与虚函数重载(符号/函数表键/vtable 槽名一致)
类内同名方法 >=2 时,方法短名追加 _v{参数签名hash}(跳过 self,static 不跳):LLVM 符号 {sha1}.Class.m_v{hash}、函数表键 Class.m_v{hash}、vtable 槽名 m_v{hash} 三者一致。vtable 收集改为先用 _method_slot_name 建槽名表:继承槽的覆盖判定按槽名比较(只有签名相同的同名方法才算覆盖),本类槽按槽名去重(重载各占一槽);__init__/__before_init__/__new__ 仍按原始名排除。实例方法调用与 Class.m(obj,...) 两条路径在候选 >=2 时用同一套决议(prefix 模式 + param_base=1),并把 method_name 换成带后缀的短名,使虚调用取到正确槽位。注:本提交含此前未提交的既有改动。
2026-10-24 17:02:33 +08:00
TermiNexus c89a0d747c feat(overload): 实参类型推导支持字段访问、函数调用结果与二元运算
字段访问按接收者类名找 FieldEntry.Spec(字段 Spec 已带注解符号性);裸名调用取被调者 Spec.Ret(被调者本身同名重载时视为未知,避免递归决议);二元运算按常规算术转换取结果类型(浮点优先、位宽取宽、同宽无符号优先,字符串拼接按左值),比较运算恒 bool。至此 ORFunc(s.f) / ORFunc(f()) / ORFunc(x + 1) 均可参与决议。
2026-10-24 16:42:26 +08:00