diff --git a/x/typesutil/check_test.go b/x/typesutil/check_test.go index 5e784e16d..07da84462 100644 --- a/x/typesutil/check_test.go +++ b/x/typesutil/check_test.go @@ -78,7 +78,7 @@ func checkInfo(fset *token.FileSet, files []*ast.File, gofiles []*goast.File) (* Implicits: make(map[ast.Node]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), Scopes: make(map[ast.Node]*types.Scope), - Overloads: make(map[*ast.Ident][]types.Object), + Overloads: make(map[*ast.Ident]types.Object), } ginfo := &types.Info{ Types: make(map[goast.Expr]types.TypeAndValue), @@ -196,3 +196,83 @@ func TestBadFile(t *testing.T) { _ = checker.Files([]*goast.File{{Name: goast.NewIdent("main")}}, []*ast.File{{Name: ast.NewIdent("main")}}) } + +func TestCheckOverload(t *testing.T) { + fset := token.NewFileSet() + info, ginfo, err := checkFiles(fset, "main.gop", ` +type foo struct { +} + +func (a *foo) mulInt(b int) *foo { + return a +} + +func (a *foo) mulFoo(b *foo) *foo { + return a +} + +func (foo).mul = ( + (foo).mulInt + (foo).mulFoo +) +func addInt0() { +} + +func addInt1(i int) { +} + +func addInt2(i, j int) { +} + +var addInt3 = func(i, j, k int) { +} + +func add = ( + addInt0 + addInt1 + addInt2 + addInt3 + func(a, b string) string { + return a + b + } +) + +var a, b *foo +var c = a.mul(100) +var d = a.mul(c) + +func init() { + add 100, 200 + add 100, 200, 300 + add("hello", "world") +} +`, "", "", "", "") + if err != nil || info == nil || ginfo == nil { + t.Fatalf("check failed: %v", err) + } + for use, ovDeclObj := range info.Overloads { + o := info.ObjectOf(use) + declObj, ovObjs := info.OverloadOf(use) + if ovDeclObj != declObj { + t.Fatal("bad overload", o) + } + found := false + for _, ovObj := range ovObjs { + if o == ovObj { + found = true + break + } + } + if !found { + t.Fatal("bad overload", o) + } + } + for use, o := range info.Uses { + declObj, ovObjs := info.OverloadOf(use) + if declObj != nil && ovObjs != nil { + if info.Overloads[use] == nil { + t.Fatal("bad overload", o) + } + } + } +} diff --git a/x/typesutil/gopinfo.go b/x/typesutil/gopinfo.go index c08530afb..2416041e3 100644 --- a/x/typesutil/gopinfo.go +++ b/x/typesutil/gopinfo.go @@ -136,8 +136,8 @@ type Info struct { // appear in this list. // InitOrder []*Initializer - // Overloads maps identifiers to the overload objects. - Overloads map[*ast.Ident][]types.Object + // Overloads maps identifiers to the overload decl object. + Overloads map[*ast.Ident]types.Object } // ObjectOf returns the object denoted by the specified id, @@ -168,6 +168,18 @@ func (info *Info) TypeOf(e ast.Expr) types.Type { return nil } +// Returns the overloaded function declaration corresponding to the ident and its overloaded function members +func (info *Info) OverloadOf(id *ast.Ident) (types.Object, []types.Object) { + if obj := info.Overloads[id]; obj != nil { + if sig, ok := obj.Type().(*types.Signature); ok { + if _, objs := gogen.CheckSigFuncExObjects(sig); len(objs) > 1 { + return obj, objs + } + } + } + return nil, nil +} + // ----------------------------------------------------------------------------- type gopRecorder struct { @@ -255,11 +267,11 @@ func (info gopRecorder) Use(id *ast.Ident, obj types.Object) { } if info.Overloads != nil { if sig, ok := obj.Type().(*types.Signature); ok { - if ext, objs := gogen.CheckSigFuncExObjects(sig); len(objs) > 1 { + if ext, ok := gogen.CheckSigFuncEx(sig); ok { if debugVerbose { log.Println("==> Overloads:", id, ext) } - info.Overloads[id] = objs + info.Overloads[id] = obj } } } diff --git a/x/typesutil/info_test.go b/x/typesutil/info_test.go index b82a510a5..b059ce71e 100644 --- a/x/typesutil/info_test.go +++ b/x/typesutil/info_test.go @@ -91,7 +91,7 @@ func parseMixedSource(mod *gopmod.Module, fset *token.FileSet, name, src string, Implicits: make(map[ast.Node]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), Scopes: make(map[ast.Node]*types.Scope), - Overloads: make(map[*ast.Ident][]types.Object), + Overloads: make(map[*ast.Ident]types.Object), } ginfo := &types.Info{ Types: make(map[goast.Expr]types.TypeAndValue), @@ -129,7 +129,7 @@ func parseSource(fset *token.FileSet, filename string, src interface{}, mode par Implicits: make(map[ast.Node]types.Object), Selections: make(map[*ast.SelectorExpr]*types.Selection), Scopes: make(map[ast.Node]*types.Scope), - Overloads: make(map[*ast.Ident][]types.Object), + Overloads: make(map[*ast.Ident]types.Object), } check := typesutil.NewChecker(conf, chkOpts, nil, info) err = check.Files(nil, []*ast.File{f}) @@ -179,6 +179,10 @@ func testGopInfoEx(t *testing.T, mod *gopmod.Module, name string, src string, go list = append(list, defsList(fset, info.Defs, true)...) list = append(list, "== uses ==") list = append(list, usesList(fset, info.Uses)...) + if len(info.Overloads) > 0 { + list = append(list, "== overloads ==") + list = append(list, overloadsList(fset, info.Overloads)...) + } result := strings.Join(list, "\n") t.Log(result) if result != expect { @@ -341,6 +345,20 @@ func goUsesList(fset *token.FileSet, uses map[*goast.Ident]types.Object) []strin return sortItems(items) } +func overloadsList(fset *token.FileSet, overloads map[*ast.Ident]types.Object) []string { + var items []string + for expr, obj := range overloads { + var buf strings.Builder + posn := fset.Position(expr.Pos()) + // line:col | expr | mode : type = value + fmt.Fprintf(&buf, "%2d:%2d | %-19s | %s", + posn.Line, posn.Column, expr, + obj) + items = append(items, buf.String()) + } + return sortItems(items) +} + /* func selectionList(fset *token.FileSet, sels map[*ast.SelectorExpr]*types.Selection) []string { var items []string @@ -1163,7 +1181,21 @@ func OnKey__a(a, b string, v ...int) { 023: 33:26 | x | var x int 024: 34: 9 | x | var x int 025: 36: 1 | OnKey | func main.OnKey__a(a string, b string, v ...int) -026: 37: 1 | OnKey | func main.OnKey__a(a string, b string, v ...int)`) +026: 37: 1 | OnKey | func main.OnKey__a(a string, b string, v ...int) +== overloads == +000: 14: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +001: 16: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +002: 18: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +003: 20: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +004: 22: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +005: 24: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +006: 26: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +007: 28: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +008: 30: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +009: 32: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +010: 33: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +011: 36: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()}) +012: 37: 1 | OnKey | func main.OnKey(__gop_overload_args__ interface{_()})`) } func TestMixedOverload2(t *testing.T) { @@ -1387,7 +1419,18 @@ func OnKey__a(a, b string, v ...int) { 028: 31: 3 | onKey | func (*main.N).OnKey__6(a []string, b []string, fn func(key string)) 029: 31:16 | nil | nil 030: 33: 1 | n | var n *main.N -031: 33: 3 | onKey | func (*main.N).OnKey__8(x int, y int)`) +031: 33: 3 | onKey | func (*main.N).OnKey__8(x int, y int) +== overloads == +000: 15: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +001: 17: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +002: 19: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +003: 21: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +004: 23: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +005: 25: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +006: 27: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +007: 29: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +008: 31: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()}) +009: 33: 3 | onKey | func (main.N).OnKey(__gop_overload_args__ interface{_()})`) } func TestMixedOverload3(t *testing.T) { @@ -1432,7 +1475,12 @@ func (p *N) Test__1(n int) { 003: 5: 1 | n | var n main.N 004: 5: 3 | test | func (*main.N).Test__0() 005: 6: 1 | n | var n main.N -006: 6: 3 | test | func (*main.N).Test__1(n int)`) +006: 6: 3 | test | func (*main.N).Test__1(n int) +== overloads == +000: 2: 1 | Test | func main.Test(__gop_overload_args__ interface{_()}) +001: 3: 1 | Test | func main.Test(__gop_overload_args__ interface{_()}) +002: 5: 3 | test | func (main.N).Test(__gop_overload_args__ interface{_()}) +003: 6: 3 | test | func (main.N).Test(__gop_overload_args__ interface{_()})`) } func TestOverloadNamed(t *testing.T) { @@ -1476,7 +1524,12 @@ d := bar.Var(bar.M) 010: 7: 6 | bar | package bar ("github.com/goplus/gop/cl/internal/overload/bar") 011: 7:10 | Var | func github.com/goplus/gop/cl/internal/overload/bar.Gopx_Var_Cast__1[T map[string]any]() *github.com/goplus/gop/cl/internal/overload/bar.Var__1[T] 012: 7:14 | bar | package bar ("github.com/goplus/gop/cl/internal/overload/bar") -013: 7:18 | M | type github.com/goplus/gop/cl/internal/overload/bar.M = map[string]any`) +013: 7:18 | M | type github.com/goplus/gop/cl/internal/overload/bar.M = map[string]any +== overloads == +000: 4:11 | Var | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()}) +001: 5:11 | Var | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()}) +002: 6:10 | Var | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()}) +003: 7:10 | Var | type github.com/goplus/gop/cl/internal/overload/bar.Var = func(__gop_overload_args__ interface{_()})`) } func TestMixedOverloadNamed(t *testing.T) { @@ -1536,7 +1589,12 @@ func Gopx_Var_Cast__1[T map[string]any]() *Var__1[T] { 004: 4: 6 | Var | func main.Gopx_Var_Cast__0[T main.basetype]() *main.Var__0[T] 005: 4:10 | string | type string 006: 5: 6 | Var | func main.Gopx_Var_Cast__1[T map[string]any]() *main.Var__1[T] -007: 5:10 | M | type main.M = map[string]any`) +007: 5:10 | M | type main.M = map[string]any +== overloads == +000: 2: 7 | Var | type main.Var = func(__gop_overload_args__ interface{_()}) +001: 3: 7 | Var | type main.Var = func(__gop_overload_args__ interface{_()}) +002: 4: 6 | Var | type main.Var = func(__gop_overload_args__ interface{_()}) +003: 5: 6 | Var | type main.Var = func(__gop_overload_args__ interface{_()})`) } func TestMixedRawNamed(t *testing.T) { @@ -1675,7 +1733,11 @@ func onCloned() { 009: 14: 8 | info | type main.info struct{x int; y int} 010: 15: 2 | clone | func github.com/goplus/gop/cl/internal/spx.Gopt_Sprite_Clone__1(sprite interface{}, data interface{}) 011: 15: 9 | info | type main.info struct{x int; y int} -012: 19: 2 | say | func (*github.com/goplus/gop/cl/internal/spx.Sprite).Say(msg string, secs ...float64)`) +012: 19: 2 | say | func (*github.com/goplus/gop/cl/internal/spx.Sprite).Say(msg string, secs ...float64) +== overloads == +000: 13: 2 | clone | func (github.com/goplus/gop/cl/internal/spx.Sprite).Clone(__gop_overload_args__ interface{_()}) +001: 14: 2 | clone | func (github.com/goplus/gop/cl/internal/spx.Sprite).Clone(__gop_overload_args__ interface{_()}) +002: 15: 2 | clone | func (github.com/goplus/gop/cl/internal/spx.Sprite).Clone(__gop_overload_args__ interface{_()})`) } func TestScopesInfo(t *testing.T) { @@ -2069,7 +2131,10 @@ Mul 100,200,300 013: 14:14 | y | var y int 014: 14:18 | z | var z int 015: 18: 1 | Mul | func main.MulInt(a int, b int) int -016: 19: 1 | Mul | func main.Mul__2(x int, y int, z int) int`) +016: 19: 1 | Mul | func main.Mul__2(x int, y int, z int) int +== overloads == +000: 18: 1 | Mul | func main.Mul(__gop_overload_args__ interface{_()}) +001: 19: 1 | Mul | func main.Mul(__gop_overload_args__ interface{_()})`) testGopInfo(t, ` type foo struct { @@ -2149,7 +2214,11 @@ var d = a.mul(c) 015: 19:11 | mul | func (*main.foo).mulInt(b int) *main.foo 016: 20: 9 | a | var main.a *main.foo 017: 20:11 | mul | func (*main.foo).mulFoo(b *main.foo) *main.foo -018: 20:15 | c | var main.c *main.foo`) +018: 20:15 | c | var main.c *main.foo +== overloads == +000: 19:11 | mul | func (main.foo).mul(__gop_overload_args__ interface{_()}) +001: 20:11 | mul | func (main.foo).mul(__gop_overload_args__ interface{_()})`) + } func TestGopOverloadDecl(t *testing.T) { @@ -2242,7 +2311,11 @@ func init() { 010: 20:14 | b | var b string 011: 25: 2 | add | func main.addInt2(i int, j int) 012: 26: 2 | add | var main.addInt3 func(i int, j int, k int) -013: 27: 2 | add | func main.add__4(a string, b string) string`) +013: 27: 2 | add | func main.add__4(a string, b string) string +== overloads == +000: 25: 2 | add | func main.add(__gop_overload_args__ interface{_()}) +001: 26: 2 | add | func main.add(__gop_overload_args__ interface{_()}) +002: 27: 2 | add | func main.add(__gop_overload_args__ interface{_()})`) testGopInfo(t, ` func add = ( @@ -2304,5 +2377,8 @@ func init() { 006: 7:10 | a | var a string 007: 7:14 | b | var b string 008: 12: 2 | add | func main.add__0(a int, b int) int -009: 13: 2 | add | func main.add__1(a string, b string) string`) +009: 13: 2 | add | func main.add__1(a string, b string) string +== overloads == +000: 12: 2 | add | func main.add(__gop_overload_args__ interface{_()}) +001: 13: 2 | add | func main.add(__gop_overload_args__ interface{_()})`) }