Repository: goplus/gop
Pull request #1865 (2024-04-22 02:54:40)

cl: preloadFile ast.OverloadFuncDecl handle error


Patch:
diff --git a/cl/compile.go b/cl/compile.go
index 8e11e163..3ed60aae 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -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 {
@@ -1090,10 +1091,14 @@ 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
@@ -1101,8 +1106,16 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
 						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
@@ -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)
@@ -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,
@@ -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 (
@@ -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 := "_"
@@ -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 {
diff --git a/cl/func_type_and_var.go b/cl/func_type_and_var.go
index 31b2b357..637359b6 100644
--- a/cl/func_type_and_var.go
+++ b/cl/func_type_and_var.go
@@ -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")
@@ -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
 	}
diff --git a/cl/typeparams.go b/cl/typeparams.go
index aeb82608..95a3df90 100644
--- a/cl/typeparams.go
+++ b/cl/typeparams.go
@@ -161,8 +161,8 @@ 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) {
@@ -170,7 +170,8 @@ L:
 			typ = t.X
 		case *ast.StarExpr:
 			if ptr {
-				panic("TODO: getRecvType")
+				ok = false
+				return
 			}
 			ptr = true
 			typ = t.X
@@ -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 {


Test patch:
diff --git a/cl/builtin_test.go b/cl/builtin_test.go
index 3cebd7f4..c73703ae 100644
--- a/cl/builtin_test.go
+++ b/cl/builtin_test.go
@@ -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" {
@@ -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) {
diff --git a/cl/error_msg_test.go b/cl/error_msg_test.go
index ddc65610..586b1222 100644
--- a/cl/error_msg_test.go
+++ b/cl/error_msg_test.go
@@ -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
+)
+`)
+}