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

#333: checkGopPkg #371

Merged
merged 6 commits into from
Feb 9, 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
29 changes: 29 additions & 0 deletions builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,35 @@ func getConf() *Config {
return &Config{Fset: fset, Importer: imp}
}

func TestCheckOverloads(t *testing.T) {
defer func() {
if e := recover(); e != "checkOverloads: should be string constant - foo" {
t.Fatal("TestCheckOverloads:", e)
}
}()
scope := types.NewScope(nil, 0, 0, "")
scope.Insert(types.NewLabel(0, nil, "foo"))
checkOverloads(scope, "bar")
checkOverloads(scope, "foo")
}

func TestCheckGopPkgNoop(t *testing.T) {
pkg := NewPackage("", "foo", nil)
pkg.Types.Scope().Insert(types.NewConst(
token.NoPos, pkg.Types, "GopPackage", types.Typ[types.UntypedBool], constant.MakeBool(true),
))
if _, ok := checkGopPkg(pkg); ok {
t.Fatal("checkGopPkg: ok?")
}
defer func() {
if recover() == nil {
t.Fatal("expDeps.typ: no panic?")
}
}()
var ed expDeps
ed.typ(&unboundFuncParam{})
}

func TestDenoted(t *testing.T) {
if denoteRecv(&ast.SelectorExpr{Sel: ast.NewIdent("foo")}) != nil {
t.Fatal("denoteRecv: not nil?")
Expand Down
3 changes: 3 additions & 0 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ func (p *Package) NewFuncWith(
if isGopFunc(name) {
p.isGopPkg = true
}
if token.IsExported(name) {
p.expObjTypes = append(p.expObjTypes, sig)
}

fn.decl = &ast.FuncDecl{}
p.file.decls = append(p.file.decls, fn.decl)
Expand Down
13 changes: 11 additions & 2 deletions func_ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ const (
func CheckSigFuncEx(sig *types.Signature) (types.Type, bool) {
if sig.Params().Len() == 1 {
if param := sig.Params().At(0); param.Name() == overloadArgs {
if typ, ok := param.Type().(*types.Interface); ok && typ.NumMethods() == 1 {
if sig, ok := typ.Method(0).Type().(*types.Signature); ok {
if typ, ok := param.Type().(*types.Interface); ok && typ.NumExplicitMethods() == 1 {
if sig, ok := typ.ExplicitMethod(0).Type().(*types.Signature); ok {
if recv := sig.Recv(); recv != nil {
return recv.Type(), true
}
Expand All @@ -100,6 +100,15 @@ func CheckSigFuncEx(sig *types.Signature) (types.Type, bool) {
return nil, false
}

func isSigFuncEx(sig *types.Signature) bool {
if sig.Params().Len() == 1 {
if param := sig.Params().At(0); param.Name() == overloadArgs {
return true
}
}
return false
}

// sigFuncEx return func type ($overloadArgs ...interface{$overloadMethod()})
func sigFuncEx(pkg *types.Package, recv *types.Var, t types.Type) *types.Signature {
sig := types.NewSignatureType(types.NewVar(token.NoPos, nil, "", t), nil, nil, nil, nil, false)
Expand Down
166 changes: 133 additions & 33 deletions import.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ func (p PkgRef) MarkForceUsed(pkg *Package) {
func (p PkgRef) EnsureImported() {
}

func shouldAddGopPkg(pkg *Package) bool {
return pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil
}

func isGopoConst(name string) bool {
return strings.HasPrefix(name, gopoPrefix)
}
Expand All @@ -94,12 +90,25 @@ func isOverload(name string) bool {
}

// InitThisGopPkg initializes a Go+ package.
func InitThisGopPkg(pkg *types.Package) {
func InitThisGopPkg(pkg *types.Package) (deps []string) {
scope := pkg.Scope()
if scope.Lookup(gopPackage) == nil { // not is a Go+ package
if scope.Lookup(gopPkgInit) != nil { // initialized
return
}
scope.Insert(types.NewConst(
token.NoPos, pkg, gopPkgInit, types.Typ[types.UntypedBool], constant.MakeBool(true),
))

pkgDeps := scope.Lookup(gopPackage)
if pkgDeps == nil { // not is a Go+ package
return
}
if debugImport {
valDeps := pkgDeps.(*types.Const).Val()
if valDeps.Kind() == constant.String {
deps = strings.Split(constant.StringVal(valDeps), ",")
}

if debugImport && pkg.Path() != "" {
log.Println("==> Import", pkg.Path())
}
gopos := make([]string, 0, 4)
Expand Down Expand Up @@ -175,6 +184,7 @@ func InitThisGopPkg(pkg *types.Package) {
on := NewOverloadNamed(token.NoPos, pkg, name, nameds...)
scope.Insert(on)
}
return
}

// name
Expand Down Expand Up @@ -271,8 +281,9 @@ func checkGoptGopx(pkg *types.Package, scope *types.Scope, name string, o types.
const (
goptPrefix = "Gopt_" // template method
gopoPrefix = "Gopo_" // overload function/method
gopxPrefix = "Gopx_"
gopxPrefix = "Gopx_" // type as parameters function/method
gopPackage = "GopPackage"
gopPkgInit = "__gop_inited"
)

/*
Expand All @@ -290,7 +301,7 @@ func checkOverloads(scope *types.Scope, gopoName string) (ret []string, exists b
return strings.Split(constant.StringVal(v), ","), true
}
}
panic("checkOverloads TODO: should be string constant - " + gopoName)
panic("checkOverloads: should be string constant - " + gopoName)
}
return
}
Expand Down Expand Up @@ -358,40 +369,129 @@ const (

// ----------------------------------------------------------------------------

// Context represents all things between packages.
type Context struct {
chkGopImports map[string]bool
stdPkg func(pkgPath string) bool
type expDeps struct {
this *types.Package
ret map[*types.Package]none
exists map[types.Type]none
}

func NewContext(isPkgtStandard func(pkgPath string) bool) *Context {
if isPkgtStandard == nil {
isPkgtStandard = isStdPkg
func checkGopPkg(pkg *Package) (val ast.Expr, ok bool) {
if pkg.Types.Scope().Lookup(gopPackage) != nil {
return
}
ed := expDeps{pkg.Types, make(map[*types.Package]none), make(map[types.Type]none)}
for _, t := range pkg.expObjTypes {
ed.typ(t)
}
return &Context{
chkGopImports: make(map[string]bool),
stdPkg: isPkgtStandard,
var deps []string
for depPkg := range ed.ret {
if depPkg.Scope().Lookup(gopPackage) != nil {
deps = append(deps, depPkg.Path())
}
}
if len(deps) > 0 {
return stringLit(strings.Join(deps, ",")), true
}
if ok = pkg.isGopPkg; ok {
return identTrue, true
}
return
}

// initGopPkg initializes a Go+ packages.
func (p *Context) initGopPkg(importer types.Importer, pkgImp *types.Package) {
pkgPath := pkgImp.Path()
if p.stdPkg(pkgPath) || p.chkGopImports[pkgPath] {
return
func (p expDeps) typ(typ types.Type) {
retry:
switch t := typ.(type) {
case *types.Basic: // bool, int, etc
case *types.Pointer:
typ = t.Elem()
goto retry
case *types.Slice:
typ = t.Elem()
goto retry
case *types.Map:
p.typ(t.Key())
typ = t.Elem()
goto retry
case *types.Named:
p.named(t)
case *types.Signature:
p.sig(t)
case *types.Struct:
p.struc(t)
case *types.Interface:
p.interf(t)
case *types.Chan:
typ = t.Elem()
goto retry
case *types.Array:
typ = t.Elem()
goto retry
default:
log.Panicf("expDeps: unknown type - %T\n", typ)
}
}

func (p expDeps) sig(sig *types.Signature) {
p.tuple(sig.Params())
p.tuple(sig.Results())
}

func (p expDeps) tuple(v *types.Tuple) {
for i, n := 0, v.Len(); i < n; i++ {
p.typ(v.At(i).Type())
}
}

func (p expDeps) named(t *types.Named) {
o := t.Obj()
if at := o.Pkg(); at != nil && at != p.this {
if _, ok := p.exists[t]; ok {
return
}
p.exists[t] = none{}
p.ret[at] = none{}
for i, n := 0, t.NumMethods(); i < n; i++ {
m := t.Method(i)
p.method(m)
}
p.typ(t.Underlying())
}
if !pkgImp.Complete() {
importer.Import(pkgPath)
}

func (p expDeps) interf(t *types.Interface) {
for i, n := 0, t.NumEmbeddeds(); i < n; i++ {
p.typ(t.EmbeddedType(i))
}
InitThisGopPkg(pkgImp)
p.chkGopImports[pkgPath] = true
for _, imp := range pkgImp.Imports() {
p.initGopPkg(importer, imp)
for i, n := 0, t.NumExplicitMethods(); i < n; i++ {
m := t.ExplicitMethod(i)
p.method(m)
}
}

func (p expDeps) method(m *types.Func) {
if m.Exported() {
if sig := m.Type().(*types.Signature); !isSigFuncEx(sig) {
p.sig(sig)
}
}
}

func (p expDeps) struc(t *types.Struct) {
for i, n := 0, t.NumFields(); i < n; i++ {
fld := t.Field(i)
if fld.Embedded() || fld.Exported() {
p.typ(fld.Type())
}
}
}

func isStdPkg(pkgPath string) bool {
return strings.IndexByte(pkgPath, '.') < 0
// initGopPkg initializes a Go+ packages.
func (p *Package) initGopPkg(importer types.Importer, pkgImp *types.Package) {
gopDeps := InitThisGopPkg(pkgImp)
for _, depPath := range gopDeps {
imp, _ := importer.Import(depPath)
p.initGopPkg(importer, imp)
}
}

// ----------------------------------------------------------------------------
Expand All @@ -409,7 +509,7 @@ func importPkg(this *Package, pkgPath string, src ast.Node) (PkgRef, error) {
}
return PkgRef{}, e
} else {
this.ctx.initGopPkg(this.imp, pkgImp)
this.initGopPkg(this.imp, pkgImp)
}
return PkgRef{Types: pkgImp}, nil
}
Expand Down
26 changes: 10 additions & 16 deletions package.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,6 @@ type Config struct {
// If Fset is nil, Load will use a new fileset, but preserve Fset's value.
Fset *token.FileSet

// Context represents all things between packages (optional).
Context *Context

// IsPkgtStandard checks a pkgPath is a Go standard package or not.
IsPkgtStandard func(pkgPath string) bool

// HandleErr is called to handle errors (optional).
HandleErr func(err error)

Expand Down Expand Up @@ -249,7 +243,11 @@ func (p *File) getDecls(this *Package) (decls []ast.Decl) {
return specs[i].(*ast.ImportSpec).Path.Value < specs[j].(*ast.ImportSpec).Path.Value
})

addGopPkg := p.fname == this.conf.DefaultGoFile && shouldAddGopPkg(this)
var valGopPkg ast.Expr
var addGopPkg bool
if p.fname == this.conf.DefaultGoFile {
valGopPkg, addGopPkg = checkGopPkg(this)
}
if len(specs) == 0 && !addGopPkg {
return p.decls
}
Expand All @@ -261,7 +259,7 @@ func (p *File) getDecls(this *Package) (decls []ast.Decl) {
&ast.ValueSpec{
Names: []*ast.Ident{{Name: gopPackage}},
Values: []ast.Expr{
&ast.Ident{Name: "true"},
valGopPkg,
},
},
}})
Expand All @@ -286,16 +284,17 @@ type Package struct {
files map[string]*File
file *File
conf *Config
ctx *Context
builtin PkgRef
pkgBig PkgRef
utBigInt *types.Named
utBigRat *types.Named
utBigFlt *types.Named
commentedStmts map[ast.Stmt]*ast.CommentGroup
implicitCast func(pkg *Package, V, T types.Type, pv *Element) bool
allowRedecl bool // for c2go
isGopPkg bool

expObjTypes []types.Type // types of export objects
isGopPkg bool
allowRedecl bool // for c2go
}

const (
Expand All @@ -311,10 +310,6 @@ func NewPackage(pkgPath, name string, conf *Config) *Package {
if fset == nil {
fset = token.NewFileSet()
}
ctx := conf.Context
if ctx == nil {
ctx = NewContext(conf.IsPkgtStandard)
}
imp := conf.Importer
if imp == nil {
imp = packages.NewImporter(fset)
Expand All @@ -331,7 +326,6 @@ func NewPackage(pkgPath, name string, conf *Config) *Package {
file: file,
files: files,
conf: conf,
ctx: ctx,
}
pkg.initAutoNames()
pkg.imp = imp
Expand Down
Loading