Skip to content

Commit

Permalink
Merge pull request #371 from xushiwei/q
Browse files Browse the repository at this point in the history
#333: checkGopPkg
  • Loading branch information
xushiwei authored Feb 9, 2024
2 parents 31705c4 + 02bb096 commit a878596
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 63 deletions.
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

0 comments on commit a878596

Please sign in to comment.