From 78cefca5c912af5512ae08e3b93b4b6fda574908 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 4 Apr 2024 17:51:03 +0300 Subject: [PATCH] compiler: Initialize named returns to default values Make them behave as locals. We must initialize them at the start because the default value could also be used inside the function body. Signed-off-by: Evgenii Stratonikov --- pkg/compiler/codegen.go | 19 ++++++++++++++++++- pkg/compiler/return_test.go | 13 +++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index e03866aad..630d95d74 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -522,6 +522,19 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types. } } + // Emit defaults for named returns. + if decl.Type.Results.NumFields() != 0 { + for _, arg := range decl.Type.Results.List { + for _, id := range arg.Names { + if id.Name != "_" { + i := c.scope.newLocal(id.Name) + c.emitDefault(c.typeOf(arg.Type)) + c.emitStoreByIndex(varLocal, i) + } + } + } + } + ast.Walk(c, decl.Body) // If we have reached the end of the function without encountering `return` statement, @@ -763,7 +776,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { for i := len(results.List) - 1; i >= 0; i-- { names := results.List[i].Names for j := len(names) - 1; j >= 0; j-- { - c.emitLoadVar("", names[j].Name) + if names[j].Name == "_" { + c.emitDefault(c.typeOf(results.List[i].Type)) + } else { + c.emitLoadVar("", names[j].Name) + } } } } diff --git a/pkg/compiler/return_test.go b/pkg/compiler/return_test.go index 437f7cd9b..c9cf60e83 100644 --- a/pkg/compiler/return_test.go +++ b/pkg/compiler/return_test.go @@ -120,6 +120,19 @@ func TestNamedReturn(t *testing.T) { t.Run("AnotherVariable", runCase("b, c", big.NewInt(5))) } +func TestNamedReturnDefault(t *testing.T) { + src := `package foo + func Main() int { + a, b, c := f() + return a + b + c + } + func f() (_ int, b int, c int) { + b += 1 + return + }` + eval(t, src, big.NewInt(1)) +} + func TestTypeAssertReturn(t *testing.T) { src := ` package main