From 4f7403b5c142be0d1e5ce2204b882f1fe68cae3f Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Wed, 10 Dec 2025 21:05:31 +0800 Subject: [PATCH 1/7] rename loopvar --- gnovm/pkg/gnolang/machine.go | 8 ++ gnovm/pkg/gnolang/nodes.go | 135 ++++++++++++++++++++++++++++++ gnovm/pkg/gnolang/nodes_string.go | 8 ++ gnovm/pkg/gnolang/op_assign.go | 5 ++ gnovm/pkg/gnolang/op_eval.go | 1 + gnovm/pkg/gnolang/preprocess.go | 37 +++++++- gnovm/pkg/gnolang/transcribe.go | 2 + gnovm/pkg/gnolang/values.go | 5 +- gnovm/tests/files/redefine7.gno | 16 ++++ gnovm/tests/files/redefine7a.gno | 13 +++ gnovm/tests/files/redefine7b.gno | 12 +++ gnovm/tests/files/redefine8.gno | 27 ++++++ gnovm/tests/files/redefine9.gno | 16 ++++ gnovm/tests/files/redefine9a.gno | 9 ++ 14 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 gnovm/tests/files/redefine7.gno create mode 100644 gnovm/tests/files/redefine7a.gno create mode 100644 gnovm/tests/files/redefine7b.gno create mode 100644 gnovm/tests/files/redefine8.gno create mode 100644 gnovm/tests/files/redefine9.gno create mode 100644 gnovm/tests/files/redefine9a.gno diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 1cc7a8f2936..400f7571bf5 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2254,6 +2254,14 @@ func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { lb := m.LastBlock() pv = lb.GetPointerTo(m.Store, lx.Path) ro = false // always mutable + case NameExprTypeLoopVarDefine: + lb := m.LastBlock() + pv = lb.GetPointerTo(m.Store, lx.Path) + ro = false // always mutable + case NameExprTypeLoopVarUse: + lb := m.LastBlock() + pv = lb.GetPointerTo(m.Store, lx.Path) + ro = false // always mutable case NameExprTypeHeapUse: lb := m.LastBlock() pv = lb.GetPointerTo(m.Store, lx.Path) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index fb9a2b88860..c0fc731d7d4 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -380,8 +380,33 @@ const ( NameExprTypeHeapDefine // when defining escaped name in loop NameExprTypeHeapUse // when above used in non-define lhs/rhs NameExprTypeHeapClosure // when closure captures name + + NameExprTypeLoopVarDefine // when defining a loopvar + NameExprTypeLoopVarUse + + NameExprTypeLoopVarHeapDefine // when defining escaped name in loop + NameExprTypeLoopVarHeapUse ) +var nameExprTypeStrings = [...]string{ + NameExprTypeNormal: "Normal", + NameExprTypeDefine: "Define", + NameExprTypeHeapDefine: "HeapDefine", + NameExprTypeHeapUse: "HeapUse", + NameExprTypeHeapClosure: "HeapClosure", + NameExprTypeLoopVarDefine: "LoopVarDefine", + NameExprTypeLoopVarUse: "LoopVarUse", + NameExprTypeLoopVarHeapDefine: "LoopVarHeapDefine", + NameExprTypeLoopVarHeapUse: "LoopVarHeapUse", +} + +func (t NameExprType) String() string { + if int(t) < 0 || int(t) >= len(nameExprTypeStrings) { + return fmt.Sprintf("NameExprType(%d)", t) + } + return nameExprTypeStrings[t] +} + type NameExpr struct { Attributes // TODO rename .Path's to .ValuePaths. @@ -1556,6 +1581,8 @@ type BlockNode interface { GetBody() Body SetBody(Body) + FindNameSkipPredefined(Store, Name) bool + // Utility methods for gno fix etc. // Unlike GetType[Decl|Expr]For[Path|Expr] which are determined // statically, functions may be variable, so GetFuncNodeFor[Path|Expr] @@ -1765,6 +1792,7 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { // Check local. gen := 1 if idx, ok := sb.GetLocalIndex(n); ok { + fmt.Printf("---gen: %d, idx: %d \n", gen, idx) return NewValuePathBlock(uint8(gen), idx, n) } sn := sb.GetSource(store) @@ -1942,6 +1970,112 @@ func (sb *StaticBlock) GetLocalIndex(n Name) (uint16, bool) { return 0, false } +func (sb *StaticBlock) FindNameSkipPredefined(store Store, n Name) bool { + fmt.Println("FindNameSkipPredefined, n: ", n) + if n == blankIdentifier { + return false + } + // Check local. + gen := 1 + // also search with .loopvar_, this make sure `i` also + // get a correct path. + if _, loopvar, ok := sb.GetLocalIndexSkipPredefined(n); ok { + fmt.Println("===loopVar: ", loopvar) + // found a NameExpr with type NameExprTypeLoopVarDefine + return loopvar + } + // Check ancestors. + gen++ + bp := sb.GetParentNode(store) + for bp != nil { + if _, loopvar, ok := sb.GetLocalIndexSkipPredefined(n); ok { + // found a NameExpr with type NameExprTypeLoopVarDefine + return loopvar + } else { + bp = bp.GetParentNode(store) + gen++ + if 0xff < gen { + panic("value path depth overflow") + } + } + } + return false +} + +func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) { + fmt.Println("===GetLocalIndexSkipPredefined, n: ", n) + // if loopvar is found. + var loopvar bool + + // firstly search general TypeDefine names, + // it potentially overrides the loopvar. + for i, name := range sb.Names { + if name == n { + if debug { + nt := reflect.TypeOf(sb.Source).String() + debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = %v, %v\n", + sb, nt, n, i, name) + } + // skip predefined name + t := sb.Types[i] + if t != nil { + return uint16(i), loopvar, true + } + // else going on search loopvar + } + } + + // if not found above, looking for loopvar. + for i, name := range sb.Names { + println("===search loopvar") + n = Name(fmt.Sprintf(".loopvar_%s", n)) + fmt.Println("===n: ", n) + if name == n { + if debug { + nt := reflect.TypeOf(sb.Source).String() + debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = %v, %v\n", + sb, nt, n, i, name) + } + + loopvar = true + + t := sb.Types[i] + if t == nil { + return 0, loopvar, false + } + return uint16(i), loopvar, true + } + } + if debug { + nt := reflect.TypeOf(sb.Source).String() + debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = undefined\n", + sb, nt, n) + } + return 0, loopvar, false +} + +func renameLoopVar(last BlockNode, nx *NameExpr) { + fmt.Println("===renameLoopVar, nx: ", nx, nx.Type) + fmt.Println("---last: ", last) + if nx.Name == blankIdentifier { + return + } + + if nx.Type == NameExprTypeNormal { + // handle loopvar stuff + found := last.FindNameSkipPredefined(nil, nx.Name) + if found { + fmt.Println("---found loopvar use, nx: ", nx) + nx.Type = NameExprTypeLoopVarUse + // XXX, necessary? + nx.Name = Name(fmt.Sprintf(".loopvar_%s", nx.Name)) + fmt.Println("===after rename, nx: ", nx) + } else { + fmt.Println("Not loopvar, nx: ", nx, nx.Type) + } + } +} + // Implemented BlockNode. // This method is too slow for runtime, but it is used during preprocessing to // compute types. If ignoreReserved, skips over names that are only reserved @@ -2221,6 +2355,7 @@ func (sb *StaticBlock) Define(n Name, tv TypedValue) { // Set type to nil, only reserving the name. func (sb *StaticBlock) Reserve(isConst bool, nx *NameExpr, origin Node, nstype NSType, index int) { + fmt.Println("======Reserve, nx: ", nx) _, exists := sb.GetLocalIndex(nx.Name) if !exists { sb.Define2(isConst, nx.Name, nil, anyValue(nil), NameSource{nx, origin, nstype, index}) diff --git a/gnovm/pkg/gnolang/nodes_string.go b/gnovm/pkg/gnolang/nodes_string.go index 7fe022d8621..136d8723508 100644 --- a/gnovm/pkg/gnolang/nodes_string.go +++ b/gnovm/pkg/gnolang/nodes_string.go @@ -102,10 +102,18 @@ func (x NameExpr) String() string { return fmt.Sprintf("%s<%s>", x.Name, x.Path.String()) case NameExprTypeDefine: return fmt.Sprintf("%s", x.Name, x.Path.String()) + case NameExprTypeLoopVarDefine: + return fmt.Sprintf("%s", x.Name, x.Path.String()) case NameExprTypeHeapDefine: return fmt.Sprintf("%s", x.Name, x.Path.String()) + case NameExprTypeLoopVarHeapDefine: + return fmt.Sprintf("%s<@!~%s>", x.Name, x.Path.String()) case NameExprTypeHeapUse: return fmt.Sprintf("%s<~%s>", x.Name, x.Path.String()) + case NameExprTypeLoopVarUse: + return fmt.Sprintf("%s<*%s>", x.Name, x.Path.String()) + case NameExprTypeLoopVarHeapUse: + return fmt.Sprintf("%s<*~%s>", x.Name, x.Path.String()) case NameExprTypeHeapClosure: return fmt.Sprintf("%s<()~%s>", x.Name, x.Path.String()) default: diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index b4291515f82..438bdd889b5 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -1,7 +1,10 @@ package gnolang +import "fmt" + func (m *Machine) doOpDefine() { s := m.PopStmt().(*AssignStmt) + fmt.Println("---doOpDefine, s: ", s) // Define each value evaluated for Lhs. // NOTE: PopValues() returns a slice in // forward order, not the usual reverse. @@ -10,6 +13,8 @@ func (m *Machine) doOpDefine() { for i := range s.Lhs { // Get name and value of i'th term. nx := s.Lhs[i].(*NameExpr) + fmt.Println("---nx: ", nx) + fmt.Println("---rvs[i]: ", rvs[i]) // Finally, define (or assign if loop block). ptr := lb.GetPointerToMaybeHeapDefine(m.Store, nx) if m.Stage != StagePre && isUntyped(rvs[i].T) && rvs[i].T.Kind() != BoolKind { diff --git a/gnovm/pkg/gnolang/op_eval.go b/gnovm/pkg/gnolang/op_eval.go index 829a31b7eea..26cbb4fac06 100644 --- a/gnovm/pkg/gnolang/op_eval.go +++ b/gnovm/pkg/gnolang/op_eval.go @@ -26,6 +26,7 @@ func (m *Machine) doOpEval() { // TODO: understand this better. if nx, ok := x.(*NameExpr); ok { m.PopExpr() + // fmt.Println("---OpEval, nx: ", nx) if nx.Path.Depth == 0 { // Name is in uverse (global). gv := Uverse().GetBlock(nil).GetPointerTo(nil, nx.Path) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ee2c17934a3..d5cd9e21f2d 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -186,6 +186,7 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { case TRANS_ENTER: switch n := n.(type) { case *AssignStmt: + fmt.Println("---initStaticBlocks, assignStmt: ", n) if n.Op == DEFINE { for i, lx := range n.Lhs { nx := lx.(*NameExpr) @@ -194,10 +195,20 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { continue } if !isLocallyDefined2(last, ln) { - // if loopvar, will promote to - // NameExprTypeHeapDefine later. - nx.Type = NameExprTypeDefine + fmt.Println("---not locally defined, Reserve it, ln: ", ln) + if ftype == TRANS_FOR_INIT { + ln = Name(fmt.Sprintf(".loopvar_%s", ln)) + nx.Type = NameExprTypeLoopVarDefine // demote if shadowed by i := i + fmt.Println("---ln: ", ln) + nx.Name = ln // rename + } else { + // if loop extern, will promote to + // NameExprTypeHeapDefine later. + nx.Type = NameExprTypeDefine + } last.Reserve(false, nx, n, NSDefine, i) + } else { + fmt.Println("---locally defined, Ignore it, ln: ", ln) } } } @@ -544,6 +555,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { switch n := n.(type) { // TRANS_ENTER ----------------------- case *AssignStmt: + fmt.Println("---Trans_Enter assignStmt, n: ", n) checkValDefineMismatch(n) if n.Op == DEFINE { @@ -1025,6 +1037,11 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { switch n := n.(type) { // TRANS_LEAVE ----------------------- case *NameExpr: + fmt.Println("---Trans_Leave NameExpr: ", n) + if len(ns) > 0 { + fmt.Println("---last node: ", ns[len(ns)-1]) + } + // fmt.Println("---Trans_Leave NameExpr, last: ", last) if isBlankIdentifier(n) { switch ftype { case TRANS_ASSIGN_LHS, TRANS_RANGE_KEY, TRANS_RANGE_VALUE, TRANS_VAR_NAME: @@ -1104,13 +1121,21 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { default: switch ftype { case TRANS_ASSIGN_LHS: + fmt.Println("---Trans_Assign_LHS") as := ns[len(ns)-1].(*AssignStmt) fillNameExprPath(last, n, as.Op == DEFINE) return n, TRANS_CONTINUE case TRANS_VAR_NAME: + fmt.Println("---Trans_Var_Name") fillNameExprPath(last, n, true) return n, TRANS_CONTINUE default: + fmt.Println("---default..., use...") + // find LoopVarUse, and rename, + + // happens before fill path + // rename ensure name match. + renameLoopVar(last, n) fillNameExprPath(last, n, false) } // If uverse, return a *ConstExpr. @@ -2205,6 +2230,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *AssignStmt: + fmt.Println("---Trans_Leave, assignStmt: ", n) n.AssertCompatible(store, last) if n.Op == ASSIGN { for _, lh := range n.Lhs { @@ -5071,6 +5097,11 @@ func fauxChildBlockNode(bn BlockNode) bool { } func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { + fmt.Println("---fillNameExprPath, nx: ", nx) + defer func() { + fmt.Println("---path filled: ", nx.Path) + }() + if nx.Name == blankIdentifier { // Blank name has no path; caller error. panic("should not happen") diff --git a/gnovm/pkg/gnolang/transcribe.go b/gnovm/pkg/gnolang/transcribe.go index 27d66474bf4..a087276fb60 100644 --- a/gnovm/pkg/gnolang/transcribe.go +++ b/gnovm/pkg/gnolang/transcribe.go @@ -351,12 +351,14 @@ func transcribe(t Transform, ns []Node, ftype TransField, index int, n Node, nc } case *AssignStmt: for idx := range cnn.Lhs { + // fmt.Println("---transcribe LHS...") cnn.Lhs[idx] = transcribe(t, nns, TRANS_ASSIGN_LHS, idx, cnn.Lhs[idx], &c).(Expr) if stopOrSkip(nc, c) { return } } for idx := range cnn.Rhs { + // fmt.Println("---transcribe RHS...") cnn.Rhs[idx] = transcribe(t, nns, TRANS_ASSIGN_RHS, idx, cnn.Rhs[idx], &c).(Expr) if stopOrSkip(nc, c) { return diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 95a5f9d9dde..68c05daa7aa 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2465,6 +2465,7 @@ func (b *Block) GetPointerToDirect(store Store, path ValuePath) PointerValue { // First defines a new HeapItemValue if heap slot. func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerValue { + PrintCaller(2, 5) switch nx.Type { case NameExprTypeNormal: // XXX convert rangestmt switchstmt names @@ -2472,6 +2473,8 @@ func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerVa return b.GetPointerTo(store, nx.Path) case NameExprTypeDefine: return b.GetPointerTo(store, nx.Path) + case NameExprTypeLoopVarDefine: + return b.GetPointerTo(store, nx.Path) case NameExprTypeHeapDefine: path := nx.Path ptr := b.GetPointerToDirect(store, path) @@ -2493,7 +2496,7 @@ func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerVa return ptr } default: - panic("unexpected NameExpr type for GetPointerToMaybeHeapDefine") + panic(fmt.Sprintf("unexpected NameExpr type for GetPointerToMaybeHeapDefine: %v \n", nx.Type)) } } diff --git a/gnovm/tests/files/redefine7.gno b/gnovm/tests/files/redefine7.gno new file mode 100644 index 00000000000..b738efe39f1 --- /dev/null +++ b/gnovm/tests/files/redefine7.gno @@ -0,0 +1,16 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + i := i + println(i) + } +} + +// Preprocessed: +// file{ package main; func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { i := .loopvar_i<*VPBlock(1,0)>; (const (println func(...interface {})))(i) } } } + +// Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/redefine7a.gno b/gnovm/tests/files/redefine7a.gno new file mode 100644 index 00000000000..7cb83e052aa --- /dev/null +++ b/gnovm/tests/files/redefine7a.gno @@ -0,0 +1,13 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + // i := i + func() { + i += 1 + }() + println(i) + } +} + +// Output: diff --git a/gnovm/tests/files/redefine7b.gno b/gnovm/tests/files/redefine7b.gno new file mode 100644 index 00000000000..f8cdae7a6b5 --- /dev/null +++ b/gnovm/tests/files/redefine7b.gno @@ -0,0 +1,12 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + i := i+1 + println(i) + } +} + +// Output: +// 1 +// 3 \ No newline at end of file diff --git a/gnovm/tests/files/redefine8.gno b/gnovm/tests/files/redefine8.gno new file mode 100644 index 00000000000..3c362d06c37 --- /dev/null +++ b/gnovm/tests/files/redefine8.gno @@ -0,0 +1,27 @@ +package main + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + println(i, e) + } + }() + + for i := 0; i < 3; i++ { + // i := i + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// go 1.22 loop var is not supported for now. + +// Output: +// 0 &(3 int) +// 1 &(3 int) +// 2 &(3 int) diff --git a/gnovm/tests/files/redefine9.gno b/gnovm/tests/files/redefine9.gno new file mode 100644 index 00000000000..df835269545 --- /dev/null +++ b/gnovm/tests/files/redefine9.gno @@ -0,0 +1,16 @@ +package main + +import "fmt" + +func main() { + for i := 0; i < 3; i++ { + i := i // shadow loop variable + func() { + i += 1 + }() + } + fmt.Println("Hello, 世界") +} + +// Error: +// unexpected NameExpr type for GetPointerToMaybeHeapDefine diff --git a/gnovm/tests/files/redefine9a.gno b/gnovm/tests/files/redefine9a.gno new file mode 100644 index 00000000000..e6bc17a6d59 --- /dev/null +++ b/gnovm/tests/files/redefine9a.gno @@ -0,0 +1,9 @@ +package main + +func main() { + if i := 1; i > 0 { + i := i + println(i) + } +} + From 34a26cd58a20a6884358e97306a6617a5786b1f7 Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Wed, 10 Dec 2025 23:42:17 +0800 Subject: [PATCH 2/7] fixup --- gnovm/pkg/gnolang/nodes.go | 32 +++++++------------------------- gnovm/pkg/gnolang/preprocess.go | 1 + gnovm/tests/files/redefine7c.gno | 16 ++++++++++++++++ gnovm/tests/files/redefine7d.gno | 27 +++++++++++++++++++++++++++ gnovm/tests/files/redefine7e.gno | 19 +++++++++++++++++++ gnovm/tests/files/redefine7f.gno | 20 ++++++++++++++++++++ gnovm/tests/files/redefine9.gno | 8 ++++++-- 7 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 gnovm/tests/files/redefine7c.gno create mode 100644 gnovm/tests/files/redefine7d.gno create mode 100644 gnovm/tests/files/redefine7e.gno create mode 100644 gnovm/tests/files/redefine7f.gno diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index c0fc731d7d4..2b18eb2509b 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -388,25 +388,6 @@ const ( NameExprTypeLoopVarHeapUse ) -var nameExprTypeStrings = [...]string{ - NameExprTypeNormal: "Normal", - NameExprTypeDefine: "Define", - NameExprTypeHeapDefine: "HeapDefine", - NameExprTypeHeapUse: "HeapUse", - NameExprTypeHeapClosure: "HeapClosure", - NameExprTypeLoopVarDefine: "LoopVarDefine", - NameExprTypeLoopVarUse: "LoopVarUse", - NameExprTypeLoopVarHeapDefine: "LoopVarHeapDefine", - NameExprTypeLoopVarHeapUse: "LoopVarHeapUse", -} - -func (t NameExprType) String() string { - if int(t) < 0 || int(t) >= len(nameExprTypeStrings) { - return fmt.Sprintf("NameExprType(%d)", t) - } - return nameExprTypeStrings[t] -} - type NameExpr struct { Attributes // TODO rename .Path's to .ValuePaths. @@ -1988,7 +1969,7 @@ func (sb *StaticBlock) FindNameSkipPredefined(store Store, n Name) bool { gen++ bp := sb.GetParentNode(store) for bp != nil { - if _, loopvar, ok := sb.GetLocalIndexSkipPredefined(n); ok { + if _, loopvar, ok := bp.GetStaticBlock().GetLocalIndexSkipPredefined(n); ok { // found a NameExpr with type NameExprTypeLoopVarDefine return loopvar } else { @@ -2003,7 +1984,8 @@ func (sb *StaticBlock) FindNameSkipPredefined(store Store, n Name) bool { } func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) { - fmt.Println("===GetLocalIndexSkipPredefined, n: ", n) + // fmt.Println("===GetLocalIndexSkipPredefined, sb: ", sb.Block) + // fmt.Println("===GetLocalIndexSkipPredefined, n: ", n) // if loopvar is found. var loopvar bool @@ -2026,11 +2008,11 @@ func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) } // if not found above, looking for loopvar. + n2 := Name(fmt.Sprintf(".loopvar_%s", n)) + // fmt.Println("===n2: ", n2) for i, name := range sb.Names { - println("===search loopvar") - n = Name(fmt.Sprintf(".loopvar_%s", n)) - fmt.Println("===n: ", n) - if name == n { + // println("===search loopvar") + if name == n2 { if debug { nt := reflect.TypeOf(sb.Source).String() debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = %v, %v\n", diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index d5cd9e21f2d..f065cb08b8f 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1123,6 +1123,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case TRANS_ASSIGN_LHS: fmt.Println("---Trans_Assign_LHS") as := ns[len(ns)-1].(*AssignStmt) + renameLoopVar(last, n) fillNameExprPath(last, n, as.Op == DEFINE) return n, TRANS_CONTINUE case TRANS_VAR_NAME: diff --git a/gnovm/tests/files/redefine7c.gno b/gnovm/tests/files/redefine7c.gno new file mode 100644 index 00000000000..8cdbb455285 --- /dev/null +++ b/gnovm/tests/files/redefine7c.gno @@ -0,0 +1,16 @@ +package main + +func main() { + for i, v := range []int{1, 2, 3} { + i := i + println(i, v) + } +} + +// Preprocessed: +// file{ package main; func main() { for i, v := range (const-type []int){(const (1 int)), (const (2 int)), (const (3 int))} { i := i; (const (println func(...interface {})))(i, v) } } } + +// Output: +// 0 1 +// 1 2 +// 2 3 diff --git a/gnovm/tests/files/redefine7d.gno b/gnovm/tests/files/redefine7d.gno new file mode 100644 index 00000000000..850367e52f2 --- /dev/null +++ b/gnovm/tests/files/redefine7d.gno @@ -0,0 +1,27 @@ +package main + +var fns []func() + +func main() { + for i := 0; i < 3; i++ { + i := i + f := func() { + i += 1 + println(i) + } + fns = append(fns, f) + // println(i) + } + + for _, ff := range fns{ + ff() + } +} + +// Preprocessed: +// file{ package main; var fns []func(); func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { i := .loopvar_i<*VPBlock(1,0)>; f := func func(){ i<~VPBlock(1,0)> += (const (1 int)); (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>; fns<~VPBlock(4,0)> = (const (append func([]func(), ...func()) []func()))(fns<~VPBlock(4,0)>, f) }; for _, ff := range fns<~VPBlock(4,0)> { ff() } } } + +// Output: +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/redefine7e.gno b/gnovm/tests/files/redefine7e.gno new file mode 100644 index 00000000000..b8443005405 --- /dev/null +++ b/gnovm/tests/files/redefine7e.gno @@ -0,0 +1,19 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + i := i + func() { + i += 1 + println(i) + }() + } +} + +// Preprocessed: +// file{ package main; func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { i := .loopvar_i<*VPBlock(1,0)>; func func(){ i<~VPBlock(1,0)> += (const (1 int)); (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>() } } } + +// Output: +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/redefine7f.gno b/gnovm/tests/files/redefine7f.gno new file mode 100644 index 00000000000..36862664303 --- /dev/null +++ b/gnovm/tests/files/redefine7f.gno @@ -0,0 +1,20 @@ +package main + +func main() { + for i := 0; i < 3; i++ { + for j := i; j < 3; j++ { + println(j) + } + } +} + +// Preprocessed: +// file{ package main; func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { for .loopvar_j := .loopvar_i<*VPBlock(2,0)>; .loopvar_j<*VPBlock(1,0)> < (const (3 int)); .loopvar_j<*VPBlock(1,0)>++ { (const (println func(...interface {})))(.loopvar_j<*VPBlock(1,0)>) } } } } + +// Output: +// 0 +// 1 +// 2 +// 1 +// 2 +// 2 diff --git a/gnovm/tests/files/redefine9.gno b/gnovm/tests/files/redefine9.gno index df835269545..b34a7640b60 100644 --- a/gnovm/tests/files/redefine9.gno +++ b/gnovm/tests/files/redefine9.gno @@ -7,10 +7,14 @@ func main() { i := i // shadow loop variable func() { i += 1 + println(i) }() } fmt.Println("Hello, 世界") } -// Error: -// unexpected NameExpr type for GetPointerToMaybeHeapDefine +// Output: +// 1 +// 2 +// 3 +// Hello, 世界 From dd99ac1e2880fa18bbc4c7aad5eb52b84dd6acfc Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Sat, 13 Dec 2025 01:28:27 +0800 Subject: [PATCH 3/7] intermediate... --- gnovm/pkg/gnolang/machine.go | 2 + gnovm/pkg/gnolang/nodes.go | 28 +-- gnovm/pkg/gnolang/op_call.go | 3 + gnovm/pkg/gnolang/op_exec.go | 2 + gnovm/pkg/gnolang/preprocess.go | 349 +++++++++++++++++++++++++++++-- gnovm/pkg/gnolang/values.go | 7 + gnovm/tests/files/redefine7g.gno | 25 +++ 7 files changed, 384 insertions(+), 32 deletions(-) create mode 100644 gnovm/tests/files/redefine7g.gno diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 400f7571bf5..8b22789f73f 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2247,6 +2247,7 @@ func (m *Machine) IsReadonly(tv *TypedValue) bool { // and the lx isn't a name (base is a block), // and the lx isn't a composite lit expr. func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { + fmt.Println("---PopAsPointer2, lx: ", lx) switch lx := lx.(type) { case *NameExpr: switch lx.Type { @@ -2260,6 +2261,7 @@ func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { ro = false // always mutable case NameExprTypeLoopVarUse: lb := m.LastBlock() + fmt.Println("------lb: ", lb) pv = lb.GetPointerTo(m.Store, lx.Path) ro = false // always mutable case NameExprTypeHeapUse: diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 2b18eb2509b..923b605affb 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -141,6 +141,7 @@ const ( ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL" ATTR_PACKAGE_PATH GnoAttribute = "ATTR_PACKAGE_PATH" // if name expr refers to package. ATTR_FIX_FROM GnoAttribute = "ATTR_FIX_FROM" // gno fix this version. + ATTR_REWRITTEN GnoAttribute = "ATTR_REWRITTEN" ) // Embedded in each Node. @@ -384,7 +385,7 @@ const ( NameExprTypeLoopVarDefine // when defining a loopvar NameExprTypeLoopVarUse - NameExprTypeLoopVarHeapDefine // when defining escaped name in loop + NameExprTypeLoopVarHeapDefine // when loopvar is captured NameExprTypeLoopVarHeapUse ) @@ -1562,7 +1563,7 @@ type BlockNode interface { GetBody() Body SetBody(Body) - FindNameSkipPredefined(Store, Name) bool + FindNameMaybeLoopvar(Store, Name) (bool, bool) // Utility methods for gno fix etc. // Unlike GetType[Decl|Expr]For[Path|Expr] which are determined @@ -1951,27 +1952,27 @@ func (sb *StaticBlock) GetLocalIndex(n Name) (uint16, bool) { return 0, false } -func (sb *StaticBlock) FindNameSkipPredefined(store Store, n Name) bool { +func (sb *StaticBlock) FindNameMaybeLoopvar(store Store, n Name) (loopvar, found bool) { fmt.Println("FindNameSkipPredefined, n: ", n) if n == blankIdentifier { - return false + return false, false } // Check local. gen := 1 // also search with .loopvar_, this make sure `i` also // get a correct path. - if _, loopvar, ok := sb.GetLocalIndexSkipPredefined(n); ok { + if _, loopvar, found = sb.GetLocalIndexMaybeLoopvar(n); found { fmt.Println("===loopVar: ", loopvar) // found a NameExpr with type NameExprTypeLoopVarDefine - return loopvar + return } // Check ancestors. gen++ bp := sb.GetParentNode(store) for bp != nil { - if _, loopvar, ok := bp.GetStaticBlock().GetLocalIndexSkipPredefined(n); ok { + if _, loopvar, found = bp.GetStaticBlock().GetLocalIndexMaybeLoopvar(n); found { // found a NameExpr with type NameExprTypeLoopVarDefine - return loopvar + return loopvar, found } else { bp = bp.GetParentNode(store) gen++ @@ -1980,10 +1981,10 @@ func (sb *StaticBlock) FindNameSkipPredefined(store Store, n Name) bool { } } } - return false + return } -func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) { +func (sb *StaticBlock) GetLocalIndexMaybeLoopvar(n Name) (uint16, bool, bool) { // fmt.Println("===GetLocalIndexSkipPredefined, sb: ", sb.Block) // fmt.Println("===GetLocalIndexSkipPredefined, n: ", n) // if loopvar is found. @@ -2021,6 +2022,7 @@ func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) loopvar = true + // XXX, skip predefine name, why? t := sb.Types[i] if t == nil { return 0, loopvar, false @@ -2036,7 +2038,7 @@ func (sb *StaticBlock) GetLocalIndexSkipPredefined(n Name) (uint16, bool, bool) return 0, loopvar, false } -func renameLoopVar(last BlockNode, nx *NameExpr) { +func processLoopVar(last BlockNode, nx *NameExpr) { fmt.Println("===renameLoopVar, nx: ", nx, nx.Type) fmt.Println("---last: ", last) if nx.Name == blankIdentifier { @@ -2045,8 +2047,8 @@ func renameLoopVar(last BlockNode, nx *NameExpr) { if nx.Type == NameExprTypeNormal { // handle loopvar stuff - found := last.FindNameSkipPredefined(nil, nx.Name) - if found { + loopvar, found := last.FindNameMaybeLoopvar(nil, nx.Name) + if found && loopvar { fmt.Println("---found loopvar use, nx: ", nx) nx.Type = NameExprTypeLoopVarUse // XXX, necessary? diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 161f4845925..835c1b29d75 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -145,6 +145,9 @@ func (m *Machine) doOpCall() { pb := fr.Func.GetParent(m.Store) b := m.Alloc.NewBlock(fs, pb) + fmt.Println("======doOpCall, fv: ", fv) + fmt.Println("======doOpCall, fv.Captures: ", fv.Captures) + // Copy *FuncValue.Captures into block // NOTE: addHeapCapture in preprocess ensures order. if len(fv.Captures) != 0 { diff --git a/gnovm/pkg/gnolang/op_exec.go b/gnovm/pkg/gnolang/op_exec.go index e1f22e1a1ac..f91349d0704 100644 --- a/gnovm/pkg/gnolang/op_exec.go +++ b/gnovm/pkg/gnolang/op_exec.go @@ -434,6 +434,8 @@ EXEC_SWITCH: if debug { debug.Printf("EXEC: %v\n", s) } + fmt.Printf("==========================EXEC: %v\n", s) + switch cs := s.(type) { case *AssignStmt: switch cs.Op { diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index f065cb08b8f..ddd157c76c8 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -201,12 +201,18 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { nx.Type = NameExprTypeLoopVarDefine // demote if shadowed by i := i fmt.Println("---ln: ", ln) nx.Name = ln // rename + + // nx0 := Nx(".redefine_i") + // nx0.Type = NameExprTypeDefine + // last.Reserve(false, nx0, n, NSDefine, i) + // last.Reserve(false, nx, n, NSDefine, i+1) + last.Reserve(false, nx, n, NSDefine, i) } else { // if loop extern, will promote to // NameExprTypeHeapDefine later. nx.Type = NameExprTypeDefine + last.Reserve(false, nx, n, NSDefine, i) } - last.Reserve(false, nx, n, NSDefine, i) } else { fmt.Println("---locally defined, Ignore it, ln: ", ln) } @@ -497,25 +503,64 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: need to use Transcribe() here instead of `bn, ok := n.(BlockNode)` // because say n may be a *CallExpr containing an anonymous function. - Transcribe(n, - func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { - if stage != TRANS_ENTER { + heapTrans := func(n Node) { + Transcribe(n, + func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + if stage != TRANS_ENTER { + return n, TRANS_CONTINUE + } + if _, ok := n.(*FuncLitExpr); ok { + if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + return n, TRANS_SKIP + } + } + if bn, ok := n.(BlockNode); ok { + // findGotoLoopDefines(ctx, bn) + findHeapDefinesByUse(ctx, bn) + findHeapUsesDemoteDefines(ctx, bn) + findPackageSelectors(bn) + return n, TRANS_SKIP + } return n, TRANS_CONTINUE - } - if _, ok := n.(*FuncLitExpr); ok { - if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + }) + } + + loopvarTrans := func() { + var stop bool + Transcribe(n, + func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + if stage != TRANS_ENTER { + return n, TRANS_CONTINUE + } + if _, ok := n.(*FuncLitExpr); ok { + if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + return n, TRANS_SKIP + } + } + if bn, ok := n.(BlockNode); ok { + stop = findHeapDefinedLoopvarByUse(ctx, bn) + if stop { + fmt.Println("---bn: ", bn) + } + return n, TRANS_SKIP } - } - if bn, ok := n.(BlockNode); ok { - // findGotoLoopDefines(ctx, bn) - findHeapDefinesByUse(ctx, bn) - findHeapUsesDemoteDefines(ctx, bn) - findPackageSelectors(bn) - return n, TRANS_SKIP - } - return n, TRANS_CONTINUE - }) + return n, TRANS_CONTINUE + }) + if stop { + fmt.Println("------do need to inject stmt...") + // clean first + // re-preprocess + resetPreprocess(ctx, n) + fmt.Println("---after reset, n: ", n) + // inject stmt + n = preprocess1(store, ctx, n) + heapTrans(n) + } + } + + loopvarTrans() + return n } @@ -1123,7 +1168,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { case TRANS_ASSIGN_LHS: fmt.Println("---Trans_Assign_LHS") as := ns[len(ns)-1].(*AssignStmt) - renameLoopVar(last, n) + // for i := n; i > 0; i >>= 1 { + processLoopVar(last, n) fillNameExprPath(last, n, as.Op == DEFINE) return n, TRANS_CONTINUE case TRANS_VAR_NAME: @@ -1136,7 +1182,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // happens before fill path // rename ensure name match. - renameLoopVar(last, n) + processLoopVar(last, n) fillNameExprPath(last, n, false) } // If uverse, return a *ConstExpr. @@ -3031,6 +3077,201 @@ func findGotoLoopDefines(ctx BlockNode, bn BlockNode) { }) } +func resetPreprocess(ctx BlockNode, n Node) { + // Iterate over all nodes recursively. + _ = TranscribeB(ctx, n, func( + ns []Node, + stack []BlockNode, + last BlockNode, + ftype TransField, + index int, + n Node, + stage TransStage, + ) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("resetPreprocess %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + + // ---------------------------------------- + case TRANS_LEAVE: + n.SetAttribute(ATTR_PREPROCESSED, false) + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + +func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { + // Iterate over all nodes recursively. + _ = TranscribeB(ctx, bn, func( + ns []Node, + stack []BlockNode, + last BlockNode, + ftype TransField, + index int, + n Node, + stage TransStage, + ) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("findHeapDefinedLoopvarByUse %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + + // ---------------------------------------- + case TRANS_LEAVE: + + switch n := n.(type) { + case *RefExpr: + lmx := LeftmostX(n.X) + if nx, ok := lmx.(*NameExpr); ok { + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, nx.Path) + // The leftmost name of possibly nested index + // and selector exprs. + // e.g. leftmost.middle[0][2].rightmost + // Mark name for heap use. + addAttrHeapUse(dbn, nx.Name) + // adjust NameExpr type. + nx.Type = NameExprTypeHeapUse + } + case *ForStmt: + fmt.Println("------forStmt: ", n) + if n.GetAttribute(ATTR_REWRITTEN) == true { + fmt.Println("------forStmt re-written...") + // origName := strings.TrimPrefix(string(n.Name), ".loopvar_") + origName := "i" + redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) + stmts := n.GetBody() + + var firstSpan Span + for i, s := range stmts { + if i == 0 { + firstSpan = s.GetSpan() + } + span := s.GetSpan() + span2 := Span4(span.Line+1, span.Column, span.End.Line, span.End.Column) + span.SetSpanOverride(span2) + } + fmt.Println("---stmts: ", stmts) + lhs := Nx(redefineName) + rhs := Nx(".loopvar_i") + as := A(lhs, ":=", rhs) + as.SetSpan(firstSpan) + stmts2 := append([]Stmt{as}, stmts...) + fmt.Println("---2, stmts: ", stmts2) + + index := len(n.GetBlockNames()) + lhs.Type = NameExprTypeHeapDefine + n.Reserve(false, lhs, n, NSDefine, index+1) + + n.SetBody(stmts2) + + fmt.Println("---after process, n: ", n) + } + case *NameExpr: + fmt.Println("---findHeapDefinedLoopvarByUse, n.Name: ", n.Name) + // NOTE: Keep in sync maybe with transpile_gno0p0.go/FindMore... + // Ignore non-block type paths + if n.Path.Type != VPBlock { + return n, TRANS_CONTINUE + } + // Ignore blank identifers + if n.Name == blankIdentifier { + return n, TRANS_CONTINUE + } + // Ignore package names + if n.GetAttribute(ATTR_PACKAGE_REF) != nil { + return n, TRANS_CONTINUE + } + // Ignore decls names. + if ftype == TRANS_VAR_NAME { + return n, TRANS_CONTINUE + } + // Ignore := defines, etc. + if n.Type != NameExprTypeLoopVarUse { + return n, TRANS_CONTINUE + } + if !strings.HasPrefix(string(n.Name), ".loopvar") { + return n, TRANS_CONTINUE + } + + // Find the block where name is defined. + dbn := last.GetBlockNodeForPath(nil, n.Path) + dbn2 := dbn + for { + // If used as closure capture, mark as heap use. + flx, _, found := findFirstClosure(stack, dbn) + fmt.Println("---found closure, flx: ", flx) + if !found { + fmt.Println("---after process, dbn2: ", dbn2) + return n, TRANS_CONTINUE + } + + origName := strings.TrimPrefix(string(n.Name), ".loopvar_") + redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) + + if dbn.GetAttribute(ATTR_REWRITTEN) != true { + // fmt.Println("---dbn not re-written: ", dbn) + // stmts := dbn.GetBody() + + // var firstSpan Span + // for i, s := range stmts { + // if i == 0 { + // firstSpan = s.GetSpan() + // } + // span := s.GetSpan() + // span2 := Span4(span.Line+1, span.Column, span.End.Line, span.End.Column) + // span.SetSpanOverride(span2) + // } + // fmt.Println("---stmts: ", stmts) + // lhs := Nx(redefineName) + // rhs := Nx(redefineName) + // as := A(lhs, ":=", rhs) + // as.SetSpan(firstSpan) + // stmts2 := append([]Stmt{as}, stmts...) + // fmt.Println("---2, stmts: ", stmts2) + + // dbn.SetBody(stmts2) + + // fmt.Println("---after process, dbn: ", dbn) + + // stop current process + // inject i := i + // preprocess1 + // find...byUse + // find... + // find... + stop = true + dbn.SetAttribute(ATTR_REWRITTEN, true) + } + + // reset to type normal + n.Type = NameExprTypeNormal + // reset name + n.Name = Name(redefineName) + + // Loop again for more closures. + dbn = flx + } + } + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) + return +} + // Finds heap defines by their use in ref expressions or // closures (captures). Also adjusts the name expr type, // and sets new closure captures' path to refer to local @@ -3091,6 +3332,7 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { nx.Type = NameExprTypeHeapUse } case *NameExpr: + // fmt.Println("---findHeapDefinesByUse, n.Name: ", n.Name) // NOTE: Keep in sync maybe with transpile_gno0p0.go/FindMore... // Ignore non-block type paths if n.Path.Type != VPBlock { @@ -3117,6 +3359,7 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { for { // If used as closure capture, mark as heap use. flx, depth, found := findFirstClosure(stack, dbn) + fmt.Println("---findHeapDefinesByUse, flx: ", flx) if !found { return n, TRANS_CONTINUE } @@ -3143,6 +3386,8 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { idx := addHeapCapture(dbn, flx, depth, n) // adjust NameExpr type. n.Type = NameExprTypeHeapUse + fmt.Println("------!!!, n.Name: ", n.Name) + // XXX, handle loopvar heapuse case n.Path.SetDepth(uint8(depth)) n.Path.Index = idx // Loop again for more closures. @@ -3286,6 +3531,72 @@ func findLastFunction(last BlockNode, stop BlockNode) (fn FuncNode, depth int, f return } +// If a heap use name is in form of ".loopvar_x", +// means there's no i := i like redefinition... +func findHeapUsesLoopvar(ctx BlockNode, bn BlockNode) { + // create stack of BlockNodes. + last := ctx + stack := append(make([]BlockNode, 0, 32), last) + + // Iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + defer doRecover(stack, n) + + if debug { + debug.Printf("findHeapUsesLoopvar %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + } + + switch stage { + // ---------------------------------------- + case TRANS_BLOCK: + pushInitBlock(n.(BlockNode), &last, &stack) + + // ---------------------------------------- + case TRANS_ENTER: + switch n := n.(type) { + case *NameExpr: + // Ignore non-block type paths + if n.Path.Type != VPBlock { + return n, TRANS_CONTINUE + } + switch n.Type { + case NameExprTypeHeapUse: + fmt.Println("---findHeapUsesLoopvar, n.Name: ", n.Name) + loopvar, found := last.FindNameMaybeLoopvar(nil, n.Name) + fmt.Printf("---findHeapUsesLoopvar, loopvar: %t, found: %t \n", loopvar, found) + + // // Find the block where name is defined + // dbn := last.GetBlockNodeForPath(nil, n.Path) + // // If the name is heap used, + // if hasAttrHeapUse(dbn, n.Name) { + // // Change type to heap use. + // n.Type = NameExprTypeHeapUse + // } + } + return n, TRANS_CONTINUE + } + + // ---------------------------------------- + case TRANS_LEAVE: + + // Defer pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + + return n, TRANS_CONTINUE + } + return n, TRANS_CONTINUE + }) +} + // If a name is used as a heap item, Convert all other uses of such names // for heap use. If a name of type heap define is not actually used // as heap use, demotes them. diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 68c05daa7aa..8670cc73b3a 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2387,6 +2387,10 @@ func (b *Block) GetParent(store Store) *Block { } func (b *Block) GetPointerToInt(store Store, index int) PointerValue { + fmt.Println("---GetPointerToInt, b: ", b) + PrintCaller(2, 5) + fmt.Println("---b.Values: ", b.Values) + fmt.Println("---index: ", index) vv := fillValueTV(store, &b.Values[index]) if hiv, ok := vv.V.(*HeapItemValue); ok { fillValueTV(store, &hiv.Value) @@ -2414,6 +2418,8 @@ func (b *Block) GetPointerToIntDirect(store Store, index int) PointerValue { } func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { + fmt.Println("---GetPointerTo, b: ", b) + fmt.Println("---GetPointerTo, path: ", path) if path.IsBlockBlankPath() { if debug { if path.Name != blankIdentifier { @@ -2434,6 +2440,7 @@ func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { // would fail as if it were 1. for i := uint8(1); i < path.Depth; i++ { b = b.GetParent(store) + fmt.Println("---parent block: ", b) } return b.GetPointerToInt(store, int(path.Index)) } diff --git a/gnovm/tests/files/redefine7g.gno b/gnovm/tests/files/redefine7g.gno new file mode 100644 index 00000000000..675397b3672 --- /dev/null +++ b/gnovm/tests/files/redefine7g.gno @@ -0,0 +1,25 @@ +package main + +var fns []func() + +func main() { + for i := 0; i < 3; i++ { + f := func() { + i += 1 + println(i) + } + fns = append(fns, f) + } + + for _, ff := range fns{ + ff() + } +} + +// Preprocessed: +// file{ package main; var fns []func(); func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; f := func func(){ .redefine_i<~VPBlock(1,0)> += (const (1 int)); (const (println func(...interface {})))(.redefine_i<~VPBlock(1,0)>) }<.redefine_i<()~VPBlock(1,2)>>; fns<~VPBlock(4,0)> = (const (append func([]func(), ...func()) []func()))(fns<~VPBlock(4,0)>, f) }; for _, ff := range fns<~VPBlock(4,0)> { ff() } } } + +// Output: +// 1 +// 2 +// 3 From 48da134fd74ae28100b07a9634130a468527e326 Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Mon, 15 Dec 2025 16:26:33 +0800 Subject: [PATCH 4/7] add test; fixup --- gnovm/pkg/gnolang/preprocess.go | 8 +++++- gnovm/tests/files/redefine7h.gno | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 gnovm/tests/files/redefine7h.gno diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ddd157c76c8..d7822b0c9c0 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -555,8 +555,8 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { fmt.Println("---after reset, n: ", n) // inject stmt n = preprocess1(store, ctx, n) - heapTrans(n) } + heapTrans(n) } loopvarTrans() @@ -4664,6 +4664,11 @@ func findUndefinedAny(store Store, last BlockNode, x Expr, stack []Name, definin if tv := last.GetSlot(store, cx.Name, true); tv != nil { return } + // find .loopvar_xxx + name2 := Name(fmt.Sprintf(".loopvar_%s", cx.Name)) + if tv := last.GetSlot(store, name2, true); tv != nil { + return + } return cx.Name, direct } } else { @@ -5042,6 +5047,7 @@ func predefineRecursively2(store Store, last BlockNode, d Decl, stack []Name, de // *TypeDecl is a TypeValue) and sets it on last. As an exception, *FuncDecls // will preprocess receiver/argument/result types recursively. func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl, stack []Name, defining map[Name]struct{}, direct bool) (un Name, untype bool, directR bool) { + fmt.Println("------tryPredefine, d: ", d) if d.GetAttribute(ATTR_PREDEFINED) == true { panic(fmt.Sprintf("decl node already predefined! %v", d)) } diff --git a/gnovm/tests/files/redefine7h.gno b/gnovm/tests/files/redefine7h.gno new file mode 100644 index 00000000000..c0d68c3b819 --- /dev/null +++ b/gnovm/tests/files/redefine7h.gno @@ -0,0 +1,42 @@ +package main + + +var f1s []func() +var f2s []func() + +func main() { + for i := 0; i < 3; i++ { + f1 := func() { + println("i: ", i) + } + + f1s = append(f1s, f1) + + var i uint64 = uint64(i) + + f2 := func() { + println("i: ", i) + } + + f2s = append(f2s, f2) + + } + for _, f1 := range f1s { + f1() + } + + for _, f2 := range f2s { + f2() + } +} + +// Preprocessed: +// file{ package main; var f1s []func(); var f2s []func(); func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; f1 := func func(){ (const (println func(...interface {})))((const ("i: " string)), .redefine_i<~VPBlock(1,0)>) }<.redefine_i<()~VPBlock(1,4)>>; f1s<~VPBlock(4,0)> = (const (append func([]func(), ...func()) []func()))(f1s<~VPBlock(4,0)>, f1); var i (const-type uint64) = (const-type uint64)(.loopvar_i<*VPBlock(1,0)>); f2 := func func(){ (const (println func(...interface {})))((const ("i: " string)), i<~VPBlock(1,0)>) }>; f2s<~VPBlock(4,1)> = (const (append func([]func(), ...func()) []func()))(f2s<~VPBlock(4,1)>, f2) }; for _, f1 := range f1s<~VPBlock(4,0)> { f1() }; for _, f2 := range f2s<~VPBlock(4,1)> { f2() } } } + +// Output: +// i: 0 +// i: 1 +// i: 2 +// i: 0 +// i: 1 +// i: 2 From 87059562c2d96d1b8ea20f0dd61fef89fa157bf4 Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Mon, 15 Dec 2025 22:10:52 +0800 Subject: [PATCH 5/7] cleanup --- gnovm/pkg/gnolang/nodes.go | 2 +- gnovm/pkg/gnolang/preprocess.go | 102 ++++++++----------------------- gnovm/tests/files/redefine7a.gno | 3 + gnovm/tests/files/redefine7b.gno | 1 + gnovm/tests/files/redefine9a.gno | 3 + 5 files changed, 34 insertions(+), 77 deletions(-) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 923b605affb..9880c6f2971 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -141,7 +141,7 @@ const ( ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL" ATTR_PACKAGE_PATH GnoAttribute = "ATTR_PACKAGE_PATH" // if name expr refers to package. ATTR_FIX_FROM GnoAttribute = "ATTR_FIX_FROM" // gno fix this version. - ATTR_REWRITTEN GnoAttribute = "ATTR_REWRITTEN" + ATTR_REDEFINE_NAME GnoAttribute = "ATTR_REDEFINE_NAME" ) // Embedded in each Node. diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index d7822b0c9c0..4407c26d46e 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -503,7 +503,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // NOTE: need to use Transcribe() here instead of `bn, ok := n.(BlockNode)` // because say n may be a *CallExpr containing an anonymous function. - heapTrans := func(n Node) { + transformHeapItem := func(n Node) { Transcribe(n, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { if stage != TRANS_ENTER { @@ -525,8 +525,8 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { }) } - loopvarTrans := func() { - var stop bool + transform := func() { + var found bool Transcribe(n, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { if stage != TRANS_ENTER { @@ -538,28 +538,21 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } } if bn, ok := n.(BlockNode); ok { - stop = findHeapDefinedLoopvarByUse(ctx, bn) - if stop { - fmt.Println("---bn: ", bn) - } - + found = findHeapDefinedLoopvarByUse(ctx, bn) return n, TRANS_SKIP } return n, TRANS_CONTINUE }) - if stop { - fmt.Println("------do need to inject stmt...") - // clean first - // re-preprocess - resetPreprocess(ctx, n) - fmt.Println("---after reset, n: ", n) - // inject stmt + if found { + // restore ATTR_PREPROCESSED attribute + RestoreNode(ctx, n) + // re-preprocess1 n = preprocess1(store, ctx, n) } - heapTrans(n) + transformHeapItem(n) } - loopvarTrans() + transform() return n } @@ -3077,7 +3070,7 @@ func findGotoLoopDefines(ctx BlockNode, bn BlockNode) { }) } -func resetPreprocess(ctx BlockNode, n Node) { +func RestoreNode(ctx BlockNode, n Node) { // Iterate over all nodes recursively. _ = TranscribeB(ctx, n, func( ns []Node, @@ -3147,37 +3140,27 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { } case *ForStmt: fmt.Println("------forStmt: ", n) - if n.GetAttribute(ATTR_REWRITTEN) == true { + if n2, ok := n.GetAttribute(ATTR_REDEFINE_NAME).(string); ok && n2 != "" { fmt.Println("------forStmt re-written...") - // origName := strings.TrimPrefix(string(n.Name), ".loopvar_") - origName := "i" - redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) stmts := n.GetBody() - var firstSpan Span - for i, s := range stmts { - if i == 0 { - firstSpan = s.GetSpan() - } - span := s.GetSpan() - span2 := Span4(span.Line+1, span.Column, span.End.Line, span.End.Column) - span.SetSpanOverride(span2) - } - fmt.Println("---stmts: ", stmts) - lhs := Nx(redefineName) + lhs := Nx(n2) rhs := Nx(".loopvar_i") as := A(lhs, ":=", rhs) - as.SetSpan(firstSpan) - stmts2 := append([]Stmt{as}, stmts...) - fmt.Println("---2, stmts: ", stmts2) + stmts2 := make([]Stmt, 0, len(stmts)+1) + stmts2 = append(stmts2, as) + stmts2 = append(stmts2, stmts...) + // Index for new injected name index := len(n.GetBlockNames()) + // Set Heap type lhs.Type = NameExprTypeHeapDefine + // Reserve for new injected name n.Reserve(false, lhs, n, NSDefine, index+1) - n.SetBody(stmts2) fmt.Println("---after process, n: ", n) + n.DelAttribute(ATTR_REDEFINE_NAME) } case *NameExpr: fmt.Println("---findHeapDefinedLoopvarByUse, n.Name: ", n.Name) @@ -3208,57 +3191,26 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { // Find the block where name is defined. dbn := last.GetBlockNodeForPath(nil, n.Path) - dbn2 := dbn for { // If used as closure capture, mark as heap use. flx, _, found := findFirstClosure(stack, dbn) fmt.Println("---found closure, flx: ", flx) if !found { - fmt.Println("---after process, dbn2: ", dbn2) return n, TRANS_CONTINUE } + // true if found once + stop = true origName := strings.TrimPrefix(string(n.Name), ".loopvar_") redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) - if dbn.GetAttribute(ATTR_REWRITTEN) != true { - // fmt.Println("---dbn not re-written: ", dbn) - // stmts := dbn.GetBody() - - // var firstSpan Span - // for i, s := range stmts { - // if i == 0 { - // firstSpan = s.GetSpan() - // } - // span := s.GetSpan() - // span2 := Span4(span.Line+1, span.Column, span.End.Line, span.End.Column) - // span.SetSpanOverride(span2) - // } - // fmt.Println("---stmts: ", stmts) - // lhs := Nx(redefineName) - // rhs := Nx(redefineName) - // as := A(lhs, ":=", rhs) - // as.SetSpan(firstSpan) - // stmts2 := append([]Stmt{as}, stmts...) - // fmt.Println("---2, stmts: ", stmts2) - - // dbn.SetBody(stmts2) - - // fmt.Println("---after process, dbn: ", dbn) - - // stop current process - // inject i := i - // preprocess1 - // find...byUse - // find... - // find... - stop = true - dbn.SetAttribute(ATTR_REWRITTEN, true) + if _, ok := dbn.GetAttribute(ATTR_REDEFINE_NAME).(string); !ok { + dbn.SetAttribute(ATTR_REDEFINE_NAME, redefineName) } - // reset to type normal + // Reset to type normal n.Type = NameExprTypeNormal - // reset name + // Redefine name n.Name = Name(redefineName) // Loop again for more closures. @@ -3359,7 +3311,6 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { for { // If used as closure capture, mark as heap use. flx, depth, found := findFirstClosure(stack, dbn) - fmt.Println("---findHeapDefinesByUse, flx: ", flx) if !found { return n, TRANS_CONTINUE } @@ -3386,7 +3337,6 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { idx := addHeapCapture(dbn, flx, depth, n) // adjust NameExpr type. n.Type = NameExprTypeHeapUse - fmt.Println("------!!!, n.Name: ", n.Name) // XXX, handle loopvar heapuse case n.Path.SetDepth(uint8(depth)) n.Path.Index = idx diff --git a/gnovm/tests/files/redefine7a.gno b/gnovm/tests/files/redefine7a.gno index 7cb83e052aa..cd2ec804779 100644 --- a/gnovm/tests/files/redefine7a.gno +++ b/gnovm/tests/files/redefine7a.gno @@ -11,3 +11,6 @@ func main() { } // Output: +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/redefine7b.gno b/gnovm/tests/files/redefine7b.gno index f8cdae7a6b5..2866a3f86c2 100644 --- a/gnovm/tests/files/redefine7b.gno +++ b/gnovm/tests/files/redefine7b.gno @@ -9,4 +9,5 @@ func main() { // Output: // 1 +// 2 // 3 \ No newline at end of file diff --git a/gnovm/tests/files/redefine9a.gno b/gnovm/tests/files/redefine9a.gno index e6bc17a6d59..736ea8b529c 100644 --- a/gnovm/tests/files/redefine9a.gno +++ b/gnovm/tests/files/redefine9a.gno @@ -7,3 +7,6 @@ func main() { } } + +// Output: +// 1 \ No newline at end of file From ac3f812a9360825eebc6dd6e620400e29d1b2bb2 Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Tue, 16 Dec 2025 00:31:20 +0800 Subject: [PATCH 6/7] refX --- gnovm/pkg/gnolang/nodes.go | 5 +- gnovm/pkg/gnolang/preprocess.go | 59 ++++++++++++++++------ gnovm/pkg/gnolang/values.go | 7 --- gnovm/tests/files/heap_alloc_forloop1.gno | 10 ++-- gnovm/tests/files/heap_alloc_forloop1a.gno | 17 +++---- gnovm/tests/files/heap_alloc_forloop1b.gno | 10 ++-- gnovm/tests/files/heap_alloc_forloop1c.gno | 36 +++++++++++++ gnovm/tests/files/heap_alloc_forloop2.gno | 2 +- gnovm/tests/files/heap_alloc_forloop2b.gno | 33 ++++++++++++ gnovm/tests/files/heap_alloc_forloop3.gno | 2 +- gnovm/tests/files/redefine7i.gno | 20 ++++++++ 11 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 gnovm/tests/files/heap_alloc_forloop1c.gno create mode 100644 gnovm/tests/files/heap_alloc_forloop2b.gno create mode 100644 gnovm/tests/files/redefine7i.gno diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 9880c6f2971..08ac860f736 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -1774,7 +1774,6 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { // Check local. gen := 1 if idx, ok := sb.GetLocalIndex(n); ok { - fmt.Printf("---gen: %d, idx: %d \n", gen, idx) return NewValuePathBlock(uint8(gen), idx, n) } sn := sb.GetSource(store) @@ -2039,8 +2038,7 @@ func (sb *StaticBlock) GetLocalIndexMaybeLoopvar(n Name) (uint16, bool, bool) { } func processLoopVar(last BlockNode, nx *NameExpr) { - fmt.Println("===renameLoopVar, nx: ", nx, nx.Type) - fmt.Println("---last: ", last) + // fmt.Println("===renameLoopVar, nx: ", nx, nx.Type) if nx.Name == blankIdentifier { return } @@ -2339,7 +2337,6 @@ func (sb *StaticBlock) Define(n Name, tv TypedValue) { // Set type to nil, only reserving the name. func (sb *StaticBlock) Reserve(isConst bool, nx *NameExpr, origin Node, nstype NSType, index int) { - fmt.Println("======Reserve, nx: ", nx) _, exists := sb.GetLocalIndex(nx.Name) if !exists { sb.Define2(isConst, nx.Name, nil, anyValue(nil), NameSource{nx, origin, nstype, index}) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 4407c26d46e..ccd7696f7d9 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -3128,15 +3128,41 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { case *RefExpr: lmx := LeftmostX(n.X) if nx, ok := lmx.(*NameExpr); ok { + if !strings.HasPrefix(string(nx.Name), ".loopvar") { + return n, TRANS_CONTINUE + } // Find the block where name is defined dbn := last.GetBlockNodeForPath(nil, nx.Path) // The leftmost name of possibly nested index // and selector exprs. // e.g. leftmost.middle[0][2].rightmost - // Mark name for heap use. - addAttrHeapUse(dbn, nx.Name) - // adjust NameExpr type. - nx.Type = NameExprTypeHeapUse + + // Ignore post stmt name + nn := ns[len(ns)-1] + if fstmt, ok := dbn.(*ForStmt); ok { + if exst, ok := fstmt.Post.(*ExprStmt); ok { + if exst.X == nn { + return n, TRANS_CONTINUE + } + } + } + + // if ftype != TRANS_FOR_INIT && ftype != TRANS_FOR_COND && ftype != TRANS_FOR_POST { + if _, ok := dbn.(*ForStmt); ok { + // true if found once + stop = true + origName := strings.TrimPrefix(string(nx.Name), ".loopvar_") + redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) + + if _, ok := dbn.GetAttribute(ATTR_REDEFINE_NAME).(string); !ok { + dbn.SetAttribute(ATTR_REDEFINE_NAME, redefineName) + } + + // Reset to type normal + nx.Type = NameExprTypeNormal + // Redefine name + nx.Name = Name(redefineName) + } } case *ForStmt: fmt.Println("------forStmt: ", n) @@ -3199,19 +3225,21 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { return n, TRANS_CONTINUE } - // true if found once - stop = true - origName := strings.TrimPrefix(string(n.Name), ".loopvar_") - redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) + if _, ok := dbn.(*ForStmt); ok { + // true if found once + stop = true + origName := strings.TrimPrefix(string(n.Name), ".loopvar_") + redefineName := fmt.Sprintf("%s%s", ".redefine_", origName) - if _, ok := dbn.GetAttribute(ATTR_REDEFINE_NAME).(string); !ok { - dbn.SetAttribute(ATTR_REDEFINE_NAME, redefineName) - } + if _, ok := dbn.GetAttribute(ATTR_REDEFINE_NAME).(string); !ok { + dbn.SetAttribute(ATTR_REDEFINE_NAME, redefineName) + } - // Reset to type normal - n.Type = NameExprTypeNormal - // Redefine name - n.Name = Name(redefineName) + // Reset to type normal + n.Type = NameExprTypeNormal + // Redefine name + n.Name = Name(redefineName) + } // Loop again for more closures. dbn = flx @@ -4997,7 +5025,6 @@ func predefineRecursively2(store Store, last BlockNode, d Decl, stack []Name, de // *TypeDecl is a TypeValue) and sets it on last. As an exception, *FuncDecls // will preprocess receiver/argument/result types recursively. func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl, stack []Name, defining map[Name]struct{}, direct bool) (un Name, untype bool, directR bool) { - fmt.Println("------tryPredefine, d: ", d) if d.GetAttribute(ATTR_PREDEFINED) == true { panic(fmt.Sprintf("decl node already predefined! %v", d)) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 8670cc73b3a..68c05daa7aa 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2387,10 +2387,6 @@ func (b *Block) GetParent(store Store) *Block { } func (b *Block) GetPointerToInt(store Store, index int) PointerValue { - fmt.Println("---GetPointerToInt, b: ", b) - PrintCaller(2, 5) - fmt.Println("---b.Values: ", b.Values) - fmt.Println("---index: ", index) vv := fillValueTV(store, &b.Values[index]) if hiv, ok := vv.V.(*HeapItemValue); ok { fillValueTV(store, &hiv.Value) @@ -2418,8 +2414,6 @@ func (b *Block) GetPointerToIntDirect(store Store, index int) PointerValue { } func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { - fmt.Println("---GetPointerTo, b: ", b) - fmt.Println("---GetPointerTo, path: ", path) if path.IsBlockBlankPath() { if debug { if path.Name != blankIdentifier { @@ -2440,7 +2434,6 @@ func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { // would fail as if it were 1. for i := uint8(1); i < path.Depth; i++ { b = b.GetParent(store) - fmt.Println("---parent block: ", b) } return b.GetPointerToInt(store, int(path.Index)) } diff --git a/gnovm/tests/files/heap_alloc_forloop1.gno b/gnovm/tests/files/heap_alloc_forloop1.gno index 64e25ef8922..c8c91c429d6 100644 --- a/gnovm/tests/files/heap_alloc_forloop1.gno +++ b/gnovm/tests/files/heap_alloc_forloop1.gno @@ -20,12 +20,10 @@ func main() { forLoopRef() } -// go 1.22 loop var is not supported for now. - // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(.redefine_i<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } // Output: -// s1[0] is: 3 -// s1[1] is: 3 -// s1[2] is: 3 +// s1[0] is: 0 +// s1[1] is: 1 +// s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_forloop1a.gno b/gnovm/tests/files/heap_alloc_forloop1a.gno index 9692b47a84d..2b9b76e3edf 100644 --- a/gnovm/tests/files/heap_alloc_forloop1a.gno +++ b/gnovm/tests/files/heap_alloc_forloop1a.gno @@ -1,7 +1,5 @@ package main -import "fmt" - type Int int var s1 []*Int @@ -13,11 +11,12 @@ func inc2(j *Int) { func forLoopRef() { defer func() { for i, e := range s1 { - fmt.Printf("s1[%d] is: %d\n", i, *e) + println("i, e: ", i, *e) } }() for i := Int(0); i < 10; inc2(&i) { + // i := i s1 = append(s1, &i) } } @@ -29,11 +28,11 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; type Int (const-type main.Int); var s1 []*(typeval{main.Int}); func inc2(j *(typeval{main.Int})) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 main.Int)); i<~VPBlock(1,0)> < (const (10 main.Int)); inc2(&(i<~VPBlock(1,0)>)) { s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; type Int (const-type main.Int); var s1 []*(typeval{main.Int}); func inc2(j *(typeval{main.Int})) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (println func(...interface {})))((const ("i, e: " string)), i, *(e)) } }(); for .loopvar_i := (const (0 main.Int)); .loopvar_i<*VPBlock(1,0)> < (const (10 main.Int)); inc2(&(.loopvar_i<~VPBlock(1,0)>)) { .redefine_i := .loopvar_i<~VPBlock(1,0)>; s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(.redefine_i<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } // Output: -// s1[0] is: 10 -// s1[1] is: 10 -// s1[2] is: 10 -// s1[3] is: 10 -// s1[4] is: 10 +// i, e: 0 (0 main.Int) +// i, e: 1 (2 main.Int) +// i, e: 2 (4 main.Int) +// i, e: 3 (6 main.Int) +// i, e: 4 (8 main.Int) diff --git a/gnovm/tests/files/heap_alloc_forloop1b.gno b/gnovm/tests/files/heap_alloc_forloop1b.gno index 7817ee0d0b5..cf5c0255647 100644 --- a/gnovm/tests/files/heap_alloc_forloop1b.gno +++ b/gnovm/tests/files/heap_alloc_forloop1b.gno @@ -23,15 +23,13 @@ func main() { forLoopRef() } -// go 1.22 loop var is not supported for now. - // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { r := i<~VPBlock(1,0)>; r, ok := (const (0 int)), (const (true bool)); (const (println func(...interface {})))(ok, r); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; r := .loopvar_i<*VPBlock(1,0)>; r, ok := (const (0 int)), (const (true bool)); (const (println func(...interface {})))(ok, r); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(.redefine_i<~VPBlock(1,3)>)) } }; func main() { forLoopRef() } } // Output: // true 0 // true 0 // true 0 -// s1[0] is: 3 -// s1[1] is: 3 -// s1[2] is: 3 +// s1[0] is: 0 +// s1[1] is: 1 +// s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_forloop1c.gno b/gnovm/tests/files/heap_alloc_forloop1c.gno new file mode 100644 index 00000000000..01f35b7ba93 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop1c.gno @@ -0,0 +1,36 @@ +package main + +type Int int + +var s1 []*Int + +func inc2(j *Int) { + *j = *j + 2 // Just as an example, increment j by 2. +} + +func forLoopRef() { + defer func() { + for i, e := range s1 { + println("i, e: ", i, *e) + } + }() + + for i := Int(0); i < 10; inc2(&i) { + i := i + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// Preprocessed: +// file{ package main; type Int (const-type main.Int); var s1 []*(typeval{main.Int}); func inc2(j *(typeval{main.Int})) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (println func(...interface {})))((const ("i, e: " string)), i, *(e)) } }(); for .loopvar_i := (const (0 main.Int)); .loopvar_i<*VPBlock(1,0)> < (const (10 main.Int)); inc2(&(.loopvar_i<~VPBlock(1,0)>)) { .redefine_i := .loopvar_i<~VPBlock(1,0)>; i := .loopvar_i<*VPBlock(1,0)>; s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(.redefine_i<~VPBlock(1,2)>)) } }; func main() { forLoopRef() } } + +// Output: +// i, e: 0 (0 main.Int) +// i, e: 1 (2 main.Int) +// i, e: 2 (4 main.Int) +// i, e: 3 (6 main.Int) +// i, e: 4 (8 main.Int) diff --git a/gnovm/tests/files/heap_alloc_forloop2.gno b/gnovm/tests/files/heap_alloc_forloop2.gno index b85ae39099f..dc8266fc2b2 100644 --- a/gnovm/tests/files/heap_alloc_forloop2.gno +++ b/gnovm/tests/files/heap_alloc_forloop2.gno @@ -25,7 +25,7 @@ func main() { // You can tell by the preprocess printout of z and z<~...>. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i + (const (1 int)); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { z := .loopvar_i<*VPBlock(1,0)> + (const (1 int)); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } // Output: // s1[0] is: 1 diff --git a/gnovm/tests/files/heap_alloc_forloop2b.gno b/gnovm/tests/files/heap_alloc_forloop2b.gno new file mode 100644 index 00000000000..ce7d027f969 --- /dev/null +++ b/gnovm/tests/files/heap_alloc_forloop2b.gno @@ -0,0 +1,33 @@ +package main + +import "fmt" + +var s1 []*int + +func forLoopRef() { + defer func() { + for i, e := range s1 { + fmt.Printf("s1[%d] is: %d\n", i, *e) + } + }() + + for i := 0; i < 3; i++ { + i := i + 1 + s1 = append(s1, &i) + } +} + +func main() { + forLoopRef() +} + +// This does make 'z' NameExprTypeHeapDefine. +// You can tell by the preprocess printout of z and z<~...>. + +// Preprocessed: +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { i := .loopvar_i<*VPBlock(1,0)> + (const (1 int)); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } + +// Output: +// s1[0] is: 1 +// s1[1] is: 2 +// s1[2] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop3.gno b/gnovm/tests/files/heap_alloc_forloop3.gno index 58a5054e747..149adb5a0df 100644 --- a/gnovm/tests/files/heap_alloc_forloop3.gno +++ b/gnovm/tests/files/heap_alloc_forloop3.gno @@ -25,7 +25,7 @@ func main() { // You can tell by the preprocess printout of z and z<()~...>. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { z := .loopvar_i<*VPBlock(1,0)>; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/redefine7i.gno b/gnovm/tests/files/redefine7i.gno new file mode 100644 index 00000000000..ad054a80acb --- /dev/null +++ b/gnovm/tests/files/redefine7i.gno @@ -0,0 +1,20 @@ +package main + +var ps []*int + +func main() { + for i := 0; i < 3; i++ { + ps = append(ps, &i) + } + for _, v := range ps{ + println(*v) + } +} + +// Preprocessed: +// file{ package main; var ps []*((const-type int)); func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; ps<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(ps<~VPBlock(4,0)>, &(.redefine_i<~VPBlock(1,1)>)) }; for _, v := range ps<~VPBlock(4,0)> { (const (println func(...interface {})))(*(v)) } } } + +// Output: +// 0 +// 1 +// 2 From 2eee635735c89ab7e5bff70ccc044f8ee25e7c8a Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Tue, 16 Dec 2025 19:07:56 +0800 Subject: [PATCH 7/7] test pass --- gnovm/pkg/gnolang/machine.go | 2 - gnovm/pkg/gnolang/nodes.go | 10 +- gnovm/pkg/gnolang/op_assign.go | 5 - gnovm/pkg/gnolang/op_call.go | 3 - gnovm/pkg/gnolang/op_exec.go | 2 +- gnovm/pkg/gnolang/preprocess.go | 240 +++++++++--------- gnovm/pkg/gnolang/values.go | 1 - gnovm/tests/files/heap_alloc_forloop1c.gno | 2 +- gnovm/tests/files/heap_alloc_forloop2a.gno | 2 +- gnovm/tests/files/heap_alloc_forloop3a.gno | 2 +- gnovm/tests/files/heap_alloc_forloop4.gno | 8 +- gnovm/tests/files/heap_alloc_forloop5.gno | 8 +- gnovm/tests/files/heap_alloc_forloop5a.gno | 2 +- gnovm/tests/files/heap_alloc_forloop6.gno | 2 +- gnovm/tests/files/heap_alloc_forloop6a.gno | 12 +- gnovm/tests/files/heap_alloc_forloop6b.gno | 2 +- gnovm/tests/files/heap_alloc_forloop6c.gno | 6 +- gnovm/tests/files/heap_alloc_forloop6f.gno | 2 +- gnovm/tests/files/heap_alloc_forloop6g.gno | 2 +- gnovm/tests/files/heap_alloc_forloop6h.gno | 3 +- gnovm/tests/files/heap_alloc_forloop6h0.gno | 10 +- gnovm/tests/files/heap_alloc_forloop6i.gno | 3 +- gnovm/tests/files/heap_alloc_forloop7.gno | 2 +- gnovm/tests/files/heap_alloc_forloop7a.gno | 2 +- gnovm/tests/files/heap_alloc_forloop8.gno | 2 +- gnovm/tests/files/heap_alloc_forloop8a.gno | 2 +- gnovm/tests/files/heap_alloc_forloop8b.gno | 2 +- gnovm/tests/files/heap_alloc_forloop8c.gno | 2 +- gnovm/tests/files/heap_alloc_forloop9.gno | 14 +- gnovm/tests/files/heap_alloc_forloop9_1.gno | 2 +- gnovm/tests/files/heap_alloc_forloop9_2.gno | 2 +- gnovm/tests/files/heap_alloc_forloop9b.gno | 2 +- gnovm/tests/files/heap_alloc_gotoloop9_22.gno | 4 +- gnovm/tests/files/redefine7a.gno | 1 - gnovm/tests/files/redefine7d2.gno | 26 ++ gnovm/tests/files/redefine8.gno | 8 +- gnovm/tests/files/redefine9b.gno | 13 + gnovm/tests/files/redefine9c.gno | 31 +++ 38 files changed, 245 insertions(+), 199 deletions(-) create mode 100644 gnovm/tests/files/redefine7d2.gno create mode 100644 gnovm/tests/files/redefine9b.gno create mode 100644 gnovm/tests/files/redefine9c.gno diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 8b22789f73f..400f7571bf5 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2247,7 +2247,6 @@ func (m *Machine) IsReadonly(tv *TypedValue) bool { // and the lx isn't a name (base is a block), // and the lx isn't a composite lit expr. func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { - fmt.Println("---PopAsPointer2, lx: ", lx) switch lx := lx.(type) { case *NameExpr: switch lx.Type { @@ -2261,7 +2260,6 @@ func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { ro = false // always mutable case NameExprTypeLoopVarUse: lb := m.LastBlock() - fmt.Println("------lb: ", lb) pv = lb.GetPointerTo(m.Store, lx.Path) ro = false // always mutable case NameExprTypeHeapUse: diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 08ac860f736..29ded27dd59 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -1952,7 +1952,7 @@ func (sb *StaticBlock) GetLocalIndex(n Name) (uint16, bool) { } func (sb *StaticBlock) FindNameMaybeLoopvar(store Store, n Name) (loopvar, found bool) { - fmt.Println("FindNameSkipPredefined, n: ", n) + // fmt.Println("FindNameSkipPredefined, n: ", n) if n == blankIdentifier { return false, false } @@ -1961,7 +1961,7 @@ func (sb *StaticBlock) FindNameMaybeLoopvar(store Store, n Name) (loopvar, found // also search with .loopvar_, this make sure `i` also // get a correct path. if _, loopvar, found = sb.GetLocalIndexMaybeLoopvar(n); found { - fmt.Println("===loopVar: ", loopvar) + // fmt.Println("===loopVar: ", loopvar) // found a NameExpr with type NameExprTypeLoopVarDefine return } @@ -2047,13 +2047,13 @@ func processLoopVar(last BlockNode, nx *NameExpr) { // handle loopvar stuff loopvar, found := last.FindNameMaybeLoopvar(nil, nx.Name) if found && loopvar { - fmt.Println("---found loopvar use, nx: ", nx) + // fmt.Println("---found loopvar use, nx: ", nx) nx.Type = NameExprTypeLoopVarUse // XXX, necessary? nx.Name = Name(fmt.Sprintf(".loopvar_%s", nx.Name)) - fmt.Println("===after rename, nx: ", nx) + // fmt.Println("===after rename, nx: ", nx) } else { - fmt.Println("Not loopvar, nx: ", nx, nx.Type) + // fmt.Println("Not loopvar, nx: ", nx, nx.Type) } } } diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index 438bdd889b5..b4291515f82 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -1,10 +1,7 @@ package gnolang -import "fmt" - func (m *Machine) doOpDefine() { s := m.PopStmt().(*AssignStmt) - fmt.Println("---doOpDefine, s: ", s) // Define each value evaluated for Lhs. // NOTE: PopValues() returns a slice in // forward order, not the usual reverse. @@ -13,8 +10,6 @@ func (m *Machine) doOpDefine() { for i := range s.Lhs { // Get name and value of i'th term. nx := s.Lhs[i].(*NameExpr) - fmt.Println("---nx: ", nx) - fmt.Println("---rvs[i]: ", rvs[i]) // Finally, define (or assign if loop block). ptr := lb.GetPointerToMaybeHeapDefine(m.Store, nx) if m.Stage != StagePre && isUntyped(rvs[i].T) && rvs[i].T.Kind() != BoolKind { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 835c1b29d75..161f4845925 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -145,9 +145,6 @@ func (m *Machine) doOpCall() { pb := fr.Func.GetParent(m.Store) b := m.Alloc.NewBlock(fs, pb) - fmt.Println("======doOpCall, fv: ", fv) - fmt.Println("======doOpCall, fv.Captures: ", fv.Captures) - // Copy *FuncValue.Captures into block // NOTE: addHeapCapture in preprocess ensures order. if len(fv.Captures) != 0 { diff --git a/gnovm/pkg/gnolang/op_exec.go b/gnovm/pkg/gnolang/op_exec.go index f91349d0704..31e2020a967 100644 --- a/gnovm/pkg/gnolang/op_exec.go +++ b/gnovm/pkg/gnolang/op_exec.go @@ -434,7 +434,7 @@ EXEC_SWITCH: if debug { debug.Printf("EXEC: %v\n", s) } - fmt.Printf("==========================EXEC: %v\n", s) + // fmt.Printf("==========================EXEC: %v\n", s) switch cs := s.(type) { case *AssignStmt: diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ccd7696f7d9..6e3d28410c0 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -26,6 +26,10 @@ const ( // This function must be called on *FileSets because declarations // in file sets may be unordered. func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { + // fmt.Println("---Start PredefineFileSet...") + // defer func() { + // fmt.Println("---Finish PredefineFileSet...") + // }() // First, initialize all file nodes and connect to package node. // This will also reserve names on BlockNode.StaticBlock by // calling StaticBlock.Reserve(). @@ -186,7 +190,7 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { case TRANS_ENTER: switch n := n.(type) { case *AssignStmt: - fmt.Println("---initStaticBlocks, assignStmt: ", n) + // fmt.Println("---initStaticBlocks, assignStmt: ", n) if n.Op == DEFINE { for i, lx := range n.Lhs { nx := lx.(*NameExpr) @@ -195,11 +199,11 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { continue } if !isLocallyDefined2(last, ln) { - fmt.Println("---not locally defined, Reserve it, ln: ", ln) + // fmt.Println("---not locally defined, Reserve it, ln: ", ln) if ftype == TRANS_FOR_INIT { ln = Name(fmt.Sprintf(".loopvar_%s", ln)) nx.Type = NameExprTypeLoopVarDefine // demote if shadowed by i := i - fmt.Println("---ln: ", ln) + // fmt.Println("---ln: ", ln) nx.Name = ln // rename // nx0 := Nx(".redefine_i") @@ -214,7 +218,7 @@ func initStaticBlocks(store Store, ctx BlockNode, nn Node) { last.Reserve(false, nx, n, NSDefine, i) } } else { - fmt.Println("---locally defined, Ignore it, ln: ", ln) + // fmt.Println("---locally defined, Ignore it, ln: ", ln) } } } @@ -477,6 +481,8 @@ var preprocessing atomic.Int32 // - Assigns BlockValuePath to NameExprs. // - TODO document what it does. func Preprocess(store Store, ctx BlockNode, n Node) Node { + // fmt.Println("---Preprocess, n: ", n, reflect.TypeOf(n)) + // PrintCaller(2, 5) // First init static blocks of blocknodes. // This may have already happened. // Keep this function idemponent. @@ -498,6 +504,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // Bulk of the preprocessor function n = preprocess1(store, ctx, n) + // fmt.Println("---After prerocess1: ", n, reflect.TypeOf(n)) // XXX check node lines and locations checkNodeLinesLocations("XXXpkgPath", "XXXfileName", n) @@ -525,39 +532,59 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { }) } - transform := func() { - var found bool + transformLoopvar := func(n Node) (found bool) { + // fmt.Println("---transformLoopvar, n: ", n, reflect.TypeOf(n)) Transcribe(n, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { - if stage != TRANS_ENTER { + if stage != TRANS_LEAVE { return n, TRANS_CONTINUE } - if _, ok := n.(*FuncLitExpr); ok { - if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { - return n, TRANS_SKIP - } - } + // fmt.Println("---!!!Trans_Enter, n: ", n) + // if _, ok := n.(*FuncLitExpr); ok { + // if n.GetAttribute(ATTR_PREPROCESS_SKIPPED) == AttrPreprocessFuncLitExpr { + // return n, TRANS_SKIP + // } + // } + // fmt.Println("---Trans_Leave bn: ", n) if bn, ok := n.(BlockNode); ok { - found = findHeapDefinedLoopvarByUse(ctx, bn) - return n, TRANS_SKIP + // fmt.Println("---TransLoopvar, bn: ", bn) + if _, ok := bn.(*ForStmt); ok { + found2 := findHeapDefinedLoopvarByUse(ctx, bn) + if found2 { + found = true + } + } + return n, TRANS_CONTINUE + } else { + // fmt.Println("---Not BlockNode, do nothing...") } return n, TRANS_CONTINUE }) + return + } + + transform := func(n Node) { + found := transformLoopvar(n) if found { + // fmt.Println("---Found loopvar ...") + // fmt.Println("---Current n: ", n) // restore ATTR_PREPROCESSED attribute RestoreNode(ctx, n) // re-preprocess1 n = preprocess1(store, ctx, n) + // fmt.Println("---after preprocess1...") } transformHeapItem(n) } - transform() + // do transform + transform(n) return n } func preprocess1(store Store, ctx BlockNode, n Node) Node { + // fmt.Println("---Start preprocess1, n: ", n, reflect.TypeOf(n)) // Increment preprocessing counter while preprocessing. preprocessing.Add(1) defer preprocessing.Add(-1) @@ -593,7 +620,6 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { switch n := n.(type) { // TRANS_ENTER ----------------------- case *AssignStmt: - fmt.Println("---Trans_Enter assignStmt, n: ", n) checkValDefineMismatch(n) if n.Op == DEFINE { @@ -1075,11 +1101,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { switch n := n.(type) { // TRANS_LEAVE ----------------------- case *NameExpr: - fmt.Println("---Trans_Leave NameExpr: ", n) - if len(ns) > 0 { - fmt.Println("---last node: ", ns[len(ns)-1]) - } - // fmt.Println("---Trans_Leave NameExpr, last: ", last) + // fmt.Println("---Trans_Leave NameExpr: ", n) if isBlankIdentifier(n) { switch ftype { case TRANS_ASSIGN_LHS, TRANS_RANGE_KEY, TRANS_RANGE_VALUE, TRANS_VAR_NAME: @@ -1159,18 +1181,18 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { default: switch ftype { case TRANS_ASSIGN_LHS: - fmt.Println("---Trans_Assign_LHS") + // fmt.Println("---Trans_Assign_LHS") as := ns[len(ns)-1].(*AssignStmt) // for i := n; i > 0; i >>= 1 { processLoopVar(last, n) fillNameExprPath(last, n, as.Op == DEFINE) return n, TRANS_CONTINUE case TRANS_VAR_NAME: - fmt.Println("---Trans_Var_Name") + // fmt.Println("---Trans_Var_Name") fillNameExprPath(last, n, true) return n, TRANS_CONTINUE default: - fmt.Println("---default..., use...") + // fmt.Println("---default..., use...") // find LoopVarUse, and rename, // happens before fill path @@ -2270,7 +2292,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *AssignStmt: - fmt.Println("---Trans_Leave, assignStmt: ", n) + // fmt.Println("---Trans_Leave, assignStmt: ", n) n.AssertCompatible(store, last) if n.Op == ASSIGN { for _, lh := range n.Lhs { @@ -2618,6 +2640,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *TypeDecl: + // fmt.Println("---Trans_Leave, TypeDecl, n: ", n) if n.Name == blankIdentifier { n.Path = NewValuePathBlock(0, 0, blankIdentifier) return n, TRANS_CONTINUE @@ -3084,7 +3107,7 @@ func RestoreNode(ctx BlockNode, n Node) { defer doRecover(stack, n) if debug { - debug.Printf("resetPreprocess %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + debug.Printf("RestoreNode %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) } switch stage { @@ -3093,7 +3116,13 @@ func RestoreNode(ctx BlockNode, n Node) { // ---------------------------------------- case TRANS_LEAVE: - n.SetAttribute(ATTR_PREPROCESSED, false) + switch n.(type) { + case *TypeDecl: + // no re-preprocess as it's reusing PredefineFileSet result. + // otherwise will be wiped. + default: + n.SetAttribute(ATTR_PREPROCESSED, false) + } return n, TRANS_CONTINUE } return n, TRANS_CONTINUE @@ -3123,16 +3152,38 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { // ---------------------------------------- case TRANS_LEAVE: - + // fmt.Println("------Trans_Leave, n: ", n, reflect.TypeOf(n)) switch n := n.(type) { case *RefExpr: lmx := LeftmostX(n.X) if nx, ok := lmx.(*NameExpr); ok { + if nx.Path.Type != VPBlock { + return n, TRANS_CONTINUE + } + // Ignore blank identifers + if nx.Name == blankIdentifier { + return n, TRANS_CONTINUE + } + // Ignore package names + if nx.GetAttribute(ATTR_PACKAGE_REF) != nil { + return n, TRANS_CONTINUE + } + // Ignore decls names. + if ftype == TRANS_VAR_NAME { + return n, TRANS_CONTINUE + } + // Ignore := defines, etc. + if nx.Type != NameExprTypeLoopVarUse { + return n, TRANS_CONTINUE + } if !strings.HasPrefix(string(nx.Name), ".loopvar") { return n, TRANS_CONTINUE } // Find the block where name is defined dbn := last.GetBlockNodeForPath(nil, nx.Path) + if _, ok := dbn.(*ForStmt); !ok { + return n, TRANS_CONTINUE + } // The leftmost name of possibly nested index // and selector exprs. // e.g. leftmost.middle[0][2].rightmost @@ -3147,7 +3198,7 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { } } - // if ftype != TRANS_FOR_INIT && ftype != TRANS_FOR_COND && ftype != TRANS_FOR_POST { + // fmt.Println("---Loopvar by RefExpr, nx: ", nx) if _, ok := dbn.(*ForStmt); ok { // true if found once stop = true @@ -3164,32 +3215,8 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { nx.Name = Name(redefineName) } } - case *ForStmt: - fmt.Println("------forStmt: ", n) - if n2, ok := n.GetAttribute(ATTR_REDEFINE_NAME).(string); ok && n2 != "" { - fmt.Println("------forStmt re-written...") - stmts := n.GetBody() - - lhs := Nx(n2) - rhs := Nx(".loopvar_i") - as := A(lhs, ":=", rhs) - stmts2 := make([]Stmt, 0, len(stmts)+1) - stmts2 = append(stmts2, as) - stmts2 = append(stmts2, stmts...) - - // Index for new injected name - index := len(n.GetBlockNames()) - // Set Heap type - lhs.Type = NameExprTypeHeapDefine - // Reserve for new injected name - n.Reserve(false, lhs, n, NSDefine, index+1) - n.SetBody(stmts2) - - fmt.Println("---after process, n: ", n) - n.DelAttribute(ATTR_REDEFINE_NAME) - } case *NameExpr: - fmt.Println("---findHeapDefinedLoopvarByUse, n.Name: ", n.Name) + // fmt.Println("---findHeapDefinedLoopvarByUse, n.Name: ", n.Name) // NOTE: Keep in sync maybe with transpile_gno0p0.go/FindMore... // Ignore non-block type paths if n.Path.Type != VPBlock { @@ -3220,11 +3247,13 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { for { // If used as closure capture, mark as heap use. flx, _, found := findFirstClosure(stack, dbn) - fmt.Println("---found closure, flx: ", flx) if !found { return n, TRANS_CONTINUE } + // fmt.Println("---Loopvar by closure, n: ", n) + // fmt.Println("---Loopvar by closure, flx: ", flx) + // fmt.Println("---dbn: ", dbn) if _, ok := dbn.(*ForStmt); ok { // true if found once stop = true @@ -3244,6 +3273,32 @@ func findHeapDefinedLoopvarByUse(ctx BlockNode, bn BlockNode) (stop bool) { // Loop again for more closures. dbn = flx } + case *ForStmt: + // fmt.Println("------Trans_Leave, forStmt: ", n) + if n2, ok := n.GetAttribute(ATTR_REDEFINE_NAME).(string); ok && n2 != "" { + // fmt.Println("------forStmt re-written...") + stmts := n.GetBody() + + origName := strings.TrimPrefix(string(n2), ".redefine_") + + lhs := Nx(n2) + rhs := Nx(fmt.Sprintf("%s%s", ".loopvar_", origName)) + as := A(lhs, ":=", rhs) + stmts2 := make([]Stmt, 0, len(stmts)+1) + stmts2 = append(stmts2, as) + stmts2 = append(stmts2, stmts...) + + // Index for new injected name + index := len(n.GetBlockNames()) + // Set Heap type + lhs.Type = NameExprTypeHeapDefine + // Reserve for new injected name + n.Reserve(false, lhs, n, NSDefine, index+1) + n.SetBody(stmts2) + + // fmt.Println("------after process, n: ", n) + n.DelAttribute(ATTR_REDEFINE_NAME) + } } return n, TRANS_CONTINUE } @@ -3365,7 +3420,6 @@ func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { idx := addHeapCapture(dbn, flx, depth, n) // adjust NameExpr type. n.Type = NameExprTypeHeapUse - // XXX, handle loopvar heapuse case n.Path.SetDepth(uint8(depth)) n.Path.Index = idx // Loop again for more closures. @@ -3509,72 +3563,6 @@ func findLastFunction(last BlockNode, stop BlockNode) (fn FuncNode, depth int, f return } -// If a heap use name is in form of ".loopvar_x", -// means there's no i := i like redefinition... -func findHeapUsesLoopvar(ctx BlockNode, bn BlockNode) { - // create stack of BlockNodes. - last := ctx - stack := append(make([]BlockNode, 0, 32), last) - - // Iterate over all nodes recursively. - _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { - defer doRecover(stack, n) - - if debug { - debug.Printf("findHeapUsesLoopvar %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) - } - - switch stage { - // ---------------------------------------- - case TRANS_BLOCK: - pushInitBlock(n.(BlockNode), &last, &stack) - - // ---------------------------------------- - case TRANS_ENTER: - switch n := n.(type) { - case *NameExpr: - // Ignore non-block type paths - if n.Path.Type != VPBlock { - return n, TRANS_CONTINUE - } - switch n.Type { - case NameExprTypeHeapUse: - fmt.Println("---findHeapUsesLoopvar, n.Name: ", n.Name) - loopvar, found := last.FindNameMaybeLoopvar(nil, n.Name) - fmt.Printf("---findHeapUsesLoopvar, loopvar: %t, found: %t \n", loopvar, found) - - // // Find the block where name is defined - // dbn := last.GetBlockNodeForPath(nil, n.Path) - // // If the name is heap used, - // if hasAttrHeapUse(dbn, n.Name) { - // // Change type to heap use. - // n.Type = NameExprTypeHeapUse - // } - } - return n, TRANS_CONTINUE - } - - // ---------------------------------------- - case TRANS_LEAVE: - - // Defer pop block from stack. - // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK - // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR - // POP BLOCK YOURSELF. - defer func() { - switch n.(type) { - case BlockNode: - stack = stack[:len(stack)-1] - last = stack[len(stack)-1] - } - }() - - return n, TRANS_CONTINUE - } - return n, TRANS_CONTINUE - }) -} - // If a name is used as a heap item, Convert all other uses of such names // for heap use. If a name of type heap define is not actually used // as heap use, demotes them. @@ -5392,10 +5380,10 @@ func fauxChildBlockNode(bn BlockNode) bool { } func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { - fmt.Println("---fillNameExprPath, nx: ", nx) - defer func() { - fmt.Println("---path filled: ", nx.Path) - }() + // fmt.Println("---fillNameExprPath, nx: ", nx) + // defer func() { + // fmt.Println("---path filled: ", nx.Path) + // }() if nx.Name == blankIdentifier { // Blank name has no path; caller error. diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 68c05daa7aa..57da1d19a06 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -2465,7 +2465,6 @@ func (b *Block) GetPointerToDirect(store Store, path ValuePath) PointerValue { // First defines a new HeapItemValue if heap slot. func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerValue { - PrintCaller(2, 5) switch nx.Type { case NameExprTypeNormal: // XXX convert rangestmt switchstmt names diff --git a/gnovm/tests/files/heap_alloc_forloop1c.gno b/gnovm/tests/files/heap_alloc_forloop1c.gno index 01f35b7ba93..d565d8099d4 100644 --- a/gnovm/tests/files/heap_alloc_forloop1c.gno +++ b/gnovm/tests/files/heap_alloc_forloop1c.gno @@ -26,7 +26,7 @@ func main() { } // Preprocessed: -// file{ package main; type Int (const-type main.Int); var s1 []*(typeval{main.Int}); func inc2(j *(typeval{main.Int})) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (println func(...interface {})))((const ("i, e: " string)), i, *(e)) } }(); for .loopvar_i := (const (0 main.Int)); .loopvar_i<*VPBlock(1,0)> < (const (10 main.Int)); inc2(&(.loopvar_i<~VPBlock(1,0)>)) { .redefine_i := .loopvar_i<~VPBlock(1,0)>; i := .loopvar_i<*VPBlock(1,0)>; s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(.redefine_i<~VPBlock(1,2)>)) } }; func main() { forLoopRef() } } +// file{ package main; type Int (const-type main.Int); var s1 []*(typeval{main.Int}); func inc2(j *(typeval{main.Int})) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (println func(...interface {})))((const ("i, e: " string)), i, *(e)) } }(); for .loopvar_i := (const (0 main.Int)); .loopvar_i<*VPBlock(1,0)> < (const (10 main.Int)); inc2(&(.loopvar_i<~VPBlock(1,0)>)) { i := .loopvar_i<*VPBlock(1,0)>; s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(i<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } // Output: // i, e: 0 (0 main.Int) diff --git a/gnovm/tests/files/heap_alloc_forloop2a.gno b/gnovm/tests/files/heap_alloc_forloop2a.gno index aa3494f3421..a72acb4a0af 100644 --- a/gnovm/tests/files/heap_alloc_forloop2a.gno +++ b/gnovm/tests/files/heap_alloc_forloop2a.gno @@ -26,7 +26,7 @@ func main() { // You can tell by the preprocess printout of z and z<~...>. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)); z<~VPBlock(1,1)>++ } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { z := .loopvar_i<*VPBlock(1,0)>; s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)); z<~VPBlock(1,1)>++ } }; func main() { forLoopRef() } } // Output: // s1[0] is: 1 diff --git a/gnovm/tests/files/heap_alloc_forloop3a.gno b/gnovm/tests/files/heap_alloc_forloop3a.gno index ee7f17407fd..073715b54fc 100644 --- a/gnovm/tests/files/heap_alloc_forloop3a.gno +++ b/gnovm/tests/files/heap_alloc_forloop3a.gno @@ -27,7 +27,7 @@ func main() { // You can tell by the preprocess printout of z and z<()~...>. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; (const (println func(...interface {})))(x); z := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; (const (println func(...interface {})))(x); z := .loopvar_i<*VPBlock(1,0)>; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop4.gno b/gnovm/tests/files/heap_alloc_forloop4.gno index 75a23244b38..992579268c0 100644 --- a/gnovm/tests/files/heap_alloc_forloop4.gno +++ b/gnovm/tests/files/heap_alloc_forloop4.gno @@ -23,9 +23,9 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(.redefine_i<~VPBlock(1,0)>) }<.redefine_i<()~VPBlock(1,1)>>)) } }; func main() { forLoopClosure() } } // Output: -// 3 -// 3 -// 3 +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop5.gno b/gnovm/tests/files/heap_alloc_forloop5.gno index 772e9ced90e..2aeb696b7bd 100644 --- a/gnovm/tests/files/heap_alloc_forloop5.gno +++ b/gnovm/tests/files/heap_alloc_forloop5.gno @@ -24,9 +24,9 @@ func main() { } // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := i<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := .redefine_i<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }<.redefine_i<()~VPBlock(1,1)>>)) } }; func main() { forLoopClosure() } } // Output: -// 3 -// 3 -// 3 +// 0 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop5a.gno b/gnovm/tests/files/heap_alloc_forloop5a.gno index db3178e8d3d..571bcd83910 100644 --- a/gnovm/tests/files/heap_alloc_forloop5a.gno +++ b/gnovm/tests/files/heap_alloc_forloop5a.gno @@ -25,7 +25,7 @@ func main() { } // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := x<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []typeval{main.f}; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := x<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6.gno b/gnovm/tests/files/heap_alloc_forloop6.gno index bea81c89924..b03723f8ef7 100644 --- a/gnovm/tests/files/heap_alloc_forloop6.gno +++ b/gnovm/tests/files/heap_alloc_forloop6.gno @@ -17,7 +17,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; f := func func() .res.0 (const-type int){ return z<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { z := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ return z<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6a.gno b/gnovm/tests/files/heap_alloc_forloop6a.gno index ec24f562ed6..dae5c803f8d 100644 --- a/gnovm/tests/files/heap_alloc_forloop6a.gno +++ b/gnovm/tests/files/heap_alloc_forloop6a.gno @@ -16,11 +16,11 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (5 int)); i<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (5 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; f := func func() .res.0 (const-type int){ return .redefine_i<~VPBlock(1,1)> }<.redefine_i<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: -// 5 -// 5 -// 5 -// 5 -// 5 +// 0 +// 1 +// 2 +// 3 +// 4 diff --git a/gnovm/tests/files/heap_alloc_forloop6b.gno b/gnovm/tests/files/heap_alloc_forloop6b.gno index 6b884d661f1..1bf2616f747 100644 --- a/gnovm/tests/files/heap_alloc_forloop6b.gno +++ b/gnovm/tests/files/heap_alloc_forloop6b.gno @@ -18,7 +18,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (0 int)); f := func func() .res.0 (const-type int){ x<~VPBlock(1,1)> += y<~VPBlock(1,2)>; x<~VPBlock(1,1)> += (const (1 int)); return x<~VPBlock(1,1)> }, y<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; y := (const (0 int)); f := func func() .res.0 (const-type int){ x<~VPBlock(1,1)> += y<~VPBlock(1,2)>; x<~VPBlock(1,1)> += (const (1 int)); return x<~VPBlock(1,1)> }, y<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop6c.gno b/gnovm/tests/files/heap_alloc_forloop6c.gno index 752c7e6b4fe..33f77d15331 100644 --- a/gnovm/tests/files/heap_alloc_forloop6c.gno +++ b/gnovm/tests/files/heap_alloc_forloop6c.gno @@ -16,8 +16,8 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; f := func func() .res.0 (const-type int){ return .redefine_i<~VPBlock(1,1)> }<.redefine_i<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: -// 2 -// 2 +// 0 +// 1 diff --git a/gnovm/tests/files/heap_alloc_forloop6f.gno b/gnovm/tests/files/heap_alloc_forloop6f.gno index 7c568884071..19bbcbdc451 100644 --- a/gnovm/tests/files/heap_alloc_forloop6f.gno +++ b/gnovm/tests/files/heap_alloc_forloop6f.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { var x (const-type int); f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; x<~VPBlock(1,1)> = i; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (5 int)); .loopvar_i<*VPBlock(1,0)>++ { var x (const-type int); f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; x<~VPBlock(1,1)> = .loopvar_i<*VPBlock(1,0)>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6g.gno b/gnovm/tests/files/heap_alloc_forloop6g.gno index c81d33ab60b..87ac1ad6753 100644 --- a/gnovm/tests/files/heap_alloc_forloop6g.gno +++ b/gnovm/tests/files/heap_alloc_forloop6g.gno @@ -17,7 +17,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { x := i; { f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (5 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; { f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6h.gno b/gnovm/tests/files/heap_alloc_forloop6h.gno index 88a2de9baad..053b8c9eb38 100644 --- a/gnovm/tests/files/heap_alloc_forloop6h.gno +++ b/gnovm/tests/files/heap_alloc_forloop6h.gno @@ -18,7 +18,8 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; for .loopvar_j := (const (0 int)); .loopvar_j<*VPBlock(1,0)> < (const (2 int)); .loopvar_j<*VPBlock(1,0)>++ { y := .loopvar_j<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } + // Go Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6h0.gno b/gnovm/tests/files/heap_alloc_forloop6h0.gno index 52ad504bd1c..35dda2b038d 100644 --- a/gnovm/tests/files/heap_alloc_forloop6h0.gno +++ b/gnovm/tests/files/heap_alloc_forloop6h0.gno @@ -18,10 +18,10 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { for j := (const (0 int)); j<~VPBlock(1,0)> < (const (2 int)); j<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> + j<~VPBlock(1,2)> }, j<()~VPBlock(1,0)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; for .loopvar_j := (const (0 int)); .loopvar_j<*VPBlock(1,0)> < (const (2 int)); .loopvar_j<*VPBlock(1,0)>++ { .redefine_j := .loopvar_j; f := func func() .res.0 (const-type int){ return .redefine_i<~VPBlock(1,1)> + .redefine_j<~VPBlock(1,2)> }<.redefine_i<()~VPBlock(2,1)>, .redefine_j<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: -// 4 -// 4 -// 4 -// 4 +// 0 +// 1 +// 1 +// 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6i.gno b/gnovm/tests/files/heap_alloc_forloop6i.gno index a71ab9fd777..4373fde980d 100644 --- a/gnovm/tests/files/heap_alloc_forloop6i.gno +++ b/gnovm/tests/files/heap_alloc_forloop6i.gno @@ -19,7 +19,8 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); var x (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x<~VPBlock(2,1)> = i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); var x (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x<~VPBlock(2,1)> = .loopvar_i<*VPBlock(1,0)>; for .loopvar_j := (const (0 int)); .loopvar_j<*VPBlock(1,0)> < (const (2 int)); .loopvar_j<*VPBlock(1,0)>++ { y := .loopvar_j<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } + // Go Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop7.gno b/gnovm/tests/files/heap_alloc_forloop7.gno index fc15ad0f3a1..ae81b675097 100644 --- a/gnovm/tests/files/heap_alloc_forloop7.gno +++ b/gnovm/tests/files/heap_alloc_forloop7.gno @@ -21,7 +21,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ if (const (true bool)) { if (const (true bool)) { return x<~VPBlock(3,1)> } }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ if (const (true bool)) { if (const (true bool)) { return x<~VPBlock(3,1)> } }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop7a.gno b/gnovm/tests/files/heap_alloc_forloop7a.gno index 0fdf062a59e..9af85f58fdb 100644 --- a/gnovm/tests/files/heap_alloc_forloop7a.gno +++ b/gnovm/tests/files/heap_alloc_forloop7a.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop8.gno b/gnovm/tests/files/heap_alloc_forloop8.gno index c0baf557515..9fbe5e8103c 100644 --- a/gnovm/tests/files/heap_alloc_forloop8.gno +++ b/gnovm/tests/files/heap_alloc_forloop8.gno @@ -18,7 +18,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ { return x<~VPBlock(2,1)> } }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ { return x<~VPBlock(2,1)> } }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop8a.gno b/gnovm/tests/files/heap_alloc_forloop8a.gno index eb58838b460..0c0aec39bac 100644 --- a/gnovm/tests/files/heap_alloc_forloop8a.gno +++ b/gnovm/tests/files/heap_alloc_forloop8a.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ for i := (const (0 int)); i < (const (1 int)); i++ { x<~VPBlock(2,1)>++ }; return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (1 int)); .loopvar_i<*VPBlock(1,0)>++ { x<~VPBlock(2,1)>++ }; return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop8b.gno b/gnovm/tests/files/heap_alloc_forloop8b.gno index 7a34bbffd58..f0614092e8d 100644 --- a/gnovm/tests/files/heap_alloc_forloop8b.gno +++ b/gnovm/tests/files/heap_alloc_forloop8b.gno @@ -21,7 +21,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; s := (const-type []int){(const (1 int)), (const (2 int))}; f := func func() .res.0 (const-type int){ for _, v := range s<~VPBlock(2,1)> { x<~VPBlock(2,2)> += v }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; s := (const-type []int){(const (1 int)), (const (2 int))}; f := func func() .res.0 (const-type int){ for _, v := range s<~VPBlock(2,1)> { x<~VPBlock(2,2)> += v }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 3 diff --git a/gnovm/tests/files/heap_alloc_forloop8c.gno b/gnovm/tests/files/heap_alloc_forloop8c.gno index f422f6ae72f..8e9d97bfd90 100644 --- a/gnovm/tests/files/heap_alloc_forloop8c.gno +++ b/gnovm/tests/files/heap_alloc_forloop8c.gno @@ -23,7 +23,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (1 int)); f := func func() .res.0 (const-type int){ switch y<~VPBlock(2,1)> { case (const (1 int)): x<~VPBlock(2,2)> += (const (1 int)); default: x<~VPBlock(2,2)> += (const (0 int)) }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { x := .loopvar_i<*VPBlock(1,0)>; y := (const (1 int)); f := func func() .res.0 (const-type int){ switch y<~VPBlock(2,1)> { case (const (1 int)): x<~VPBlock(2,2)> += (const (1 int)); default: x<~VPBlock(2,2)> += (const (0 int)) }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop9.gno b/gnovm/tests/files/heap_alloc_forloop9.gno index cf93649ee30..c496a938ee5 100644 --- a/gnovm/tests/files/heap_alloc_forloop9.gno +++ b/gnovm/tests/files/heap_alloc_forloop9.gno @@ -28,15 +28,15 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; func main() { var fns []func(.arg_0 (const-type int)) .res.0 (const-type int); var recursiveFunc func(.arg_0 (const-type int)) .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { recursiveFunc<~VPBlock(2,1)> = func func(num (const-type int)) .res.0 (const-type int){ x := i<~VPBlock(1,3)>; (const (println func(...interface {})))((const ("value of x: " string)), x); if num <= (const (0 int)) { return (const (1 int)) }; return num * recursiveFunc<~VPBlock(1,4)>(num - (const (1 int))) }, recursiveFunc<()~VPBlock(2,1)>>; fns = (const (append func([]func(int) int, ...func(int) int) []func(int) int))(fns, recursiveFunc<~VPBlock(2,1)>) }; for i, r := range fns { result := r(i); (const (ref(fmt) package{})).Printf((const ("Factorial of %d is: %d\n" string)), i, result) } } } +// file{ package main; import fmt fmt; func main() { var fns []func(.arg_0 (const-type int)) .res.0 (const-type int); var recursiveFunc func(.arg_0 (const-type int)) .res.0 (const-type int); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; recursiveFunc<~VPBlock(2,1)> = func func(num (const-type int)) .res.0 (const-type int){ x := .redefine_i<~VPBlock(1,3)>; (const (println func(...interface {})))((const ("value of x: " string)), x); if num <= (const (0 int)) { return (const (1 int)) }; return num * recursiveFunc<~VPBlock(1,4)>(num - (const (1 int))) }<.redefine_i<()~VPBlock(1,1)>, recursiveFunc<()~VPBlock(2,1)>>; fns = (const (append func([]func(int) int, ...func(int) int) []func(int) int))(fns, recursiveFunc<~VPBlock(2,1)>) }; for i, r := range fns { result := r(i); (const (ref(fmt) package{})).Printf((const ("Factorial of %d is: %d\n" string)), i, result) } } } // Output: -// value of x: 3 +// value of x: 0 // Factorial of 0 is: 1 -// value of x: 3 -// value of x: 3 +// value of x: 1 +// value of x: 2 // Factorial of 1 is: 1 -// value of x: 3 -// value of x: 3 -// value of x: 3 +// value of x: 2 +// value of x: 2 +// value of x: 2 // Factorial of 2 is: 2 diff --git a/gnovm/tests/files/heap_alloc_forloop9_1.gno b/gnovm/tests/files/heap_alloc_forloop9_1.gno index 7aa58f1ccd0..f27c648a9cc 100644 --- a/gnovm/tests/files/heap_alloc_forloop9_1.gno +++ b/gnovm/tests/files/heap_alloc_forloop9_1.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) .res.0 (const-type bool)) .res.0 (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for x := (const (0 int)); x<~VPBlock(1,0)> < (const (2 int)); x<~VPBlock(1,0)>++ { count := (const (0 int)); (const (println func(...interface {})))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) .res.0 (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= x<~VPBlock(1,3)>) }, x<()~VPBlock(1,0)>>); (const (println func(...interface {})))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } +// file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) .res.0 (const-type bool)) .res.0 (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for .loopvar_x := (const (0 int)); .loopvar_x<*VPBlock(1,0)> < (const (2 int)); .loopvar_x<*VPBlock(1,0)>++ { .redefine_x := .loopvar_x; count := (const (0 int)); (const (println func(...interface {})))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) .res.0 (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= .redefine_x<~VPBlock(1,3)>) }, .redefine_x<()~VPBlock(1,2)>>); (const (println func(...interface {})))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } // Output: // first: count: 0 diff --git a/gnovm/tests/files/heap_alloc_forloop9_2.gno b/gnovm/tests/files/heap_alloc_forloop9_2.gno index cb2e378a7ec..bad033f25ee 100644 --- a/gnovm/tests/files/heap_alloc_forloop9_2.gno +++ b/gnovm/tests/files/heap_alloc_forloop9_2.gno @@ -23,7 +23,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() .res.0 (const-type int); (const (println func(...interface {})))((const ("start for loop" string))); for i := (const (0 int)); i < (const (2 int)); i++ { defer func func(){ (const (println func(...interface {})))((const ("defer" string))); for _, fn := range fns<~VPBlock(2,0)> { (const (println func(...interface {})))(fn()) } }>(); x := i; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns<~VPBlock(2,0)> = (const (append func([]func() int, ...func() int) []func() int))(fns<~VPBlock(2,0)>, f) }; (const (println func(...interface {})))((const ("end for loop" string))) } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); (const (println func(...interface {})))((const ("start for loop" string))); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { defer func func(){ (const (println func(...interface {})))((const ("defer" string))); for _, fn := range fns<~VPBlock(2,0)> { (const (println func(...interface {})))(fn()) } }>(); x := .loopvar_i<*VPBlock(1,0)>; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns<~VPBlock(2,0)> = (const (append func([]func() int, ...func() int) []func() int))(fns<~VPBlock(2,0)>, f) }; (const (println func(...interface {})))((const ("end for loop" string))) } } // Output: // start for loop diff --git a/gnovm/tests/files/heap_alloc_forloop9b.gno b/gnovm/tests/files/heap_alloc_forloop9b.gno index f5d9028a87c..5e08a89e31a 100644 --- a/gnovm/tests/files/heap_alloc_forloop9b.gno +++ b/gnovm/tests/files/heap_alloc_forloop9b.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var y (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for i := (const (0 int)); i < (const (2 int)); i++ { for j := (const (0 int)); j < (const (2 int)); j++ { x := y; f<~VPBlock(3,1)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,1)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++ } } } } +// file{ package main; func main() { var y (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { for .loopvar_j := (const (0 int)); .loopvar_j<*VPBlock(1,0)> < (const (2 int)); .loopvar_j<*VPBlock(1,0)>++ { x := y; f<~VPBlock(3,1)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,1)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++ } } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_22.gno b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno index a25c3b01108..5a673e94ef3 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_22.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno @@ -24,9 +24,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for i := (const (0 int)); i < (const (2 int)); i++ { counter = (const (0 int)); if counter == (const (2 int)) { continue }; x := y; f<~VPBlock(2,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(2,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0,1> } } } - - +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (2 int)); .loopvar_i<*VPBlock(1,0)>++ { counter = (const (0 int)); if counter == (const (2 int)) { continue }; x := y; f<~VPBlock(2,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(2,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0,1> } } } // Output: // 0 diff --git a/gnovm/tests/files/redefine7a.gno b/gnovm/tests/files/redefine7a.gno index cd2ec804779..4cfae7a0805 100644 --- a/gnovm/tests/files/redefine7a.gno +++ b/gnovm/tests/files/redefine7a.gno @@ -2,7 +2,6 @@ package main func main() { for i := 0; i < 3; i++ { - // i := i func() { i += 1 }() diff --git a/gnovm/tests/files/redefine7d2.gno b/gnovm/tests/files/redefine7d2.gno new file mode 100644 index 00000000000..ef4661870f2 --- /dev/null +++ b/gnovm/tests/files/redefine7d2.gno @@ -0,0 +1,26 @@ +package main + +var fns []func() + +func main() { + for i := 0; i < 3; i++ { + f := func() { + i += 1 + println(i) + } + fns = append(fns, f) + // println(i) + } + + for _, ff := range fns{ + ff() + } +} + +// Preprocessed: +// file{ package main; var fns []func(); func main() { for .loopvar_i := (const (0 int)); .loopvar_i<*VPBlock(1,0)> < (const (3 int)); .loopvar_i<*VPBlock(1,0)>++ { .redefine_i := .loopvar_i; f := func func(){ .redefine_i<~VPBlock(1,0)> += (const (1 int)); (const (println func(...interface {})))(.redefine_i<~VPBlock(1,0)>) }<.redefine_i<()~VPBlock(1,2)>>; fns<~VPBlock(4,0)> = (const (append func([]func(), ...func()) []func()))(fns<~VPBlock(4,0)>, f) }; for _, ff := range fns<~VPBlock(4,0)> { ff() } } } + +// Output: +// 1 +// 2 +// 3 diff --git a/gnovm/tests/files/redefine8.gno b/gnovm/tests/files/redefine8.gno index 3c362d06c37..65755df6fa8 100644 --- a/gnovm/tests/files/redefine8.gno +++ b/gnovm/tests/files/redefine8.gno @@ -5,7 +5,7 @@ var s1 []*int func forLoopRef() { defer func() { for i, e := range s1 { - println(i, e) + println(i, *e) } }() @@ -22,6 +22,6 @@ func main() { // go 1.22 loop var is not supported for now. // Output: -// 0 &(3 int) -// 1 &(3 int) -// 2 &(3 int) +// 0 0 +// 1 1 +// 2 2 diff --git a/gnovm/tests/files/redefine9b.gno b/gnovm/tests/files/redefine9b.gno new file mode 100644 index 00000000000..c63bf990ca0 --- /dev/null +++ b/gnovm/tests/files/redefine9b.gno @@ -0,0 +1,13 @@ +package main + +import ( + "gno.land/p/nt/ufmt" +) + +func main() { + println(ufmt.Println("hello ufmt")) +} + +// Output: +// hello ufmt +// 11 undefined diff --git a/gnovm/tests/files/redefine9c.gno b/gnovm/tests/files/redefine9c.gno new file mode 100644 index 00000000000..b3d354350c8 --- /dev/null +++ b/gnovm/tests/files/redefine9c.gno @@ -0,0 +1,31 @@ +package main + +type printer struct { +} + +func newPrinter() *printer { + return &printer{} +} + +func (p *printer) doPrintf() { + for i := 0; i < 3; i++{ + digits := func() string { + start := i + println(start) + return "ok" + } + digits() + // i++ + // println(i) + } +} + +func main() { + p := newPrinter() + p.doPrintf() +} + +// Output: +// 0 +// 1 +// 2