Skip to content

Commit 343403d

Browse files
author
Tural Devrishev
committed
compiler: include lambdas into DebugInfo
Close #3619. Signed-off-by: Tural Devrishev <tural@nspcc.ru>
1 parent 956bd03 commit 343403d

2 files changed

Lines changed: 74 additions & 8 deletions

File tree

pkg/compiler/codegen.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -592,11 +592,12 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
592592
f.rng.End = uint16(c.prog.Len() - 1)
593593

594594
if !isLambda {
595-
for _, f := range c.lambda {
595+
for name, f := range c.lambda {
596596
if _, ok := c.lambda[c.getIdentName("", f.decl.Name.Name)]; !ok {
597597
panic("ICE: lambda name doesn't match map key")
598598
}
599599
c.convertFuncDecl(file, f.decl, pkg)
600+
c.funcs[name] = f
600601
}
601602
c.lambda = make(map[string]*funcScope)
602603
}
@@ -627,10 +628,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
627628
return nil // Program is invalid.
628629
}
629630

630-
if n.Tok == token.VAR || n.Tok == token.CONST {
631-
c.saveSequencePoint(n)
632-
}
633631
if n.Tok == token.CONST {
632+
c.saveSequencePoint(n)
634633
for _, spec := range n.Specs {
635634
vs := spec.(*ast.ValueSpec)
636635
for i := range vs.Names {
@@ -648,6 +647,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
648647
for _, spec := range n.Specs {
649648
switch t := spec.(type) {
650649
case *ast.ValueSpec:
650+
if !containsFuncLit(t.Values...) {
651+
c.saveSequencePoint(t)
652+
}
651653
var isMapKeyCheck bool
652654
// Filter out type assertion with two return values: var i, ok = v.(int)
653655
// and map's index expression: var v, ok = myMap["key"]
@@ -719,7 +721,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
719721
isMapKeyCheck = c.checkGetMapValueWithOKFlag(n.Rhs[0])
720722
}
721723
multiRet := len(n.Rhs) != len(n.Lhs)
722-
c.saveSequencePoint(n)
724+
if !containsFuncLit(n.Rhs...) {
725+
c.saveSequencePoint(n)
726+
}
723727
// Assign operations are grouped https://github.com/golang/go/blob/master/src/go/types/stmt.go#L160
724728
isAssignOp := token.ADD_ASSIGN <= n.Tok && n.Tok <= token.AND_NOT_ASSIGN
725729
if isAssignOp {
@@ -829,7 +833,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
829833

830834
c.processDefers()
831835

832-
c.saveSequencePoint(n)
836+
if !containsFuncLit(n.Results...) {
837+
c.saveSequencePoint(n)
838+
}
833839
if len(c.pkgInfoInline) == 0 {
834840
emit.Opcodes(c.prog.BinWriter, opcode.RET)
835841
} else {
@@ -1096,7 +1102,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
10961102
isLiteral = true
10971103
}
10981104

1099-
c.saveSequencePoint(n)
1105+
if !containsFuncLit(n.Fun) {
1106+
c.saveSequencePoint(n)
1107+
}
11001108

11011109
args := transformArgs(f, n.Fun, isBuiltin, n.Args)
11021110

@@ -2417,7 +2425,7 @@ func (c *codegen) getFuncNameFromSelector(e *ast.SelectorExpr) (string, bool) {
24172425
}
24182426

24192427
func (c *codegen) newLambda(u uint16, lit *ast.FuncLit) {
2420-
name := fmt.Sprintf("lambda@%d", u)
2428+
name := fmt.Sprintf("*lambda@%d", u)
24212429
f := c.newFuncScope(&ast.FuncDecl{
24222430
Name: ast.NewIdent(name),
24232431
Type: lit.Type,
@@ -2763,6 +2771,15 @@ func calcOffsetCorrection(ip, target int, offsets []int) int {
27632771
return cnt
27642772
}
27652773

2774+
func containsFuncLit(exprs ...ast.Expr) bool {
2775+
for _, expr := range exprs {
2776+
if _, ok := expr.(*ast.FuncLit); ok {
2777+
return true
2778+
}
2779+
}
2780+
return false
2781+
}
2782+
27662783
func negateJmp(op opcode.Opcode) opcode.Opcode {
27672784
switch op {
27682785
case opcode.JMPIFL:

pkg/compiler/lambda_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ package compiler_test
22

33
import (
44
"math/big"
5+
"strings"
56
"testing"
7+
8+
"github.com/nspcc-dev/neo-go/pkg/compiler"
9+
"github.com/stretchr/testify/require"
610
)
711

812
func TestFuncLiteral(t *testing.T) {
@@ -26,3 +30,48 @@ func TestCallInPlace(t *testing.T) {
2630
}`
2731
eval(t, src, big.NewInt(111))
2832
}
33+
34+
func TestLambdaInDebugInfo(t *testing.T) {
35+
srcSimple := `package main
36+
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
37+
func PublicContractMethod() {
38+
var f = func() {
39+
runtime.Log("bla")
40+
}
41+
42+
f()
43+
f()
44+
}
45+
`
46+
srcFromArray := `package main
47+
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
48+
func PublicContractMethod() {
49+
arr := make([]func(), 1)
50+
arr[0] = func() { runtime.Log("bla") }
51+
f := arr[0]
52+
f()
53+
}
54+
`
55+
srcFromAnotherFunc := `package main
56+
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
57+
func PublicContractMethod() {
58+
var f = func() func() {
59+
return func() { runtime.Log("bla") }
60+
}()
61+
f()
62+
}
63+
`
64+
for _, src := range []string{srcSimple, srcFromArray, srcFromAnotherFunc} {
65+
_, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
66+
require.NoError(t, err)
67+
require.GreaterOrEqual(t, len(di.Methods), 2)
68+
require.True(t, func() bool {
69+
for _, methodDebugInfo := range di.Methods {
70+
if strings.Contains(methodDebugInfo.Name.Name, "lambda") {
71+
return true
72+
}
73+
}
74+
return false
75+
}())
76+
}
77+
}

0 commit comments

Comments
 (0)