go/src/internal/reflectlite/all_test.go
Matthew Dempsky ab8d7dd75e cmd/compile: set LocalPkg.Path to -p flag
Since CL 391014, cmd/compile now requires the -p flag to be set the
build system. This CL changes it to initialize LocalPkg.Path to the
provided path, rather than relying on writing out `"".` into object
files and expecting cmd/link to substitute them.

However, this actually involved a rather long tail of fixes. Many have
already been submitted, but a few notable ones that have to land
simultaneously with changing LocalPkg:

1. When compiling package runtime, there are really two "runtime"
packages: types.LocalPkg (the source package itself) and
ir.Pkgs.Runtime (the compiler's internal representation, for synthetic
references). Previously, these ended up creating separate link
symbols (`"".xxx` and `runtime.xxx`, respectively), but now they both
end up as `runtime.xxx`, which causes lsym collisions (notably
inittask and funcsyms).

2. test/codegen tests need to be updated to expect symbols to be named
`command-line-arguments.xxx` rather than `"".foo`.

3. The issue20014 test case is sensitive to the sort order of field
tracking symbols. In particular, the local package now sorts to its
natural place in the list, rather than to the front.

Thanks to David Chase for helping track down all of the fixes needed
for this CL.

Updates #51734.

Change-Id: Iba3041cf7ad967d18c6e17922fa06ba11798b565
Reviewed-on: https://go-review.googlesource.com/c/go/+/393715
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2022-05-16 18:19:47 +00:00

1038 lines
24 KiB
Go

// Copyright 2009 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 reflectlite_test
import (
"encoding/base64"
"fmt"
. "internal/reflectlite"
"math"
"reflect"
"runtime"
"testing"
"unsafe"
)
func ToValue(v Value) reflect.Value {
return reflect.ValueOf(ToInterface(v))
}
func TypeString(t Type) string {
return fmt.Sprintf("%T", ToInterface(Zero(t)))
}
type integer int
type T struct {
a int
b float64
c string
d *int
}
type pair struct {
i any
s string
}
func assert(t *testing.T, s, want string) {
t.Helper()
if s != want {
t.Errorf("have %#q want %#q", s, want)
}
}
var typeTests = []pair{
{struct{ x int }{}, "int"},
{struct{ x int8 }{}, "int8"},
{struct{ x int16 }{}, "int16"},
{struct{ x int32 }{}, "int32"},
{struct{ x int64 }{}, "int64"},
{struct{ x uint }{}, "uint"},
{struct{ x uint8 }{}, "uint8"},
{struct{ x uint16 }{}, "uint16"},
{struct{ x uint32 }{}, "uint32"},
{struct{ x uint64 }{}, "uint64"},
{struct{ x float32 }{}, "float32"},
{struct{ x float64 }{}, "float64"},
{struct{ x int8 }{}, "int8"},
{struct{ x (**int8) }{}, "**int8"},
{struct{ x (**integer) }{}, "**reflectlite_test.integer"},
{struct{ x ([32]int32) }{}, "[32]int32"},
{struct{ x ([]int8) }{}, "[]int8"},
{struct{ x (map[string]int32) }{}, "map[string]int32"},
{struct{ x (chan<- string) }{}, "chan<- string"},
{struct {
x struct {
c chan *int32
d float32
}
}{},
"struct { c chan *int32; d float32 }",
},
{struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
{struct {
x struct {
c func(chan *integer, *int8)
}
}{},
"struct { c func(chan *reflectlite_test.integer, *int8) }",
},
{struct {
x struct {
a int8
b int32
}
}{},
"struct { a int8; b int32 }",
},
{struct {
x struct {
a int8
b int8
c int32
}
}{},
"struct { a int8; b int8; c int32 }",
},
{struct {
x struct {
a int8
b int8
c int8
d int32
}
}{},
"struct { a int8; b int8; c int8; d int32 }",
},
{struct {
x struct {
a int8
b int8
c int8
d int8
e int32
}
}{},
"struct { a int8; b int8; c int8; d int8; e int32 }",
},
{struct {
x struct {
a int8
b int8
c int8
d int8
e int8
f int32
}
}{},
"struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
},
{struct {
x struct {
a int8 `reflect:"hi there"`
}
}{},
`struct { a int8 "reflect:\"hi there\"" }`,
},
{struct {
x struct {
a int8 `reflect:"hi \x00there\t\n\"\\"`
}
}{},
`struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
},
{struct {
x struct {
f func(args ...int)
}
}{},
"struct { f func(...int) }",
},
// {struct {
// x (interface {
// a(func(func(int) int) func(func(int)) int)
// b()
// })
// }{},
// "interface { reflectlite_test.a(func(func(int) int) func(func(int)) int); reflectlite_test.b() }",
// },
{struct {
x struct {
int32
int64
}
}{},
"struct { int32; int64 }",
},
}
var valueTests = []pair{
{new(int), "132"},
{new(int8), "8"},
{new(int16), "16"},
{new(int32), "32"},
{new(int64), "64"},
{new(uint), "132"},
{new(uint8), "8"},
{new(uint16), "16"},
{new(uint32), "32"},
{new(uint64), "64"},
{new(float32), "256.25"},
{new(float64), "512.125"},
{new(complex64), "532.125+10i"},
{new(complex128), "564.25+1i"},
{new(string), "stringy cheese"},
{new(bool), "true"},
{new(*int8), "*int8(0)"},
{new(**int8), "**int8(0)"},
{new([5]int32), "[5]int32{0, 0, 0, 0, 0}"},
{new(**integer), "**reflectlite_test.integer(0)"},
{new(map[string]int32), "map[string]int32{<can't iterate on maps>}"},
{new(chan<- string), "chan<- string"},
{new(func(a int8, b int32)), "func(int8, int32)(arg)"},
{new(struct {
c chan *int32
d float32
}),
"struct { c chan *int32; d float32 }{chan *int32, 0}",
},
{new(struct{ c func(chan *integer, *int8) }),
"struct { c func(chan *reflectlite_test.integer, *int8) }{func(chan *reflectlite_test.integer, *int8)(arg)}",
},
{new(struct {
a int8
b int32
}),
"struct { a int8; b int32 }{0, 0}",
},
{new(struct {
a int8
b int8
c int32
}),
"struct { a int8; b int8; c int32 }{0, 0, 0}",
},
}
func testType(t *testing.T, i int, typ Type, want string) {
s := TypeString(typ)
if s != want {
t.Errorf("#%d: have %#q, want %#q", i, s, want)
}
}
func testReflectType(t *testing.T, i int, typ Type, want string) {
s := TypeString(typ)
if s != want {
t.Errorf("#%d: have %#q, want %#q", i, s, want)
}
}
func TestTypes(t *testing.T) {
for i, tt := range typeTests {
testReflectType(t, i, Field(ValueOf(tt.i), 0).Type(), tt.s)
}
}
func TestSetValue(t *testing.T) {
for i, tt := range valueTests {
v := ValueOf(tt.i).Elem()
switch v.Kind() {
case Int:
v.Set(ValueOf(int(132)))
case Int8:
v.Set(ValueOf(int8(8)))
case Int16:
v.Set(ValueOf(int16(16)))
case Int32:
v.Set(ValueOf(int32(32)))
case Int64:
v.Set(ValueOf(int64(64)))
case Uint:
v.Set(ValueOf(uint(132)))
case Uint8:
v.Set(ValueOf(uint8(8)))
case Uint16:
v.Set(ValueOf(uint16(16)))
case Uint32:
v.Set(ValueOf(uint32(32)))
case Uint64:
v.Set(ValueOf(uint64(64)))
case Float32:
v.Set(ValueOf(float32(256.25)))
case Float64:
v.Set(ValueOf(512.125))
case Complex64:
v.Set(ValueOf(complex64(532.125 + 10i)))
case Complex128:
v.Set(ValueOf(complex128(564.25 + 1i)))
case String:
v.Set(ValueOf("stringy cheese"))
case Bool:
v.Set(ValueOf(true))
}
s := valueToString(v)
if s != tt.s {
t.Errorf("#%d: have %#q, want %#q", i, s, tt.s)
}
}
}
func TestCanSetField(t *testing.T) {
type embed struct{ x, X int }
type Embed struct{ x, X int }
type S1 struct {
embed
x, X int
}
type S2 struct {
*embed
x, X int
}
type S3 struct {
Embed
x, X int
}
type S4 struct {
*Embed
x, X int
}
type testCase struct {
index []int
canSet bool
}
tests := []struct {
val Value
cases []testCase
}{{
val: ValueOf(&S1{}),
cases: []testCase{
{[]int{0}, false},
{[]int{0, 0}, false},
{[]int{0, 1}, true},
{[]int{1}, false},
{[]int{2}, true},
},
}, {
val: ValueOf(&S2{embed: &embed{}}),
cases: []testCase{
{[]int{0}, false},
{[]int{0, 0}, false},
{[]int{0, 1}, true},
{[]int{1}, false},
{[]int{2}, true},
},
}, {
val: ValueOf(&S3{}),
cases: []testCase{
{[]int{0}, true},
{[]int{0, 0}, false},
{[]int{0, 1}, true},
{[]int{1}, false},
{[]int{2}, true},
},
}, {
val: ValueOf(&S4{Embed: &Embed{}}),
cases: []testCase{
{[]int{0}, true},
{[]int{0, 0}, false},
{[]int{0, 1}, true},
{[]int{1}, false},
{[]int{2}, true},
},
}}
for _, tt := range tests {
t.Run(tt.val.Type().Name(), func(t *testing.T) {
for _, tc := range tt.cases {
f := tt.val
for _, i := range tc.index {
if f.Kind() == Ptr {
f = f.Elem()
}
f = Field(f, i)
}
if got := f.CanSet(); got != tc.canSet {
t.Errorf("CanSet() = %v, want %v", got, tc.canSet)
}
}
})
}
}
var _i = 7
var valueToStringTests = []pair{
{123, "123"},
{123.5, "123.5"},
{byte(123), "123"},
{"abc", "abc"},
{T{123, 456.75, "hello", &_i}, "reflectlite_test.T{123, 456.75, hello, *int(&7)}"},
{new(chan *T), "*chan *reflectlite_test.T(&chan *reflectlite_test.T)"},
{[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
{&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
{[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
{&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
}
func TestValueToString(t *testing.T) {
for i, test := range valueToStringTests {
s := valueToString(ValueOf(test.i))
if s != test.s {
t.Errorf("#%d: have %#q, want %#q", i, s, test.s)
}
}
}
func TestPtrSetNil(t *testing.T) {
var i int32 = 1234
ip := &i
vip := ValueOf(&ip)
vip.Elem().Set(Zero(vip.Elem().Type()))
if ip != nil {
t.Errorf("got non-nil (%d), want nil", *ip)
}
}
func TestMapSetNil(t *testing.T) {
m := make(map[string]int)
vm := ValueOf(&m)
vm.Elem().Set(Zero(vm.Elem().Type()))
if m != nil {
t.Errorf("got non-nil (%p), want nil", m)
}
}
func TestAll(t *testing.T) {
testType(t, 1, TypeOf((int8)(0)), "int8")
testType(t, 2, TypeOf((*int8)(nil)).Elem(), "int8")
typ := TypeOf((*struct {
c chan *int32
d float32
})(nil))
testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
etyp := typ.Elem()
testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
}
func TestInterfaceValue(t *testing.T) {
var inter struct {
E any
}
inter.E = 123.456
v1 := ValueOf(&inter)
v2 := Field(v1.Elem(), 0)
// assert(t, TypeString(v2.Type()), "interface {}")
v3 := v2.Elem()
assert(t, TypeString(v3.Type()), "float64")
i3 := ToInterface(v2)
if _, ok := i3.(float64); !ok {
t.Error("v2.Interface() did not return float64, got ", TypeOf(i3))
}
}
func TestFunctionValue(t *testing.T) {
var x any = func() {}
v := ValueOf(x)
if fmt.Sprint(ToInterface(v)) != fmt.Sprint(x) {
t.Fatalf("TestFunction returned wrong pointer")
}
assert(t, TypeString(v.Type()), "func()")
}
var appendTests = []struct {
orig, extra []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 TestBigUnnamedStruct(t *testing.T) {
b := struct{ a, b, c, d int64 }{1, 2, 3, 4}
v := ValueOf(b)
b1 := ToInterface(v).(struct {
a, b, c, d int64
})
if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d {
t.Errorf("ValueOf(%v).Interface().(*Big) = %v", b, b1)
}
}
type big struct {
a, b, c, d, e int64
}
func TestBigStruct(t *testing.T) {
b := big{1, 2, 3, 4, 5}
v := ValueOf(b)
b1 := ToInterface(v).(big)
if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e {
t.Errorf("ValueOf(%v).Interface().(big) = %v", b, b1)
}
}
type Basic struct {
x int
y float32
}
type NotBasic Basic
type DeepEqualTest struct {
a, b any
eq bool
}
// Simple functions for DeepEqual tests.
var (
fn1 func() // nil.
fn2 func() // nil.
fn3 = func() { fn1() } // Not nil.
)
type self struct{}
type Loop *Loop
type Loopy any
var loop1, loop2 Loop
var loopy1, loopy2 Loopy
func init() {
loop1 = &loop2
loop2 = &loop1
loopy1 = &loopy2
loopy2 = &loopy1
}
var typeOfTests = []DeepEqualTest{
// Equalities
{nil, nil, true},
{1, 1, true},
{int32(1), int32(1), true},
{0.5, 0.5, true},
{float32(0.5), float32(0.5), true},
{"hello", "hello", true},
{make([]int, 10), make([]int, 10), true},
{&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
{Basic{1, 0.5}, Basic{1, 0.5}, true},
{error(nil), error(nil), true},
{map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
{fn1, fn2, true},
// Inequalities
{1, 2, false},
{int32(1), int32(2), false},
{0.5, 0.6, false},
{float32(0.5), float32(0.6), false},
{"hello", "hey", false},
{make([]int, 10), make([]int, 11), false},
{&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
{Basic{1, 0.5}, Basic{1, 0.6}, false},
{Basic{1, 0}, Basic{2, 0}, false},
{map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
{map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
{map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
{map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
{nil, 1, false},
{1, nil, false},
{fn1, fn3, false},
{fn3, fn3, false},
{[][]int{{1}}, [][]int{{2}}, false},
{math.NaN(), math.NaN(), false},
{&[1]float64{math.NaN()}, &[1]float64{math.NaN()}, false},
{&[1]float64{math.NaN()}, self{}, true},
{[]float64{math.NaN()}, []float64{math.NaN()}, false},
{[]float64{math.NaN()}, self{}, true},
{map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false},
{map[float64]float64{math.NaN(): 1}, self{}, true},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
{[]int{}, []int{}, true},
{[]int(nil), []int(nil), true},
{map[int]int{}, map[int]int(nil), false},
{map[int]int{}, map[int]int{}, true},
{map[int]int(nil), map[int]int(nil), true},
// Mismatched types
{1, 1.0, false},
{int32(1), int64(1), false},
{0.5, "hello", false},
{[]int{1, 2, 3}, [3]int{1, 2, 3}, 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},
// Possible loops.
{&loop1, &loop1, true},
{&loop1, &loop2, true},
{&loopy1, &loopy1, true},
{&loopy1, &loopy2, true},
}
func TestTypeOf(t *testing.T) {
// Special case for nil
if typ := TypeOf(nil); typ != nil {
t.Errorf("expected nil type for nil value; got %v", typ)
}
for _, test := range typeOfTests {
v := ValueOf(test.a)
if !v.IsValid() {
continue
}
typ := TypeOf(test.a)
if typ != v.Type() {
t.Errorf("TypeOf(%v) = %v, but ValueOf(%v).Type() = %v", test.a, typ, test.a, v.Type())
}
}
}
func Nil(a any, t *testing.T) {
n := Field(ValueOf(a), 0)
if !n.IsNil() {
t.Errorf("%v should be nil", a)
}
}
func NotNil(a any, t *testing.T) {
n := Field(ValueOf(a), 0)
if n.IsNil() {
t.Errorf("value of type %v should not be nil", TypeString(ValueOf(a).Type()))
}
}
func TestIsNil(t *testing.T) {
// These implement IsNil.
// Wrap in extra struct to hide interface type.
doNil := []any{
struct{ x *int }{},
struct{ x any }{},
struct{ x map[string]int }{},
struct{ x func() bool }{},
struct{ x chan int }{},
struct{ x []string }{},
struct{ x unsafe.Pointer }{},
}
for _, ts := range doNil {
ty := TField(TypeOf(ts), 0)
v := Zero(ty)
v.IsNil() // panics if not okay to call
}
// Check the implementations
var pi struct {
x *int
}
Nil(pi, t)
pi.x = new(int)
NotNil(pi, t)
var si struct {
x []int
}
Nil(si, t)
si.x = make([]int, 10)
NotNil(si, t)
var ci struct {
x chan int
}
Nil(ci, t)
ci.x = make(chan int)
NotNil(ci, t)
var mi struct {
x map[int]int
}
Nil(mi, t)
mi.x = make(map[int]int)
NotNil(mi, t)
var ii struct {
x any
}
Nil(ii, t)
ii.x = 2
NotNil(ii, t)
var fi struct {
x func(t *testing.T)
}
Nil(fi, t)
fi.x = TestIsNil
NotNil(fi, t)
}
// Indirect returns the value that v points to.
// If v is a nil pointer, Indirect returns a zero Value.
// If v is not a pointer, Indirect returns v.
func Indirect(v Value) Value {
if v.Kind() != Ptr {
return v
}
return v.Elem()
}
func TestNilPtrValueSub(t *testing.T) {
var pi *int
if pv := ValueOf(pi); pv.Elem().IsValid() {
t.Error("ValueOf((*int)(nil)).Elem().IsValid()")
}
}
type Point struct {
x, y int
}
// This will be index 0.
func (p Point) AnotherMethod(scale int) int {
return -1
}
// This will be index 1.
func (p Point) Dist(scale int) int {
//println("Point.Dist", p.x, p.y, scale)
return p.x*p.x*scale + p.y*p.y*scale
}
// This will be index 2.
func (p Point) GCMethod(k int) int {
runtime.GC()
return k + p.x
}
// This will be index 3.
func (p Point) NoArgs() {
// Exercise no-argument/no-result paths.
}
// This will be index 4.
func (p Point) TotalDist(points ...Point) int {
tot := 0
for _, q := range points {
dx := q.x - p.x
dy := q.y - p.y
tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test.
}
return tot
}
type D1 struct {
d int
}
type D2 struct {
d int
}
func TestImportPath(t *testing.T) {
tests := []struct {
t Type
path string
}{
{TypeOf(&base64.Encoding{}).Elem(), "encoding/base64"},
{TypeOf(int(0)), ""},
{TypeOf(int8(0)), ""},
{TypeOf(int16(0)), ""},
{TypeOf(int32(0)), ""},
{TypeOf(int64(0)), ""},
{TypeOf(uint(0)), ""},
{TypeOf(uint8(0)), ""},
{TypeOf(uint16(0)), ""},
{TypeOf(uint32(0)), ""},
{TypeOf(uint64(0)), ""},
{TypeOf(uintptr(0)), ""},
{TypeOf(float32(0)), ""},
{TypeOf(float64(0)), ""},
{TypeOf(complex64(0)), ""},
{TypeOf(complex128(0)), ""},
{TypeOf(byte(0)), ""},
{TypeOf(rune(0)), ""},
{TypeOf([]byte(nil)), ""},
{TypeOf([]rune(nil)), ""},
{TypeOf(string("")), ""},
{TypeOf((*any)(nil)).Elem(), ""},
{TypeOf((*byte)(nil)), ""},
{TypeOf((*rune)(nil)), ""},
{TypeOf((*int64)(nil)), ""},
{TypeOf(map[string]int{}), ""},
{TypeOf((*error)(nil)).Elem(), ""},
{TypeOf((*Point)(nil)), ""},
{TypeOf((*Point)(nil)).Elem(), "internal/reflectlite_test"},
}
for _, test := range tests {
if path := test.t.PkgPath(); path != test.path {
t.Errorf("%v.PkgPath() = %q, want %q", test.t, path, test.path)
}
}
}
func noAlloc(t *testing.T, n int, f func(int)) {
if testing.Short() {
t.Skip("skipping malloc count in short mode")
}
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
}
i := -1
allocs := testing.AllocsPerRun(n, func() {
f(i)
i++
})
if allocs > 0 {
t.Errorf("%d iterations: got %v mallocs, want 0", n, allocs)
}
}
func TestAllocations(t *testing.T) {
noAlloc(t, 100, func(j int) {
var i any
var v Value
// We can uncomment this when compiler escape analysis
// is good enough to see that the integer assigned to i
// does not escape and therefore need not be allocated.
//
// i = 42 + j
// v = ValueOf(i)
// if int(v.Int()) != 42+j {
// panic("wrong int")
// }
i = func(j int) int { return j }
v = ValueOf(i)
if ToInterface(v).(func(int) int)(j) != j {
panic("wrong result")
}
})
}
func TestSetPanic(t *testing.T) {
ok := func(f func()) { f() }
bad := shouldPanic
clear := func(v Value) { v.Set(Zero(v.Type())) }
type t0 struct {
W int
}
type t1 struct {
Y int
t0
}
type T2 struct {
Z int
namedT0 t0
}
type T struct {
X int
t1
T2
NamedT1 t1
NamedT2 T2
namedT1 t1
namedT2 T2
}
// not addressable
v := ValueOf(T{})
bad(func() { clear(Field(v, 0)) }) // .X
bad(func() { clear(Field(v, 1)) }) // .t1
bad(func() { clear(Field(Field(v, 1), 0)) }) // .t1.Y
bad(func() { clear(Field(Field(v, 1), 1)) }) // .t1.t0
bad(func() { clear(Field(Field(Field(v, 1), 1), 0)) }) // .t1.t0.W
bad(func() { clear(Field(v, 2)) }) // .T2
bad(func() { clear(Field(Field(v, 2), 0)) }) // .T2.Z
bad(func() { clear(Field(Field(v, 2), 1)) }) // .T2.namedT0
bad(func() { clear(Field(Field(Field(v, 2), 1), 0)) }) // .T2.namedT0.W
bad(func() { clear(Field(v, 3)) }) // .NamedT1
bad(func() { clear(Field(Field(v, 3), 0)) }) // .NamedT1.Y
bad(func() { clear(Field(Field(v, 3), 1)) }) // .NamedT1.t0
bad(func() { clear(Field(Field(Field(v, 3), 1), 0)) }) // .NamedT1.t0.W
bad(func() { clear(Field(v, 4)) }) // .NamedT2
bad(func() { clear(Field(Field(v, 4), 0)) }) // .NamedT2.Z
bad(func() { clear(Field(Field(v, 4), 1)) }) // .NamedT2.namedT0
bad(func() { clear(Field(Field(Field(v, 4), 1), 0)) }) // .NamedT2.namedT0.W
bad(func() { clear(Field(v, 5)) }) // .namedT1
bad(func() { clear(Field(Field(v, 5), 0)) }) // .namedT1.Y
bad(func() { clear(Field(Field(v, 5), 1)) }) // .namedT1.t0
bad(func() { clear(Field(Field(Field(v, 5), 1), 0)) }) // .namedT1.t0.W
bad(func() { clear(Field(v, 6)) }) // .namedT2
bad(func() { clear(Field(Field(v, 6), 0)) }) // .namedT2.Z
bad(func() { clear(Field(Field(v, 6), 1)) }) // .namedT2.namedT0
bad(func() { clear(Field(Field(Field(v, 6), 1), 0)) }) // .namedT2.namedT0.W
// addressable
v = ValueOf(&T{}).Elem()
ok(func() { clear(Field(v, 0)) }) // .X
bad(func() { clear(Field(v, 1)) }) // .t1
ok(func() { clear(Field(Field(v, 1), 0)) }) // .t1.Y
bad(func() { clear(Field(Field(v, 1), 1)) }) // .t1.t0
ok(func() { clear(Field(Field(Field(v, 1), 1), 0)) }) // .t1.t0.W
ok(func() { clear(Field(v, 2)) }) // .T2
ok(func() { clear(Field(Field(v, 2), 0)) }) // .T2.Z
bad(func() { clear(Field(Field(v, 2), 1)) }) // .T2.namedT0
bad(func() { clear(Field(Field(Field(v, 2), 1), 0)) }) // .T2.namedT0.W
ok(func() { clear(Field(v, 3)) }) // .NamedT1
ok(func() { clear(Field(Field(v, 3), 0)) }) // .NamedT1.Y
bad(func() { clear(Field(Field(v, 3), 1)) }) // .NamedT1.t0
ok(func() { clear(Field(Field(Field(v, 3), 1), 0)) }) // .NamedT1.t0.W
ok(func() { clear(Field(v, 4)) }) // .NamedT2
ok(func() { clear(Field(Field(v, 4), 0)) }) // .NamedT2.Z
bad(func() { clear(Field(Field(v, 4), 1)) }) // .NamedT2.namedT0
bad(func() { clear(Field(Field(Field(v, 4), 1), 0)) }) // .NamedT2.namedT0.W
bad(func() { clear(Field(v, 5)) }) // .namedT1
bad(func() { clear(Field(Field(v, 5), 0)) }) // .namedT1.Y
bad(func() { clear(Field(Field(v, 5), 1)) }) // .namedT1.t0
bad(func() { clear(Field(Field(Field(v, 5), 1), 0)) }) // .namedT1.t0.W
bad(func() { clear(Field(v, 6)) }) // .namedT2
bad(func() { clear(Field(Field(v, 6), 0)) }) // .namedT2.Z
bad(func() { clear(Field(Field(v, 6), 1)) }) // .namedT2.namedT0
bad(func() { clear(Field(Field(Field(v, 6), 1), 0)) }) // .namedT2.namedT0.W
}
func shouldPanic(f func()) {
defer func() {
if recover() == nil {
panic("did not panic")
}
}()
f()
}
type S struct {
i1 int64
i2 int64
}
func TestBigZero(t *testing.T) {
const size = 1 << 10
var v [size]byte
z := ToInterface(Zero(ValueOf(v).Type())).([size]byte)
for i := 0; i < size; i++ {
if z[i] != 0 {
t.Fatalf("Zero object not all zero, index %d", i)
}
}
}
func TestInvalid(t *testing.T) {
// Used to have inconsistency between IsValid() and Kind() != Invalid.
type T struct{ v any }
v := Field(ValueOf(T{}), 0)
if v.IsValid() != true || v.Kind() != Interface {
t.Errorf("field: IsValid=%v, Kind=%v, want true, Interface", v.IsValid(), v.Kind())
}
v = v.Elem()
if v.IsValid() != false || v.Kind() != Invalid {
t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind())
}
}
type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int
type nameTest struct {
v any
want string
}
type A struct{}
type B[T any] struct{}
var nameTests = []nameTest{
{(*int32)(nil), "int32"},
{(*D1)(nil), "D1"},
{(*[]D1)(nil), ""},
{(*chan D1)(nil), ""},
{(*func() D1)(nil), ""},
{(*<-chan D1)(nil), ""},
{(*chan<- D1)(nil), ""},
{(*any)(nil), ""},
{(*interface {
F()
})(nil), ""},
{(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"},
{(*B[A])(nil), "B[internal/reflectlite_test.A]"},
{(*B[B[A]])(nil), "B[internal/reflectlite_test.B[internal/reflectlite_test.A]]"},
}
func TestNames(t *testing.T) {
for _, test := range nameTests {
typ := TypeOf(test.v).Elem()
if got := typ.Name(); got != test.want {
t.Errorf("%v Name()=%q, want %q", typ, got, test.want)
}
}
}
// TestUnaddressableField tests that the reflect package will not allow
// a type from another package to be used as a named type with an
// unexported field.
//
// This ensures that unexported fields cannot be modified by other packages.
func TestUnaddressableField(t *testing.T) {
var b Buffer // type defined in reflect, a different package
var localBuffer struct {
buf []byte
}
lv := ValueOf(&localBuffer).Elem()
rv := ValueOf(b)
shouldPanic(func() {
lv.Set(rv)
})
}
type Tint int
type Tint2 = Tint
type Talias1 struct {
byte
uint8
int
int32
rune
}
type Talias2 struct {
Tint
Tint2
}
func TestAliasNames(t *testing.T) {
t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
out := fmt.Sprintf("%#v", t1)
want := "reflectlite_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
if out != want {
t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
}
t2 := Talias2{Tint: 1, Tint2: 2}
out = fmt.Sprintf("%#v", t2)
want = "reflectlite_test.Talias2{Tint:1, Tint2:2}"
if out != want {
t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
}
}