compiler: allow to call methods on return values

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgeniy Stratonikov 2022-07-11 19:28:15 +03:00
parent aa338b7960
commit e1a581be0e
5 changed files with 50 additions and 4 deletions

View file

@ -918,7 +918,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
f, ok = c.funcs[name] f, ok = c.funcs[name]
if ok { if ok {
f.selector = fun.X.(*ast.Ident) f.selector = fun.X
isBuiltin = isCustomBuiltin(f) isBuiltin = isCustomBuiltin(f)
if canInline(f.pkg.Path(), f.decl.Name.Name) { if canInline(f.pkg.Path(), f.decl.Name.Name) {
c.inlineCall(f, n) c.inlineCall(f, n)
@ -2069,15 +2069,16 @@ func (c *codegen) getFuncFromIdent(fun *ast.Ident) (*funcScope, bool) {
// getFuncNameFromSelector returns fully-qualified function name from the selector expression. // getFuncNameFromSelector returns fully-qualified function name from the selector expression.
// Second return value is true iff this was a method call, not foreign package call. // Second return value is true iff this was a method call, not foreign package call.
func (c *codegen) getFuncNameFromSelector(e *ast.SelectorExpr) (string, bool) { func (c *codegen) getFuncNameFromSelector(e *ast.SelectorExpr) (string, bool) {
ident := e.X.(*ast.Ident)
if c.typeInfo.Selections[e] != nil { if c.typeInfo.Selections[e] != nil {
typ := c.typeInfo.Types[ident].Type.String() typ := c.typeInfo.Types[e.X].Type.String()
name := c.getIdentName(typ, e.Sel.Name) name := c.getIdentName(typ, e.Sel.Name)
if name[0] == '*' { if name[0] == '*' {
name = name[1:] name = name[1:]
} }
return name, true return name, true
} }
ident := e.X.(*ast.Ident)
return c.getIdentName(ident.Name, e.Sel.Name), false return c.getIdentName(ident.Name, e.Sel.Name), false
} }

View file

@ -13,7 +13,7 @@ type funcScope struct {
// Selector of the function if there is any. Only functions imported // Selector of the function if there is any. Only functions imported
// from other packages should have a selector. // from other packages should have a selector.
selector *ast.Ident selector ast.Expr
// The declaration of the function in the AST. Nil if this scope is not a function. // The declaration of the function in the AST. Nil if this scope is not a function.
decl *ast.FuncDecl decl *ast.FuncDecl

View file

@ -11,6 +11,27 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestReturnValueReceiver(t *testing.T) {
t.Run("regular", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/method"
func Main() int {
return method.NewX().GetA()
}`
eval(t, src, big.NewInt(42))
})
t.Run("inline", func(t *testing.T) {
src := `package foo
import "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline"
func Main() int {
return inline.NewT().GetN()
}`
eval(t, src, big.NewInt(42))
})
}
func TestSimpleFunctionCall(t *testing.T) { func TestSimpleFunctionCall(t *testing.T) {
src := ` src := `
package testcase package testcase

View file

@ -56,3 +56,11 @@ func (t *T) Inc(i int) int {
t.N += i t.N += i
return n return n
} }
func NewT() T {
return T{N: 42}
}
func (t T) GetN() int {
return t.N
}

16
pkg/compiler/testdata/method/struct.go vendored Normal file
View file

@ -0,0 +1,16 @@
package method
// X is some type.
type X struct {
a int
}
// GetA returns the value of a.
func (x X) GetA() int {
return x.a
}
// NewX creates a new X instance.
func NewX() X {
return X{a: 42}
}