From 390570c037566ae8b2df852871bccf7b92177d4d Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 13:20:15 +0800 Subject: [PATCH 1/6] shouldAddGopPkg => checkGopPkg --- func.go | 3 ++ import.go | 6 +--- package.go | 22 ++++++++++++-- typeparams_test.go | 71 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 91 insertions(+), 11 deletions(-) diff --git a/func.go b/func.go index 47beb982..030d5757 100644 --- a/func.go +++ b/func.go @@ -213,6 +213,9 @@ func (p *Package) NewFuncWith( if isGopFunc(name) { p.isGopPkg = true } + if isExported(name) { + _ = name + } fn.decl = &ast.FuncDecl{} p.file.decls = append(p.file.decls, fn.decl) diff --git a/import.go b/import.go index 11eca3b0..076800a0 100644 --- a/import.go +++ b/import.go @@ -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) } @@ -271,7 +267,7 @@ 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" ) diff --git a/package.go b/package.go index 2f3af2e9..077845a6 100644 --- a/package.go +++ b/package.go @@ -249,7 +249,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 } @@ -261,7 +265,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, }, }, }}) @@ -269,6 +273,20 @@ func (p *File) getDecls(this *Package) (decls []ast.Decl) { return append(decls, p.decls...) } +func checkGopPkg(pkg *Package) (val ast.Expr, ok bool) { + if ok = pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil; ok { + val = identTrue + } + return +} + +func isExported(name string) bool { // types.isExported + // ch, _ := utf8.DecodeRuneInString(name) + // return unicode.IsUpper(ch) + c := name[0] + return c >= 'A' && c <= 'Z' +} + // ---------------------------------------------------------------------------- // ObjectDocs maps an object to its document. diff --git a/typeparams_test.go b/typeparams_test.go index ec4e6299..5e172a19 100644 --- a/typeparams_test.go +++ b/typeparams_test.go @@ -134,13 +134,13 @@ func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { if err != nil { t.Fatal(err) } - pkg := gt.NewPackage("", "main") + pkg := gt.NewPackage("", "test") foo := pkg.Import("foo") objTable := foo.Ref("Table") typ := objTable.Type().(*types.Named) tyInt := types.Typ[types.Int] - cb := pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). + cb := pkg.NewFunc(nil, "Example", nil, nil, false).BodyStart(pkg). NewVar(types.NewPointer(typ), "tbl") _, err = cb.VarVal("tbl").Member("col", gox.MemberFlagMethodAlias) if err != nil { @@ -151,11 +151,11 @@ func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { Val(foo.Ref("Row")).Typ(tyInt).Val(1, source("1")).Call(2).EndStmt(). End() - domTest(t, pkg, `package main + domTest(t, pkg, `package test import "foo" -func main() { +func Example() { var tbl *foo.Table foo.Gopt_Table_Gopx_Col__0[int](tbl, "bar") foo.Gopx_Bar[int]("1") @@ -164,6 +164,69 @@ func main() { `) } +func _TestTypeAsParamsFunc2(t *testing.T) { + const src = `package foo + +const GopPackage = true + +type basetype interface { + int | string +} + +func Gopx_Bar[T basetype](name string) { +} + +func Gopx_Row__0[T basetype](name string) { +} + +func Gopx_Row__1[Array any](v int) { +} + +type Table struct { +} + +func Gopt_Table_Gopx_Col__0[T basetype](p *Table, name string) { +} + +func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { +} +` + gt := newGoxTest() + _, err := gt.LoadGoPackage("foo", "foo.go", src) + if err != nil { + t.Fatal(err) + } + pkg := gt.NewPackage("", "test") + foo := pkg.Import("foo") + objTable := foo.Ref("Table") + typ := objTable.Type().(*types.Named) + tyInt := types.Typ[types.Int] + + args := types.NewTuple(types.NewParam(0, pkg.Types, "tbl", types.NewPointer(typ))) + cb := pkg.NewFunc(nil, "Example", args, nil, false).BodyStart(pkg) + _, err = cb.VarVal("tbl").Member("col", gox.MemberFlagMethodAlias) + if err != nil { + t.Fatal("tbl.Member(col):", err) + } + cb.Typ(tyInt).Val("bar").Call(2).EndStmt(). + Val(foo.Ref("Bar")).Typ(tyInt).Val("1").Call(2).EndStmt(). + Val(foo.Ref("Row")).Typ(tyInt).Val(1, source("1")).Call(2).EndStmt(). + End() + + domTest(t, pkg, `package test + +import "foo" + +const GopPackage = "foo" + +func Example(tbl *foo.Table) { + foo.Gopt_Table_Gopx_Col__0[int](tbl, "bar") + foo.Gopx_Bar[int]("1") + foo.Gopx_Row__1[int](1) +} +`) +} + func TestOverloadNamed(t *testing.T) { const src = `package foo From 3ba28087a0695b12ae2a87cc6346f2b74f186548 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 14:50:52 +0800 Subject: [PATCH 2/6] #333: rm IsPkgtStandard; initGopPkg by checking GopPackage value --- import.go | 64 +++++++++++++++++++++++++------------------------ package.go | 26 -------------------- package_test.go | 8 ------- 3 files changed, 33 insertions(+), 65 deletions(-) diff --git a/import.go b/import.go index 076800a0..285fa73c 100644 --- a/import.go +++ b/import.go @@ -90,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 } - if debugImport { + 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 + } + 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) @@ -171,6 +184,7 @@ func InitThisGopPkg(pkg *types.Package) { on := NewOverloadNamed(token.NoPos, pkg, name, nameds...) scope.Insert(on) } + return } // name @@ -269,6 +283,7 @@ const ( gopoPrefix = "Gopo_" // overload function/method gopxPrefix = "Gopx_" // type as parameters function/method gopPackage = "GopPackage" + gopPkgInit = "__gop_inited" ) /* @@ -286,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 } @@ -354,42 +369,29 @@ const ( // ---------------------------------------------------------------------------- -// Context represents all things between packages. -type Context struct { - chkGopImports map[string]bool - stdPkg func(pkgPath string) bool +func isExported(name string) bool { // types.isExported + // ch, _ := utf8.DecodeRuneInString(name) + // return unicode.IsUpper(ch) + c := name[0] + return c >= 'A' && c <= 'Z' } -func NewContext(isPkgtStandard func(pkgPath string) bool) *Context { - if isPkgtStandard == nil { - isPkgtStandard = isStdPkg - } - return &Context{ - chkGopImports: make(map[string]bool), - stdPkg: isPkgtStandard, +func checkGopPkg(pkg *Package) (val ast.Expr, ok bool) { + if ok = pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil; ok { + val = identTrue } + 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 - } - if !pkgImp.Complete() { - importer.Import(pkgPath) - } - InitThisGopPkg(pkgImp) - p.chkGopImports[pkgPath] = true - for _, imp := range pkgImp.Imports() { +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) } } -func isStdPkg(pkgPath string) bool { - return strings.IndexByte(pkgPath, '.') < 0 -} - // ---------------------------------------------------------------------------- func importPkg(this *Package, pkgPath string, src ast.Node) (PkgRef, error) { @@ -405,7 +407,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 } diff --git a/package.go b/package.go index 077845a6..116ab17e 100644 --- a/package.go +++ b/package.go @@ -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) @@ -273,20 +267,6 @@ func (p *File) getDecls(this *Package) (decls []ast.Decl) { return append(decls, p.decls...) } -func checkGopPkg(pkg *Package) (val ast.Expr, ok bool) { - if ok = pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil; ok { - val = identTrue - } - return -} - -func isExported(name string) bool { // types.isExported - // ch, _ := utf8.DecodeRuneInString(name) - // return unicode.IsUpper(ch) - c := name[0] - return c >= 'A' && c <= 'Z' -} - // ---------------------------------------------------------------------------- // ObjectDocs maps an object to its document. @@ -304,7 +284,6 @@ type Package struct { files map[string]*File file *File conf *Config - ctx *Context builtin PkgRef pkgBig PkgRef utBigInt *types.Named @@ -329,10 +308,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) @@ -349,7 +324,6 @@ func NewPackage(pkgPath, name string, conf *Config) *Package { file: file, files: files, conf: conf, - ctx: ctx, } pkg.initAutoNames() pkg.imp = imp diff --git a/package_test.go b/package_test.go index 568c4221..552b2b2c 100644 --- a/package_test.go +++ b/package_test.go @@ -22,7 +22,6 @@ import ( "go/types" "log" "os" - "strings" "syscall" "testing" "unsafe" @@ -56,11 +55,6 @@ func (p eventRecorder) Member(id ast.Node, obj types.Object) { func (p eventRecorder) Call(fn ast.Node, obj types.Object) { } -func isStdPkg(pkgPath string) bool { - is := pkgPath != "foo" && strings.IndexByte(pkgPath, '.') < 0 - return is -} - func newMainPackage( implicitCast ...func(pkg *gox.Package, V, T types.Type, pv *gox.Element) bool) *gox.Package { conf := &gox.Config{ @@ -69,7 +63,6 @@ func newMainPackage( Recorder: eventRecorder{}, NodeInterpreter: nodeInterp{}, DbgPositioner: nodeInterp{}, - IsPkgtStandard: isStdPkg, } if len(implicitCast) > 0 { conf.CanImplicitCast = implicitCast[0] @@ -150,7 +143,6 @@ func (p *goxTest) NewPackage(pkgPath string, name string) *gox.Package { Importer: p.imp, NodeInterpreter: nodeInterp{}, DbgPositioner: nodeInterp{}, - IsPkgtStandard: isStdPkg, } return gox.NewPackage(pkgPath, name, conf) } From 5feddb6b77042051a867bdd005a17cc2eee1ba88 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 16:14:57 +0800 Subject: [PATCH 3/6] #333: checkGopPkg --- builtin_test.go | 10 ++++ func.go | 4 +- import.go | 114 ++++++++++++++++++++++++++++++++++++++++++--- package.go | 6 ++- typeparams_test.go | 2 +- 5 files changed, 124 insertions(+), 12 deletions(-) diff --git a/builtin_test.go b/builtin_test.go index 127b442b..ce1edca2 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -44,6 +44,16 @@ func getConf() *Config { return &Config{Fset: fset, Importer: imp} } +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?") + } +} + func TestDenoted(t *testing.T) { if denoteRecv(&ast.SelectorExpr{Sel: ast.NewIdent("foo")}) != nil { t.Fatal("denoteRecv: not nil?") diff --git a/func.go b/func.go index 030d5757..6545c0d2 100644 --- a/func.go +++ b/func.go @@ -213,8 +213,8 @@ func (p *Package) NewFuncWith( if isGopFunc(name) { p.isGopPkg = true } - if isExported(name) { - _ = name + if token.IsExported(name) { + p.expObjTypes = append(p.expObjTypes, sig) } fn.decl = &ast.FuncDecl{} diff --git a/import.go b/import.go index 285fa73c..80d90eb3 100644 --- a/import.go +++ b/import.go @@ -369,20 +369,120 @@ const ( // ---------------------------------------------------------------------------- -func isExported(name string) bool { // types.isExported - // ch, _ := utf8.DecodeRuneInString(name) - // return unicode.IsUpper(ch) - c := name[0] - return c >= 'A' && c <= 'Z' +type expDeps struct { + this *types.Package + ret map[*types.Package]none + exists map[types.Type]none } func checkGopPkg(pkg *Package) (val ast.Expr, ok bool) { - if ok = pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil; ok { - val = identTrue + 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) + } + 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 } +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) + if m.Exported() { + sig := m.Type().(*types.Signature) + p.sig(sig) + } + } + p.typ(t.Underlying()) + } +} + +func (p expDeps) interf(t *types.Interface) { + for i, n := 0, t.NumEmbeddeds(); i < n; i++ { + p.typ(t.EmbeddedType(i)) + } + for i, n := 0, t.NumExplicitMethods(); i < n; i++ { + m := t.ExplicitMethod(i) + if m.Exported() { + sig := m.Type().(*types.Signature) + 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()) + } + } +} + // initGopPkg initializes a Go+ packages. func (p *Package) initGopPkg(importer types.Importer, pkgImp *types.Package) { gopDeps := InitThisGopPkg(pkgImp) diff --git a/package.go b/package.go index 116ab17e..de55abb0 100644 --- a/package.go +++ b/package.go @@ -291,8 +291,10 @@ type Package struct { 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 ( diff --git a/typeparams_test.go b/typeparams_test.go index 5e172a19..9cdc5c37 100644 --- a/typeparams_test.go +++ b/typeparams_test.go @@ -164,7 +164,7 @@ func Example() { `) } -func _TestTypeAsParamsFunc2(t *testing.T) { +func TestCheckGopPkg(t *testing.T) { const src = `package foo const GopPackage = true From 058c0d3559f6606b7165c1f3ff558d1143d6da5d Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 20:33:10 +0800 Subject: [PATCH 4/6] TestCheckGopPkg --- typeparams_test.go | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/typeparams_test.go b/typeparams_test.go index 9cdc5c37..e9cee2fb 100644 --- a/typeparams_test.go +++ b/typeparams_test.go @@ -167,7 +167,9 @@ func Example() { func TestCheckGopPkg(t *testing.T) { const src = `package foo -const GopPackage = true +import "io" + +const GopPackage = "io" type basetype interface { int | string @@ -182,7 +184,15 @@ func Gopx_Row__0[T basetype](name string) { func Gopx_Row__1[Array any](v int) { } +type EmbIntf interface { + io.Reader + Close() +} + type Table struct { + EmbIntf + N int + b string } func Gopt_Table_Gopx_Col__0[T basetype](p *Table, name string) { @@ -202,9 +212,12 @@ func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { typ := objTable.Type().(*types.Named) tyInt := types.Typ[types.Int] - args := types.NewTuple(types.NewParam(0, pkg.Types, "tbl", types.NewPointer(typ))) + typSlice := types.NewSlice(types.NewPointer(typ)) + typMap := types.NewMap(types.Typ[types.String], typSlice) + + args := types.NewTuple(types.NewParam(0, pkg.Types, "tbls", typMap)) cb := pkg.NewFunc(nil, "Example", args, nil, false).BodyStart(pkg) - _, err = cb.VarVal("tbl").Member("col", gox.MemberFlagMethodAlias) + _, err = cb.VarVal("tbls").Val("Hi").Index(1, false).Val(0).Index(1, false).Member("col", gox.MemberFlagMethodAlias) if err != nil { t.Fatal("tbl.Member(col):", err) } @@ -213,17 +226,24 @@ func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { Val(foo.Ref("Row")).Typ(tyInt).Val(1, source("1")).Call(2).EndStmt(). End() + typChan := types.NewChan(types.SendRecv, typSlice) + typArray := types.NewArray(typChan, 2) + args = types.NewTuple(types.NewParam(0, pkg.Types, "", typArray)) + pkg.NewFunc(nil, "Create", args, nil, false).BodyStart(pkg).End() + domTest(t, pkg, `package test import "foo" const GopPackage = "foo" -func Example(tbl *foo.Table) { - foo.Gopt_Table_Gopx_Col__0[int](tbl, "bar") +func Example(tbls map[string][]*foo.Table) { + foo.Gopt_Table_Gopx_Col__0[int](tbls["Hi"][0], "bar") foo.Gopx_Bar[int]("1") foo.Gopx_Row__1[int](1) } +func Create([2]chan []*foo.Table) { +} `) } From 4f1d6be24188398fb9fc2cb607a1cb75b06ea054 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 20:43:33 +0800 Subject: [PATCH 5/6] TestCheckOverloads --- builtin_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/builtin_test.go b/builtin_test.go index ce1edca2..84eb9727 100644 --- a/builtin_test.go +++ b/builtin_test.go @@ -44,6 +44,18 @@ 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( @@ -52,6 +64,13 @@ func TestCheckGopPkgNoop(t *testing.T) { 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) { From 02bb096b7a122788a2f61b9d38a8dfcc030e2665 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Fri, 9 Feb 2024 20:56:47 +0800 Subject: [PATCH 6/6] check isSigFuncEx --- func_ext.go | 13 +++++++++++-- import.go | 14 ++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/func_ext.go b/func_ext.go index 39edd536..4684d89a 100644 --- a/func_ext.go +++ b/func_ext.go @@ -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 } @@ -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) diff --git a/import.go b/import.go index 80d90eb3..75b28df9 100644 --- a/import.go +++ b/import.go @@ -452,10 +452,7 @@ func (p expDeps) named(t *types.Named) { p.ret[at] = none{} for i, n := 0, t.NumMethods(); i < n; i++ { m := t.Method(i) - if m.Exported() { - sig := m.Type().(*types.Signature) - p.sig(sig) - } + p.method(m) } p.typ(t.Underlying()) } @@ -467,8 +464,13 @@ func (p expDeps) interf(t *types.Interface) { } for i, n := 0, t.NumExplicitMethods(); i < n; i++ { m := t.ExplicitMethod(i) - if m.Exported() { - sig := m.Type().(*types.Signature) + p.method(m) + } +} + +func (p expDeps) method(m *types.Func) { + if m.Exported() { + if sig := m.Type().(*types.Signature); !isSigFuncEx(sig) { p.sig(sig) } }