fix(codegen): widen from the value expression, not the enclosing statement

should_zext_widen decides the widening direction from the narrow side's AST
node, but the return and assignment coercions passed the statement node.
A statement has no type of its own, so the literal rule and the annotated
variable rule were skipped and the value fell through to sext:
`def f() -> uint64: return 0xDEADBEEF` produced 0xFFFFFFFFDEADBEEF and the
caller compared against 0xDEADBEEF and failed.

Unwrap Return/Assign/AnnAssign/AugAssign/Expr to their value expression
before the direction rules run, so a non-negative literal wider than
INT32_MAX zero-extends (0xDEADBEEF -> 0xDEADBEEF) and a negative one keeps
its sign (-1 -> 0xFFFFFFFFFFFFFFFF).
This commit is contained in:
TermiNexus committed 2026-10-28 23:15:07 +08:00
1 parent 19f9c53a5f
commit d5d05ec11e
1 file changed
+17
+17
View File
@@ -144,6 +144,11 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
6. 其余 → sext。
"""
if narrow_val is None or narrow_val.Ty is None: return 0
# Some call sites hand over the enclosing statement (return / assignment) instead of the
# value expression. The statement carries no type of its own, so rules 2/3/5 would miss a
# literal or an annotated variable and fall through to sext (`return 0xDEADBEEF` from a
# uint64 function became 0xFFFFFFFFDEADBEEF). Unwrap to the value expression first.
narrow_node = self._widen_value_node(narrow_node)
narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty)
if narrow_bits == 1: return 1
# 2. 整数字面量:以字面量数值为准(`0xFFFFFFFF` 是 4294967295 > INT32_MAX,必须 zext)
@@ -170,6 +175,18 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
if narrow_node is not None:
if self._node_type_unsigned(pool, narrow_node, trans) != 0: return 1
return 0
# _widen_value_node - 取语句节点的值表达式(Return/Assign/AnnAssign/AugAssign/Expr),
# 其他节点原样返回。加宽方向的判定必须落在**有类型的值节点**上。
def _widen_value_node(self, node: ast.AST*) -> ast.AST*:
"""Value expression of a statement node (Return/Assign/AnnAssign/AugAssign/Expr)."""
if node is None: return node
nk_wv: int = node.kind()
if nk_wv == ast.ASTKind.Return: return (ast.Return*(node)).value
if nk_wv == ast.ASTKind.Assign: return (ast.Assign*(node)).value
if nk_wv == ast.ASTKind.AnnAssign: return (ast.AnnAssign*(node)).value
if nk_wv == ast.ASTKind.AugAssign: return (ast.AugAssign*(node)).value
if nk_wv == ast.ASTKind.Expr: return (ast.Expr*(node)).value
return node
# _cdefine_int_of - 取节点引用的 DefineT 常量值。支持两种引用形态:
# · 裸名 `N`
# · 模块属性 `mod.N`(跨模块经 .vpi 注册;常量名就是 at.attr)