Skip to content

Commit

Permalink
Merge pull request #1865 from visualfc/overload_check
Browse files Browse the repository at this point in the history
cl: preloadFile ast.OverloadFuncDecl handle error
  • Loading branch information
xushiwei authored Apr 22, 2024
2 parents 297ad04 + 3fbc454 commit 64a3001
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 116 deletions.
89 changes: 4 additions & 85 deletions cl/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,85 +155,6 @@ func TestErrStringLit(t *testing.T) {
func TestErrPreloadFile(t *testing.T) {
pkg := gogen.NewPackage("", "foo", goxConf)
ctx := &blockCtx{pkgCtx: &pkgCtx{}}
t.Run("overloadName", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - can't overload operator ++\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
overloadName(&ast.Ident{}, "++", true)
})
t.Run("checkOverloadFunc", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - cl.preloadFile OverloadFuncDecl: checkOverloadFunc\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
checkOverloadFunc(&ast.OverloadFuncDecl{
Recv: &ast.FieldList{},
})
})
t.Run("checkOverloadMethod", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - cl.preloadFile OverloadFuncDecl: checkOverloadMethod\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
checkOverloadMethod(&ast.OverloadFuncDecl{})
})
t.Run("checkOverloadMethodRecvType1", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - checkOverloadMethodRecvType: bar\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
checkOverloadMethodRecvType(&ast.Ident{Name: "foo"}, &ast.Ident{Name: "bar"})
})
t.Run("checkOverloadMethodRecvType2", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - checkOverloadMethodRecvType: &{0 INT 123 <nil>}\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
expr := &ast.BasicLit{Kind: token.INT, Value: "123"}
checkOverloadMethodRecvType(&ast.Ident{Name: "foo"}, expr)
})
t.Run("OverloadFuncDecl: invalid recv", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - cl.preloadFile OverloadFuncDecl: invalid recv\n" {
t.Fatal("TestErrPreloadFile:", e)
}
}()
decls := []ast.Decl{
&ast.OverloadFuncDecl{
Name: &ast.Ident{Name: "add"},
Funcs: []ast.Expr{
&ast.FuncLit{},
},
Recv: &ast.FieldList{List: []*ast.Field{
{Type: &ast.StarExpr{}},
}},
},
}
preloadFile(pkg, ctx, &ast.File{Decls: decls}, "", true)
})
t.Run("OverloadFuncDecl: unknown func", func(t *testing.T) {
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, &ast.File{Decls: decls}, "", true)
})
t.Run("unknown decl", func(t *testing.T) {
defer func() {
if e := recover(); e == nil || e != "TODO - cl.preloadFile: unknown decl - *ast.BadDecl\n" {
Expand Down Expand Up @@ -391,14 +312,12 @@ func TestFileClassType(t *testing.T) {
}

func TestErrMultiStarRecv(t *testing.T) {
defer func() {
if e := recover(); e == nil {
t.Fatal("TestErrMultiStarRecv: no panic?")
}
}()
getRecvType(&ast.StarExpr{
_, _, ok := getRecvType(&ast.StarExpr{
X: &ast.StarExpr{},
})
if ok {
t.Fatal("TestErrMultiStarRecv: no error?")
}
}

func TestErrAssign(t *testing.T) {
Expand Down
62 changes: 37 additions & 25 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,8 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
if d.Recv != nil {
otyp, ok := d.Recv.List[0].Type.(*ast.Ident)
if !ok {
log.Panicln("TODO - cl.preloadFile OverloadFuncDecl: invalid recv")
ctx.handleErrorf(d.Recv.List[0].Type.Pos(), "invalid recv type %v", ctx.LoadExpr(d.Recv.List[0].Type))
break
}
recv = otyp
if ctx.rec != nil {
Expand All @@ -1090,19 +1091,31 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
onames := make([]string, 0, 4)
exov := false
name := d.Name
LoopFunc:
for idx, fn := range d.Funcs {
switch expr := fn.(type) {
case *ast.Ident:
checkOverloadFunc(d)
if d.Recv != nil && !d.Operator {
ctx.handleErrorf(expr.Pos(), "invalid method %v", ctx.LoadExpr(expr))
break LoopFunc
}
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)
rtyp := checkOverloadMethodRecvType(recv, expr.X)
if d.Recv == nil {
ctx.handleErrorf(expr.Pos(), "invalid func %v", ctx.LoadExpr(expr))
break LoopFunc
}
rtyp, ok := checkOverloadMethodRecvType(recv, expr.X)
if !ok {
ctx.handleErrorf(expr.Pos(), "invalid recv type %v", ctx.LoadExpr(expr.X))
break LoopFunc
}

onames = append(onames, "."+expr.Sel.Name)
ctx.lbinames = append(ctx.lbinames, recv)
exov = true
Expand All @@ -1111,7 +1124,10 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
ctx.rec.Refer(expr.Sel, rtyp.Name+"."+expr.Sel.Name)
}
case *ast.FuncLit:
checkOverloadFunc(d)
if d.Recv != nil && !d.Operator {
ctx.handleErrorf(expr.Pos(), "invalid method %v", ctx.LoadExpr(expr))
break LoopFunc
}
name1 := overloadFuncName(name.Name, idx)
onames = append(onames, "") // const Gopo_xxx = "xxxInt,,xxxFloat"
ctx.lbinames = append(ctx.lbinames, name1)
Expand All @@ -1122,11 +1138,16 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
Body: expr.Body,
})
default:
log.Panicf("TODO - cl.preloadFile OverloadFuncDecl: unknown func - %T\n", expr)
ctx.handleErrorf(expr.Pos(), "unknown func %v", ctx.LoadExpr(expr))
break LoopFunc
}
}
if exov { // need Gopo_xxx
oname := overloadName(recv, name.Name, d.Operator)
oname, err := overloadName(recv, name.Name, d.Operator)
if err != nil {
ctx.handleErrorf(name.NamePos, "%v", err)
break
}
oval := strings.Join(onames, ",")
preloadConst(&ast.GenDecl{
Doc: d.Doc,
Expand All @@ -1147,25 +1168,16 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
}
}

func checkOverloadFunc(d *ast.OverloadFuncDecl) {
if d.Recv != nil && !d.Operator {
log.Panicln("TODO - cl.preloadFile OverloadFuncDecl: checkOverloadFunc")
}
}

func checkOverloadMethod(d *ast.OverloadFuncDecl) {
if d.Recv == nil {
log.Panicln("TODO - cl.preloadFile OverloadFuncDecl: checkOverloadMethod")
func checkOverloadMethodRecvType(ot *ast.Ident, recv ast.Expr) (*ast.Ident, bool) {
rtyp, _, ok := getRecvType(recv)
if !ok {
return nil, false
}
}

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 nil, false
}
return rt
return rt, true
}

const (
Expand All @@ -1176,12 +1188,12 @@ func overloadFuncName(name string, idx int) string {
return name + "__" + indexTable[idx:idx+1]
}

func overloadName(recv *ast.Ident, name string, isOp bool) string {
func overloadName(recv *ast.Ident, name string, isOp bool) (string, error) {
if isOp {
if oname, ok := binaryGopNames[name]; ok {
name = oname
} else {
log.Panicln("TODO - can't overload operator", name)
return "", fmt.Errorf("invalid overload operator %v", name)
}
}
sep := "_"
Expand All @@ -1192,7 +1204,7 @@ func overloadName(recv *ast.Ident, name string, isOp bool) string {
if recv != nil {
typ = recv.Name + sep
}
return "Gopo" + sep + typ + name
return "Gopo" + sep + typ + name, nil
}

func staticMethod(tname, name string) string {
Expand Down
43 changes: 43 additions & 0 deletions cl/error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1063,3 +1063,46 @@ func _() {
}
`)
}

func TestOverloadFuncDecl(t *testing.T) {
codeErrorTest(t, "bar.gop:3:2: invalid func (foo).mulInt", `
func mul = (
(foo).mulInt
)
`)
codeErrorTest(t, "bar.gop:2:7: invalid recv type *foo", `
func (*foo).mul = (
(foo).mulInt
)
`)
codeErrorTest(t, "bar.gop:3:2: invalid recv type (foo2)", `
func (foo).mul = (
(foo2).mulInt
)
`)
codeErrorTest(t, "bar.gop:3:2: invalid method mulInt", `
func (foo).mul = (
mulInt
)
`)
codeErrorTest(t, "bar.gop:3:2: invalid recv type (**foo)", `
func (foo).mul = (
(**foo).mulInt
)
`)
codeErrorTest(t, `bar.gop:3:9: unknown func ("ok")`, `
func mul = (
println("ok")
)
`)
codeErrorTest(t, "bar.gop:3:2: invalid method func(){}", `
func (foo).mul = (
func(){}
)
`)
codeErrorTest(t, "bar.gop:2:12: invalid overload operator ++", `
func (foo).++ = (
mulInt
)
`)
}
4 changes: 2 additions & 2 deletions cl/func_type_and_var.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func toRecv(ctx *blockCtx, recv *ast.FieldList) *types.Var {
if len(v.Names) > 0 {
name = v.Names[0].Name
}
typ, star := getRecvType(v.Type)
typ, star, _ := getRecvType(v.Type)
id, ok := typ.(*ast.Ident)
if !ok {
panic("TODO: getRecvType")
Expand All @@ -56,7 +56,7 @@ func toRecv(ctx *blockCtx, recv *ast.FieldList) *types.Var {
}

func getRecvTypeName(ctx *pkgCtx, recv *ast.FieldList, handleErr bool) (string, bool) {
typ, _ := getRecvType(recv.List[0].Type)
typ, _, _ := getRecvType(recv.List[0].Type)
if t, ok := typ.(*ast.Ident); ok {
return t.Name, true
}
Expand Down
10 changes: 6 additions & 4 deletions cl/typeparams.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,17 @@ func initType(ctx *blockCtx, named *types.Named, spec *ast.TypeSpec) {
named.SetUnderlying(typ)
}

func getRecvType(typ ast.Expr) (ast.Expr, bool) {
var ptr bool
func getRecvType(expr ast.Expr) (typ ast.Expr, ptr bool, ok bool) {
typ = expr
L:
for {
switch t := typ.(type) {
case *ast.ParenExpr:
typ = t.X
case *ast.StarExpr:
if ptr {
panic("TODO: getRecvType")
ok = false
return
}
ptr = true
typ = t.X
Expand All @@ -184,7 +185,8 @@ L:
case *ast.IndexListExpr:
typ = t.X
}
return typ, ptr
ok = true
return
}

func collectTypeParams(ctx *blockCtx, list *ast.FieldList) []*types.TypeParam {
Expand Down

0 comments on commit 64a3001

Please sign in to comment.