fix(gen): App 短模块名键保留 + find_struct sha1 字面量精确匹配,修复同名类归属错乱

ViperOS 目录含两份同内容 gfx.vp:App 的 Apps/Scene3D/gfx.vp(9aab) 与
VKernel 的 VKernel/.../vesafb/gfx.vp(0ae),都定义 class Scene3D。includes
扫描("../.."=ViperOS)先以全路径模块名注册 9aab,AppendToSha1MapStore 按
sha1 去重吞掉 App 短模块名 "gfx" 键 → LookupSha1ByModName("gfx") 失败 →
后缀匹配劫持到 VKernel gfx(0ae) → Scene3D 类归属 0ae → 返回类型解析查
temp/0a/0ae*.text.ll(不存在)→ Phase A _deps_pending 永不收敛。

- AppendToSha1MapStore:去重改为 sha1 与模块名都相同才跳过,App 短模块名
  键("gfx")保留,import gfx 精确查找可命中
- find_struct:限定名模块段为 16 位 hex(sha1 字面量,如 "9aab.Scene3D")
  时直接按 name+sha1 精确匹配(find_struct_by_module),不再落到裸名回退
- find_struct 第二遍裸名回退加同名唯一性检查:跨模块同名类(VKernel 与
  App 的 Scene3D)存在时返回 None 而非先注册的错误 entry
This commit is contained in:
TermiNexus committed 2026-08-26 17:19:23 +08:00
1 parent 00606057c4
commit c656cba393
2 files changed
+100 -6

No files matched your search

+68 -5
View File
@@ -163,11 +163,6 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
StubMerger._sha1_store_count = 0
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
return 1
# 去重:若 SHA1 已存在则跳过
for i in range(StubMerger._sha1_store_count):
sidx_d: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
return 0
# 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger"
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
if full_path_buf is None:
@@ -177,6 +172,18 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
stdlib.free(full_path_buf)
if mod_name is None:
return 1
# 去重:SHA1 与模块名都相同才跳过。同一 SHA1 可能被 includes 扫描先以
# 全路径模块名注册(如 App 源文件在 includes 目录下 → "Apps.Scene3D.gfx"),
# App 追加的短模块名("gfx")必须保留——否则 import gfx 的精确查找
# LookupSha1ByModName("gfx") 失败 → 后缀匹配劫持到 VKernel 同名 gfx
# (VKernel/Kernel/drivers/video/vesafb/gfx.vp,类 Scene3D 归属错乱根因)。
for i in range(StubMerger._sha1_store_count):
sidx_d: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
midx_d: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0:
stdlib.free(mod_name)
return 0
# 写入 SHA1
idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
@@ -327,6 +334,62 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
ci += 1
return None
# ============================================================
# LookupModNameByAlias - 从 from_imports 别名映射解析模块真名
#
# import X as Y 时 ImportsGenMixin.add_from_import 写入 "Y:X"(Y=别名,
# X=模块真名)。本函数返回别名 Y 对应的模块真名 X(供限定名解析
# "Y.Class" → 按 X 模块归属匹配,如 "types.fileinfo" → "fat32_types")。
#
# Returns:
# 模块名字符串(stdlib 分配,调用方负责 free),None 未找到
# ============================================================
def LookupModNameByAlias(from_imports: str, alias: str) -> str:
"""从 from_imports 别名映射解析模块真名(import X as Y → Y:X)"""
if from_imports is None or alias is None:
return None
alias_len: t.CSizeT = string.strlen(alias)
if alias_len == 0:
return None
total_len: t.CSizeT = string.strlen(from_imports)
ci: t.CSizeT = 0
while ci < total_len:
# 跳过前导空格
while ci < total_len and from_imports[ci] == ' ':
ci += 1
if ci >= total_len:
break
# 条目起点 ci,找 ':'(local_name 结束)
colon: t.CSizeT = ci
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
colon += 1
local_len: t.CSizeT = colon - ci
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
# 比较 local_name == alias
match: int = 1
li: t.CSizeT = 0
while li < alias_len:
if from_imports[ci + li] != alias[li]:
match = 0
break
li += 1
if match == 1:
# 提取 module(colon+1 到下一个 ':' 或空格)
m_start: t.CSizeT = colon + 1
m_end: t.CSizeT = m_start
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ':
m_end += 1
if m_end > m_start:
mbuf: str = stdlib.malloc(m_end - m_start + 1)
if mbuf is not None:
string.strncpy(mbuf, from_imports + m_start, m_end - m_start)
mbuf[m_end - m_start] = '\0'
return mbuf
return None
# 跳到下一条目
while ci < total_len and from_imports[ci] != ' ':
ci += 1
return None
# ============================================================
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
#
# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules
+32 -1
View File
@@ -512,6 +512,27 @@ class StructGenMixin:
string.strncpy(mod_buf_f, name, mod_len_f)
mod_buf_f[mod_len_f] = '\0'
if string.strcmp(mod_buf_f, "t") != 0 and string.strcmp(mod_buf_f, "c") != 0:
# 模块段是 16 位 hex = SHA1 字面量(如 "{9aab}.Scene3D",
# TypeGenResolve L1397-1402 的 sha1 前缀形态):跳过 store
# 模块名查询(store 键是模块名不是 sha1),直接按 name+sha1
# 精确匹配。否则 _resolve_module_sha1("9aab") 返回 None →
# 落到第二遍裸名回退 → 跨模块同名类(VKernel gfx 与 App gfx
# 都定义 Scene3D)返回先注册的错误 entry(Scene3D 归属错乱
# → ret_sha1=0ae → Phase A _deps_pending 死锁根因)。
mod_hex_ok: int = 1
if string.strlen(mod_buf_f) == 16:
for hi_f in range(16):
ch_h: t.CChar = mod_buf_f[hi_f]
if not ((ch_h >= 48 and ch_h <= 57) or (ch_h >= 97 and ch_h <= 102)):
mod_hex_ok = 0
break
else:
mod_hex_ok = 0
if mod_hex_ok != 0:
me_h: GenTypes.StructEntry | t.CPtr = \
self.find_struct_by_module(bare_f, mod_buf_f)
stdlib.free(mod_buf_f)
return me_h
mod_sha1_f: str = self._resolve_module_sha1(mod_buf_f)
if mod_sha1_f is not None:
me_f: GenTypes.StructEntry | t.CPtr = \
@@ -539,11 +560,21 @@ class StructGenMixin:
if dot_pos is not None:
class_name: str = dot_pos + 1
if class_name is not None and class_name[0] != '\0':
# 同名唯一性检查(对齐上方限定名路径 L543-554):跨模块同名类
# (如 VKernel gfx 与 App gfx 都定义 Scene3D)存在时不得返回
# 先注册的错误 entry——否则模块段无法解析的限定名(如
# "9aab.Scene3D")被劫持到错误模块 → 返回类型解析查错 text.ll
# → Phase A _deps_pending 死锁(Scene3D ret_sha1=0ae 根因)。
same_cnt_b: int = 0
same_entry_b: GenTypes.StructEntry | t.CPtr = None
for i in range(self.StructCount):
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
return entry
same_cnt_b += 1
same_entry_b = entry
if same_cnt_b == 1:
return same_entry_b
return None
def find_struct_by_module(self, name: str, sha1: str) -> GenTypes.StructEntry | t.CPtr: