summaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2016-07-22 18:15:38 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2016-07-22 18:15:38 +0000
commit22b955cca564a9a3a5b8c9d9dd1e295b7943c128 (patch)
treeabdbd898676e1f853fca2d7e031d105d7ebcf676 /libgo/go/reflect
parent9d04a3af4c6491536badf6bde9707c907e4d196b (diff)
libgo: update to go1.7rc3
Reviewed-on: https://go-review.googlesource.com/25150 From-SVN: r238662
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/all_test.go908
-rw-r--r--libgo/go/reflect/deepequal.go2
-rw-r--r--libgo/go/reflect/example_test.go30
-rw-r--r--libgo/go/reflect/export_test.go44
-rw-r--r--libgo/go/reflect/makefunc.go2
-rw-r--r--libgo/go/reflect/set_test.go4
-rw-r--r--libgo/go/reflect/type.go331
-rw-r--r--libgo/go/reflect/value.go67
8 files changed, 1244 insertions, 144 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index b8e7cd883cb..7045e448ea3 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -21,6 +21,8 @@ import (
"sync"
"testing"
"time"
+ "unicode"
+ "unicode/utf8"
"unsafe"
)
@@ -44,16 +46,12 @@ type pair struct {
s string
}
-func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
-
func assert(t *testing.T, s, want string) {
if s != want {
t.Errorf("have %#q want %#q", s, want)
}
}
-func typestring(i interface{}) string { return TypeOf(i).String() }
-
var typeTests = []pair{
{struct{ x int }{}, "int"},
{struct{ x int8 }{}, "int8"},
@@ -1891,32 +1889,6 @@ type Tbigp [2]uintptr
func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
-// Again, with an unexported method.
-
-type tsmallv byte
-
-func (v tsmallv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type tsmallp byte
-
-func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type twordv uintptr
-
-func (v twordv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type twordp uintptr
-
-func (p *twordp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type tbigv [2]uintptr
-
-func (v tbigv) m(x int, b byte) (byte, int) { return b, x + int(v[0]) + int(v[1]) }
-
-type tbigp [2]uintptr
-
-func (p *tbigp) m(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
-
type tinter interface {
m(int, byte) (byte, int)
}
@@ -1960,7 +1932,6 @@ func TestMethod5(t *testing.T) {
}
var TinterType = TypeOf(new(Tinter)).Elem()
- var tinterType = TypeOf(new(tinter)).Elem()
CheckI := func(name string, i interface{}, inc int) {
v := ValueOf(i)
@@ -2002,39 +1973,6 @@ func TestMethod5(t *testing.T) {
CheckI("t1", t1, 40)
CheckI("&t1", &t1, 40)
- methodShouldPanic := func(name string, i interface{}) {
- v := ValueOf(i)
- m := v.Method(0)
- shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
- shouldPanic(func() { m.Interface() })
-
- v = v.Convert(tinterType)
- m = v.Method(0)
- shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
- shouldPanic(func() { m.Interface() })
- }
-
- _sv := tsmallv(1)
- methodShouldPanic("_sv", _sv)
- methodShouldPanic("&_sv", &_sv)
-
- _sp := tsmallp(2)
- methodShouldPanic("&_sp", &_sp)
-
- _wv := twordv(3)
- methodShouldPanic("_wv", _wv)
- methodShouldPanic("&_wv", &_wv)
-
- _wp := twordp(4)
- methodShouldPanic("&_wp", &_wp)
-
- _bv := tbigv([2]uintptr{5, 6})
- methodShouldPanic("_bv", _bv)
- methodShouldPanic("&_bv", &_bv)
-
- _bp := tbigp([2]uintptr{7, 8})
- methodShouldPanic("&_bp", &_bp)
-
var tnil Tinter
vnil := ValueOf(&tnil).Elem()
shouldPanic(func() { vnil.Method(0) })
@@ -2323,6 +2261,8 @@ func TestImportPath(t *testing.T) {
{TypeOf((*int64)(nil)), ""},
{TypeOf(map[string]int{}), ""},
{TypeOf((*error)(nil)).Elem(), ""},
+ {TypeOf((*Point)(nil)), ""},
+ {TypeOf((*Point)(nil)).Elem(), "reflect_test"},
}
for _, test := range tests {
if path := test.t.PkgPath(); path != test.path {
@@ -2331,6 +2271,33 @@ func TestImportPath(t *testing.T) {
}
}
+func TestFieldPkgPath(t *testing.T) {
+ typ := TypeOf(struct {
+ Exported string
+ unexported string
+ OtherPkgFields
+ }{})
+ for _, test := range []struct {
+ index []int
+ pkgPath string
+ anonymous bool
+ }{
+ {[]int{0}, "", false}, // Exported
+ {[]int{1}, "reflect_test", false}, // unexported
+ {[]int{2}, "", true}, // OtherPkgFields
+ {[]int{2, 0}, "", false}, // OtherExported
+ {[]int{2, 1}, "reflect", false}, // otherUnexported
+ } {
+ f := typ.FieldByIndex(test.index)
+ if got, want := f.PkgPath, test.pkgPath; got != want {
+ t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want)
+ }
+ if got, want := f.Anonymous, test.anonymous; got != want {
+ t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want)
+ }
+ }
+}
+
func TestVariadicType(t *testing.T) {
// Test example from Type documentation.
var f func(x int, y ...float64)
@@ -2363,14 +2330,14 @@ type outer struct {
inner
}
-func (*inner) m() {}
-func (*outer) m() {}
+func (*inner) M() {}
+func (*outer) M() {}
func TestNestedMethods(t *testing.T) {
t.Skip("fails on gccgo due to function wrappers")
typ := TypeOf((*outer)(nil))
- if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
- t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+ 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())
@@ -2378,6 +2345,25 @@ func TestNestedMethods(t *testing.T) {
}
}
+type unexp struct{}
+
+func (*unexp) f() (int32, int8) { return 7, 7 }
+func (*unexp) g() (int64, int8) { return 8, 8 }
+
+type unexpI interface {
+ f() (int32, int8)
+}
+
+var unexpi unexpI = new(unexp)
+
+func TestUnexportedMethods(t *testing.T) {
+ typ := TypeOf(unexpi)
+
+ if got := typ.NumMethod(); got != 0 {
+ t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
+ }
+}
+
type InnerInt struct {
X int
}
@@ -2419,6 +2405,17 @@ func TestEmbeddedMethods(t *testing.T) {
}
}
+type FuncDDD func(...interface{}) error
+
+func (f FuncDDD) M() {}
+
+func TestNumMethodOnDDD(t *testing.T) {
+ rv := ValueOf((FuncDDD)(nil))
+ if n := rv.NumMethod(); n != 1 {
+ t.Fatalf("NumMethod()=%d, want 1", n)
+ }
+}
+
func TestPtrTo(t *testing.T) {
var i int
@@ -2861,12 +2858,11 @@ func TestUnexported(t *testing.T) {
isValid(v.Elem().Field(1))
isValid(v.Elem().FieldByName("x"))
isValid(v.Elem().FieldByName("y"))
- isValid(v.Type().Method(0).Func)
shouldPanic(func() { v.Elem().Field(0).Interface() })
shouldPanic(func() { v.Elem().Field(1).Interface() })
shouldPanic(func() { v.Elem().FieldByName("x").Interface() })
shouldPanic(func() { v.Elem().FieldByName("y").Interface() })
- shouldPanic(func() { v.Type().Method(0).Func.Interface() })
+ shouldPanic(func() { v.Type().Method(0) })
}
func TestSetPanic(t *testing.T) {
@@ -3846,6 +3842,9 @@ func TestSliceOf(t *testing.T) {
// check construction and use of type not in binary
type T int
st := SliceOf(TypeOf(T(1)))
+ if got, want := st.String(), "[]reflect_test.T"; got != want {
+ t.Errorf("SliceOf(T(1)).String()=%q, want %q", got, want)
+ }
v := MakeSlice(st, 10, 10)
runtime.GC()
for i := 0; i < v.Len(); i++ {
@@ -3910,6 +3909,591 @@ func TestSliceOfGC(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{}),
+ },
+ }
+
+ st := StructOf(fields)
+ v := New(st).Elem()
+ runtime.GC()
+ v.FieldByName("X").Set(ValueOf(byte(2)))
+ v.FieldByIndex([]int{1}).Set(ValueOf(byte(1)))
+ runtime.GC()
+
+ s := fmt.Sprint(v.Interface())
+ want := `{ 1 0 [0 0 0]}`
+ if s != want {
+ t.Errorf("constructed struct = %s, want %s", s, want)
+ }
+ const stStr = `struct { S string "s"; X uint8 "x"; Y uint64; Z [3]uint16 }`
+ if got, want := st.String(), stStr; got != want {
+ t.Errorf("StructOf(fields).String()=%q, want %q", got, want)
+ }
+
+ // check the size, alignment and field offsets
+ stt := TypeOf(struct {
+ String string
+ X byte
+ Y uint64
+ Z [3]uint16
+ }{})
+ if st.Size() != stt.Size() {
+ t.Errorf("constructed struct size = %v, want %v", st.Size(), stt.Size())
+ }
+ if st.Align() != stt.Align() {
+ t.Errorf("constructed struct align = %v, want %v", st.Align(), stt.Align())
+ }
+ if st.FieldAlign() != stt.FieldAlign() {
+ t.Errorf("constructed struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+ }
+ for i := 0; i < st.NumField(); i++ {
+ o1 := st.Field(i).Offset
+ o2 := stt.Field(i).Offset
+ if o1 != o2 {
+ t.Errorf("constructed struct field %v offset = %v, want %v", i, o1, o2)
+ }
+ }
+
+ // check duplicate names
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Name: "string", Type: TypeOf("")},
+ StructField{Name: "string", Type: TypeOf("")},
+ })
+ })
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Type: TypeOf("")},
+ StructField{Name: "string", Type: TypeOf("")},
+ })
+ })
+ shouldPanic(func() {
+ StructOf([]StructField{
+ StructField{Type: TypeOf("")},
+ StructField{Type: TypeOf("")},
+ })
+ })
+ // check that type already in binary is found
+ checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{})
+}
+
+func TestStructOfExportRules(t *testing.T) {
+ type S1 struct{}
+ type s2 struct{}
+ type ΦType struct{}
+ type φType struct{}
+
+ testPanic := func(i int, mustPanic bool, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil && mustPanic {
+ t.Errorf("test-%d did not panic", i)
+ }
+ if err != nil && !mustPanic {
+ t.Errorf("test-%d panicked: %v\n", i, err)
+ }
+ }()
+ f()
+ }
+
+ for i, test := range []struct {
+ field StructField
+ mustPanic bool
+ exported bool
+ }{
+ {
+ field: StructField{Name: "", Type: TypeOf(S1{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*S1)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(s2{})},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*s2)(nil))},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf(S1{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf(s2{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(S1{})},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*S1)(nil))},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(s2{})},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*s2)(nil))},
+ mustPanic: true,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+ mustPanic: true, // TODO(sbinet): creating a name with a package path
+ exported: false,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(ΦType{})},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "", Type: TypeOf(φType{})},
+ mustPanic: false,
+ exported: false,
+ },
+ {
+ field: StructField{Name: "Φ", Type: TypeOf(0)},
+ mustPanic: false,
+ exported: true,
+ },
+ {
+ field: StructField{Name: "φ", Type: TypeOf(0)},
+ mustPanic: false,
+ exported: false,
+ },
+ } {
+ testPanic(i, test.mustPanic, func() {
+ typ := StructOf([]StructField{test.field})
+ if typ == nil {
+ t.Errorf("test-%d: error creating struct type", i)
+ return
+ }
+ field := typ.Field(0)
+ n := field.Name
+ if n == "" {
+ n = field.Type.Name()
+ }
+ exported := isExported(n)
+ if exported != test.exported {
+ t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported)
+ }
+ })
+ }
+}
+
+// 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))
+ fields := []StructField{
+ {Name: "X", Type: tt},
+ {Name: "Y", Type: tt},
+ }
+ st := StructOf(fields)
+
+ const n = 10000
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := New(st).Elem()
+ for j := 0; j < v.NumField(); j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.Field(j).Set(ValueOf(p).Convert(tt))
+ }
+ x = append(x, v.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ v := ValueOf(xi)
+ for j := 0; j < v.NumField(); j++ {
+ k := v.Field(j).Elem().Interface()
+ if k != uintptr(i*n+j) {
+ t.Errorf("lost x[%d].%c = %d, want %d", i, "XY"[j], k, i*n+j)
+ }
+ }
+ }
+}
+
+func TestStructOfAlg(t *testing.T) {
+ st := StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf(int(0))}})
+ v1 := New(st).Elem()
+ v2 := New(st).Elem()
+ if !DeepEqual(v1.Interface(), v1.Interface()) {
+ t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+ }
+ v1.FieldByName("X").Set(ValueOf(int(1)))
+ if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+ }
+
+ st = StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf([]int(nil))}})
+ v1 = New(st).Elem()
+ shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
+}
+
+func TestStructOfGenericAlg(t *testing.T) {
+ st1 := StructOf([]StructField{
+ {Name: "X", Tag: "x", Type: TypeOf(int64(0))},
+ {Name: "Y", Type: TypeOf(string(""))},
+ })
+ st := StructOf([]StructField{
+ {Name: "S0", Type: st1},
+ {Name: "S1", Type: st1},
+ })
+
+ for _, table := range []struct {
+ rt Type
+ idx []int
+ }{
+ {
+ rt: st,
+ idx: []int{0, 1},
+ },
+ {
+ rt: st1,
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([0]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([0]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([2]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([1]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([1]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([1]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf([2]int{})},
+ {Name: "YY", Type: TypeOf("")},
+ {Name: "ZZ", Type: TypeOf([2]int{})},
+ },
+ ),
+ idx: []int{1},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf(int64(0))},
+ {Name: "YY", Type: TypeOf(byte(0))},
+ {Name: "ZZ", Type: TypeOf("")},
+ },
+ ),
+ idx: []int{2},
+ },
+ {
+ rt: StructOf(
+ []StructField{
+ {Name: "XX", Type: TypeOf(int64(0))},
+ {Name: "YY", Type: TypeOf(int64(0))},
+ {Name: "ZZ", Type: TypeOf("")},
+ {Name: "AA", Type: TypeOf([1]int64{})},
+ },
+ ),
+ idx: []int{2},
+ },
+ } {
+ v1 := New(table.rt).Elem()
+ v2 := New(table.rt).Elem()
+
+ if !DeepEqual(v1.Interface(), v1.Interface()) {
+ t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+ }
+
+ v1.FieldByIndex(table.idx).Set(ValueOf("abc"))
+ v2.FieldByIndex(table.idx).Set(ValueOf("def"))
+ if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+ }
+
+ abc := "abc"
+ v1.FieldByIndex(table.idx).Set(ValueOf(abc))
+ val := "+" + abc + "-"
+ v2.FieldByIndex(table.idx).Set(ValueOf(val[1:4]))
+ if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+ }
+
+ // Test hash
+ m := MakeMap(MapOf(table.rt, TypeOf(int(0))))
+ m.SetMapIndex(v1, ValueOf(1))
+ if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+ t.Errorf("constructed structs %#v and %#v have different hashes", i1, i2)
+ }
+
+ v2.FieldByIndex(table.idx).Set(ValueOf("abc"))
+ if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+ t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+ }
+
+ if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+ t.Errorf("constructed structs %v and %v have different hashes", i1, i2)
+ }
+ }
+}
+
+/*
+gccgo does not use the same directiface settings as gc.
+
+func TestStructOfDirectIface(t *testing.T) {
+ {
+ type T struct{ X [1]*byte }
+ i1 := Zero(TypeOf(T{})).Interface()
+ v1 := ValueOf(&i1).Elem()
+ p1 := v1.InterfaceData()[1]
+
+ i2 := Zero(StructOf([]StructField{
+ {
+ Name: "X",
+ Type: ArrayOf(1, TypeOf((*int8)(nil))),
+ },
+ })).Interface()
+ v2 := ValueOf(&i2).Elem()
+ p2 := v2.InterfaceData()[1]
+
+ if p1 != 0 {
+ t.Errorf("got p1=%v. want=%v", p1, nil)
+ }
+
+ if p2 != 0 {
+ t.Errorf("got p2=%v. want=%v", p2, nil)
+ }
+ }
+ {
+ type T struct{ X [0]*byte }
+ i1 := Zero(TypeOf(T{})).Interface()
+ v1 := ValueOf(&i1).Elem()
+ p1 := v1.InterfaceData()[1]
+
+ i2 := Zero(StructOf([]StructField{
+ {
+ Name: "X",
+ Type: ArrayOf(0, TypeOf((*int8)(nil))),
+ },
+ })).Interface()
+ v2 := ValueOf(&i2).Elem()
+ p2 := v2.InterfaceData()[1]
+
+ if p1 == 0 {
+ t.Errorf("got p1=%v. want=not-%v", p1, nil)
+ }
+
+ if p2 == 0 {
+ t.Errorf("got p2=%v. want=not-%v", p2, nil)
+ }
+ }
+}
+*/
+
+type StructI int
+
+func (i StructI) Get() int { return int(i) }
+
+type StructIPtr int
+
+func (i *StructIPtr) Get() int { return int(*i) }
+
+/*
+gccgo does not yet support StructOf with methods.
+
+func TestStructOfWithInterface(t *testing.T) {
+ const want = 42
+ type Iface interface {
+ Get() int
+ }
+ for i, table := range []struct {
+ typ Type
+ val Value
+ impl bool
+ }{
+ {
+ typ: TypeOf(StructI(want)),
+ val: ValueOf(StructI(want)),
+ impl: true,
+ },
+ {
+ typ: PtrTo(TypeOf(StructI(want))),
+ val: ValueOf(func() interface{} {
+ v := StructI(want)
+ return &v
+ }()),
+ impl: true,
+ },
+ {
+ typ: PtrTo(TypeOf(StructIPtr(want))),
+ val: ValueOf(func() interface{} {
+ v := StructIPtr(want)
+ return &v
+ }()),
+ impl: true,
+ },
+ {
+ typ: TypeOf(StructIPtr(want)),
+ val: ValueOf(StructIPtr(want)),
+ impl: false,
+ },
+ // {
+ // typ: TypeOf((*Iface)(nil)).Elem(), // FIXME(sbinet): fix method.ifn/tfn
+ // val: ValueOf(StructI(want)),
+ // impl: true,
+ // },
+ } {
+ rt := StructOf(
+ []StructField{
+ {
+ Name: "",
+ PkgPath: "",
+ Type: table.typ,
+ },
+ },
+ )
+ rv := New(rt).Elem()
+ rv.Field(0).Set(table.val)
+
+ if _, ok := rv.Interface().(Iface); ok != table.impl {
+ if table.impl {
+ t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ)
+ } else {
+ t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ)
+ }
+ continue
+ }
+
+ if !table.impl {
+ continue
+ }
+
+ v := rv.Interface().(Iface).Get()
+ if v != want {
+ t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, v, want)
+ }
+
+ fct := rv.MethodByName("Get")
+ out := fct.Call(nil)
+ if !DeepEqual(out[0].Interface(), want) {
+ t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, out[0].Interface(), want)
+ }
+ }
+}
+*/
+
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
@@ -4116,7 +4700,7 @@ func TestFuncOf(t *testing.T) {
if len(args) != 1 {
t.Errorf("args == %v, want exactly one arg", args)
} else if args[0].Type() != TypeOf(K("")) {
- t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K("")))
+ t.Errorf("args[0] is type %v, want %v", args[0].Type(), TypeOf(K("")))
} else if args[0].String() != "gopher" {
t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher")
}
@@ -4128,7 +4712,7 @@ func TestFuncOf(t *testing.T) {
if len(outs) != 1 {
t.Fatalf("v.Call returned %v, want exactly one result", outs)
} else if outs[0].Type() != TypeOf(V(0)) {
- t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0)))
+ t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type(), TypeOf(V(0)))
}
f := outs[0].Float()
if f != 3.14 {
@@ -4479,7 +5063,7 @@ func TestFieldByIndexNil(t *testing.T) {
// off the stack into the frame will store an *Inner there, and then if a garbage collection
// happens to scan that argument frame before it is discarded, it will scan the *Inner
// memory as if it were an *Outer. If the two have different memory layouts, the
-// collection will intepret the memory incorrectly.
+// collection will interpret the memory incorrectly.
//
// One such possible incorrect interpretation is to treat two arbitrary memory words
// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
@@ -4555,7 +5139,7 @@ func useStack(n int) {
type Impl struct{}
-func (Impl) f() {}
+func (Impl) F() {}
func TestValueString(t *testing.T) {
rv := ValueOf(Impl{})
@@ -4589,6 +5173,41 @@ func TestLargeGCProg(t *testing.T) {
fv.Call([]Value{ValueOf([256]*byte{})})
}
+func fieldIndexRecover(t Type, i int) (recovered interface{}) {
+ defer func() {
+ recovered = recover()
+ }()
+
+ t.Field(i)
+ return
+}
+
+// Issue 15046.
+func TestTypeFieldOutOfRangePanic(t *testing.T) {
+ typ := TypeOf(struct{ X int }{10})
+ testIndices := [...]struct {
+ i int
+ mustPanic bool
+ }{
+ 0: {-2, true},
+ 1: {0, false},
+ 2: {1, true},
+ 3: {1 << 10, true},
+ }
+ for i, tt := range testIndices {
+ recoveredErr := fieldIndexRecover(typ, tt.i)
+ if tt.mustPanic {
+ if recoveredErr == nil {
+ t.Errorf("#%d: fieldIndex %d expected to panic", i, tt.i)
+ }
+ } else {
+ if recoveredErr != nil {
+ t.Errorf("#%d: got err=%v, expected no panic", i, recoveredErr)
+ }
+ }
+ }
+}
+
// Issue 9179.
func TestCallGC(t *testing.T) {
f := func(a, b, c, d, e string) {
@@ -4716,7 +5335,7 @@ func init() {
2 * PtrSize,
[]byte{1},
[]byte{1},
- // Note: this one is tricky, as the receiver is not a pointer. But we
+ // Note: this one is tricky, as the receiver is not a pointer. But we
// pass the receiver by reference to the autogenerated pointer-receiver
// version of the function.
})
@@ -4768,6 +5387,9 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
for len(bits) > 2 && bits[len(bits)-1] == 0 {
bits = bits[:len(bits)-1]
}
+ if len(bits) == 2 && bits[0] == 0 && bits[1] == 0 {
+ bits = bits[:0]
+ }
if !bytes.Equal(heapBits, bits) {
t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
}
@@ -5027,6 +5649,140 @@ func TestChanAlloc(t *testing.T) {
t.Errorf("allocs per chan send/recv: want 1 got %f", allocs)
}
// Note: there is one allocation in reflect.recv which seems to be
- // a limitation of escape analysis. If that is ever fixed the
+ // a limitation of escape analysis. If that is ever fixed the
// allocs < 0.5 condition will trigger and this test should be fixed.
}
+
+type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int
+
+type nameTest struct {
+ v interface{}
+ want string
+}
+
+var nameTests = []nameTest{
+ {(*int32)(nil), "int32"},
+ {(*D1)(nil), "D1"},
+ {(*[]D1)(nil), ""},
+ {(*chan D1)(nil), ""},
+ {(*func() D1)(nil), ""},
+ {(*<-chan D1)(nil), ""},
+ {(*chan<- D1)(nil), ""},
+ {(*interface{})(nil), ""},
+ {(*interface {
+ F()
+ })(nil), ""},
+ {(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"},
+}
+
+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)
+ }
+ }
+}
+
+/*
+gccgo doesn't really record whether a type is exported.
+It's not in the reflect API anyhow.
+
+func TestExported(t *testing.T) {
+ type ΦExported struct{}
+ type φUnexported struct{}
+ type BigP *big
+ type P int
+ type p *P
+ type P2 p
+ type p3 p
+
+ type exportTest struct {
+ v interface{}
+ want bool
+ }
+ exportTests := []exportTest{
+ {D1{}, true},
+ {(*D1)(nil), true},
+ {big{}, false},
+ {(*big)(nil), false},
+ {(BigP)(nil), true},
+ {(*BigP)(nil), true},
+ {ΦExported{}, true},
+ {φUnexported{}, false},
+ {P(0), true},
+ {(p)(nil), false},
+ {(P2)(nil), true},
+ {(p3)(nil), false},
+ }
+
+ for i, test := range exportTests {
+ typ := TypeOf(test.v)
+ if got := IsExported(typ); got != test.want {
+ t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want)
+ }
+ }
+}
+*/
+
+type embed struct {
+ EmbedWithUnexpMeth
+}
+
+/*
+func TestNameBytesAreAligned(t *testing.T) {
+ typ := TypeOf(embed{})
+ b := FirstMethodNameBytes(typ)
+ v := uintptr(unsafe.Pointer(b))
+ if v%unsafe.Alignof((*byte)(nil)) != 0 {
+ t.Errorf("reflect.name.bytes pointer is not aligned: %x", v)
+ }
+}
+*/
+
+func TestTypeStrings(t *testing.T) {
+ type stringTest struct {
+ typ Type
+ want string
+ }
+ stringTests := []stringTest{
+ {TypeOf(func(int) {}), "func(int)"},
+ {FuncOf([]Type{TypeOf(int(0))}, nil, false), "func(int)"},
+ {TypeOf(XM{}), "reflect_test.XM"},
+ {TypeOf(new(XM)), "*reflect_test.XM"},
+ {TypeOf(new(XM).String), "func() string"},
+ {TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"},
+ }
+
+ for i, test := range stringTests {
+ if got, want := test.typ.String(), test.want; got != want {
+ t.Errorf("type %d String()=%q, want %q", i, got, want)
+ }
+ }
+}
+
+/*
+gccgo does not have resolveReflectName.
+
+func TestOffsetLock(t *testing.T) {
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ i := i
+ wg.Add(1)
+ go func() {
+ for j := 0; j < 50; j++ {
+ ResolveReflectName(fmt.Sprintf("OffsetLockName:%d:%d", i, j))
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+*/
+
+func BenchmarkNew(b *testing.B) {
+ v := TypeOf(XM{})
+ for i := 0; i < b.N; i++ {
+ New(v)
+ }
+}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index 3743e8042d3..9770358ae77 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -9,7 +9,7 @@ package reflect
import "unsafe"
// During deepValueEqual, must keep track of checks that are
-// in progress. The comparison algorithm assumes that all
+// in progress. The comparison algorithm assumes that all
// checks in progress are true when it reencounters them.
// Visited comparisons are stored in a map indexed by visit.
type visit struct {
diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go
index 8ebf9765b8d..9e2b9b3e972 100644
--- a/libgo/go/reflect/example_test.go
+++ b/libgo/go/reflect/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
@@ -67,6 +67,34 @@ func ExampleStructTag() {
// blue gopher
}
+func ExampleStructTag_Lookup() {
+ type S struct {
+ F0 string `alias:"field_0"`
+ F1 string `alias:""`
+ F2 string
+ }
+
+ s := S{}
+ st := reflect.TypeOf(s)
+ for i := 0; i < st.NumField(); i++ {
+ field := st.Field(i)
+ if alias, ok := field.Tag.Lookup("alias"); ok {
+ if alias == "" {
+ fmt.Println("(blank)")
+ } else {
+ fmt.Println(alias)
+ }
+ } else {
+ fmt.Println("(not specified)")
+ }
+ }
+
+ // Output:
+ // field_0
+ // (blank)
+ // (not specified)
+}
+
func ExampleTypeOf() {
// As interface types are only used for static typing, a
// common idiom to find the reflection Type for an interface
diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go
index bdbd60074ac..a06e8d0a944 100644
--- a/libgo/go/reflect/export_test.go
+++ b/libgo/go/reflect/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
@@ -41,3 +41,45 @@ func MapBucketOf(x, y Type) Type {
func CachedBucketOf(m Type) Type {
return nil
}
+
+type EmbedWithUnexpMeth struct{}
+
+func (EmbedWithUnexpMeth) f() {}
+
+type pinUnexpMeth interface {
+ f()
+}
+
+var pinUnexpMethI = pinUnexpMeth(EmbedWithUnexpMeth{})
+
+/*
+func FirstMethodNameBytes(t Type) *byte {
+ _ = pinUnexpMethI
+
+ ut := t.uncommon()
+ if ut == nil {
+ panic("type has no methods")
+ }
+ m := ut.methods()[0]
+ mname := t.(*rtype).nameOff(m.name)
+ if *mname.data(0)&(1<<2) == 0 {
+ panic("method name does not have pkgPath *string")
+ }
+ return mname.bytes
+}
+*/
+
+type OtherPkgFields struct {
+ OtherExported int
+ otherUnexported int
+}
+
+func IsExported(t Type) bool {
+ return t.PkgPath() == ""
+}
+
+/*
+func ResolveReflectName(s string) {
+ resolveReflectName(newName(s, "", "", false))
+}
+*/
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 7ec277b864a..543a335d841 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/libgo/go/reflect/set_test.go b/libgo/go/reflect/set_test.go
index 85dc55e6812..bc35c78e1bb 100644
--- a/libgo/go/reflect/set_test.go
+++ b/libgo/go/reflect/set_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2011 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.
@@ -194,11 +194,13 @@ var assignableTests = []struct {
{new(*int), new(IntPtr), true},
{new(IntPtr), new(*int), true},
{new(IntPtr), new(IntPtr1), false},
+ {new(Ch), new(<-chan interface{}), true},
// test runs implementsTests too
}
type IntPtr *int
type IntPtr1 *int
+type Ch <-chan interface{}
func TestAssignableTo(t *testing.T) {
for _, tt := range append(assignableTests, implementsTests...) {
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 88da632584c..d89f15631ac 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package reflect implements run-time reflection, allowing a program to
-// manipulate objects with arbitrary types. The typical use is to take a value
+// manipulate objects with arbitrary types. The typical use is to take a value
// with static type interface{} and extract its dynamic type information by
// calling TypeOf, which returns a Type.
//
@@ -24,10 +24,10 @@ import (
// Type is the representation of a Go type.
//
-// Not all methods apply to all kinds of types. Restrictions,
+// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of type before
-// calling kind-specific methods. Calling a method
+// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
type Type interface {
// Methods applicable to all types.
@@ -80,7 +80,7 @@ type Type interface {
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
- // guaranteed to be unique among types. To test for equality,
+ // guaranteed to be unique among types. To test for equality,
// compare the Types directly.
String() string
@@ -124,7 +124,7 @@ type Type interface {
ChanDir() ChanDir
// IsVariadic reports whether a function type's final input parameter
- // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
+ // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
@@ -147,7 +147,7 @@ type Type interface {
Field(i int) StructField
// FieldByIndex returns the nested field corresponding
- // to the index sequence. It is equivalent to calling Field
+ // to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField
@@ -389,7 +389,7 @@ const (
type Method struct {
// Name is the method name.
// PkgPath is the package path that qualifies a lower case (unexported)
- // method name. It is empty for upper case (exported) method names.
+ // method name. It is empty for upper case (exported) method names.
// The combination of PkgPath and Name uniquely identifies a method
// in a method set.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
@@ -509,6 +509,21 @@ func (t *uncommonType) Method(i int) (m Method) {
if t == nil || i < 0 || i >= len(t.methods) {
panic("reflect: Method index out of range")
}
+ found := false
+ for mi := range t.methods {
+ if t.methods[mi].pkgPath == nil {
+ if i == 0 {
+ i = mi
+ found = true
+ break
+ }
+ i--
+ }
+ }
+ if !found {
+ panic("reflect: Method index out of range")
+ }
+
p := &t.methods[i]
if p.name != nil {
m.Name = *p.name
@@ -531,7 +546,13 @@ func (t *uncommonType) NumMethod() int {
if t == nil {
return 0
}
- return len(t.methods)
+ c := 0
+ for i := range t.methods {
+ if t.methods[i].pkgPath == nil {
+ c++
+ }
+ }
+ return c
}
func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
@@ -541,7 +562,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
var p *method
for i := range t.methods {
p = &t.methods[i]
- if p.name != nil && *p.name == name {
+ if p.pkgPath == nil && p.name != nil && *p.name == name {
return t.Method(i), true
}
}
@@ -758,7 +779,7 @@ type StructField struct {
// Name is the field name.
Name string
// PkgPath is the package path that qualifies a lower case (unexported)
- // field name. It is empty for upper case (exported) field names.
+ // field name. It is empty for upper case (exported) field names.
// See https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
@@ -782,8 +803,20 @@ type StructTag string
// Get returns the value associated with key in the tag string.
// If there is no such key in the tag, Get returns the empty string.
// If the tag does not have the conventional format, the value
-// returned by Get is unspecified.
+// returned by Get is unspecified. To determine whether a tag is
+// explicitly set to the empty string, use Lookup.
func (tag StructTag) Get(key string) string {
+ v, _ := tag.Lookup(key)
+ return v
+}
+
+// Lookup returns the value associated with key in the tag string.
+// If the key is present in the tag the value (which may be empty)
+// is returned. Otherwise the returned value will be the empty string.
+// The ok return value reports whether the value was explicitly set in
+// the tag string. If the tag does not have the conventional format,
+// the value returned by Lookup is unspecified.
+func (tag StructTag) Lookup(key string) (value string, ok bool) {
// When modifying this code, also update the validateStructTag code
// in golang.org/x/tools/cmd/vet/structtag.go.
@@ -831,16 +864,16 @@ func (tag StructTag) Get(key string) string {
if err != nil {
break
}
- return value
+ return value, true
}
}
- return ""
+ return "", false
}
// Field returns the i'th struct field.
func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
- return
+ panic("reflect: Field index out of bounds")
}
p := &t.fields[i]
f.Type = toType(p.typ)
@@ -863,12 +896,12 @@ func (t *structType) Field(i int) (f StructField) {
f.Offset = p.offset
// NOTE(rsc): This is the only allocation in the interface
- // presented by a reflect.Type. It would be nice to avoid,
+ // presented by a reflect.Type. It would be nice to avoid,
// at least in the common cases, but we need to make sure
// that misbehaving clients of reflect cannot affect other
- // uses of reflect. One possibility is CL 5371098, but we
+ // uses of reflect. One possibility is CL 5371098, but we
// postponed that ugliness until there is a demonstrated
- // need for the performance. This is issue 2320.
+ // need for the performance. This is issue 2320.
f.Index = []int{i}
return
}
@@ -1082,11 +1115,7 @@ func (t *rtype) ptrTo() *rtype {
return p
}
- // Otherwise, synthesize one.
- // This only happens for pointers with no methods.
- // We keep the mapping in a map on the side, because
- // this operation is rare and a separate map lets us keep
- // the type structures in read-only memory.
+ // Check the cache.
ptrMap.RLock()
if m := ptrMap.m; m != nil {
if p := m[t]; p != nil {
@@ -1095,6 +1124,7 @@ func (t *rtype) ptrTo() *rtype {
}
}
ptrMap.RUnlock()
+
ptrMap.Lock()
if ptrMap.m == nil {
ptrMap.m = make(map[*rtype]*ptrType)
@@ -1762,7 +1792,7 @@ func needKeyUpdate(t *rtype) bool {
// Make sure these routines stay in sync with ../../runtime/hashmap.go!
// These types exist only for GC, so we only fill out GC relevant info.
-// Currently, that's just size and the GC program. We also fill in string
+// Currently, that's just size and the GC program. We also fill in string
// for possible debugging use.
const (
bucketSize uintptr = 8
@@ -1866,7 +1896,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
}
// Take the GC program for "t" and append it to the GC program "gc".
-func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
+func appendGCProgram(gc []uintptr, t *rtype, offset uintptr) []uintptr {
p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
@@ -1888,7 +1918,11 @@ loop:
panic("unknown GC program op for " + *t.string + ": " + strconv.FormatUint(*(*uint64)(p), 10))
}
for i := 0; i < argcnt+1; i++ {
- gc = append(gc, *(*uintptr)(p))
+ v := *(*uintptr)(p)
+ if i == 1 {
+ v += offset
+ }
+ gc = append(gc, v)
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0)))
}
}
@@ -1997,8 +2031,247 @@ func SliceOf(t Type) Type {
return cachePut(ckey, &slice.rtype)
}
-// See cmd/compile/internal/gc/reflect.go for derivation of constant.
-const maxPtrmaskBytes = 2048
+// The structLookupCache caches StructOf lookups.
+// StructOf does not share the common lookupCache since we need to pin
+// the memory associated with *structTypeFixedN.
+var structLookupCache struct {
+ sync.RWMutex
+ m map[uint32][]interface {
+ common() *rtype
+ } // keyed by hash calculated in StructOf
+}
+
+// StructOf returns the struct type containing fields.
+// The Offset and Index fields are ignored and computed as they would be
+// by the compiler.
+//
+// StructOf currently does not generate wrapper methods for embedded fields.
+// This limitation may be lifted in a future version.
+func StructOf(fields []StructField) Type {
+ var (
+ hash = uint32(0)
+ size uintptr
+ typalign int8
+
+ fs = make([]structField, len(fields))
+ repr = make([]byte, 0, 64)
+ fset = map[string]struct{}{} // fields' names
+
+ hasPtr = false // records whether at least one struct-field is a pointer
+ )
+
+ repr = append(repr, "struct {"...)
+ for i, field := range fields {
+ if field.Type == nil {
+ panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
+ }
+ f := runtimeStructField(field)
+ ft := f.typ
+ if ft.pointers() {
+ hasPtr = true
+ }
+
+ name := ""
+ // Update string and hash
+ hash = (hash << 1) + ft.hash
+ if f.name != nil {
+ name = *f.name
+ repr = append(repr, (" " + name)...)
+ } else {
+ // Embedded field
+ repr = append(repr, " ?"...)
+ if f.typ.Kind() == Ptr {
+ // Embedded ** and *interface{} are illegal
+ elem := ft.Elem()
+ if k := elem.Kind(); k == Ptr || k == Interface {
+ panic("reflect.StructOf: illegal anonymous field type " + ft.String())
+ }
+ name = elem.String()
+ } else {
+ name = ft.String()
+ }
+ // TODO(sbinet) check for syntactically impossible type names?
+
+ switch f.typ.Kind() {
+ case Interface:
+ ift := (*interfaceType)(unsafe.Pointer(ft))
+ if len(ift.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ case Ptr:
+ ptr := (*ptrType)(unsafe.Pointer(ft))
+ if unt := ptr.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ if unt := ptr.elem.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ default:
+ if unt := ft.uncommon(); unt != nil {
+ if len(unt.methods) > 0 {
+ panic("reflect.StructOf: embedded field with methods not supported")
+ }
+ }
+ }
+ }
+ if _, dup := fset[name]; dup {
+ panic("reflect.StructOf: duplicate field " + name)
+ }
+ fset[name] = struct{}{}
+
+ repr = append(repr, (" " + ft.String())...)
+ if f.tag != nil {
+ repr = append(repr, (" " + strconv.Quote(*f.tag))...)
+ }
+ if i < len(fields)-1 {
+ repr = append(repr, ';')
+ }
+
+ f.offset = align(size, uintptr(ft.fieldAlign))
+ if int8(ft.fieldAlign) > typalign {
+ typalign = int8(ft.fieldAlign)
+ }
+ size = f.offset + ft.size
+
+ fs[i] = f
+ }
+
+ if len(fs) > 0 {
+ repr = append(repr, ' ')
+ }
+ repr = append(repr, '}')
+ hash <<= 2
+ str := string(repr)
+
+ // Round the size up to be a multiple of the alignment.
+ size = align(size, uintptr(typalign))
+
+ // Make the struct type.
+ var istruct interface{} = struct{}{}
+ prototype := *(**structType)(unsafe.Pointer(&istruct))
+ typ := new(structType)
+ *typ = *prototype
+ typ.fields = fs
+
+ // Look in cache
+ structLookupCache.RLock()
+ for _, st := range structLookupCache.m[hash] {
+ t := st.common()
+ if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ structLookupCache.RUnlock()
+ return t
+ }
+ }
+ structLookupCache.RUnlock()
+
+ // not in cache, lock and retry
+ structLookupCache.Lock()
+ defer structLookupCache.Unlock()
+ if structLookupCache.m == nil {
+ structLookupCache.m = make(map[uint32][]interface {
+ common() *rtype
+ })
+ }
+ for _, st := range structLookupCache.m[hash] {
+ t := st.common()
+ if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ return t
+ }
+ }
+
+ typ.string = &str
+ typ.hash = hash
+ typ.size = size
+ typ.align = typalign
+ typ.fieldAlign = uint8(typalign)
+ if !hasPtr {
+ typ.kind |= kindNoPointers
+ gc := [...]uintptr{size, _GC_END}
+ typ.gc = unsafe.Pointer(&gc[0])
+ } else {
+ typ.kind &^= kindNoPointers
+ gc := []uintptr{size}
+ for _, ft := range fs {
+ gc = appendGCProgram(gc, ft.typ, ft.offset)
+ }
+ gc = append(gc, _GC_END)
+ typ.gc = unsafe.Pointer(&gc[0])
+ }
+
+ typ.hashfn = func(p unsafe.Pointer, size uintptr) uintptr {
+ ret := uintptr(0)
+ for i, ft := range typ.fields {
+ if i > 0 {
+ ret *= 33
+ }
+ o := unsafe.Pointer(uintptr(p) + ft.offset)
+ ret += ft.typ.hashfn(o, ft.typ.size)
+ }
+ return ret
+ }
+
+ typ.equalfn = func(p, q unsafe.Pointer, size uintptr) bool {
+ for _, ft := range typ.fields {
+ pi := unsafe.Pointer(uintptr(p) + ft.offset)
+ qi := unsafe.Pointer(uintptr(q) + ft.offset)
+ if !ft.typ.equalfn(pi, qi, ft.typ.size) {
+ return false
+ }
+ }
+ return true
+ }
+
+ typ.kind &^= kindDirectIface
+ typ.uncommonType = nil
+ typ.ptrToThis = nil
+
+ structLookupCache.m[hash] = append(structLookupCache.m[hash], typ)
+ return &typ.rtype
+}
+
+func runtimeStructField(field StructField) structField {
+ var name *string
+ if field.Name == "" {
+ t := field.Type.(*rtype)
+ if t.Kind() == Ptr {
+ t = t.Elem().(*rtype)
+ }
+ } else if field.PkgPath == "" {
+ s := field.Name
+ name = &s
+ b0 := s[0]
+ if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
+ panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
+ }
+ }
+
+ var pkgPath *string
+ if field.PkgPath != "" {
+ s := field.PkgPath
+ pkgPath = &s
+ // This could work with gccgo but we panic to be
+ // compatible with gc.
+ panic("reflect: creating a name with a package path is not supported")
+ }
+
+ var tag *string
+ if field.Tag != "" {
+ s := string(field.Tag)
+ tag = &s
+ }
+
+ return structField{
+ name: name,
+ pkgPath: pkgPath,
+ typ: field.Type.common(),
+ tag: tag,
+ offset: 0,
+ }
+}
// ArrayOf returns the array type with the given count and element type.
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
@@ -2037,6 +2310,7 @@ func ArrayOf(count int, elem Type) Type {
array.hash = typ.hash + 1 + 13
array.elem = typ
+ array.ptrToThis = nil
max := ^uintptr(0) / typ.size
if uintptr(count) > max {
panic("reflect.ArrayOf: array size would exceed virtual address space")
@@ -2048,7 +2322,6 @@ func ArrayOf(count int, elem Type) Type {
array.align = typ.align
array.fieldAlign = typ.fieldAlign
array.uncommonType = nil
- array.ptrToThis = nil
array.len = uintptr(count)
array.slice = slice.(*rtype)
@@ -2067,7 +2340,7 @@ func ArrayOf(count int, elem Type) Type {
default:
gc := []uintptr{array.size, _GC_ARRAY_START, 0, uintptr(count), typ.size}
- gc = appendGCProgram(gc, typ)
+ gc = appendGCProgram(gc, typ, 0)
gc = append(gc, _GC_ARRAY_NEXT, _GC_END)
array.gc = unsafe.Pointer(&gc[0])
}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 75944a6e532..1d1887693d3 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -11,14 +11,13 @@ import (
)
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
-const cannotSet = "cannot set value obtained from unexported struct field"
// Value is the reflection interface to a Go value.
//
-// Not all methods apply to all kinds of values. Restrictions,
+// Not all methods apply to all kinds of values. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of value before
-// calling kind-specific methods. Calling a method
+// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
//
// The zero Value represents no value.
@@ -57,7 +56,7 @@ type Value struct {
flag
// A method value represents a curried method invocation
- // like r.Read for some receiver r. The typ+val+flag bits describe
+ // like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
@@ -116,14 +115,14 @@ func packEface(v Value) interface{} {
}
e.word = ptr
case v.flag&flagIndir != 0:
- // Value is indirect, but interface is direct. We need
+ // Value is indirect, but interface is direct. We need
// to load the data at v.ptr into the interface data word.
e.word = *(*unsafe.Pointer)(v.ptr)
default:
// Value is direct, and so is the interface.
e.word = v.ptr
}
- // Now, fill in the type portion. We're very careful here not
+ // Now, fill in the type portion. We're very careful here not
// to have any operation between the e.word and e.typ assignments
// that would let the garbage collector observe the partially-built
// interface value.
@@ -147,7 +146,7 @@ func unpackEface(i interface{}) Value {
}
// A ValueError occurs when a Value method is invoked on
-// a Value that does not support it. Such cases are documented
+// a Value that does not support it. Such cases are documented
// in the description of each method.
type ValueError struct {
Method string
@@ -269,7 +268,7 @@ func (v Value) runes() []rune {
}
// CanAddr reports whether the value's address can be obtained with Addr.
-// Such values are called addressable. A value is addressable if it is
+// Such values are called addressable. A value is addressable if it is
// an element of a slice, an element of an addressable array,
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
@@ -500,7 +499,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
return
}
-// v is a method receiver. Store at p the word which is used to
+// v is a method receiver. Store at p the word which is used to
// encode that receiver at the start of the argument list.
// Reflect uses the "interface" calling convention for
// methods, which always uses one word to record the receiver.
@@ -541,7 +540,7 @@ func (v Value) Cap() int {
case Array:
return v.typ.Len()
case Chan:
- return int(chancap(v.pointer()))
+ return chancap(v.pointer())
case Slice:
// Slice is always bigger than a word; assume flagIndir.
return (*sliceHeader)(v.ptr).Cap
@@ -760,7 +759,7 @@ func (v Value) Int() int64 {
case Int32:
return int64(*(*int32)(p))
case Int64:
- return int64(*(*int64)(p))
+ return *(*int64)(p)
}
panic(&ValueError{"reflect.Value.Int", v.kind()})
}
@@ -909,9 +908,9 @@ func (v Value) MapIndex(key Value) Value {
// Do not require key to be exported, so that DeepEqual
// and other programs can use all the keys returned by
- // MapKeys as arguments to MapIndex. If either the map
+ // MapKeys as arguments to MapIndex. If either the map
// or the key is unexported, though, the result will be
- // considered unexported. This is consistent with the
+ // considered unexported. This is consistent with the
// behavior for structs, which allow read but not write
// of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
@@ -963,7 +962,7 @@ func (v Value) MapKeys() []Value {
key := mapiterkey(it)
if key == nil {
// Someone deleted an entry from the map since we
- // called maplen above. It's a data race, but nothing
+ // called maplen above. It's a data race, but nothing
// we can do about it.
break
}
@@ -1110,7 +1109,7 @@ func (v Value) OverflowUint(x uint64) bool {
// result is zero if and only if v is a nil func Value.
//
// If v's Kind is Slice, the returned pointer is to the first
-// element of the slice. If the slice is nil the returned value
+// element of the slice. If the slice is nil the returned value
// is 0. If the slice is empty but non-nil the return value is non-zero.
func (v Value) Pointer() uintptr {
// TODO: deprecate
@@ -1311,7 +1310,7 @@ func (v Value) SetCap(n int) {
v.mustBeAssignable()
v.mustBe(Slice)
s := (*sliceHeader)(v.ptr)
- if n < int(s.Len) || n > int(s.Cap) {
+ if n < s.Len || n > s.Cap {
panic("reflect: slice capacity out of range in SetCap")
}
s.Cap = n
@@ -1413,7 +1412,7 @@ func (v Value) Slice(i, j int) Value {
case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ))
s := (*sliceHeader)(v.ptr)
- base = unsafe.Pointer(s.Data)
+ base = s.Data
cap = s.Cap
case String:
@@ -1585,7 +1584,7 @@ func (v Value) Uint() uint64 {
case Uint32:
return uint64(*(*uint32)(p))
case Uint64:
- return uint64(*(*uint64)(p))
+ return *(*uint64)(p)
case Uintptr:
return uint64(*(*uintptr)(p))
}
@@ -1751,13 +1750,13 @@ func Copy(dst, src Value) int {
// A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/select.go:/runtimeSelect
type runtimeSelect struct {
- dir uintptr // 0, SendDir, or RecvDir
+ dir SelectDir // SelectSend, SelectRecv or SelectDefault
typ *rtype // channel type
ch unsafe.Pointer // channel
val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
}
-// rselect runs a select. It returns the index of the chosen case.
+// rselect runs a select. It returns the index of the chosen case.
// If the case was a receive, val is filled in with the received value.
// The conventional OK bool indicates whether the receive corresponds
// to a sent value.
@@ -1814,7 +1813,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
haveDefault := false
for i, c := range cases {
rc := &runcases[i]
- rc.dir = uintptr(c.Dir)
+ rc.dir = c.Dir
switch c.Dir {
default:
panic("reflect.Select: invalid Dir")
@@ -1877,7 +1876,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
}
chosen, recvOK = rselect(runcases)
- if runcases[chosen].dir == uintptr(SelectRecv) {
+ if runcases[chosen].dir == SelectRecv {
tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
t := tt.elem
p := runcases[chosen].val
@@ -1954,14 +1953,14 @@ func Indirect(v Value) Value {
}
// ValueOf returns a new Value initialized to the concrete value
-// stored in the interface i. ValueOf(nil) returns the zero Value.
+// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {
if i == nil {
return Value{}
}
// TODO: Maybe allow contents of a Value to live on the stack.
- // For now we make the contents always escape to the heap. It
+ // For now we make the contents always escape to the heap. It
// makes life easier in a few places (see chanrecv/mapassign
// comment below).
escapes(i)
@@ -1987,7 +1986,7 @@ func Zero(typ Type) Value {
}
// New returns a Value representing a pointer to a new zero value
-// for the specified type. That is, the returned Value's Type is PtrTo(typ).
+// for the specified type. That is, the returned Value's Type is PtrTo(typ).
func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
@@ -2142,13 +2141,13 @@ func makeInt(f flag, bits uint64, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 1:
- *(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
+ *(*uint8)(ptr) = uint8(bits)
case 2:
- *(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
+ *(*uint16)(ptr) = uint16(bits)
case 4:
- *(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
+ *(*uint32)(ptr) = uint32(bits)
case 8:
- *(*uint64)(unsafe.Pointer(ptr)) = bits
+ *(*uint64)(ptr) = bits
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2160,9 +2159,9 @@ func makeFloat(f flag, v float64, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 4:
- *(*float32)(unsafe.Pointer(ptr)) = float32(v)
+ *(*float32)(ptr) = float32(v)
case 8:
- *(*float64)(unsafe.Pointer(ptr)) = v
+ *(*float64)(ptr) = v
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2174,9 +2173,9 @@ func makeComplex(f flag, v complex128, t Type) Value {
ptr := unsafe_New(typ)
switch typ.size {
case 8:
- *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
+ *(*complex64)(ptr) = complex64(v)
case 16:
- *(*complex128)(unsafe.Pointer(ptr)) = v
+ *(*complex128)(ptr) = v
}
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
}
@@ -2320,7 +2319,7 @@ func chanclose(ch unsafe.Pointer)
func chanlen(ch unsafe.Pointer) int
// Note: some of the noescape annotations below are technically a lie,
-// but safe in the context of this package. Functions like chansend
+// but safe in the context of this package. Functions like chansend
// and mapassign don't escape the referent, but may escape anything
// the referent points to (they do shallow copies of the referent).
// It is safe in this package because the referent may only point