Skip to content

Commit

Permalink
Merge pull request #339 from xushiwei/ov
Browse files Browse the repository at this point in the history
initThisGopPkg: overloadNameds; NewOverloadNamed
  • Loading branch information
xushiwei authored Jan 21, 2024
2 parents 2b7bf77 + 46d7112 commit 1d1b45f
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 73 deletions.
4 changes: 2 additions & 2 deletions ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func toExpr(pkg *Package, val interface{}, src ast.Node) *internal.Elem {
Src: src,
}
case *types.TypeName:
if typ := v.Type(); isType(typ) {
if typ := v.Type(); isTypeType(typ) {
return &internal.Elem{
Val: toType(pkg, typ), Type: NewTypeType(typ), Src: src,
}
Expand Down Expand Up @@ -694,7 +694,7 @@ retry:
} else if t.hasApproxType() {
flags |= instrFlagApproxType
}
case *instructionType:
case *TyInstruction:
return t.instr.Call(pkg, args, flags, fn.Src)
case *types.Named:
fnType = pkg.cb.getUnderlying(t)
Expand Down
32 changes: 29 additions & 3 deletions builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,28 @@ func getConf() *Config {
return &Config{Fset: fset, Importer: imp}
}

func TestOverloadNameds(t *testing.T) {
pkg := types.NewPackage("", "")
tn := types.NewTypeName(0, pkg, "foo__1", nil)
named := types.NewNamed(tn, TyByte, nil)
func() {
defer func() {
if e := recover(); e != "overload type foo__1 out of range 0..0\n" {
t.Fatal("TestOverloadFuncs:", e)
}
}()
overloadNameds(5, []*types.Named{named})
}()
func() {
defer func() {
if e := recover(); e != "overload type foo__1 exists?\n" {
t.Fatal("TestOverloadFuncs:", e)
}
}()
overloadNameds(5, []*types.Named{named, named})
}()
}

func TestOverloadFuncs(t *testing.T) {
pkg := types.NewPackage("", "")
fn := types.NewFunc(0, pkg, "foo__1", nil)
Expand Down Expand Up @@ -564,8 +586,8 @@ func TestMethodAutoProperty(t *testing.T) {
}
}

func TestIsType(t *testing.T) {
if isType(sigFuncEx(nil, nil, &TyOverloadFunc{})) {
func TestIsTypeType(t *testing.T) {
if isTypeType(sigFuncEx(nil, nil, &TyOverloadFunc{})) {
t.Fatal("TestIsType: isType(TyOverloadFunc)")
}
}
Expand All @@ -585,7 +607,8 @@ func TestUnderlying(t *testing.T) {
&TyOverloadFunc{},
&TyOverloadMethod{},
&TyTemplateRecvMethod{},
&instructionType{},
&TyInstruction{},
&TyOverloadNamed{},
&TypeType{},
&unboundFuncParam{},
&unboundProxyParam{},
Expand All @@ -609,6 +632,9 @@ func TestUnderlying(t *testing.T) {
if fex, ok := typ.(TyFuncEx); ok {
fex.funcEx()
}
if fex, ok := typ.(TyTypeEx); ok {
fex.typeEx()
}
if typ.Underlying() == typ {
panic("noop Underlying")
}
Expand Down
2 changes: 1 addition & 1 deletion codebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -1838,7 +1838,7 @@ func (p *CodeBuilder) IncDec(op token.Token, src ...ast.Node) *CodeBuilder {
if fn == nil {
panic("TODO: operator not matched")
}
t := fn.Type().(*instructionType)
t := fn.Type().(*TyInstruction)
if _, err := t.instr.Call(pkg, []*Element{arg}, 0, nil); err != nil {
panic(err)
}
Expand Down
4 changes: 0 additions & 4 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,4 @@ type Instruction interface {
Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error)
}

func NewInstruction(pos token.Pos, pkg *types.Package, name string, instr Instruction) *types.TypeName {
return types.NewTypeName(pos, pkg, name, &instructionType{instr})
}

// ----------------------------------------------------------------------------
69 changes: 53 additions & 16 deletions import.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,19 @@ func shouldAddGopPkg(pkg *Package) bool {
return pkg.isGopPkg && pkg.Types.Scope().Lookup(gopPackage) == nil
}

func isGopoConst(name string) bool {
return strings.HasPrefix(name, gopoPrefix)
}

func isGopFunc(name string) bool {
return isOverloadFunc(name) || isGoptFunc(name)
return isOverload(name) || isGoptFunc(name)
}

func isGoptFunc(name string) bool {
return strings.HasPrefix(name, goptPrefix)
}

func isGopoFunc(name string) bool {
return strings.HasPrefix(name, gopoPrefix)
}

func isOverloadFunc(name string) bool {
func isOverload(name string) bool {
n := len(name)
return n > 3 && name[n-3:n-1] == "__"
}
Expand All @@ -115,18 +115,18 @@ func initThisGopPkg(pkg *types.Package) {
}
gopos := make([]string, 0, 4)
overloads := make(map[omthd][]types.Object)
onameds := make(map[string][]*types.Named)
names := scope.Names()
for _, name := range names {
if isGopoConst(name) {
gopos = append(gopos, name)
continue
}
o := scope.Lookup(name)
if tn, ok := o.(*types.TypeName); ok && tn.IsAlias() {
continue
}
if isGopoFunc(name) {
gopos = append(gopos, name)
} else if isOverloadFunc(name) { // overload function
key := omthd{nil, name[:len(name)-3]}
overloads[key] = append(overloads[key], o)
} else if named, ok := o.Type().(*types.Named); ok {
if named, ok := o.Type().(*types.Named); ok {
var list methodList
switch t := named.Underlying().(type) {
case *types.Interface:
Expand All @@ -137,12 +137,19 @@ func initThisGopPkg(pkg *types.Package) {
for i, n := 0, list.NumMethods(); i < n; i++ {
m := list.Method(i)
mName := m.Name()
if isOverloadFunc(mName) { // overload method
if isOverload(mName) { // overload method
mthd := mName[:len(mName)-3]
key := omthd{named, mthd}
overloads[key] = append(overloads[key], m)
}
}
if isOverload(name) { // overload named
key := name[:len(name)-3]
onameds[key] = append(onameds[key], named)
}
} else if isOverload(name) { // overload function
key := omthd{nil, name[:len(name)-3]}
overloads[key] = append(overloads[key], o)
} else {
checkTemplateMethod(pkg, name, o)
}
Expand Down Expand Up @@ -170,6 +177,15 @@ func initThisGopPkg(pkg *types.Package) {
fns := overloadFuncs(off, items)
newOverload(pkg, scope, key, fns)
}
for name, items := range onameds {
off := len(name) + 2
nameds := overloadNameds(off, items)
if debugImport {
log.Println("==> NewOverloadNamed", name)
}
on := NewOverloadNamed(token.NoPos, pkg, name, nameds...)
scope.Insert(on)
}
}

// name
Expand Down Expand Up @@ -312,6 +328,22 @@ func overloadFuncs(off int, items []types.Object) []types.Object {
return fns
}

func overloadNameds(off int, items []*types.Named) []*types.Named {
nameds := make([]*types.Named, len(items))
for _, item := range items {
name := item.Obj().Name()
idx := toIndex(name[off])
if idx >= len(items) {
log.Panicf("overload type %v out of range 0..%v\n", name, len(nameds)-1)
}
if nameds[idx] != nil {
log.Panicf("overload type %v exists?\n", name)
}
nameds[idx] = item
}
return nameds
}

func toIndex(c byte) int {
if c >= '0' && c <= '9' {
return int(c - '0')
Expand All @@ -331,18 +363,23 @@ const (
// Context represents all things between packages.
type Context struct {
chkGopImports map[string]bool
stdPkg func(pkgPath string) bool
}

func NewContext() *Context {
func NewContext(isPkgtStandard func(pkgPath string) bool) *Context {
if isPkgtStandard == nil {
isPkgtStandard = isStdPkg
}
return &Context{
chkGopImports: make(map[string]bool),
stdPkg: isPkgtStandard,
}
}

// initGopPkg initializes a Go+ packages.
func (p *Context) initGopPkg(importer types.Importer, pkgImp *types.Package) {
pkgPath := pkgImp.Path()
if stdPkg(pkgPath) || p.chkGopImports[pkgPath] {
if p.stdPkg(pkgPath) || p.chkGopImports[pkgPath] {
return
}
if !pkgImp.Complete() {
Expand All @@ -355,7 +392,7 @@ func (p *Context) initGopPkg(importer types.Importer, pkgImp *types.Package) {
}
}

func stdPkg(pkgPath string) bool {
func isStdPkg(pkgPath string) bool {
return strings.IndexByte(pkgPath, '.') < 0
}

Expand Down
11 changes: 7 additions & 4 deletions package.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ type Config struct {
// 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 @@ -131,11 +134,11 @@ type Config struct {
// A Recorder records selected objects such as methods, etc (optional).
Recorder Recorder

// NoSkipConstant is to disable optimization of skipping constant (optional).
NoSkipConstant bool

// (internal) only for testing
DbgPositioner dbgPositioner

// NoSkipConstant is to disable optimization of skipping constant (optional).
NoSkipConstant bool
}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -348,7 +351,7 @@ func NewPackage(pkgPath, name string, conf *Config) *Package {
}
ctx := conf.Context
if ctx == nil {
ctx = NewContext()
ctx = NewContext(conf.IsPkgtStandard)
}
imp := conf.Importer
if imp == nil {
Expand Down
9 changes: 9 additions & 0 deletions package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"go/types"
"log"
"os"
"strings"
"syscall"
"testing"
"unsafe"
Expand Down Expand Up @@ -55,6 +56,12 @@ 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
log.Println("isStdPkg:", pkgPath, is)
return is
}

func newMainPackage(
implicitCast ...func(pkg *gox.Package, V, T types.Type, pv *gox.Element) bool) *gox.Package {
conf := &gox.Config{
Expand All @@ -63,6 +70,7 @@ func newMainPackage(
Recorder: eventRecorder{},
NodeInterpreter: nodeInterp{},
DbgPositioner: nodeInterp{},
IsPkgtStandard: isStdPkg,
}
if len(implicitCast) > 0 {
conf.CanImplicitCast = implicitCast[0]
Expand Down Expand Up @@ -142,6 +150,7 @@ 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)
}
Expand Down
Loading

0 comments on commit 1d1b45f

Please sign in to comment.