Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cl: preloadFile ast.OverloadFuncDecl handle error #1865

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading