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 }