1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2017-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * fromreflect.go 12 * 13 * Created on May 07, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package xreflect 18 19import ( 20 "go/ast" 21 "go/token" 22 "go/types" 23 "reflect" 24 "strings" 25) 26 27// TypeOf creates a Type corresponding to reflect.TypeOf() of given value. 28// Note: conversions from Type to reflect.Type and back are not exact, 29// because of the reasons listed in Type.ReflectType() 30// Conversions from reflect.Type to Type and back are not exact for the same reasons. 31func (v *Universe) TypeOf(rvalue interface{}) Type { 32 return v.FromReflectType(reflect.TypeOf(rvalue)) 33} 34 35// FromReflectType creates a Type corresponding to given reflect.Type 36// Note: conversions from Type to reflect.Type and back are not exact, 37// because of the reasons listed in Type.ReflectType() 38// Conversions from reflect.Type to Type and back are not exact for the same reasons. 39func (v *Universe) FromReflectType(rtype reflect.Type) Type { 40 if rtype == nil { 41 return nil 42 } 43 if v.ThreadSafe { 44 defer un(lock(v)) 45 } 46 defer v.partialTypes.clear() 47 48 if v.debug() { 49 v.debugf("FromReflectType: %v", rtype) 50 defer de(bug(v)) 51 } 52 53 t := v.fromReflectType(rtype) 54 55 // add methods only after generating all requested types. 56 // reason: cannot add methods to incomplete types, 57 // their t.gunderlying() will often be interface{} 58 // 59 // we need to iterate multiple times because new types 60 // may be added to v.partialTypes.gmap while iterating 61 for v.partialTypes.gmap.Len() != 0 { 62 vec := v.partialTypes.gmap.Values() 63 v.partialTypes.clear() 64 for _, interf := range vec { 65 if interf != nil { 66 ti := interf.(Type) 67 v.addmethods(ti, ti.ReflectType()) 68 } 69 } 70 } 71 return t 72} 73 74func (v *Universe) fromReflectType(rtype reflect.Type) Type { 75 if rtype == nil { 76 return nil 77 } 78 t := v.BasicTypes[rtype.Kind()] 79 if t != nil && t.ReflectType() == rtype { 80 return t 81 } 82 debug := v.debug() 83 if t = v.ReflectTypes[rtype]; t != nil { 84 if debug { 85 if rtype != t.ReflectType() { 86 v.debugf("warning: mismatched rtype cache: %v -> %v (%v)", rtype, t, t.ReflectType()) 87 } 88 } 89 // time.Sleep(100 * time.Millisecond) 90 return t 91 } 92 name := rtype.Name() 93 tryresolve := v.TryResolve 94 if tryresolve != nil && len(name) != 0 { 95 t = tryresolve(name, rtype.PkgPath()) 96 if t != nil { 97 if debug { 98 v.debugf("found named type using TryResolve: %v -> %v", t, rtype) 99 } 100 v.queueForAddMethods(t, rtype) 101 return t 102 } 103 } 104 if v.rebuild() { 105 // decrement ONLY here and in fromReflectPtr() when calling fromReflectInterfacePtrStruct() 106 v.RebuildDepth-- 107 defer func() { 108 v.RebuildDepth++ 109 }() 110 } 111 // when converting a named type and v.Importer cannot locate it, 112 // immediately register it in the cache because it may reference itself, 113 // as for example type List struct { Elem int; Rest *List } 114 // otherwise we may get an infinite recursion 115 if len(name) != 0 { 116 if !v.rebuild() { 117 if t = v.namedTypeFromImport(rtype); unwrap(t) != nil { 118 v.queueForAddMethods(t, rtype) 119 return t 120 } 121 } 122 // t.gunderlying() will often be interface{}. ugly and dangerous, but no solution 123 t = v.reflectNamedOf(name, rtype.PkgPath(), rtype.Kind(), rtype) 124 v.cache(rtype, t) // support self-referencing types 125 } 126 if debug { 127 v.debugf("%s %v", rtype.Kind(), rtype) 128 defer de(bug(v)) 129 } 130 131 var u Type 132 switch k := rtype.Kind(); k { 133 case reflect.Invalid: 134 return nil 135 case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 136 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 137 reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String, 138 reflect.UnsafePointer: 139 u = v.BasicTypes[k] 140 case reflect.Array: 141 u = v.fromReflectArray(rtype) 142 case reflect.Chan: 143 u = v.fromReflectChan(rtype) 144 case reflect.Func: 145 u = v.fromReflectFunc(rtype) 146 case reflect.Interface: 147 u = v.fromReflectInterface(rtype) 148 case reflect.Map: 149 u = v.fromReflectMap(rtype) 150 case reflect.Ptr: 151 u = v.fromReflectPtr(rtype) 152 case reflect.Slice: 153 u = v.fromReflectSlice(rtype) 154 case reflect.Struct: 155 u = v.fromReflectStruct(rtype) 156 default: 157 errorf(t, "unsupported reflect.Type %v", rtype) 158 } 159 if t == nil { 160 t = u 161 // cache before adding methods - otherwise we get an infinite recursion 162 // if u is a pointer to named type with methods that reference the named type 163 v.cache(rtype, t) 164 } else { 165 t.SetUnderlying(u) 166 // t.ReflectType() is now u.ReflectType(). overwrite with the exact rtype instead 167 if !v.rebuild() { 168 t.UnsafeForceReflectType(rtype) 169 } 170 } 171 v.queueForAddMethods(t, rtype) 172 return t 173} 174 175func (v *Universe) queueForAddMethods(t Type, rtype reflect.Type) bool { 176 if rtype.NumMethod() != 0 || rtype.Kind() != reflect.Ptr && reflect.PtrTo(rtype).NumMethod() != 0 { 177 // FromReflectType() will invoke addmethods(t, t.ReflectType()) on all v.partialTypes 178 v.debugf("will scan methods of: %v", t) 179 v.partialTypes.add(t) 180 return true 181 } 182 v.debugf("no methods to scan for: %v", rtype) 183 return false 184} 185 186func (v *Universe) addmethods(t Type, rtype reflect.Type) Type { 187 xt := unwrap(t) 188 if xt.kind == reflect.Interface { 189 // fromReflectInterface() already added methods to interface. 190 return t 191 } 192 // collect methods with both value and pointer receiver 193 rtypes := [2]reflect.Type{rtype, rtype} 194 if rtype.Kind() == reflect.Ptr { 195 rtypes[0] = rtype.Elem() 196 } else { 197 rtypes[1] = reflect.PtrTo(rtype) 198 } 199 ntotal := rtypes[0].NumMethod() + rtypes[1].NumMethod() 200 if ntotal == 0 { 201 return t 202 } 203 if xt.kind == reflect.Ptr { 204 if xt.Named() { 205 errorf(t, "CANNOT add methods to named pointer %v", t) 206 } else { 207 // methods on pointer-to-type. add them to the type itself 208 xt = unwrap(xt.elem()) 209 if xt.kind == reflect.Interface { 210 errorf(t, "CANNOT add methods to pointer to interface %v", t) 211 } else if xt.kind == reflect.Ptr { 212 errorf(t, "CANNOT add methods to pointer to pointer %v", t) 213 } 214 } 215 } 216 if !xt.Named() { 217 // debugf("NOT adding methods to unnamed type %v", t) 218 return t 219 } 220 debug := v.debug() 221 if xt.kind != gtypeToKind(xt, xt.gtype) { 222 if debug { 223 v.debugf("NOT adding methods to incomplete named type %v. call SetUnderlying() first.", xt) 224 } 225 return t 226 } 227 if xt.methodvalues != nil { 228 // prevent another infinite recursion: Type.AddMethod() may reference the type itself in its methods 229 // debugf("NOT adding again %d methods to %v", n, tm) 230 return t 231 } 232 if debug { 233 v.debugf("adding methods to: %v", xt) 234 defer de(bug(v)) 235 } 236 xt.methodvalues = make([]reflect.Value, 0, ntotal) 237 nilv := reflect.Value{} 238 if v.rebuild() { 239 v.RebuildDepth-- 240 } 241 gtype := xt.gtype.(*types.Named) 242 cache := makeGmethodMap(gtype) 243 244 for _, rtype := range rtypes { 245 for i, ni := 0, rtype.NumMethod(); i < ni; i++ { 246 rmethod := rtype.Method(i) 247 qname := QName2(rmethod.Name, rmethod.PkgPath) 248 if cache[qname] { 249 if debug { 250 m, _ := xt.methodByName(rmethod.Name, rmethod.PkgPath) 251 v.debugf("method already present: %v", m) 252 } 253 continue 254 } 255 256 signature := v.fromReflectMethod(rmethod.Type) 257 n1 := xt.NumExplicitMethod() 258 xt.AddMethod(rmethod.Name, signature) 259 n2 := xt.NumExplicitMethod() 260 if n1 == n2 { 261 if debug { 262 m, _ := xt.methodByName(rmethod.Name, rmethod.PkgPath) 263 v.debugf("method already present (case 2, should not happen): %v", m) 264 } 265 continue 266 } 267 for len(xt.methodvalues) < n2 { 268 xt.methodvalues = append(xt.methodvalues, nilv) 269 } 270 xt.methodvalues[n1] = rmethod.Func 271 cache[qname] = true 272 if debug { 273 m := xt.method(n1) 274 v.debugf("added method %v", m) 275 } 276 } 277 } 278 return t 279} 280 281func makeGmethodMap(gtype *types.Named) map[QName]bool { 282 n := gtype.NumMethods() 283 m := make(map[QName]bool) 284 for i := 0; i < n; i++ { 285 m[QNameGo(gtype.Method(i))] = true 286 } 287 return m 288} 289 290func (v *Universe) fromReflectField(rfield *reflect.StructField) StructField { 291 t := v.fromReflectType(rfield.Type) 292 name := rfield.Name 293 anonymous := rfield.Anonymous 294 295 if strings.HasPrefix(name, StrGensymAnonymous) { 296 // this reflect.StructField emulates anonymous field using our own convention. 297 // eat our own dogfood and convert it back to an anonymous field. 298 name = name[len(StrGensymAnonymous):] 299 if len(name) == 0 || name[0] >= '0' && name[0] <= '9' { 300 rtype := rfield.Type 301 name = rtype.Name() 302 // rebuild the type's name and package 303 t = v.rebuildnamed(t, name, rtype.PkgPath()) 304 } 305 anonymous = true 306 } else if strings.HasPrefix(name, StrGensymPrivate) { 307 // this reflect.StructField emulates private (unexported) field using our own convention. 308 // eat our own dogfood and convert it back to a private field. 309 name = name[len(StrGensymPrivate):] 310 } 311 312 return StructField{ 313 Name: name, 314 Pkg: v.loadPackage(rfield.PkgPath), 315 Type: t, 316 Tag: rfield.Tag, 317 Offset: rfield.Offset, 318 Index: rfield.Index, 319 Anonymous: anonymous, 320 } 321} 322 323// rebuildnamed re-creates a named Type based on t, having the given name and pkgpath 324func (v *Universe) rebuildnamed(t Type, name string, pkgpath string) Type { 325 if t.Name() != name || t.PkgPath() != pkgpath { 326 t2 := v.namedOf(name, pkgpath, t.Kind()) 327 rtype := t.ReflectType() 328 // do not trust v.maketype() detection of reflect.Kind from t.gunderlying(): 329 // t may be incomplete, thus t.gunderlying() could be a dummy interface{} 330 t2.SetUnderlying(v.maketype3(t.Kind(), t.gunderlying(), ReflectUnderlying(rtype))) 331 t2.UnsafeForceReflectType(rtype) 332 t = t2 333 } 334 return t 335} 336 337// fromReflectArray converts a reflect.Type with Kind reflect.Array into a Type 338func (v *Universe) fromReflectArray(rtype reflect.Type) Type { 339 count := rtype.Len() 340 elem := v.fromReflectType(rtype.Elem()) 341 if true || v.rebuild() { // rtype may be named... clean it 342 rtype = reflect.ArrayOf(count, elem.ReflectType()) 343 } 344 return v.maketype(types.NewArray(elem.GoType(), int64(count)), rtype) 345} 346 347// fromReflectChan converts a reflect.Type with Kind reflect.Chan into a Type 348func (v *Universe) fromReflectChan(rtype reflect.Type) Type { 349 dir := rtype.ChanDir() 350 elem := v.fromReflectType(rtype.Elem()) 351 if true || v.rebuild() { // rtype may be named... clean it 352 rtype = reflect.ChanOf(dir, elem.ReflectType()) 353 } 354 gdir := dirToGdir(dir) 355 return v.maketype(types.NewChan(gdir, elem.GoType()), rtype) 356} 357 358// fromReflectFunc converts a reflect.Type with Kind reflect.Func into a function Type 359func (v *Universe) fromReflectFunc(rtype reflect.Type) Type { 360 nin, nout := rtype.NumIn(), rtype.NumOut() 361 in := make([]Type, nin) 362 out := make([]Type, nout) 363 for i := 0; i < nin; i++ { 364 in[i] = v.fromReflectType(rtype.In(i)) 365 } 366 for i := 0; i < nout; i++ { 367 out[i] = v.fromReflectType(rtype.Out(i)) 368 } 369 gin := toGoTuple(in) 370 gout := toGoTuple(out) 371 variadic := rtype.IsVariadic() 372 373 if true || v.rebuild() { // rtype may be named... clean it 374 rin := toReflectTypes(in) 375 rout := toReflectTypes(out) 376 rtype = reflect.FuncOf(rin, rout, variadic) 377 } 378 return v.maketype( 379 types.NewSignature(nil, gin, gout, variadic), 380 rtype, 381 ) 382} 383 384// fromReflectMethod converts a reflect.Type with Kind reflect.Func into a method Type, 385// i.e. into a function with receiver 386func (v *Universe) fromReflectMethod(rtype reflect.Type) Type { 387 nin, nout := rtype.NumIn(), rtype.NumOut() 388 if nin == 0 { 389 errorf(nil, "fromReflectMethod: function type has zero arguments, cannot use first one as receiver: <%v>", rtype) 390 } 391 in := make([]Type, nin) 392 out := make([]Type, nout) 393 for i := 0; i < nin; i++ { 394 in[i] = v.fromReflectType(rtype.In(i)) 395 } 396 for i := 0; i < nout; i++ { 397 out[i] = v.fromReflectType(rtype.Out(i)) 398 } 399 grecv := toGoParam(in[0]) 400 gin := toGoTuple(in[1:]) 401 gout := toGoTuple(out) 402 variadic := rtype.IsVariadic() 403 404 if v.RebuildDepth > 1 { 405 rin := toReflectTypes(in) 406 rout := toReflectTypes(out) 407 rtype = reflect.FuncOf(rin, rout, variadic) 408 } 409 return v.maketype( 410 types.NewSignature(grecv, gin, gout, variadic), 411 rtype, 412 ) 413} 414 415// fromReflectMethod converts a reflect.Type with Kind reflect.Func into a method Type, 416// manually adding the given type as receiver 417func (v *Universe) fromReflectInterfaceMethod(rtype, rmethod reflect.Type) Type { 418 return v.fromReflectMethod(rAddReceiver(rtype, rmethod)) 419} 420 421// fromReflectInterface converts a reflect.Type with Kind reflect.Interface into a Type 422func (v *Universe) fromReflectInterface(rtype reflect.Type) Type { 423 if rtype == v.TypeOfInterface.ReflectType() { 424 return v.TypeOfInterface 425 } 426 n := rtype.NumMethod() 427 gmethods := make([]*types.Func, n) 428 for i := 0; i < n; i++ { 429 rmethod := rtype.Method(i) 430 method := v.fromReflectFunc(rmethod.Type) // do NOT add a receiver: types.NewInterface() will add it 431 pkg := v.loadPackage(rmethod.PkgPath) 432 if v.debug() { 433 debugf("fromReflectInterface: add interface method rtype: %v, gotype: %v (receiver: %v)", rmethod.Type, method.GoType(), method.GoType().(*types.Signature).Recv()) 434 } 435 // types.NewInterface() below will modify method.GoType() by adding a receiver: 436 // clone it NOW in order to detach from xreflect.Type and its associated reflect.Type 437 // otherwise the modified method.GoType() will remain inside an unmodified xreflect.Type 438 // Strange bugs happen then, see https://github.com/gopherdata/gophernotes/issues/151 439 gsig := cloneGoSignature(method.GoType().(*types.Signature)) 440 gmethods[i] = types.NewFunc(token.NoPos, (*types.Package)(pkg), rmethod.Name, gsig) 441 } 442 // no way to extract embedded interfaces from reflect.Type. Just collect all methods 443 if v.rebuild() { 444 rfields := make([]reflect.StructField, 1+n) 445 rfields[0] = approxInterfaceHeader() 446 for i := 0; i < n; i++ { 447 rmethod := rtype.Method(i) 448 rmethodtype := rmethod.Type 449 if v.RebuildDepth > 1 { 450 // needed? method := v.FromReflectType(rmethod.Type) above 451 // should already rebuild rmethod.Type.ReflectType() 452 rmethodtype = v.fromReflectInterfaceMethod(rtype, rmethod.Type).ReflectType() 453 } 454 rfields[i+1] = approxInterfaceMethodAsField(rmethod.Name, rmethodtype) 455 } 456 // interfaces may have lots of methods, thus a lot of fields in the proxy struct. 457 // Then use a pointer to the proxy struct: InterfaceOf() does that, and we must behave identically 458 rtype = reflect.PtrTo(reflect.StructOf(rfields)) 459 } 460 return v.maketype(types.NewInterface(gmethods, nil).Complete(), rtype) 461} 462 463// isReflectInterfaceStruct returns true if rtype is a reflect.Type with Kind reflect.Struct, 464// that contains our own conventions to emulate an interface 465func isReflectInterfaceStruct(rtype reflect.Type) bool { 466 if rtype.Kind() == reflect.Struct { 467 if n := rtype.NumField(); n != 0 { 468 rfield := rtype.Field(0) 469 return rfield.Name == StrGensymInterface && rfield.Type == rTypeOfInterfaceHeader 470 } 471 } 472 return false 473} 474 475// fromReflectInterfacePtrStruct converts a reflect.Type with Kind reflect.Ptr, 476// that contains our own conventions to emulate an interface, into a Type 477func (v *Universe) fromReflectInterfacePtrStruct(rtype reflect.Type) Type { 478 if rtype.Kind() != reflect.Ptr || rtype.Elem().Kind() != reflect.Struct { 479 errorf(nil, "internal error: fromReflectInterfacePtrStruct expects pointer-to-struct reflect.Type, found: %v", rtype) 480 } 481 rebuild := v.rebuild() 482 rtype = rtype.Elem() 483 n := rtype.NumField() 484 // skip rtype.Field(0), it is just approxInterfaceSelf() 485 var gmethods []*types.Func 486 var gembeddeds []*types.Named 487 var rebuildfields []reflect.StructField 488 if rebuild { 489 rebuildfields = make([]reflect.StructField, n) 490 rebuildfields[0] = approxInterfaceHeader() 491 } 492 for i := 1; i < n; i++ { 493 rfield := rtype.Field(i) 494 name := rfield.Name 495 496 if strings.HasPrefix(name, StrGensymPrivate) { 497 name = name[len(StrGensymPrivate):] 498 } 499 t := v.fromReflectFunc(rfield.Type) 500 if t.Kind() != reflect.Func { 501 errorf(t, "FromReflectType: reflect.Type <%v> is an emulated interface containing the method <%v>.\n\tExtracting the latter returned a non-function: %v", t) 502 } 503 gtype := t.GoType().Underlying() 504 pkg := v.loadPackage(rfield.PkgPath) 505 gmethods = append(gmethods, types.NewFunc(token.NoPos, (*types.Package)(pkg), name, gtype.(*types.Signature))) 506 if rebuild { 507 rebuildfields[i] = approxInterfaceMethodAsField(name, t.ReflectType()) 508 } 509 } 510 if rebuild { 511 rtype = reflect.PtrTo(reflect.StructOf(rebuildfields)) 512 } 513 return v.maketype(types.NewInterface(gmethods, gembeddeds).Complete(), rtype) 514} 515 516func (v *Universe) fromReflectInterfaceEmbeddeds(rinterf, rtype reflect.Type) []Type { 517 if rtype.Kind() != reflect.Array || rtype.Len() != 0 || rtype.Elem().Kind() != reflect.Struct { 518 return nil 519 } 520 rtype = rtype.Elem() 521 n := rtype.NumField() 522 ts := make([]Type, n) 523 for i := 0; i < n; i++ { 524 f := rtype.Field(i) 525 t := v.fromReflectInterface(f.Type) 526 if t.Kind() != reflect.Interface { 527 errorf(t, `FromReflectType: reflect.Type <%v> is an emulated interface containing the embedded interface <%v>. 528 Extracting the latter returned a non-interface: %v`, rinterf, f.Type, t) 529 } 530 ts[i] = t 531 } 532 return ts 533} 534 535// fromReflectMap converts a reflect.Type with Kind reflect.map into a Type 536func (v *Universe) fromReflectMap(rtype reflect.Type) Type { 537 key := v.fromReflectType(rtype.Key()) 538 elem := v.fromReflectType(rtype.Elem()) 539 if true || v.rebuild() { // rtype may be named... clean it 540 rtype = reflect.MapOf(key.ReflectType(), elem.ReflectType()) 541 } 542 return v.maketype(types.NewMap(key.GoType(), elem.GoType()), rtype) 543} 544 545// fromReflectPtr converts a reflect.Type with Kind reflect.Ptr into a Type 546func (v *Universe) fromReflectPtr(rtype reflect.Type) Type { 547 relem := rtype.Elem() 548 var gtype types.Type 549 rebuild := v.rebuild() 550 if isReflectInterfaceStruct(relem) { 551 if rebuild { 552 v.RebuildDepth-- 553 defer func() { 554 v.RebuildDepth++ 555 }() 556 } 557 t := v.fromReflectInterfacePtrStruct(rtype) 558 if rebuild { 559 relem = t.ReflectType().Elem() 560 } 561 gtype = t.GoType() 562 } else { 563 elem := v.fromReflectType(relem) 564 gtype = types.NewPointer(elem.GoType()) 565 } 566 if true || rebuild { // rtype may be named... clean it 567 rtype = reflect.PtrTo(relem) 568 } 569 return v.maketype3(reflect.Ptr, gtype, rtype) 570} 571 572// fromReflectPtr converts a reflect.Type with Kind reflect.Slice into a Type 573func (v *Universe) fromReflectSlice(rtype reflect.Type) Type { 574 elem := v.fromReflectType(rtype.Elem()) 575 if true || v.rebuild() { // rtype may be named... clean it 576 rtype = reflect.SliceOf(elem.ReflectType()) 577 } 578 return v.maketype(types.NewSlice(elem.GoType()), rtype) 579} 580 581// fromReflectStruct converts a reflect.Type with Kind reflect.Struct into a Type 582func (v *Universe) fromReflectStruct(rtype reflect.Type) Type { 583 n := rtype.NumField() 584 fields := make([]StructField, n) 585 canrebuildexactly := true 586 for i := 0; i < n; i++ { 587 rfield := rtype.Field(i) 588 fields[i] = v.fromReflectField(&rfield) 589 if canrebuildexactly && (fields[i].Anonymous || !ast.IsExported(fields[i].Name)) { 590 canrebuildexactly = false 591 } 592 } 593 vars := toGoFields(fields) 594 tags := toTags(fields) 595 596 // use reflect.StructOf to recreate reflect.Type only if requested, 597 // or if rtype is named but we can guarantee that result is 100% accurate: 598 // reflect.StructOf does not support unexported or anonymous fields, 599 // and cannot create self-referencing types from scratch. 600 if v.rebuild() || (canrebuildexactly && len(rtype.Name()) != 0) { 601 rfields := toReflectFields(fields, !v.rebuild()) 602 rtype2 := reflect.StructOf(rfields) 603 if v.rebuild() || rtype2.AssignableTo(rtype) { 604 rtype = rtype2 605 } 606 } 607 return v.maketype(types.NewStruct(vars, tags), rtype) 608} 609 610// best-effort implementation of missing reflect.Type.Underlying() 611func ReflectUnderlying(rtype reflect.Type) reflect.Type { 612 if len(rtype.Name()) == 0 { 613 return rtype 614 } 615 ru := rbasictypes[rtype.Kind()] 616 if ru != nil { 617 return ru 618 } 619 switch rtype.Kind() { 620 case reflect.Array: 621 ru = reflect.ArrayOf(rtype.Len(), rtype.Elem()) 622 case reflect.Chan: 623 ru = reflect.ChanOf(rtype.ChanDir(), rtype.Elem()) 624 case reflect.Func: 625 rin := make([]reflect.Type, rtype.NumIn()) 626 for i := range rin { 627 rin[i] = rtype.In(i) 628 } 629 rout := make([]reflect.Type, rtype.NumOut()) 630 for i := range rout { 631 rout[i] = rtype.Out(i) 632 } 633 ru = reflect.FuncOf(rin, rout, rtype.IsVariadic()) 634 case reflect.Map: 635 ru = reflect.MapOf(rtype.Key(), rtype.Elem()) 636 case reflect.Ptr: 637 ru = reflect.PtrTo(rtype.Elem()) 638 case reflect.Slice: 639 ru = reflect.SliceOf(rtype.Elem()) 640 case reflect.Struct: 641 f := make([]reflect.StructField, rtype.NumField()) 642 for i := range f { 643 f[i] = rtype.Field(i) 644 } 645 ru = reflect.StructOf(f) 646 default: 647 ru = rtype // cannot do better... reflect cannot create interfaces 648 } 649 return ru 650} 651