github.com/goplus/xtypes@v0.2.1/types.go (about)

     1  /*
     2   Copyright 2020 The GoPlus Authors (goplus.org)
     3  
     4   Licensed under the Apache License, Version 2.0 (the "License");
     5   you may not use this file except in compliance with the License.
     6   You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   Unless required by applicable law or agreed to in writing, software
    11   distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  // Package xtypes provides `go/types` extended utilities. for example,
    18  // converting `types.Type` into `reflect.Type`.
    19  
    20  package xtypes
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"go/token"
    26  	"go/types"
    27  	"reflect"
    28  	"unsafe"
    29  
    30  	"github.com/goplus/reflectx"
    31  )
    32  
    33  var basicTypes = [...]reflect.Type{
    34  	types.Bool:          reflect.TypeOf(false),
    35  	types.Int:           reflect.TypeOf(0),
    36  	types.Int8:          reflect.TypeOf(int8(0)),
    37  	types.Int16:         reflect.TypeOf(int16(0)),
    38  	types.Int32:         reflect.TypeOf(int32(0)),
    39  	types.Int64:         reflect.TypeOf(int64(0)),
    40  	types.Uint:          reflect.TypeOf(uint(0)),
    41  	types.Uint8:         reflect.TypeOf(uint8(0)),
    42  	types.Uint16:        reflect.TypeOf(uint16(0)),
    43  	types.Uint32:        reflect.TypeOf(uint32(0)),
    44  	types.Uint64:        reflect.TypeOf(uint64(0)),
    45  	types.Uintptr:       reflect.TypeOf(uintptr(0)),
    46  	types.Float32:       reflect.TypeOf(float32(0)),
    47  	types.Float64:       reflect.TypeOf(float64(0)),
    48  	types.Complex64:     reflect.TypeOf(complex64(0)),
    49  	types.Complex128:    reflect.TypeOf(complex128(0)),
    50  	types.String:        reflect.TypeOf(""),
    51  	types.UnsafePointer: reflect.TypeOf(unsafe.Pointer(nil)),
    52  }
    53  
    54  var (
    55  	tyEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem()
    56  	tyErrorInterface = reflect.TypeOf((*error)(nil)).Elem()
    57  )
    58  
    59  var (
    60  	// ErrUntyped error
    61  	ErrUntyped = errors.New("untyped type")
    62  	// ErrUnknownArrayLen error
    63  	ErrUnknownArrayLen = errors.New("unknown array length")
    64  )
    65  
    66  func ToTypeList(tuple *types.Tuple, ctx Context) (list []reflect.Type, err error) {
    67  	for i := 0; i < tuple.Len(); i++ {
    68  		t, err := ToType(tuple.At(i).Type(), ctx)
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  		list = append(list, t)
    73  	}
    74  	return
    75  }
    76  
    77  func ToType(typ types.Type, ctx Context) (reflect.Type, error) {
    78  	if t, ok := ctx.FindType(typ); ok {
    79  		return t, nil
    80  	}
    81  	switch t := typ.(type) {
    82  	case *types.Basic:
    83  		if kind := t.Kind(); kind >= types.Bool && kind <= types.UnsafePointer {
    84  			return basicTypes[kind], nil
    85  		} else if kind == types.UntypedBool {
    86  			return basicTypes[types.Bool], nil
    87  		} else if kind == types.UntypedString {
    88  			return basicTypes[types.String], nil
    89  		}
    90  		return nil, ErrUntyped
    91  	case *types.Pointer:
    92  		elem, err := ToType(t.Elem(), ctx)
    93  		if err != nil {
    94  			return nil, fmt.Errorf("unknown pointer elem type - %w", err)
    95  		}
    96  		return reflect.PtrTo(elem), nil
    97  	case *types.Slice:
    98  		elem, err := ToType(t.Elem(), ctx)
    99  		if err != nil {
   100  			return nil, fmt.Errorf("unknown slice elem type - %w", err)
   101  		}
   102  		return reflect.SliceOf(elem), nil
   103  	case *types.Array:
   104  		elem, err := ToType(t.Elem(), ctx)
   105  		if err != nil {
   106  			return nil, fmt.Errorf("unknown array elem type - %w", err)
   107  		}
   108  		n := t.Len()
   109  		if n < 0 {
   110  			return nil, ErrUnknownArrayLen
   111  		}
   112  		return reflect.ArrayOf(int(n), elem), nil
   113  	case *types.Map:
   114  		key, err := ToType(t.Key(), ctx)
   115  		if err != nil {
   116  			return nil, fmt.Errorf("unknown map key type - %w", err)
   117  		}
   118  		elem, err := ToType(t.Elem(), ctx)
   119  		if err != nil {
   120  			return nil, fmt.Errorf("unknown map elem type - %w", err)
   121  		}
   122  		return reflect.MapOf(key, elem), nil
   123  	case *types.Chan:
   124  		elem, err := ToType(t.Elem(), ctx)
   125  		if err != nil {
   126  			return nil, fmt.Errorf("unknown chan elem type - %w", err)
   127  		}
   128  		return reflect.ChanOf(toChanDir(t.Dir()), elem), nil
   129  	case *types.Struct:
   130  		return toStructType(t, ctx)
   131  	case *types.Named:
   132  		return toNamedType(t, ctx)
   133  	case *types.Interface:
   134  		return toInterfaceType(t, ctx)
   135  	case *types.Signature:
   136  		in, err := ToTypeList(t.Params(), ctx)
   137  		if err != nil {
   138  			return nil, err
   139  		}
   140  		out, err := ToTypeList(t.Results(), ctx)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		return reflect.FuncOf(in, out, t.Variadic()), nil
   145  	}
   146  	return nil, fmt.Errorf("unknown type %v", typ)
   147  }
   148  
   149  var (
   150  	sigMap = make(map[string]reflect.Type)
   151  )
   152  
   153  func toChanDir(d types.ChanDir) reflect.ChanDir {
   154  	switch d {
   155  	case types.SendRecv:
   156  		return reflect.BothDir
   157  	case types.SendOnly:
   158  		return reflect.SendDir
   159  	case types.RecvOnly:
   160  		return reflect.RecvDir
   161  	}
   162  	return 0
   163  }
   164  
   165  // toStructType converts a types.Struct to reflect.Type.
   166  func toStructType(t *types.Struct, ctx Context) (typ reflect.Type, err error) {
   167  	n := t.NumFields()
   168  	flds := make([]reflect.StructField, n)
   169  	for i := 0; i < n; i++ {
   170  		flds[i], err = toStructField(t.Field(i), t.Tag(i), ctx)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  	}
   175  	typ = reflectx.StructOf(flds)
   176  	typ, _ = toMethodSet(t, typ, ctx)
   177  	//ctx.UpdateType(typ, fnUpdate)
   178  	return typ, nil
   179  }
   180  
   181  func toStructField(v *types.Var, tag string, ctx Context) (fld reflect.StructField, err error) {
   182  	name := v.Name()
   183  	typ, err := ToType(v.Type(), ctx)
   184  	if err != nil {
   185  		err = fmt.Errorf("unknown struct field `%s` type - %w", name, err)
   186  		return
   187  	}
   188  	fld = reflect.StructField{
   189  		Name:      name,
   190  		Type:      typ,
   191  		Tag:       reflect.StructTag(tag),
   192  		Anonymous: v.Anonymous(),
   193  	}
   194  	if !token.IsExported(name) {
   195  		fld.PkgPath = v.Pkg().Path()
   196  	}
   197  	return
   198  }
   199  
   200  func toMethodSet(t types.Type, styp reflect.Type, ctx Context) (reflect.Type, func() error) {
   201  	methods := IntuitiveMethodSet(t)
   202  	numMethods := len(methods)
   203  	if numMethods == 0 {
   204  		return styp, nil
   205  	}
   206  	var mcount, pcount int
   207  	for i := 0; i < numMethods; i++ {
   208  		sig := methods[i].Type().(*types.Signature)
   209  		pointer := isPointer(sig.Recv().Type())
   210  		if !pointer {
   211  			mcount++
   212  		}
   213  		pcount++
   214  	}
   215  	typ := reflectx.NewMethodSet(styp, mcount, pcount)
   216  	fn := func() error {
   217  		var ms []reflectx.Method
   218  		for i := 0; i < numMethods; i++ {
   219  			fn := methods[i].Obj().(*types.Func)
   220  			sig := methods[i].Type().(*types.Signature)
   221  			pointer := isPointer(sig.Recv().Type())
   222  			mtyp, err := ToType(sig, ctx)
   223  			if err != nil {
   224  				return fmt.Errorf("named methods `%s.%s` - %w", t, fn.Name(), err)
   225  			}
   226  			var mfn func(args []reflect.Value) []reflect.Value
   227  			if ctx != nil {
   228  				idx := methods[i].Index()
   229  				//				pkgPath := typ.PkgPath()
   230  				if len(idx) > 1 {
   231  					isptr := isPointer(fn.Type().Underlying().(*types.Signature).Recv().Type())
   232  					mfn = func(args []reflect.Value) []reflect.Value {
   233  						this := args[0].FieldByIndex(idx[:len(idx)-1])
   234  						if isptr && this.Kind() != reflect.Ptr {
   235  							this = this.Addr()
   236  						}
   237  						m := methodByName(this, fn.Name())
   238  						return callValue(m, args[1:])
   239  					}
   240  				} else {
   241  					mfn = ctx.FindMethod(mtyp, fn)
   242  				}
   243  			}
   244  			var pkgpath string
   245  			if pkg := fn.Pkg(); pkg != nil {
   246  				pkgpath = pkg.Path()
   247  			}
   248  			ms = append(ms, reflectx.MakeMethod(fn.Name(), pkgpath, pointer, mtyp, mfn))
   249  		}
   250  		return reflectx.SetMethodSet(typ, ms, false)
   251  	}
   252  	fn()
   253  	return typ, fn
   254  }
   255  
   256  func toNamedType(t *types.Named, ctx Context) (reflect.Type, error) {
   257  	name := t.Obj()
   258  	if name.Pkg() == nil {
   259  		if name.Name() == "error" {
   260  			return tyErrorInterface, nil
   261  		}
   262  		return ToType(t.Underlying(), ctx)
   263  	}
   264  	if ctx != nil {
   265  		if t, ok := ctx.FindTypeName(name); ok {
   266  			return t, nil
   267  		}
   268  	}
   269  	utype, err := ToType(t.Underlying(), ctx)
   270  	if err != nil {
   271  		return nil, fmt.Errorf("named type `%s` - %w", name.Name(), err)
   272  	}
   273  	typ := reflectx.NamedTypeOf(name.Pkg().Path(), name.Name(), utype)
   274  	var fnUpdate func() error
   275  	if typ.Kind() != reflect.Interface {
   276  		typ, fnUpdate = toMethodSet(t, typ, ctx)
   277  	}
   278  	ctx.UpdateType(name, typ, fnUpdate)
   279  	return typ, nil
   280  }
   281  
   282  func isPointer(typ types.Type) bool {
   283  	_, ok := typ.Underlying().(*types.Pointer)
   284  	return ok
   285  }
   286  
   287  func toInterfaceType(t *types.Interface, ctx Context) (reflect.Type, error) {
   288  	n := t.NumMethods()
   289  	if n == 0 {
   290  		return tyEmptyInterface, nil
   291  	}
   292  	ms := make([]reflect.Method, n)
   293  	for i := 0; i < n; i++ {
   294  		fn := t.Method(i)
   295  		mtyp, err := ToType(fn.Type(), ctx)
   296  		if err != nil {
   297  			return nil, fmt.Errorf("unknown interface method `%v` `%s` type - %w", t, fn.Name(), err)
   298  		}
   299  		ms[i] = reflect.Method{
   300  			Name: fn.Name(),
   301  			Type: mtyp,
   302  		}
   303  		if pkg := fn.Pkg(); pkg != nil {
   304  			ms[i].PkgPath = pkg.Path()
   305  		}
   306  	}
   307  	return reflectx.InterfaceOf(nil, ms), nil
   308  }
   309  
   310  // Context interface
   311  type Context interface {
   312  	FindType(typ types.Type) (reflect.Type, bool)
   313  	FindTypeName(name *types.TypeName) (reflect.Type, bool)
   314  	FindMethod(mtyp reflect.Type, method *types.Func) func(args []reflect.Value) []reflect.Value
   315  	UpdateType(name *types.TypeName, typ reflect.Type, fnUpdateMethods func() error)
   316  }
   317  
   318  type typeScope struct {
   319  	rtype map[reflect.Type]reflect.Type // pre_type => type
   320  }
   321  
   322  type context struct {
   323  	scope        map[*types.Scope]*typeScope
   324  	ntype        map[reflect.Type](func() error) // type => update_methods
   325  	findMethod   func(mtyp reflect.Type, method *types.Func) func(args []reflect.Value) []reflect.Value
   326  	findTypeName func(name *types.TypeName) (reflect.Type, bool)
   327  	findType     func(typ types.Type) (reflect.Type, bool)
   328  }
   329  
   330  func NewContext(
   331  	findMethod func(mtyp reflect.Type, method *types.Func) func(args []reflect.Value) []reflect.Value,
   332  	findTypeName func(name *types.TypeName) (reflect.Type, bool),
   333  	findType func(typ types.Type) (reflect.Type, bool),
   334  ) Context {
   335  	ctx := &context{
   336  		scope:        make(map[*types.Scope]*typeScope),
   337  		ntype:        make(map[reflect.Type](func() error)),
   338  		findMethod:   findMethod,
   339  		findTypeName: findTypeName,
   340  		findType:     findType,
   341  	}
   342  	if ctx.findMethod == nil {
   343  		ctx.findMethod = func(mtyp reflect.Type, method *types.Func) func(args []reflect.Value) []reflect.Value {
   344  			return nil
   345  		}
   346  	}
   347  	if ctx.findTypeName == nil {
   348  		ctx.findTypeName = func(name *types.TypeName) (reflect.Type, bool) {
   349  			return nil, false
   350  		}
   351  	}
   352  	if ctx.findType == nil {
   353  		ctx.findType = func(typ types.Type) (reflect.Type, bool) {
   354  			return nil, false
   355  		}
   356  	}
   357  	return ctx
   358  }
   359  
   360  func (t *context) FindMethod(mtyp reflect.Type, method *types.Func) func(args []reflect.Value) []reflect.Value {
   361  	return t.findMethod(mtyp, method)
   362  }
   363  
   364  func (t *context) FindType(typ types.Type) (reflect.Type, bool) {
   365  	return t.findType(typ)
   366  }
   367  
   368  func (t *typeScope) FindTypeName(name *types.TypeName) (reflect.Type, bool) {
   369  	for k, v := range t.rtype {
   370  		if k.PkgPath() == name.Pkg().Path() && k.Name() == name.Name() {
   371  			if v != nil {
   372  				return v, true
   373  			}
   374  			return k, true
   375  		}
   376  	}
   377  	typ := reflectx.NamedTypeOf(name.Pkg().Path(), name.Name(), tyEmptyInterface)
   378  	t.rtype[typ] = nil
   379  	return typ, false
   380  }
   381  
   382  func typeId(typ reflect.Type) string {
   383  	var id string
   384  	if path := typ.PkgPath(); path != "" {
   385  		id = path + "."
   386  	}
   387  	return id + typ.Name()
   388  }
   389  
   390  func (t *typeScope) UpdateType(typ reflect.Type) {
   391  	rmap := make(map[string]reflect.Type)
   392  	for k, v := range t.rtype {
   393  		if k.PkgPath() == typ.PkgPath() && k.Name() == typ.Name() {
   394  			t.rtype[k] = typ
   395  			v = typ
   396  		}
   397  		if v != nil {
   398  			rmap[typeId(k)] = v
   399  		}
   400  	}
   401  	for _, v := range t.rtype {
   402  		if v != nil {
   403  			reflectx.ReplaceType(v.PkgPath(), v, rmap)
   404  		}
   405  	}
   406  }
   407  
   408  func (t *context) findScope(parent *types.Scope) *typeScope {
   409  	scope, ok := t.scope[parent]
   410  	if !ok {
   411  		scope = &typeScope{make(map[reflect.Type]reflect.Type)}
   412  		t.scope[parent] = scope
   413  	}
   414  	return scope
   415  }
   416  func (t *context) FindTypeName(name *types.TypeName) (reflect.Type, bool) {
   417  	if typ, ok := t.findTypeName(name); ok {
   418  		return typ, true
   419  	}
   420  	return t.findScope(name.Parent()).FindTypeName(name)
   421  }
   422  
   423  func (t *context) UpdateType(name *types.TypeName, typ reflect.Type, fnUpdateMethods func() error) {
   424  	t.findScope(name.Parent()).UpdateType(typ)
   425  	if fnUpdateMethods != nil {
   426  		t.ntype[typ] = fnUpdateMethods
   427  		for _, fn := range t.ntype {
   428  			fn()
   429  		}
   430  	}
   431  }
   432  
   433  // golang.org/x/tools/go/types/typeutil.IntuitiveMethodSet
   434  func IntuitiveMethodSet(T types.Type) []*types.Selection {
   435  	isPointerToConcrete := func(T types.Type) bool {
   436  		ptr, ok := T.(*types.Pointer)
   437  		return ok && !types.IsInterface(ptr.Elem())
   438  	}
   439  
   440  	var result []*types.Selection
   441  	mset := types.NewMethodSet(T)
   442  	if types.IsInterface(T) || isPointerToConcrete(T) {
   443  		for i, n := 0, mset.Len(); i < n; i++ {
   444  			result = append(result, mset.At(i))
   445  		}
   446  	} else {
   447  		// T is some other concrete type.
   448  		// Report methods of T and *T, preferring those of T.
   449  		pmset := types.NewMethodSet(types.NewPointer(T))
   450  		for i, n := 0, pmset.Len(); i < n; i++ {
   451  			meth := pmset.At(i)
   452  			if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
   453  				meth = m
   454  			}
   455  			result = append(result, meth)
   456  		}
   457  	}
   458  	return result
   459  }