feat(gen): 同名全局 + 注解冲突优先报重复定义

- translate_annassign: 函数内(无 global/nonlocal、非模块级)再次注解同名变量时,若注解类型与模块级变量类型内容不一致 ⇒ TypeError 重复定义 fail-fast,不再延后到 RHS 的 coerce_to_type 报无关的「指针隐式转整数」(PointerTest/App/main.vp:46 _g_ptr: int = None,全局已是 t.CUInt32T | t.CPtr)

- 注解与全局一致时仍按 Python 语义遮蔽为独立局部变量(既有行为不变)

- 该检查走 _stg_ty_equal 内容比较(TypePrint),非地址比较,避免 Int32()/Ptr() 新实例造成误判
This commit is contained in:
TermiNexus committed 2026-09-27 08:50:18 +08:00
1 parent f0309e4904
commit 78fc7313fb
1 file changed
+30
+30
View File
@@ -2127,6 +2127,36 @@ novirtual class AssignGenMixin:
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
"SyntaxError")
# 重复定义检测(优先于一切下游转换,fail-fast):
# 模块级已有同名变量,而当前作用域既无 global/nonlocal 声明(有则被下方
# global/nonlocal 分支接管)、又不在模块级(模块级由 handle_module_level_var
# 登记,本就不构成"重复"),此处却用**与全局不一致的注解**再次声明同名变量
# ⇒ 报重复定义。若无此检查,会先建局部 alloca 再由 RHS 走 coerce_to_type,
# 把根因暴露成无关的 CastError(如 PointerTest/App/main.vp:46
# `_g_ptr: int = None`:全局已是 t.CUInt32T | t.CPtr,报"指针隐式转整数")。
# 注解与全局**一致**时不报错:保持 Python 语义,遮蔽为独立局部变量
# (如全局 `_g_val: t.CInt` 与局部 `_g_val: int` 解析后同为 i32)。
if nm.id is not None and trans is not None and var_ty is not None \
and GenApi.is_global_name(trans, nm.id) == 0 \
and GenApi.is_nonlocal_name(trans, nm.id) == 0 \
and self.Gen.VarGen.is_module_scope(trans.SymTab) == 0:
dup_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id)
if dup_alloca is not None and dup_alloca.Ty is not None:
dup_g_ty: llvmlite.LLVMType* = dup_alloca.Ty.Pointee
if dup_g_ty is not None and self._stg_ty_equal(pool, dup_g_ty, var_ty) == 0:
# 类型内容不等(_stg_ty_equal 走 TypePrint 内容比较,非地址比较:
# llvmlite 的 Int32()/Ptr() 每次构造都是新实例)。
dup_g_buf: str = pool.alloc(256)
dup_l_buf: str = pool.alloc(256)
if dup_g_buf is not None and dup_l_buf is not None:
llvmlite.TypePrint(dup_g_buf, 256, dup_g_ty, pool)
llvmlite.TypePrint(dup_l_buf, 256, var_ty, pool)
self.Gen.TypeGenErr.fatal_error(aa,
f"重复定义:'{nm.id}' 已是模块级变量(类型 {dup_g_buf}),"
f"此处又注解为 {dup_l_buf}。函数内同名注解必须与全局一致;"
f"如需独立局部变量请换名,如需修改全局请在函数内加 global 声明",
"TypeError")
# t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型)
callable_ret: llvmlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, annot, trans._imported_modules, trans._from_imports, trans)
if callable_ret is not None: