chore: 清理超长历史注释,并一并提交并行会话的代码改动
注释清理(65 文件 / 约 -2578 行 / 约 516 处):删除/压缩叙述式历史注释——多行根因叙事、工作代号段(D25/D30/N11/B5/S4/阶段E 等)、改前改后与先例叙述、逐条推导块,压成一行讲清作用信息;契约类注释(用途、参数与返回、关键约束与不变量、IR 结构说明)与被注释掉的代码一律保留 存疑 标记 6 处一字未动:StubMergerStore.vp、VpiReader.vp、VLogger.vp、AssignGenMixin.vp、CallGenLib.vp、CallGenLeafKit.vp 本次一并带入并行会话的代码改动(同批文件,按文件粒度无法拆分):fileio.File -> rowptr[fileio.File] 等 已知副作用/残留:① CallGenDispatch.vp 有 2 行非注释行的行尾被 LF->CRLF 规范化(纯字节变化,无文本改动);② core/Gen 区约 24 处压缩因并行会话整文件覆写被写回原样,尚未生效(StmtGenCifMixin/ClassGenVTable/FuncGenDef/ClassGenEnum/StructGenMixin/TypeSpec 等) 清单与复跑判据见 Debugger/comment_cleanup_summary.md(该目录不受版本控制)
This commit is contained in:
1 parent
b28f20cce7
commit
7cba4cbc95
65 files changed
+1233
-3292
No files matched your search
+143
-215
@@ -199,16 +199,9 @@ class AssignGenMixin:
|
||||
val_fp: int64 = self.extract_cdefine_int_value(val_node)
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, val_fp)
|
||||
|
||||
# ============================================================
|
||||
# 源文件重读恢复 CDefine 浮点值
|
||||
#
|
||||
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
|
||||
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
|
||||
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
|
||||
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
|
||||
#
|
||||
# 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。
|
||||
# ============================================================
|
||||
# 源文件重读恢复 CDefine 浮点值:读 "NAME: t.CDefine = value" 行 atof 解析
|
||||
# (AST 节点 float_val/str_val 可能被 pool 分配覆写,源文件文本最可靠)。
|
||||
# 是否命中记在实例字段 self.RecoverFound。
|
||||
|
||||
def _recover_found(self) -> int:
|
||||
"""检查最近一次 _recover_cdefine_float 是否成功"""
|
||||
@@ -227,7 +220,7 @@ class AssignGenMixin:
|
||||
fp: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if fp is None or name is None or out is None:
|
||||
return 0
|
||||
f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R)
|
||||
f: rowptr[fileio.File] = fileio.File(fp, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return 0
|
||||
BUF_SZ: sizet = 1048576
|
||||
@@ -297,12 +290,9 @@ class AssignGenMixin:
|
||||
eq += 1
|
||||
while eq < line_start + line_len and buf[eq] == ' ':
|
||||
eq += 1
|
||||
# Call 包装的浮点常量(如 PI: t.CDefine = float(3.14159...) /
|
||||
# t.CDouble(1.0)):值的 token 是整段 "float(3.14159...)"。
|
||||
# atof 只认数字/符号/'.',首字符 'f' → 恒得 0.0,导致浮点 CDefine
|
||||
# 被注册为 0(gfx.vp PI 编成 0.0 的直接根因)。此处跳过 "float("
|
||||
# 之类前缀,从括号内首个数字/符号/'.' 起取值。
|
||||
# 裸字面量(3.14 / -1.5,首字符已是数字/符号/'.')不受影响。
|
||||
# Call 包装的浮点常量(t.CDouble(1.0) / float(3.14...)):跳过 "float(" 等
|
||||
# 前缀,从括号内首个数字/符号/'.' 起取值(否则 atof 只认数字恒得 0.0)。
|
||||
# 裸字面量(3.14 / -1.5)首字符已是数字/符号/'.',不受影响。
|
||||
if eq < line_start + line_len:
|
||||
c0_rf: char = buf[eq]
|
||||
if not ((c0_rf >= '0' and c0_rf <= '9') or c0_rf == '-' or c0_rf == '+' or c0_rf == '.'):
|
||||
@@ -522,12 +512,9 @@ class AssignGenMixin:
|
||||
"""
|
||||
if ty_name is None:
|
||||
return 0
|
||||
# [FIX 2026-08-31] 前缀归一化:剥离 "t."/"c." 内建命名空间前缀,使
|
||||
# "int" 与裸名 "CInt" 判定一致。泛型实参经 _norm_type_arg_name 规则 3
|
||||
# 保留 "t." 前缀(list[int] 的 T → "int"),不剥离则 _is_scalar_ty_name
|
||||
# 匹配不到白名单裸名 "CInt" → 误判为非标量 → _is_ptr_element_annotation 返回
|
||||
# 1(8 字节指针槽)→ _list.vp elem_ptr[0]=item 的 GEP 元素类型退化为指针 →
|
||||
# 整数存指针误报 CastError(ast/base.vp L391 list[int] 根因)。
|
||||
# 前缀归一化:剥离 "t."/"c." 内建命名空间前缀,使 "int" 与裸名 "CInt" 判定
|
||||
# 一致(泛型实参经 _norm_type_arg_name 规则 3 会保留 "t.")。不剥离则
|
||||
# 误判为非标量 → 8 字节指针槽 → GEP 元素类型退化为指针(整数存指针报 CastError)。
|
||||
if ty_name[0] == 't' and ty_name[1] == '.':
|
||||
ty_name += 2
|
||||
elif ty_name[0] == 'c' and ty_name[1] == '.':
|
||||
@@ -700,11 +687,9 @@ class AssignGenMixin:
|
||||
builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||||
if elem_ptr is None:
|
||||
continue
|
||||
# 内层嵌套数组:元素类型是数组且元素节点是列表字面量 → 递归数组
|
||||
# 初始化(逐元素 GEP + store)。list 字面量赋给 t.CArray 属数组
|
||||
# 语义,不应特化 list 泛型(gfx.vp faces: t.CArray[t.CArray[int,3],12]
|
||||
# 根因)——否则 _list 未注册时 "list literal generic specialization
|
||||
# failed";只有显式 list[T] 注解才引入 _list。
|
||||
# 内层嵌套数组:元素类型是数组且元素节点是列表字面量 → 递归数组初始化
|
||||
# (逐元素 GEP + store)。list 字面量赋给 t.CArray 属数组语义,不特化
|
||||
# list 泛型(否则 _list 未注册时报特化失败);只有显式 list[T] 注解才引入 _list。
|
||||
inner_arr: int = 0
|
||||
if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0:
|
||||
if elem_node is not None and elem_node.kind() == ast.ASTKind.List:
|
||||
@@ -779,9 +764,7 @@ class AssignGenMixin:
|
||||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||||
lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node, trans)
|
||||
|
||||
# 无符号操作数(如 u_num_l: uint64 的 //= / %=)→ udiv/urem。
|
||||
# 此前一律 sdiv/srem(translate_binop 的 Div/Mod 已修,但 AugAssign 走本
|
||||
# 函数独立发射 → viperlib %lu/%lx 的 //= 仍为 sdiv,T3 未覆盖根因)。
|
||||
# 无符号操作数(如 u_num_l: uint64 的 //= / %=)→ udiv/urem,有符号走 sdiv/srem。
|
||||
aug_unsigned: int = 0
|
||||
if lhs_node is not None:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, lhs_node, trans) != 0:
|
||||
@@ -1088,15 +1071,10 @@ class AssignGenMixin:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组
|
||||
#
|
||||
# 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时,
|
||||
# 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation):
|
||||
# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期
|
||||
# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须
|
||||
# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。
|
||||
# ============================================================
|
||||
# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → [len x elem_ty]
|
||||
# 单参 t.CArray[elem_ty] 本解析为 Ptr(elem_ty),RHS 为列表字面量时按 TPC
|
||||
# ParseListAnnotation 语义推断为静态数组(否则误走动态 list 构造 → 链接期 undefined)。
|
||||
# PreScan 与 Handle 都必须调用:两处 alloca 类型须一致,否则复用旧 alloca 使推断失效。
|
||||
def _infer_static_array_ty_from_literal(self, pool: rowptr[memhub.MemBuddy],
|
||||
annot: ast.AST | t.CPtr,
|
||||
value: ast.AST | t.CPtr,
|
||||
@@ -1239,8 +1217,8 @@ class AssignGenMixin:
|
||||
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
|
||||
# PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的
|
||||
# get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。
|
||||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
# [D31 fail-fast] 泛型注解退化成裸基类 → 立即终止(暴露退化点)
|
||||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
# [D31 fail-fast] 泛型注解退化成裸基类 → 立即终止(暴露退化点)
|
||||
self._fail_on_degenerated_generic_annotation(aa, nm.id, annot, var_ty)
|
||||
else:
|
||||
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
|
||||
@@ -1261,11 +1239,9 @@ class AssignGenMixin:
|
||||
if alloca is not None:
|
||||
if self.Gen.VarGen.define_var(
|
||||
trans.SymTab, nm.id, alloca) == 0:
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
# 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化
|
||||
# struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册
|
||||
# → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest
|
||||
# __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3)
|
||||
# 存储原始类型注解的类名(方法调用检测时 Ptr(i8) 回退按类名查结构体)。
|
||||
# 传 pool:泛型 Subscript 返回 mangled 特化名;pool=None 只得裸模板名,
|
||||
# 模板未注册时属性访问会报"类未注册"。
|
||||
if annot is not None:
|
||||
cls_nm_ps: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(
|
||||
annot, trans._imported_modules, pool, trans._from_imports)
|
||||
@@ -1280,27 +1256,13 @@ class AssignGenMixin:
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _prespecialize_generic_annotation - 注解为泛型 Subscript(含 | t.CPtr 联合)
|
||||
# 时先注册特化,保证随后的 resolve_annotation_type 得到「带类型实参」的特化
|
||||
# 结构体(如 {sha1}.list[ast.ASTptr]),而不是退化为不透明基类(裸 list*)。
|
||||
#
|
||||
# 背景(崩溃根因,IR 实证):`body_list: list[ast.AST | t.CPtr] | t.CPtr =
|
||||
# mc.children` 若在 resolve 时该特化尚未注册,注解会退化成裸 list* →
|
||||
# 之后 body_list.get(i) 被分派到默认 list[int].get(返回 i32)→
|
||||
# inttoptr i32→AST* 截断指针 → 读垃圾 AST 节点,
|
||||
# StmtGenMixin._translate_stmt_impl 崩溃。gen1 IR 实证(MatchGenMixin 模块):
|
||||
# %"body_list.1" = alloca %"….list"* ← 裸 list(丢类型实参)
|
||||
# %cast_arg_0.9 = bitcast %"….list"* … to %"….list[int]"*
|
||||
# %call = call i32 @…list[int].get(…) ; 返回 i32
|
||||
# %int2ptr_stmt = inttoptr i32 %call to %"….AST"* ← 截断
|
||||
# PreScan 路径(pre_scan_allocas)此前已有此补救,但 Handle 路径
|
||||
# (translate_annassign)缺失 ⇒ 在任何「未复用预扫描 alloca」的场景
|
||||
# (如循环体内换作用域重新声明同名变量)又会建出裸 list* alloca。
|
||||
# 故抽成公共 helper,两条路径共用,保证两处解析结果一致。
|
||||
#
|
||||
# _prespecialize_generic_annotation - 注解为泛型 Subscript(含 | t.CPtr 联合)时
|
||||
# 先注册特化,使随后的 resolve_annotation_type 得到带类型实参的特化结构体,
|
||||
# 而非退化为不透明基类(裸 list* 会让 .get() 误分派到 list[int].get 截断指针)。
|
||||
# PreScan(pre_scan_allocas)与 Handle(translate_annassign)两条路径共用本 helper,
|
||||
# 保证两处解析结果一致(未复用预扫描 alloca 的路径也必须先特化)。
|
||||
# _specialize_generic_class 幂等,重复调用安全。
|
||||
# 返回 1=执行过特化尝试;0=注解形态不适用(非泛型 Subscript)。
|
||||
# ============================================================
|
||||
def _prespecialize_generic_annotation(self, trans: HT.Translator | t.CPtr,
|
||||
pool: rowptr[memhub.MemBuddy],
|
||||
annot: ast.AST | t.CPtr) -> int:
|
||||
@@ -1343,66 +1305,66 @@ class AssignGenMixin:
|
||||
#
|
||||
# 返回新增的变量数
|
||||
# ============================================================
|
||||
def _fail_on_degenerated_generic_annotation(self,
|
||||
aa: ast.AnnAssign | t.CPtr,
|
||||
var_name: str,
|
||||
annot: ast.AST | t.CPtr,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""fail-fast:泛型注解解析成了「裸泛型基类指针」(丢失类型实参)
|
||||
|
||||
场景:注解是泛型下标 `list[X]` 或 `list[X] | t.CPtr`,但
|
||||
`resolve_annotation_type` 退化成裸基类 `list*`(没有 `[...]`)
|
||||
⇒ 之后该变量的任何泛型方法调用(`.get()`/`.set()`/...)都会按**错误**
|
||||
元素类型特化(实测 `list[int].get` 返回 i32)⇒ `inttoptr` 把 i32 当
|
||||
指针 ⇒ 读垃圾 AST 节点(D21/D25/D31 崩溃族,ASan 现场
|
||||
`MatchGenMixin._handle_simple_match → StmtGenMixin._translate_stmt_impl`)。
|
||||
|
||||
与 D25 既有守卫的区别:那条守卫判「复用到的**旧 alloca** 是裸泛型基类」;
|
||||
本守卫判「**本次注解解析结果本身**就是裸泛型基类」,覆盖「旧 alloca 恰好
|
||||
也是裸类型 → 两边一致 → 既有守卫不触发」的漏网路径。
|
||||
|
||||
返回 0=未退化(继续);退化则 fatal_error 终止(不返回)。
|
||||
"""
|
||||
if aa is None or annot is None or var_ty is None:
|
||||
return 0
|
||||
# 取注解里的泛型 Subscript 一侧:Subscript 本身,或 A | t.CPtr 的 Subscript 分支
|
||||
ann_sub: ast.Subscript | t.CPtr = None
|
||||
if annot.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(annot)
|
||||
elif annot.kind() == ast.ASTKind.BinOp:
|
||||
bop_ff: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if bop_ff.op == ast.OpKind.BitOr:
|
||||
if bop_ff.left is not None and bop_ff.left.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.left)
|
||||
elif bop_ff.right is not None and bop_ff.right.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.right)
|
||||
if ann_sub is None or ann_sub.value is None \
|
||||
or ann_sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
base_nm_ff: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_sub.value)
|
||||
if base_nm_ff.id is None:
|
||||
return 0
|
||||
# 仅当该基名确实是泛型模板(list/GSList/...)才判定为退化
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm_ff.id) is None:
|
||||
return 0
|
||||
if var_ty.Pointee is None:
|
||||
return 0
|
||||
vt_nm_ff: str = llvmlite.get_struct_name(var_ty.Pointee)
|
||||
if vt_nm_ff is None:
|
||||
return 0
|
||||
vt_pf_ff: int = GenApi.sha1_prefix_len(vt_nm_ff)
|
||||
vt_short_ff: str = vt_nm_ff + vt_pf_ff if vt_pf_ff != 0 else vt_nm_ff
|
||||
if string.strchr(vt_short_ff, '[') is not None:
|
||||
return 0 # 带类型实参:未退化
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
aa,
|
||||
f"变量 '{var_name}' 的泛型注解 '{base_nm_ff.id}[...]' 解析成了裸基类 "
|
||||
f"'{vt_nm_ff}*'(丢失类型实参);后续 .get()/.set() 会按错误元素类型"
|
||||
f"特化(如 list[int].get 返回 i32)→ inttoptr 截断指针崩溃。"
|
||||
f"禁止静默继续——请检查该注解在 resolve_annotation_type 中的退化点。",
|
||||
"TypeError")
|
||||
return 0
|
||||
|
||||
def _fail_on_degenerated_generic_annotation(self,
|
||||
aa: ast.AnnAssign | t.CPtr,
|
||||
var_name: str,
|
||||
annot: ast.AST | t.CPtr,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""fail-fast:泛型注解解析成了「裸泛型基类指针」(丢失类型实参)
|
||||
|
||||
场景:注解是泛型下标 `list[X]` 或 `list[X] | t.CPtr`,但
|
||||
`resolve_annotation_type` 退化成裸基类 `list*`(没有 `[...]`)
|
||||
⇒ 之后该变量的任何泛型方法调用(`.get()`/`.set()`/...)都会按**错误**
|
||||
元素类型特化(实测 `list[int].get` 返回 i32)⇒ `inttoptr` 把 i32 当
|
||||
指针 ⇒ 读垃圾 AST 节点(D21/D25/D31 崩溃族,ASan 现场
|
||||
`MatchGenMixin._handle_simple_match → StmtGenMixin._translate_stmt_impl`)。
|
||||
|
||||
与 D25 既有守卫的区别:那条守卫判「复用到的**旧 alloca** 是裸泛型基类」;
|
||||
本守卫判「**本次注解解析结果本身**就是裸泛型基类」,覆盖「旧 alloca 恰好
|
||||
也是裸类型 → 两边一致 → 既有守卫不触发」的漏网路径。
|
||||
|
||||
返回 0=未退化(继续);退化则 fatal_error 终止(不返回)。
|
||||
"""
|
||||
if aa is None or annot is None or var_ty is None:
|
||||
return 0
|
||||
# 取注解里的泛型 Subscript 一侧:Subscript 本身,或 A | t.CPtr 的 Subscript 分支
|
||||
ann_sub: ast.Subscript | t.CPtr = None
|
||||
if annot.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(annot)
|
||||
elif annot.kind() == ast.ASTKind.BinOp:
|
||||
bop_ff: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if bop_ff.op == ast.OpKind.BitOr:
|
||||
if bop_ff.left is not None and bop_ff.left.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.left)
|
||||
elif bop_ff.right is not None and bop_ff.right.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.right)
|
||||
if ann_sub is None or ann_sub.value is None \
|
||||
or ann_sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
base_nm_ff: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_sub.value)
|
||||
if base_nm_ff.id is None:
|
||||
return 0
|
||||
# 仅当该基名确实是泛型模板(list/GSList/...)才判定为退化
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm_ff.id) is None:
|
||||
return 0
|
||||
if var_ty.Pointee is None:
|
||||
return 0
|
||||
vt_nm_ff: str = llvmlite.get_struct_name(var_ty.Pointee)
|
||||
if vt_nm_ff is None:
|
||||
return 0
|
||||
vt_pf_ff: int = GenApi.sha1_prefix_len(vt_nm_ff)
|
||||
vt_short_ff: str = vt_nm_ff + vt_pf_ff if vt_pf_ff != 0 else vt_nm_ff
|
||||
if string.strchr(vt_short_ff, '[') is not None:
|
||||
return 0 # 带类型实参:未退化
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
aa,
|
||||
f"变量 '{var_name}' 的泛型注解 '{base_nm_ff.id}[...]' 解析成了裸基类 "
|
||||
f"'{vt_nm_ff}*'(丢失类型实参);后续 .get()/.set() 会按错误元素类型"
|
||||
f"特化(如 list[int].get 返回 i32)→ inttoptr 截断指针崩溃。"
|
||||
f"禁止静默继续——请检查该注解在 resolve_annotation_type 中的退化点。",
|
||||
"TypeError")
|
||||
return 0
|
||||
|
||||
def translate_annassign(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
|
||||
@@ -1447,11 +1409,9 @@ class AssignGenMixin:
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
annot: ast.AST | t.CPtr = aa.annotation
|
||||
if annot is not None:
|
||||
# 与 PreScan 同源:先注册泛型特化,避免 list[X](含 | t.CPtr 联合)
|
||||
# 在 resolve 时退化为裸 list* → 之后 .get() 误分派到默认
|
||||
# list[int](返回 i32)→ inttoptr 截断指针 → 读垃圾 AST 节点崩溃。
|
||||
# 此处是崩溃根因路径:循环体内重新声明同名变量时不会复用预扫描
|
||||
# alloca,必须在本路径同样先特化(详见 _prespecialize_generic_annotation)。
|
||||
# 与 PreScan 同源:先注册泛型特化,避免 list[X] 退化为裸 list* 后 .get()
|
||||
# 误分派(返回 i32 → inttoptr 截断)。此处为循环体内重声明同名变量、
|
||||
# 不复用预扫描 alloca 的路径(详见 _prespecialize_generic_annotation)。
|
||||
self._prespecialize_generic_annotation(trans, pool, annot)
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
@@ -1669,7 +1629,7 @@ class AssignGenMixin:
|
||||
# [D31 fail-fast] 泛型注解退化成裸基类 → 立即终止(暴露退化点)
|
||||
self._fail_on_degenerated_generic_annotation(aa, nm.id, annot, var_ty)
|
||||
|
||||
# 普通局部变量
|
||||
# 普通局部变量
|
||||
# 创建 alloca
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym(
|
||||
trans.SymTab, pool, builder, nm.id, var_ty)
|
||||
@@ -1679,42 +1639,37 @@ class AssignGenMixin:
|
||||
aa,
|
||||
f"无法为变量 {nm.id} 创建存储",
|
||||
"TypeError")
|
||||
# [D25 根治] 复用到的 alloca 类型必须与本次注解解析类型一致。
|
||||
# get_or_create_sym 只用「名字 + 作用域」复用(ty 不参与判定,见 VarGenMixin),
|
||||
# 因此可能命中一个**类型不同**的旧 alloca(同名重声明 / 不同路径建出的退化
|
||||
# alloca,如裸 list* 对上 list[ast.ASTptr]*)→ alloca 类型与使用点注解类型
|
||||
# 分裂 → 方法调用按错误的元素类型特化(list[int].get 返回 i32)→ inttoptr
|
||||
# 截断指针 → 读垃圾 AST 节点(D21/D25 崩溃族)。
|
||||
# 只比较「双方都是指针且 pointee 都是结构体」这一最典型的退化形态:
|
||||
# 结构体名不同即 fail-fast,直接暴露退化点与变量名(不兜底)。
|
||||
if alloca is not None and alloca.Ty is not None and var_ty is not None:
|
||||
av_pt_d: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if av_pt_d is not None and self.Gen.ExprGenBase.is_ptr_type(av_pt_d) != 0 \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(var_ty) != 0:
|
||||
av_in: llvmlite.LLVMType | t.CPtr = av_pt_d.Pointee
|
||||
vt_in: llvmlite.LLVMType | t.CPtr = var_ty.Pointee
|
||||
if av_in is not None and vt_in is not None:
|
||||
av_nm_d: str = llvmlite.get_struct_name(av_in)
|
||||
vt_nm_d: str = llvmlite.get_struct_name(vt_in)
|
||||
if av_nm_d is not None and vt_nm_d is not None \
|
||||
and string.strcmp(av_nm_d, vt_nm_d) != 0:
|
||||
# 只在「旧 alloca 的 pointee 是**裸泛型模板基类**(丢类型实参,
|
||||
# 如裸 list / 裸 GSList)而注解是另一个类型」时 fail-fast ——
|
||||
# 这正是 D25 的退化形态(后续方法调用按错误元素类型特化 → 截断)。
|
||||
# 普通的不同具体类(如 Tuple* vs AST*)是**同名重声明换类型**的
|
||||
# 合法用法(两者都是 8 字节指针槽,运行期无误),不在此拦截。
|
||||
av_pf: int = GenApi.sha1_prefix_len(av_nm_d)
|
||||
av_short: str = av_nm_d + av_pf if av_pf != 0 else av_nm_d
|
||||
if string.strchr(av_short, '[') is None:
|
||||
av_tpl: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(av_short)
|
||||
if av_tpl is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
aa,
|
||||
f"变量 '{nm.id}' 复用到的存储类型为裸泛型基类 '{av_nm_d}*'"
|
||||
f"(丢了类型实参),与注解解析类型 '{vt_nm_d}*' 不一致;"
|
||||
f"禁止静默混用——方法调用会按错误元素类型特化并截断指针",
|
||||
"TypeError")
|
||||
|
||||
# 复用到的 alloca 类型必须与本次注解解析类型一致:get_or_create_sym 只用
|
||||
# 「名字 + 作用域」复用(ty 不参与判定,见 VarGenMixin),可能命中类型不同的
|
||||
# 旧 alloca(同名重声明 / 退化 alloca,如裸 list* 对上 list[ast.ASTptr]*)。
|
||||
# 只比较「双方都是指针且 pointee 都是结构体」:结构体名不同即 fail-fast(不兜底)。
|
||||
if alloca is not None and alloca.Ty is not None and var_ty is not None:
|
||||
av_pt_d: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if av_pt_d is not None and self.Gen.ExprGenBase.is_ptr_type(av_pt_d) != 0 \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(var_ty) != 0:
|
||||
av_in: llvmlite.LLVMType | t.CPtr = av_pt_d.Pointee
|
||||
vt_in: llvmlite.LLVMType | t.CPtr = var_ty.Pointee
|
||||
if av_in is not None and vt_in is not None:
|
||||
av_nm_d: str = llvmlite.get_struct_name(av_in)
|
||||
vt_nm_d: str = llvmlite.get_struct_name(vt_in)
|
||||
if av_nm_d is not None and vt_nm_d is not None \
|
||||
and string.strcmp(av_nm_d, vt_nm_d) != 0:
|
||||
# 仅当旧 alloca 的 pointee 是裸泛型模板基类(丢类型实参,如裸
|
||||
# list / 裸 GSList)而注解是另一个类型时 fail-fast(后续方法调用
|
||||
# 会按错误元素类型特化 → 截断);不同具体类(如 Tuple* vs AST*)
|
||||
# 属合法的同名重声明换类型(都是 8 字节指针槽),不拦截。
|
||||
av_pf: int = GenApi.sha1_prefix_len(av_nm_d)
|
||||
av_short: str = av_nm_d + av_pf if av_pf != 0 else av_nm_d
|
||||
if string.strchr(av_short, '[') is None:
|
||||
av_tpl: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(av_short)
|
||||
if av_tpl is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
aa,
|
||||
f"变量 '{nm.id}' 复用到的存储类型为裸泛型基类 '{av_nm_d}*'"
|
||||
f"(丢了类型实参),与注解解析类型 '{vt_nm_d}*' 不一致;"
|
||||
f"禁止静默混用——方法调用会按错误元素类型特化并截断指针",
|
||||
"TypeError")
|
||||
|
||||
# FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储)
|
||||
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / char|t.CPtr 不创建。
|
||||
# a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,
|
||||
@@ -1789,11 +1744,8 @@ class AssignGenMixin:
|
||||
if inm2.id is not None:
|
||||
if self.Gen.AsyncGen.is_async_func(trans, inm2.id) != 0:
|
||||
self.Gen.AsyncGen.register_coro_var(trans, nm.id, inm2.id)
|
||||
# 局部数组:列表字面量 → 逐元素 GEP + store 初始化
|
||||
# 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal,
|
||||
# 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的
|
||||
# t.CArray[char, 256] = [0])。局部 alloca 未零初始化,
|
||||
# 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。
|
||||
# 局部数组:列表字面量 → 先整体置零,再逐元素 GEP + store 初始化。
|
||||
# 不走 translate_list_literal(避免误触发 list[T] 泛型特化)。
|
||||
local_arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None:
|
||||
pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
@@ -1824,16 +1776,10 @@ class AssignGenMixin:
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, trans, lv_target_ty)
|
||||
if rhs_val is not None:
|
||||
# 注解退化修复(对齐 TPC 从构造结果推断类型):
|
||||
# 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板
|
||||
# 未注册 struct → resolve 退化)会让 alloca 类型退化为
|
||||
# Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int]
|
||||
# 结构))。此时按退化 alloca store 会丢失特化类型,后续
|
||||
# vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName
|
||||
# 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。
|
||||
# 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用
|
||||
# 按精确特化类名解析。旧退化 alloca 行残留为 entry block
|
||||
# 死代码(文本 IR 即时生成,无法删除,无害)。
|
||||
# 注解退化修复(对齐 TPC 从构造结果推断类型):无实参泛型模板注解
|
||||
# 会让 alloca 退化为 Ptr(i8),而 rhs 构造返回精确结构体指针 → 用 rhs
|
||||
# 精确类型重建 alloca 并更新符号表,使方法调用按精确特化类名解析;
|
||||
# 旧退化 alloca 残留为 entry 块死代码(文本 IR 即时生成无法删除,无害)。
|
||||
precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if rhs_val.Ty is not None:
|
||||
match rhs_val.Ty:
|
||||
@@ -1847,23 +1793,13 @@ class AssignGenMixin:
|
||||
pass
|
||||
if precise_rhs_ty is not None and alloca.Ty is not None:
|
||||
alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
# 禁止「降级重建」:RHS 的 pointee 若为**裸泛型基类**(丢类型
|
||||
# 实参,如 {sha1}.list / {sha1}.GSList),以它重建 alloca 会把后
|
||||
# 注解已解析出的「带类型实参特化」(如 list[ast.ASTptr])覆盖成裸
|
||||
# 基类 → 之后 .get() 按错误元素类型特化(list[int].get 返回 i32)
|
||||
# → inttoptr 把 i32 当指针(截断)→ translate_stmt 读垃圾 AST 节
|
||||
# 点崩溃。本重建本意是「注解退化成裸基类/i8*,RHS 构造出精确特化」
|
||||
# 的**反向升级**(见上方注释),因此仅在 RHS 不是裸泛型基类时才执行。
|
||||
# 现场根因:AST.children 字段注册为裸 list*(其注解
|
||||
# list[rowptr[AST]] | t.CPtr 在字段注册期未解析出带实参特化),
|
||||
# 故 `body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children`
|
||||
# 的 RHS 静态类型退化为裸 list*,触发本降级重建 →
|
||||
# MatchGenMixin._handle_renum_match 崩溃(IR 实证:
|
||||
# %"body_list.1" = alloca %"….list"* 被使用,%body_list 特化 alloca
|
||||
# 成死代码;.get 被分派到 list[int].get 返回 i32 → inttoptr 截断)。
|
||||
# 裸泛型基类不可作为 receiver 静态类型,否则泛型方法分派必错。
|
||||
# 禁止「降级重建」:RHS 的 pointee 若是裸泛型基类(丢类型实参,
|
||||
# 如 {sha1}.list / {sha1}.GSList),以它重建会把注解已解析出的
|
||||
# 带类型实参特化覆盖成裸基类 → .get() 按错误元素类型分派 →
|
||||
# inttoptr 截断崩溃。故仅 RHS 不是裸泛型基类时才执行重建
|
||||
# (本重建本意是注解退化为裸基类/i8*、RHS 精确的反向升级)。
|
||||
# 取注解侧泛型基名(Base ∈ list/dict/...,仅 Name 形态的
|
||||
# Subscript 一侧),用于下方**不依赖泛型模板注册表**的方向判定。
|
||||
# Subscript 一侧),用于下方不依赖泛型模板注册表的方向判定。
|
||||
ann_gen_base: str = None
|
||||
if annot is not None:
|
||||
ag_side: ast.AST | t.CPtr = annot
|
||||
@@ -2275,10 +2211,7 @@ class AssignGenMixin:
|
||||
if tk == ast.ASTKind.Attribute:
|
||||
# property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时,
|
||||
# 生成 call Class.attr$set(obj, v),跳过字段存储
|
||||
# 注意参数顺序:_try_property_setter(pool, builder, mod, ...)——
|
||||
# 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数
|
||||
# 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable
|
||||
# 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。
|
||||
# 注意参数顺序:_try_property_setter(pool, builder, mod, ...)。
|
||||
if self.Gen.CallGenProp._try_property_setter(
|
||||
pool, builder, mod, target, rhs_val, trans) == 1:
|
||||
continue
|
||||
@@ -2366,10 +2299,9 @@ class AssignGenMixin:
|
||||
target,
|
||||
f"global 变量 '{nm.id}' 未注册,无法赋值",
|
||||
"NameError")
|
||||
# 对象类全局(裸类名注解 → 静态 storage):对象构造/赋值 → 引用
|
||||
# 绑定到 storage + 复制对象到 storage。否则 store 栈 alloca 指针
|
||||
# 悬垂(devfs serial0_file 根因),或模块级构造初始化器被丢弃后
|
||||
# 全局保持 NULL(页 0 混叠根因,见 TranslatorGenMixin storage 逻辑)。
|
||||
# 对象类全局(裸类名注解 → 静态 storage):对象构造/赋值 → 引用绑定
|
||||
# 到 storage + 复制对象到 storage;否则 store 栈 alloca 指针悬垂,
|
||||
# 或模块级构造初始化器被丢弃后全局保持 NULL(见 TranslatorGenMixin)。
|
||||
stg_ref_as: llvmlite.Value | t.CPtr = None
|
||||
if nm.id is not None:
|
||||
stg_key_as: str = pool.alloc(sizet(string.strlen(nm.id)) + 8)
|
||||
@@ -2524,14 +2456,10 @@ class AssignGenMixin:
|
||||
return None
|
||||
obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans)
|
||||
if obj_cls is None:
|
||||
# 模块级函数调用(requests.get):ca.value 是已导入模块名
|
||||
# 而非对象变量(模块名 lookup_var_entry 返回 None → 上面
|
||||
# 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回
|
||||
# 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与
|
||||
# CallGenMixin 跨模块返回类型解析一致)。
|
||||
# WebTest resp = requests.get(...) 根因:无注解赋值变量
|
||||
# AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤
|
||||
# (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。
|
||||
# 模块级函数调用(requests.get):ca.value 是已导入模块名而非对象变量
|
||||
# (模块名 lookup_var_entry 返回 None → 对象类名推断失败)。从该模块
|
||||
# vpi 返回注解缓存解析返回类名(键 {sha1}.{func},cls_name=None 即模块级
|
||||
# 函数,与 CallGenMixin 跨模块返回类型解析一致)。
|
||||
if ca.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
|
||||
if mod_nm_rhs.id is not None:
|
||||
|
||||
Reference in new issue
Block a user