summaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-09-06 18:12:46 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-09-06 18:12:46 +0000
commitaa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch)
tree7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/reflect
parent920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff)
downloadgcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.gz
libgo: update to Go 1.13beta1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/193497 From-SVN: r275473
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/all_test.go276
-rw-r--r--libgo/go/reflect/makefunc_ffi.go11
-rw-r--r--libgo/go/reflect/swapper.go2
-rw-r--r--libgo/go/reflect/type.go81
-rw-r--r--libgo/go/reflect/value.go85
5 files changed, 358 insertions, 97 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 9452255f9a6..823d43c6e88 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -9,6 +9,7 @@ import (
"encoding/base64"
"flag"
"fmt"
+ "go/token"
"io"
"math"
"math/rand"
@@ -22,8 +23,6 @@ import (
"sync/atomic"
"testing"
"time"
- "unicode"
- "unicode/utf8"
"unsafe"
)
@@ -1061,6 +1060,113 @@ func TestIsNil(t *testing.T) {
NotNil(fi, t)
}
+func TestIsZero(t *testing.T) {
+ for i, tt := range []struct {
+ x interface{}
+ want bool
+ }{
+ // Booleans
+ {true, false},
+ {false, true},
+ // Numeric types
+ {int(0), true},
+ {int(1), false},
+ {int8(0), true},
+ {int8(1), false},
+ {int16(0), true},
+ {int16(1), false},
+ {int32(0), true},
+ {int32(1), false},
+ {int64(0), true},
+ {int64(1), false},
+ {uint(0), true},
+ {uint(1), false},
+ {uint8(0), true},
+ {uint8(1), false},
+ {uint16(0), true},
+ {uint16(1), false},
+ {uint32(0), true},
+ {uint32(1), false},
+ {uint64(0), true},
+ {uint64(1), false},
+ {float32(0), true},
+ {float32(1.2), false},
+ {float64(0), true},
+ {float64(1.2), false},
+ {math.Copysign(0, -1), false},
+ {complex64(0), true},
+ {complex64(1.2), false},
+ {complex128(0), true},
+ {complex128(1.2), false},
+ {complex(math.Copysign(0, -1), 0), false},
+ {complex(0, math.Copysign(0, -1)), false},
+ {complex(math.Copysign(0, -1), math.Copysign(0, -1)), false},
+ {uintptr(0), true},
+ {uintptr(128), false},
+ // Array
+ {Zero(TypeOf([5]string{})).Interface(), true},
+ {[5]string{"", "", "", "", ""}, true},
+ {[5]string{}, true},
+ {[5]string{"", "", "", "a", ""}, false},
+ // Chan
+ {(chan string)(nil), true},
+ {make(chan string), false},
+ {time.After(1), false},
+ // Func
+ {(func())(nil), true},
+ {New, false},
+ // Interface
+ {New(TypeOf(new(error)).Elem()).Elem(), true},
+ {(io.Reader)(strings.NewReader("")), false},
+ // Map
+ {(map[string]string)(nil), true},
+ {map[string]string{}, false},
+ {make(map[string]string), false},
+ // Ptr
+ {(*func())(nil), true},
+ {(*int)(nil), true},
+ {new(int), false},
+ // Slice
+ {[]string{}, false},
+ {([]string)(nil), true},
+ {make([]string, 0), false},
+ // Strings
+ {"", true},
+ {"not-zero", false},
+ // Structs
+ {T{}, true},
+ {T{123, 456.75, "hello", &_i}, false},
+ // UnsafePointer
+ {(unsafe.Pointer)(nil), true},
+ {(unsafe.Pointer)(new(int)), false},
+ } {
+ var x Value
+ if v, ok := tt.x.(Value); ok {
+ x = v
+ } else {
+ x = ValueOf(tt.x)
+ }
+
+ b := x.IsZero()
+ if b != tt.want {
+ t.Errorf("%d: IsZero((%s)(%+v)) = %t, want %t", i, x.Kind(), tt.x, b, tt.want)
+ }
+
+ if !Zero(TypeOf(tt.x)).IsZero() {
+ t.Errorf("%d: IsZero(Zero(TypeOf((%s)(%+v)))) is false", i, x.Kind(), tt.x)
+ }
+ }
+
+ func() {
+ defer func() {
+ if r := recover(); r == nil {
+ t.Error("should panic for invalid value")
+ }
+ }()
+ (Value{}).IsZero()
+ }()
+}
+
func TestInterfaceExtraction(t *testing.T) {
var s struct {
W io.Writer
@@ -1831,6 +1937,91 @@ func TestMakeFuncVariadic(t *testing.T) {
}
}
+// Dummy type that implements io.WriteCloser
+type WC struct {
+}
+
+func (w *WC) Write(p []byte) (n int, err error) {
+ return 0, nil
+}
+func (w *WC) Close() error {
+ return nil
+}
+
+func TestMakeFuncValidReturnAssignments(t *testing.T) {
+ // reflect.Values returned from the wrapped function should be assignment-converted
+ // to the types returned by the result of MakeFunc.
+
+ // Concrete types should be promotable to interfaces they implement.
+ var f func() error
+ f = MakeFunc(TypeOf(f), func([]Value) []Value {
+ return []Value{ValueOf(io.EOF)}
+ }).Interface().(func() error)
+ f()
+
+ // Super-interfaces should be promotable to simpler interfaces.
+ var g func() io.Writer
+ g = MakeFunc(TypeOf(g), func([]Value) []Value {
+ var w io.WriteCloser = &WC{}
+ return []Value{ValueOf(&w).Elem()}
+ }).Interface().(func() io.Writer)
+ g()
+
+ // Channels should be promotable to directional channels.
+ var h func() <-chan int
+ h = MakeFunc(TypeOf(h), func([]Value) []Value {
+ return []Value{ValueOf(make(chan int))}
+ }).Interface().(func() <-chan int)
+ h()
+
+ // Unnamed types should be promotable to named types.
+ type T struct{ a, b, c int }
+ var i func() T
+ i = MakeFunc(TypeOf(i), func([]Value) []Value {
+ return []Value{ValueOf(struct{ a, b, c int }{a: 1, b: 2, c: 3})}
+ }).Interface().(func() T)
+ i()
+}
+
+func TestMakeFuncInvalidReturnAssignments(t *testing.T) {
+ // Type doesn't implement the required interface.
+ shouldPanic(func() {
+ var f func() error
+ f = MakeFunc(TypeOf(f), func([]Value) []Value {
+ return []Value{ValueOf(int(7))}
+ }).Interface().(func() error)
+ f()
+ })
+ // Assigning to an interface with additional methods.
+ shouldPanic(func() {
+ var f func() io.ReadWriteCloser
+ f = MakeFunc(TypeOf(f), func([]Value) []Value {
+ var w io.WriteCloser = &WC{}
+ return []Value{ValueOf(&w).Elem()}
+ }).Interface().(func() io.ReadWriteCloser)
+ f()
+ })
+ // Directional channels can't be assigned to bidirectional ones.
+ shouldPanic(func() {
+ var f func() chan int
+ f = MakeFunc(TypeOf(f), func([]Value) []Value {
+ var c <-chan int = make(chan int)
+ return []Value{ValueOf(c)}
+ }).Interface().(func() chan int)
+ f()
+ })
+ // Two named types which are otherwise identical.
+ shouldPanic(func() {
+ type T struct{ a, b, c int }
+ type U struct{ a, b, c int }
+ var f func() T
+ f = MakeFunc(TypeOf(f), func([]Value) []Value {
+ return []Value{ValueOf(U{a: 1, b: 2, c: 3})}
+ }).Interface().(func() T)
+ f()
+ })
+}
+
type Point struct {
x, y int
}
@@ -2110,6 +2301,39 @@ func TestVariadicMethodValue(t *testing.T) {
}
}
+type DirectIfaceT struct {
+ p *int
+}
+
+func (d DirectIfaceT) M() int { return *d.p }
+
+func TestDirectIfaceMethod(t *testing.T) {
+ x := 42
+ v := DirectIfaceT{&x}
+ typ := TypeOf(v)
+ m, ok := typ.MethodByName("M")
+ if !ok {
+ t.Fatalf("cannot find method M")
+ }
+ in := []Value{ValueOf(v)}
+ out := m.Func.Call(in)
+ if got := out[0].Int(); got != 42 {
+ t.Errorf("Call with value receiver got %d, want 42", got)
+ }
+
+ pv := &v
+ typ = TypeOf(pv)
+ m, ok = typ.MethodByName("M")
+ if !ok {
+ t.Fatalf("cannot find method M")
+ }
+ in = []Value{ValueOf(pv)}
+ out = m.Func.Call(in)
+ if got := out[0].Int(); got != 42 {
+ t.Errorf("Call with pointer receiver got %d, want 42", got)
+ }
+}
+
// Reflect version of $GOROOT/test/method5.go
// Concrete types implementing M method.
@@ -4249,37 +4473,37 @@ func TestStructOfFieldName(t *testing.T) {
// invalid field name "1nvalid"
shouldPanic(func() {
StructOf([]StructField{
- StructField{Name: "valid", Type: TypeOf("")},
- StructField{Name: "1nvalid", Type: TypeOf("")},
+ {Name: "valid", Type: TypeOf("")},
+ {Name: "1nvalid", Type: TypeOf("")},
})
})
// invalid field name "+"
shouldPanic(func() {
StructOf([]StructField{
- StructField{Name: "val1d", Type: TypeOf("")},
- StructField{Name: "+", Type: TypeOf("")},
+ {Name: "val1d", Type: TypeOf("")},
+ {Name: "+", Type: TypeOf("")},
})
})
// no field name
shouldPanic(func() {
StructOf([]StructField{
- StructField{Name: "", Type: TypeOf("")},
+ {Name: "", Type: TypeOf("")},
})
})
// verify creation of a struct with valid struct fields
validFields := []StructField{
- StructField{
+ {
Name: "φ",
Type: TypeOf(""),
},
- StructField{
+ {
Name: "ValidName",
Type: TypeOf(""),
},
- StructField{
+ {
Name: "Val1dNam5",
Type: TypeOf(""),
},
@@ -4296,21 +4520,21 @@ func TestStructOfFieldName(t *testing.T) {
func TestStructOf(t *testing.T) {
// check construction and use of type not in binary
fields := []StructField{
- StructField{
+ {
Name: "S",
Tag: "s",
Type: TypeOf(""),
},
- StructField{
+ {
Name: "X",
Tag: "x",
Type: TypeOf(byte(0)),
},
- StructField{
+ {
Name: "Y",
Type: TypeOf(uint64(0)),
},
- StructField{
+ {
Name: "Z",
Type: TypeOf([3]uint16{}),
},
@@ -4393,20 +4617,20 @@ func TestStructOf(t *testing.T) {
// check duplicate names
shouldPanic(func() {
StructOf([]StructField{
- StructField{Name: "string", Type: TypeOf("")},
- StructField{Name: "string", Type: TypeOf("")},
+ {Name: "string", Type: TypeOf("")},
+ {Name: "string", Type: TypeOf("")},
})
})
shouldPanic(func() {
StructOf([]StructField{
- StructField{Type: TypeOf("")},
- StructField{Name: "string", Type: TypeOf("")},
+ {Type: TypeOf("")},
+ {Name: "string", Type: TypeOf("")},
})
})
shouldPanic(func() {
StructOf([]StructField{
- StructField{Type: TypeOf("")},
- StructField{Type: TypeOf("")},
+ {Type: TypeOf("")},
+ {Type: TypeOf("")},
})
})
// check that type already in binary is found
@@ -4416,7 +4640,7 @@ func TestStructOf(t *testing.T) {
type structFieldType interface{}
checkSameType(t,
StructOf([]StructField{
- StructField{
+ {
Name: "F",
Type: TypeOf((*structFieldType)(nil)).Elem(),
},
@@ -4575,7 +4799,7 @@ func TestStructOfExportRules(t *testing.T) {
if n == "" {
panic("field.Name must not be empty")
}
- exported := isExported(n)
+ exported := token.IsExported(n)
if exported != test.exported {
t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported)
}
@@ -4583,14 +4807,6 @@ func TestStructOfExportRules(t *testing.T) {
}
}
-// isExported reports whether name is an exported Go symbol
-// (that is, whether it begins with an upper-case letter).
-//
-func isExported(name string) bool {
- ch, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(ch)
-}
-
func TestStructOfGC(t *testing.T) {
type T *uintptr
tt := TypeOf(T(nil))
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
index 9d9cbdec25d..4564736bc99 100644
--- a/libgo/go/reflect/makefunc_ffi.go
+++ b/libgo/go/reflect/makefunc_ffi.go
@@ -44,11 +44,6 @@ func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc
off := uintptr(0)
for i, typ := range ftyp.out {
v := out[i]
- if v.typ != typ {
- panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
- " returned wrong type: have " +
- out[i].typ.String() + " for " + typ.String())
- }
if v.flag&flagRO != 0 {
panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
" returned value obtained from unexported field")
@@ -56,6 +51,12 @@ func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc
off = align(off, uintptr(typ.fieldAlign))
addr := unsafe.Pointer(uintptr(results) + off)
+
+ // Convert v to type typ if v is assignable to a variable
+ // of type t in the language spec.
+ // See issue 28761.
+ v = v.assignTo("reflect.MakeFunc", typ, addr)
+
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
*(*unsafe.Pointer)(addr) = v.ptr
} else {
diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go
index bf77b682c4d..016f95d7b01 100644
--- a/libgo/go/reflect/swapper.go
+++ b/libgo/go/reflect/swapper.go
@@ -29,7 +29,7 @@ func Swapper(slice interface{}) func(i, j int) {
typ := v.Type().Elem().(*rtype)
size := typ.Size()
- hasPtr := typ.kind&kindNoPointers == 0
+ hasPtr := typ.ptrdata != 0
// Some common & small cases, without using memmove:
if hasPtr {
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 8493d87f802..f82f5eb1121 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -53,6 +53,9 @@ type Type interface {
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
+ //
+ // Only exported methods are accessible and they are sorted in
+ // lexicographic order.
Method(int) Method
// MethodByName returns the method with that name in the type's
@@ -415,7 +418,6 @@ type Method struct {
const (
kindDirectIface = 1 << 5
kindGCProg = 1 << 6 // Type.gc points to GC program
- kindNoPointers = 1 << 7
kindMask = (1 << 5) - 1
)
@@ -546,7 +548,7 @@ func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
-func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
+func (t *rtype) pointers() bool { return t.ptrdata != 0 }
func (t *rtype) common() *rtype { return t }
@@ -1761,13 +1763,6 @@ const (
)
func bucketOf(ktyp, etyp *rtype) *rtype {
- // See comment on hmap.overflow in ../runtime/map.go.
- var kind uint8
- if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 &&
- ktyp.size <= maxKeySize && etyp.size <= maxValSize {
- kind = kindNoPointers
- }
-
if ktyp.size > maxKeySize {
ktyp = PtrTo(ktyp).(*rtype)
}
@@ -1804,14 +1799,14 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
ovoff := size
size += ptrSize
- if kind != kindNoPointers {
+ if ktyp.ptrdata != 0 || etyp.ptrdata != 0 {
nptr := size / ptrSize
mask := make([]byte, (nptr+7)/8)
psize := bucketSize
psize = align(psize, uintptr(ktyp.fieldAlign))
base := psize / ptrSize
- if ktyp.kind&kindNoPointers == 0 {
+ if ktyp.ptrdata != 0 {
if ktyp.kind&kindGCProg != 0 {
panic("reflect: unexpected GC program in MapOf")
}
@@ -1829,7 +1824,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
psize = align(psize, uintptr(etyp.fieldAlign))
base = psize / ptrSize
- if etyp.kind&kindNoPointers == 0 {
+ if etyp.ptrdata != 0 {
if etyp.kind&kindGCProg != 0 {
panic("reflect: unexpected GC program in MapOf")
}
@@ -1859,7 +1854,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
align: int8(maxAlign),
fieldAlign: uint8(maxAlign),
size: size,
- kind: kind,
+ kind: uint8(Struct),
ptrdata: ptrdata,
gcdata: gcdata,
}
@@ -1962,7 +1957,6 @@ func StructOf(fields []StructField) Type {
repr = make([]byte, 0, 64)
fset = map[string]struct{}{} // fields' names
- hasPtr = false // records whether at least one struct-field is a pointer
hasGCProg = false // records whether a struct-field type has a GCProg
)
@@ -1983,9 +1977,6 @@ func StructOf(fields []StructField) Type {
if ft.kind&kindGCProg != 0 {
hasGCProg = true
}
- if ft.pointers() {
- hasPtr = true
- }
// Update string and hash
name := *f.name
@@ -2129,13 +2120,9 @@ func StructOf(fields []StructField) Type {
typ.string = &str
typ.hash = hash
typ.size = size
+ typ.ptrdata = typeptrdata(typ.common())
typ.align = typalign
typ.fieldAlign = uint8(typalign)
- if !hasPtr {
- typ.kind |= kindNoPointers
- } else {
- typ.kind &^= kindNoPointers
- }
if hasGCProg {
lastPtrField := 0
@@ -2145,44 +2132,50 @@ func StructOf(fields []StructField) Type {
}
}
prog := []byte{0, 0, 0, 0} // will be length of prog
+ var off uintptr
for i, ft := range fs {
if i > lastPtrField {
// gcprog should not include anything for any field after
// the last field that contains pointer data
break
}
- // FIXME(sbinet) handle padding, fields smaller than a word
+ if !ft.typ.pointers() {
+ // Ignore pointerless fields.
+ continue
+ }
+ // Pad to start of this field with zeros.
+ if ft.offset() > off {
+ n := (ft.offset() - off) / ptrSize
+ prog = append(prog, 0x01, 0x00) // emit a 0 bit
+ if n > 1 {
+ prog = append(prog, 0x81) // repeat previous bit
+ prog = appendVarint(prog, n-1) // n-1 times
+ }
+ off = ft.offset()
+ }
+
elemGC := (*[1 << 30]byte)(unsafe.Pointer(ft.typ.gcdata))[:]
elemPtrs := ft.typ.ptrdata / ptrSize
- switch {
- case ft.typ.kind&kindGCProg == 0 && ft.typ.ptrdata != 0:
+ if ft.typ.kind&kindGCProg == 0 {
// Element is small with pointer mask; use as literal bits.
mask := elemGC
// Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes).
var n uintptr
- for n := elemPtrs; n > 120; n -= 120 {
+ for n = elemPtrs; n > 120; n -= 120 {
prog = append(prog, 120)
prog = append(prog, mask[:15]...)
mask = mask[15:]
}
prog = append(prog, byte(n))
prog = append(prog, mask[:(n+7)/8]...)
- case ft.typ.kind&kindGCProg != 0:
+ } else {
// Element has GC program; emit one element.
elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1]
prog = append(prog, elemProg...)
}
- // Pad from ptrdata to size.
- elemWords := ft.typ.size / ptrSize
- if elemPtrs < elemWords {
- // Emit literal 0 bit, then repeat as needed.
- prog = append(prog, 0x01, 0x00)
- if elemPtrs+1 < elemWords {
- prog = append(prog, 0x81)
- prog = appendVarint(prog, elemWords-elemPtrs-1)
- }
- }
+ off += ft.typ.ptrdata
}
+ prog = append(prog, 0)
*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
typ.kind |= kindGCProg
typ.gcdata = &prog[0]
@@ -2276,20 +2269,20 @@ func runtimeStructField(field StructField) structField {
// containing pointer data. Anything after this offset is scalar data.
// keep in sync with ../cmd/compile/internal/gc/reflect.go
func typeptrdata(t *rtype) uintptr {
- if !t.pointers() {
- return 0
- }
switch t.Kind() {
case Struct:
st := (*structType)(unsafe.Pointer(t))
// find the last field that has pointers.
- field := 0
+ field := -1
for i := range st.fields {
ft := st.fields[i].typ
if ft.pointers() {
field = i
}
}
+ if field == -1 {
+ return 0
+ }
f := st.fields[field]
return f.offset() + f.typ.ptrdata
@@ -2357,11 +2350,9 @@ func ArrayOf(count int, elem Type) Type {
array.len = uintptr(count)
array.slice = SliceOf(elem).(*rtype)
- array.kind &^= kindNoPointers
switch {
- case typ.kind&kindNoPointers != 0 || array.size == 0:
+ case typ.ptrdata == 0 || array.size == 0:
// No pointers.
- array.kind |= kindNoPointers
array.gcdata = nil
array.ptrdata = 0
@@ -2522,7 +2513,7 @@ func (bv *bitVector) append(bit uint8) {
}
func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
- if t.kind&kindNoPointers != 0 {
+ if t.ptrdata == 0 {
return
}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 298fbacf364..c4a62c34b83 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -201,7 +201,8 @@ type nonEmptyInterface struct {
// v.flag.mustBe(Bool), which will only bother to copy the
// single important word for the receiver.
func (f flag) mustBe(expected Kind) {
- if f.kind() != expected {
+ // TODO(mvdan): use f.kind() again once mid-stack inlining gets better
+ if Kind(f&flagKindMask) != expected {
panic(&ValueError{methodName(), f.kind()})
}
}
@@ -209,8 +210,14 @@ func (f flag) mustBe(expected Kind) {
// mustBeExported panics if f records that the value was obtained using
// an unexported field.
func (f flag) mustBeExported() {
+ if f == 0 || f&flagRO != 0 {
+ f.mustBeExportedSlow()
+ }
+}
+
+func (f flag) mustBeExportedSlow() {
if f == 0 {
- panic(&ValueError{methodName(), 0})
+ panic(&ValueError{methodName(), Invalid})
}
if f&flagRO != 0 {
panic("reflect: " + methodName() + " using value obtained using unexported field")
@@ -221,6 +228,12 @@ func (f flag) mustBeExported() {
// which is to say that either it was obtained using an unexported field
// or it is not addressable.
func (f flag) mustBeAssignable() {
+ if f&flagRO != 0 || f&flagAddr == 0 {
+ f.mustBeAssignableSlow()
+ }
+}
+
+func (f flag) mustBeAssignableSlow() {
if f == 0 {
panic(&ValueError{methodName(), Invalid})
}
@@ -790,7 +803,7 @@ func (v Value) Interface() (i interface{}) {
func valueInterface(v Value, safe bool) interface{} {
if v.flag == 0 {
- panic(&ValueError{"reflect.Value.Interface", 0})
+ panic(&ValueError{"reflect.Value.Interface", Invalid})
}
if safe && v.flag&flagRO != 0 {
// Do not allow access to unexported values via Interface,
@@ -877,6 +890,46 @@ func (v Value) IsValid() bool {
return v.flag != 0
}
+// IsZero reports whether v is the zero value for its type.
+// It panics if the argument is invalid.
+func (v Value) IsZero() bool {
+ switch v.kind() {
+ case Bool:
+ return !v.Bool()
+ case Int, Int8, Int16, Int32, Int64:
+ return v.Int() == 0
+ case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+ return v.Uint() == 0
+ case Float32, Float64:
+ return math.Float64bits(v.Float()) == 0
+ case Complex64, Complex128:
+ c := v.Complex()
+ return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
+ case Array:
+ for i := 0; i < v.Len(); i++ {
+ if !v.Index(i).IsZero() {
+ return false
+ }
+ }
+ return true
+ case Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer:
+ return v.IsNil()
+ case String:
+ return v.Len() == 0
+ case Struct:
+ for i := 0; i < v.NumField(); i++ {
+ if !v.Field(i).IsZero() {
+ return false
+ }
+ }
+ return true
+ default:
+ // This should never happens, but will act as a safeguard for
+ // later, as a default value doesn't makes sense here.
+ panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
+ }
+}
+
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
@@ -1003,7 +1056,7 @@ func (it *MapIter) Value() Value {
t := (*mapType)(unsafe.Pointer(it.m.typ))
vtype := t.elem
- return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapitervalue(it.it))
+ return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapiterelem(it.it))
}
// Next advances the map iterator and reports whether there is another
@@ -1391,13 +1444,13 @@ func (v Value) SetCap(n int) {
s.Cap = n
}
-// SetMapIndex sets the value associated with key in the map v to val.
+// SetMapIndex sets the element associated with key in the map v to elem.
// It panics if v's Kind is not Map.
-// If val is the zero Value, SetMapIndex deletes the key from the map.
+// If elem is the zero Value, SetMapIndex deletes the key from the map.
// Otherwise if v holds a nil map, SetMapIndex will panic.
-// As in Go, key's value must be assignable to the map's key type,
-// and val's value must be assignable to the map's value type.
-func (v Value) SetMapIndex(key, val Value) {
+// As in Go, key's elem must be assignable to the map's key type,
+// and elem's value must be assignable to the map's elem type.
+func (v Value) SetMapIndex(key, elem Value) {
v.mustBe(Map)
v.mustBeExported()
key.mustBeExported()
@@ -1409,17 +1462,17 @@ func (v Value) SetMapIndex(key, val Value) {
} else {
k = unsafe.Pointer(&key.ptr)
}
- if val.typ == nil {
+ if elem.typ == nil {
mapdelete(v.typ, v.pointer(), k)
return
}
- val.mustBeExported()
- val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+ elem.mustBeExported()
+ elem = elem.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
var e unsafe.Pointer
- if val.flag&flagIndir != 0 {
- e = val.ptr
+ if elem.flag&flagIndir != 0 {
+ e = elem.ptr
} else {
- e = unsafe.Pointer(&val.ptr)
+ e = unsafe.Pointer(&elem.ptr)
}
mapassign(v.typ, v.pointer(), k, e)
}
@@ -2464,7 +2517,7 @@ func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
//go:noescape
-func mapitervalue(it unsafe.Pointer) (value unsafe.Pointer)
+func mapiterelem(it unsafe.Pointer) (elem unsafe.Pointer)
//go:noescape
func mapiternext(it unsafe.Pointer)