Repository: goplus/gop
Pull request #1475 (2023-10-20 09:51:43)

gox: pkg.TryImport; typesutil.SetDebug


Patch:
diff --git a/cl/builtin.go b/cl/builtin.go
index a97ecf34..3058e246 100644
--- a/cl/builtin.go
+++ b/cl/builtin.go
@@ -41,39 +41,51 @@ func initBuiltinFns(builtin *types.Package, scope *types.Scope, pkg *gox.PkgRef,
 
 func initBuiltin(pkg *gox.Package, builtin *types.Package, os, fmt, ng, iox, buil *gox.PkgRef) {
 	scope := builtin.Scope()
-	typs := []string{"bigint", "bigrat", "bigfloat"}
-	for _, typ := range typs {
-		name := string(typ[0]-('a'-'A')) + typ[1:]
-		scope.Insert(types.NewTypeName(token.NoPos, builtin, typ, ng.Ref(name).Type()))
+	if ng != nil {
+		typs := []string{"bigint", "bigrat", "bigfloat"}
+		for _, typ := range typs {
+			name := string(typ[0]-('a'-'A')) + typ[1:]
+			scope.Insert(types.NewTypeName(token.NoPos, builtin, typ, ng.Ref(name).Type()))
+		}
+		scope.Insert(types.NewTypeName(token.NoPos, builtin, "uint128", ng.Ref("Uint128").Type()))
+		scope.Insert(types.NewTypeName(token.NoPos, builtin, "int128", ng.Ref("Int128").Type()))
+	}
+	if fmt != nil {
+		initBuiltinFns(builtin, scope, fmt, []string{
+			"print", "println", "printf", "errorf",
+			"fprint", "fprintln", "fprintf",
+			"sprint", "sprintln", "sprintf",
+		})
+	}
+	if os != nil {
+		initBuiltinFns(builtin, scope, os, []string{
+			"open", "create",
+		})
+	}
+	if iox != nil {
+		initBuiltinFns(builtin, scope, iox, []string{
+			"lines",
+		})
+		scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "blines", iox.Ref("BLines")))
+	}
+	if buil != nil {
+		scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "newRange", buil.Ref("NewRange__0")))
 	}
-	initBuiltinFns(builtin, scope, fmt, []string{
-		"print", "println", "printf", "errorf",
-		"fprint", "fprintln", "fprintf",
-		"sprint", "sprintln", "sprintf",
-	})
-	initBuiltinFns(builtin, scope, os, []string{
-		"open", "create",
-	})
-	initBuiltinFns(builtin, scope, iox, []string{
-		"lines",
-	})
-	scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "blines", iox.Ref("BLines")))
-	scope.Insert(gox.NewOverloadFunc(token.NoPos, builtin, "newRange", buil.Ref("NewRange__0")))
-	scope.Insert(types.NewTypeName(token.NoPos, builtin, "uint128", ng.Ref("Uint128").Type()))
-	scope.Insert(types.NewTypeName(token.NoPos, builtin, "int128", ng.Ref("Int128").Type()))
 	scope.Insert(types.NewTypeName(token.NoPos, builtin, "any", gox.TyEmptyInterface))
 }
 
 func newBuiltinDefault(pkg *gox.Package, conf *gox.Config) *types.Package {
 	builtin := types.NewPackage("", "")
-	fmt := pkg.Import("fmt")
-	os := pkg.Import("os")
-	buil := pkg.Import("github.com/goplus/gop/builtin")
-	ng := pkg.Import("github.com/goplus/gop/builtin/ng")
-	iox := pkg.Import("github.com/goplus/gop/builtin/iox")
-	pkg.Import("strconv")
-	pkg.Import("strings")
-	initMathBig(pkg, conf, ng)
+	fmt := pkg.TryImport("fmt")
+	os := pkg.TryImport("os")
+	buil := pkg.TryImport("github.com/goplus/gop/builtin")
+	ng := pkg.TryImport("github.com/goplus/gop/builtin/ng")
+	iox := pkg.TryImport("github.com/goplus/gop/builtin/iox")
+	pkg.TryImport("strconv")
+	pkg.TryImport("strings")
+	if ng != nil {
+		initMathBig(pkg, conf, ng)
+	}
 	initBuiltin(pkg, builtin, os, fmt, ng, iox, buil)
 	gox.InitBuiltin(pkg, builtin, conf)
 	return builtin
diff --git a/cl/c.go b/cl/c.go
index 39b4c989..b203bbb2 100644
--- a/cl/c.go
+++ b/cl/c.go
@@ -60,8 +60,7 @@ func c2goBase(base string) string {
 func loadC2goPkg(ctx *blockCtx, realPath string, src *ast.BasicLit) *gox.PkgRef {
 	cpkg, err := ctx.cpkgs.Import(realPath)
 	if err != nil {
-		pos := ctx.Position(src.Pos())
-		ctx.handleCodeErrorf(&pos,
+		ctx.handleErrorf(src.Pos(),
 			"%v not found or not a valid C package (c2go.a.pub file not found).\n", realPath)
 		return nil
 	}
diff --git a/cl/compile.go b/cl/compile.go
index 1ce82085..f4f35968 100644
--- a/cl/compile.go
+++ b/cl/compile.go
@@ -36,8 +36,10 @@ import (
 	"github.com/qiniu/x/errors"
 )
 
+type dbgFlags int
+
 const (
-	DbgFlagLoad = 1 << iota
+	DbgFlagLoad dbgFlags = 1 << iota
 	DbgFlagLookup
 	DbgFlagAll = DbgFlagLoad | DbgFlagLookup
 )
@@ -55,7 +57,7 @@ func SetDisableRecover(disableRecover bool) {
 	enableRecover = !disableRecover
 }
 
-func SetDebug(flags int) {
+func SetDebug(flags dbgFlags) {
 	debugLoad = (flags & DbgFlagLoad) != 0
 	debugLookup = (flags & DbgFlagLookup) != 0
 }
@@ -271,13 +273,9 @@ func initLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name strin
 		return
 	}
 	if old, ok := syms[name]; ok {
-		var pos token.Position
-		if start != token.NoPos {
-			pos = ctx.Position(start)
-		}
 		oldpos := ctx.Position(old.pos())
-		ctx.handleCodeErrorf(
-			&pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
+		ctx.handleErrorf(
+			start, "%s redeclared in this block\n\tprevious declaration at %v", name, oldpos)
 		return
 	}
 	syms[name] = &baseLoader{start: start, fn: fn}
@@ -305,8 +303,8 @@ func getTypeLoader(ctx *pkgCtx, syms map[string]loader, start token.Pos, name st
 			if ld.start == token.NoPos {
 				ld.start = start
 			} else {
-				pos := ctx.Position(start)
-				ctx.handleCodeErrorf(&pos, "%s redeclared in this block\n\tprevious declaration at %v",
+				ctx.handleErrorf(
+					start, "%s redeclared in this block\n\tprevious declaration at %v",
 					name, ctx.Position(ld.start))
 			}
 			return ld
@@ -414,6 +412,11 @@ func (p *pkgCtx) handleCodeErrorf(pos *token.Position, format string, args ...in
 	p.handleErr(newCodeErrorf(pos, format, args...))
 }
 
+func (p *pkgCtx) handleErrorf(start token.Pos, format string, args ...interface{}) {
+	pos := p.Position(start)
+	p.handleErr(newCodeErrorf(&pos, format, args...))
+}
+
 func (p *pkgCtx) handleErr(err error) {
 	p.errs = append(p.errs, err)
 }
diff --git a/cl/func_type_and_var.go b/cl/func_type_and_var.go
index 52b69f94..32191348 100644
--- a/cl/func_type_and_var.go
+++ b/cl/func_type_and_var.go
@@ -115,7 +115,8 @@ func toType(ctx *blockCtx, typ ast.Expr) types.Type {
 							break
 						}
 					}
-					panic(ctx.newCodeErrorf(pos, "cannot use generic type %v without instantiation", t.Obj().Type()))
+					ctx.handleErrorf(pos, "cannot use generic type %v without instantiation", t.Obj().Type())
+					return types.Typ[types.Invalid]
 				}
 			}
 		}
@@ -182,9 +183,11 @@ func toExternalType(ctx *blockCtx, v *ast.SelectorExpr) types.Type {
 		if t, ok := o.(*types.TypeName); ok {
 			return t.Type()
 		}
-		panic(ctx.newCodeErrorf(v.Pos(), "%s.%s is not a type", name, v.Sel.Name))
+		ctx.handleErrorf(v.Pos(), "%s.%s is not a type", name, v.Sel.Name)
+	} else {
+		ctx.handleErrorf(v.Pos(), "undefined: %s", name)
 	}
-	panic(ctx.newCodeErrorf(v.Pos(), "undefined: %s", name))
+	return types.Typ[types.Invalid]
 }
 
 /*-----------------------------------------------------------------------------
@@ -204,7 +207,8 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) types.Type {
 	}
 	v, builtin := lookupType(ctx, ident.Name)
 	if isBuiltin(builtin) {
-		panic(ctx.newCodeErrorf(ident.Pos(), "use of builtin %s not in function call", ident.Name))
+		ctx.handleErrorf(ident.Pos(), "use of builtin %s not in function call", ident.Name)
+		return types.Typ[types.Invalid]
 	}
 	if t, ok := v.(*types.TypeName); ok {
 		return t.Type()
@@ -214,7 +218,8 @@ func toIdentType(ctx *blockCtx, ident *ast.Ident) types.Type {
 			return t.Type()
 		}
 	}
-	panic(ctx.newCodeErrorf(ident.Pos(), "%s is not a type", ident.Name))
+	ctx.handleErrorf(ident.Pos(), "%s is not a type", ident.Name)
+	return types.Typ[types.Invalid]
 }
 
 // TODO: optimization
@@ -255,8 +260,8 @@ func (p *checkRedecl) chkRedecl(ctx *blockCtx, name string, pos token.Pos) bool
 		return false
 	}
 	if opos, ok := p.names[name]; ok {
-		npos := ctx.Position(pos)
-		ctx.handleCodeErrorf(&npos, "%v redeclared\n\t%v other declaration of %v",
+		ctx.handleErrorf(
+			pos, "%v redeclared\n\t%v other declaration of %v",
 			name, ctx.Position(opos), name)
 		return true
 	}
diff --git a/cl/stmt.go b/cl/stmt.go
index 77183fc4..121c2898 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -559,11 +559,15 @@ func compileTypeSwitchStmt(ctx *blockCtx, v *ast.TypeSwitchStmt) {
 			for t, other := range seen {
 				if T == nil && t == nil || T != nil && t != nil && types.Identical(T, t) {
 					haserr = true
-					pos := ctx.Position(citem.Pos())
+					pos := citem.Pos()
 					if T == types.Typ[types.UntypedNil] {
-						ctx.handleCodeErrorf(&pos, "multiple nil cases in type switch (first at %v)", ctx.Position(other.Pos()))
+						ctx.handleErrorf(
+							pos, "multiple nil cases in type switch (first at %v)",
+							ctx.Position(other.Pos()))
 					} else {
-						ctx.handleCodeErrorf(&pos, "duplicate case %s in type switch\n\tprevious case at %v", T, ctx.Position(other.Pos()))
+						ctx.handleErrorf(
+							pos, "duplicate case %s in type switch\n\tprevious case at %v",
+							T, ctx.Position(other.Pos()))
 					}
 				}
 			}
@@ -573,8 +577,7 @@ func compileTypeSwitchStmt(ctx *blockCtx, v *ast.TypeSwitchStmt) {
 		}
 		if c.List == nil {
 			if firstDefault != nil {
-				pos := ctx.Position(c.Pos())
-				ctx.handleCodeErrorf(&pos, "multiple defaults in type switch (first at %v)", ctx.Position(firstDefault.Pos()))
+				ctx.handleErrorf(c.Pos(), "multiple defaults in type switch (first at %v)", ctx.Position(firstDefault.Pos()))
 			} else {
 				firstDefault = c
 			}
@@ -648,8 +651,7 @@ func compileSwitchStmt(ctx *blockCtx, v *ast.SwitchStmt) {
 		}
 		if c.List == nil {
 			if firstDefault != nil {
-				pos := ctx.Position(c.Pos())
-				ctx.handleCodeErrorf(&pos, "multiple defaults in switch (first at %v)", ctx.Position(firstDefault.Pos()))
+				ctx.handleErrorf(c.Pos(), "multiple defaults in switch (first at %v)", ctx.Position(firstDefault.Pos()))
 			} else {
 				firstDefault = c
 			}
@@ -735,8 +737,7 @@ func compileBranchStmt(ctx *blockCtx, v *ast.BranchStmt) {
 	case token.CONTINUE:
 		ctx.cb.Continue(getLabel(ctx, label))
 	case token.FALLTHROUGH:
-		pos := ctx.Position(v.Pos())
-		ctx.handleCodeErrorf(&pos, "fallthrough statement out of place")
+		ctx.handleErrorf(v.Pos(), "fallthrough statement out of place")
 	default:
 		panic("unknown branch statement")
 	}
@@ -747,8 +748,7 @@ func getLabel(ctx *blockCtx, label *ast.Ident) *gox.Label {
 		if l, ok := ctx.cb.LookupLabel(label.Name); ok {
 			return l
 		}
-		pos := ctx.Position(label.Pos())
-		ctx.handleCodeErrorf(&pos, "label %v is not defined", label.Name)
+		ctx.handleErrorf(label.Pos(), "label %v is not defined", label.Name)
 	}
 	return nil
 }
diff --git a/x/build/build.go b/x/build/build.go
index 9373c616..980e6064 100644
--- a/x/build/build.go
+++ b/x/build/build.go
@@ -65,14 +65,14 @@ type Package struct {
 
 func (p *Package) ToSource() ([]byte, error) {
 	var buf bytes.Buffer
-	if err := gox.WriteTo(&buf, p.Pkg); err != nil {
+	if err := p.Pkg.WriteTo(&buf); err != nil {
 		return nil, err
 	}
 	return buf.Bytes(), nil
 }
 
 func (p *Package) ToAst() *goast.File {
-	return gox.ASTFile(p.Pkg)
+	return p.Pkg.ASTFile()
 }
 
 func ClassKind(fname string) (isProj, ok bool) {
diff --git a/x/typesutil/check.go b/x/typesutil/check.go
index 6b6e2eb1..8febfaf8 100644
--- a/x/typesutil/check.go
+++ b/x/typesutil/check.go
@@ -19,12 +19,42 @@ package typesutil
 import (
 	goast "go/ast"
 	"go/types"
+	"path/filepath"
+	"strings"
 
 	"github.com/goplus/gop/ast"
 	"github.com/goplus/gop/cl"
 	"github.com/goplus/gop/token"
+	"github.com/qiniu/x/log"
 )
 
+// -----------------------------------------------------------------------------
+
+type dbgFlags int
+
+const (
+	DbgFlagVerbose dbgFlags = 1 << iota
+	DbgFlagPrintError
+	DbgFlagDisableRecover
+	DbgFlagDefault = DbgFlagVerbose | DbgFlagPrintError
+	DbgFlagAll     = DbgFlagDefault | DbgFlagDisableRecover
+)
+
+var (
+	debugVerbose  bool
+	debugPrintErr bool
+)
+
+func SetDebug(flags dbgFlags) {
+	debugVerbose = (flags & DbgFlagVerbose) != 0
+	debugPrintErr = (flags & DbgFlagPrintError) != 0
+	if (flags & DbgFlagDisableRecover) != 0 {
+		cl.SetDisableRecover(true)
+	}
+}
+
+// -----------------------------------------------------------------------------
+
 type Project = cl.Project
 
 type Config struct {
@@ -81,12 +111,20 @@ func (p *Checker) Files(goFiles []*goast.File, gopFiles []*ast.File) error {
 	gopfs := make(map[string]*ast.File)
 	for _, goFile := range goFiles {
 		f := fset.File(goFile.Pos())
-		gofs[f.Name()] = goFile
+		file := f.Name()
+		fname := filepath.Base(file)
+		if strings.HasPrefix(fname, "gop_autogen") {
+			continue
+		}
+		gofs[file] = goFile
 	}
 	for _, gopFile := range gopFiles {
 		f := fset.File(gopFile.Pos())
 		gopfs[f.Name()] = gopFile
 	}
+	if debugVerbose {
+		log.Println("typesutil.Check:", pkgTypes.Path(), "gopFiles =", len(gopfs), "goFiles =", len(gofs))
+	}
 	pkg := &ast.Package{
 		Name:    pkgTypes.Name(),
 		Files:   gopfs,
@@ -105,5 +143,11 @@ func (p *Checker) Files(goFiles []*goast.File, gopFiles []*ast.File) error {
 		NoAutoGenMain:  true,
 		NoSkipConstant: true,
 	})
+	if debugPrintErr {
+		if err != nil {
+			log.Println("typesutil.Check err:", err)
+			log.SingleStack()
+		}
+	}
 	return err
 }
diff --git a/x/typesutil/typesutil.go b/x/typesutil/gopinfo.go
similarity index 97%
rename from x/typesutil/typesutil.go
rename to x/typesutil/gopinfo.go
index 4f357561..0648ec4d 100644
--- a/x/typesutil/typesutil.go
+++ b/x/typesutil/gopinfo.go
@@ -20,6 +20,7 @@ import (
 	"go/types"
 
 	"github.com/goplus/gop/ast"
+	"github.com/qiniu/x/log"
 )
 
 // -----------------------------------------------------------------------------
@@ -210,6 +211,9 @@ func (info gopRecorder) Instantiate(id *ast.Ident, inst types.Instance) {
 //
 // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
 func (info gopRecorder) Def(id *ast.Ident, obj types.Object) {
+	if debugVerbose {
+		log.Println("==> Def:", id, obj.Type())
+	}
 	info.Defs[id] = obj
 }
 
@@ -219,6 +223,9 @@ func (info gopRecorder) Def(id *ast.Ident, obj types.Object) {
 //
 // Invariant: Uses[id].Pos() != id.Pos()
 func (info gopRecorder) Use(id *ast.Ident, obj types.Object) {
+	if debugVerbose {
+		log.Println("==> Use:", id, obj.Type())
+	}
 	info.Uses[id] = obj
 }
 
@@ -231,6 +238,9 @@ func (info gopRecorder) Use(id *ast.Ident, obj types.Object) {
 //	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
 //	*ast.Field         anonymous parameter *Var (incl. unnamed results)
 func (info gopRecorder) Implicit(node ast.Node, obj types.Object) {
+	if debugVerbose {
+		log.Println("==> Implicit:", obj)
+	}
 	info.Implicits[node] = obj
 }
 
@@ -264,6 +274,9 @@ func (info gopRecorder) Select(e *ast.SelectorExpr, sel *types.Selection) {
 //	*ast.ForStmt
 //	*ast.RangeStmt
 func (info gopRecorder) Scope(n ast.Node, scope *types.Scope) {
+	if debugVerbose {
+		log.Println("==> Scope:", scope)
+	}
 	info.Scopes[n] = scope
 }
 


Test patch:
diff --git a/x/build/build_test.go b/x/build/build_test.go
index 72e46f14..a677214e 100644
--- a/x/build/build_test.go
+++ b/x/build/build_test.go
@@ -515,7 +515,7 @@ func (i *emptyImporter) Import(path string) (*types.Package, error) {
 
 func TestContext(t *testing.T) {
 	ctx := build.NewContext(&emptyImporter{}, nil)
-	_, err := ctx.BuildFile("main.gop", `println "Go+"`)
+	_, err := ctx.BuildFile("main.gop", `import "fmt"; fmt.Println "Go+"`)
 	if err == nil {
 		t.Fatal("BuildFile: no error?")
 	}