compiler: fix nil method receiver handling
An attempt to compile the following code leads to runtime panic: ``` package foo type CustomInt int func Main() int { var i CustomInt i = 5 return i.Do(2) } func (CustomInt) Do(arg int) int { return arg } ``` The panic: ``` panic: runtime error: index out of range [0] with length 0 [recovered] panic: runtime error: index out of range [0] with length 0 goroutine 22 [running]: testing.tRunner.func1.2({0xa341c0, 0xc0001606d8}) /usr/local/go/src/testing/testing.go:1209 +0x24e testing.tRunner.func1() /usr/local/go/src/testing/testing.go:1212 +0x218 panic({0xa341c0, 0xc0001606d8}) /usr/local/go/src/runtime/panic.go:1038 +0x215 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).convertFuncDecl(0xc00015e3c0, {0xc753b8, 0xc000152c80}, 0xc000266300, 0x30) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/codegen.go:497 +0x10b3 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).compile.func2(0xc000152c80, 0xc00023c410) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/codegen.go:2153 +0x3f8 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).ForEachFile.func1(0xc000229b80) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/compiler.go:102 +0x82 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).ForEachPackage(0xc00015e3c0, 0xc000189bb0) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/compiler.go:93 +0xc6 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).ForEachFile(0x999a20, 0xc000130d80) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/compiler.go:99 +0x45 github.com/nspcc-dev/neo-go/pkg/compiler.(*codegen).compile(0xc00015e3c0, 0xc0002669f0, 0x1) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/codegen.go:2140 +0x445 github.com/nspcc-dev/neo-go/pkg/compiler.codeGen(0xc0002669f0) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/codegen.go:2191 +0x353 github.com/nspcc-dev/neo-go/pkg/compiler.CompileWithOptions({0xa6f39a, 0x50b6b3}, {0xc6d1a0, 0xc0002421e0}, 0x0) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/compiler.go:218 +0x65 github.com/nspcc-dev/neo-go/pkg/compiler_test.vmAndCompileInterop(0x5648df, {0xa9bf23, 0x94}) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/vm_test.go:75 +0x113 github.com/nspcc-dev/neo-go/pkg/compiler_test.eval(0xc0002421c0, {0xa9bf23, 0x61be8c7}, {0xa68880, 0xc0002421c0}) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/vm_test.go:36 +0x2d github.com/nspcc-dev/neo-go/pkg/compiler_test.TestUnnamedMethodReceiver(0x4079f9) /home/anna/Documents/GitProjects/nspcc-dev/neo-go/pkg/compiler/function_call_test.go:400 +0x4f testing.tRunner(0xc000204b60, 0xbcebb0) /usr/local/go/src/testing/testing.go:1259 +0x102 created by testing.(*T).Run /usr/local/go/src/testing/testing.go:1306 +0x35a ``` The solution is to use the same approach as for unnamed function parameters handling introduced in #2204. (c *funcScope).newVariable is able to properly handle "_" receiver.
This commit is contained in:
parent
f8857c5ebe
commit
16dbb35bd8
2 changed files with 22 additions and 1 deletions
|
@ -493,8 +493,15 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
|
|||
// to support other types.
|
||||
if decl.Recv != nil {
|
||||
for _, arg := range decl.Recv.List {
|
||||
// Use underscore instead of unnamed receiver name, e.g.:
|
||||
// func (MyCustomStruct) DoSmth(arg1 int) {...}
|
||||
// Unnamed receiver will never be referenced, thus we can use the same approach as for multiple unnamed parameters handling, see #2204.
|
||||
recvName := "_"
|
||||
if len(arg.Names) != 0 {
|
||||
recvName = arg.Names[0].Name
|
||||
}
|
||||
// only create an argument here, it will be stored via INITSLOT
|
||||
c.scope.newVariable(varArgument, arg.Names[0].Name)
|
||||
c.scope.newVariable(varArgument, recvName)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -385,3 +385,17 @@ func TestUnusedFunctions(t *testing.T) {
|
|||
eval(t, src, big.NewInt(2231))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnnamedMethodReceiver(t *testing.T) {
|
||||
src := `package foo
|
||||
type CustomInt int
|
||||
func Main() int {
|
||||
var i CustomInt
|
||||
i = 5
|
||||
return i.Do(2)
|
||||
}
|
||||
func (CustomInt) Do(arg int) int {
|
||||
return arg
|
||||
}`
|
||||
eval(t, src, big.NewInt(2))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue