go.tools/ssa/interp: fixes to enable running tests of package "encoding".
Running the interpreter on (most of) the tests package in "encoding" unearthed a couple of ssa.builder bugs, already fixed. This CL contains the interpreter fixes that were required. (The "encoding" tests aren't added to the suite since they're slow.) Added intrinsics for: math.Exp math.Min hash/crc32.haveSSE42 (reflect.Type).Field (reflect.Type).NumField (reflect.Type).NumMethod reflect.New (reflect.Value).NumMethod syscall.RawSyscall (returns ENOSYS) reflect.Set (a no-op) Treat unsafe.Pointer -> *T conversions by returning new(T). This is incorrect but at least preserves type-safety, which is sufficient for these tests. hashmap: treat nil *hashmap as an empty map. R=gri CC=golang-dev https://golang.org/cl/12901046
This commit is contained in:
parent
daa44ab970
commit
7e7d99b4c9
|
@ -26,11 +26,15 @@ type externalFn func(fn *ssa.Function, args []value) value
|
|||
// Key strings are from Function.FullName().
|
||||
// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
|
||||
var externals = map[string]externalFn{
|
||||
"(*runtime.Func).Entry": ext۰runtime۰Func۰Entry,
|
||||
"(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine,
|
||||
"(*runtime.Func).Name": ext۰runtime۰Func۰Name,
|
||||
"(reflect.Value).Bool": ext۰reflect۰Value۰Bool,
|
||||
"(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
|
||||
"(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
|
||||
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
|
||||
"(reflect.Value).Field": ext۰reflect۰Value۰Field,
|
||||
"(reflect.Value).Float": ext۰reflect۰Value۰Float,
|
||||
"(reflect.Value).Index": ext۰reflect۰Value۰Index,
|
||||
"(reflect.Value).Int": ext۰reflect۰Value۰Int,
|
||||
"(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
|
||||
|
@ -39,27 +43,41 @@ var externals = map[string]externalFn{
|
|||
"(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
|
||||
"(reflect.Value).Len": ext۰reflect۰Value۰Len,
|
||||
"(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
|
||||
"(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
|
||||
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
|
||||
"(reflect.Value).Set": ext۰reflect۰Value۰Set,
|
||||
"(reflect.Value).String": ext۰reflect۰Value۰String,
|
||||
"(reflect.Value).Type": ext۰reflect۰Value۰Type,
|
||||
"(reflect.Value).Uint": ext۰reflect۰Value۰Uint,
|
||||
"(reflect.error).Error": ext۰reflect۰error۰Error,
|
||||
"(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
|
||||
"(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
|
||||
"(reflect.rtype).Field": ext۰reflect۰rtype۰Field,
|
||||
"(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
|
||||
"(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField,
|
||||
"(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod,
|
||||
"(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut,
|
||||
"(reflect.rtype).Out": ext۰reflect۰rtype۰Out,
|
||||
"(reflect.rtype).Size": ext۰reflect۰rtype۰Size,
|
||||
"(reflect.rtype).String": ext۰reflect۰rtype۰String,
|
||||
"bytes.Equal": ext۰bytes۰Equal,
|
||||
"bytes.IndexByte": ext۰bytes۰IndexByte,
|
||||
"hash/crc32.haveSSE42": ext۰crc32۰haveSSE42,
|
||||
"math.Abs": ext۰math۰Abs,
|
||||
"math.Exp": ext۰math۰Exp,
|
||||
"math.Float32bits": ext۰math۰Float32bits,
|
||||
"math.Float32frombits": ext۰math۰Float32frombits,
|
||||
"math.Float64bits": ext۰math۰Float64bits,
|
||||
"math.Float64frombits": ext۰math۰Float64frombits,
|
||||
"math.Min": ext۰math۰Min,
|
||||
"reflect.New": ext۰reflect۰New,
|
||||
"reflect.TypeOf": ext۰reflect۰TypeOf,
|
||||
"reflect.ValueOf": ext۰reflect۰ValueOf,
|
||||
"reflect.init": ext۰reflect۰Init,
|
||||
"reflect.valueInterface": ext۰reflect۰valueInterface,
|
||||
"runtime.Breakpoint": ext۰runtime۰Breakpoint,
|
||||
"runtime.Caller": ext۰runtime۰Caller,
|
||||
"runtime.FuncForPC": ext۰runtime۰FuncForPC,
|
||||
"runtime.GC": ext۰runtime۰GC,
|
||||
"runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS,
|
||||
"runtime.Gosched": ext۰runtime۰Gosched,
|
||||
|
@ -67,6 +85,7 @@ var externals = map[string]externalFn{
|
|||
"runtime.ReadMemStats": ext۰runtime۰ReadMemStats,
|
||||
"runtime.SetFinalizer": ext۰runtime۰SetFinalizer,
|
||||
"runtime.getgoroot": ext۰runtime۰getgoroot,
|
||||
"strings.IndexByte": ext۰strings۰IndexByte,
|
||||
"sync.runtime_Syncsemcheck": ext۰sync۰runtime_Syncsemcheck,
|
||||
"sync/atomic.AddInt32": ext۰atomic۰AddInt32,
|
||||
"sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32,
|
||||
|
@ -83,6 +102,7 @@ var externals = map[string]externalFn{
|
|||
"syscall.Lstat": ext۰syscall۰Lstat,
|
||||
"syscall.Open": ext۰syscall۰Open,
|
||||
"syscall.ParseDirent": ext۰syscall۰ParseDirent,
|
||||
"syscall.RawSyscall": ext۰syscall۰RawSyscall,
|
||||
"syscall.Read": ext۰syscall۰Read,
|
||||
"syscall.ReadDirent": ext۰syscall۰ReadDirent,
|
||||
"syscall.Stat": ext۰syscall۰Stat,
|
||||
|
@ -99,6 +119,18 @@ func wrapError(err error) value {
|
|||
return iface{t: errorType, v: err.Error()}
|
||||
}
|
||||
|
||||
func ext۰runtime۰Func۰Entry(fn *ssa.Function, args []value) value {
|
||||
return 0
|
||||
}
|
||||
|
||||
func ext۰runtime۰Func۰FileLine(fn *ssa.Function, args []value) value {
|
||||
return tuple{"unknown.go", -1}
|
||||
}
|
||||
|
||||
func ext۰runtime۰Func۰Name(fn *ssa.Function, args []value) value {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func ext۰bytes۰Equal(fn *ssa.Function, args []value) value {
|
||||
// func Equal(a, b []byte) bool
|
||||
a := args[0].([]value)
|
||||
|
@ -126,6 +158,10 @@ func ext۰bytes۰IndexByte(fn *ssa.Function, args []value) value {
|
|||
return -1
|
||||
}
|
||||
|
||||
func ext۰crc32۰haveSSE42(fn *ssa.Function, args []value) value {
|
||||
return false
|
||||
}
|
||||
|
||||
func ext۰math۰Float64frombits(fn *ssa.Function, args []value) value {
|
||||
return math.Float64frombits(args[0].(uint64))
|
||||
}
|
||||
|
@ -138,19 +174,56 @@ func ext۰math۰Float32frombits(fn *ssa.Function, args []value) value {
|
|||
return math.Float32frombits(args[0].(uint32))
|
||||
}
|
||||
|
||||
func ext۰math۰Abs(fn *ssa.Function, args []value) value {
|
||||
return math.Abs(args[0].(float64))
|
||||
}
|
||||
|
||||
func ext۰math۰Exp(fn *ssa.Function, args []value) value {
|
||||
return math.Exp(args[0].(float64))
|
||||
}
|
||||
|
||||
func ext۰math۰Float32bits(fn *ssa.Function, args []value) value {
|
||||
return math.Float32bits(args[0].(float32))
|
||||
}
|
||||
|
||||
func ext۰math۰Min(fn *ssa.Function, args []value) value {
|
||||
return math.Min(args[0].(float64), args[1].(float64))
|
||||
}
|
||||
|
||||
func ext۰runtime۰Breakpoint(fn *ssa.Function, args []value) value {
|
||||
runtime.Breakpoint()
|
||||
return nil
|
||||
}
|
||||
|
||||
func ext۰runtime۰Caller(fn *ssa.Function, args []value) value {
|
||||
// TODO(adonovan): actually inspect the stack.
|
||||
return tuple{0, "somefile.go", 42, true}
|
||||
}
|
||||
|
||||
func ext۰runtime۰FuncForPC(fn *ssa.Function, args []value) value {
|
||||
// TODO(adonovan): actually inspect the stack.
|
||||
return (*value)(nil)
|
||||
//tuple{0, "somefile.go", 42, true}
|
||||
//
|
||||
//func FuncForPC(pc uintptr) *Func
|
||||
}
|
||||
|
||||
func ext۰runtime۰getgoroot(fn *ssa.Function, args []value) value {
|
||||
return os.Getenv("GOROOT")
|
||||
}
|
||||
|
||||
func ext۰strings۰IndexByte(fn *ssa.Function, args []value) value {
|
||||
// func IndexByte(s string, c byte) int
|
||||
s := args[0].(string)
|
||||
c := args[1].(byte)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func ext۰sync۰runtime_Syncsemcheck(fn *ssa.Function, args []value) value {
|
||||
return nil
|
||||
}
|
||||
|
@ -222,6 +295,14 @@ func ext۰runtime۰SetFinalizer(fn *ssa.Function, args []value) value {
|
|||
return nil // ignore
|
||||
}
|
||||
|
||||
func ext۰runtime۰funcname_go(fn *ssa.Function, args []value) value {
|
||||
// TODO(adonovan): actually inspect the stack.
|
||||
return (*value)(nil)
|
||||
//tuple{0, "somefile.go", 42, true}
|
||||
//
|
||||
//func FuncForPC(pc uintptr) *Func
|
||||
}
|
||||
|
||||
func ext۰time۰now(fn *ssa.Function, args []value) value {
|
||||
nano := time.Now().UnixNano()
|
||||
return tuple{int64(nano / 1e9), int32(nano % 1e9)}
|
||||
|
@ -245,6 +326,10 @@ func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
|
|||
return syscall.Getpid()
|
||||
}
|
||||
|
||||
func ext۰syscall۰RawSyscall(fn *ssa.Function, args []value) value {
|
||||
return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
|
||||
}
|
||||
|
||||
// The set of remaining native functions we need to implement (as needed):
|
||||
|
||||
// crypto/aes/cipher_asm.go:10:func hasAsm() bool
|
||||
|
@ -272,7 +357,6 @@ func ext۰syscall۰Getpid(fn *ssa.Function, args []value) value {
|
|||
// math/big/arith_decl.go:19:func bitLen(x Word) (n int)
|
||||
// math/dim.go:13:func Dim(x, y float64) float64
|
||||
// math/dim.go:26:func Max(x, y float64) float64
|
||||
// math/dim.go:53:func Min(x, y float64) float64
|
||||
// math/exp.go:14:func Exp(x float64) float64
|
||||
// math/exp.go:135:func Exp2(x float64) float64
|
||||
// math/expm1.go:124:func Expm1(x float64) float64
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package interp
|
||||
|
||||
// Custom hashtable atop map.
|
||||
|
@ -42,22 +46,24 @@ func makeMap(kt types.Type, reserve int) value {
|
|||
|
||||
// delete removes the association for key k, if any.
|
||||
func (m *hashmap) delete(k hashable) {
|
||||
hash := k.hash()
|
||||
head := m.table[hash]
|
||||
if head != nil {
|
||||
if k.eq(head.key) {
|
||||
m.table[hash] = head.next
|
||||
m.length--
|
||||
return
|
||||
}
|
||||
prev := head
|
||||
for e := head.next; e != nil; e = e.next {
|
||||
if k.eq(e.key) {
|
||||
prev.next = e.next
|
||||
if m != nil {
|
||||
hash := k.hash()
|
||||
head := m.table[hash]
|
||||
if head != nil {
|
||||
if k.eq(head.key) {
|
||||
m.table[hash] = head.next
|
||||
m.length--
|
||||
return
|
||||
}
|
||||
prev = e
|
||||
prev := head
|
||||
for e := head.next; e != nil; e = e.next {
|
||||
if k.eq(e.key) {
|
||||
prev.next = e.next
|
||||
m.length--
|
||||
return
|
||||
}
|
||||
prev = e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,10 +71,12 @@ func (m *hashmap) delete(k hashable) {
|
|||
// lookup returns the value associated with key k, if present, or
|
||||
// value(nil) otherwise.
|
||||
func (m *hashmap) lookup(k hashable) value {
|
||||
hash := k.hash()
|
||||
for e := m.table[hash]; e != nil; e = e.next {
|
||||
if k.eq(e.key) {
|
||||
return e.value
|
||||
if m != nil {
|
||||
hash := k.hash()
|
||||
for e := m.table[hash]; e != nil; e = e.next {
|
||||
if k.eq(e.key) {
|
||||
return e.value
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -97,5 +105,8 @@ func (m *hashmap) insert(k hashable, v value) {
|
|||
|
||||
// len returns the number of key/value associations in the map.
|
||||
func (m *hashmap) len() int {
|
||||
return m.length
|
||||
if m != nil {
|
||||
return m.length
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package interp
|
||||
|
||||
import (
|
||||
|
@ -1205,7 +1209,8 @@ func conv(t_dst, t_src types.Type, x value) value {
|
|||
// TODO(adonovan): this is wrong and cannot
|
||||
// really be fixed with the current design.
|
||||
//
|
||||
// It creates a new pointer of a different
|
||||
// return (*value)(x.(unsafe.Pointer))
|
||||
// creates a new pointer of a different
|
||||
// type but the underlying interface value
|
||||
// knows its "true" type and so cannot be
|
||||
// meaningfully used through the new pointer.
|
||||
|
@ -1213,7 +1218,11 @@ func conv(t_dst, t_src types.Type, x value) value {
|
|||
// To make this work, the interpreter needs to
|
||||
// simulate the memory layout of a real
|
||||
// compiled implementation.
|
||||
return (*value)(x.(unsafe.Pointer))
|
||||
//
|
||||
// To at least preserve type-safety, we'll
|
||||
// just return the zero value of the
|
||||
// destination type.
|
||||
return zero(t_dst)
|
||||
}
|
||||
|
||||
// Conversions between complex numeric types?
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package interp
|
||||
|
||||
// Emulated "reflect" package.
|
||||
|
@ -113,11 +117,37 @@ func ext۰reflect۰rtype۰Elem(fn *ssa.Function, args []value) value {
|
|||
}).Elem()})
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰Field(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype, i int) reflect.StructField
|
||||
st := args[0].(rtype).t.Underlying().(*types.Struct)
|
||||
i := args[1].(int)
|
||||
f := st.Field(i)
|
||||
return structure{
|
||||
f.Name(),
|
||||
f.Pkg().Path(),
|
||||
makeReflectType(rtype{f.Type()}),
|
||||
st.Tag(i),
|
||||
0, // TODO(adonovan): offset
|
||||
[]value{}, // TODO(adonovan): indices
|
||||
f.Anonymous(),
|
||||
}
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰Kind(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) uint
|
||||
return uint(reflectKind(args[0].(rtype).t))
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰NumField(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) int
|
||||
return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰NumMethod(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) int
|
||||
return args[0].(rtype).t.MethodSet().Len()
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰NumOut(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) int
|
||||
return args[0].(rtype).t.(*types.Signature).Results().Len()
|
||||
|
@ -129,11 +159,24 @@ func ext۰reflect۰rtype۰Out(fn *ssa.Function, args []value) value {
|
|||
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰Size(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) uintptr
|
||||
// (Assumes no custom Sizeof used during SSA construction.)
|
||||
return uintptr(types.DefaultSizeof(args[0].(rtype).t))
|
||||
}
|
||||
|
||||
func ext۰reflect۰rtype۰String(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) string
|
||||
return args[0].(rtype).t.String()
|
||||
}
|
||||
|
||||
func ext۰reflect۰New(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.Type) reflect.Value
|
||||
t := args[0].(iface).v.(rtype).t
|
||||
alloc := zero(t)
|
||||
return makeReflectValue(types.NewPointer(t), &alloc)
|
||||
}
|
||||
|
||||
func ext۰reflect۰TypeOf(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (t reflect.rtype) string
|
||||
return makeReflectType(rtype{args[0].(iface).t})
|
||||
|
@ -223,6 +266,25 @@ func ext۰reflect۰Value۰Type(fn *ssa.Function, args []value) value {
|
|||
return makeReflectType(rV2T(args[0]))
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Uint(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (reflect.Value) uint64
|
||||
switch v := rV2V(args[0]).(type) {
|
||||
case uint:
|
||||
return uint64(v)
|
||||
case uint8:
|
||||
return uint64(v)
|
||||
case uint16:
|
||||
return uint64(v)
|
||||
case uint32:
|
||||
return uint64(v)
|
||||
case uint64:
|
||||
return uint64(v)
|
||||
case uintptr:
|
||||
return uint64(v)
|
||||
}
|
||||
panic("reflect.Value.Uint")
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Len(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (reflect.Value) int
|
||||
switch v := rV2V(args[0]).(type) {
|
||||
|
@ -249,6 +311,11 @@ func ext۰reflect۰Value۰NumField(fn *ssa.Function, args []value) value {
|
|||
return len(rV2V(args[0]).(structure))
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰NumMethod(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (reflect.Value) int
|
||||
return rV2T(args[0]).t.MethodSet().Len()
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Pointer(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (v reflect.Value) uintptr
|
||||
switch v := rV2V(args[0]).(type) {
|
||||
|
@ -322,6 +389,17 @@ func ext۰reflect۰Value۰Field(fn *ssa.Function, args []value) value {
|
|||
return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Float(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (reflect.Value) float64
|
||||
switch v := rV2V(args[0]).(type) {
|
||||
case float32:
|
||||
return float64(v)
|
||||
case float64:
|
||||
return float64(v)
|
||||
}
|
||||
panic("reflect.Value.Float")
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Interface(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (v reflect.Value) interface{}
|
||||
return ext۰reflect۰valueInterface(fn, args)
|
||||
|
@ -378,6 +456,11 @@ func ext۰reflect۰Value۰IsValid(fn *ssa.Function, args []value) value {
|
|||
return rV2V(args[0]) != nil
|
||||
}
|
||||
|
||||
func ext۰reflect۰Value۰Set(fn *ssa.Function, args []value) value {
|
||||
// TODO(adonovan): implement.
|
||||
return nil
|
||||
}
|
||||
|
||||
func ext۰reflect۰valueInterface(fn *ssa.Function, args []value) value {
|
||||
// Signature: func (v reflect.Value, safe bool) interface{}
|
||||
v := args[0].(structure)
|
||||
|
@ -409,12 +492,16 @@ func initReflect(i *interpreter) {
|
|||
}
|
||||
|
||||
i.rtypeMethods = methodSet{
|
||||
"Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
|
||||
"Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
|
||||
"Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
|
||||
"NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
|
||||
"Out": newMethod(i.reflectPackage, rtypeType, "Out"),
|
||||
"String": newMethod(i.reflectPackage, rtypeType, "String"),
|
||||
"Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
|
||||
"Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
|
||||
"Field": newMethod(i.reflectPackage, rtypeType, "Field"),
|
||||
"Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
|
||||
"NumField": newMethod(i.reflectPackage, rtypeType, "NumField"),
|
||||
"NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
|
||||
"NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
|
||||
"Out": newMethod(i.reflectPackage, rtypeType, "Out"),
|
||||
"Size": newMethod(i.reflectPackage, rtypeType, "Size"),
|
||||
"String": newMethod(i.reflectPackage, rtypeType, "String"),
|
||||
}
|
||||
i.errorMethods = methodSet{
|
||||
"Error": newMethod(i.reflectPackage, errorType, "Error"),
|
||||
|
|
Loading…
Reference in New Issue