Files
ViperC/App/lib
TermiNexus dc4e06d88b fix(TPV): 本文件自己声明的 extern 裸名优先于依赖 vpi 注入的同名声明
现场:Test/WebTest 编译 includes/socket.vp:236 报
  CastError: 指针隐式转指针已禁止:源 %"56d0ee99ecf0a0b5.SocketAddr"* →
  目标 %"99c88d4cbd933ac6.WSASocketAddr"*
  源码: result = connect(self.fd, c.Addr(addr), 16)

机制(**链接期无冲突**——两边都不是 export,@connect 是同一个 C 符号,最终只有
ws2_32 里一个定义;问题在"编译 socket.vp 时的同一个模块内"):
1. extern/state/export 声明的符号**不带 SHA1 前缀**(FuncGenDef.vp:172-173
   `mangled_name = fd.name`)⇒ socket.vp 与 w32.winsock2 都产出裸名 @connect
   (前者形参 SocketAddr|t.CPtr,后者 WSASocketAddr|t.CPtr)。
2. Translator 的 prologue 先注入依赖 w32.winsock2 的 vpi
   (StubMergerBuild.LoadDepVpiIntoModule → VpiReader.ParseVpiIntoModule →
   _inject_function_declare:create_declare + module_add_function),当前模块里
   先出现了 winsock2 版的 @connect。
3. 随后 forward_declare_functions 处理 socket.vp 自己的 `extern def connect` 时,
   find_func_in_module 命中已存在 ⇒ `continue`(FuncGenDef.vp:178-182)
   ⇒ **本文件自己的声明被静默丢弃**,调用点改按 winsock2 的形参 coerce
   (报错里的目标类型 WSASocketAddr* 正是 winsock2 版的指纹)。
   (同文件 send/recv/socket/listen 亦被顶掉,只是形参是 i8*/u64,不报错——
   即 socket.vp 的 POSIX 分支本来就在调用 winsock2 的声明。)

改动(注入期跳过"本文件已声明的裸名",让本文件自己的声明优先):
- StructGenMixin:新增 FileFuncNames 表 + register_file_funcs(pool, tree) /
  is_file_func(name),与既有的 FileClassNames / register_file_classes /
  is_file_class 同规矩(键与表同池、每文件随 reset_visible_structs 重建)。
- GenApi:新增 register_file_funcs / is_file_func 委托包装。
- Translator._translate_module_level:在 register_file_classes 之后调用
  register_file_funcs(三种模式共用、早于依赖 vpi 注入)。
- VpiReader._inject_function_declare:算出 mangled name 后,若 `use_bare_name != 0`
  且 `is_file_func(fd.name) != 0` 直接返回(不注入)。判据只用**裸名**:带 SHA1
  前缀的依赖函数名与本文件同名声明不会互相顶替,避免误跳过跨模块调用。

待验证:重编译 TransPyV(自举两遍)→ WebTest / JsonTest / FileIoTest。
2026-10-01 14:46:47 +08:00
..