diff --git a/cl/compile.go b/cl/compile.go index 9b4b2b3d6..8e11e1631 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -512,6 +512,9 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gogen.Packag if conf.Recorder != nil { rec = newRecorder(conf.Recorder) confGox.Recorder = rec + defer func() { + rec.Complete(p.Types.Scope()) + }() } if enableRecover { defer func() { @@ -1080,6 +1083,9 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge log.Panicln("TODO - cl.preloadFile OverloadFuncDecl: invalid recv") } recv = otyp + if ctx.rec != nil { + ctx.rec.Refer(recv, recv.Name) + } } onames := make([]string, 0, 4) exov := false @@ -1091,12 +1097,19 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge onames = append(onames, expr.Name) ctx.lbinames = append(ctx.lbinames, expr.Name) exov = true + if ctx.rec != nil { + ctx.rec.Refer(expr, expr.Name) + } case *ast.SelectorExpr: checkOverloadMethod(d) - checkOverloadMethodRecvType(recv, expr.X) + rtyp := checkOverloadMethodRecvType(recv, expr.X) onames = append(onames, "."+expr.Sel.Name) 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) + } case *ast.FuncLit: checkOverloadFunc(d) name1 := overloadFuncName(name.Name, idx) @@ -1104,7 +1117,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge ctx.lbinames = append(ctx.lbinames, name1) preloadFuncDecl(&ast.FuncDecl{ Doc: d.Doc, - Name: &ast.Ident{NamePos: name.NamePos, Name: name1}, + Name: &ast.Ident{NamePos: expr.Pos(), Name: name1}, Type: expr.Type, Body: expr.Body, }) @@ -1146,12 +1159,13 @@ func checkOverloadMethod(d *ast.OverloadFuncDecl) { } } -func checkOverloadMethodRecvType(ot *ast.Ident, recv ast.Expr) { +func checkOverloadMethodRecvType(ot *ast.Ident, recv ast.Expr) *ast.Ident { rtyp, _ := getRecvType(recv) rt, ok := rtyp.(*ast.Ident) if !ok || ot.Name != rt.Name { log.Panicln("TODO - checkOverloadMethodRecvType:", recv) } + return rt } const ( diff --git a/cl/recorder.go b/cl/recorder.go index beccc1b95..4ac4c6277 100644 --- a/cl/recorder.go +++ b/cl/recorder.go @@ -18,6 +18,7 @@ package cl import ( "go/types" + "strings" "github.com/goplus/gogen" "github.com/goplus/gop/ast" @@ -28,12 +29,49 @@ import ( type goxRecorder struct { Recorder - types map[ast.Expr]types.TypeAndValue + types map[ast.Expr]types.TypeAndValue + refers map[string][]*ast.Ident } func newRecorder(rec Recorder) *goxRecorder { types := make(map[ast.Expr]types.TypeAndValue) - return &goxRecorder{rec, types} + refers := make(map[string][]*ast.Ident) + return &goxRecorder{rec, types, refers} +} + +// 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) +} + +// Complete computes the types record. +func (p *goxRecorder) Complete(scope *types.Scope) { + for name, idents := range p.refers { + pos := strings.Index(name, ".") + if pos == -1 { + if obj := scope.Lookup(name); obj != nil { + for _, id := range idents { + p.Use(id, obj) + } + } + continue + } + if obj := scope.Lookup(name[:pos]); 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() == name[pos+1:] { + for _, id := range idents { + p.Use(id, m) + } + break + } + } + } + } + } + p.types = nil + p.refers = nil } // Member maps identifiers to the objects they denote. diff --git a/x/typesutil/info_test.go b/x/typesutil/info_test.go index 07b8dfdd0..d70fbe679 100644 --- a/x/typesutil/info_test.go +++ b/x/typesutil/info_test.go @@ -1985,3 +1985,163 @@ func (p *N) Test__1(n int) { t.Fatal("check TyOverloadMethod failed") } } + +func TestGopOverloadUses(t *testing.T) { + testGopInfo(t, ` +func MulInt(a, b int) int { + return a * b +} + +func MulFloat(a, b float64) float64 { + return a * b +} + +func Mul = ( + MulInt + MulFloat + func(x, y, z int) int { + return x * y * z + } +) + +Mul 100,200 +Mul 100,200,300 +`, ``, `== types == +000: 0: 0 | "MulInt,MulFloat," *ast.BasicLit | value : untyped string = "MulInt,MulFloat," | constant +001: 2:18 | int *ast.Ident | type : int | type +002: 2:23 | int *ast.Ident | type : int | type +003: 3: 9 | a *ast.Ident | var : int | variable +004: 3: 9 | a * b *ast.BinaryExpr | value : int | value +005: 3:13 | b *ast.Ident | var : int | variable +006: 6:20 | float64 *ast.Ident | type : float64 | type +007: 6:29 | float64 *ast.Ident | type : float64 | type +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 +== defs == +000: 0: 0 | Gopo_Mul | const main.Gopo_Mul untyped string +001: 2: 6 | MulInt | func main.MulInt(a int, b int) int +002: 2:13 | a | var a int +003: 2:16 | b | var b int +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() +== uses == +000: 2:18 | int | type int +001: 2:23 | int | type int +002: 3: 9 | a | var a int +003: 3:13 | b | var b int +004: 6:20 | float64 | type float64 +005: 6:29 | float64 | type float64 +006: 7: 9 | a | var a float64 +007: 7:13 | b | var b float64 +008: 11: 2 | MulInt | func main.MulInt(a int, b int) int +009: 12: 2 | MulFloat | func main.MulFloat(a float64, b float64) float64 +010: 13:15 | int | type int +011: 13:20 | int | type int +012: 14:10 | x | var x int +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`) + + testGopInfo(t, ` +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 +) + +var a, b *foo +var c = a.mul(100) +var d = a.mul(c) +`, ``, `== types == +000: 0: 0 | ".mulInt,.mulFoo" *ast.BasicLit | value : untyped string = ".mulInt,.mulFoo" | constant +001: 2:10 | struct { +} *ast.StructType | type : struct{} | type +002: 5:10 | foo *ast.Ident | type : main.foo | type +003: 5:24 | int *ast.Ident | type : int | type +004: 5:29 | *foo *ast.StarExpr | type : *main.foo | type +005: 5:30 | foo *ast.Ident | type : main.foo | type +006: 6: 9 | a *ast.Ident | var : *main.foo | variable +007: 9:10 | foo *ast.Ident | type : main.foo | type +008: 9:24 | *foo *ast.StarExpr | type : *main.foo | type +009: 9:25 | foo *ast.Ident | type : main.foo | type +010: 9:30 | *foo *ast.StarExpr | type : *main.foo | type +011: 9:31 | foo *ast.Ident | type : main.foo | type +012: 10: 9 | a *ast.Ident | var : *main.foo | variable +013: 18:10 | *foo *ast.StarExpr | type : *main.foo | type +014: 18:11 | foo *ast.Ident | type : main.foo | type +015: 19: 9 | a *ast.Ident | var : *main.foo | variable +016: 19: 9 | a.mul *ast.SelectorExpr | value : func(b int) *main.foo | value +017: 19: 9 | a.mul(100) *ast.CallExpr | value : *main.foo | value +018: 19:15 | 100 *ast.BasicLit | value : untyped int = 100 | constant +019: 20: 9 | a *ast.Ident | var : *main.foo | variable +020: 20: 9 | a.mul *ast.SelectorExpr | value : func(b *main.foo) *main.foo | value +021: 20: 9 | a.mul(c) *ast.CallExpr | value : *main.foo | value +022: 20:15 | c *ast.Ident | var : *main.foo | variable +== defs == +000: 0: 0 | Gopo_foo_mul | const main.Gopo_foo_mul untyped string +001: 2: 6 | foo | type main.foo struct{} +002: 5: 7 | a | var a *main.foo +003: 5:15 | mulInt | func (*main.foo).mulInt(b int) *main.foo +004: 5:22 | b | var b int +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 +== uses == +000: 5:10 | foo | type main.foo struct{} +001: 5:24 | int | type int +002: 5:30 | foo | type main.foo struct{} +003: 6: 9 | a | var a *main.foo +004: 9:10 | foo | type main.foo struct{} +005: 9:25 | foo | type main.foo struct{} +006: 9:31 | foo | type main.foo struct{} +007: 10: 9 | a | var a *main.foo +008: 13: 7 | foo | type main.foo struct{} +009: 14: 3 | foo | type main.foo struct{} +010: 14: 8 | mulInt | func (*main.foo).mulInt(b int) *main.foo +011: 15: 3 | foo | type main.foo struct{} +012: 15: 8 | mulFoo | func (*main.foo).mulFoo(b *main.foo) *main.foo +013: 18:11 | foo | type main.foo struct{} +014: 19: 9 | a | var main.a *main.foo +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`) +}