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