Repository: goplus/gop
Pull request #1675 (2024-01-27 04:36:06)

OverloadFunc


Patch:
diff --git a/cl/compile.go b/cl/compile.go
index d84b88a8..f009dead 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -24,6 +24,7 @@ import (
 	"log"
 	"reflect"
 	"sort"
+	"strconv"
 	"strings"
 	_ "unsafe"
 
@@ -344,6 +345,7 @@ type pkgCtx struct {
 	fset    *token.FileSet
 	cpkgs   *cpackages.Importer
 	syms    map[string]loader
+	ovnames []string // names should load before initGopPkg
 	inits   []func()
 	tylds   []*typeLoader
 	errs    errors.List
@@ -642,6 +644,9 @@ func initGopPkg(ctx *pkgCtx, pkg *gox.Package, gopSyms map[string]bool) {
 			ctx.loadSymbol(name)
 		}
 	}
+	for _, name := range ctx.ovnames {
+		ctx.loadSymbol(name)
+	}
 	if pkg.Types.Scope().Lookup(gopPackage) == nil {
 		pkg.Types.Scope().Insert(types.NewConst(token.NoPos, pkg.Types, gopPackage, types.Typ[types.UntypedBool], constant.MakeBool(true)))
 	}
@@ -664,17 +669,6 @@ func getEntrypoint(f *ast.File) string {
 func loadFile(ctx *pkgCtx, f *ast.File) {
 	for _, decl := range f.Decls {
 		switch d := decl.(type) {
-		case *ast.FuncDecl:
-			if d.Recv == nil {
-				name := d.Name.Name
-				if name != "init" {
-					ctx.loadSymbol(name)
-				}
-			} else {
-				if name, ok := getRecvTypeName(ctx, d.Recv, false); ok {
-					getTypeLoader(ctx, ctx.syms, token.NoPos, name).load()
-				}
-			}
 		case *ast.GenDecl:
 			switch d.Tok {
 			case token.TYPE:
@@ -688,6 +682,27 @@ func loadFile(ctx *pkgCtx, f *ast.File) {
 					}
 				}
 			}
+		case *ast.FuncDecl:
+			if d.Recv == nil {
+				name := d.Name.Name
+				if name != "init" {
+					ctx.loadSymbol(name)
+				}
+			} else {
+				if name, ok := getRecvTypeName(ctx, d.Recv, false); ok {
+					getTypeLoader(ctx, ctx.syms, token.NoPos, name).load()
+				}
+			}
+		case *ast.OverloadFuncDecl:
+			/* name := d.Name
+			for idx, fn := range d.Funcs {
+				switch expr := fn.(type) {
+				case *ast.FuncLit:
+					// ctx.loadSymbol(overloadFuncName(name.Name, idx))
+				default:
+					log.Panicf("TODO - cl.loadFile OverloadFuncDecl: unknown func - %T\n", expr)
+				}
+			} */
 		}
 	}
 }
@@ -891,51 +906,75 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, goFile
 	if f.IsClass {
 		skipClassFields = true
 	}
-	for _, decl := range f.Decls {
-		switch d := decl.(type) {
-		case *ast.FuncDecl:
-			if ctx.classRecv != nil { // in class file (.spx/.gmx)
-				if d.Recv == nil {
-					d.Recv = ctx.classRecv
-					d.IsClass = true
+
+	preloadFuncDecl := func(d *ast.FuncDecl) {
+		if ctx.classRecv != nil { // in class file (.spx/.gmx)
+			if d.Recv == nil {
+				d.Recv = ctx.classRecv
+				d.IsClass = true
+			}
+		}
+		if d.Recv == nil {
+			name := d.Name
+			fn := func() {
+				old, _ := p.SetCurFile(goFile, true)
+				defer p.RestoreCurFile(old)
+				loadFunc(ctx, nil, d, genFnBody)
+			}
+			if name.Name == "init" {
+				if genFnBody {
+					if debugLoad {
+						log.Println("==> Preload func init")
+					}
+					parent.inits = append(parent.inits, fn)
+				}
+			} else {
+				if debugLoad {
+					log.Println("==> Preload func", name.Name)
 				}
+				initLoader(parent, syms, name.Pos(), name.Name, fn, genFnBody)
 			}
-			if d.Recv == nil {
-				name := d.Name
+		} else {
+			if name, ok := getRecvTypeName(parent, d.Recv, true); ok {
+				if debugLoad {
+					log.Printf("==> Preload method %s.%s\n", name, d.Name.Name)
+				}
+				ld := getTypeLoader(parent, syms, token.NoPos, name)
 				fn := func() {
 					old, _ := p.SetCurFile(goFile, true)
 					defer p.RestoreCurFile(old)
-					loadFunc(ctx, nil, d, genFnBody)
-				}
-				if name.Name == "init" {
-					if genFnBody {
-						if debugLoad {
-							log.Println("==> Preload func init")
-						}
-						parent.inits = append(parent.inits, fn)
-					}
-				} else {
-					if debugLoad {
-						log.Println("==> Preload func", name.Name)
-					}
-					initLoader(parent, syms, name.Pos(), name.Name, fn, genFnBody)
+					doInitType(ld)
+					recv := toRecv(ctx, d.Recv)
+					loadFunc(ctx, recv, d, genFnBody)
 				}
-			} else {
-				if name, ok := getRecvTypeName(parent, d.Recv, true); ok {
-					if debugLoad {
-						log.Printf("==> Preload method %s.%s\n", name, d.Name.Name)
-					}
-					ld := getTypeLoader(parent, syms, token.NoPos, name)
-					fn := func() {
-						old, _ := p.SetCurFile(goFile, true)
-						defer p.RestoreCurFile(old)
-						doInitType(ld)
-						recv := toRecv(ctx, d.Recv)
-						loadFunc(ctx, recv, d, genFnBody)
+				ld.methods = append(ld.methods, fn)
+			}
+		}
+	}
+
+	preloadConst := func(d *ast.GenDecl) {
+		pkg := ctx.pkg
+		cdecl := pkg.NewConstDefs(pkg.Types.Scope())
+		for _, spec := range d.Specs {
+			vSpec := spec.(*ast.ValueSpec)
+			if debugLoad {
+				log.Println("==> Preload const", vSpec.Names)
+			}
+			setNamesLoader(parent, syms, vSpec.Names, func() {
+				if c := cdecl; c != nil {
+					cdecl = nil
+					loadConstSpecs(ctx, c, d.Specs)
+					for _, s := range d.Specs {
+						v := s.(*ast.ValueSpec)
+						removeNames(syms, v.Names)
 					}
-					ld.methods = append(ld.methods, fn)
 				}
-			}
+			})
+		}
+	}
+
+	for _, decl := range f.Decls {
+		switch d := decl.(type) {
 		case *ast.GenDecl:
 			switch d.Tok {
 			case token.IMPORT:
@@ -1009,24 +1048,7 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, goFile
 					}
 				}
 			case token.CONST:
-				pkg := ctx.pkg
-				cdecl := pkg.NewConstDefs(pkg.Types.Scope())
-				for _, spec := range d.Specs {
-					vSpec := spec.(*ast.ValueSpec)
-					if debugLoad {
-						log.Println("==> Preload const", vSpec.Names)
-					}
-					setNamesLoader(parent, syms, vSpec.Names, func() {
-						if c := cdecl; c != nil {
-							cdecl = nil
-							loadConstSpecs(ctx, c, d.Specs)
-							for _, s := range d.Specs {
-								v := s.(*ast.ValueSpec)
-								removeNames(syms, v.Names)
-							}
-						}
-					})
-				}
+				preloadConst(d)
 			case token.VAR:
 				if skipClassFields {
 					skipClassFields = false
@@ -1050,12 +1072,84 @@ func preloadFile(p *gox.Package, ctx *blockCtx, file string, f *ast.File, goFile
 			default:
 				log.Panicln("TODO - tok:", d.Tok, "spec:", reflect.TypeOf(d.Specs).Elem())
 			}
+
+		case *ast.FuncDecl:
+			preloadFuncDecl(d)
+
+		case *ast.OverloadFuncDecl:
+			const (
+				markIdent = 1 << iota
+				markSelector
+				markFuncLit
+			)
+			onames := make([]string, 0, 4)
+			mark := 0
+			name := d.Name
+			for idx, fn := range d.Funcs {
+				switch expr := fn.(type) {
+				case *ast.Ident:
+					onames = append(onames, expr.Name)
+					ctx.ovnames = append(ctx.ovnames, expr.Name)
+					mark |= markIdent
+				case *ast.FuncLit:
+					if d.Recv != nil || d.Operator {
+						log.Panicln("TODO - OverloadFuncDecl")
+					}
+					name1 := overloadFuncName(name.Name, idx)
+					ctx.ovnames = append(ctx.ovnames, name1)
+					preloadFuncDecl(&ast.FuncDecl{
+						Doc:  d.Doc,
+						Name: &ast.Ident{NamePos: name.NamePos, Name: name1},
+						Type: expr.Type,
+						Body: expr.Body,
+					})
+					mark |= markFuncLit
+				default:
+					log.Panicf("TODO - cl.preloadFile OverloadFuncDecl: unknown func - %T\n", expr)
+				}
+			}
+			if (mark & (markIdent | markSelector)) != 0 {
+				oname := overloadName(name.Name)
+				oval := strings.Join(onames, ",")
+				preloadConst(&ast.GenDecl{
+					Doc: d.Doc,
+					Tok: token.CONST,
+					Specs: []ast.Spec{
+						&ast.ValueSpec{
+							Names:  []*ast.Ident{{Name: oname}},
+							Values: []ast.Expr{stringLit(oval)},
+						},
+					},
+				})
+				ctx.ovnames = append(ctx.ovnames, oname)
+			}
+
 		default:
-			log.Panicln("TODO - gopkg.Package.load: unknown decl -", reflect.TypeOf(decl))
+			log.Panicf("TODO - cl.preloadFile: unknown decl - %T\n", decl)
 		}
 	}
 }
 
+const (
+	indexTable = "0123456789abcdefghijklmnopqrstuvwxyz"
+)
+
+func overloadFuncName(name string, idx int) string {
+	return name + "__" + indexTable[idx:idx+1]
+}
+
+func overloadName(name string) string {
+	prefix := "Gopo_"
+	if strings.ContainsRune(name, '_') {
+		prefix = "Gopo__"
+	}
+	return prefix + name
+}
+
+func stringLit(val string) *ast.BasicLit {
+	return &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(val)}
+}
+
 func newType(pkg *types.Package, pos token.Pos, name string) *types.Named {
 	typName := types.NewTypeName(pos, pkg, name, nil)
 	if old := pkg.Scope().Insert(typName); old != nil {


Test patch:
diff --git a/cl/builtin_test.go b/cl/builtin_test.go
index 9fa72894..e70d7b67 100644
--- a/cl/builtin_test.go
+++ b/cl/builtin_test.go
@@ -53,6 +53,65 @@ func TestErrStringLit(t *testing.T) {
 	})
 }
 
+func TestErrPreloadFile(t *testing.T) {
+	pkg := gox.NewPackage("", "foo", goxConf)
+	ctx := &blockCtx{pkgCtx: &pkgCtx{}}
+	func() {
+		defer func() {
+			if e := recover(); e == nil || e != "TODO - OverloadFuncDecl\n" {
+				t.Fatal("TestErrPreloadFile:", e)
+			}
+		}()
+		decls := []ast.Decl{
+			&ast.OverloadFuncDecl{
+				Name: &ast.Ident{Name: "add"},
+				Funcs: []ast.Expr{
+					&ast.FuncLit{},
+				},
+				Operator: true,
+			},
+		}
+		preloadFile(pkg, ctx, "foo.gop", &ast.File{Decls: decls}, "", true)
+	}()
+	func() {
+		defer func() {
+			if e := recover(); e == nil || e != "TODO - cl.preloadFile OverloadFuncDecl: unknown func - *ast.BasicLit\n" {
+				t.Fatal("TestErrPreloadFile:", e)
+			}
+		}()
+		decls := []ast.Decl{
+			&ast.OverloadFuncDecl{
+				Name: &ast.Ident{Name: "add"},
+				Funcs: []ast.Expr{
+					&ast.BasicLit{},
+				},
+				Operator: true,
+			},
+		}
+		preloadFile(pkg, ctx, "foo.gop", &ast.File{Decls: decls}, "", true)
+	}()
+	func() {
+		defer func() {
+			if e := recover(); e == nil || e != "TODO - cl.preloadFile: unknown decl - *ast.BadDecl\n" {
+				t.Fatal("TestErrPreloadFile:", e)
+			}
+		}()
+		decls := []ast.Decl{
+			&ast.BadDecl{},
+		}
+		preloadFile(pkg, ctx, "foo.gop", &ast.File{Decls: decls}, "", true)
+	}()
+}
+
+func TestErrParseTypeEmbedName(t *testing.T) {
+	defer func() {
+		if e := recover(); e == nil {
+			t.Fatal("TestErrParseTypeEmbedName: no panic?")
+		}
+	}()
+	parseTypeEmbedName(&ast.StructType{})
+}
+
 func TestGmxMainFunc(t *testing.T) {
 	gmxMainFunc(nil, &pkgCtx{
 		projs: map[string]*gmxProject{
diff --git a/cl/compile_gop_test.go b/cl/compile_gop_test.go
new file mode 100644
index 00000000..c72f41a5
--- /dev/null
+++ b/cl/compile_gop_test.go
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cl_test
+
+import (
+	"testing"
+)
+
+func TestOverloadFunc(t *testing.T) {
+	gopClTest(t, `
+func add = (
+	func(a, b int) int {
+		return a + b
+	}
+	func(a, b string) string {
+		return a + b
+	}
+)
+
+println add(100, 7)
+println add("Hello", "World")
+`, `package main
+
+import "fmt"
+
+func add__0(a int, b int) int {
+	return a + b
+}
+func add__1(a string, b string) string {
+	return a + b
+}
+func main() {
+	fmt.Println(add__0(100, 7))
+	fmt.Println(add__1("Hello", "World"))
+}
+`)
+}
+
+func TestOverloadFunc2(t *testing.T) {
+	gopClTest(t, `
+func mulInt(a, b int) int {
+	return a * b
+}
+
+func mulFloat(a, b float64) float64 {
+	return a * b
+}
+
+func mul = (
+	mulInt
+	mulFloat
+)
+
+println mul(100, 7)
+println mul(1.2, 3.14)
+`, `package main
+
+import "fmt"
+
+const Gopo_mul = "mulInt,mulFloat"
+
+func mulInt(a int, b int) int {
+	return a * b
+}
+func mulFloat(a float64, b float64) float64 {
+	return a * b
+}
+func main() {
+	fmt.Println(mulInt(100, 7))
+	fmt.Println(mulFloat(1.2, 3.14))
+}
+`)
+}
+
+func TestStringLitBasic(t *testing.T) {
+	gopClTest(t, `echo "$$"`, `package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("$")
+}
+`)
+}
+
+func TestStringLitVar(t *testing.T) {
+	gopClTest(t, `
+x := 1
+println "Hi, " + "a${x}b"`, `package main
+
+import (
+	"fmt"
+	"strconv"
+)
+
+func main() {
+	x := 1
+	fmt.Println("Hi, " + ("a" + strconv.Itoa(x) + "b"))
+}
+`)
+}
+
+func TestFileOpen(t *testing.T) {
+	gopClTest(t, `
+for line <- open("foo.txt")! {
+	println line
+}
+`, `package main
+
+import (
+	"fmt"
+	"github.com/goplus/gop/builtin/iox"
+	"github.com/qiniu/x/errors"
+	"os"
+)
+
+func main() {
+	for _gop_it := iox.EnumLines(func() (_gop_ret *os.File) {
+		var _gop_err error
+		_gop_ret, _gop_err = os.Open("foo.txt")
+		if _gop_err != nil {
+			_gop_err = errors.NewFrame(_gop_err, "open(\"foo.txt\")", "/foo/bar.gop", 2, "main.main")
+			panic(_gop_err)
+		}
+		return
+	}()); ; {
+		var _gop_ok bool
+		line, _gop_ok := _gop_it.Next()
+		if !_gop_ok {
+			break
+		}
+		fmt.Println(line)
+	}
+}
+`)
+}
+
+func TestFileEnumLines(t *testing.T) {
+	gopClTest(t, `
+import "os"
+
+for line <- os.Stdin {
+	println line
+}
+`, `package main
+
+import (
+	"fmt"
+	"github.com/goplus/gop/builtin/iox"
+	"os"
+)
+
+func main() {
+	for _gop_it := iox.EnumLines(os.Stdin); ; {
+		var _gop_ok bool
+		line, _gop_ok := _gop_it.Next()
+		if !_gop_ok {
+			break
+		}
+		fmt.Println(line)
+	}
+}
+`)
+}
+
+func TestIoxLines(t *testing.T) {
+	gopClTest(t, `
+import "io"
+
+var r io.Reader
+
+for line <- lines(r) {
+	println line
+}
+`, `package main
+
+import (
+	"fmt"
+	"github.com/goplus/gop/builtin/iox"
+	"io"
+)
+
+var r io.Reader
+
+func main() {
+	for _gop_it := iox.Lines(r).Gop_Enum(); ; {
+		var _gop_ok bool
+		line, _gop_ok := _gop_it.Next()
+		if !_gop_ok {
+			break
+		}
+		fmt.Println(line)
+	}
+}
+`)
+}
+
+func TestMixedGo(t *testing.T) {
+	gopMixedClTest(t, "main", `package main
+
+import "strconv"
+
+const n = 10
+
+func f(v int) string {
+	return strconv.Itoa(v)
+}
+
+type foo struct {
+	v int
+}
+
+func (a foo) _() {
+}
+
+func (a foo) Str() string {
+	return f(a.v)
+}
+
+func (a *foo) Bar() int {
+	return 0
+}
+
+type foo2 = foo
+type foo3 foo2
+`, `
+var a [n]int
+var b string = f(n)
+var c foo2
+var d int = c.v
+var e = foo3{}
+var x string = c.str
+`, `package main
+
+var a [10]int
+var b string = f(n)
+var c foo
+var d int = c.v
+var e = foo3{}
+var x string = c.Str()
+`, true)
+	gopMixedClTest(t, "main", `package main
+type Point struct {
+	X int
+	Y int
+}
+`, `
+type T struct{}
+println(&T{},&Point{10,20})
+`, `package main
+
+import "fmt"
+
+type T struct {
+}
+
+func main() {
+	fmt.Println(&T{}, &Point{10, 20})
+}
+`, false)
+}
+
+func Test_RangeExpressionIf_Issue1243(t *testing.T) {
+	gopClTest(t, `
+for i <- :10, i%3 == 0 {
+	println i
+}`, `package main
+
+import "fmt"
+
+func main() {
+	for i := 0; i < 10; i += 1 {
+		if i%3 == 0 {
+			fmt.Println(i)
+		}
+	}
+}
+`)
+}
diff --git a/cl/compile_test.go b/cl/compile_test.go
index 6889a30b..125a5846 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -122,34 +122,6 @@ func gopClTestFS(t *testing.T, conf *cl.Config, fs parser.FileSystem, pkgname, e
 	}
 }
 
-func TestStringLitBasic(t *testing.T) {
-	gopClTest(t, `echo "$$"`, `package main
-
-import "fmt"
-
-func main() {
-	fmt.Println("$")
-}
-`)
-}
-
-func TestStringLitVar(t *testing.T) {
-	gopClTest(t, `
-x := 1
-println "Hi, " + "a${x}b"`, `package main
-
-import (
-	"fmt"
-	"strconv"
-)
-
-func main() {
-	x := 1
-	fmt.Println("Hi, " + ("a" + strconv.Itoa(x) + "b"))
-}
-`)
-}
-
 func TestVargCommand(t *testing.T) {
 	gopClTest(t, `
 type foo int
@@ -184,184 +156,6 @@ ls
 `)
 }
 
-func TestFileOpen(t *testing.T) {
-	gopClTest(t, `
-for line <- open("foo.txt")! {
-	println line
-}
-`, `package main
-
-import (
-	"fmt"
-	"github.com/goplus/gop/builtin/iox"
-	"github.com/qiniu/x/errors"
-	"os"
-)
-
-func main() {
-	for _gop_it := iox.EnumLines(func() (_gop_ret *os.File) {
-		var _gop_err error
-		_gop_ret, _gop_err = os.Open("foo.txt")
-		if _gop_err != nil {
-			_gop_err = errors.NewFrame(_gop_err, "open(\"foo.txt\")", "/foo/bar.gop", 2, "main.main")
-			panic(_gop_err)
-		}
-		return
-	}()); ; {
-		var _gop_ok bool
-		line, _gop_ok := _gop_it.Next()
-		if !_gop_ok {
-			break
-		}
-		fmt.Println(line)
-	}
-}
-`)
-}
-
-func TestFileEnumLines(t *testing.T) {
-	gopClTest(t, `
-import "os"
-
-for line <- os.Stdin {
-	println line
-}
-`, `package main
-
-import (
-	"fmt"
-	"github.com/goplus/gop/builtin/iox"
-	"os"
-)
-
-func main() {
-	for _gop_it := iox.EnumLines(os.Stdin); ; {
-		var _gop_ok bool
-		line, _gop_ok := _gop_it.Next()
-		if !_gop_ok {
-			break
-		}
-		fmt.Println(line)
-	}
-}
-`)
-}
-
-func TestIoxLines(t *testing.T) {
-	gopClTest(t, `
-import "io"
-
-var r io.Reader
-
-for line <- lines(r) {
-	println line
-}
-`, `package main
-
-import (
-	"fmt"
-	"github.com/goplus/gop/builtin/iox"
-	"io"
-)
-
-var r io.Reader
-
-func main() {
-	for _gop_it := iox.Lines(r).Gop_Enum(); ; {
-		var _gop_ok bool
-		line, _gop_ok := _gop_it.Next()
-		if !_gop_ok {
-			break
-		}
-		fmt.Println(line)
-	}
-}
-`)
-}
-
-func TestMixedGo(t *testing.T) {
-	gopMixedClTest(t, "main", `package main
-
-import "strconv"
-
-const n = 10
-
-func f(v int) string {
-	return strconv.Itoa(v)
-}
-
-type foo struct {
-	v int
-}
-
-func (a foo) _() {
-}
-
-func (a foo) Str() string {
-	return f(a.v)
-}
-
-func (a *foo) Bar() int {
-	return 0
-}
-
-type foo2 = foo
-type foo3 foo2
-`, `
-var a [n]int
-var b string = f(n)
-var c foo2
-var d int = c.v
-var e = foo3{}
-var x string = c.str
-`, `package main
-
-var a [10]int
-var b string = f(n)
-var c foo
-var d int = c.v
-var e = foo3{}
-var x string = c.Str()
-`, true)
-	gopMixedClTest(t, "main", `package main
-type Point struct {
-	X int
-	Y int
-}
-`, `
-type T struct{}
-println(&T{},&Point{10,20})
-`, `package main
-
-import "fmt"
-
-type T struct {
-}
-
-func main() {
-	fmt.Println(&T{}, &Point{10, 20})
-}
-`, false)
-}
-
-func Test_RangeExpressionIf_Issue1243(t *testing.T) {
-	gopClTest(t, `
-for i <- :10, i%3 == 0 {
-	println i
-}`, `package main
-
-import "fmt"
-
-func main() {
-	for i := 0; i < 10; i += 1 {
-		if i%3 == 0 {
-			fmt.Println(i)
-		}
-	}
-}
-`)
-}
-
 func Test_CastSlice_Issue1240(t *testing.T) {
 	gopClTest(t, `
 type fvec []float64
diff --git a/testdata/overloadfunc1/add.gop b/testdata/overloadfunc1/add.gop
new file mode 100644
index 00000000..c8fe0b8a
--- /dev/null
+++ b/testdata/overloadfunc1/add.gop
@@ -0,0 +1,11 @@
+func add = (
+	func(a, b int) int {
+		return a + b
+	}
+	func(a, b string) string {
+		return a + b
+	}
+)
+
+println add(100, 7)
+println add("Hello", "World")
diff --git a/testdata/overloadfunc2/mul.gop b/testdata/overloadfunc2/mul.gop
new file mode 100644
index 00000000..6b18ac0d
--- /dev/null
+++ b/testdata/overloadfunc2/mul.gop
@@ -0,0 +1,15 @@
+func mulInt(a, b int) int {
+	return a * b
+}
+
+func mulFloat(a, b float64) float64 {
+	return a * b
+}
+
+func mul = (
+	mulInt
+	mulFloat
+)
+
+println mul(100, 7)
+println mul(1.2, 3.14)