From 18369c489e9dc797e2f932160d72c2bf016c4591 Mon Sep 17 00:00:00 2001
From: Evgenii Stratonikov <evgeniy@nspcc.ru>
Date: Sun, 6 Sep 2020 15:26:03 +0300
Subject: [PATCH] compiler: do not allocate slotes for unused "_" vars

---
 pkg/compiler/analysis.go    |  6 +++++-
 pkg/compiler/codegen.go     | 14 ++++++++------
 pkg/compiler/global_test.go | 16 ++++++++++++++++
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go
index 190ea7511..11be72e32 100644
--- a/pkg/compiler/analysis.go
+++ b/pkg/compiler/analysis.go
@@ -112,7 +112,11 @@ func countGlobals(f ast.Node) (i int) {
 		case *ast.GenDecl:
 			if n.Tok == token.VAR {
 				for _, s := range n.Specs {
-					i += len(s.(*ast.ValueSpec).Names)
+					for _, id := range s.(*ast.ValueSpec).Names {
+						if id.Name != "_" {
+							i++
+						}
+					}
 				}
 			}
 			return false
diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go
index 710d58de6..bf01115ad 100644
--- a/pkg/compiler/codegen.go
+++ b/pkg/compiler/codegen.go
@@ -434,13 +434,15 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
 			switch t := spec.(type) {
 			case *ast.ValueSpec:
 				for _, id := range t.Names {
-					if c.scope == nil {
-						// it is a global declaration
-						c.newGlobal("", id.Name)
-					} else {
-						c.scope.newLocal(id.Name)
+					if id.Name != "_" {
+						if c.scope == nil {
+							// it is a global declaration
+							c.newGlobal("", id.Name)
+						} else {
+							c.scope.newLocal(id.Name)
+						}
+						c.registerDebugVariable(id.Name, t.Type)
 					}
-					c.registerDebugVariable(id.Name, t.Type)
 				}
 				for i := range t.Names {
 					if len(t.Values) != 0 {
diff --git a/pkg/compiler/global_test.go b/pkg/compiler/global_test.go
index b8ab1b045..434c22290 100644
--- a/pkg/compiler/global_test.go
+++ b/pkg/compiler/global_test.go
@@ -255,3 +255,19 @@ func TestConstDontUseSlots(t *testing.T) {
 	src := buf.String()
 	eval(t, src, big.NewInt(count))
 }
+
+func TestUnderscoreVarsDontUseSlots(t *testing.T) {
+	const count = 128
+	buf := bytes.NewBufferString("package foo\n")
+	for i := 0; i < count; i++ {
+		buf.WriteString(fmt.Sprintf("var _, n%d = 1, 1\n", i))
+	}
+	buf.WriteString("func Main() int { sum := 0\n")
+	for i := 0; i < count; i++ {
+		buf.WriteString(fmt.Sprintf("sum += n%d\n", i))
+	}
+	buf.WriteString("return sum }")
+
+	src := buf.String()
+	eval(t, src, big.NewInt(count))
+}