fix(ExprGenBase): REnum 变体构造纳入「构造物化」豁免;错误报文只报问题本身
1) _ctor_call_agg_ty 增加 REnum 变体构造识别:`EnumType.Variant(...)` 的变体名不是结构体名 (find_struct 必 miss)⇒ 取属性链最右裸名,若判为基础枚举则返回该枚举的聚合类型。 否则 `*槽 = <boxed 变体>` 会被「指针 → 非基本类型值」禁令拦下—— 现场 ClassGenDef.vp:128 `*existing.Ty = llvmlite.LLVMType.Struct(...)`。 2) 按用户要求简化 Error 输出:CastError 只报问题(原因 + 源/目标类型),去掉 ";出错表达式: <形态>(行/列)源码: ..." 后缀(文件与行号已由 TypeGenErr 的 Traceback 帧给出,属重复展示),并删除随之失去调用点的 _cast_fail_where / _source_snippet。
This commit is contained in:
1 parent
a714ec9d37
commit
21d5cd1cd1
2 files changed
+29
-96
No files matched your search
@@ -362,91 +362,8 @@ novirtual class ExprGenBase:
|
||||
v = (ast.Return*(node)).value
|
||||
if v is None:
|
||||
return node
|
||||
return v
|
||||
# ============================================================
|
||||
# _source_snippet - 尽力取「源码片段」(行文本),失败返回空串
|
||||
#
|
||||
# 报文风格对齐本仓既有「源码片段 + 行:列」(源行由 TypeGenErr.fatal_error 的
|
||||
# Traceback 帧也会打印;此处再在报文内附一份,便于单行错误消息自洽可读)。
|
||||
# 行文本由 stdlib.malloc 分配,拼进 f-string 后立即 free。
|
||||
# ============================================================
|
||||
def _source_snippet(self, lineno: int) -> str:
|
||||
"""尽力读取第 lineno 行源码文本,拼成片段;取不到返回空串"""
|
||||
if lineno <= 0:
|
||||
return ""
|
||||
file_name: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if file_name is None:
|
||||
return ""
|
||||
line: str = self.Gen.TypeGenErr.read_source_line(file_name, lineno)
|
||||
if line is None:
|
||||
return ""
|
||||
body: str = GenApi.escape_fstring_copy(f"\n 源码: {line}")
|
||||
stdlib.free(line)
|
||||
return body
|
||||
# ============================================================
|
||||
# _cast_fail_where - 隐式转换失败时报出**出错的表达式**(→ 定位到具体实参)
|
||||
#
|
||||
# 调用点只传 AST 节点,报错原本只有"调用所在行",多实参时看不出是哪一个
|
||||
# (如 `_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)`
|
||||
# 报指针→整数,无法判断是哪个实参)。此处按节点形态给出可读名:
|
||||
# Name→'id'、Attribute→'.attr'、Call/Subscript→形态名,并附**行:列**。
|
||||
#
|
||||
# 诊断错位修复(2026-09-28):
|
||||
# ① 先经 _value_node_of 把外层语句节点(Assign kind=3 等)下沉到真正被转换的
|
||||
# 值子表达式节点,再按形态描述;
|
||||
# ② 列号 col_offset 缺省为 -1,此前按无符号格式化成 4294967295;现按有符号
|
||||
# 打印,未知(<0)一律显示 '-',绝不出现 4294967295;
|
||||
# ③ 尽力附源码片段(行 + 列 + 源行文本)。
|
||||
# ============================================================
|
||||
def _cast_fail_where(self, node: ast.AST*) -> str:
|
||||
"""取隐式转换失败的定位文本(出错表达式 + 行:列 + 源码片段)
|
||||
|
||||
返回值会**逃逸本函数**(被 coerce_to_type 拼进更大的报文),而 f-string 结果
|
||||
指向当前函数的栈缓冲 ⇒ 每处都经 GenApi.escape_fstring_copy 显式拷到 stdlib 堆
|
||||
(历史事故:直接 return f"..." 让调用方读到已弹栈的帧,ASan
|
||||
stack-buffer-underflow in vsnprintf)。
|
||||
"""
|
||||
node = self._value_node_of(node)
|
||||
if node is None:
|
||||
return "节点未知(无 AST 信息)"
|
||||
k: int = node.kind()
|
||||
pos: int = -1
|
||||
where: str = None
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
pos = nm.col_offset
|
||||
where = f"Name '{nm.id}'"
|
||||
elif k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None:
|
||||
pos = at.col_offset
|
||||
where = f"属性 '.{at.attr}'"
|
||||
elif k == ast.ASTKind.Call:
|
||||
pos = (ast.Call*(node)).col_offset
|
||||
where = "调用结果 Call"
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
pos = (ast.Subscript*(node)).col_offset
|
||||
where = "下标表达式 Subscript"
|
||||
elif k == ast.ASTKind.Constant:
|
||||
pos = (ast.Constant*(node)).col_offset
|
||||
where = "常量 Constant"
|
||||
if where is None:
|
||||
where = f"表达式 kind={k}"
|
||||
# 列号按**有符号**打印:col_offset 未知/缺省为 -1,若按无符号会打成
|
||||
# 4294967295;未知一律显示 '-'。
|
||||
col_txt: str = "-"
|
||||
if pos >= 0:
|
||||
col_txt = f"{pos}"
|
||||
# 行号:node.lineno 缺省为 0/负,未知显示 '-'。
|
||||
ln: int = node.lineno
|
||||
ln_txt: str = "-"
|
||||
if ln > 0:
|
||||
ln_txt = f"{ln}"
|
||||
snippet: str = self._source_snippet(ln)
|
||||
return GenApi.escape_fstring_copy(f"{where}(行 {ln_txt},列 {col_txt}){snippet}")
|
||||
|
||||
# ============================================================
|
||||
return v
|
||||
# ============================================================
|
||||
# IsNoneValue - 判据:源值是否为 None(空值常量),返回 1=是 / 0=否
|
||||
#
|
||||
# None 是特殊的空值常量:语义上「无值」,按语言规则**允许隐式转换为任意
|
||||
@@ -780,9 +697,25 @@ novirtual class ExprGenBase:
|
||||
if callee is None:
|
||||
return None
|
||||
ent: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(callee)
|
||||
if ent is None or ent.Ty is None:
|
||||
return None
|
||||
return ent.Ty
|
||||
if ent is not None and ent.Ty is not None:
|
||||
return ent.Ty
|
||||
# REnum 变体构造 `EnumType.Variant(...)`:被调方是「基础枚举.变体」,变体名不是
|
||||
# 结构体名(find_struct 必 miss);但构造结果物化的就是**基础枚举**的整对象
|
||||
# (boxed 指针指向该枚举结构体)⇒ 返回该 REnum 的聚合类型,使「构造物化」豁免
|
||||
# 覆盖 `*槽 = <boxed 变体>`。否则该写法会被「指针 → 非基本类型值」禁令拦下
|
||||
# (现场 ClassGenDef.vp:128 `*existing.Ty = llvmlite.LLVMType.Struct(...)`)。
|
||||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||||
base_v: ast.AST* = (ast.Attribute*(cl.func)).value
|
||||
# 取属性链最右的裸名(llvmlite.LLVMType → LLVMType)
|
||||
while base_v is not None and base_v.kind() == ast.ASTKind.Attribute:
|
||||
base_v = (ast.Attribute*(base_v)).value
|
||||
if base_v is not None and base_v.kind() == ast.ASTKind.Name:
|
||||
base_nm: str = (ast.Name*(base_v)).id
|
||||
if base_nm is not None and self.Gen.ClassGenEnum._is_renum_class_name(base_nm) != 0:
|
||||
rn_ent: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(base_nm)
|
||||
if rn_ent is not None and rn_ent.Ty is not None:
|
||||
return rn_ent.Ty
|
||||
return None
|
||||
# ============================================================
|
||||
# _same_agg_ty - 两个聚合类型是否为「同一非基本类型」(构造物化豁免的类型匹配)
|
||||
# ============================================================
|
||||
@@ -851,7 +784,7 @@ novirtual class ExprGenBase:
|
||||
return llvmlite.build_inttoptr(builder, llvmlite.const_int64(builder.Pool, 0), target_ty)
|
||||
m_i2p: str = "整数隐式转指针已禁止:必须显式强转为指针(如 t.CPtr(x))才能把整数赋给指针类型"
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_i2p};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
m_i2p, "CastError")
|
||||
return val
|
||||
# Pointer -> integer: rejected (symmetric with the integer -> pointer rule above).
|
||||
# No implicit pointer <-> integer conversion is allowed; an explicit cast is
|
||||
@@ -860,7 +793,7 @@ novirtual class ExprGenBase:
|
||||
if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and self.is_ptr_type(target_ty) == 0:
|
||||
m_p2i: str = "指针隐式转整数已禁止:必须显式强转(如 uint64(p) / t.CInt64T(p) / int(p))才能把指针赋给整数类型"
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_p2i};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
m_p2i, "CastError")
|
||||
return val
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
if val_bits == target_bits:
|
||||
@@ -906,7 +839,7 @@ novirtual class ExprGenBase:
|
||||
if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \
|
||||
(self.is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"unsupported type conversion: float <-> ptr;出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
"unsupported type conversion: float <-> ptr", "CastError")
|
||||
return val
|
||||
if val_fbits != 0 and target_fbits != 0:
|
||||
if val_fbits == target_fbits:
|
||||
@@ -932,7 +865,7 @@ novirtual class ExprGenBase:
|
||||
v2p_txt: str = GenApi.escape_fstring_copy(
|
||||
f";源值类型 {self._type_text(builder.Pool, val.Ty)} → 目标类型 {self._type_text(builder.Pool, target_ty)}")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_v2p}{v2p_txt};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
f"{m_v2p}{v2p_txt}", "CastError")
|
||||
return val
|
||||
tmp_agg: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, val.Ty)
|
||||
if tmp_agg is not None:
|
||||
@@ -962,11 +895,11 @@ novirtual class ExprGenBase:
|
||||
p2v_txt: str = GenApi.escape_fstring_copy(
|
||||
f";源类型 {self._type_text(builder.Pool, val.Ty)} → 目标值类型 {self._type_text(builder.Pool, target_ty)}")
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{m_p2v}{p2v_txt};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
f"{m_p2v}{p2v_txt}", "CastError")
|
||||
return val
|
||||
return llvmlite.build_load(builder, target_ty, val)
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"指针隐式转非指针值已禁止:必须显式解引用(c.Deref(p) / *p)或显式强转(uint64(p));出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
f"指针隐式转非指针值已禁止:必须显式解引用(c.Deref(p) / *p)或显式强转(uint64(p))", "CastError")
|
||||
return val
|
||||
# 指针 → 指针: 隐式转换须满足两条新规则(见 _ptr_cast_reason 单一真源):
|
||||
# 规则 1 通用指针(t.CPtr / i8*)与任何 T* 双向互转都放行;
|
||||
@@ -979,7 +912,7 @@ novirtual class ExprGenBase:
|
||||
if pc != PC_OK:
|
||||
reason: str = self._ptr_cast_reason_text(pc, builder.Pool, val.Ty, target_ty)
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
f"{reason};出错表达式: {self._cast_fail_where(node)}", "CastError")
|
||||
reason, "CastError")
|
||||
return val
|
||||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||||
return val
|
||||
|
||||
@@ -166,7 +166,7 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
# ASan stack-buffer-underflow in vsnprintf(READ size 1,栈左红区)。
|
||||
# · 确需逃逸时**显式分配后拷贝**:GenApi.escape_fstring_copy
|
||||
# (stdlib.malloc + string.strcpy);编译器自身的报文构造即此写法
|
||||
# (ExprGenBase._cast_fail_where / AssignGenMixin.const_assign_msg)。
|
||||
# (AssignGenMixin.const_assign_msg)。
|
||||
buf_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
||||
buf_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, buf_ty)
|
||||
if buf_alloca is None: return None
|
||||
|
||||
Reference in new issue
Block a user