"flag"
"fmt"
"go/token"
+ "internal/abi"
"internal/goarch"
+ "internal/testenv"
"io"
"math"
"math/rand"
+ "net"
"os"
. "reflect"
"reflect/internal/example1"
"unsafe"
)
-var sink interface{}
+const bucketCount = abi.MapBucketCount
+
+var sink any
func TestBool(t *testing.T) {
v := ValueOf(true)
d *int
}
+var _ = T{} == T{} // tests depend on T being comparable
+
type pair struct {
- i interface{}
+ i any
s string
}
}
func TestMapIterSet(t *testing.T) {
- m := make(map[string]interface{}, len(valueTests))
+ m := make(map[string]any, len(valueTests))
for _, tt := range valueTests {
m[tt.s] = tt.i
}
iter := v.MapRange()
for iter.Next() {
- iter.SetKey(k)
- iter.SetValue(e)
+ k.SetIterKey(iter)
+ e.SetIterValue(iter)
want := m[k.String()]
got := e.Interface()
if got != want {
}
}
+ if testenv.OptimizationOff() {
+ return // no inlining with the noopt builder
+ }
+
got := int(testing.AllocsPerRun(10, func() {
iter := v.MapRange()
for iter.Next() {
- iter.SetKey(k)
- iter.SetValue(e)
+ k.SetIterKey(iter)
+ e.SetIterValue(iter)
}
}))
- // Making a *MapIter allocates. This should be the only allocation.
- if got != 1 {
- t.Errorf("wanted 1 alloc, got %d", got)
+ // Calling MapRange should not allocate even though it returns a *MapIter.
+ // The function is inlineable, so if the local usage does not escape
+ // the *MapIter, it can remain stack allocated.
+ want := 0
+ if got != want {
+ t.Errorf("wanted %d alloc, got %d", want, got)
}
}
var ops = [...]string{"CanInt", "CanUint", "CanFloat", "CanComplex"}
var testCases = []struct {
- i interface{}
+ i any
want [4]bool
}{
// signed integer
for _, tc := range tt.cases {
f := tt.val
for _, i := range tc.index {
- if f.Kind() == Ptr {
+ if f.Kind() == Pointer {
f = f.Elem()
}
if i == -1 {
func TestInterfaceGet(t *testing.T) {
var inter struct {
- E interface{}
+ E any
}
inter.E = 123.456
v1 := ValueOf(&inter)
func TestInterfaceValue(t *testing.T) {
var inter struct {
- E interface{}
+ E any
}
inter.E = 123.456
v1 := ValueOf(&inter)
}
func TestFunctionValue(t *testing.T) {
- var x interface{} = func() {}
+ var x any = func() {}
v := ValueOf(x)
if fmt.Sprint(v.Interface()) != fmt.Sprint(x) {
t.Fatalf("TestFunction returned wrong pointer")
assert(t, v.Type().String(), "func()")
}
+func TestGrow(t *testing.T) {
+ v := ValueOf([]int(nil))
+ shouldPanic("reflect.Value.Grow using unaddressable value", func() { v.Grow(0) })
+ v = ValueOf(new([]int)).Elem()
+ v.Grow(0)
+ if !v.IsNil() {
+ t.Errorf("v.Grow(0) should still be nil")
+ }
+ v.Grow(1)
+ if v.Cap() == 0 {
+ t.Errorf("v.Cap = %v, want non-zero", v.Cap())
+ }
+ want := v.UnsafePointer()
+ v.Grow(1)
+ got := v.UnsafePointer()
+ if got != want {
+ t.Errorf("noop v.Grow should not change pointers")
+ }
+
+ t.Run("Append", func(t *testing.T) {
+ var got, want []T
+ v := ValueOf(&got).Elem()
+ appendValue := func(vt T) {
+ v.Grow(1)
+ v.SetLen(v.Len() + 1)
+ v.Index(v.Len() - 1).Set(ValueOf(vt))
+ }
+ for i := 0; i < 10; i++ {
+ vt := T{i, float64(i), strconv.Itoa(i), &i}
+ appendValue(vt)
+ want = append(want, vt)
+ }
+ if !DeepEqual(got, want) {
+ t.Errorf("value mismatch:\ngot %v\nwant %v", got, want)
+ }
+ })
+
+ t.Run("Rate", func(t *testing.T) {
+ var b []byte
+ v := ValueOf(new([]byte)).Elem()
+ for i := 0; i < 10; i++ {
+ b = append(b[:cap(b)], make([]byte, 1)...)
+ v.SetLen(v.Cap())
+ v.Grow(1)
+ if v.Cap() != cap(b) {
+ t.Errorf("v.Cap = %v, want %v", v.Cap(), cap(b))
+ }
+ }
+ })
+
+ t.Run("ZeroCapacity", func(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ v := ValueOf(new([]byte)).Elem()
+ v.Grow(61)
+ b := v.Bytes()
+ b = b[:cap(b)]
+ for i, c := range b {
+ if c != 0 {
+ t.Fatalf("Value.Bytes[%d] = 0x%02x, want 0x00", i, c)
+ }
+ b[i] = 0xff
+ }
+ runtime.GC()
+ }
+ })
+}
+
var appendTests = []struct {
orig, extra []int
}{
+ {nil, nil},
+ {[]int{}, nil},
+ {nil, []int{}},
+ {[]int{}, []int{}},
+ {nil, []int{22}},
+ {[]int{}, []int{22}},
+ {make([]int, 2, 4), nil},
+ {make([]int, 2, 4), []int{}},
{make([]int, 2, 4), []int{22}},
{make([]int, 2, 4), []int{22, 33, 44}},
}
-func sameInts(x, y []int) bool {
- if len(x) != len(y) {
- return false
- }
- for i, xx := range x {
- if xx != y[i] {
- return false
- }
- }
- return true
-}
-
func TestAppend(t *testing.T) {
for i, test := range appendTests {
origLen, extraLen := len(test.orig), len(test.extra)
}
// Convert extra from []int to *SliceValue.
e1 := ValueOf(test.extra)
+
// Test Append.
- a0 := ValueOf(test.orig)
- have0 := Append(a0, e0...).Interface().([]int)
- if !sameInts(have0, want) {
- t.Errorf("Append #%d: have %v, want %v (%p %p)", i, have0, want, test.orig, have0)
+ a0 := ValueOf(&test.orig).Elem()
+ have0 := Append(a0, e0...)
+ if have0.CanAddr() {
+ t.Errorf("Append #%d: have slice should not be addressable", i)
+ }
+ if !DeepEqual(have0.Interface(), want) {
+ t.Errorf("Append #%d: have %v, want %v (%p %p)", i, have0, want, test.orig, have0.Interface())
}
// Check that the orig and extra slices were not modified.
+ if a0.Len() != len(test.orig) {
+ t.Errorf("Append #%d: a0.Len: have %d, want %d", i, a0.Len(), origLen)
+ }
if len(test.orig) != origLen {
t.Errorf("Append #%d origLen: have %v, want %v", i, len(test.orig), origLen)
}
if len(test.extra) != extraLen {
t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
}
+
// Test AppendSlice.
- a1 := ValueOf(test.orig)
- have1 := AppendSlice(a1, e1).Interface().([]int)
- if !sameInts(have1, want) {
+ a1 := ValueOf(&test.orig).Elem()
+ have1 := AppendSlice(a1, e1)
+ if have1.CanAddr() {
+ t.Errorf("AppendSlice #%d: have slice should not be addressable", i)
+ }
+ if !DeepEqual(have1.Interface(), want) {
t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
}
// Check that the orig and extra slices were not modified.
+ if a1.Len() != len(test.orig) {
+ t.Errorf("AppendSlice #%d: a1.Len: have %d, want %d", i, a0.Len(), origLen)
+ }
if len(test.orig) != origLen {
t.Errorf("AppendSlice #%d origLen: have %v, want %v", i, len(test.orig), origLen)
}
if len(test.extra) != extraLen {
t.Errorf("AppendSlice #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
}
+
+ // Test Append and AppendSlice with unexported value.
+ ax := ValueOf(struct{ x []int }{test.orig}).Field(0)
+ shouldPanic("using unexported field", func() { Append(ax, e0...) })
+ shouldPanic("using unexported field", func() { AppendSlice(ax, e1) })
}
}
type NotBasic Basic
type DeepEqualTest struct {
- a, b interface{}
+ a, b any
eq bool
}
type self struct{}
type Loop *Loop
-type Loopy interface{}
+type Loopy any
var loop1, loop2 Loop
var loopy1, loopy2 Loopy
-var cycleMap1, cycleMap2, cycleMap3 map[string]interface{}
+var cycleMap1, cycleMap2, cycleMap3 map[string]any
type structWithSelfPtr struct {
p *structWithSelfPtr
loopy1 = &loopy2
loopy2 = &loopy1
- cycleMap1 = map[string]interface{}{}
+ cycleMap1 = map[string]any{}
cycleMap1["cycle"] = cycleMap1
- cycleMap2 = map[string]interface{}{}
+ cycleMap2 = map[string]any{}
cycleMap2["cycle"] = cycleMap2
- cycleMap3 = map[string]interface{}{}
+ cycleMap3 = map[string]any{}
cycleMap3["different"] = cycleMap3
}
{int32(1), int64(1), false},
{0.5, "hello", false},
{[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
- {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
+ {&[3]any{1, 2, 4}, &[3]any{1, 2, "s"}, false},
{Basic{1, 0.5}, NotBasic{1, 0.5}, false},
{map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
{[]byte{1, 2, 3}, []MyByte{1, 2, 3}, false},
}
var deepEqualPerfTests = []struct {
- x, y interface{}
+ x, y any
}{
{x: int8(99), y: int8(99)},
{x: []int8{99}, y: []int8{99}},
}
}
-func BenchmarkDeepEqual(b *testing.B) {
- for _, bb := range deepEqualPerfTests {
- b.Run(ValueOf(bb.x).Type().String(), func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- sink = DeepEqual(bb.x, bb.y)
- }
- })
- }
-}
-
-func check2ndField(x interface{}, offs uintptr, t *testing.T) {
+func check2ndField(x any, offs uintptr, t *testing.T) {
s := ValueOf(x)
f := s.Type().Field(1)
if f.Offset != offs {
check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
}
-func Nil(a interface{}, t *testing.T) {
+func Nil(a any, t *testing.T) {
n := ValueOf(a).Field(0)
if !n.IsNil() {
t.Errorf("%v should be nil", a)
}
}
-func NotNil(a interface{}, t *testing.T) {
+func NotNil(a any, t *testing.T) {
n := ValueOf(a).Field(0)
if n.IsNil() {
t.Errorf("value of type %v should not be nil", ValueOf(a).Type().String())
func TestIsNil(t *testing.T) {
// These implement IsNil.
// Wrap in extra struct to hide interface type.
- doNil := []interface{}{
+ doNil := []any{
struct{ x *int }{},
- struct{ x interface{} }{},
+ struct{ x any }{},
struct{ x map[string]int }{},
struct{ x func() bool }{},
struct{ x chan int }{},
NotNil(mi, t)
var ii struct {
- x interface{}
+ x any
}
Nil(ii, t)
ii.x = 2
NotNil(fi, t)
}
+func setField[S, V any](in S, offset uintptr, value V) (out S) {
+ *(*V)(unsafe.Add(unsafe.Pointer(&in), offset)) = value
+ return in
+}
+
func TestIsZero(t *testing.T) {
for i, tt := range []struct {
- x interface{}
+ x any
want bool
}{
// Booleans
{float32(1.2), false},
{float64(0), true},
{float64(1.2), false},
- {math.Copysign(0, -1), false},
+ {math.Copysign(0, -1), true},
{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},
+ {complex(math.Copysign(0, -1), 0), true},
+ {complex(0, math.Copysign(0, -1)), true},
+ {complex(math.Copysign(0, -1), math.Copysign(0, -1)), true},
{uintptr(0), true},
{uintptr(128), false},
// Array
{Zero(TypeOf([5]string{})).Interface(), true},
- {[5]string{"", "", "", "", ""}, true},
- {[5]string{}, true},
- {[5]string{"", "", "", "a", ""}, false},
+ {[5]string{}, true}, // comparable array
+ {[5]string{"", "", "", "a", ""}, false}, // comparable array
+ {[1]*int{}, true}, // direct pointer array
+ {[1]*int{new(int)}, false}, // direct pointer array
+ {[3][]int{}, true}, // incomparable array
+ {[3][]int{{1}}, false}, // incomparable array
+ {[1 << 12]byte{}, true},
+ {[1 << 12]byte{1}, false},
+ {[1]struct{ p *int }{}, true},
+ {[1]struct{ p *int }{{new(int)}}, false},
+ {[3]Value{}, true},
+ {[3]Value{{}, ValueOf(0), {}}, false},
// Chan
{(chan string)(nil), true},
{make(chan string), false},
{(map[string]string)(nil), true},
{map[string]string{}, false},
{make(map[string]string), false},
- // Ptr
+ // Pointer
{(*func())(nil), true},
{(*int)(nil), true},
{new(int), false},
{"", true},
{"not-zero", false},
// Structs
- {T{}, true},
- {T{123, 456.75, "hello", &_i}, false},
+ {T{}, true}, // comparable struct
+ {T{123, 456.75, "hello", &_i}, false}, // comparable struct
+ {struct{ p *int }{}, true}, // direct pointer struct
+ {struct{ p *int }{new(int)}, false}, // direct pointer struct
+ {struct{ s []int }{}, true}, // incomparable struct
+ {struct{ s []int }{[]int{1}}, false}, // incomparable struct
+ {struct{ Value }{}, true},
+ {struct{ Value }{ValueOf(0)}, false},
+ {struct{ _, a, _ uintptr }{}, true}, // comparable struct with blank fields
+ {setField(struct{ _, a, _ uintptr }{}, 0*unsafe.Sizeof(uintptr(0)), 1), true},
+ {setField(struct{ _, a, _ uintptr }{}, 1*unsafe.Sizeof(uintptr(0)), 1), false},
+ {setField(struct{ _, a, _ uintptr }{}, 2*unsafe.Sizeof(uintptr(0)), 1), true},
+ {struct{ _, a, _ func() }{}, true}, // incomparable struct with blank fields
+ {setField(struct{ _, a, _ func() }{}, 0*unsafe.Sizeof((func())(nil)), func() {}), true},
+ {setField(struct{ _, a, _ func() }{}, 1*unsafe.Sizeof((func())(nil)), func() {}), false},
+ {setField(struct{ _, a, _ func() }{}, 2*unsafe.Sizeof((func())(nil)), func() {}), true},
// UnsafePointer
{(unsafe.Pointer)(nil), true},
{(unsafe.Pointer)(new(int)), false},
if !Zero(TypeOf(tt.x)).IsZero() {
t.Errorf("%d: IsZero(Zero(TypeOf((%s)(%+v)))) is false", i, x.Kind(), tt.x)
}
+
+ p := New(x.Type()).Elem()
+ p.Set(x)
+ p.SetZero()
+ if !p.IsZero() {
+ t.Errorf("%d: IsZero((%s)(%+v)) is true after SetZero", i, p.Kind(), tt.x)
+ }
}
func() {
}()
}
+func TestInternalIsZero(t *testing.T) {
+ b := make([]byte, 512)
+ for a := 0; a < 8; a++ {
+ for i := 256 + 7; i <= 512-a; i++ {
+ InternalIsZero(b[a : a+i])
+ }
+ }
+}
+
func TestInterfaceExtraction(t *testing.T) {
var s struct {
W io.Writer
s.W = os.Stdout
v := Indirect(ValueOf(&s)).Field(0).Interface()
- if v != s.W.(interface{}) {
+ if v != s.W.(any) {
t.Error("Interface() on interface: ", v, s.W)
}
}
if m != nil {
t.Errorf("mv.Set(nil) failed")
}
+
+ type S string
+ shouldPanic("not assignable", func() { mv.MapIndex(ValueOf(S("key"))) })
+ shouldPanic("not assignable", func() { mv.SetMapIndex(ValueOf(S("key")), ValueOf(0)) })
}
func TestNilMap(t *testing.T) {
if i, ok := cv.Recv(); i.Int() != 0 || ok {
t.Errorf("after close Recv %d, %t", i.Int(), ok)
}
+ // Closing a read-only channel
+ shouldPanic("", func() {
+ c := make(<-chan int, 1)
+ cv := ValueOf(c)
+ cv.Close()
+ })
}
// check creation of unbuffered channel
recvStr = fmt.Sprintf(", received %v, %v", recv.Interface(), recvOK)
}
t.Fatalf("%s\nselected #%d incorrectly%s", fmtSelect(info), i, recvStr)
- continue
}
if cas.panic {
t.Fatalf("%s\nselected #%d incorrectly (case should panic)", fmtSelect(info), i)
- continue
}
if cases[i].Dir == SelectRecv {
}
}
-func BenchmarkSelect(b *testing.B) {
- channel := make(chan int)
- close(channel)
- var cases []SelectCase
- for i := 0; i < 8; i++ {
- cases = append(cases, SelectCase{
- Dir: SelectRecv,
- Chan: ValueOf(channel),
- })
- }
- for _, numCases := range []int{1, 4, 8} {
- b.Run(strconv.Itoa(numCases), func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- _, _, _ = Select(cases[:numCases])
- }
- })
- }
-}
-
// selectWatch and the selectWatcher are a watchdog mechanism for running Select.
// If the selectWatcher notices that the select has been blocked for >1 second, it prints
// an error describing the select and panics the entire test binary.
// runSelect runs a single select test.
// It returns the values returned by Select but also returns
// a panic value if the Select panics.
-func runSelect(cases []SelectCase, info []caseInfo) (chosen int, recv Value, recvOK bool, panicErr interface{}) {
+func runSelect(cases []SelectCase, info []caseInfo) (chosen int, recv Value, recvOK bool, panicErr any) {
defer func() {
panicErr = recover()
// fmtSelect formats the information about a single select test.
func fmtSelect(info []caseInfo) string {
- var buf bytes.Buffer
+ var buf strings.Builder
fmt.Fprintf(&buf, "\nselect {\n")
for i, cas := range info {
fmt.Fprintf(&buf, "%d: %s", i, cas.desc)
runtime.KeepAlive(v)
}
-func BenchmarkCall(b *testing.B) {
- fv := ValueOf(func(a, b string) {})
- b.ReportAllocs()
- b.RunParallel(func(pb *testing.PB) {
- args := []Value{ValueOf("a"), ValueOf("b")}
- for pb.Next() {
- fv.Call(args)
- }
- })
-}
-
-type myint int64
-
-func (i *myint) inc() {
- *i = *i + 1
-}
-
-func BenchmarkCallMethod(b *testing.B) {
- b.ReportAllocs()
- z := new(myint)
-
- v := ValueOf(z.inc)
- for i := 0; i < b.N; i++ {
- v.Call(nil)
- }
-}
-
-func BenchmarkCallArgCopy(b *testing.B) {
- byteArray := func(n int) Value {
- return Zero(ArrayOf(n, TypeOf(byte(0))))
- }
- sizes := [...]struct {
- fv Value
- arg Value
- }{
- {ValueOf(func(a [128]byte) {}), byteArray(128)},
- {ValueOf(func(a [256]byte) {}), byteArray(256)},
- {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
- {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
- {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
- }
- for _, size := range sizes {
- bench := func(b *testing.B) {
- args := []Value{size.arg}
- b.SetBytes(int64(size.arg.Len()))
- b.ResetTimer()
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- size.fv.Call(args)
- }
- })
- }
- name := fmt.Sprintf("size=%v", size.arg.Len())
- b.Run(name, bench)
- }
-}
-
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
t.Errorf("NoArgs returned %d values; want 0", n)
}
+ _, ok = TypeOf(&p).MethodByName("AA")
+ if ok {
+ t.Errorf(`MethodByName("AA") should have failed`)
+ }
+
+ _, ok = TypeOf(&p).MethodByName("ZZ")
+ if ok {
+ t.Errorf(`MethodByName("ZZ") should have failed`)
+ }
+
// Curried method of value.
tfunc := TypeOf((func(int) int)(nil))
v := ValueOf(p).Method(1)
p := Point{3, 4}
var i int64
+ // Check that method value have the same underlying code pointers.
+ if p1, p2 := ValueOf(Point{1, 1}).Method(1), ValueOf(Point{2, 2}).Method(1); p1.Pointer() != p2.Pointer() {
+ t.Errorf("methodValueCall mismatched: %v - %v", p1, p2)
+ }
+
// Curried method of value.
tfunc := TypeOf((func(int) int)(nil))
v := ValueOf(p).Method(1)
var TinterType = TypeOf(new(Tinter)).Elem()
- CheckI := func(name string, i interface{}, inc int) {
+ CheckI := func(name string, i any, inc int) {
v := ValueOf(i)
CheckV(name, v, inc)
CheckV("(i="+name+")", v.Convert(TinterType), inc)
p := &Point{3, 4}
var s struct {
- I interface{}
+ I any
P interface {
Dist(int) int
}
}
type FTest struct {
- s interface{}
+ s any
name string
index []int
value int
{TypeOf([]byte(nil)), ""},
{TypeOf([]rune(nil)), ""},
{TypeOf(string("")), ""},
- {TypeOf((*interface{})(nil)).Elem(), ""},
+ {TypeOf((*any)(nil)).Elem(), ""},
{TypeOf((*byte)(nil)), ""},
{TypeOf((*rune)(nil)), ""},
{TypeOf((*int64)(nil)), ""},
func TestNestedMethods(t *testing.T) {
typ := TypeOf((*outer)(nil))
- if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+ if typ.NumMethod() != 1 || typ.Method(0).Func.UnsafePointer() != ValueOf((*outer).M).UnsafePointer() {
t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M)
for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i)
- t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
+ t.Errorf("\t%d: %s %p\n", i, m.Name, m.Func.UnsafePointer())
}
}
}
f() (int32, int8)
}
-var unexpi unexpI = new(unexp)
-
func TestUnexportedMethods(t *testing.T) {
- typ := TypeOf(unexpi)
-
+ typ := TypeOf(new(unexp))
if got := typ.NumMethod(); got != 0 {
t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
+
+ typ = TypeOf((*unexpI)(nil))
+ if got := typ.Elem().NumMethod(); got != 1 {
+ t.Errorf("NumMethod=%d, want 1 satisfied methods", got)
+ }
}
type InnerInt struct {
func TestEmbeddedMethods(t *testing.T) {
typ := TypeOf((*OuterInt)(nil))
- if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() {
+ if typ.NumMethod() != 1 || typ.Method(0).Func.UnsafePointer() != ValueOf((*OuterInt).M).UnsafePointer() {
t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i)
- t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
+ t.Errorf("\t%d: %s %p\n", i, m.Name, m.Func.UnsafePointer())
}
}
}
}
-type FuncDDD func(...interface{}) error
+type FuncDDD func(...any) error
func (f FuncDDD) M() {}
typ := TypeOf(z)
for i = 0; i < 100; i++ {
- typ = PtrTo(typ)
+ typ = PointerTo(typ)
}
for i = 0; i < 100; i++ {
typ = typ.Elem()
}
if typ != TypeOf(z) {
- t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(z))
+ t.Errorf("after 100 PointerTo and Elem, have %s, want %s", typ, TypeOf(z))
}
}
func TestPtrToGC(t *testing.T) {
type T *uintptr
tt := TypeOf(T(nil))
- pt := PtrTo(tt)
+ pt := PointerTo(tt)
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := New(pt)
p := new(*uintptr)
}
}
-func BenchmarkPtrTo(b *testing.B) {
- // Construct a type with a zero ptrToThis.
- type T struct{ int }
- t := SliceOf(TypeOf(T{}))
- ptrToThis := ValueOf(t).Elem().FieldByName("ptrToThis")
- if !ptrToThis.IsValid() {
- b.Fatalf("%v has no ptrToThis field; was it removed from rtype?", t)
- }
- if ptrToThis.Int() != 0 {
- b.Fatalf("%v.ptrToThis unexpectedly nonzero", t)
- }
- b.ResetTimer()
-
- // Now benchmark calling PtrTo on it: we'll have to hit the ptrMap cache on
- // every call.
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- PtrTo(t)
- }
- })
-}
-
func TestAddr(t *testing.T) {
var p struct {
X, Y int
func TestAllocations(t *testing.T) {
noAlloc(t, 100, func(j int) {
- var i interface{}
+ var i any
var v Value
// We can uncomment this when compiler escape analysis
rv := ValueOf(&xs).Elem()
rv = rv.Slice(3, 4)
- ptr2 := rv.Pointer()
+ ptr2 := rv.UnsafePointer()
rv = rv.Slice(5, 5)
- ptr3 := rv.Pointer()
+ ptr3 := rv.UnsafePointer()
if ptr3 != ptr2 {
- t.Errorf("xs.Slice(3,4).Slice3(5,5).Pointer() = %#x, want %#x", ptr3, ptr2)
+ t.Errorf("xs.Slice(3,4).Slice3(5,5).UnsafePointer() = %p, want %p", ptr3, ptr2)
}
}
rv = ValueOf(&xs).Elem()
rv = rv.Slice3(3, 5, 7)
- ptr2 := rv.Pointer()
+ ptr2 := rv.UnsafePointer()
rv = rv.Slice3(4, 4, 4)
- ptr3 := rv.Pointer()
+ ptr3 := rv.UnsafePointer()
if ptr3 != ptr2 {
- t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).Pointer() = %#x, want %#x", ptr3, ptr2)
+ t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).UnsafePointer() = %p, want %p", ptr3, ptr2)
}
}
}
func TestVariadic(t *testing.T) {
- var b bytes.Buffer
+ var b strings.Builder
V := ValueOf
b.Reset()
}
b.Reset()
- V(fmt.Fprintf).CallSlice([]Value{V(&b), V("%s, %d world"), V([]interface{}{"hello", 42})})
+ V(fmt.Fprintf).CallSlice([]Value{V(&b), V("%s, %d world"), V([]any{"hello", 42})})
if b.String() != "hello, 42 world" {
t.Errorf("after Fprintf CallSlice: %q != %q", b.String(), "hello 42 world")
}
}
func TestBytes(t *testing.T) {
- type B []byte
- x := B{1, 2, 3, 4}
+ shouldPanic("on int Value", func() { ValueOf(0).Bytes() })
+ shouldPanic("of non-byte slice", func() { ValueOf([]string{}).Bytes() })
+
+ type S []byte
+ x := S{1, 2, 3, 4}
y := ValueOf(x).Bytes()
if !bytes.Equal(x, y) {
t.Fatalf("ValueOf(%v).Bytes() = %v", x, y)
if &x[0] != &y[0] {
t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
}
+
+ type A [4]byte
+ a := A{1, 2, 3, 4}
+ shouldPanic("unaddressable", func() { ValueOf(a).Bytes() })
+ shouldPanic("on ptr Value", func() { ValueOf(&a).Bytes() })
+ b := ValueOf(&a).Elem().Bytes()
+ if !bytes.Equal(a[:], y) {
+ t.Fatalf("ValueOf(%v).Bytes() = %v", a, b)
+ }
+ if &a[0] != &b[0] {
+ t.Errorf("ValueOf(%p).Bytes() = %p", &a[0], &b[0])
+ }
+
+ // Per issue #24746, it was decided that Bytes can be called on byte slices
+ // that normally cannot be converted from per Go language semantics.
+ type B byte
+ type SB []B
+ type AB [4]B
+ ValueOf([]B{1, 2, 3, 4}).Bytes() // should not panic
+ ValueOf(new([4]B)).Elem().Bytes() // should not panic
+ ValueOf(SB{1, 2, 3, 4}).Bytes() // should not panic
+ ValueOf(new(AB)).Elem().Bytes() // should not panic
}
func TestSetBytes(t *testing.T) {
badCall(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
}
+func TestValuePanic(t *testing.T) {
+ vo := ValueOf
+ shouldPanic("reflect.Value.Addr of unaddressable value", func() { vo(0).Addr() })
+ shouldPanic("call of reflect.Value.Bool on float64 Value", func() { vo(0.0).Bool() })
+ shouldPanic("call of reflect.Value.Bytes on string Value", func() { vo("").Bytes() })
+ shouldPanic("call of reflect.Value.Call on bool Value", func() { vo(true).Call(nil) })
+ shouldPanic("call of reflect.Value.CallSlice on int Value", func() { vo(0).CallSlice(nil) })
+ shouldPanic("call of reflect.Value.Close on string Value", func() { vo("").Close() })
+ shouldPanic("call of reflect.Value.Complex on float64 Value", func() { vo(0.0).Complex() })
+ shouldPanic("call of reflect.Value.Elem on bool Value", func() { vo(false).Elem() })
+ shouldPanic("call of reflect.Value.Field on int Value", func() { vo(0).Field(0) })
+ shouldPanic("call of reflect.Value.Float on string Value", func() { vo("").Float() })
+ shouldPanic("call of reflect.Value.Index on float64 Value", func() { vo(0.0).Index(0) })
+ shouldPanic("call of reflect.Value.Int on bool Value", func() { vo(false).Int() })
+ shouldPanic("call of reflect.Value.IsNil on int Value", func() { vo(0).IsNil() })
+ shouldPanic("call of reflect.Value.Len on bool Value", func() { vo(false).Len() })
+ shouldPanic("call of reflect.Value.MapIndex on float64 Value", func() { vo(0.0).MapIndex(vo(0.0)) })
+ shouldPanic("call of reflect.Value.MapKeys on string Value", func() { vo("").MapKeys() })
+ shouldPanic("call of reflect.Value.MapRange on int Value", func() { vo(0).MapRange() })
+ shouldPanic("call of reflect.Value.Method on zero Value", func() { vo(nil).Method(0) })
+ shouldPanic("call of reflect.Value.NumField on string Value", func() { vo("").NumField() })
+ shouldPanic("call of reflect.Value.NumMethod on zero Value", func() { vo(nil).NumMethod() })
+ shouldPanic("call of reflect.Value.OverflowComplex on float64 Value", func() { vo(float64(0)).OverflowComplex(0) })
+ shouldPanic("call of reflect.Value.OverflowFloat on int64 Value", func() { vo(int64(0)).OverflowFloat(0) })
+ shouldPanic("call of reflect.Value.OverflowInt on uint64 Value", func() { vo(uint64(0)).OverflowInt(0) })
+ shouldPanic("call of reflect.Value.OverflowUint on complex64 Value", func() { vo(complex64(0)).OverflowUint(0) })
+ shouldPanic("call of reflect.Value.Recv on string Value", func() { vo("").Recv() })
+ shouldPanic("call of reflect.Value.Send on bool Value", func() { vo(true).Send(vo(true)) })
+ shouldPanic("value of type string is not assignable to type bool", func() { vo(new(bool)).Elem().Set(vo("")) })
+ shouldPanic("call of reflect.Value.SetBool on string Value", func() { vo(new(string)).Elem().SetBool(false) })
+ shouldPanic("reflect.Value.SetBytes using unaddressable value", func() { vo("").SetBytes(nil) })
+ shouldPanic("call of reflect.Value.SetCap on string Value", func() { vo(new(string)).Elem().SetCap(0) })
+ shouldPanic("call of reflect.Value.SetComplex on string Value", func() { vo(new(string)).Elem().SetComplex(0) })
+ shouldPanic("call of reflect.Value.SetFloat on string Value", func() { vo(new(string)).Elem().SetFloat(0) })
+ shouldPanic("call of reflect.Value.SetInt on string Value", func() { vo(new(string)).Elem().SetInt(0) })
+ shouldPanic("call of reflect.Value.SetLen on string Value", func() { vo(new(string)).Elem().SetLen(0) })
+ shouldPanic("call of reflect.Value.SetString on int Value", func() { vo(new(int)).Elem().SetString("") })
+ shouldPanic("reflect.Value.SetUint using unaddressable value", func() { vo(0.0).SetUint(0) })
+ shouldPanic("call of reflect.Value.Slice on bool Value", func() { vo(true).Slice(1, 2) })
+ shouldPanic("call of reflect.Value.Slice3 on int Value", func() { vo(0).Slice3(1, 2, 3) })
+ shouldPanic("call of reflect.Value.TryRecv on bool Value", func() { vo(true).TryRecv() })
+ shouldPanic("call of reflect.Value.TrySend on string Value", func() { vo("").TrySend(vo("")) })
+ shouldPanic("call of reflect.Value.Uint on float64 Value", func() { vo(0.0).Uint() })
+}
+
func shouldPanic(expect string, f func()) {
defer func() {
r := recover()
f()
}
-func isNonNil(x interface{}) {
+func isNonNil(x any) {
if x == nil {
panic("nil interface")
}
var V = ValueOf
-func EmptyInterfaceV(x interface{}) Value {
+func EmptyInterfaceV(x any) Value {
return ValueOf(&x).Elem()
}
{V(MyString("runes♝")), V(MyRunes("runes♝"))},
{V(MyRunes("runes♕")), V(MyString("runes♕"))},
+ // slice to array
+ {V([]byte(nil)), V([0]byte{})},
+ {V([]byte{}), V([0]byte{})},
+ {V([]byte{1}), V([1]byte{1})},
+ {V([]byte{1, 2}), V([2]byte{1, 2})},
+ {V([]byte{1, 2, 3}), V([3]byte{1, 2, 3})},
+ {V(MyBytes([]byte(nil))), V([0]byte{})},
+ {V(MyBytes{}), V([0]byte{})},
+ {V(MyBytes{1}), V([1]byte{1})},
+ {V(MyBytes{1, 2}), V([2]byte{1, 2})},
+ {V(MyBytes{1, 2, 3}), V([3]byte{1, 2, 3})},
+ {V([]byte(nil)), V(MyBytesArray0{})},
+ {V([]byte{}), V(MyBytesArray0([0]byte{}))},
+ {V([]byte{1, 2, 3, 4}), V(MyBytesArray([4]byte{1, 2, 3, 4}))},
+ {V(MyBytes{}), V(MyBytesArray0([0]byte{}))},
+ {V(MyBytes{5, 6, 7, 8}), V(MyBytesArray([4]byte{5, 6, 7, 8}))},
+ {V([]MyByte{}), V([0]MyByte{})},
+ {V([]MyByte{1, 2}), V([2]MyByte{1, 2})},
+
// slice to array pointer
{V([]byte(nil)), V((*[0]byte)(nil))},
{V([]byte{}), V(new([0]byte))},
// cannot convert mismatched array sizes
{V([2]byte{}), V([2]byte{})},
{V([3]byte{}), V([3]byte{})},
+ {V(MyBytesArray0{}), V([0]byte{})},
+ {V([0]byte{}), V(MyBytesArray0{})},
// cannot convert other instances
{V((**byte)(nil)), V((**byte)(nil))},
{V((map[uint]bool)(nil)), V((map[uint]bool)(nil))},
{V([]uint(nil)), V([]uint(nil))},
{V([]int(nil)), V([]int(nil))},
- {V(new(interface{})), V(new(interface{}))},
+ {V(new(any)), V(new(any))},
{V(new(io.Reader)), V(new(io.Reader))},
{V(new(io.Writer)), V(new(io.Writer))},
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
_ = v.Convert(pt)
})
+
+ if v.CanConvert(pt.Elem()) {
+ t.Errorf("slice with length 4 should not be convertible to [8]byte")
+ }
+ shouldPanic("reflect: cannot convert slice with length 4 to array with length 8", func() {
+ _ = v.Convert(pt.Elem())
+ })
+}
+
+func TestConvertSlice2Array(t *testing.T) {
+ s := make([]int, 4)
+ p := [4]int{}
+ pt := TypeOf(p)
+ ov := ValueOf(s)
+ v := ov.Convert(pt)
+ // Converting a slice to non-empty array needs to return
+ // a non-addressable copy of the original memory.
+ if v.CanAddr() {
+ t.Fatalf("convert slice to non-empty array returns a addressable copy array")
+ }
+ for i := range s {
+ ov.Index(i).Set(ValueOf(i + 1))
+ }
+ for i := range s {
+ if v.Index(i).Int() != 0 {
+ t.Fatalf("slice (%v) mutation visible in converted result (%v)", ov, v)
+ }
+ }
}
var gFloat32 float32
{TypeOf(NonComparableStruct{}), false},
{TypeOf([10]map[string]int{}), false},
{TypeOf([10]string{}), true},
- {TypeOf(new(interface{})).Elem(), true},
+ {TypeOf(new(any)).Elem(), true},
}
func TestComparable(t *testing.T) {
}
}
-func checkSameType(t *testing.T, x Type, y interface{}) {
+func checkSameType(t *testing.T, x Type, y any) {
if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) {
t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))
}
// check construction and use of type not in binary
tests := []struct {
n int
- value func(i int) interface{}
+ value func(i int) any
comparable bool
want string
}{
{
n: 0,
- value: func(i int) interface{} { type Tint int; return Tint(i) },
+ value: func(i int) any { type Tint int; return Tint(i) },
comparable: true,
want: "[]",
},
{
n: 10,
- value: func(i int) interface{} { type Tint int; return Tint(i) },
+ value: func(i int) any { type Tint int; return Tint(i) },
comparable: true,
want: "[0 1 2 3 4 5 6 7 8 9]",
},
{
n: 10,
- value: func(i int) interface{} { type Tfloat float64; return Tfloat(i) },
+ value: func(i int) any { type Tfloat float64; return Tfloat(i) },
comparable: true,
want: "[0 1 2 3 4 5 6 7 8 9]",
},
{
n: 10,
- value: func(i int) interface{} { type Tstring string; return Tstring(strconv.Itoa(i)) },
+ value: func(i int) any { type Tstring string; return Tstring(strconv.Itoa(i)) },
comparable: true,
want: "[0 1 2 3 4 5 6 7 8 9]",
},
{
n: 10,
- value: func(i int) interface{} { type Tstruct struct{ V int }; return Tstruct{i} },
+ value: func(i int) any { type Tstruct struct{ V int }; return Tstruct{i} },
comparable: true,
want: "[{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}]",
},
{
n: 10,
- value: func(i int) interface{} { type Tint int; return []Tint{Tint(i)} },
+ value: func(i int) any { type Tint int; return []Tint{Tint(i)} },
comparable: false,
want: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
},
{
n: 10,
- value: func(i int) interface{} { type Tint int; return [1]Tint{Tint(i)} },
+ value: func(i int) any { type Tint int; return [1]Tint{Tint(i)} },
comparable: true,
want: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
},
{
n: 10,
- value: func(i int) interface{} { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} },
+ value: func(i int) any { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} },
comparable: true,
want: "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
},
{
n: 10,
- value: func(i int) interface{} { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} },
+ value: func(i int) any { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} },
comparable: false,
want: "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
},
{
n: 10,
- value: func(i int) interface{} { type TstructUV struct{ U, V int }; return TstructUV{i, i} },
+ value: func(i int) any { type TstructUV struct{ U, V int }; return TstructUV{i, i} },
comparable: true,
want: "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
},
{
n: 10,
- value: func(i int) interface{} {
+ value: func(i int) any {
type TstructUV struct {
U int
V float64
type T *uintptr
tt := TypeOf(T(nil))
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := New(ArrayOf(n, tt)).Elem()
for j := 0; j < v.Len(); j++ {
v1 := ValueOf(&i1).Elem()
p1 := v1.InterfaceData()[1]
- i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface()
+ i2 := Zero(ArrayOf(1, PointerTo(TypeOf(int8(0))))).Interface()
v2 := ValueOf(&i2).Elem()
p2 := v2.InterfaceData()[1]
v1 := ValueOf(&i1).Elem()
p1 := v1.InterfaceData()[1]
- i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface()
+ i2 := Zero(ArrayOf(0, PointerTo(TypeOf(int8(0))))).Interface()
v2 := ValueOf(&i2).Elem()
p2 := v2.InterfaceData()[1]
tt := TypeOf(T(nil))
st := SliceOf(tt)
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := MakeSlice(st, n, n)
for j := 0; j < v.Len(); j++ {
checkSameType(t, StructOf(fields[2:3]), struct{ Y uint64 }{})
// gccgo used to fail this test.
- type structFieldType interface{}
+ type structFieldType any
checkSameType(t,
StructOf([]StructField{
{
st := StructOf(fields)
const n = 10000
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := New(st).Elem()
for j := 0; j < v.NumField(); j++ {
},
{
name: "StructI",
- typ: PtrTo(TypeOf(StructI(want))),
- val: ValueOf(func() interface{} {
+ typ: PointerTo(TypeOf(StructI(want))),
+ val: ValueOf(func() any {
v := StructI(want)
return &v
}()),
},
{
name: "StructIPtr",
- typ: PtrTo(TypeOf(StructIPtr(want))),
- val: ValueOf(func() interface{} {
+ typ: PointerTo(TypeOf(StructIPtr(want))),
+ val: ValueOf(func() any {
v := StructIPtr(want)
return &v
}()),
fields := []StructField{{
Name: "StructIPtr",
Anonymous: true,
- Type: PtrTo(TypeOf(StructIPtr(want))),
+ Type: PointerTo(TypeOf(StructIPtr(want))),
}}
rt := StructOf(fields)
rv := New(rt).Elem()
fields = []StructField{{
Name: "SettableStruct",
Anonymous: true,
- Type: PtrTo(TypeOf(SettableStruct{})),
+ Type: PointerTo(TypeOf(SettableStruct{})),
}}
rt = StructOf(fields)
rv = New(rt).Elem()
{
Name: "SettableStruct",
Anonymous: true,
- Type: PtrTo(TypeOf(SettableStruct{})),
+ Type: PointerTo(TypeOf(SettableStruct{})),
},
{
Name: "EmptyStruct",
})
}
+func TestStructOfTooLarge(t *testing.T) {
+ t1 := TypeOf(byte(0))
+ t2 := TypeOf(int16(0))
+ t4 := TypeOf(int32(0))
+ t0 := ArrayOf(0, t1)
+
+ // 2^64-3 sized type (or 2^32-3 on 32-bit archs)
+ bigType := StructOf([]StructField{
+ {Name: "F1", Type: ArrayOf(int(^uintptr(0)>>1), t1)},
+ {Name: "F2", Type: ArrayOf(int(^uintptr(0)>>1-1), t1)},
+ })
+
+ type test struct {
+ shouldPanic bool
+ fields []StructField
+ }
+
+ tests := [...]test{
+ {
+ shouldPanic: false, // 2^64-1, ok
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(2, t1)},
+ },
+ },
+ {
+ shouldPanic: true, // overflow in total size
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(3, t1)},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while aligning F2
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: t4},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while adding trailing byte for zero-sized fields
+ fields: []StructField{
+ {Name: "F1", Type: bigType},
+ {Name: "F2", Type: ArrayOf(2, t1)},
+ {Name: "F3", Type: t0},
+ },
+ },
+ {
+ shouldPanic: true, // overflow while aligning total size
+ fields: []StructField{
+ {Name: "F1", Type: t2},
+ {Name: "F2", Type: bigType},
+ },
+ },
+ }
+
+ for i, tt := range tests {
+ func() {
+ defer func() {
+ err := recover()
+ if !tt.shouldPanic {
+ if err != nil {
+ t.Errorf("test %d should not panic, got %s", i, err)
+ }
+ return
+ }
+ if err == nil {
+ t.Errorf("test %d expected to panic", i)
+ return
+ }
+ s := fmt.Sprintf("%s", err)
+ if s != "reflect.StructOf: struct size would exceed virtual address space" {
+ t.Errorf("test %d wrong panic message: %s", i, s)
+ return
+ }
+ }()
+ _ = StructOf(tt.fields)
+ }()
+ }
+}
+
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
// so we have to save pointers to channels in x; the pointer code will
// use the gc info in the newly constructed chan type.
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := MakeChan(ct, n)
for j := 0; j < n; j++ {
// so we have to save pointers to maps in x; the pointer code will
// use the gc info in the newly constructed map type.
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := MakeMap(mt)
for j := 0; j < n; j++ {
// so we have to save pointers to maps in x; the pointer code will
// use the gc info in the newly constructed map type.
const n = 100
- var x []interface{}
+ var x []any
for i := 0; i < n; i++ {
v := MakeMap(mt)
for j := 0; j < n; j++ {
testCases := []struct {
in, out []Type
variadic bool
- want interface{}
+ want any
}{
{in: []Type{TypeOf(T1(0))}, want: (func(T1))(nil)},
{in: []Type{TypeOf(int(0))}, want: (func(int))(nil)},
FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true)
shouldPanic("must be slice", func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) })
shouldPanic("must be slice", func() { FuncOf(nil, nil, true) })
-}
-
-type B1 struct {
- X int
- Y int
- Z int
-}
-
-func BenchmarkFieldByName1(b *testing.B) {
- t := TypeOf(B1{})
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- t.FieldByName("Z")
- }
- })
-}
-func BenchmarkFieldByName2(b *testing.B) {
- t := TypeOf(S3{})
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- t.FieldByName("B")
- }
- })
+ //testcase for #54669
+ var in []Type
+ for i := 0; i < 51; i++ {
+ in = append(in, TypeOf(1))
+ }
+ FuncOf(in, nil, false)
}
type R0 struct {
}
}
-func BenchmarkFieldByName3(b *testing.B) {
- t := TypeOf(R0{})
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- t.FieldByName("X")
- }
- })
-}
-
-type S struct {
- i1 int64
- i2 int64
-}
-
-func BenchmarkInterfaceBig(b *testing.B) {
- v := ValueOf(S{})
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- v.Interface()
- }
- })
- b.StopTimer()
-}
-
func TestAllocsInterfaceBig(t *testing.T) {
if testing.Short() {
t.Skip("skipping malloc count in short mode")
}
}
-func BenchmarkInterfaceSmall(b *testing.B) {
- v := ValueOf(int64(0))
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- v.Interface()
- }
- })
-}
-
func TestAllocsInterfaceSmall(t *testing.T) {
if testing.Short() {
t.Skip("skipping malloc count in short mode")
// [false false false false]
// ...
// [true true true true]
-//
type exhaustive struct {
r *rand.Rand
pos int
*CallGC = false
}
+func TestCallArgLive(t *testing.T) {
+ type T struct{ X, Y *string } // pointerful aggregate
+
+ F := func(t T) { *t.X = "ok" }
+
+ // In reflect.Value.Call, trigger a garbage collection in reflect.call
+ // between marshaling argument and the actual call.
+ *CallGC = true
+
+ x := new(string)
+ runtime.SetFinalizer(x, func(p *string) {
+ if *p != "ok" {
+ t.Errorf("x dead prematurely")
+ }
+ })
+ v := T{x, nil}
+
+ ValueOf(F).Call([]Value{ValueOf(v)})
+
+ // Stop garbage collecting during reflect.call.
+ *CallGC = false
+}
+
func TestMakeFuncStackCopy(t *testing.T) {
target := func(in []Value) []Value {
runtime.GC()
func TestInvalid(t *testing.T) {
// Used to have inconsistency between IsValid() and Kind() != Invalid.
- type T struct{ v interface{} }
+ type T struct{ v any }
v := ValueOf(T{}).Field(0)
if v.IsValid() != true || v.Kind() != Interface {
fv.Call([]Value{ValueOf([256]*byte{})})
}
-func fieldIndexRecover(t Type, i int) (recovered interface{}) {
+func fieldIndexRecover(t Type, i int) (recovered any) {
defer func() {
recovered = recover()
}()
gc: r,
},
{
- typ: ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
+ typ: ValueOf(func(a map[int]int, b uintptr, c any) {}).Type(),
size: 4 * goarch.PtrSize,
argsize: 4 * goarch.PtrSize,
retOffset: 4 * goarch.PtrSize,
}
}
+// trimBitmap removes trailing 0 elements from b and returns the result.
+func trimBitmap(b []byte) []byte {
+ for len(b) > 0 && b[len(b)-1] == 0 {
+ b = b[:len(b)-1]
+ }
+ return b
+}
+
func verifyGCBits(t *testing.T, typ Type, bits []byte) {
heapBits := GCBits(New(typ).Interface())
- if !bytes.Equal(heapBits, bits) {
- _, _, line, _ := runtime.Caller(1)
- t.Errorf("line %d: heapBits incorrect for %v\nhave %v\nwant %v", line, typ, heapBits, bits)
+
+ // Trim scalars at the end, as bits might end in zero,
+ // e.g. with rep(2, lit(1, 0)).
+ bits = trimBitmap(bits)
+
+ if bytes.HasPrefix(heapBits, bits) {
+ // Just the prefix matching is OK.
+ //
+ // The Go runtime's pointer/scalar iterator generates pointers beyond
+ // the size of the type, up to the size of the size class. This space
+ // is safe for the GC to scan since it's zero, and GCBits checks to
+ // make sure that's true. But we need to handle the fact that the bitmap
+ // may be larger than we expect.
+ return
}
+ _, _, line, _ := runtime.Caller(1)
+ t.Errorf("line %d: heapBits incorrect for %v\nhave %v\nwant %v", line, typ, heapBits, bits)
}
func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
// repeat a bitmap for a small array or executing a repeat in
// a GC program.
val := MakeSlice(typ, 0, cap)
- data := NewAt(ArrayOf(cap, typ), unsafe.Pointer(val.Pointer()))
+ data := NewAt(typ.Elem(), val.UnsafePointer())
heapBits := GCBits(data.Interface())
// Repeat the bitmap for the slice size, trimming scalars in
// the last element.
- bits = rep(cap, bits)
- for len(bits) > 0 && bits[len(bits)-1] == 0 {
- bits = bits[:len(bits)-1]
+ bits = trimBitmap(rep(cap, bits))
+ if bytes.Equal(heapBits, bits) {
+ return
}
- if !bytes.Equal(heapBits, bits) {
- t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
+ if len(heapBits) > len(bits) && bytes.Equal(heapBits[:len(bits)], bits) {
+ // Just the prefix matching is OK.
+ return
}
+ _, _, line, _ := runtime.Caller(1)
+ t.Errorf("line %d: heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", line, typ, cap, heapBits, bits)
}
func TestGCBits(t *testing.T) {
verifyGCBits(t, MapOf(ArrayOf(10000, Tscalarptr), Tscalar), lit(1))
verifyGCBits(t, TypeOf((*[10000]Xscalar)(nil)), lit(1))
- verifyGCBits(t, PtrTo(ArrayOf(10000, Tscalar)), lit(1))
+ verifyGCBits(t, PointerTo(ArrayOf(10000, Tscalar)), lit(1))
verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1))
verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1))
- hdr := make([]byte, 8/goarch.PtrSize)
+ hdr := make([]byte, bucketCount/goarch.PtrSize)
- verifyMapBucket := func(t *testing.T, k, e Type, m interface{}, want []byte) {
+ verifyMapBucket := func(t *testing.T, k, e Type, m any, want []byte) {
verifyGCBits(t, MapBucketOf(k, e), want)
verifyGCBits(t, CachedBucketOf(TypeOf(m)), want)
}
verifyMapBucket(t,
Tscalar, Tptr,
map[Xscalar]Xptr(nil),
- join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1)))
+ join(hdr, rep(bucketCount, lit(0)), rep(bucketCount, lit(1)), lit(1)))
verifyMapBucket(t,
Tscalarptr, Tptr,
map[Xscalarptr]Xptr(nil),
- join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1)))
+ join(hdr, rep(bucketCount, lit(0, 1)), rep(bucketCount, lit(1)), lit(1)))
verifyMapBucket(t, Tint64, Tptr,
map[int64]Xptr(nil),
- join(hdr, rep(8, rep(8/goarch.PtrSize, lit(0))), rep(8, lit(1)), lit(1)))
+ join(hdr, rep(bucketCount, rep(8/goarch.PtrSize, lit(0))), rep(bucketCount, lit(1)), lit(1)))
verifyMapBucket(t,
Tscalar, Tscalar,
map[Xscalar]Xscalar(nil),
verifyMapBucket(t,
ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar),
map[[2]Xscalarptr][3]Xptrscalar(nil),
- join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1)))
+ join(hdr, rep(bucketCount*2, lit(0, 1)), rep(bucketCount*3, lit(1, 0)), lit(1)))
verifyMapBucket(t,
ArrayOf(64/goarch.PtrSize, Tscalarptr), ArrayOf(64/goarch.PtrSize, Tptrscalar),
map[[64 / goarch.PtrSize]Xscalarptr][64 / goarch.PtrSize]Xptrscalar(nil),
- join(hdr, rep(8*64/goarch.PtrSize, lit(0, 1)), rep(8*64/goarch.PtrSize, lit(1, 0)), lit(1)))
+ join(hdr, rep(bucketCount*64/goarch.PtrSize, lit(0, 1)), rep(bucketCount*64/goarch.PtrSize, lit(1, 0)), lit(1)))
verifyMapBucket(t,
ArrayOf(64/goarch.PtrSize+1, Tscalarptr), ArrayOf(64/goarch.PtrSize, Tptrscalar),
map[[64/goarch.PtrSize + 1]Xscalarptr][64 / goarch.PtrSize]Xptrscalar(nil),
- join(hdr, rep(8, lit(1)), rep(8*64/goarch.PtrSize, lit(1, 0)), lit(1)))
+ join(hdr, rep(bucketCount, lit(1)), rep(bucketCount*64/goarch.PtrSize, lit(1, 0)), lit(1)))
verifyMapBucket(t,
ArrayOf(64/goarch.PtrSize, Tscalarptr), ArrayOf(64/goarch.PtrSize+1, Tptrscalar),
map[[64 / goarch.PtrSize]Xscalarptr][64/goarch.PtrSize + 1]Xptrscalar(nil),
- join(hdr, rep(8*64/goarch.PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1)))
+ join(hdr, rep(bucketCount*64/goarch.PtrSize, lit(0, 1)), rep(bucketCount, lit(1)), lit(1)))
verifyMapBucket(t,
ArrayOf(64/goarch.PtrSize+1, Tscalarptr), ArrayOf(64/goarch.PtrSize+1, Tptrscalar),
map[[64/goarch.PtrSize + 1]Xscalarptr][64/goarch.PtrSize + 1]Xptrscalar(nil),
- join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1)))
+ join(hdr, rep(bucketCount, lit(1)), rep(bucketCount, lit(1)), lit(1)))
}
func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) }
check("ChanOf", ChanOf(BothDir, TypeOf(T{})))
check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false))
check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{})))
- check("PtrTo", PtrTo(TypeOf(T{})))
+ check("PtrTo", PointerTo(TypeOf(T{})))
check("SliceOf", SliceOf(TypeOf(T{})))
}
type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int
type nameTest struct {
- v interface{}
+ v any
want string
}
{(*func() D1)(nil), ""},
{(*<-chan D1)(nil), ""},
{(*chan<- D1)(nil), ""},
- {(*interface{})(nil), ""},
+ {(*any)(nil), ""},
{(*interface {
F()
})(nil), ""},
type p3 p
type exportTest struct {
- v interface{}
+ v any
want bool
}
exportTests := []exportTest{
wg.Wait()
}
-func BenchmarkNew(b *testing.B) {
- v := TypeOf(XM{})
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- New(v)
- }
- })
-}
-
-func BenchmarkMap(b *testing.B) {
- type V *int
- value := ValueOf((V)(nil))
- stringKeys := []string{}
- mapOfStrings := map[string]V{}
- uint64Keys := []uint64{}
- mapOfUint64s := map[uint64]V{}
- for i := 0; i < 100; i++ {
- stringKey := fmt.Sprintf("key%d", i)
- stringKeys = append(stringKeys, stringKey)
- mapOfStrings[stringKey] = nil
-
- uint64Key := uint64(i)
- uint64Keys = append(uint64Keys, uint64Key)
- mapOfUint64s[uint64Key] = nil
- }
-
- tests := []struct {
- label string
- m, keys, value Value
- }{
- {"StringKeys", ValueOf(mapOfStrings), ValueOf(stringKeys), value},
- {"Uint64Keys", ValueOf(mapOfUint64s), ValueOf(uint64Keys), value},
- }
-
- for _, tt := range tests {
- b.Run(tt.label, func(b *testing.B) {
- b.Run("MapIndex", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for j := tt.keys.Len() - 1; j >= 0; j-- {
- tt.m.MapIndex(tt.keys.Index(j))
- }
- }
- })
- b.Run("SetMapIndex", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- for j := tt.keys.Len() - 1; j >= 0; j-- {
- tt.m.SetMapIndex(tt.keys.Index(j), tt.value)
- }
- }
- })
- })
- }
-}
-
func TestSwapper(t *testing.T) {
type I int
var a, b, c I
type S string
tests := []struct {
- in interface{}
+ in any
i, j int
- want interface{}
+ want any
}{
{
in: []int{1, 20, 300},
var seenk, seenv uint64
iter.Reset(ValueOf(m3))
for iter.Next() {
- iter.SetKey(kv)
+ kv.SetIterKey(iter)
seenk ^= kv.Uint()
- iter.SetValue(kv)
+ kv.SetIterValue(iter)
seenv ^= kv.Uint()
}
if seenk != 0b111 {
t.Fatalf("(%s).ConvertibleTo(%s) = true, want false", t3, t4)
}
}
+
+func TestSetIter(t *testing.T) {
+ data := map[string]int{
+ "foo": 1,
+ "bar": 2,
+ "baz": 3,
+ }
+
+ m := ValueOf(data)
+ i := m.MapRange()
+ k := New(TypeOf("")).Elem()
+ v := New(TypeOf(0)).Elem()
+ shouldPanic("Value.SetIterKey called before Next", func() {
+ k.SetIterKey(i)
+ })
+ shouldPanic("Value.SetIterValue called before Next", func() {
+ v.SetIterValue(i)
+ })
+ data2 := map[string]int{}
+ for i.Next() {
+ k.SetIterKey(i)
+ v.SetIterValue(i)
+ data2[k.Interface().(string)] = v.Interface().(int)
+ }
+ if !DeepEqual(data, data2) {
+ t.Errorf("maps not equal, got %v want %v", data2, data)
+ }
+ shouldPanic("Value.SetIterKey called on exhausted iterator", func() {
+ k.SetIterKey(i)
+ })
+ shouldPanic("Value.SetIterValue called on exhausted iterator", func() {
+ v.SetIterValue(i)
+ })
+
+ i.Reset(m)
+ i.Next()
+ shouldPanic("Value.SetIterKey using unaddressable value", func() {
+ ValueOf("").SetIterKey(i)
+ })
+ shouldPanic("Value.SetIterValue using unaddressable value", func() {
+ ValueOf(0).SetIterValue(i)
+ })
+ shouldPanic("value of type string is not assignable to type int", func() {
+ New(TypeOf(0)).Elem().SetIterKey(i)
+ })
+ shouldPanic("value of type int is not assignable to type string", func() {
+ New(TypeOf("")).Elem().SetIterValue(i)
+ })
+
+ // Make sure assignment conversion works.
+ var x any
+ y := ValueOf(&x).Elem()
+ y.SetIterKey(i)
+ if _, ok := data[x.(string)]; !ok {
+ t.Errorf("got key %s which is not in map", x)
+ }
+ y.SetIterValue(i)
+ if x.(int) < 1 || x.(int) > 3 {
+ t.Errorf("got value %d which is not in map", x)
+ }
+
+ // Try some key/value types which are direct interfaces.
+ a := 88
+ b := 99
+ pp := map[*int]*int{
+ &a: &b,
+ }
+ i = ValueOf(pp).MapRange()
+ i.Next()
+ y.SetIterKey(i)
+ if got := *y.Interface().(*int); got != a {
+ t.Errorf("pointer incorrect: got %d want %d", got, a)
+ }
+ y.SetIterValue(i)
+ if got := *y.Interface().(*int); got != b {
+ t.Errorf("pointer incorrect: got %d want %d", got, b)
+ }
+
+ // Make sure we panic assigning from an unexported field.
+ m = ValueOf(struct{ m map[string]int }{data}).Field(0)
+ for iter := m.MapRange(); iter.Next(); {
+ shouldPanic("using value obtained using unexported field", func() {
+ k.SetIterKey(iter)
+ })
+ shouldPanic("using value obtained using unexported field", func() {
+ v.SetIterValue(iter)
+ })
+ }
+}
+
+func TestMethodCallValueCodePtr(t *testing.T) {
+ m := ValueOf(Point{}).Method(1)
+ want := MethodValueCallCodePtr()
+ if got := uintptr(m.UnsafePointer()); got != want {
+ t.Errorf("methodValueCall code pointer mismatched, want: %v, got: %v", want, got)
+ }
+ if got := m.Pointer(); got != want {
+ t.Errorf("methodValueCall code pointer mismatched, want: %v, got: %v", want, got)
+ }
+}
+
+type A struct{}
+type B[T any] struct{}
+
+func TestIssue50208(t *testing.T) {
+ want1 := "B[reflect_test.A]"
+ if got := TypeOf(new(B[A])).Elem().Name(); got != want1 {
+ t.Errorf("name of type parameter mismatched, want:%s, got:%s", want1, got)
+ }
+ want2 := "B[reflect_test.B[reflect_test.A]]"
+ if got := TypeOf(new(B[B[A]])).Elem().Name(); got != want2 {
+ t.Errorf("name of type parameter mismatched, want:%s, got:%s", want2, got)
+ }
+}
+
+func TestNegativeKindString(t *testing.T) {
+ x := -1
+ s := Kind(x).String()
+ want := "kind-1"
+ if s != want {
+ t.Fatalf("Kind(-1).String() = %q, want %q", s, want)
+ }
+}
+
+type (
+ namedBool bool
+ namedBytes []byte
+)
+
+func TestValue_Cap(t *testing.T) {
+ a := &[3]int{1, 2, 3}
+ v := ValueOf(a)
+ if v.Cap() != cap(a) {
+ t.Errorf("Cap = %d want %d", v.Cap(), cap(a))
+ }
+
+ a = nil
+ v = ValueOf(a)
+ if v.Cap() != cap(a) {
+ t.Errorf("Cap = %d want %d", v.Cap(), cap(a))
+ }
+
+ getError := func(f func()) (errorStr string) {
+ defer func() {
+ e := recover()
+ if str, ok := e.(string); ok {
+ errorStr = str
+ }
+ }()
+ f()
+ return
+ }
+ e := getError(func() {
+ var ptr *int
+ ValueOf(ptr).Cap()
+ })
+ wantStr := "reflect: call of reflect.Value.Cap on ptr to non-array Value"
+ if e != wantStr {
+ t.Errorf("error is %q, want %q", e, wantStr)
+ }
+}
+
+func TestValue_Len(t *testing.T) {
+ a := &[3]int{1, 2, 3}
+ v := ValueOf(a)
+ if v.Len() != len(a) {
+ t.Errorf("Len = %d want %d", v.Len(), len(a))
+ }
+
+ a = nil
+ v = ValueOf(a)
+ if v.Len() != len(a) {
+ t.Errorf("Len = %d want %d", v.Len(), len(a))
+ }
+
+ getError := func(f func()) (errorStr string) {
+ defer func() {
+ e := recover()
+ if str, ok := e.(string); ok {
+ errorStr = str
+ }
+ }()
+ f()
+ return
+ }
+ e := getError(func() {
+ var ptr *int
+ ValueOf(ptr).Len()
+ })
+ wantStr := "reflect: call of reflect.Value.Len on ptr to non-array Value"
+ if e != wantStr {
+ t.Errorf("error is %q, want %q", e, wantStr)
+ }
+}
+
+func TestValue_Comparable(t *testing.T) {
+ var a int
+ var s []int
+ var i interface{} = a
+ var iSlice interface{} = s
+ var iArrayFalse interface{} = [2]interface{}{1, map[int]int{}}
+ var iArrayTrue interface{} = [2]interface{}{1, struct{ I interface{} }{1}}
+ var testcases = []struct {
+ value Value
+ comparable bool
+ deref bool
+ }{
+ {
+ ValueOf(32),
+ true,
+ false,
+ },
+ {
+ ValueOf(int8(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(int16(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(int32(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(int64(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(uint8(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(uint16(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(uint32(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(uint64(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(float32(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(float64(1)),
+ true,
+ false,
+ },
+ {
+ ValueOf(complex(float32(1), float32(1))),
+ true,
+ false,
+ },
+ {
+ ValueOf(complex(float64(1), float64(1))),
+ true,
+ false,
+ },
+ {
+ ValueOf("abc"),
+ true,
+ false,
+ },
+ {
+ ValueOf(true),
+ true,
+ false,
+ },
+ {
+ ValueOf(map[int]int{}),
+ false,
+ false,
+ },
+ {
+ ValueOf([]int{}),
+ false,
+ false,
+ },
+ {
+ Value{},
+ false,
+ false,
+ },
+ {
+ ValueOf(&a),
+ true,
+ false,
+ },
+ {
+ ValueOf(&s),
+ true,
+ false,
+ },
+ {
+ ValueOf(&i),
+ true,
+ true,
+ },
+ {
+ ValueOf(&iSlice),
+ false,
+ true,
+ },
+ {
+ ValueOf([2]int{}),
+ true,
+ false,
+ },
+ {
+ ValueOf([2]map[int]int{}),
+ false,
+ false,
+ },
+ {
+ ValueOf([0]func(){}),
+ false,
+ false,
+ },
+ {
+ ValueOf([2]struct{ I interface{} }{{1}, {1}}),
+ true,
+ false,
+ },
+ {
+ ValueOf([2]struct{ I interface{} }{{[]int{}}, {1}}),
+ false,
+ false,
+ },
+ {
+ ValueOf([2]interface{}{1, struct{ I int }{1}}),
+ true,
+ false,
+ },
+ {
+ ValueOf([2]interface{}{[1]interface{}{map[int]int{}}, struct{ I int }{1}}),
+ false,
+ false,
+ },
+ {
+ ValueOf(&iArrayFalse),
+ false,
+ true,
+ },
+ {
+ ValueOf(&iArrayTrue),
+ true,
+ true,
+ },
+ }
+
+ for _, cas := range testcases {
+ v := cas.value
+ if cas.deref {
+ v = v.Elem()
+ }
+ got := v.Comparable()
+ if got != cas.comparable {
+ t.Errorf("%T.Comparable = %t, want %t", v, got, cas.comparable)
+ }
+ }
+}
+
+type ValueEqualTest struct {
+ v, u any
+ eq bool
+ vDeref, uDeref bool
+}
+
+var equalI interface{} = 1
+var equalSlice interface{} = []int{1}
+var nilInterface interface{}
+var mapInterface interface{} = map[int]int{}
+
+var valueEqualTests = []ValueEqualTest{
+ {
+ Value{}, Value{},
+ true,
+ false, false,
+ },
+ {
+ true, true,
+ true,
+ false, false,
+ },
+ {
+ 1, 1,
+ true,
+ false, false,
+ },
+ {
+ int8(1), int8(1),
+ true,
+ false, false,
+ },
+ {
+ int16(1), int16(1),
+ true,
+ false, false,
+ },
+ {
+ int32(1), int32(1),
+ true,
+ false, false,
+ },
+ {
+ int64(1), int64(1),
+ true,
+ false, false,
+ },
+ {
+ uint(1), uint(1),
+ true,
+ false, false,
+ },
+ {
+ uint8(1), uint8(1),
+ true,
+ false, false,
+ },
+ {
+ uint16(1), uint16(1),
+ true,
+ false, false,
+ },
+ {
+ uint32(1), uint32(1),
+ true,
+ false, false,
+ },
+ {
+ uint64(1), uint64(1),
+ true,
+ false, false,
+ },
+ {
+ float32(1), float32(1),
+ true,
+ false, false,
+ },
+ {
+ float64(1), float64(1),
+ true,
+ false, false,
+ },
+ {
+ complex(1, 1), complex(1, 1),
+ true,
+ false, false,
+ },
+ {
+ complex128(1 + 1i), complex128(1 + 1i),
+ true,
+ false, false,
+ },
+ {
+ func() {}, nil,
+ false,
+ false, false,
+ },
+ {
+ &equalI, 1,
+ true,
+ true, false,
+ },
+ {
+ (chan int)(nil), nil,
+ false,
+ false, false,
+ },
+ {
+ (chan int)(nil), (chan int)(nil),
+ true,
+ false, false,
+ },
+ {
+ &equalI, &equalI,
+ true,
+ false, false,
+ },
+ {
+ struct{ i int }{1}, struct{ i int }{1},
+ true,
+ false, false,
+ },
+ {
+ struct{ i int }{1}, struct{ i int }{2},
+ false,
+ false, false,
+ },
+ {
+ &nilInterface, &nilInterface,
+ true,
+ true, true,
+ },
+ {
+ 1, ValueOf(struct{ i int }{1}).Field(0),
+ true,
+ false, false,
+ },
+}
+
+func TestValue_Equal(t *testing.T) {
+ for _, test := range valueEqualTests {
+ var v, u Value
+ if vv, ok := test.v.(Value); ok {
+ v = vv
+ } else {
+ v = ValueOf(test.v)
+ }
+
+ if uu, ok := test.u.(Value); ok {
+ u = uu
+ } else {
+ u = ValueOf(test.u)
+ }
+ if test.vDeref {
+ v = v.Elem()
+ }
+
+ if test.uDeref {
+ u = u.Elem()
+ }
+
+ if r := v.Equal(u); r != test.eq {
+ t.Errorf("%s == %s got %t, want %t", v.Type(), u.Type(), r, test.eq)
+ }
+ }
+}
+
+func TestValue_EqualNonComparable(t *testing.T) {
+ var invalid = Value{} // ValueOf(nil)
+ var values = []Value{
+ // Value of slice is non-comparable.
+ ValueOf([]int(nil)),
+ ValueOf(([]int{})),
+
+ // Value of map is non-comparable.
+ ValueOf(map[int]int(nil)),
+ ValueOf((map[int]int{})),
+
+ // Value of func is non-comparable.
+ ValueOf(((func())(nil))),
+ ValueOf(func() {}),
+
+ // Value of struct is non-comparable because of non-comparable elements.
+ ValueOf((NonComparableStruct{})),
+
+ // Value of array is non-comparable because of non-comparable elements.
+ ValueOf([0]map[int]int{}),
+ ValueOf([0]func(){}),
+ ValueOf(([1]struct{ I interface{} }{{[]int{}}})),
+ ValueOf(([1]interface{}{[1]interface{}{map[int]int{}}})),
+ }
+ for _, value := range values {
+ // Panic when reflect.Value.Equal using two valid non-comparable values.
+ shouldPanic("are not comparable", func() { value.Equal(value) })
+
+ // If one is non-comparable and the other is invalid, the expected result is always false.
+ if r := value.Equal(invalid); r != false {
+ t.Errorf("%s == invalid got %t, want false", value.Type(), r)
+ }
+ }
+}
+
+func TestInitFuncTypes(t *testing.T) {
+ n := 100
+ var wg sync.WaitGroup
+
+ wg.Add(n)
+ for i := 0; i < n; i++ {
+ go func() {
+ defer wg.Done()
+ ipT := TypeOf(net.IP{})
+ for i := 0; i < ipT.NumMethod(); i++ {
+ _ = ipT.Method(i)
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func TestClear(t *testing.T) {
+ m := make(map[string]any, len(valueTests))
+ for _, tt := range valueTests {
+ m[tt.s] = tt.i
+ }
+ mapTestFn := func(v Value) bool { v.Clear(); return v.Len() == 0 }
+
+ s := make([]*pair, len(valueTests))
+ for i := range s {
+ s[i] = &valueTests[i]
+ }
+ sliceTestFn := func(v Value) bool {
+ v.Clear()
+ for i := 0; i < v.Len(); i++ {
+ if !v.Index(i).IsZero() {
+ return false
+ }
+ }
+ return true
+ }
+
+ panicTestFn := func(v Value) bool { shouldPanic("reflect.Value.Clear", func() { v.Clear() }); return true }
+
+ tests := []struct {
+ name string
+ value Value
+ testFunc func(v Value) bool
+ }{
+ {"map", ValueOf(m), mapTestFn},
+ {"slice no pointer", ValueOf([]int{1, 2, 3, 4, 5}), sliceTestFn},
+ {"slice has pointer", ValueOf(s), sliceTestFn},
+ {"non-map/slice", ValueOf(1), panicTestFn},
+ }
+
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ if !tc.testFunc(tc.value) {
+ t.Errorf("unexpected result for value.Clear(): %value", tc.value)
+ }
+ })
+ }
+}