github.com/goplus/igop@v0.25.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, ok := r.ctx.pkgs[pkg.Path]
   171  		if !ok {
   172  			var err error
   173  			tp, err = r.ctx.addImportFile(pkg.Path, pkg.Name+".go", pkg.Source)
   174  			if err != nil {
   175  				return nil, err
   176  			}
   177  		}
   178  		if err := tp.Load(); err != nil {
   179  			return nil, err
   180  		}
   181  		tp.Register = true
   182  		r.packages[path] = tp.Package
   183  		r.installed[path] = pkg
   184  		return tp.Package, nil
   185  	}
   186  	if err := r.installPackage(pkg); err != nil {
   187  		return nil, err
   188  	}
   189  	var list []*types.Package
   190  	for dep := range pkg.Deps {
   191  		if p, ok := r.packages[dep]; ok {
   192  			list = append(list, p)
   193  		}
   194  	}
   195  	p.SetImports(list)
   196  	p.MarkComplete()
   197  	return p, nil
   198  }
   199  
   200  func (r *TypesLoader) installPackage(pkg *Package) (err error) {
   201  	defer func() {
   202  		if e := recover(); e != nil {
   203  			err = e.(error)
   204  		}
   205  		r.curpkg = nil
   206  	}()
   207  	r.curpkg = pkg
   208  	r.installed[pkg.Path] = pkg
   209  	p, ok := r.packages[pkg.Path]
   210  	if !ok {
   211  		p = types.NewPackage(pkg.Path, pkg.Name)
   212  		r.packages[pkg.Path] = p
   213  	}
   214  	for name, typ := range pkg.Interfaces {
   215  		r.InsertInterface(p, name, typ)
   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.NamedTypes {
   223  		if typ.Kind() != reflect.Struct {
   224  			r.InsertNamedType(p, name, typ)
   225  		}
   226  	}
   227  	for name, typ := range pkg.AliasTypes {
   228  		r.InsertAlias(p, name, typ)
   229  	}
   230  	for name, fn := range pkg.Funcs {
   231  		r.InsertFunc(p, name, fn)
   232  	}
   233  	for name, v := range pkg.Vars {
   234  		r.InsertVar(p, name, v.Elem())
   235  	}
   236  	for name, c := range pkg.TypedConsts {
   237  		r.InsertTypedConst(p, name, c)
   238  	}
   239  	for name, c := range pkg.UntypedConsts {
   240  		r.InsertUntypedConst(p, name, c)
   241  	}
   242  	return
   243  }
   244  
   245  func (r *TypesLoader) InsertInterface(p *types.Package, name string, rt reflect.Type) {
   246  	r.ToType(rt)
   247  }
   248  
   249  func (r *TypesLoader) InsertNamedType(p *types.Package, name string, rt reflect.Type) {
   250  	r.ToType(rt)
   251  }
   252  
   253  func (r *TypesLoader) InsertAlias(p *types.Package, name string, rt reflect.Type) {
   254  	typ := r.ToType(rt)
   255  	p.Scope().Insert(types.NewTypeName(token.NoPos, p, name, typ))
   256  }
   257  
   258  func (r *TypesLoader) InsertFunc(p *types.Package, name string, v reflect.Value) {
   259  	typ := r.ToType(v.Type())
   260  	p.Scope().Insert(types.NewFunc(token.NoPos, p, name, typ.(*types.Signature)))
   261  }
   262  
   263  func (r *TypesLoader) InsertVar(p *types.Package, name string, v reflect.Value) {
   264  	typ := r.ToType(v.Type())
   265  	p.Scope().Insert(types.NewVar(token.NoPos, p, name, typ))
   266  }
   267  
   268  func (r *TypesLoader) InsertConst(p *types.Package, name string, typ types.Type, c constant.Value) {
   269  	p.Scope().Insert(types.NewConst(token.NoPos, p, name, typ, c))
   270  }
   271  
   272  func splitPath(path string) (pkg string, name string, ok bool) {
   273  	pos := strings.LastIndex(path, ".")
   274  	if pos == -1 {
   275  		return path, "", false
   276  	}
   277  	return path[:pos], path[pos+1:], true
   278  }
   279  
   280  func (r *TypesLoader) parserNamed(path string) (*types.Package, string) {
   281  	if pkg, name, ok := splitPath(path); ok {
   282  		if p := r.GetPackage(pkg); p != nil {
   283  			return p, name
   284  		}
   285  	}
   286  	panic(fmt.Errorf("parse path failed: %v", path))
   287  }
   288  
   289  func (r *TypesLoader) LookupType(typ string) types.Type {
   290  	if t, ok := basicTypeNames[typ]; ok {
   291  		return t
   292  	}
   293  	p, name := r.parserNamed(typ)
   294  	return p.Scope().Lookup(name).Type()
   295  }
   296  
   297  func (r *TypesLoader) InsertTypedConst(p *types.Package, name string, v TypedConst) {
   298  	typ := r.ToType(v.Typ)
   299  	r.InsertConst(p, name, typ, v.Value)
   300  }
   301  
   302  func (r *TypesLoader) InsertUntypedConst(p *types.Package, name string, v UntypedConst) {
   303  	var typ types.Type
   304  	if t, ok := basicTypeNames[v.Typ]; ok {
   305  		typ = t
   306  	} else {
   307  		typ = r.LookupType(v.Typ)
   308  	}
   309  	r.InsertConst(p, name, typ, v.Value)
   310  }
   311  
   312  func (r *TypesLoader) GetPackage(pkg string) *types.Package {
   313  	if pkg == "" {
   314  		return nil
   315  	}
   316  	if p, ok := r.packages[pkg]; ok {
   317  		return p
   318  	}
   319  	var name string
   320  	if r.curpkg != nil {
   321  		name = r.curpkg.Deps[pkg]
   322  	}
   323  	if name == "" {
   324  		pkgs := strings.Split(pkg, "/")
   325  		name = pkgs[len(pkgs)-1]
   326  	}
   327  	p := types.NewPackage(pkg, name)
   328  	r.packages[pkg] = p
   329  	return p
   330  }
   331  
   332  func toTypeChanDir(dir reflect.ChanDir) types.ChanDir {
   333  	switch dir {
   334  	case reflect.RecvDir:
   335  		return types.RecvOnly
   336  	case reflect.SendDir:
   337  		return types.SendOnly
   338  	case reflect.BothDir:
   339  		return types.SendRecv
   340  	}
   341  	panic("unreachable")
   342  }
   343  
   344  func (r *TypesLoader) Insert(v reflect.Value) {
   345  	typ := r.ToType(v.Type())
   346  	if v.Kind() == reflect.Func {
   347  		name := runtime.FuncForPC(v.Pointer()).Name()
   348  		names := strings.Split(name, ".")
   349  		pkg := r.GetPackage(names[0])
   350  		pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, names[1], typ.(*types.Signature)))
   351  	}
   352  }
   353  
   354  func (r *TypesLoader) toMethod(pkg *types.Package, recv *types.Var, inoff int, rt reflect.Type) *types.Signature {
   355  	numIn := rt.NumIn()
   356  	numOut := rt.NumOut()
   357  	in := make([]*types.Var, numIn-inoff)
   358  	out := make([]*types.Var, numOut)
   359  	for i := inoff; i < numIn; i++ {
   360  		it := r.ToType(rt.In(i))
   361  		in[i-inoff] = types.NewVar(token.NoPos, pkg, "", it)
   362  	}
   363  	for i := 0; i < numOut; i++ {
   364  		it := r.ToType(rt.Out(i))
   365  		out[i] = types.NewVar(token.NoPos, pkg, "", it)
   366  	}
   367  	return types.NewSignature(recv, types.NewTuple(in...), types.NewTuple(out...), rt.IsVariadic())
   368  }
   369  
   370  func (r *TypesLoader) toFunc(pkg *types.Package, rt reflect.Type) *types.Signature {
   371  	numIn := rt.NumIn()
   372  	numOut := rt.NumOut()
   373  	in := make([]*types.Var, numIn)
   374  	out := make([]*types.Var, numOut)
   375  	// mock type
   376  	variadic := rt.IsVariadic()
   377  	if variadic {
   378  		for i := 0; i < numIn-1; i++ {
   379  			in[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   380  		}
   381  		in[numIn-1] = types.NewVar(token.NoPos, pkg, "", typesDummySlice)
   382  	} else {
   383  		for i := 0; i < numIn; i++ {
   384  			in[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   385  		}
   386  	}
   387  	for i := 0; i < numOut; i++ {
   388  		out[i] = types.NewVar(token.NoPos, pkg, "", typesDummyStruct)
   389  	}
   390  	typ := types.NewSignature(nil, types.NewTuple(in...), types.NewTuple(out...), variadic)
   391  	r.rcache[rt] = typ
   392  	r.tcache.Set(typ, rt)
   393  	// real type
   394  	for i := 0; i < numIn; i++ {
   395  		it := r.ToType(rt.In(i))
   396  		in[i] = types.NewVar(token.NoPos, pkg, "", it)
   397  	}
   398  	for i := 0; i < numOut; i++ {
   399  		it := r.ToType(rt.Out(i))
   400  		out[i] = types.NewVar(token.NoPos, pkg, "", it)
   401  	}
   402  	return typ
   403  }
   404  
   405  func (r *TypesLoader) ToType(rt reflect.Type) types.Type {
   406  	if t, ok := r.rcache[rt]; ok {
   407  		return t
   408  	}
   409  	var isNamed bool
   410  	var pkgPath string
   411  	// check complete pkg named type
   412  	if pkgPath = rt.PkgPath(); pkgPath != "" {
   413  		if pkg, ok := r.packages[pkgPath]; ok && pkg.Complete() {
   414  			if obj := pkg.Scope().Lookup(rt.Name()); obj != nil {
   415  				typ := obj.Type()
   416  				r.rcache[rt] = typ
   417  				return typ
   418  			}
   419  		}
   420  		isNamed = true
   421  	}
   422  	var typ types.Type
   423  	var fields []*types.Var
   424  	var imethods []*types.Func
   425  	kind := rt.Kind()
   426  	switch kind {
   427  	case reflect.Invalid:
   428  		typ = types.Typ[types.Invalid]
   429  	case reflect.Bool:
   430  		typ = types.Typ[types.Bool]
   431  	case reflect.Int:
   432  		typ = types.Typ[types.Int]
   433  	case reflect.Int8:
   434  		typ = types.Typ[types.Int8]
   435  	case reflect.Int16:
   436  		typ = types.Typ[types.Int16]
   437  	case reflect.Int32:
   438  		typ = types.Typ[types.Int32]
   439  	case reflect.Int64:
   440  		typ = types.Typ[types.Int64]
   441  	case reflect.Uint:
   442  		typ = types.Typ[types.Uint]
   443  	case reflect.Uint8:
   444  		typ = types.Typ[types.Uint8]
   445  	case reflect.Uint16:
   446  		typ = types.Typ[types.Uint16]
   447  	case reflect.Uint32:
   448  		typ = types.Typ[types.Uint32]
   449  	case reflect.Uint64:
   450  		typ = types.Typ[types.Uint64]
   451  	case reflect.Uintptr:
   452  		typ = types.Typ[types.Uintptr]
   453  	case reflect.Float32:
   454  		typ = types.Typ[types.Float32]
   455  	case reflect.Float64:
   456  		typ = types.Typ[types.Float64]
   457  	case reflect.Complex64:
   458  		typ = types.Typ[types.Complex64]
   459  	case reflect.Complex128:
   460  		typ = types.Typ[types.Complex128]
   461  	case reflect.Array:
   462  		elem := r.ToType(rt.Elem())
   463  		typ = types.NewArray(elem, int64(rt.Len()))
   464  	case reflect.Chan:
   465  		elem := r.ToType(rt.Elem())
   466  		dir := toTypeChanDir(rt.ChanDir())
   467  		typ = types.NewChan(dir, elem)
   468  	case reflect.Func:
   469  		if !isNamed {
   470  			typ = r.toMethod(nil, nil, 0, rt)
   471  		} else {
   472  			typ = typesDummySig
   473  		}
   474  	case reflect.Interface:
   475  		n := rt.NumMethod()
   476  		imethods = make([]*types.Func, n)
   477  		for i := 0; i < n; i++ {
   478  			im := rt.Method(i)
   479  			sig := typesDummySig
   480  			pkg := r.GetPackage(im.PkgPath)
   481  			imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig)
   482  		}
   483  		typ = types.NewInterfaceType(imethods, nil)
   484  	case reflect.Map:
   485  		key := r.ToType(rt.Key())
   486  		elem := r.ToType(rt.Elem())
   487  		typ = types.NewMap(key, elem)
   488  	case reflect.Ptr:
   489  		elem := r.ToType(rt.Elem())
   490  		typ = types.NewPointer(elem)
   491  	case reflect.Slice:
   492  		elem := r.ToType(rt.Elem())
   493  		typ = types.NewSlice(elem)
   494  	case reflect.String:
   495  		typ = types.Typ[types.String]
   496  	case reflect.Struct:
   497  		n := rt.NumField()
   498  		fields = make([]*types.Var, n)
   499  		tags := make([]string, n)
   500  		pkg := r.GetPackage(rt.PkgPath())
   501  		for i := 0; i < n; i++ {
   502  			f := rt.Field(i)
   503  			ft := types.Typ[types.UnsafePointer] //r.ToType(f.Type)
   504  			fields[i] = types.NewVar(token.NoPos, pkg, f.Name, ft)
   505  			tags[i] = string(f.Tag)
   506  		}
   507  		typ = types.NewStruct(fields, tags)
   508  	case reflect.UnsafePointer:
   509  		typ = types.Typ[types.UnsafePointer]
   510  	default:
   511  		panic("unreachable")
   512  	}
   513  	var named *types.Named
   514  	if isNamed {
   515  		pkg := r.GetPackage(pkgPath)
   516  		obj := types.NewTypeName(token.NoPos, pkg, rt.Name(), nil)
   517  		named = types.NewNamed(obj, typ, nil)
   518  		typ = named
   519  		pkg.Scope().Insert(obj)
   520  	}
   521  	r.rcache[rt] = typ
   522  	r.tcache.Set(typ, rt)
   523  	if kind == reflect.Struct {
   524  		n := rt.NumField()
   525  		pkg := r.GetPackage(pkgPath)
   526  		for i := 0; i < n; i++ {
   527  			f := rt.Field(i)
   528  			if enabledTypeParam && r.hasTypeArgs(f.Type) {
   529  				continue
   530  			}
   531  			ft := r.ToType(f.Type)
   532  			fields[i] = types.NewField(token.NoPos, pkg, f.Name, ft, f.Anonymous)
   533  		}
   534  	} else if kind == reflect.Interface {
   535  		n := rt.NumMethod()
   536  		pkg := r.GetPackage(rt.PkgPath())
   537  		recv := types.NewVar(token.NoPos, pkg, "", typ)
   538  		for i := 0; i < n; i++ {
   539  			im := rt.Method(i)
   540  			pkg := r.GetPackage(im.PkgPath)
   541  			sig := r.toMethod(pkg, recv, 0, im.Type)
   542  			imethods[i] = types.NewFunc(token.NoPos, pkg, im.Name, sig)
   543  		}
   544  		typ.Underlying().(*types.Interface).Complete()
   545  	}
   546  	if named != nil {
   547  		switch kind {
   548  		case reflect.Func:
   549  			named.SetUnderlying(r.toMethod(named.Obj().Pkg(), nil, 0, rt))
   550  		}
   551  		if kind != reflect.Interface {
   552  			pkg := named.Obj().Pkg()
   553  			skip := make(map[string]bool)
   554  			recv := types.NewVar(token.NoPos, pkg, "", typ)
   555  			for _, im := range allMethodX(rt) {
   556  				var sig *types.Signature
   557  				if im.Type != nil {
   558  					sig = r.toMethod(pkg, recv, 1, im.Type)
   559  				} else {
   560  					sig = r.toMethod(pkg, recv, 0, tyEmptyFunc)
   561  				}
   562  				skip[im.Name] = true
   563  				named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig))
   564  			}
   565  			prt := reflect.PtrTo(rt)
   566  			ptyp := r.ToType(prt)
   567  			precv := types.NewVar(token.NoPos, pkg, "", ptyp)
   568  			for _, im := range allMethodX(prt) {
   569  				if skip[im.Name] {
   570  					continue
   571  				}
   572  				var sig *types.Signature
   573  				if im.Type != nil {
   574  					sig = r.toMethod(pkg, precv, 1, im.Type)
   575  				} else {
   576  					sig = r.toMethod(pkg, precv, 0, tyEmptyFunc)
   577  				}
   578  				named.AddMethod(types.NewFunc(token.NoPos, pkg, im.Name, sig))
   579  			}
   580  		}
   581  	}
   582  	return typ
   583  }