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 }