fix(HandlesClassDef/DeclarationGenerator): 未声明字段不再静默兜底 i32,推不出类型即 fail-fast
类别:a 编译器缺陷(静默兜底推断)+ 隐患预防。
判据(为什么必须去掉 i32 兜底):成员类型是 struct 布局的唯一来源,静默把"没声明/
推不出"的字段当成 i32 会把错误推到下游——值域不匹配时表现为与真因无关的报文
(同族既有现场:`free_lists: uint64*` 被当成 i32 后,`self.free_lists = base`(i8*) 报
"指针隐式转整数已禁止")。项目约定:类型信息缺失立即终止(与同函数 `self.X: T` 分支
HandlesClassDef.py:1356-1386 已有 fail-fast 同口径)。
改动 1(定义端布局,权威侧)HandlesClassDef._scan_node_for_self_assign 的 Assign 分支:
删除 `MemberType = ir.IntType(32)` 默认值,改为显式 `MemberType = None` + 白名单定型;
推不出即 compile_error(含 文件:行:列、源码行、取值原文、建议写法,行号按 _line_offset
还原)+ sys.exit(1)。
采纳形态(逐条写进注释,必须与 stub 侧一致):
整型/布尔字面量→i32;浮点字面量→double;字符串字面量→i8*;
值为本方法带注解形参→该形参类型;白名单调用 float()/double()→double、char()→i8、
int()/long()/short()→i32、`x.len()`→i32;其余(None 字面量/BinOp/任意调用…)→终止。
改动 2(stub 声明侧)DeclarationGenerator._CollectOwnMemberTypes 的 Assign 分支:
删除 `InferredType = 'i32'` 默认值,改白名单 + 推不出即 raise `[FATAL] …拒绝静默写成
i32`;同时纠正两处与定义端不一致的映射:浮点字面量 'float'(f32) → 'double'(f64),
布尔字面量 'i8' → 'i32'(定义端 bool 走 int 分支),否则 stub 与定义端槽宽/类型分叉。
预检(确认不打断既有构建):用 TPC 自家解析器扫全工作区 .vp(678 类;口径 =
类体 AnnAssign + 任意位置 `self.X: T` + 祖先传递声明),"未声明字段 + 首次裸赋值"
实例数 = 0(曾疑似的 4 例 `self.Next = None` 均为继承字段:G4Node/Value 继承
GSListNode 已声明 Next)。
冒烟(合成样例,跑完删除):
A `self.flag = None`(未声明、None 无类型信息)⇒ SystemExit(1) + 明确报文;
B `self.n = 5`(可定型)⇒ 正常翻译;C `flag: int` 已声明后赋 None ⇒ 正常翻译。
已知残留(本次未动,已在代码注释里写明,避免下次盲修):stub 侧方法体内裸
`self.X = ...` 仍被 seen_member_names 过滤(该集合只含本类自有声明、不含继承字段);
若放行,继承字段(如 G4Node.Next)会被当成自有字段重复加槽 → 反而制造布局分叉。
要放行必须先在该处补"祖先字段名"判定。
This commit is contained in:
1 parent
1903ed14f6
commit
de89fda73d
2 files changed
+85
-10
No files matched your search
@@ -829,14 +829,42 @@ class DeclarationGenerator:
|
||||
attr_name: str = item.targets[0].attr
|
||||
if attr_name in seen_member_names:
|
||||
continue
|
||||
InferredType: str = 'i32'
|
||||
if item.value and isinstance(item.value, ast.Constant):
|
||||
if isinstance(item.value.value, float):
|
||||
InferredType = 'float'
|
||||
elif isinstance(item.value.value, bool):
|
||||
InferredType = 'i8'
|
||||
elif isinstance(item.value.value, str):
|
||||
# 不再兜底 i32:只认**能唯一确定**的取值形态,推不出即响亮失败。
|
||||
# 规则表必须与定义端 HandlesClassDef._scan_node_for_self_assign 的
|
||||
# Assign 分支**逐条一致**(stub 与定义端 struct 布局必须同源,
|
||||
# 少/多一个槽 ⇒ 跨模块字段偏移整体错位):
|
||||
# 整型/布尔字面量 → 'i32'(定义端 bool 走 int 分支);
|
||||
# 浮点字面量 → 'double'(定义端 DoubleType;此前这里写 'float'
|
||||
# = f32,与定义端 8 字节不一致);字符串字面量 → 'i8*'。
|
||||
# 注:`self.X = <带注解形参>` / 白名单调用(float()/double()/char()/
|
||||
# int()…/len())在定义端可定型,本函数**拿不到**符号表故不在此推
|
||||
# (这些形态一旦出现会被定义端接受,而 stub 这里判不了);
|
||||
# 另外方法体内的裸 `self.X = ...` 已被上方 seen_member_names 过滤
|
||||
# (只对**本类自有声明**判重,不含继承字段)——若贸然放行,
|
||||
# 继承字段(如 G4Node.Next)会被当成自有字段重复加一个槽,
|
||||
# 反而制造布局分叉。要放行必须先在此补"祖先字段名"判定。
|
||||
InferredType: str | None = None
|
||||
if item.value is not None and isinstance(item.value, ast.Constant):
|
||||
_v: object = item.value.value
|
||||
if isinstance(_v, bool):
|
||||
InferredType = 'i32'
|
||||
elif isinstance(_v, int):
|
||||
InferredType = 'i32'
|
||||
elif isinstance(_v, float):
|
||||
InferredType = 'double'
|
||||
elif isinstance(_v, str):
|
||||
InferredType = 'i8*'
|
||||
if InferredType is None:
|
||||
_vt: str = ''
|
||||
try:
|
||||
_vt = ast.unparse(item.value) if item.value is not None else '<无值>'
|
||||
except Exception:
|
||||
_vt = '<无法反解析>'
|
||||
raise ValueError(
|
||||
f"[FATAL] 类 '{node.name}' 的字段 '{attr_name}' 在 stub 声明里"
|
||||
f"推不出类型(`self.{attr_name} = {_vt}`,行 "
|
||||
f"{getattr(item, 'lineno', 0)})——拒绝静默写成 i32。"
|
||||
f"请在类体声明该字段并给注解。")
|
||||
member_types.append(InferredType)
|
||||
else:
|
||||
member_types.append('i32')
|
||||
|
||||
@@ -1407,11 +1407,29 @@ class ClassHandle(BaseHandle):
|
||||
and target.value.id == 'self'):
|
||||
VarName = target.attr
|
||||
if VarName not in existing_members:
|
||||
MemberType = ir.IntType(32)
|
||||
if node.value:
|
||||
# 类型判定:只接受**能唯一确定**的取值形态(下表);推不出即
|
||||
# fail-fast,绝不静默产出 i32 槽(项目约定:类型信息缺失立即
|
||||
# 终止;与同函数 `self.X: T` 分支 :1356-1386 同口径)。
|
||||
# 同族现场:`free_lists: uint64*` 被当成 i32 后,
|
||||
# `self.free_lists = base`(i8*) 误报"指针隐式转整数已禁止"。
|
||||
# 【必须与 DeclarationGenerator._CollectOwnMemberTypes 的
|
||||
# 同名规则逐条一致】否则 stub 与定义端 struct 布局分叉
|
||||
# (stub 少/多一个槽 ⇒ 跨模块字段偏移整体错位):
|
||||
# 整型字面量 → i32;布尔字面量 → i32(Python 中 bool 是 int
|
||||
# 子类,维持既有 int 分支语义);浮点字面量 → double;
|
||||
# 字符串字面量 → i8*;值为**本方法带注解的形参** → 该形参类型;
|
||||
# 白名单调用 float()/double() → double、char() → i8、
|
||||
# int()/long()/short() → i32、`x.len()` → i32。
|
||||
# 其余(None 字面量、BinOp、任意调用/属性链…)→ fail-fast:
|
||||
# 这些形态推不出成员类型,静默 i32 只会把错误推到下游
|
||||
# (写指针值 → "指针隐式转整数已禁止")。
|
||||
MemberType: ir.Type | None = None
|
||||
if node.value is not None:
|
||||
try:
|
||||
if isinstance(node.value, ast.Constant):
|
||||
if isinstance(node.value.value, int):
|
||||
if isinstance(node.value.value, bool):
|
||||
MemberType = ir.IntType(32)
|
||||
elif isinstance(node.value.value, int):
|
||||
MemberType = ir.IntType(32)
|
||||
elif isinstance(node.value.value, float):
|
||||
MemberType = ir.DoubleType()
|
||||
@@ -1441,6 +1459,35 @@ class ClassHandle(BaseHandle):
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||||
if MemberType is None:
|
||||
_src_f: str = getattr(Gen, '_current_source_file', '') or ''
|
||||
_ln_f: int = getattr(node, 'lineno', 0) or 0
|
||||
_col_f: int = getattr(node, 'col_offset', -1)
|
||||
# 行号还原:AST 行号含 _inject_auto_imports 注入的 N 行
|
||||
_off_f: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||||
if _off_f > 0 and _ln_f > _off_f:
|
||||
_ln_f -= _off_f
|
||||
_code_f: str = ''
|
||||
try:
|
||||
_code_f = (Gen._get_source_line(_ln_f) or '').strip()
|
||||
except Exception:
|
||||
_code_f = ''
|
||||
_val_txt: str = ''
|
||||
try:
|
||||
_val_txt = ast.unparse(node.value) if node.value is not None else '<无值>'
|
||||
except Exception:
|
||||
_val_txt = '<无法反解析>'
|
||||
_msg_f: str = (
|
||||
f"类 '{ClassName}' 的字段 '{VarName}' 没有声明类型"
|
||||
f"(既不在类体注解、也不在祖先中),且首次赋值 "
|
||||
f"`self.{VarName} = {_val_txt}` 的取值形态推不出成员类型"
|
||||
f"——拒绝静默当成 i32(那会把错误推到下游:写指针值时报"
|
||||
f"「指针隐式转整数已禁止」)。请在类体声明该字段并给注解"
|
||||
f"(如 `{VarName}: t.CInt32T` / `{VarName}: t.CPtr`),"
|
||||
f"或在赋值处给出可定型的取值。"
|
||||
f"位置 {_src_f}:{_ln_f}:{_col_f}")
|
||||
_vlog().compile_error(_msg_f, _src_f, _ln_f, _code_f)
|
||||
sys.exit(1)
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
Gen.class_member_signeds[ClassName][VarName] = None
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
|
||||
Reference in new issue
Block a user