@@ -491,23 +491,59 @@ fn (mut g Gen) gen_stmt(id flat.NodeId) {
491491}
492492
493493fn (mut g Gen) gen_decl_assign (node flat.Node) {
494+ // Multi-declaration (`x, y := a, b`): evaluate every RHS against the outer
495+ // scope before binding any new name, so a shadowing `x, y := x+1, x+2`
496+ // reads the outer x for both initializers.
497+ if node.children_count > 2 {
498+ g.gen_multi_decl (node)
499+ return
500+ }
501+ lhs := g.a.child_node (& node, 0 )
502+ rhs_id := g.a.child (& node, 1 )
503+ w := g.expr_wtype (rhs_id, node.typ)
504+ uns := g.decl_is_unsigned (rhs_id, node.typ)
505+ width := g.decl_width (rhs_id, node.typ)
506+ if lhs.kind == .ident {
507+ // Emit the initializer before binding the new name, so a shadowing
508+ // `x := x + 1` reads the outer x rather than the fresh zero local.
509+ g.gen_expr_as (rhs_id, w)
510+ idx := g.new_local (lhs.value, w, uns, width)
511+ g.narrow_for_local (lhs.value)
512+ g.cur.local_set (idx)
513+ }
514+ }
515+
516+ fn (mut g Gen) gen_multi_decl (node flat.Node) {
517+ mut temps := []int {}
518+ mut names := []string {}
519+ mut ws := []WType{}
520+ mut unss := []bool {}
521+ mut widths := []int {}
522+ // Phase 1: buffer every RHS into a temporary (outer bindings still in scope).
494523 mut i := 0
495524 for i + 1 < node.children_count {
496525 lhs := g.a.child_node (& node, i)
497526 rhs_id := g.a.child (& node, i + 1 )
498- w := g.expr_wtype (rhs_id, node.typ)
499- uns := g.decl_is_unsigned (rhs_id, node.typ)
500- width := g.decl_width (rhs_id, node.typ)
501527 if lhs.kind == .ident {
502- // Emit the initializer before binding the new name, so a shadowing
503- // `x := x + 1` reads the outer x rather than the fresh zero local.
528+ w := g.expr_wtype (rhs_id, node.typ)
504529 g.gen_expr_as (rhs_id, w)
505- idx := g.new_local (lhs.value, w, uns, width)
506- g.narrow_for_local (lhs.value)
507- g.cur.local_set (idx)
530+ t := g.alloc_temp (w)
531+ g.cur.local_set (t)
532+ temps << t
533+ names << lhs.value
534+ ws << w
535+ unss << g.decl_is_unsigned (rhs_id, node.typ)
536+ widths << g.decl_width (rhs_id, node.typ)
508537 }
509538 i + = 2
510539 }
540+ // Phase 2: bind each new local and store its buffered value.
541+ for k, name in names {
542+ idx := g.new_local (name, ws[k], unss[k], widths[k])
543+ g.cur.local_get (temps[k])
544+ g.narrow_for_local (name)
545+ g.cur.local_set (idx)
546+ }
511547}
512548
513549fn (mut g Gen) gen_assign (node flat.Node) {
@@ -786,7 +822,7 @@ fn (mut g Gen) gen_expr(id flat.NodeId) WType {
786822 return g.gen_infix (id, node)
787823 }
788824 .prefix {
789- return g.gen_prefix (node)
825+ return g.gen_prefix (id, node)
790826 }
791827 .postfix {
792828 g.gen_postfix (node)
@@ -852,10 +888,17 @@ fn (mut g Gen) gen_infix(id flat.NodeId, node flat.Node) WType {
852888 }
853889 signed := ! g.is_unsigned (lhs_id)
854890 g.gen_expr_as (lhs_id, value_w)
891+ if op == .right_shift_unsigned && value_w == .i32 {
892+ // A narrow signed lhs is stored sign-extended in i32; mask it to its
893+ // width so the upper bits don't feed into the logical shift.
894+ lw := narrow_width (g.tc.resolve_type (lhs_id))
895+ if lw != 32 {
896+ g.emit_narrow (lw, true )
897+ }
898+ }
855899 g.emit_shift_with_count (op, value_w, rhs_id, signed)
856900 if value_w == .i32 {
857- rt := g.tc.resolve_type (id)
858- g.emit_narrow (narrow_width (rt), type_is_unsigned (rt))
901+ g.narrow_result (id)
859902 }
860903 return value_w
861904 }
@@ -869,12 +912,18 @@ fn (mut g Gen) gen_infix(id flat.NodeId, node flat.Node) WType {
869912 g.emit_arith (op, ow, signed)
870913 // Sub-32-bit results (e.g. u8 + u8) wrap to their declared width in V.
871914 if ow == .i32 {
872- rt := g.tc.resolve_type (id)
873- g.emit_narrow (narrow_width (rt), type_is_unsigned (rt))
915+ g.narrow_result (id)
874916 }
875917 return ow
876918}
877919
920+ // narrow_result masks/sign-extends the i32 on the stack to the resolved type's
921+ // sub-32-bit width (a no-op for 32/64-bit types).
922+ fn (mut g Gen) narrow_result (id flat.NodeId) {
923+ rt := g.tc.resolve_type (id)
924+ g.emit_narrow (narrow_width (rt), type_is_unsigned (rt))
925+ }
926+
878927fn (mut g Gen) gen_logical (node flat.Node) WType {
879928 lhs_id := g.a.child (& node, 0 )
880929 rhs_id := g.a.child (& node, 1 )
@@ -896,7 +945,7 @@ fn (mut g Gen) gen_logical(node flat.Node) WType {
896945 return .i32
897946}
898947
899- fn (mut g Gen) gen_prefix (node flat.Node) WType {
948+ fn (mut g Gen) gen_prefix (id flat.NodeId, node flat.Node) WType {
900949 child_id := g.a.child (& node, 0 )
901950 match node.op {
902951 .minus {
@@ -922,6 +971,7 @@ fn (mut g Gen) gen_prefix(node flat.Node) WType {
922971 g.cur.i32_const (0 )
923972 g.gen_expr_as (child_id, .i32 )
924973 g.cur.raw (0x6b ) // i32.sub
974+ g.narrow_result (id) // negation of a narrow type wraps to its width
925975 return .i32
926976 }
927977 }
@@ -940,6 +990,7 @@ fn (mut g Gen) gen_prefix(node flat.Node) WType {
940990 }
941991 g.cur.i32_const (- 1 )
942992 g.cur.raw (0x73 ) // i32.xor
993+ g.narrow_result (id) // ~ of a narrow type keeps its width (e.g. ~u8(0)=255)
943994 return .i32
944995 }
945996 else {
0 commit comments