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 }