Repository: goplus/gop
Pull request #1866 (2024-04-24 05:27:21)

cl: record def for ast.OverloadFuncDecl

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/goplus/gop/pull/1866?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 93.90%. Comparing base [(`64a3001`)](https://app.codecov.io/gh/goplus/gop/commit/64a3001223da3a7d81d1313082698deff6721af0?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) to head [(`c450177`)](https://app.codecov.io/gh/goplus/gop/pull/1866?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1866      +/-   ##
==========================================
+ Coverage   93.27%   93.90%   +0.62%     
==========================================
  Files          40       39       -1     
  Lines       11607     9577    -2030     
==========================================
- Hits        10827     8993    -1834     
+ Misses        623      427     -196     
  Partials      157      157              
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/goplus/gop/pull/1866?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).


Patch:
diff --git a/cl/compile.go b/cl/compile.go
index 3ed60aae..cab47ce1 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -127,6 +127,7 @@ type Recorder interface {
 	//     *ast.ImportSpec    *PkgName for imports without renames
 	//     *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
 	//     *ast.Field         anonymous parameter *Var (incl. unnamed results)
+	//     *ast.FunLit        function literal in *ast.OverloadFuncDecl
 	//
 	Implicit(node ast.Node, obj types.Object)
 
@@ -1085,7 +1086,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 				}
 				recv = otyp
 				if ctx.rec != nil {
-					ctx.rec.Refer(recv, recv.Name)
+					ctx.rec.ReferUse(recv, recv.Name)
 				}
 			}
 			onames := make([]string, 0, 4)
@@ -1103,7 +1104,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 					ctx.lbinames = append(ctx.lbinames, expr.Name)
 					exov = true
 					if ctx.rec != nil {
-						ctx.rec.Refer(expr, expr.Name)
+						ctx.rec.ReferUse(expr, expr.Name)
 					}
 				case *ast.SelectorExpr:
 					if d.Recv == nil {
@@ -1120,8 +1121,8 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 					ctx.lbinames = append(ctx.lbinames, recv)
 					exov = true
 					if ctx.rec != nil {
-						ctx.rec.Refer(rtyp, rtyp.Name)
-						ctx.rec.Refer(expr.Sel, rtyp.Name+"."+expr.Sel.Name)
+						ctx.rec.ReferUse(rtyp, rtyp.Name)
+						ctx.rec.ReferUse(expr.Sel, rtyp.Name+"."+expr.Sel.Name)
 					}
 				case *ast.FuncLit:
 					if d.Recv != nil && !d.Operator {
@@ -1131,9 +1132,13 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 					name1 := overloadFuncName(name.Name, idx)
 					onames = append(onames, "") // const Gopo_xxx = "xxxInt,,xxxFloat"
 					ctx.lbinames = append(ctx.lbinames, name1)
+					id := &ast.Ident{NamePos: expr.Pos(), Name: name1}
+					if ctx.rec != nil {
+						ctx.rec.ReferDef(id, expr)
+					}
 					preloadFuncDecl(&ast.FuncDecl{
 						Doc:  d.Doc,
-						Name: &ast.Ident{NamePos: expr.Pos(), Name: name1},
+						Name: id,
 						Type: expr.Type,
 						Body: expr.Body,
 					})
@@ -1160,6 +1165,9 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 					},
 				})
 				ctx.lbinames = append(ctx.lbinames, oname)
+				if ctx.rec != nil {
+					ctx.rec.ReferDef(d.Name, d)
+				}
 			}
 
 		default:
diff --git a/cl/recorder.go b/cl/recorder.go
index 4ac4c627..a69f21bf 100644
--- a/cl/recorder.go
+++ b/cl/recorder.go
@@ -29,24 +29,58 @@ import (
 
 type goxRecorder struct {
 	Recorder
-	types  map[ast.Expr]types.TypeAndValue
-	refers map[string][]*ast.Ident
+	types     map[ast.Expr]types.TypeAndValue
+	referDefs map[*ast.Ident]ast.Node
+	referUses map[string][]*ast.Ident
 }
 
 func newRecorder(rec Recorder) *goxRecorder {
 	types := make(map[ast.Expr]types.TypeAndValue)
-	refers := make(map[string][]*ast.Ident)
-	return &goxRecorder{rec, types, refers}
+	referDefs := make(map[*ast.Ident]ast.Node)
+	referUses := make(map[string][]*ast.Ident)
+	return &goxRecorder{rec, types, referDefs, referUses}
 }
 
-// Refer maps identifiers to name for ast.OverloadFuncDecl.
-func (p *goxRecorder) Refer(ident *ast.Ident, name string) {
-	p.refers[name] = append(p.refers[name], ident)
+// Refer uses maps identifiers to name for ast.OverloadFuncDecl.
+func (p *goxRecorder) ReferUse(ident *ast.Ident, name string) {
+	p.referUses[name] = append(p.referUses[name], ident)
+}
+
+// Refer def maps for ast.FuncLit or ast.OverloadFuncDecl.
+func (p *goxRecorder) ReferDef(ident *ast.Ident, node ast.Node) {
+	p.referDefs[ident] = node
 }
 
 // Complete computes the types record.
 func (p *goxRecorder) Complete(scope *types.Scope) {
-	for name, idents := range p.refers {
+	for id, node := range p.referDefs {
+		switch fn := node.(type) {
+		case *ast.FuncLit:
+			if obj := scope.Lookup(id.Name); obj != nil {
+				p.recordFuncLit(fn, obj.Type())
+				p.Implicit(node, obj)
+			}
+		case *ast.OverloadFuncDecl:
+			if fn.Recv == nil {
+				if obj := scope.Lookup(id.Name); obj != nil {
+					p.Def(id, obj)
+				}
+			} else {
+				if obj := scope.Lookup(fn.Recv.List[0].Type.(*ast.Ident).Name); obj != nil {
+					if named, ok := obj.Type().(*types.Named); ok {
+						n := named.NumMethods()
+						for i := 0; i < n; i++ {
+							if m := named.Method(i); m.Name() == id.Name {
+								p.Def(id, m)
+								break
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	for name, idents := range p.referUses {
 		pos := strings.Index(name, ".")
 		if pos == -1 {
 			if obj := scope.Lookup(name); obj != nil {
@@ -71,7 +105,8 @@ func (p *goxRecorder) Complete(scope *types.Scope) {
 		}
 	}
 	p.types = nil
-	p.refers = nil
+	p.referDefs = nil
+	p.referUses = nil
 }
 
 // Member maps identifiers to the objects they denote.
diff --git a/x/typesutil/gopinfo.go b/x/typesutil/gopinfo.go
index e2c00d71..c08530af 100644
--- a/x/typesutil/gopinfo.go
+++ b/x/typesutil/gopinfo.go
@@ -91,6 +91,7 @@ type Info struct {
 	//     *ast.ImportSpec    *PkgName for imports without renames
 	//     *ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
 	//     *ast.Field         anonymous parameter *Var (incl. unnamed results)
+	//     *ast.FunLit        function literal in *ast.OverloadFuncDecl
 	//
 	Implicits map[ast.Node]types.Object
 


Test patch:
diff --git a/x/typesutil/info_test.go b/x/typesutil/info_test.go
index d70fbe67..4f0c00be 100644
--- a/x/typesutil/info_test.go
+++ b/x/typesutil/info_test.go
@@ -2018,22 +2018,26 @@ Mul 100,200,300
 008:  7: 9 | a                   *ast.Ident                     | var     : float64 | variable
 009:  7: 9 | a * b               *ast.BinaryExpr                | value   : float64 | value
 010:  7:13 | b                   *ast.Ident                     | var     : float64 | variable
-011: 13:15 | int                 *ast.Ident                     | type    : int | type
-012: 13:20 | int                 *ast.Ident                     | type    : int | type
-013: 14:10 | x                   *ast.Ident                     | var     : int | variable
-014: 14:10 | x * y               *ast.BinaryExpr                | value   : int | value
-015: 14:10 | x * y * z           *ast.BinaryExpr                | value   : int | value
-016: 14:14 | y                   *ast.Ident                     | var     : int | variable
-017: 14:18 | z                   *ast.Ident                     | var     : int | variable
-018: 18: 1 | Mul                 *ast.Ident                     | value   : func(a int, b int) int | value
-019: 18: 1 | Mul 100, 200        *ast.CallExpr                  | value   : int | value
-020: 18: 5 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
-021: 18: 9 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
-022: 19: 1 | Mul                 *ast.Ident                     | value   : func(x int, y int, z int) int | value
-023: 19: 1 | Mul 100, 200, 300   *ast.CallExpr                  | value   : int | value
-024: 19: 5 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
-025: 19: 9 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
-026: 19:13 | 300                 *ast.BasicLit                  | value   : untyped int = 300 | constant
+011: 13: 2 | func(x, y, z int) int *ast.FuncType                  | type    : func(x int, y int, z int) int | type
+012: 13: 2 | func(x, y, z int) int {
+	return x * y * z
+} *ast.FuncLit                   | value   : func(x int, y int, z int) int | value
+013: 13:15 | int                 *ast.Ident                     | type    : int | type
+014: 13:20 | int                 *ast.Ident                     | type    : int | type
+015: 14:10 | x                   *ast.Ident                     | var     : int | variable
+016: 14:10 | x * y               *ast.BinaryExpr                | value   : int | value
+017: 14:10 | x * y * z           *ast.BinaryExpr                | value   : int | value
+018: 14:14 | y                   *ast.Ident                     | var     : int | variable
+019: 14:18 | z                   *ast.Ident                     | var     : int | variable
+020: 18: 1 | Mul                 *ast.Ident                     | value   : func(a int, b int) int | value
+021: 18: 1 | Mul 100, 200        *ast.CallExpr                  | value   : int | value
+022: 18: 5 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
+023: 18: 9 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
+024: 19: 1 | Mul                 *ast.Ident                     | value   : func(x int, y int, z int) int | value
+025: 19: 1 | Mul 100, 200, 300   *ast.CallExpr                  | value   : int | value
+026: 19: 5 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
+027: 19: 9 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
+028: 19:13 | 300                 *ast.BasicLit                  | value   : untyped int = 300 | constant
 == defs ==
 000:  0: 0 | Gopo_Mul            | const main.Gopo_Mul untyped string
 001:  2: 6 | MulInt              | func main.MulInt(a int, b int) int
@@ -2042,11 +2046,12 @@ Mul 100,200,300
 004:  6: 6 | MulFloat            | func main.MulFloat(a float64, b float64) float64
 005:  6:15 | a                   | var a float64
 006:  6:18 | b                   | var b float64
-007: 13: 2 | Mul__2              | func main.Mul__2(x int, y int, z int) int
-008: 13: 7 | x                   | var x int
-009: 13:10 | y                   | var y int
-010: 13:13 | z                   | var z int
-011: 18: 1 | main                | func main.main()
+007: 10: 6 | Mul                 | func main.Mul(__gop_overload_args__ interface{_()})
+008: 13: 2 | Mul__2              | func main.Mul__2(x int, y int, z int) int
+009: 13: 7 | x                   | var x int
+010: 13:10 | y                   | var y int
+011: 13:13 | z                   | var z int
+012: 18: 1 | main                | func main.main()
 == uses ==
 000:  2:18 | int                 | type int
 001:  2:23 | int                 | type int
@@ -2120,10 +2125,11 @@ var d = a.mul(c)
 005:  9: 7 | a                   | var a *main.foo
 006:  9:15 | mulFoo              | func (*main.foo).mulFoo(b *main.foo) *main.foo
 007:  9:22 | b                   | var b *main.foo
-008: 18: 5 | a                   | var main.a *main.foo
-009: 18: 8 | b                   | var main.b *main.foo
-010: 19: 5 | c                   | var main.c *main.foo
-011: 20: 5 | d                   | var main.d *main.foo
+008: 13:12 | mul                 | func (main.foo).mul(__gop_overload_args__ interface{_()})
+009: 18: 5 | a                   | var main.a *main.foo
+010: 18: 8 | b                   | var main.b *main.foo
+011: 19: 5 | c                   | var main.c *main.foo
+012: 20: 5 | d                   | var main.d *main.foo
 == uses ==
 000:  5:10 | foo                 | type main.foo struct{}
 001:  5:24 | int                 | type int
@@ -2145,3 +2151,96 @@ var d = a.mul(c)
 017: 20:11 | mul                 | func (*main.foo).mulFoo(b *main.foo) *main.foo
 018: 20:15 | c                   | var main.c *main.foo`)
 }
+
+func TestGopOverloadDecl(t *testing.T) {
+	testGopInfo(t, `
+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
+	}
+)
+
+func init() {
+	add 100, 200
+	add 100, 200, 300
+	add("hello", "world")
+}
+`, ``, `== types ==
+000:  0: 0 | "addInt0,addInt1,addInt2,addInt3," *ast.BasicLit                  | value   : untyped string = "addInt0,addInt1,addInt2,addInt3," | constant
+001:  5:16 | int                 *ast.Ident                     | type    : int | type
+002:  8:19 | int                 *ast.Ident                     | type    : int | type
+003: 11:15 | func(i, j, k int)   *ast.FuncType                  | type    : func(i int, j int, k int) | type
+004: 11:15 | func(i, j, k int) {
+} *ast.FuncLit                   | value   : func(i int, j int, k int) | value
+005: 11:28 | int                 *ast.Ident                     | type    : int | type
+006: 19: 2 | func(a, b string) string *ast.FuncType                  | type    : func(a string, b string) string | type
+007: 19: 2 | func(a, b string) string {
+	return a + b
+} *ast.FuncLit                   | value   : func(a string, b string) string | value
+008: 19:12 | string              *ast.Ident                     | type    : string | type
+009: 19:20 | string              *ast.Ident                     | type    : string | type
+010: 20:10 | a                   *ast.Ident                     | var     : string | variable
+011: 20:10 | a + b               *ast.BinaryExpr                | value   : string | value
+012: 20:14 | b                   *ast.Ident                     | var     : string | variable
+013: 25: 2 | add                 *ast.Ident                     | value   : func(i int, j int) | value
+014: 25: 2 | add 100, 200        *ast.CallExpr                  | void    : () | no value
+015: 25: 6 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
+016: 25:11 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
+017: 26: 2 | add                 *ast.Ident                     | var     : func(i int, j int, k int) | variable
+018: 26: 2 | add 100, 200, 300   *ast.CallExpr                  | void    : () | no value
+019: 26: 6 | 100                 *ast.BasicLit                  | value   : untyped int = 100 | constant
+020: 26:11 | 200                 *ast.BasicLit                  | value   : untyped int = 200 | constant
+021: 26:16 | 300                 *ast.BasicLit                  | value   : untyped int = 300 | constant
+022: 27: 2 | add                 *ast.Ident                     | value   : func(a string, b string) string | value
+023: 27: 2 | add("hello", "world") *ast.CallExpr                  | value   : string | value
+024: 27: 6 | "hello"             *ast.BasicLit                  | value   : untyped string = "hello" | constant
+025: 27:15 | "world"             *ast.BasicLit                  | value   : untyped string = "world" | constant
+== defs ==
+000:  0: 0 | Gopo_add            | const main.Gopo_add untyped string
+001:  2: 6 | addInt0             | func main.addInt0()
+002:  5: 6 | addInt1             | func main.addInt1(i int)
+003:  5:14 | i                   | var i int
+004:  8: 6 | addInt2             | func main.addInt2(i int, j int)
+005:  8:14 | i                   | var i int
+006:  8:17 | j                   | var j int
+007: 11: 5 | addInt3             | var main.addInt3 func(i int, j int, k int)
+008: 11:20 | i                   | var i int
+009: 11:23 | j                   | var j int
+010: 11:26 | k                   | var k int
+011: 14: 6 | add                 | func main.add(__gop_overload_args__ interface{_()})
+012: 19: 2 | add__4              | func main.add__4(a string, b string) string
+013: 19: 7 | a                   | var a string
+014: 19:10 | b                   | var b string
+015: 24: 6 | init                | func main.init()
+== uses ==
+000:  5:16 | int                 | type int
+001:  8:19 | int                 | type int
+002: 11:28 | int                 | type int
+003: 15: 2 | addInt0             | func main.addInt0()
+004: 16: 2 | addInt1             | func main.addInt1(i int)
+005: 17: 2 | addInt2             | func main.addInt2(i int, j int)
+006: 18: 2 | addInt3             | var main.addInt3 func(i int, j int, k int)
+007: 19:12 | string              | type string
+008: 19:20 | string              | type string
+009: 20:10 | a                   | var a string
+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`)
+}