github.com/goplus/igop@v0.17.0/rtypes.go (about)

     1  /*
     2   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     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 igop
    18  
    19  import (
    20  	"fmt"
    21  	"go/constant"
    22  	"go/importer"
    23  	"go/token"
    24  	"go/types"
    25  	"reflect"
    26  	"runtime"
    27  	"strings"
    28  
    29  	"golang.org/x/tools/go/types/typeutil"
    30  )
    31  
    32  var (
    33  	basicTypeNames = make(map[string]*types.Basic)
    34  )
    35  
    36  var (
    37  	typesDummyStruct    = types.NewStruct(nil, nil)
    38  	typesDummySig       = types.NewSignature(nil, nil, nil, false)
    39  	typesDummySlice     = types.NewSlice(typesDummyStruct)
    40  	typesError          = types.Universe.Lookup("error").Type()
    41  	typesEmptyInterface = types.NewInterfaceType(nil, nil)
    42  )
    43  
    44  var (
    45  	tyEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem()
    46  	tyErrorInterface = reflect.TypeOf((*error)(nil)).Elem()
    47  )
    48  
    49  func init() {
    50  	for i := types.Invalid; i <= types.UntypedNil; i++ {
    51  		typ := types.Typ[i]
    52  		basicTypeNames[typ.String()] = typ
    53  	}
    54  }
    55  
    56  type TypesLoader struct {
    57  	importer  types.Importer
    58  	ctx       *Context
    59  	tcache    *typeutil.Map
    60  	curpkg    *Package
    61  	packages  map[string]*types.Package
    62  	installed map[string]*Package
    63  	pkgloads  map[string]func() error
    64  	rcache    map[reflect.Type]types.Type
    65  	mode      Mode
    66  }
    67  
    68  // NewTypesLoader install package and readonly
    69  func NewTypesLoader(ctx *Context, mode Mode) Loader {
    70  	r := &TypesLoader{
    71  		packages:  make(map[string]*types.Package),
    72  		installed: make(map[string]*Package),
    73  		pkgloads:  make(map[string]func() error),
    74  		rcache:    make(map[reflect.Type]types.Type),
    75  		tcache:    &typeutil.Map{},
    76  		ctx:       ctx,
    77  		mode:      mode,
    78  	}
    79  	r.packages["unsafe"] = types.Unsafe
    80  	r.rcache[tyErrorInterface] = typesError
    81  	r.rcache[tyEmptyInterface] = typesEmptyInterface
    82  	r.importer = importer.Default()
    83  	return r
    84  }
    85  
    86  func (r *TypesLoader) SetImport(path string, pkg *types.Package, load func() error) error {
    87  	r.packages[path] = pkg
    88  	if load != nil {
    89  		r.pkgloads[path] = load
    90  	}
    91  	return nil
    92  }
    93  
    94  func (r *TypesLoader) Installed(path string) (pkg *Package, ok bool) {
    95  	pkg, ok = r.installed[path]
    96  	return
    97  }
    98  
    99  func (r *TypesLoader) Packages() (pkgs []*types.Package) {
   100  	for _, pkg := range r.packages {
   101  		pkgs = append(pkgs, pkg)
   102  	}
   103  	return
   104  }
   105  
   106  func (r *TypesLoader) LookupPackage(pkgpath string) (*types.Package, bool) {
   107  	pkg, ok := r.packages[pkgpath]
   108  	return pkg, ok
   109  }
   110  
   111  func (r *TypesLoader) lookupRelfect(typ types.Type) (reflect.Type, bool) {
   112  	var star bool
   113  	if t, ok := typ.(*types.Pointer); ok {
   114  		star = true
   115  		typ = t.Elem()
   116  	}
   117  	if named, ok := typ.(*types.Named); ok {
   118  		if pkg := named.Obj().Pkg(); pkg != nil {
   119  			if p, ok := r.installed[pkg.Path()]; ok {
   120  				if rt, ok := p.NamedTypes[named.Obj().Name()]; ok {
   121  					if star {
   122  						rt = reflect.PtrTo(rt)
   123  					}
   124  					return rt, true
   125  				}
   126  			}
   127  		}
   128  	}
   129  	return nil, false
   130  }
   131  
   132  func (r *TypesLoader) LookupReflect(typ types.Type) (reflect.Type, bool) {
   133  	if rt := r.tcache.At(typ); rt != nil {
   134  		return rt.(reflect.Type), true
   135  	}
   136  	if rt, ok := r.lookupRelfect(typ); ok {
   137  		r.tcache.Set(typ, rt)
   138  		return rt, ok
   139  	}
   140  	return nil, false
   141  }
   142  
   143  func (r *TypesLoader) LookupTypes(typ reflect.Type) (types.Type, bool) {
   144  	t, ok := r.rcache[typ]
   145  	return t, ok
   146  }
   147  
   148  func (r *TypesLoader) Import(path string) (*types.Package, error) {
   149  	if p, ok := r.packages[path]; ok {
   150  		if !p.Complete() {
   151  			if load, ok := r.pkgloads[path]; ok {
   152  				load()
   153  			}
   154  			if pkg, ok := registerPkgs[path]; ok {
   155  				r.installed[path] = pkg
   156  			}
   157  		}
   158  		return p, nil
   159  	}
   160  	pkg, ok := registerPkgs[path]
   161  	if !ok {
   162  		return nil, fmt.Errorf("not found package %v", path)
   163  	}
   164  	p := types.NewPackage(pkg.Path, pkg.Name)
   165  	r.packages[path] = p
   166  	for dep := range pkg.Deps {
   167  		r.Import(dep)
   168  	}
   169  	if len(pkg.Source) > 0 {
   170  		tp, err := r.ctx.addImportFile(pkg.Path, pkg.Name+".go", pkg.Source)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  		if err := tp.Load(); err != nil {
   175  			return nil, err
   176  		}
   177  		r.packages[path] = tp.Package
   178  		r.installed[path] = pkg
   179  		return tp.Package, nil
   180  	}
   181  	if err := r.installPackage(pkg); err != nil {
   182  		return nil, err
   183  	}
   184  	var list []*types.Package
   185  	for dep := range pkg.Deps {
   186  		if p, ok := r.packages[dep]; ok {
   187  			list = append(list, p)
   188  		}
   189  	}
   190  	p.SetImports(list)
   191  	p.MarkComplete()
   192  	return p, nil
   193  }
   194  
   195  func (r *TypesLoader) installPackage(pkg *Package) (err error) {
   196  	defer func() {
   197  		if e := recover(); e != nil {
   198  			err = e.(error)
   199  		}
   200  		r.curpkg = nil
   201  	}()
   202  	r.curpkg = pkg
   203  	r.installed[pkg.Path] = pkg
   204  	p, ok := r.packages[pkg.Path]
   205  	if !ok {
   206  		p = types.NewPackage(pkg.Path, pkg.Name)
   207  		r.packages[pkg.Path] = p
   208  	}
   209  	for name, typ := range pkg.Interfaces {
   210  		r.InsertInterface(p, name, typ)
   211  	}
   212  	for name, typ := range pkg.NamedTypes {
   213  		if typ.Kind() == reflect.Struct {
   214  			r.InsertNamedType(p, name, typ)
   215  		}
   216  	}
   217  	for name, typ := range pkg.NamedTypes {
   218  		if typ.Kind() != reflect.Struct {
   219  			r.InsertNamedType(p, name, typ)
   220  		}
   221  	}
   222  	for name, typ := range pkg.AliasTypes {
   223  		r.InsertAlias(p, name, typ)
   224  	}
   225  	for name, fn := range pkg.Funcs {
   226  		r.InsertFunc(p, name, fn)
   227  	}
   228  	for name, v := range pkg.Vars {
   229  		r.InsertVar(p, name, v.Elem())
   230  	}
   231  	for name, c := range pkg.TypedConsts {
   232  		r.InsertTypedConst(p, name, c)
   233  	}
   234  	for name, c := range pkg.UntypedConsts {
   235  		r.InsertUntypedConst(p, name, c)
   236  	}
   237  	return
   238  }
   239  
   240  func (r *TypesLoader) InsertInterface(p *types.Package, name string, rt reflect.Type) {
   241  	r.ToType(rt)
   242  }
   243  
   244  func (r *TypesLoader) InsertNamedType(p *types.Package, name string, rt reflect.Type) {
   245  	r.ToType(rt)
   246  }
   247  
   248  func (r *TypesLoader) InsertAlias(p *types.Package, name string, rt reflect.Type) {
   249  	typ := r.ToType(rt)
   250  	p.Scope().Insert(types.NewTypeName(token.NoPos, p, name, typ))
   251  }
   252  
   253  func (r *TypesLoader) InsertFunc(p *types.Package, name string, v reflect.Value) {
   254  	typ := r.ToType(v.Type())
   255  	p.Scope().Insert(types.NewFunc(token.NoPos, p, name, typ.(*types.Signature)))
   256  }
   257  
   258  func (r *TypesLoader) InsertVar(p *types.Package, name string, v reflect.Value) {
   259  	typ := r.ToType(v.Type())
   260  	p.Scope().Insert(types.NewVar(token.NoPos, p, name, typ))
   261  }
   262  
   263  func (r *TypesLoader) InsertConst(p *types.Package, name string, typ types.Type, c constant.Value) {
   264  	p.Scope().Insert(types.NewConst(token.NoPos, p, name, typ, c))
   265  }
   266  
   267  func splitPath(path string) (pkg string, name string, ok bool) {
   268  	pos := strings.LastIndex(path, ".")
   269  	if pos == -1 {
   270  		return path, "", false
   271  	}
   272  	return path[:pos], path[pos+1:], true
   273  }
   274  
   275  func (r *TypesLoader) parserNamed(path string) (*types.Package, string) {
   276  	if pkg, name, ok := splitPath(path); ok {
   277  		if p := r.GetPackage(pkg); p != nil {
   278  			return p, name
   279  		}
   280  	}
   281  	panic(fmt.Errorf("parse path failed: %v", path))
   282  }
   283  
   284  func (r *TypesLoader) LookupType(typ string) types.Type {
   285  	if t, ok := basicTypeNames[typ]; ok {
   286  		return t
   287  	}
   288  	p, name := r.parserNamed(typ)
   289  	return p.Scope().Lookup(name).Type()
   290  }
   291  
   292  func (r *TypesLoader) InsertTypedConst(p *types.Package, name string, v TypedConst) {
   293  	typ := r.ToType(v.Typ)
   294  	r.InsertConst(p, name, typ, v.Value)
   295  }
   296  
   297  func (r *TypesLoader) InsertUntypedConst(p *types.Package, name string, v UntypedConst) {
   298  	var typ types.Type
   299  	if t, ok := basicTypeNames[v.Typ]; ok {
   300  		typ = t
   301  	} else {
   302  		typ = r.LookupType(v.Typ)
   303  	}
   304  	r.InsertConst(p, name, typ, v.Value)
   305  }
   306  
   307  func (r *TypesLoader) GetPackage(pkg string) *types.Package {
   308  	if pkg == "" {
   309  		return nil
   310  	}
   311  	if p, ok := r.packages[pkg]; ok {
   312  		return p
   313  	}
   314  	var name string
   315  	if r.curpkg != nil {
   316  		name = r.curpkg.Deps[pkg]
   317  	}
   318  	if name == "" {
   319  		pkgs := strings.Split(pkg, "/")
   320  		name = pkgs[len(pkgs)-1]
   321  	}
   322  	p := types.NewPackage(pkg, name)
   323  	r.packages[pkg] = p
   324  	return p
   325  }
   326  
   327  func toTypeChanDir(dir reflect.ChanDir) types.ChanDir {
   328  	switch dir {
   329  	case reflect.RecvDir:
   330  		return types.RecvOnly
   331  	case reflect.SendDir:
   332  		return types.SendOnly
   333  	case reflect.BothDir:
   334  		return types.SendRecv
   335  	}
   336  	panic("unreachable")
   337  }
   338  
   339  func (r *TypesLoader) Insert(v reflect.Value) {
   340  	typ := r.ToType(v.Type())
   341  	if v.Kind() == reflect.Func {
   342  		name := runtime.FuncForPC(v.Pointer()).Name()
   343  		names := strings.Split(name, ".")
   344  		pkg := r.GetPackage(names[0])
   345  		pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, names[1], typ.(*types.Signature)))
   346  	}
   347  }
   348  
   349  func (r *TypesLoader) toMethod(pkg *types.Package, recv *types.Var, inoff int, rt reflect.Type) *types.Signature {
   350  	numIn := rt.NumIn()
   351  	numOut := rt.NumOut()
   352  	in := make([]*types.Var, numIn-inoff)
   353  	out := make([]*types.Var, numOut)
   354  	for i := inoff; i < numIn; i++ {
   355  		it := r.ToType(rt.In(i))
   356  		in[i-inoff] = types.NewVar(token.NoPos, pkg, "", it)
   357  	}
   358  	for i := 0; i < numOut; i++ {
   359  		it := r.ToType(rt.Out(i))
   360  		out[i] = types.NewVar(token.NoPos, pkg, "", it)
   361  	}
   362  	return types.NewSignature(recv, types.NewTuple(in...), types.NewTuple(out...), rt.IsVariadic())
   363  }
   364  
   365  func (r *TypesLoader) toFunc(pkg *types.Package, rt reflect.Type) *types.Signature {
   366  	numIn := rt.NumIn()
   367  	numOut := rt.NumOut()
   368  	in := make([]*types.Var, numIn)
   369  	out := make([]*types.Var, numOut)
   370  	// mock type
   371  	variadic := rt.IsVariadic()
   372  	if variadic {
   373  		for i := 0; i < numIn-1; i++ {
   374  			in[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   375  		}
   376  		in[numIn-1] = types.NewVar(token.NoPos, pkg, "", typesDummySlice)
   377  	} else {
   378  		for i := 0; i < numIn; i++ {
   379  			in[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   380  		}
   381  	}
   382  	for i := 0; i < numOut; i++ {
   383  		out[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   384  	}
   385  	typ := types.NewSignature(nil, types.NewTuple(in...), types.NewTuple(out...), variadic)
   386  	r.rcache[rt] = typ
   387  	r.tcache.Set(typ, rt)
   388  	// real type
   389  	for i := 0; i < numIn; i++ {
   390  		it := r.ToType(rt.In(i))
   391  		in[i] = types.NewVar(token.NoPos, pkg, "", it)
   392  	}
   393  	for i := 0; i < numOut; i++ {
   394  		it := r.ToType(rt.Out(i))
   395  		out[i] = types.NewVar(token.NoPos, pkg, "", it)
   396  	}
   397  	return typ
   398  }
   399  
   400  func (r *TypesLoader) ToType(rt reflect.Type) types.Type {
   401  	if t, ok := r.rcache[rt]; ok {
   402  		return t
   403  	}
   404  	var isNamed bool
   405  	var pkgPath string
   406  	// check complete pkg named type
   407  	if pkgPath = rt.PkgPath(); pkgPath != "" {
   408  		if pkg, ok := r.packages[pkgPath]; ok && pkg.Complete() {
   409  			if obj := pkg.Scope().Lookup(rt.Name()); obj != nil {
   410  				typ := obj.Type()
   411  				r.rcache[rt] = typ
   412  				return typ
   413  			}
   414  		}
   415  		isNamed = true
   416  	}
   417  	var typ types.Type
   418  	var fields []*types.Var
   419  	var imethods []*types.Func
   420  	kind := rt.Kind()
   421  	switch kind {
   422  	case reflect.Invalid:
   423  		typ = types.Typ[types.Invalid]
   424  	case reflect.Bool:
   425  		typ = types.Typ[types.Bool]
   426  	case reflect.Int:
   427  		typ = types.Typ[types.Int]
   428  	case reflect.Int8:
   429  		typ = types.Typ[types.Int8]
   430  	case reflect.Int16:
   431  		typ = types.Typ[types.Int16]
   432  	case reflect.Int32:
   433  		typ = types.Typ[types.Int32]
   434  	case reflect.Int64:
   435  		typ = types.Typ[types.Int64]
   436  	case reflect.Uint:
   437  		typ = types.Typ[types.Uint]
   438  	case reflect.Uint8:
   439  		typ = types.Typ[types.Uint8]
   440  	case reflect.Uint16:
   441  		typ = types.Typ[types.Uint16]
   442  	case reflect.Uint32:
   443  		typ = types.Typ[types.Uint32]
   444  	case reflect.Uint64:
   445  		typ = types.Typ[types.Uint64]
   446  	case reflect.Uintptr:
   447  		typ = types.Typ[types.Uintptr]
   448  	case reflect.Float32:
   449  		typ = types.Typ[types.Float32]
   450  	case reflect.Float64:
   451  		typ = types.Typ[types.Float64]
   452  	case reflect.Complex64:
   453  		typ = types.Typ[types.Complex64]
   454  	case reflect.Complex128:
   455  		typ = types.Typ[types.Complex128]
   456  	case reflect.Array:
   457  		elem := r.ToType(rt.Elem())
   458  		typ = types.NewArray(elem, int64(rt.Len()))
   459  	case reflect.Chan:
   460  		elem := r.ToType(rt.Elem())
   461  		dir := toTypeChanDir(rt.ChanDir())
   462  		typ = types.NewChan(dir, elem)
   463  	case reflect.Func:
   464  		if !isNamed {
   465  			typ = r.toMethod(nil, nil, 0, rt)
   466  		} else {
   467  			typ = typesDummySig
   468  		}
   469  	case reflect.Interface:
   470  		n := rt.NumMethod()
   471  		imethods = make([]*types.Func, n)
   472  		pkg := r.GetPackage(rt.PkgPath())
   473  		for i := 0; i < n; i++ {
   474  			im := rt.Method(i)
   475  			sig := typesDummySig
   476  			imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig)
   477  		}
   478  		typ = types.NewInterfaceType(imethods, nil)
   479  	case reflect.Map:
   480  		key := r.ToType(rt.Key())
   481  		elem := r.ToType(rt.Elem())
   482  		typ = types.NewMap(key, elem)
   483  	case reflect.Ptr:
   484  		elem := r.ToType(rt.Elem())
   485  		typ = types.NewPointer(elem)
   486  	case reflect.Slice:
   487  		elem := r.ToType(rt.Elem())
   488  		typ = types.NewSlice(elem)
   489  	case reflect.String:
   490  		typ = types.Typ[types.String]
   491  	case reflect.Struct:
   492  		n := rt.NumField()
   493  		fields = make([]*types.Var, n)
   494  		tags := make([]string, n)
   495  		pkg := r.GetPackage(rt.PkgPath())
   496  		for i := 0; i < n; i++ {
   497  			f := rt.Field(i)
   498  			ft := types.Typ[types.UnsafePointer] //r.ToType(f.Type)
   499  			fields[i] = types.NewVar(token.NoPos, pkg, f.Name, ft)
   500  			tags[i] = string(f.Tag)
   501  		}
   502  		typ = types.NewStruct(fields, tags)
   503  	case reflect.UnsafePointer:
   504  		typ = types.Typ[types.UnsafePointer]
   505  	default:
   506  		panic("unreachable")
   507  	}
   508  	var named *types.Named
   509  	if isNamed {
   510  		pkg := r.GetPackage(pkgPath)
   511  		obj := types.NewTypeName(token.NoPos, pkg, rt.Name(), nil)
   512  		named = types.NewNamed(obj, typ, nil)
   513  		typ = named
   514  		pkg.Scope().Insert(obj)
   515  	}
   516  	r.rcache[rt] = typ
   517  	r.tcache.Set(typ, rt)
   518  	if kind == reflect.Struct {
   519  		n := rt.NumField()
   520  		pkg := r.GetPackage(pkgPath)
   521  		for i := 0; i < n; i++ {
   522  			f := rt.Field(i)
   523  			if enabledTypeParam && r.hasTypeArgs(f.Type) {
   524  				continue
   525  			}
   526  			ft := r.ToType(f.Type)
   527  			fields[i] = types.NewField(token.NoPos, pkg, f.Name, ft, f.Anonymous)
   528  		}
   529  	} else if kind == reflect.Interface {
   530  		n := rt.NumMethod()
   531  		pkg := named.Obj().Pkg()
   532  		recv := types.NewVar(token.NoPos, pkg, "", typ)
   533  		for i := 0; i < n; i++ {
   534  			im := rt.Method(i)
   535  			sig := r.toMethod(pkg, recv, 0, im.Type)
   536  			imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig)
   537  		}
   538  		typ.Underlying().(*types.Interface).Complete()
   539  	}
   540  	if named != nil {
   541  		switch kind {
   542  		case reflect.Func:
   543  			named.SetUnderlying(r.toMethod(named.Obj().Pkg(), nil, 0, rt))
   544  		}
   545  		if kind != reflect.Interface {
   546  			pkg := named.Obj().Pkg()
   547  			skip := make(map[string]bool)
   548  			recv := types.NewVar(token.NoPos, pkg, "", typ)
   549  			for _, im := range allMethodX(rt) {
   550  				var sig *types.Signature
   551  				if im.Type != nil {
   552  					sig = r.toMethod(pkg, recv, 1, im.Type)
   553  				} else {
   554  					sig = r.toMethod(pkg, recv, 0, tyEmptyFunc)
   555  				}
   556  				skip[im.Name] = true
   557  				named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig))
   558  			}
   559  			prt := reflect.PtrTo(rt)
   560  			ptyp := r.ToType(prt)
   561  			precv := types.NewVar(token.NoPos, pkg, "", ptyp)
   562  			for _, im := range allMethodX(prt) {
   563  				if skip[im.Name] {
   564  					continue
   565  				}
   566  				var sig *types.Signature
   567  				if im.Type != nil {
   568  					sig = r.toMethod(pkg, precv, 1, im.Type)
   569  				} else {
   570  					sig = r.toMethod(pkg, precv, 0, tyEmptyFunc)
   571  				}
   572  				named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig))
   573  			}
   574  		}
   575  	}
   576  	return typ
   577  }