Skip to content

Commit

Permalink
Merge pull request #1851 from visualfc/record_overloadfuncdecl
Browse files Browse the repository at this point in the history
cl: record ast.OverloadFuncDecl
  • Loading branch information
xushiwei authored Apr 10, 2024
2 parents 570665d + e2890c6 commit 444d455
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 5 deletions.
20 changes: 17 additions & 3 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand All @@ -1091,20 +1097,27 @@ 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)
onames = append(onames, "") // const Gopo_xxx = "xxxInt,,xxxFloat"
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,
})
Expand Down Expand Up @@ -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 (
Expand Down
42 changes: 40 additions & 2 deletions cl/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cl

import (
"go/types"
"strings"

"github.com/goplus/gogen"
"github.com/goplus/gop/ast"
Expand All @@ -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.
Expand Down
160 changes: 160 additions & 0 deletions x/typesutil/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
}

0 comments on commit 444d455

Please sign in to comment.