diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/reflect | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/reflect')
-rw-r--r-- | src/pkg/reflect/all_test.go | 3841 | ||||
-rw-r--r-- | src/pkg/reflect/asm_386.s | 27 | ||||
-rw-r--r-- | src/pkg/reflect/asm_amd64.s | 27 | ||||
-rw-r--r-- | src/pkg/reflect/asm_amd64p32.s | 27 | ||||
-rw-r--r-- | src/pkg/reflect/asm_arm.s | 27 | ||||
-rw-r--r-- | src/pkg/reflect/deepequal.go | 145 | ||||
-rw-r--r-- | src/pkg/reflect/example_test.go | 66 | ||||
-rw-r--r-- | src/pkg/reflect/export_test.go | 19 | ||||
-rw-r--r-- | src/pkg/reflect/makefunc.go | 120 | ||||
-rw-r--r-- | src/pkg/reflect/set_test.go | 211 | ||||
-rw-r--r-- | src/pkg/reflect/tostring_test.go | 95 | ||||
-rw-r--r-- | src/pkg/reflect/type.go | 1926 | ||||
-rw-r--r-- | src/pkg/reflect/value.go | 2684 |
13 files changed, 0 insertions, 9215 deletions
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go deleted file mode 100644 index e9949012c..000000000 --- a/src/pkg/reflect/all_test.go +++ /dev/null @@ -1,3841 +0,0 @@ -// 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 reflect_test - -import ( - "bytes" - "encoding/base64" - "flag" - "fmt" - "io" - "math/rand" - "os" - . "reflect" - "runtime" - "sort" - "strings" - "sync" - "testing" - "time" - "unsafe" -) - -func TestBool(t *testing.T) { - v := ValueOf(true) - if v.Bool() != true { - t.Fatal("ValueOf(true).Bool() = false") - } -} - -type integer int -type T struct { - a int - b float64 - c string - d *int -} - -type pair struct { - i interface{} - 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"}, - {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) }{}, "**reflect_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 *reflect_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 { reflect_test.a(func(func(int) int) func(func(int)) int); reflect_test.b() }", - }, -} - -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), "**reflect_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)(0)"}, - {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 *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}", - }, - {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 := typ.String() - if s != want { - t.Errorf("#%d: have %#q, want %#q", i, s, want) - } -} - -func TestTypes(t *testing.T) { - for i, tt := range typeTests { - testType(t, i, ValueOf(tt.i).Field(0).Type(), tt.s) - } -} - -func TestSet(t *testing.T) { - for i, tt := range valueTests { - v := ValueOf(tt.i) - v = v.Elem() - switch v.Kind() { - case Int: - v.SetInt(132) - case Int8: - v.SetInt(8) - case Int16: - v.SetInt(16) - case Int32: - v.SetInt(32) - case Int64: - v.SetInt(64) - case Uint: - v.SetUint(132) - case Uint8: - v.SetUint(8) - case Uint16: - v.SetUint(16) - case Uint32: - v.SetUint(32) - case Uint64: - v.SetUint(64) - case Float32: - v.SetFloat(256.25) - case Float64: - v.SetFloat(512.125) - case Complex64: - v.SetComplex(532.125 + 10i) - case Complex128: - v.SetComplex(564.25 + 1i) - case String: - v.SetString("stringy cheese") - case Bool: - v.SetBool(true) - } - s := valueToString(v) - if s != tt.s { - t.Errorf("#%d: have %#q, want %#q", i, s, 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) - } - } -} - -var _i = 7 - -var valueToStringTests = []pair{ - {123, "123"}, - {123.5, "123.5"}, - {byte(123), "123"}, - {"abc", "abc"}, - {T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"}, - {new(chan *T), "*chan *reflect_test.T(&chan *reflect_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 TestArrayElemSet(t *testing.T) { - v := ValueOf(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).Elem() - v.Index(4).SetInt(123) - s := valueToString(v) - const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}" - if s != want { - t.Errorf("[10]int: have %#q want %#q", s, want) - } - - v = ValueOf([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) - v.Index(4).SetInt(123) - s = valueToString(v) - const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}" - if s != want1 { - t.Errorf("[]int: have %#q want %#q", s, want1) - } -} - -func TestPtrPointTo(t *testing.T) { - var ip *int32 - var i int32 = 1234 - vip := ValueOf(&ip) - vi := ValueOf(&i).Elem() - vip.Elem().Set(vi.Addr()) - if *ip != 1234 { - t.Errorf("got %d, want 1234", *ip) - } - - ip = nil - vp := ValueOf(&ip).Elem() - vp.Set(Zero(vp.Type())) - if ip != nil { - t.Errorf("got non-nil (%p), want nil", ip) - } -} - -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 }") - styp := etyp - f := styp.Field(0) - testType(t, 5, f.Type, "chan *int32") - - f, present := styp.FieldByName("d") - if !present { - t.Errorf("FieldByName says present field is absent") - } - testType(t, 6, f.Type, "float32") - - f, present = styp.FieldByName("absent") - if present { - t.Errorf("FieldByName says absent field is present") - } - - typ = TypeOf([32]int32{}) - testType(t, 7, typ, "[32]int32") - testType(t, 8, typ.Elem(), "int32") - - typ = TypeOf((map[string]*int32)(nil)) - testType(t, 9, typ, "map[string]*int32") - mtyp := typ - testType(t, 10, mtyp.Key(), "string") - testType(t, 11, mtyp.Elem(), "*int32") - - typ = TypeOf((chan<- string)(nil)) - testType(t, 12, typ, "chan<- string") - testType(t, 13, typ.Elem(), "string") - - // make sure tag strings are not part of element type - typ = TypeOf(struct { - d []uint32 `reflect:"TAG"` - }{}).Field(0).Type - testType(t, 14, typ, "[]uint32") -} - -func TestInterfaceGet(t *testing.T) { - var inter struct { - E interface{} - } - inter.E = 123.456 - v1 := ValueOf(&inter) - v2 := v1.Elem().Field(0) - assert(t, v2.Type().String(), "interface {}") - i2 := v2.Interface() - v3 := ValueOf(i2) - assert(t, v3.Type().String(), "float64") -} - -func TestInterfaceValue(t *testing.T) { - var inter struct { - E interface{} - } - inter.E = 123.456 - v1 := ValueOf(&inter) - v2 := v1.Elem().Field(0) - assert(t, v2.Type().String(), "interface {}") - v3 := v2.Elem() - assert(t, v3.Type().String(), "float64") - - i3 := v2.Interface() - if _, ok := i3.(float64); !ok { - t.Error("v2.Interface() did not return float64, got ", TypeOf(i3)) - } -} - -func TestFunctionValue(t *testing.T) { - var x interface{} = func() {} - v := ValueOf(x) - if fmt.Sprint(v.Interface()) != fmt.Sprint(x) { - t.Fatalf("TestFunction returned wrong pointer") - } - assert(t, v.Type().String(), "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 TestAppend(t *testing.T) { - for i, test := range appendTests { - origLen, extraLen := len(test.orig), len(test.extra) - want := append(test.orig, test.extra...) - // Convert extra from []int to []Value. - e0 := make([]Value, len(test.extra)) - for j, e := range test.extra { - e0[j] = ValueOf(e) - } - // 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) - } - // Check that the orig and extra slices were not modified. - 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) { - t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want) - } - // Check that the orig and extra slices were not modified. - 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) - } - } -} - -func TestCopy(t *testing.T) { - a := []int{1, 2, 3, 4, 10, 9, 8, 7} - b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44} - c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44} - for i := 0; i < len(b); i++ { - if b[i] != c[i] { - t.Fatalf("b != c before test") - } - } - a1 := a - b1 := b - aa := ValueOf(&a1).Elem() - ab := ValueOf(&b1).Elem() - for tocopy := 1; tocopy <= 7; tocopy++ { - aa.SetLen(tocopy) - Copy(ab, aa) - aa.SetLen(8) - for i := 0; i < tocopy; i++ { - if a[i] != b[i] { - t.Errorf("(i) tocopy=%d a[%d]=%d, b[%d]=%d", - tocopy, i, a[i], i, b[i]) - } - } - for i := tocopy; i < len(b); i++ { - if b[i] != c[i] { - if i < len(a) { - t.Errorf("(ii) tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d", - tocopy, i, a[i], i, b[i], i, c[i]) - } else { - t.Errorf("(iii) tocopy=%d b[%d]=%d, c[%d]=%d", - tocopy, i, b[i], i, c[i]) - } - } else { - t.Logf("tocopy=%d elem %d is okay\n", tocopy, i) - } - } - } -} - -func TestCopyArray(t *testing.T) { - a := [8]int{1, 2, 3, 4, 10, 9, 8, 7} - b := [11]int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44} - c := b - aa := ValueOf(&a).Elem() - ab := ValueOf(&b).Elem() - Copy(ab, aa) - for i := 0; i < len(a); i++ { - if a[i] != b[i] { - t.Errorf("(i) a[%d]=%d, b[%d]=%d", i, a[i], i, b[i]) - } - } - for i := len(a); i < len(b); i++ { - if b[i] != c[i] { - t.Errorf("(ii) b[%d]=%d, c[%d]=%d", i, b[i], i, c[i]) - } else { - t.Logf("elem %d is okay\n", i) - } - } -} - -func TestBigUnnamedStruct(t *testing.T) { - b := struct{ a, b, c, d int64 }{1, 2, 3, 4} - v := ValueOf(b) - b1 := v.Interface().(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 := v.Interface().(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 interface{} - eq bool -} - -// Simple functions for DeepEqual tests. -var ( - fn1 func() // nil. - fn2 func() // nil. - fn3 = func() { fn1() } // Not nil. -) - -var deepEqualTests = []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{[]int{1}}, [][]int{[]int{2}}, false}, - - // 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]interface{}{1, 2, 4}, &[3]interface{}{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}, -} - -func TestDeepEqual(t *testing.T) { - for _, test := range deepEqualTests { - if r := DeepEqual(test.a, test.b); r != test.eq { - t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq) - } - } -} - -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 deepEqualTests { - 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()) - } - } -} - -type Recursive struct { - x int - r *Recursive -} - -func TestDeepEqualRecursiveStruct(t *testing.T) { - a, b := new(Recursive), new(Recursive) - *a = Recursive{12, a} - *b = Recursive{12, b} - if !DeepEqual(a, b) { - t.Error("DeepEqual(recursive same) = false, want true") - } -} - -type _Complex struct { - a int - b [3]*_Complex - c *string - d map[float64]float64 -} - -func TestDeepEqualComplexStruct(t *testing.T) { - m := make(map[float64]float64) - stra, strb := "hello", "hello" - a, b := new(_Complex), new(_Complex) - *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m} - *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m} - if !DeepEqual(a, b) { - t.Error("DeepEqual(complex same) = false, want true") - } -} - -func TestDeepEqualComplexStructInequality(t *testing.T) { - m := make(map[float64]float64) - stra, strb := "hello", "helloo" // Difference is here - a, b := new(_Complex), new(_Complex) - *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m} - *b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m} - if DeepEqual(a, b) { - t.Error("DeepEqual(complex different) = true, want false") - } -} - -type UnexpT struct { - m map[int]int -} - -func TestDeepEqualUnexportedMap(t *testing.T) { - // Check that DeepEqual can look at unexported fields. - x1 := UnexpT{map[int]int{1: 2}} - x2 := UnexpT{map[int]int{1: 2}} - if !DeepEqual(&x1, &x2) { - t.Error("DeepEqual(x1, x2) = false, want true") - } - - y1 := UnexpT{map[int]int{2: 3}} - if DeepEqual(&x1, &y1) { - t.Error("DeepEqual(x1, y1) = true, want false") - } -} - -func check2ndField(x interface{}, offs uintptr, t *testing.T) { - s := ValueOf(x) - f := s.Type().Field(1) - if f.Offset != offs { - t.Error("mismatched offsets in structure alignment:", f.Offset, offs) - } -} - -// Check that structure alignment & offsets viewed through reflect agree with those -// from the compiler itself. -func TestAlignment(t *testing.T) { - type T1inner struct { - a int - } - type T1 struct { - T1inner - f int - } - type T2inner struct { - a, b int - } - type T2 struct { - T2inner - f int - } - - x := T1{T1inner{2}, 17} - check2ndField(x, uintptr(unsafe.Pointer(&x.f))-uintptr(unsafe.Pointer(&x)), t) - - x1 := T2{T2inner{2, 3}, 17} - check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t) -} - -func Nil(a interface{}, 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) { - 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{}{ - struct{ x *int }{}, - struct{ x interface{} }{}, - struct{ x map[string]int }{}, - struct{ x func() bool }{}, - struct{ x chan int }{}, - struct{ x []string }{}, - } - for _, ts := range doNil { - ty := TypeOf(ts).Field(0).Type - 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 interface{} - } - 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) -} - -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{}) { - t.Error("Interface() on interface: ", v, s.W) - } -} - -func TestNilPtrValueSub(t *testing.T) { - var pi *int - if pv := ValueOf(pi); pv.Elem().IsValid() { - t.Error("ValueOf((*int)(nil)).Elem().IsValid()") - } -} - -func TestMap(t *testing.T) { - m := map[string]int{"a": 1, "b": 2} - mv := ValueOf(m) - if n := mv.Len(); n != len(m) { - t.Errorf("Len = %d, want %d", n, len(m)) - } - keys := mv.MapKeys() - newmap := MakeMap(mv.Type()) - for k, v := range m { - // Check that returned Keys match keys in range. - // These aren't required to be in the same order. - seen := false - for _, kv := range keys { - if kv.String() == k { - seen = true - break - } - } - if !seen { - t.Errorf("Missing key %q", k) - } - - // Check that value lookup is correct. - vv := mv.MapIndex(ValueOf(k)) - if vi := vv.Int(); vi != int64(v) { - t.Errorf("Key %q: have value %d, want %d", k, vi, v) - } - - // Copy into new map. - newmap.SetMapIndex(ValueOf(k), ValueOf(v)) - } - vv := mv.MapIndex(ValueOf("not-present")) - if vv.IsValid() { - t.Errorf("Invalid key: got non-nil value %s", valueToString(vv)) - } - - newm := newmap.Interface().(map[string]int) - if len(newm) != len(m) { - t.Errorf("length after copy: newm=%d, m=%d", len(newm), len(m)) - } - - for k, v := range newm { - mv, ok := m[k] - if mv != v { - t.Errorf("newm[%q] = %d, but m[%q] = %d, %v", k, v, k, mv, ok) - } - } - - newmap.SetMapIndex(ValueOf("a"), Value{}) - v, ok := newm["a"] - if ok { - t.Errorf("newm[\"a\"] = %d after delete", v) - } - - mv = ValueOf(&m).Elem() - mv.Set(Zero(mv.Type())) - if m != nil { - t.Errorf("mv.Set(nil) failed") - } -} - -func TestNilMap(t *testing.T) { - var m map[string]int - mv := ValueOf(m) - keys := mv.MapKeys() - if len(keys) != 0 { - t.Errorf(">0 keys for nil map: %v", keys) - } - - // Check that value for missing key is zero. - x := mv.MapIndex(ValueOf("hello")) - if x.Kind() != Invalid { - t.Errorf("m.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x) - } - - // Check big value too. - var mbig map[string][10 << 20]byte - x = ValueOf(mbig).MapIndex(ValueOf("hello")) - if x.Kind() != Invalid { - t.Errorf("mbig.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x) - } - - // Test that deletes from a nil map succeed. - mv.SetMapIndex(ValueOf("hi"), Value{}) -} - -func TestChan(t *testing.T) { - for loop := 0; loop < 2; loop++ { - var c chan int - var cv Value - - // check both ways to allocate channels - switch loop { - case 1: - c = make(chan int, 1) - cv = ValueOf(c) - case 0: - cv = MakeChan(TypeOf(c), 1) - c = cv.Interface().(chan int) - } - - // Send - cv.Send(ValueOf(2)) - if i := <-c; i != 2 { - t.Errorf("reflect Send 2, native recv %d", i) - } - - // Recv - c <- 3 - if i, ok := cv.Recv(); i.Int() != 3 || !ok { - t.Errorf("native send 3, reflect Recv %d, %t", i.Int(), ok) - } - - // TryRecv fail - val, ok := cv.TryRecv() - if val.IsValid() || ok { - t.Errorf("TryRecv on empty chan: %s, %t", valueToString(val), ok) - } - - // TryRecv success - c <- 4 - val, ok = cv.TryRecv() - if !val.IsValid() { - t.Errorf("TryRecv on ready chan got nil") - } else if i := val.Int(); i != 4 || !ok { - t.Errorf("native send 4, TryRecv %d, %t", i, ok) - } - - // TrySend fail - c <- 100 - ok = cv.TrySend(ValueOf(5)) - i := <-c - if ok { - t.Errorf("TrySend on full chan succeeded: value %d", i) - } - - // TrySend success - ok = cv.TrySend(ValueOf(6)) - if !ok { - t.Errorf("TrySend on empty chan failed") - } else { - if i = <-c; i != 6 { - t.Errorf("TrySend 6, recv %d", i) - } - } - - // Close - c <- 123 - cv.Close() - if i, ok := cv.Recv(); i.Int() != 123 || !ok { - t.Errorf("send 123 then close; Recv %d, %t", i.Int(), ok) - } - if i, ok := cv.Recv(); i.Int() != 0 || ok { - t.Errorf("after close Recv %d, %t", i.Int(), ok) - } - } - - // check creation of unbuffered channel - var c chan int - cv := MakeChan(TypeOf(c), 0) - c = cv.Interface().(chan int) - if cv.TrySend(ValueOf(7)) { - t.Errorf("TrySend on sync chan succeeded") - } - if v, ok := cv.TryRecv(); v.IsValid() || ok { - t.Errorf("TryRecv on sync chan succeeded: isvalid=%v ok=%v", v.IsValid(), ok) - } - - // len/cap - cv = MakeChan(TypeOf(c), 10) - c = cv.Interface().(chan int) - for i := 0; i < 3; i++ { - c <- i - } - if l, m := cv.Len(), cv.Cap(); l != len(c) || m != cap(c) { - t.Errorf("Len/Cap = %d/%d want %d/%d", l, m, len(c), cap(c)) - } -} - -// caseInfo describes a single case in a select test. -type caseInfo struct { - desc string - canSelect bool - recv Value - closed bool - helper func() - panic bool -} - -var allselect = flag.Bool("allselect", false, "exhaustive select test") - -func TestSelect(t *testing.T) { - selectWatch.once.Do(func() { go selectWatcher() }) - - var x exhaustive - nch := 0 - newop := func(n int, cap int) (ch, val Value) { - nch++ - if nch%101%2 == 1 { - c := make(chan int, cap) - ch = ValueOf(c) - val = ValueOf(n) - } else { - c := make(chan string, cap) - ch = ValueOf(c) - val = ValueOf(fmt.Sprint(n)) - } - return - } - - for n := 0; x.Next(); n++ { - if testing.Short() && n >= 1000 { - break - } - if n >= 100000 && !*allselect { - break - } - if n%100000 == 0 && testing.Verbose() { - println("TestSelect", n) - } - var cases []SelectCase - var info []caseInfo - - // Ready send. - if x.Maybe() { - ch, val := newop(len(cases), 1) - cases = append(cases, SelectCase{ - Dir: SelectSend, - Chan: ch, - Send: val, - }) - info = append(info, caseInfo{desc: "ready send", canSelect: true}) - } - - // Ready recv. - if x.Maybe() { - ch, val := newop(len(cases), 1) - ch.Send(val) - cases = append(cases, SelectCase{ - Dir: SelectRecv, - Chan: ch, - }) - info = append(info, caseInfo{desc: "ready recv", canSelect: true, recv: val}) - } - - // Blocking send. - if x.Maybe() { - ch, val := newop(len(cases), 0) - cases = append(cases, SelectCase{ - Dir: SelectSend, - Chan: ch, - Send: val, - }) - // Let it execute? - if x.Maybe() { - f := func() { ch.Recv() } - info = append(info, caseInfo{desc: "blocking send", helper: f}) - } else { - info = append(info, caseInfo{desc: "blocking send"}) - } - } - - // Blocking recv. - if x.Maybe() { - ch, val := newop(len(cases), 0) - cases = append(cases, SelectCase{ - Dir: SelectRecv, - Chan: ch, - }) - // Let it execute? - if x.Maybe() { - f := func() { ch.Send(val) } - info = append(info, caseInfo{desc: "blocking recv", recv: val, helper: f}) - } else { - info = append(info, caseInfo{desc: "blocking recv"}) - } - } - - // Zero Chan send. - if x.Maybe() { - // Maybe include value to send. - var val Value - if x.Maybe() { - val = ValueOf(100) - } - cases = append(cases, SelectCase{ - Dir: SelectSend, - Send: val, - }) - info = append(info, caseInfo{desc: "zero Chan send"}) - } - - // Zero Chan receive. - if x.Maybe() { - cases = append(cases, SelectCase{ - Dir: SelectRecv, - }) - info = append(info, caseInfo{desc: "zero Chan recv"}) - } - - // nil Chan send. - if x.Maybe() { - cases = append(cases, SelectCase{ - Dir: SelectSend, - Chan: ValueOf((chan int)(nil)), - Send: ValueOf(101), - }) - info = append(info, caseInfo{desc: "nil Chan send"}) - } - - // nil Chan recv. - if x.Maybe() { - cases = append(cases, SelectCase{ - Dir: SelectRecv, - Chan: ValueOf((chan int)(nil)), - }) - info = append(info, caseInfo{desc: "nil Chan recv"}) - } - - // closed Chan send. - if x.Maybe() { - ch := make(chan int) - close(ch) - cases = append(cases, SelectCase{ - Dir: SelectSend, - Chan: ValueOf(ch), - Send: ValueOf(101), - }) - info = append(info, caseInfo{desc: "closed Chan send", canSelect: true, panic: true}) - } - - // closed Chan recv. - if x.Maybe() { - ch, val := newop(len(cases), 0) - ch.Close() - val = Zero(val.Type()) - cases = append(cases, SelectCase{ - Dir: SelectRecv, - Chan: ch, - }) - info = append(info, caseInfo{desc: "closed Chan recv", canSelect: true, closed: true, recv: val}) - } - - var helper func() // goroutine to help the select complete - - // Add default? Must be last case here, but will permute. - // Add the default if the select would otherwise - // block forever, and maybe add it anyway. - numCanSelect := 0 - canProceed := false - canBlock := true - canPanic := false - helpers := []int{} - for i, c := range info { - if c.canSelect { - canProceed = true - canBlock = false - numCanSelect++ - if c.panic { - canPanic = true - } - } else if c.helper != nil { - canProceed = true - helpers = append(helpers, i) - } - } - if !canProceed || x.Maybe() { - cases = append(cases, SelectCase{ - Dir: SelectDefault, - }) - info = append(info, caseInfo{desc: "default", canSelect: canBlock}) - numCanSelect++ - } else if canBlock { - // Select needs to communicate with another goroutine. - cas := &info[helpers[x.Choose(len(helpers))]] - helper = cas.helper - cas.canSelect = true - numCanSelect++ - } - - // Permute cases and case info. - // Doing too much here makes the exhaustive loop - // too exhausting, so just do two swaps. - for loop := 0; loop < 2; loop++ { - i := x.Choose(len(cases)) - j := x.Choose(len(cases)) - cases[i], cases[j] = cases[j], cases[i] - info[i], info[j] = info[j], info[i] - } - - if helper != nil { - // We wait before kicking off a goroutine to satisfy a blocked select. - // The pause needs to be big enough to let the select block before - // we run the helper, but if we lose that race once in a while it's okay: the - // select will just proceed immediately. Not a big deal. - // For short tests we can grow [sic] the timeout a bit without fear of taking too long - pause := 10 * time.Microsecond - if testing.Short() { - pause = 100 * time.Microsecond - } - time.AfterFunc(pause, helper) - } - - // Run select. - i, recv, recvOK, panicErr := runSelect(cases, info) - if panicErr != nil && !canPanic { - t.Fatalf("%s\npanicked unexpectedly: %v", fmtSelect(info), panicErr) - } - if panicErr == nil && canPanic && numCanSelect == 1 { - t.Fatalf("%s\nselected #%d incorrectly (should panic)", fmtSelect(info), i) - } - if panicErr != nil { - continue - } - - cas := info[i] - if !cas.canSelect { - recvStr := "" - if recv.IsValid() { - 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 { - if !recv.IsValid() { - t.Fatalf("%s\nselected #%d but got %v, %v, want %v, %v", fmtSelect(info), i, recv, recvOK, cas.recv.Interface(), !cas.closed) - } - if !cas.recv.IsValid() { - t.Fatalf("%s\nselected #%d but internal error: missing recv value", fmtSelect(info), i) - } - if recv.Interface() != cas.recv.Interface() || recvOK != !cas.closed { - if recv.Interface() == cas.recv.Interface() && recvOK == !cas.closed { - t.Fatalf("%s\nselected #%d, got %#v, %v, and DeepEqual is broken on %T", fmtSelect(info), i, recv.Interface(), recvOK, recv.Interface()) - } - t.Fatalf("%s\nselected #%d but got %#v, %v, want %#v, %v", fmtSelect(info), i, recv.Interface(), recvOK, cas.recv.Interface(), !cas.closed) - } - } else { - if recv.IsValid() || recvOK { - t.Fatalf("%s\nselected #%d but got %v, %v, want %v, %v", fmtSelect(info), i, recv, recvOK, Value{}, false) - } - } - } -} - -// 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. -var selectWatch struct { - sync.Mutex - once sync.Once - now time.Time - info []caseInfo -} - -func selectWatcher() { - for { - time.Sleep(1 * time.Second) - selectWatch.Lock() - if selectWatch.info != nil && time.Since(selectWatch.now) > 1*time.Second { - fmt.Fprintf(os.Stderr, "TestSelect:\n%s blocked indefinitely\n", fmtSelect(selectWatch.info)) - panic("select stuck") - } - selectWatch.Unlock() - } -} - -// 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{}) { - defer func() { - panicErr = recover() - - selectWatch.Lock() - selectWatch.info = nil - selectWatch.Unlock() - }() - - selectWatch.Lock() - selectWatch.now = time.Now() - selectWatch.info = info - selectWatch.Unlock() - - chosen, recv, recvOK = Select(cases) - return -} - -// fmtSelect formats the information about a single select test. -func fmtSelect(info []caseInfo) string { - var buf bytes.Buffer - fmt.Fprintf(&buf, "\nselect {\n") - for i, cas := range info { - fmt.Fprintf(&buf, "%d: %s", i, cas.desc) - if cas.recv.IsValid() { - fmt.Fprintf(&buf, " val=%#v", cas.recv.Interface()) - } - if cas.canSelect { - fmt.Fprintf(&buf, " canselect") - } - if cas.panic { - fmt.Fprintf(&buf, " panic") - } - fmt.Fprintf(&buf, "\n") - } - fmt.Fprintf(&buf, "}") - return buf.String() -} - -type two [2]uintptr - -// Difficult test for function call because of -// implicit padding between arguments. -func dummy(b byte, c int, d byte, e two, f byte, g float32, h byte) (i byte, j int, k byte, l two, m byte, n float32, o byte) { - return b, c, d, e, f, g, h -} - -func TestFunc(t *testing.T) { - ret := ValueOf(dummy).Call([]Value{ - ValueOf(byte(10)), - ValueOf(20), - ValueOf(byte(30)), - ValueOf(two{40, 50}), - ValueOf(byte(60)), - ValueOf(float32(70)), - ValueOf(byte(80)), - }) - if len(ret) != 7 { - t.Fatalf("Call returned %d values, want 7", len(ret)) - } - - i := byte(ret[0].Uint()) - j := int(ret[1].Int()) - k := byte(ret[2].Uint()) - l := ret[3].Interface().(two) - m := byte(ret[4].Uint()) - n := float32(ret[5].Float()) - o := byte(ret[6].Uint()) - - if i != 10 || j != 20 || k != 30 || l != (two{40, 50}) || m != 60 || n != 70 || o != 80 { - t.Errorf("Call returned %d, %d, %d, %v, %d, %g, %d; want 10, 20, 30, [40, 50], 60, 70, 80", i, j, k, l, m, n, o) - } -} - -type emptyStruct struct{} - -type nonEmptyStruct struct { - member int -} - -func returnEmpty() emptyStruct { - return emptyStruct{} -} - -func takesEmpty(e emptyStruct) { -} - -func returnNonEmpty(i int) nonEmptyStruct { - return nonEmptyStruct{member: i} -} - -func takesNonEmpty(n nonEmptyStruct) int { - return n.member -} - -func TestCallWithStruct(t *testing.T) { - r := ValueOf(returnEmpty).Call(nil) - if len(r) != 1 || r[0].Type() != TypeOf(emptyStruct{}) { - t.Errorf("returning empty struct returned %#v instead", r) - } - r = ValueOf(takesEmpty).Call([]Value{ValueOf(emptyStruct{})}) - if len(r) != 0 { - t.Errorf("takesEmpty returned values: %#v", r) - } - r = ValueOf(returnNonEmpty).Call([]Value{ValueOf(42)}) - if len(r) != 1 || r[0].Type() != TypeOf(nonEmptyStruct{}) || r[0].Field(0).Int() != 42 { - t.Errorf("returnNonEmpty returned %#v", r) - } - r = ValueOf(takesNonEmpty).Call([]Value{ValueOf(nonEmptyStruct{member: 42})}) - if len(r) != 1 || r[0].Type() != TypeOf(1) || r[0].Int() != 42 { - t.Errorf("takesNonEmpty returned %#v", r) - } -} - -func TestMakeFunc(t *testing.T) { - f := dummy - fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in }) - ValueOf(&f).Elem().Set(fv) - - // Call g with small arguments so that there is - // something predictable (and different from the - // correct results) in those positions on the stack. - g := dummy - g(1, 2, 3, two{4, 5}, 6, 7, 8) - - // Call constructed function f. - i, j, k, l, m, n, o := f(10, 20, 30, two{40, 50}, 60, 70, 80) - if i != 10 || j != 20 || k != 30 || l != (two{40, 50}) || m != 60 || n != 70 || o != 80 { - t.Errorf("Call returned %d, %d, %d, %v, %d, %g, %d; want 10, 20, 30, [40, 50], 60, 70, 80", i, j, k, l, m, n, o) - } -} - -func TestMakeFuncInterface(t *testing.T) { - fn := func(i int) int { return i } - incr := func(in []Value) []Value { - return []Value{ValueOf(int(in[0].Int() + 1))} - } - fv := MakeFunc(TypeOf(fn), incr) - ValueOf(&fn).Elem().Set(fv) - if r := fn(2); r != 3 { - t.Errorf("Call returned %d, want 3", r) - } - if r := fv.Call([]Value{ValueOf(14)})[0].Int(); r != 15 { - t.Errorf("Call returned %d, want 15", r) - } - if r := fv.Interface().(func(int) int)(26); r != 27 { - t.Errorf("Call returned %d, want 27", r) - } -} - -func TestMakeFuncVariadic(t *testing.T) { - // Test that variadic arguments are packed into a slice and passed as last arg - fn := func(_ int, is ...int) []int { return nil } - fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] }) - ValueOf(&fn).Elem().Set(fv) - - r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) - if r[0] != 2 || r[1] != 3 { - t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) - } - - r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int) - if r[0] != 2 || r[1] != 3 { - t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) - } -} - -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 -} - -func TestMethod(t *testing.T) { - // Non-curried method of type. - p := Point{3, 4} - i := TypeOf(p).Method(1).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int() - if i != 250 { - t.Errorf("Type Method returned %d; want 250", i) - } - - m, ok := TypeOf(p).MethodByName("Dist") - if !ok { - t.Fatalf("method by name failed") - } - i = m.Func.Call([]Value{ValueOf(p), ValueOf(11)})[0].Int() - if i != 275 { - t.Errorf("Type MethodByName returned %d; want 275", i) - } - - i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(12)})[0].Int() - if i != 300 { - t.Errorf("Pointer Type Method returned %d; want 300", i) - } - - m, ok = TypeOf(&p).MethodByName("Dist") - if !ok { - t.Fatalf("ptr method by name failed") - } - i = m.Func.Call([]Value{ValueOf(&p), ValueOf(13)})[0].Int() - if i != 325 { - t.Errorf("Pointer Type MethodByName returned %d; want 325", i) - } - - // Curried method of value. - tfunc := TypeOf((func(int) int)(nil)) - v := ValueOf(p).Method(1) - if tt := v.Type(); tt != tfunc { - t.Errorf("Value Method Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(14)})[0].Int() - if i != 350 { - t.Errorf("Value Method returned %d; want 350", i) - } - v = ValueOf(p).MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(15)})[0].Int() - if i != 375 { - t.Errorf("Value MethodByName returned %d; want 375", i) - } - - // Curried method of pointer. - v = ValueOf(&p).Method(1) - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(16)})[0].Int() - if i != 400 { - t.Errorf("Pointer Value Method returned %d; want 400", i) - } - v = ValueOf(&p).MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(17)})[0].Int() - if i != 425 { - t.Errorf("Pointer Value MethodByName returned %d; want 425", i) - } - - // Curried method of interface value. - // Have to wrap interface value in a struct to get at it. - // Passing it to ValueOf directly would - // access the underlying Point, not the interface. - var x interface { - Dist(int) int - } = p - pv := ValueOf(&x).Elem() - v = pv.Method(0) - if tt := v.Type(); tt != tfunc { - t.Errorf("Interface Method Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(18)})[0].Int() - if i != 450 { - t.Errorf("Interface Method returned %d; want 450", i) - } - v = pv.MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc) - } - i = v.Call([]Value{ValueOf(19)})[0].Int() - if i != 475 { - t.Errorf("Interface MethodByName returned %d; want 475", i) - } -} - -func TestMethodValue(t *testing.T) { - p := Point{3, 4} - var i int64 - - // Curried method of value. - tfunc := TypeOf((func(int) int)(nil)) - v := ValueOf(p).Method(1) - if tt := v.Type(); tt != tfunc { - t.Errorf("Value Method Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(10)})[0].Int() - if i != 250 { - t.Errorf("Value Method returned %d; want 250", i) - } - v = ValueOf(p).MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(11)})[0].Int() - if i != 275 { - t.Errorf("Value MethodByName returned %d; want 275", i) - } - - // Curried method of pointer. - v = ValueOf(&p).Method(1) - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(12)})[0].Int() - if i != 300 { - t.Errorf("Pointer Value Method returned %d; want 300", i) - } - v = ValueOf(&p).MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(13)})[0].Int() - if i != 325 { - t.Errorf("Pointer Value MethodByName returned %d; want 325", i) - } - - // Curried method of pointer to pointer. - pp := &p - v = ValueOf(&pp).Elem().Method(1) - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Pointer Value Method Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(14)})[0].Int() - if i != 350 { - t.Errorf("Pointer Pointer Value Method returned %d; want 350", i) - } - v = ValueOf(&pp).Elem().MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Pointer Pointer Value MethodByName Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(15)})[0].Int() - if i != 375 { - t.Errorf("Pointer Pointer Value MethodByName returned %d; want 375", i) - } - - // Curried method of interface value. - // Have to wrap interface value in a struct to get at it. - // Passing it to ValueOf directly would - // access the underlying Point, not the interface. - var s = struct { - X interface { - Dist(int) int - } - }{p} - pv := ValueOf(s).Field(0) - v = pv.Method(0) - if tt := v.Type(); tt != tfunc { - t.Errorf("Interface Method Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(16)})[0].Int() - if i != 400 { - t.Errorf("Interface Method returned %d; want 400", i) - } - v = pv.MethodByName("Dist") - if tt := v.Type(); tt != tfunc { - t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc) - } - i = ValueOf(v.Interface()).Call([]Value{ValueOf(17)})[0].Int() - if i != 425 { - t.Errorf("Interface MethodByName returned %d; want 425", i) - } -} - -// Reflect version of $GOROOT/test/method5.go - -// Concrete types implementing M method. -// Smaller than a word, word-sized, larger than a word. -// Value and pointer receivers. - -type Tinter interface { - M(int, byte) (byte, int) -} - -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]) } - -// 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) -} - -// Embedding via pointer. - -type Tm1 struct { - Tm2 -} - -type Tm2 struct { - *Tm3 -} - -type Tm3 struct { - *Tm4 -} - -type Tm4 struct { -} - -func (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 } - -func TestMethod5(t *testing.T) { - CheckF := func(name string, f func(int, byte) (byte, int), inc int) { - b, x := f(1000, 99) - if b != 99 || x != 1000+inc { - t.Errorf("%s(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc) - } - } - - CheckV := func(name string, i Value, inc int) { - bx := i.Method(0).Call([]Value{ValueOf(1000), ValueOf(byte(99))}) - b := bx[0].Interface() - x := bx[1].Interface() - if b != byte(99) || x != 1000+inc { - t.Errorf("direct %s.M(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc) - } - - CheckF(name+".M", i.Method(0).Interface().(func(int, byte) (byte, int)), inc) - } - - var TinterType = TypeOf(new(Tinter)).Elem() - var tinterType = TypeOf(new(tinter)).Elem() - - CheckI := func(name string, i interface{}, inc int) { - v := ValueOf(i) - CheckV(name, v, inc) - CheckV("(i="+name+")", v.Convert(TinterType), inc) - } - - sv := Tsmallv(1) - CheckI("sv", sv, 1) - CheckI("&sv", &sv, 1) - - sp := Tsmallp(2) - CheckI("&sp", &sp, 2) - - wv := Twordv(3) - CheckI("wv", wv, 3) - CheckI("&wv", &wv, 3) - - wp := Twordp(4) - CheckI("&wp", &wp, 4) - - bv := Tbigv([2]uintptr{5, 6}) - CheckI("bv", bv, 11) - CheckI("&bv", &bv, 11) - - bp := Tbigp([2]uintptr{7, 8}) - CheckI("&bp", &bp, 15) - - t4 := Tm4{} - t3 := Tm3{&t4} - t2 := Tm2{&t3} - t1 := Tm1{t2} - CheckI("t4", t4, 40) - CheckI("&t4", &t4, 40) - CheckI("t3", t3, 40) - CheckI("&t3", &t3, 40) - CheckI("t2", t2, 40) - CheckI("&t2", &t2, 40) - 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) }) -} - -func TestInterfaceSet(t *testing.T) { - p := &Point{3, 4} - - var s struct { - I interface{} - P interface { - Dist(int) int - } - } - sv := ValueOf(&s).Elem() - sv.Field(0).Set(ValueOf(p)) - if q := s.I.(*Point); q != p { - t.Errorf("i: have %p want %p", q, p) - } - - pv := sv.Field(1) - pv.Set(ValueOf(p)) - if q := s.P.(*Point); q != p { - t.Errorf("i: have %p want %p", q, p) - } - - i := pv.Method(0).Call([]Value{ValueOf(10)})[0].Int() - if i != 250 { - t.Errorf("Interface Method returned %d; want 250", i) - } -} - -type T1 struct { - a string - int -} - -func TestAnonymousFields(t *testing.T) { - var field StructField - var ok bool - var t1 T1 - type1 := TypeOf(t1) - if field, ok = type1.FieldByName("int"); !ok { - t.Fatal("no field 'int'") - } - if field.Index[0] != 1 { - t.Error("field index should be 1; is", field.Index) - } -} - -type FTest struct { - s interface{} - name string - index []int - value int -} - -type D1 struct { - d int -} -type D2 struct { - d int -} - -type S0 struct { - A, B, C int - D1 - D2 -} - -type S1 struct { - B int - S0 -} - -type S2 struct { - A int - *S1 -} - -type S1x struct { - S1 -} - -type S1y struct { - S1 -} - -type S3 struct { - S1x - S2 - D, E int - *S1y -} - -type S4 struct { - *S4 - A int -} - -// The X in S6 and S7 annihilate, but they also block the X in S8.S9. -type S5 struct { - S6 - S7 - S8 -} - -type S6 struct { - X int -} - -type S7 S6 - -type S8 struct { - S9 -} - -type S9 struct { - X int - Y int -} - -// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. -type S10 struct { - S11 - S12 - S13 -} - -type S11 struct { - S6 -} - -type S12 struct { - S6 -} - -type S13 struct { - S8 -} - -// The X in S15.S11.S1 and S16.S11.S1 annihilate. -type S14 struct { - S15 - S16 -} - -type S15 struct { - S11 -} - -type S16 struct { - S11 -} - -var fieldTests = []FTest{ - {struct{}{}, "", nil, 0}, - {struct{}{}, "Foo", nil, 0}, - {S0{A: 'a'}, "A", []int{0}, 'a'}, - {S0{}, "D", nil, 0}, - {S1{S0: S0{A: 'a'}}, "A", []int{1, 0}, 'a'}, - {S1{B: 'b'}, "B", []int{0}, 'b'}, - {S1{}, "S0", []int{1}, 0}, - {S1{S0: S0{C: 'c'}}, "C", []int{1, 2}, 'c'}, - {S2{A: 'a'}, "A", []int{0}, 'a'}, - {S2{}, "S1", []int{1}, 0}, - {S2{S1: &S1{B: 'b'}}, "B", []int{1, 0}, 'b'}, - {S2{S1: &S1{S0: S0{C: 'c'}}}, "C", []int{1, 1, 2}, 'c'}, - {S2{}, "D", nil, 0}, - {S3{}, "S1", nil, 0}, - {S3{S2: S2{A: 'a'}}, "A", []int{1, 0}, 'a'}, - {S3{}, "B", nil, 0}, - {S3{D: 'd'}, "D", []int{2}, 0}, - {S3{E: 'e'}, "E", []int{3}, 'e'}, - {S4{A: 'a'}, "A", []int{1}, 'a'}, - {S4{}, "B", nil, 0}, - {S5{}, "X", nil, 0}, - {S5{}, "Y", []int{2, 0, 1}, 0}, - {S10{}, "X", nil, 0}, - {S10{}, "Y", []int{2, 0, 0, 1}, 0}, - {S14{}, "X", nil, 0}, -} - -func TestFieldByIndex(t *testing.T) { - for _, test := range fieldTests { - s := TypeOf(test.s) - f := s.FieldByIndex(test.index) - if f.Name != "" { - if test.index != nil { - if f.Name != test.name { - t.Errorf("%s.%s found; want %s", s.Name(), f.Name, test.name) - } - } else { - t.Errorf("%s.%s found", s.Name(), f.Name) - } - } else if len(test.index) > 0 { - t.Errorf("%s.%s not found", s.Name(), test.name) - } - - if test.value != 0 { - v := ValueOf(test.s).FieldByIndex(test.index) - if v.IsValid() { - if x, ok := v.Interface().(int); ok { - if x != test.value { - t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value) - } - } else { - t.Errorf("%s%v value not an int", s.Name(), test.index) - } - } else { - t.Errorf("%s%v value not found", s.Name(), test.index) - } - } - } -} - -func TestFieldByName(t *testing.T) { - for _, test := range fieldTests { - s := TypeOf(test.s) - f, found := s.FieldByName(test.name) - if found { - if test.index != nil { - // Verify field depth and index. - if len(f.Index) != len(test.index) { - t.Errorf("%s.%s depth %d; want %d: %v vs %v", s.Name(), test.name, len(f.Index), len(test.index), f.Index, test.index) - } else { - for i, x := range f.Index { - if x != test.index[i] { - t.Errorf("%s.%s.Index[%d] is %d; want %d", s.Name(), test.name, i, x, test.index[i]) - } - } - } - } else { - t.Errorf("%s.%s found", s.Name(), f.Name) - } - } else if len(test.index) > 0 { - t.Errorf("%s.%s not found", s.Name(), test.name) - } - - if test.value != 0 { - v := ValueOf(test.s).FieldByName(test.name) - if v.IsValid() { - if x, ok := v.Interface().(int); ok { - if x != test.value { - t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value) - } - } else { - t.Errorf("%s.%s value not an int", s.Name(), test.name) - } - } else { - t.Errorf("%s.%s value not found", s.Name(), test.name) - } - } - } -} - -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((*interface{})(nil)).Elem(), ""}, - {TypeOf((*byte)(nil)), ""}, - {TypeOf((*rune)(nil)), ""}, - {TypeOf((*int64)(nil)), ""}, - {TypeOf(map[string]int{}), ""}, - {TypeOf((*error)(nil)).Elem(), ""}, - } - 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 TestVariadicType(t *testing.T) { - // Test example from Type documentation. - var f func(x int, y ...float64) - typ := TypeOf(f) - if typ.NumIn() == 2 && typ.In(0) == TypeOf(int(0)) { - sl := typ.In(1) - if sl.Kind() == Slice { - if sl.Elem() == TypeOf(0.0) { - // ok - return - } - } - } - - // Failed - t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float64") - s := fmt.Sprintf("have NumIn() = %d", typ.NumIn()) - for i := 0; i < typ.NumIn(); i++ { - s += fmt.Sprintf(", In(%d) = %s", i, typ.In(i)) - } - t.Error(s) -} - -type inner struct { - x int -} - -type outer struct { - y int - inner -} - -func (*inner) m() {} -func (*outer) m() {} - -func TestNestedMethods(t *testing.T) { - 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) - for i := 0; i < typ.NumMethod(); i++ { - m := typ.Method(i) - t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer()) - } - } -} - -type InnerInt struct { - X int -} - -type OuterInt struct { - Y int - InnerInt -} - -func (i *InnerInt) M() int { - return i.X -} - -func TestEmbeddedMethods(t *testing.T) { - typ := TypeOf((*OuterInt)(nil)) - if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*OuterInt).M).Pointer() { - 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()) - } - } - - i := &InnerInt{3} - if v := ValueOf(i).Method(0).Call(nil)[0].Int(); v != 3 { - t.Errorf("i.M() = %d, want 3", v) - } - - o := &OuterInt{1, InnerInt{2}} - if v := ValueOf(o).Method(0).Call(nil)[0].Int(); v != 2 { - t.Errorf("i.M() = %d, want 2", v) - } - - f := (*OuterInt).M - if v := f(o); v != 2 { - t.Errorf("f(o) = %d, want 2", v) - } -} - -func TestPtrTo(t *testing.T) { - var i int - - typ := TypeOf(i) - for i = 0; i < 100; i++ { - typ = PtrTo(typ) - } - for i = 0; i < 100; i++ { - typ = typ.Elem() - } - if typ != TypeOf(i) { - t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, TypeOf(i)) - } -} - -func TestPtrToGC(t *testing.T) { - type T *uintptr - tt := TypeOf(T(nil)) - pt := PtrTo(tt) - const n = 100 - var x []interface{} - for i := 0; i < n; i++ { - v := New(pt) - p := new(*uintptr) - *p = new(uintptr) - **p = uintptr(i) - v.Elem().Set(ValueOf(p).Convert(pt)) - x = append(x, v.Interface()) - } - runtime.GC() - - for i, xi := range x { - k := ValueOf(xi).Elem().Elem().Elem().Interface().(uintptr) - if k != uintptr(i) { - t.Errorf("lost x[%d] = %d, want %d", i, k, i) - } - } -} - -func TestAddr(t *testing.T) { - var p struct { - X, Y int - } - - v := ValueOf(&p) - v = v.Elem() - v = v.Addr() - v = v.Elem() - v = v.Field(0) - v.SetInt(2) - if p.X != 2 { - t.Errorf("Addr.Elem.Set failed to set value") - } - - // Again but take address of the ValueOf value. - // Exercises generation of PtrTypes not present in the binary. - q := &p - v = ValueOf(&q).Elem() - v = v.Addr() - v = v.Elem() - v = v.Elem() - v = v.Addr() - v = v.Elem() - v = v.Field(0) - v.SetInt(3) - if p.X != 3 { - t.Errorf("Addr.Elem.Set failed to set value") - } - - // Starting without pointer we should get changed value - // in interface. - qq := p - v = ValueOf(&qq).Elem() - v0 := v - v = v.Addr() - v = v.Elem() - v = v.Field(0) - v.SetInt(4) - if p.X != 3 { // should be unchanged from last time - t.Errorf("somehow value Set changed original p") - } - p = v0.Interface().(struct { - X, Y int - }) - if p.X != 4 { - t.Errorf("Addr.Elem.Set valued to set value in top value") - } - - // Verify that taking the address of a type gives us a pointer - // which we can convert back using the usual interface - // notation. - var s struct { - B *bool - } - ps := ValueOf(&s).Elem().Field(0).Addr().Interface() - *(ps.(**bool)) = new(bool) - if s.B == nil { - t.Errorf("Addr.Interface direct assignment failed") - } -} - -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 interface{} - var v Value - i = 42 + j - v = ValueOf(i) - if int(v.Int()) != 42+j { - panic("wrong int") - } - }) -} - -func TestSmallNegativeInt(t *testing.T) { - i := int16(-1) - v := ValueOf(i) - if v.Int() != -1 { - t.Errorf("int16(-1).Int() returned %v", v.Int()) - } -} - -func TestIndex(t *testing.T) { - xs := []byte{1, 2, 3, 4, 5, 6, 7, 8} - v := ValueOf(xs).Index(3).Interface().(byte) - if v != xs[3] { - t.Errorf("xs.Index(3) = %v; expected %v", v, xs[3]) - } - xa := [8]byte{10, 20, 30, 40, 50, 60, 70, 80} - v = ValueOf(xa).Index(2).Interface().(byte) - if v != xa[2] { - t.Errorf("xa.Index(2) = %v; expected %v", v, xa[2]) - } - s := "0123456789" - v = ValueOf(s).Index(3).Interface().(byte) - if v != s[3] { - t.Errorf("s.Index(3) = %v; expected %v", v, s[3]) - } -} - -func TestSlice(t *testing.T) { - xs := []int{1, 2, 3, 4, 5, 6, 7, 8} - v := ValueOf(xs).Slice(3, 5).Interface().([]int) - if len(v) != 2 { - t.Errorf("len(xs.Slice(3, 5)) = %d", len(v)) - } - if cap(v) != 5 { - t.Errorf("cap(xs.Slice(3, 5)) = %d", cap(v)) - } - if !DeepEqual(v[0:5], xs[3:]) { - t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5]) - } - xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} - v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int) - if len(v) != 3 { - t.Errorf("len(xa.Slice(2, 5)) = %d", len(v)) - } - if cap(v) != 6 { - t.Errorf("cap(xa.Slice(2, 5)) = %d", cap(v)) - } - if !DeepEqual(v[0:6], xa[2:]) { - t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6]) - } - s := "0123456789" - vs := ValueOf(s).Slice(3, 5).Interface().(string) - if vs != s[3:5] { - t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5]) - } -} - -func TestSlice3(t *testing.T) { - xs := []int{1, 2, 3, 4, 5, 6, 7, 8} - v := ValueOf(xs).Slice3(3, 5, 7).Interface().([]int) - if len(v) != 2 { - t.Errorf("len(xs.Slice3(3, 5, 7)) = %d", len(v)) - } - if cap(v) != 4 { - t.Errorf("cap(xs.Slice3(3, 5, 7)) = %d", cap(v)) - } - if !DeepEqual(v[0:4], xs[3:7:7]) { - t.Errorf("xs.Slice3(3, 5, 7)[0:4] = %v", v[0:4]) - } - rv := ValueOf(&xs).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 1) }) - shouldPanic(func() { rv.Slice3(1, 1, 11) }) - shouldPanic(func() { rv.Slice3(2, 2, 1) }) - - xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} - v = ValueOf(&xa).Elem().Slice3(2, 5, 6).Interface().([]int) - if len(v) != 3 { - t.Errorf("len(xa.Slice(2, 5, 6)) = %d", len(v)) - } - if cap(v) != 4 { - t.Errorf("cap(xa.Slice(2, 5, 6)) = %d", cap(v)) - } - if !DeepEqual(v[0:4], xa[2:6:6]) { - t.Errorf("xs.Slice(2, 5, 6)[0:4] = %v", v[0:4]) - } - rv = ValueOf(&xa).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 1) }) - shouldPanic(func() { rv.Slice3(1, 1, 11) }) - shouldPanic(func() { rv.Slice3(2, 2, 1) }) - - s := "hello world" - rv = ValueOf(&s).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 3) }) -} - -func TestSetLenCap(t *testing.T) { - xs := []int{1, 2, 3, 4, 5, 6, 7, 8} - xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} - - vs := ValueOf(&xs).Elem() - shouldPanic(func() { vs.SetLen(10) }) - shouldPanic(func() { vs.SetCap(10) }) - shouldPanic(func() { vs.SetLen(-1) }) - shouldPanic(func() { vs.SetCap(-1) }) - shouldPanic(func() { vs.SetCap(6) }) // smaller than len - vs.SetLen(5) - if len(xs) != 5 || cap(xs) != 8 { - t.Errorf("after SetLen(5), len, cap = %d, %d, want 5, 8", len(xs), cap(xs)) - } - vs.SetCap(6) - if len(xs) != 5 || cap(xs) != 6 { - t.Errorf("after SetCap(6), len, cap = %d, %d, want 5, 6", len(xs), cap(xs)) - } - vs.SetCap(5) - if len(xs) != 5 || cap(xs) != 5 { - t.Errorf("after SetCap(5), len, cap = %d, %d, want 5, 5", len(xs), cap(xs)) - } - shouldPanic(func() { vs.SetCap(4) }) // smaller than len - shouldPanic(func() { vs.SetLen(6) }) // bigger than cap - - va := ValueOf(&xa).Elem() - shouldPanic(func() { va.SetLen(8) }) - shouldPanic(func() { va.SetCap(8) }) -} - -func TestVariadic(t *testing.T) { - var b bytes.Buffer - V := ValueOf - - b.Reset() - V(fmt.Fprintf).Call([]Value{V(&b), V("%s, %d world"), V("hello"), V(42)}) - if b.String() != "hello, 42 world" { - t.Errorf("after Fprintf Call: %q != %q", b.String(), "hello 42 world") - } - - b.Reset() - V(fmt.Fprintf).CallSlice([]Value{V(&b), V("%s, %d world"), V([]interface{}{"hello", 42})}) - if b.String() != "hello, 42 world" { - t.Errorf("after Fprintf CallSlice: %q != %q", b.String(), "hello 42 world") - } -} - -func TestFuncArg(t *testing.T) { - f1 := func(i int, f func(int) int) int { return f(i) } - f2 := func(i int) int { return i + 1 } - r := ValueOf(f1).Call([]Value{ValueOf(100), ValueOf(f2)}) - if r[0].Int() != 101 { - t.Errorf("function returned %d, want 101", r[0].Int()) - } -} - -var tagGetTests = []struct { - Tag StructTag - Key string - Value string -}{ - {`protobuf:"PB(1,2)"`, `protobuf`, `PB(1,2)`}, - {`protobuf:"PB(1,2)"`, `foo`, ``}, - {`protobuf:"PB(1,2)"`, `rotobuf`, ``}, - {`protobuf:"PB(1,2)" json:"name"`, `json`, `name`}, - {`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`}, -} - -func TestTagGet(t *testing.T) { - for _, tt := range tagGetTests { - if v := tt.Tag.Get(tt.Key); v != tt.Value { - t.Errorf("StructTag(%#q).Get(%#q) = %#q, want %#q", tt.Tag, tt.Key, v, tt.Value) - } - } -} - -func TestBytes(t *testing.T) { - type B []byte - x := B{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]) - } -} - -func TestSetBytes(t *testing.T) { - type B []byte - var x B - y := []byte{1, 2, 3, 4} - ValueOf(&x).Elem().SetBytes(y) - 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 Private struct { - x int - y **int -} - -func (p *Private) m() { -} - -type Public struct { - X int - Y **int -} - -func (p *Public) M() { -} - -func TestUnexported(t *testing.T) { - var pub Public - v := ValueOf(&pub) - isValid(v.Elem().Field(0)) - isValid(v.Elem().Field(1)) - isValid(v.Elem().FieldByName("X")) - isValid(v.Elem().FieldByName("Y")) - isValid(v.Type().Method(0).Func) - isNonNil(v.Elem().Field(0).Interface()) - isNonNil(v.Elem().Field(1).Interface()) - isNonNil(v.Elem().FieldByName("X").Interface()) - isNonNil(v.Elem().FieldByName("Y").Interface()) - isNonNil(v.Type().Method(0).Func.Interface()) - - var priv Private - v = ValueOf(&priv) - isValid(v.Elem().Field(0)) - 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() }) -} - -func shouldPanic(f func()) { - defer func() { - if recover() == nil { - panic("did not panic") - } - }() - f() -} - -func isNonNil(x interface{}) { - if x == nil { - panic("nil interface") - } -} - -func isValid(v Value) { - if !v.IsValid() { - panic("zero Value") - } -} - -func TestAlias(t *testing.T) { - x := string("hello") - v := ValueOf(&x).Elem() - oldvalue := v.Interface() - v.SetString("world") - newvalue := v.Interface() - - if oldvalue != "hello" || newvalue != "world" { - t.Errorf("aliasing: old=%q new=%q, want hello, world", oldvalue, newvalue) - } -} - -var V = ValueOf - -func EmptyInterfaceV(x interface{}) Value { - return ValueOf(&x).Elem() -} - -func ReaderV(x io.Reader) Value { - return ValueOf(&x).Elem() -} - -func ReadWriterV(x io.ReadWriter) Value { - return ValueOf(&x).Elem() -} - -type Empty struct{} -type MyString string -type MyBytes []byte -type MyRunes []int32 -type MyFunc func() -type MyByte byte - -var convertTests = []struct { - in Value - out Value -}{ - // numbers - /* - Edit .+1,/\*\//-1>cat >/tmp/x.go && go run /tmp/x.go - - package main - - import "fmt" - - var numbers = []string{ - "int8", "uint8", "int16", "uint16", - "int32", "uint32", "int64", "uint64", - "int", "uint", "uintptr", - "float32", "float64", - } - - func main() { - // all pairs but in an unusual order, - // to emit all the int8, uint8 cases - // before n grows too big. - n := 1 - for i, f := range numbers { - for _, g := range numbers[i:] { - fmt.Printf("\t{V(%s(%d)), V(%s(%d))},\n", f, n, g, n) - n++ - if f != g { - fmt.Printf("\t{V(%s(%d)), V(%s(%d))},\n", g, n, f, n) - n++ - } - } - } - } - */ - {V(int8(1)), V(int8(1))}, - {V(int8(2)), V(uint8(2))}, - {V(uint8(3)), V(int8(3))}, - {V(int8(4)), V(int16(4))}, - {V(int16(5)), V(int8(5))}, - {V(int8(6)), V(uint16(6))}, - {V(uint16(7)), V(int8(7))}, - {V(int8(8)), V(int32(8))}, - {V(int32(9)), V(int8(9))}, - {V(int8(10)), V(uint32(10))}, - {V(uint32(11)), V(int8(11))}, - {V(int8(12)), V(int64(12))}, - {V(int64(13)), V(int8(13))}, - {V(int8(14)), V(uint64(14))}, - {V(uint64(15)), V(int8(15))}, - {V(int8(16)), V(int(16))}, - {V(int(17)), V(int8(17))}, - {V(int8(18)), V(uint(18))}, - {V(uint(19)), V(int8(19))}, - {V(int8(20)), V(uintptr(20))}, - {V(uintptr(21)), V(int8(21))}, - {V(int8(22)), V(float32(22))}, - {V(float32(23)), V(int8(23))}, - {V(int8(24)), V(float64(24))}, - {V(float64(25)), V(int8(25))}, - {V(uint8(26)), V(uint8(26))}, - {V(uint8(27)), V(int16(27))}, - {V(int16(28)), V(uint8(28))}, - {V(uint8(29)), V(uint16(29))}, - {V(uint16(30)), V(uint8(30))}, - {V(uint8(31)), V(int32(31))}, - {V(int32(32)), V(uint8(32))}, - {V(uint8(33)), V(uint32(33))}, - {V(uint32(34)), V(uint8(34))}, - {V(uint8(35)), V(int64(35))}, - {V(int64(36)), V(uint8(36))}, - {V(uint8(37)), V(uint64(37))}, - {V(uint64(38)), V(uint8(38))}, - {V(uint8(39)), V(int(39))}, - {V(int(40)), V(uint8(40))}, - {V(uint8(41)), V(uint(41))}, - {V(uint(42)), V(uint8(42))}, - {V(uint8(43)), V(uintptr(43))}, - {V(uintptr(44)), V(uint8(44))}, - {V(uint8(45)), V(float32(45))}, - {V(float32(46)), V(uint8(46))}, - {V(uint8(47)), V(float64(47))}, - {V(float64(48)), V(uint8(48))}, - {V(int16(49)), V(int16(49))}, - {V(int16(50)), V(uint16(50))}, - {V(uint16(51)), V(int16(51))}, - {V(int16(52)), V(int32(52))}, - {V(int32(53)), V(int16(53))}, - {V(int16(54)), V(uint32(54))}, - {V(uint32(55)), V(int16(55))}, - {V(int16(56)), V(int64(56))}, - {V(int64(57)), V(int16(57))}, - {V(int16(58)), V(uint64(58))}, - {V(uint64(59)), V(int16(59))}, - {V(int16(60)), V(int(60))}, - {V(int(61)), V(int16(61))}, - {V(int16(62)), V(uint(62))}, - {V(uint(63)), V(int16(63))}, - {V(int16(64)), V(uintptr(64))}, - {V(uintptr(65)), V(int16(65))}, - {V(int16(66)), V(float32(66))}, - {V(float32(67)), V(int16(67))}, - {V(int16(68)), V(float64(68))}, - {V(float64(69)), V(int16(69))}, - {V(uint16(70)), V(uint16(70))}, - {V(uint16(71)), V(int32(71))}, - {V(int32(72)), V(uint16(72))}, - {V(uint16(73)), V(uint32(73))}, - {V(uint32(74)), V(uint16(74))}, - {V(uint16(75)), V(int64(75))}, - {V(int64(76)), V(uint16(76))}, - {V(uint16(77)), V(uint64(77))}, - {V(uint64(78)), V(uint16(78))}, - {V(uint16(79)), V(int(79))}, - {V(int(80)), V(uint16(80))}, - {V(uint16(81)), V(uint(81))}, - {V(uint(82)), V(uint16(82))}, - {V(uint16(83)), V(uintptr(83))}, - {V(uintptr(84)), V(uint16(84))}, - {V(uint16(85)), V(float32(85))}, - {V(float32(86)), V(uint16(86))}, - {V(uint16(87)), V(float64(87))}, - {V(float64(88)), V(uint16(88))}, - {V(int32(89)), V(int32(89))}, - {V(int32(90)), V(uint32(90))}, - {V(uint32(91)), V(int32(91))}, - {V(int32(92)), V(int64(92))}, - {V(int64(93)), V(int32(93))}, - {V(int32(94)), V(uint64(94))}, - {V(uint64(95)), V(int32(95))}, - {V(int32(96)), V(int(96))}, - {V(int(97)), V(int32(97))}, - {V(int32(98)), V(uint(98))}, - {V(uint(99)), V(int32(99))}, - {V(int32(100)), V(uintptr(100))}, - {V(uintptr(101)), V(int32(101))}, - {V(int32(102)), V(float32(102))}, - {V(float32(103)), V(int32(103))}, - {V(int32(104)), V(float64(104))}, - {V(float64(105)), V(int32(105))}, - {V(uint32(106)), V(uint32(106))}, - {V(uint32(107)), V(int64(107))}, - {V(int64(108)), V(uint32(108))}, - {V(uint32(109)), V(uint64(109))}, - {V(uint64(110)), V(uint32(110))}, - {V(uint32(111)), V(int(111))}, - {V(int(112)), V(uint32(112))}, - {V(uint32(113)), V(uint(113))}, - {V(uint(114)), V(uint32(114))}, - {V(uint32(115)), V(uintptr(115))}, - {V(uintptr(116)), V(uint32(116))}, - {V(uint32(117)), V(float32(117))}, - {V(float32(118)), V(uint32(118))}, - {V(uint32(119)), V(float64(119))}, - {V(float64(120)), V(uint32(120))}, - {V(int64(121)), V(int64(121))}, - {V(int64(122)), V(uint64(122))}, - {V(uint64(123)), V(int64(123))}, - {V(int64(124)), V(int(124))}, - {V(int(125)), V(int64(125))}, - {V(int64(126)), V(uint(126))}, - {V(uint(127)), V(int64(127))}, - {V(int64(128)), V(uintptr(128))}, - {V(uintptr(129)), V(int64(129))}, - {V(int64(130)), V(float32(130))}, - {V(float32(131)), V(int64(131))}, - {V(int64(132)), V(float64(132))}, - {V(float64(133)), V(int64(133))}, - {V(uint64(134)), V(uint64(134))}, - {V(uint64(135)), V(int(135))}, - {V(int(136)), V(uint64(136))}, - {V(uint64(137)), V(uint(137))}, - {V(uint(138)), V(uint64(138))}, - {V(uint64(139)), V(uintptr(139))}, - {V(uintptr(140)), V(uint64(140))}, - {V(uint64(141)), V(float32(141))}, - {V(float32(142)), V(uint64(142))}, - {V(uint64(143)), V(float64(143))}, - {V(float64(144)), V(uint64(144))}, - {V(int(145)), V(int(145))}, - {V(int(146)), V(uint(146))}, - {V(uint(147)), V(int(147))}, - {V(int(148)), V(uintptr(148))}, - {V(uintptr(149)), V(int(149))}, - {V(int(150)), V(float32(150))}, - {V(float32(151)), V(int(151))}, - {V(int(152)), V(float64(152))}, - {V(float64(153)), V(int(153))}, - {V(uint(154)), V(uint(154))}, - {V(uint(155)), V(uintptr(155))}, - {V(uintptr(156)), V(uint(156))}, - {V(uint(157)), V(float32(157))}, - {V(float32(158)), V(uint(158))}, - {V(uint(159)), V(float64(159))}, - {V(float64(160)), V(uint(160))}, - {V(uintptr(161)), V(uintptr(161))}, - {V(uintptr(162)), V(float32(162))}, - {V(float32(163)), V(uintptr(163))}, - {V(uintptr(164)), V(float64(164))}, - {V(float64(165)), V(uintptr(165))}, - {V(float32(166)), V(float32(166))}, - {V(float32(167)), V(float64(167))}, - {V(float64(168)), V(float32(168))}, - {V(float64(169)), V(float64(169))}, - - // truncation - {V(float64(1.5)), V(int(1))}, - - // complex - {V(complex64(1i)), V(complex64(1i))}, - {V(complex64(2i)), V(complex128(2i))}, - {V(complex128(3i)), V(complex64(3i))}, - {V(complex128(4i)), V(complex128(4i))}, - - // string - {V(string("hello")), V(string("hello"))}, - {V(string("bytes1")), V([]byte("bytes1"))}, - {V([]byte("bytes2")), V(string("bytes2"))}, - {V([]byte("bytes3")), V([]byte("bytes3"))}, - {V(string("runes♝")), V([]rune("runes♝"))}, - {V([]rune("runes♕")), V(string("runes♕"))}, - {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V(int('a')), V(string("a"))}, - {V(int8('a')), V(string("a"))}, - {V(int16('a')), V(string("a"))}, - {V(int32('a')), V(string("a"))}, - {V(int64('a')), V(string("a"))}, - {V(uint('a')), V(string("a"))}, - {V(uint8('a')), V(string("a"))}, - {V(uint16('a')), V(string("a"))}, - {V(uint32('a')), V(string("a"))}, - {V(uint64('a')), V(string("a"))}, - {V(uintptr('a')), V(string("a"))}, - {V(int(-1)), V(string("\uFFFD"))}, - {V(int8(-2)), V(string("\uFFFD"))}, - {V(int16(-3)), V(string("\uFFFD"))}, - {V(int32(-4)), V(string("\uFFFD"))}, - {V(int64(-5)), V(string("\uFFFD"))}, - {V(uint(0x110001)), V(string("\uFFFD"))}, - {V(uint32(0x110002)), V(string("\uFFFD"))}, - {V(uint64(0x110003)), V(string("\uFFFD"))}, - {V(uintptr(0x110004)), V(string("\uFFFD"))}, - - // named string - {V(MyString("hello")), V(string("hello"))}, - {V(string("hello")), V(MyString("hello"))}, - {V(string("hello")), V(string("hello"))}, - {V(MyString("hello")), V(MyString("hello"))}, - {V(MyString("bytes1")), V([]byte("bytes1"))}, - {V([]byte("bytes2")), V(MyString("bytes2"))}, - {V([]byte("bytes3")), V([]byte("bytes3"))}, - {V(MyString("runes♝")), V([]rune("runes♝"))}, - {V([]rune("runes♕")), V(MyString("runes♕"))}, - {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V([]rune("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, - {V(MyRunes("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V(int('a')), V(MyString("a"))}, - {V(int8('a')), V(MyString("a"))}, - {V(int16('a')), V(MyString("a"))}, - {V(int32('a')), V(MyString("a"))}, - {V(int64('a')), V(MyString("a"))}, - {V(uint('a')), V(MyString("a"))}, - {V(uint8('a')), V(MyString("a"))}, - {V(uint16('a')), V(MyString("a"))}, - {V(uint32('a')), V(MyString("a"))}, - {V(uint64('a')), V(MyString("a"))}, - {V(uintptr('a')), V(MyString("a"))}, - {V(int(-1)), V(MyString("\uFFFD"))}, - {V(int8(-2)), V(MyString("\uFFFD"))}, - {V(int16(-3)), V(MyString("\uFFFD"))}, - {V(int32(-4)), V(MyString("\uFFFD"))}, - {V(int64(-5)), V(MyString("\uFFFD"))}, - {V(uint(0x110001)), V(MyString("\uFFFD"))}, - {V(uint32(0x110002)), V(MyString("\uFFFD"))}, - {V(uint64(0x110003)), V(MyString("\uFFFD"))}, - {V(uintptr(0x110004)), V(MyString("\uFFFD"))}, - - // named []byte - {V(string("bytes1")), V(MyBytes("bytes1"))}, - {V(MyBytes("bytes2")), V(string("bytes2"))}, - {V(MyBytes("bytes3")), V(MyBytes("bytes3"))}, - {V(MyString("bytes1")), V(MyBytes("bytes1"))}, - {V(MyBytes("bytes2")), V(MyString("bytes2"))}, - - // named []rune - {V(string("runes♝")), V(MyRunes("runes♝"))}, - {V(MyRunes("runes♕")), V(string("runes♕"))}, - {V(MyRunes("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, - {V(MyString("runes♝")), V(MyRunes("runes♝"))}, - {V(MyRunes("runes♕")), V(MyString("runes♕"))}, - - // named types and equal underlying types - {V(new(int)), V(new(integer))}, - {V(new(integer)), V(new(int))}, - {V(Empty{}), V(struct{}{})}, - {V(new(Empty)), V(new(struct{}))}, - {V(struct{}{}), V(Empty{})}, - {V(new(struct{})), V(new(Empty))}, - {V(Empty{}), V(Empty{})}, - {V(MyBytes{}), V([]byte{})}, - {V([]byte{}), V(MyBytes{})}, - {V((func())(nil)), V(MyFunc(nil))}, - {V((MyFunc)(nil)), V((func())(nil))}, - - // can convert *byte and *MyByte - {V((*byte)(nil)), V((*MyByte)(nil))}, - {V((*MyByte)(nil)), V((*byte)(nil))}, - - // cannot convert mismatched array sizes - {V([2]byte{}), V([2]byte{})}, - {V([3]byte{}), V([3]byte{})}, - - // cannot convert other instances - {V((**byte)(nil)), V((**byte)(nil))}, - {V((**MyByte)(nil)), V((**MyByte)(nil))}, - {V((chan byte)(nil)), V((chan byte)(nil))}, - {V((chan MyByte)(nil)), V((chan MyByte)(nil))}, - {V(([]byte)(nil)), V(([]byte)(nil))}, - {V(([]MyByte)(nil)), V(([]MyByte)(nil))}, - {V((map[int]byte)(nil)), V((map[int]byte)(nil))}, - {V((map[int]MyByte)(nil)), V((map[int]MyByte)(nil))}, - {V((map[byte]int)(nil)), V((map[byte]int)(nil))}, - {V((map[MyByte]int)(nil)), V((map[MyByte]int)(nil))}, - {V([2]byte{}), V([2]byte{})}, - {V([2]MyByte{}), V([2]MyByte{})}, - - // other - {V((***int)(nil)), V((***int)(nil))}, - {V((***byte)(nil)), V((***byte)(nil))}, - {V((***int32)(nil)), V((***int32)(nil))}, - {V((***int64)(nil)), V((***int64)(nil))}, - {V((chan int)(nil)), V((<-chan int)(nil))}, - {V((chan int)(nil)), V((chan<- int)(nil))}, - {V((chan string)(nil)), V((<-chan string)(nil))}, - {V((chan string)(nil)), V((chan<- string)(nil))}, - {V((chan byte)(nil)), V((chan byte)(nil))}, - {V((chan MyByte)(nil)), V((chan MyByte)(nil))}, - {V((map[int]bool)(nil)), V((map[int]bool)(nil))}, - {V((map[int]byte)(nil)), V((map[int]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(io.Reader)), V(new(io.Reader))}, - {V(new(io.Writer)), V(new(io.Writer))}, - - // interfaces - {V(int(1)), EmptyInterfaceV(int(1))}, - {V(string("hello")), EmptyInterfaceV(string("hello"))}, - {V(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, - {ReadWriterV(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, - {V(new(bytes.Buffer)), ReadWriterV(new(bytes.Buffer))}, -} - -func TestConvert(t *testing.T) { - canConvert := map[[2]Type]bool{} - all := map[Type]bool{} - - for _, tt := range convertTests { - t1 := tt.in.Type() - if !t1.ConvertibleTo(t1) { - t.Errorf("(%s).ConvertibleTo(%s) = false, want true", t1, t1) - continue - } - - t2 := tt.out.Type() - if !t1.ConvertibleTo(t2) { - t.Errorf("(%s).ConvertibleTo(%s) = false, want true", t1, t2) - continue - } - - all[t1] = true - all[t2] = true - canConvert[[2]Type{t1, t2}] = true - - // vout1 represents the in value converted to the in type. - v1 := tt.in - vout1 := v1.Convert(t1) - out1 := vout1.Interface() - if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) { - t.Errorf("ValueOf(%T(%[1]v)).Convert(%s) = %T(%[3]v), want %T(%[4]v)", tt.in.Interface(), t1, out1, tt.in.Interface()) - } - - // vout2 represents the in value converted to the out type. - vout2 := v1.Convert(t2) - out2 := vout2.Interface() - if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) { - t.Errorf("ValueOf(%T(%[1]v)).Convert(%s) = %T(%[3]v), want %T(%[4]v)", tt.in.Interface(), t2, out2, tt.out.Interface()) - } - - // vout3 represents a new value of the out type, set to vout2. This makes - // sure the converted value vout2 is really usable as a regular value. - vout3 := New(t2).Elem() - vout3.Set(vout2) - out3 := vout3.Interface() - if vout3.Type() != tt.out.Type() || !DeepEqual(out3, tt.out.Interface()) { - t.Errorf("Set(ValueOf(%T(%[1]v)).Convert(%s)) = %T(%[3]v), want %T(%[4]v)", tt.in.Interface(), t2, out3, tt.out.Interface()) - } - - if IsRO(v1) { - t.Errorf("table entry %v is RO, should not be", v1) - } - if IsRO(vout1) { - t.Errorf("self-conversion output %v is RO, should not be", vout1) - } - if IsRO(vout2) { - t.Errorf("conversion output %v is RO, should not be", vout2) - } - if IsRO(vout3) { - t.Errorf("set(conversion output) %v is RO, should not be", vout3) - } - if !IsRO(MakeRO(v1).Convert(t1)) { - t.Errorf("RO self-conversion output %v is not RO, should be", v1) - } - if !IsRO(MakeRO(v1).Convert(t2)) { - t.Errorf("RO conversion output %v is not RO, should be", v1) - } - } - - // Assume that of all the types we saw during the tests, - // if there wasn't an explicit entry for a conversion between - // a pair of types, then it's not to be allowed. This checks for - // things like 'int64' converting to '*int'. - for t1 := range all { - for t2 := range all { - expectOK := t1 == t2 || canConvert[[2]Type{t1, t2}] || t2.Kind() == Interface && t2.NumMethod() == 0 - if ok := t1.ConvertibleTo(t2); ok != expectOK { - t.Errorf("(%s).ConvertibleTo(%s) = %v, want %v", t1, t2, ok, expectOK) - } - } - } -} - -func TestOverflow(t *testing.T) { - if ovf := V(float64(0)).OverflowFloat(1e300); ovf { - t.Errorf("%v wrongly overflows float64", 1e300) - } - - maxFloat32 := float64((1<<24 - 1) << (127 - 23)) - if ovf := V(float32(0)).OverflowFloat(maxFloat32); ovf { - t.Errorf("%v wrongly overflows float32", maxFloat32) - } - ovfFloat32 := float64((1<<24-1)<<(127-23) + 1<<(127-52)) - if ovf := V(float32(0)).OverflowFloat(ovfFloat32); !ovf { - t.Errorf("%v should overflow float32", ovfFloat32) - } - if ovf := V(float32(0)).OverflowFloat(-ovfFloat32); !ovf { - t.Errorf("%v should overflow float32", -ovfFloat32) - } - - maxInt32 := int64(0x7fffffff) - if ovf := V(int32(0)).OverflowInt(maxInt32); ovf { - t.Errorf("%v wrongly overflows int32", maxInt32) - } - if ovf := V(int32(0)).OverflowInt(-1 << 31); ovf { - t.Errorf("%v wrongly overflows int32", -int64(1)<<31) - } - ovfInt32 := int64(1 << 31) - if ovf := V(int32(0)).OverflowInt(ovfInt32); !ovf { - t.Errorf("%v should overflow int32", ovfInt32) - } - - maxUint32 := uint64(0xffffffff) - if ovf := V(uint32(0)).OverflowUint(maxUint32); ovf { - t.Errorf("%v wrongly overflows uint32", maxUint32) - } - ovfUint32 := uint64(1 << 32) - if ovf := V(uint32(0)).OverflowUint(ovfUint32); !ovf { - t.Errorf("%v should overflow uint32", ovfUint32) - } -} - -func checkSameType(t *testing.T, x, y interface{}) { - if TypeOf(x) != TypeOf(y) { - t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y)) - } -} - -func TestArrayOf(t *testing.T) { - // check construction and use of type not in binary - type T int - at := ArrayOf(10, TypeOf(T(1))) - v := New(at).Elem() - for i := 0; i < v.Len(); i++ { - v.Index(i).Set(ValueOf(T(i))) - } - s := fmt.Sprint(v.Interface()) - want := "[0 1 2 3 4 5 6 7 8 9]" - if s != want { - t.Errorf("constructed array = %s, want %s", s, want) - } - - // check that type already in binary is found - checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) -} - -func TestSliceOf(t *testing.T) { - // check construction and use of type not in binary - type T int - st := SliceOf(TypeOf(T(1))) - v := MakeSlice(st, 10, 10) - runtime.GC() - for i := 0; i < v.Len(); i++ { - v.Index(i).Set(ValueOf(T(i))) - runtime.GC() - } - s := fmt.Sprint(v.Interface()) - want := "[0 1 2 3 4 5 6 7 8 9]" - if s != want { - t.Errorf("constructed slice = %s, want %s", s, want) - } - - // check that type already in binary is found - type T1 int - checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{}) -} - -func TestSliceOverflow(t *testing.T) { - // check that MakeSlice panics when size of slice overflows uint - const S = 1e6 - s := uint(S) - l := (1<<(unsafe.Sizeof((*byte)(nil))*8)-1)/s + 1 - if l*s >= s { - t.Fatal("slice size does not overflow") - } - var x [S]byte - st := SliceOf(TypeOf(x)) - defer func() { - err := recover() - if err == nil { - t.Fatal("slice overflow does not panic") - } - }() - MakeSlice(st, int(l), int(l)) -} - -func TestSliceOfGC(t *testing.T) { - type T *uintptr - tt := TypeOf(T(nil)) - st := SliceOf(tt) - const n = 100 - var x []interface{} - for i := 0; i < n; i++ { - v := MakeSlice(st, n, n) - for j := 0; j < v.Len(); j++ { - p := new(uintptr) - *p = uintptr(i*n + j) - v.Index(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.Len(); j++ { - k := v.Index(j).Elem().Interface() - if k != uintptr(i*n+j) { - t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j) - } - } - } -} - -func TestChanOf(t *testing.T) { - // check construction and use of type not in binary - type T string - ct := ChanOf(BothDir, TypeOf(T(""))) - v := MakeChan(ct, 2) - runtime.GC() - v.Send(ValueOf(T("hello"))) - runtime.GC() - v.Send(ValueOf(T("world"))) - runtime.GC() - - sv1, _ := v.Recv() - sv2, _ := v.Recv() - s1 := sv1.String() - s2 := sv2.String() - if s1 != "hello" || s2 != "world" { - t.Errorf("constructed chan: have %q, %q, want %q, %q", s1, s2, "hello", "world") - } - - // check that type already in binary is found - type T1 int - checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) -} - -func TestChanOfGC(t *testing.T) { - done := make(chan bool, 1) - go func() { - select { - case <-done: - case <-time.After(5 * time.Second): - panic("deadlock in TestChanOfGC") - } - }() - - defer func() { - done <- true - }() - - type T *uintptr - tt := TypeOf(T(nil)) - ct := ChanOf(BothDir, tt) - - // NOTE: The garbage collector handles allocated channels specially, - // 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{} - for i := 0; i < n; i++ { - v := MakeChan(ct, n) - for j := 0; j < n; j++ { - p := new(uintptr) - *p = uintptr(i*n + j) - v.Send(ValueOf(p).Convert(tt)) - } - pv := New(ct) - pv.Elem().Set(v) - x = append(x, pv.Interface()) - } - runtime.GC() - - for i, xi := range x { - v := ValueOf(xi).Elem() - for j := 0; j < n; j++ { - pv, _ := v.Recv() - k := pv.Elem().Interface() - if k != uintptr(i*n+j) { - t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j) - } - } - } -} - -func TestMapOf(t *testing.T) { - // check construction and use of type not in binary - type K string - type V float64 - - v := MakeMap(MapOf(TypeOf(K("")), TypeOf(V(0)))) - runtime.GC() - v.SetMapIndex(ValueOf(K("a")), ValueOf(V(1))) - runtime.GC() - - s := fmt.Sprint(v.Interface()) - want := "map[a:1]" - if s != want { - t.Errorf("constructed map = %s, want %s", s, want) - } - - // check that type already in binary is found - checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil)) - - // check that invalid key type panics - shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) }) -} - -func TestMapOfGCKeys(t *testing.T) { - type T *uintptr - tt := TypeOf(T(nil)) - mt := MapOf(tt, TypeOf(false)) - - // NOTE: The garbage collector handles allocated maps specially, - // 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{} - for i := 0; i < n; i++ { - v := MakeMap(mt) - for j := 0; j < n; j++ { - p := new(uintptr) - *p = uintptr(i*n + j) - v.SetMapIndex(ValueOf(p).Convert(tt), ValueOf(true)) - } - pv := New(mt) - pv.Elem().Set(v) - x = append(x, pv.Interface()) - } - runtime.GC() - - for i, xi := range x { - v := ValueOf(xi).Elem() - var out []int - for _, kv := range v.MapKeys() { - out = append(out, int(kv.Elem().Interface().(uintptr))) - } - sort.Ints(out) - for j, k := range out { - if k != i*n+j { - t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j) - } - } - } -} - -func TestMapOfGCValues(t *testing.T) { - type T *uintptr - tt := TypeOf(T(nil)) - mt := MapOf(TypeOf(1), tt) - - // NOTE: The garbage collector handles allocated maps specially, - // 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{} - for i := 0; i < n; i++ { - v := MakeMap(mt) - for j := 0; j < n; j++ { - p := new(uintptr) - *p = uintptr(i*n + j) - v.SetMapIndex(ValueOf(j), ValueOf(p).Convert(tt)) - } - pv := New(mt) - pv.Elem().Set(v) - x = append(x, pv.Interface()) - } - runtime.GC() - - for i, xi := range x { - v := ValueOf(xi).Elem() - for j := 0; j < n; j++ { - k := v.MapIndex(ValueOf(j)).Elem().Interface().(uintptr) - if k != uintptr(i*n+j) { - t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j) - } - } - } -} - -type B1 struct { - X int - Y int - Z int -} - -func BenchmarkFieldByName1(b *testing.B) { - t := TypeOf(B1{}) - for i := 0; i < b.N; i++ { - t.FieldByName("Z") - } -} - -func BenchmarkFieldByName2(b *testing.B) { - t := TypeOf(S3{}) - for i := 0; i < b.N; i++ { - t.FieldByName("B") - } -} - -type R0 struct { - *R1 - *R2 - *R3 - *R4 -} - -type R1 struct { - *R5 - *R6 - *R7 - *R8 -} - -type R2 R1 -type R3 R1 -type R4 R1 - -type R5 struct { - *R9 - *R10 - *R11 - *R12 -} - -type R6 R5 -type R7 R5 -type R8 R5 - -type R9 struct { - *R13 - *R14 - *R15 - *R16 -} - -type R10 R9 -type R11 R9 -type R12 R9 - -type R13 struct { - *R17 - *R18 - *R19 - *R20 -} - -type R14 R13 -type R15 R13 -type R16 R13 - -type R17 struct { - *R21 - *R22 - *R23 - *R24 -} - -type R18 R17 -type R19 R17 -type R20 R17 - -type R21 struct { - X int -} - -type R22 R21 -type R23 R21 -type R24 R21 - -func TestEmbed(t *testing.T) { - typ := TypeOf(R0{}) - f, ok := typ.FieldByName("X") - if ok { - t.Fatalf(`FieldByName("X") should fail, returned %v`, f.Index) - } -} - -func BenchmarkFieldByName3(b *testing.B) { - t := TypeOf(R0{}) - for i := 0; i < b.N; i++ { - t.FieldByName("X") - } -} - -type S struct { - i1 int64 - i2 int64 -} - -func BenchmarkInterfaceBig(b *testing.B) { - v := ValueOf(S{}) - for i := 0; i < b.N; i++ { - v.Interface() - } - b.StopTimer() -} - -func TestAllocsInterfaceBig(t *testing.T) { - if testing.Short() { - t.Skip("skipping malloc count in short mode") - } - v := ValueOf(S{}) - if allocs := testing.AllocsPerRun(100, func() { v.Interface() }); allocs > 0 { - t.Error("allocs:", allocs) - } -} - -func BenchmarkInterfaceSmall(b *testing.B) { - v := ValueOf(int64(0)) - for i := 0; i < b.N; i++ { - v.Interface() - } -} - -func TestAllocsInterfaceSmall(t *testing.T) { - if testing.Short() { - t.Skip("skipping malloc count in short mode") - } - v := ValueOf(int64(0)) - if allocs := testing.AllocsPerRun(100, func() { v.Interface() }); allocs > 0 { - t.Error("allocs:", allocs) - } -} - -// An exhaustive is a mechanism for writing exhaustive or stochastic tests. -// The basic usage is: -// -// for x.Next() { -// ... code using x.Maybe() or x.Choice(n) to create test cases ... -// } -// -// Each iteration of the loop returns a different set of results, until all -// possible result sets have been explored. It is okay for different code paths -// to make different method call sequences on x, but there must be no -// other source of non-determinism in the call sequences. -// -// When faced with a new decision, x chooses randomly. Future explorations -// of that path will choose successive values for the result. Thus, stopping -// the loop after a fixed number of iterations gives somewhat stochastic -// testing. -// -// Example: -// -// for x.Next() { -// v := make([]bool, x.Choose(4)) -// for i := range v { -// v[i] = x.Maybe() -// } -// fmt.Println(v) -// } -// -// prints (in some order): -// -// [] -// [false] -// [true] -// [false false] -// [false true] -// ... -// [true true] -// [false false false] -// ... -// [true true true] -// [false false false false] -// ... -// [true true true true] -// -type exhaustive struct { - r *rand.Rand - pos int - last []choice -} - -type choice struct { - off int - n int - max int -} - -func (x *exhaustive) Next() bool { - if x.r == nil { - x.r = rand.New(rand.NewSource(time.Now().UnixNano())) - } - x.pos = 0 - if x.last == nil { - x.last = []choice{} - return true - } - for i := len(x.last) - 1; i >= 0; i-- { - c := &x.last[i] - if c.n+1 < c.max { - c.n++ - x.last = x.last[:i+1] - return true - } - } - return false -} - -func (x *exhaustive) Choose(max int) int { - if x.pos >= len(x.last) { - x.last = append(x.last, choice{x.r.Intn(max), 0, max}) - } - c := &x.last[x.pos] - x.pos++ - if c.max != max { - panic("inconsistent use of exhaustive tester") - } - return (c.n + c.off) % max -} - -func (x *exhaustive) Maybe() bool { - return x.Choose(2) == 1 -} - -func GCFunc(args []Value) []Value { - runtime.GC() - return []Value{} -} - -func TestReflectFuncTraceback(t *testing.T) { - f := MakeFunc(TypeOf(func() {}), GCFunc) - f.Call([]Value{}) -} - -func (p Point) GCMethod(k int) int { - runtime.GC() - return k + p.x -} - -func TestReflectMethodTraceback(t *testing.T) { - p := Point{3, 4} - m := ValueOf(p).MethodByName("GCMethod") - i := ValueOf(m.Interface()).Call([]Value{ValueOf(5)})[0].Int() - if i != 8 { - t.Errorf("Call returned %d; want 8", i) - } -} - -func TestBigZero(t *testing.T) { - const size = 1 << 10 - var v [size]byte - z := Zero(ValueOf(v).Type()).Interface().([size]byte) - for i := 0; i < size; i++ { - if z[i] != 0 { - t.Fatalf("Zero object not all zero, index %d", i) - } - } -} - -func TestFieldByIndexNil(t *testing.T) { - type P struct { - F int - } - type T struct { - *P - } - v := ValueOf(T{}) - - v.FieldByName("P") // should be fine - - defer func() { - if err := recover(); err == nil { - t.Fatalf("no error") - } else if !strings.Contains(fmt.Sprint(err), "nil pointer to embedded struct") { - t.Fatalf(`err=%q, wanted error containing "nil pointer to embedded struct"`, err) - } - }() - v.FieldByName("F") // should panic - - t.Fatalf("did not panic") -} - -// Given -// type Outer struct { -// *Inner -// ... -// } -// the compiler generates the implementation of (*Outer).M dispatching to the embedded Inner. -// The implementation is logically: -// func (p *Outer) M() { -// (p.Inner).M() -// } -// but since the only change here is the replacement of one pointer receiver with another, -// the actual generated code overwrites the original receiver with the p.Inner pointer and -// then jumps to the M method expecting the *Inner receiver. -// -// During reflect.Value.Call, we create an argument frame and the associated data structures -// to describe it to the garbage collector, populate the frame, call reflect.call to -// run a function call using that frame, and then copy the results back out of the frame. -// The reflect.call function does a memmove of the frame structure onto the -// stack (to set up the inputs), runs the call, and the memmoves the stack back to -// the frame structure (to preserve the outputs). -// -// Originally reflect.call did not distinguish inputs from outputs: both memmoves -// were for the full stack frame. However, in the case where the called function was -// one of these wrappers, the rewritten receiver is almost certainly a different type -// than the original receiver. This is not a problem on the stack, where we use the -// program counter to determine the type information and understand that -// during (*Outer).M the receiver is an *Outer while during (*Inner).M the receiver in the same -// memory word is now an *Inner. But in the statically typed argument frame created -// by reflect, the receiver is always an *Outer. Copying the modified receiver pointer -// 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. -// -// 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 -// an interface requires dereferencing the itab word, the misinterpretation will try to -// deference Inner.P1, causing a crash during garbage collection. -// -// This came up in a real program in issue 7725. - -type Outer struct { - *Inner - R io.Reader -} - -type Inner struct { - X *Outer - P1 uintptr - P2 uintptr -} - -func (pi *Inner) M() { - // Clear references to pi so that the only way the - // garbage collection will find the pointer is in the - // argument frame, typed as a *Outer. - pi.X.Inner = nil - - // Set up an interface value that will cause a crash. - // P1 = 1 is a non-zero, so the interface looks non-nil. - // P2 = pi ensures that the data word points into the - // allocated heap; if not the collection skips the interface - // value as irrelevant, without dereferencing P1. - pi.P1 = 1 - pi.P2 = uintptr(unsafe.Pointer(pi)) -} - -func TestCallMethodJump(t *testing.T) { - // In reflect.Value.Call, trigger a garbage collection after reflect.call - // returns but before the args frame has been discarded. - // This is a little clumsy but makes the failure repeatable. - *CallGC = true - - p := &Outer{Inner: new(Inner)} - p.Inner.X = p - ValueOf(p).Method(0).Call(nil) - - // Stop garbage collecting during reflect.call. - *CallGC = false -} diff --git a/src/pkg/reflect/asm_386.s b/src/pkg/reflect/asm_386.s deleted file mode 100644 index 75413c752..000000000 --- a/src/pkg/reflect/asm_386.s +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#include "../../cmd/ld/textflag.h" - -// makeFuncStub is the code half of the function returned by MakeFunc. -// See the comment on the declaration of makeFuncStub in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 - MOVL DX, 0(SP) - LEAL argframe+0(FP), CX - MOVL CX, 4(SP) - CALL ·callReflect(SB) - RET - -// methodValueCall is the code half of the function returned by makeMethodValue. -// See the comment on the declaration of methodValueCall in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 - MOVL DX, 0(SP) - LEAL argframe+0(FP), CX - MOVL CX, 4(SP) - CALL ·callMethod(SB) - RET diff --git a/src/pkg/reflect/asm_amd64.s b/src/pkg/reflect/asm_amd64.s deleted file mode 100644 index 712959843..000000000 --- a/src/pkg/reflect/asm_amd64.s +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#include "../../cmd/ld/textflag.h" - -// makeFuncStub is the code half of the function returned by MakeFunc. -// See the comment on the declaration of makeFuncStub in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16 - MOVQ DX, 0(SP) - LEAQ argframe+0(FP), CX - MOVQ CX, 8(SP) - CALL ·callReflect(SB) - RET - -// methodValueCall is the code half of the function returned by makeMethodValue. -// See the comment on the declaration of methodValueCall in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16 - MOVQ DX, 0(SP) - LEAQ argframe+0(FP), CX - MOVQ CX, 8(SP) - CALL ·callMethod(SB) - RET diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s deleted file mode 100644 index 75413c752..000000000 --- a/src/pkg/reflect/asm_amd64p32.s +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#include "../../cmd/ld/textflag.h" - -// makeFuncStub is the code half of the function returned by MakeFunc. -// See the comment on the declaration of makeFuncStub in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 - MOVL DX, 0(SP) - LEAL argframe+0(FP), CX - MOVL CX, 4(SP) - CALL ·callReflect(SB) - RET - -// methodValueCall is the code half of the function returned by makeMethodValue. -// See the comment on the declaration of methodValueCall in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 - MOVL DX, 0(SP) - LEAL argframe+0(FP), CX - MOVL CX, 4(SP) - CALL ·callMethod(SB) - RET diff --git a/src/pkg/reflect/asm_arm.s b/src/pkg/reflect/asm_arm.s deleted file mode 100644 index 68ded4ac6..000000000 --- a/src/pkg/reflect/asm_arm.s +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -#include "../../cmd/ld/textflag.h" - -// makeFuncStub is jumped to by the code generated by MakeFunc. -// See the comment on the declaration of makeFuncStub in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 - MOVW R7, 4(R13) - MOVW $argframe+0(FP), R1 - MOVW R1, 8(R13) - BL ·callReflect(SB) - RET - -// methodValueCall is the code half of the function returned by makeMethodValue. -// See the comment on the declaration of methodValueCall in makefunc.go -// for more details. -// No argsize here, gc generates argsize info at call site. -TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 - MOVW R7, 4(R13) - MOVW $argframe+0(FP), R1 - MOVW R1, 8(R13) - BL ·callMethod(SB) - RET diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go deleted file mode 100644 index f63715c9a..000000000 --- a/src/pkg/reflect/deepequal.go +++ /dev/null @@ -1,145 +0,0 @@ -// 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. - -// Deep equality test via reflection - -package reflect - -// During deepValueEqual, must keep track of checks that are -// 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 { - a1 uintptr - a2 uintptr - typ Type -} - -// Tests for deep equality using reflected types. The map argument tracks -// comparisons that have already been seen, which allows short circuiting on -// recursive types. -func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { - if !v1.IsValid() || !v2.IsValid() { - return v1.IsValid() == v2.IsValid() - } - if v1.Type() != v2.Type() { - return false - } - - // if depth > 10 { panic("deepValueEqual") } // for debugging - hard := func(k Kind) bool { - switch k { - case Array, Map, Slice, Struct: - return true - } - return false - } - - if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { - addr1 := v1.UnsafeAddr() - addr2 := v2.UnsafeAddr() - if addr1 > addr2 { - // Canonicalize order to reduce number of entries in visited. - addr1, addr2 = addr2, addr1 - } - - // Short circuit if references are identical ... - if addr1 == addr2 { - return true - } - - // ... or already seen - typ := v1.Type() - v := visit{addr1, addr2, typ} - if visited[v] { - return true - } - - // Remember for later. - visited[v] = true - } - - switch v1.Kind() { - case Array: - for i := 0; i < v1.Len(); i++ { - if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { - return false - } - } - return true - case Slice: - if v1.IsNil() != v2.IsNil() { - return false - } - if v1.Len() != v2.Len() { - return false - } - if v1.Pointer() == v2.Pointer() { - return true - } - for i := 0; i < v1.Len(); i++ { - if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { - return false - } - } - return true - case Interface: - if v1.IsNil() || v2.IsNil() { - return v1.IsNil() == v2.IsNil() - } - return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) - case Ptr: - return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) - case Struct: - for i, n := 0, v1.NumField(); i < n; i++ { - if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) { - return false - } - } - return true - case Map: - if v1.IsNil() != v2.IsNil() { - return false - } - if v1.Len() != v2.Len() { - return false - } - if v1.Pointer() == v2.Pointer() { - return true - } - for _, k := range v1.MapKeys() { - if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) { - return false - } - } - return true - case Func: - if v1.IsNil() && v2.IsNil() { - return true - } - // Can't do better than this: - return false - default: - // Normal equality suffices - return valueInterface(v1, false) == valueInterface(v2, false) - } -} - -// DeepEqual tests for deep equality. It uses normal == equality where -// possible but will scan elements of arrays, slices, maps, and fields of -// structs. In maps, keys are compared with == but elements use deep -// equality. DeepEqual correctly handles recursive types. Functions are equal -// only if they are both nil. -// An empty slice is not equal to a nil slice. -func DeepEqual(a1, a2 interface{}) bool { - if a1 == nil || a2 == nil { - return a1 == a2 - } - v1 := ValueOf(a1) - v2 := ValueOf(a2) - if v1.Type() != v2.Type() { - return false - } - return deepValueEqual(v1, v2, make(map[visit]bool), 0) -} diff --git a/src/pkg/reflect/example_test.go b/src/pkg/reflect/example_test.go deleted file mode 100644 index cca28eeec..000000000 --- a/src/pkg/reflect/example_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// 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. - -package reflect_test - -import ( - "fmt" - "reflect" -) - -func ExampleMakeFunc() { - // swap is the implementation passed to MakeFunc. - // It must work in terms of reflect.Values so that it is possible - // to write code without knowing beforehand what the types - // will be. - swap := func(in []reflect.Value) []reflect.Value { - return []reflect.Value{in[1], in[0]} - } - - // makeSwap expects fptr to be a pointer to a nil function. - // It sets that pointer to a new function created with MakeFunc. - // When the function is invoked, reflect turns the arguments - // into Values, calls swap, and then turns swap's result slice - // into the values returned by the new function. - makeSwap := func(fptr interface{}) { - // fptr is a pointer to a function. - // Obtain the function value itself (likely nil) as a reflect.Value - // so that we can query its type and then set the value. - fn := reflect.ValueOf(fptr).Elem() - - // Make a function of the right type. - v := reflect.MakeFunc(fn.Type(), swap) - - // Assign it to the value fn represents. - fn.Set(v) - } - - // Make and call a swap function for ints. - var intSwap func(int, int) (int, int) - makeSwap(&intSwap) - fmt.Println(intSwap(0, 1)) - - // Make and call a swap function for float64s. - var floatSwap func(float64, float64) (float64, float64) - makeSwap(&floatSwap) - fmt.Println(floatSwap(2.72, 3.14)) - - // Output: - // 1 0 - // 3.14 2.72 -} - -func ExampleStructTag() { - type S struct { - F string `species:"gopher" color:"blue"` - } - - s := S{} - st := reflect.TypeOf(s) - field := st.Field(0) - fmt.Println(field.Tag.Get("color"), field.Tag.Get("species")) - - // Output: - // blue gopher -} diff --git a/src/pkg/reflect/export_test.go b/src/pkg/reflect/export_test.go deleted file mode 100644 index 0778ad37f..000000000 --- a/src/pkg/reflect/export_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -package reflect - -// MakeRO returns a copy of v with the read-only flag set. -func MakeRO(v Value) Value { - v.flag |= flagRO - return v -} - -// IsRO reports whether v's read-only flag is set. -func IsRO(v Value) bool { - return v.flag&flagRO != 0 -} - -var ArrayOf = arrayOf -var CallGC = &callGC diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go deleted file mode 100644 index 0e61fdea7..000000000 --- a/src/pkg/reflect/makefunc.go +++ /dev/null @@ -1,120 +0,0 @@ -// 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. - -// MakeFunc implementation. - -package reflect - -import ( - "unsafe" -) - -// makeFuncImpl is the closure value implementing the function -// returned by MakeFunc. -type makeFuncImpl struct { - code uintptr - typ *funcType - fn func([]Value) []Value -} - -// MakeFunc returns a new function of the given Type -// that wraps the function fn. When called, that new function -// does the following: -// -// - converts its arguments to a slice of Values. -// - runs results := fn(args). -// - returns the results as a slice of Values, one per formal result. -// -// The implementation fn can assume that the argument Value slice -// has the number and type of arguments given by typ. -// If typ describes a variadic function, the final Value is itself -// a slice representing the variadic arguments, as in the -// body of a variadic function. The result Value slice returned by fn -// must have the number and type of results given by typ. -// -// The Value.Call method allows the caller to invoke a typed function -// in terms of Values; in contrast, MakeFunc allows the caller to implement -// a typed function in terms of Values. -// -// The Examples section of the documentation includes an illustration -// of how to use MakeFunc to build a swap function for different types. -// -func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { - if typ.Kind() != Func { - panic("reflect: call of MakeFunc with non-Func type") - } - - t := typ.common() - ftyp := (*funcType)(unsafe.Pointer(t)) - - // Indirect Go func value (dummy) to obtain - // actual code address. (A Go func value is a pointer - // to a C function pointer. http://golang.org/s/go11func.) - dummy := makeFuncStub - code := **(**uintptr)(unsafe.Pointer(&dummy)) - - impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn} - - return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift} -} - -// makeFuncStub is an assembly function that is the code half of -// the function returned from MakeFunc. It expects a *callReflectFunc -// as its context register, and its job is to invoke callReflect(ctxt, frame) -// where ctxt is the context register and frame is a pointer to the first -// word in the passed-in argument frame. -func makeFuncStub() - -type methodValue struct { - fn uintptr - method int - rcvr Value -} - -// makeMethodValue converts v from the rcvr+method index representation -// of a method value to an actual method func value, which is -// basically the receiver value with a special bit set, into a true -// func value - a value holding an actual func. The output is -// semantically equivalent to the input as far as the user of package -// reflect can tell, but the true func representation can be handled -// by code like Convert and Interface and Assign. -func makeMethodValue(op string, v Value) Value { - if v.flag&flagMethod == 0 { - panic("reflect: internal error: invalid use of makeMethodValue") - } - - // Ignoring the flagMethod bit, v describes the receiver, not the method type. - fl := v.flag & (flagRO | flagAddr | flagIndir) - fl |= flag(v.typ.Kind()) << flagKindShift - rcvr := Value{v.typ, v.ptr, v.scalar, fl} - - // v.Type returns the actual type of the method value. - funcType := v.Type().(*rtype) - - // Indirect Go func value (dummy) to obtain - // actual code address. (A Go func value is a pointer - // to a C function pointer. http://golang.org/s/go11func.) - dummy := methodValueCall - code := **(**uintptr)(unsafe.Pointer(&dummy)) - - fv := &methodValue{ - fn: code, - method: int(v.flag) >> flagMethodShift, - rcvr: rcvr, - } - - // Cause panic if method is not appropriate. - // The panic would still happen during the call if we omit this, - // but we want Interface() and other operations to fail early. - methodReceiver(op, fv.rcvr, fv.method) - - return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift} -} - -// methodValueCall is an assembly function that is the code half of -// the function returned from makeMethodValue. It expects a *methodValue -// as its context register, and its job is to invoke callMethod(ctxt, frame) -// where ctxt is the context register and frame is a pointer to the first -// word in the passed-in argument frame. -func methodValueCall() diff --git a/src/pkg/reflect/set_test.go b/src/pkg/reflect/set_test.go deleted file mode 100644 index 85dc55e68..000000000 --- a/src/pkg/reflect/set_test.go +++ /dev/null @@ -1,211 +0,0 @@ -// 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. - -package reflect_test - -import ( - "bytes" - "go/ast" - "io" - . "reflect" - "testing" - "unsafe" -) - -type MyBuffer bytes.Buffer - -func TestImplicitMapConversion(t *testing.T) { - // Test implicit conversions in MapIndex and SetMapIndex. - { - // direct - m := make(map[int]int) - mv := ValueOf(m) - mv.SetMapIndex(ValueOf(1), ValueOf(2)) - x, ok := m[1] - if x != 2 { - t.Errorf("#1 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) - } - if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { - t.Errorf("#1 MapIndex(1) = %d", n) - } - } - { - // convert interface key - m := make(map[interface{}]int) - mv := ValueOf(m) - mv.SetMapIndex(ValueOf(1), ValueOf(2)) - x, ok := m[1] - if x != 2 { - t.Errorf("#2 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) - } - if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { - t.Errorf("#2 MapIndex(1) = %d", n) - } - } - { - // convert interface value - m := make(map[int]interface{}) - mv := ValueOf(m) - mv.SetMapIndex(ValueOf(1), ValueOf(2)) - x, ok := m[1] - if x != 2 { - t.Errorf("#3 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) - } - if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { - t.Errorf("#3 MapIndex(1) = %d", n) - } - } - { - // convert both interface key and interface value - m := make(map[interface{}]interface{}) - mv := ValueOf(m) - mv.SetMapIndex(ValueOf(1), ValueOf(2)) - x, ok := m[1] - if x != 2 { - t.Errorf("#4 after SetMapIndex(1,2): %d, %t (map=%v)", x, ok, m) - } - if n := mv.MapIndex(ValueOf(1)).Interface().(int); n != 2 { - t.Errorf("#4 MapIndex(1) = %d", n) - } - } - { - // convert both, with non-empty interfaces - m := make(map[io.Reader]io.Writer) - mv := ValueOf(m) - b1 := new(bytes.Buffer) - b2 := new(bytes.Buffer) - mv.SetMapIndex(ValueOf(b1), ValueOf(b2)) - x, ok := m[b1] - if x != b2 { - t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) - } - if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2) - } - } - { - // convert channel direction - m := make(map[<-chan int]chan int) - mv := ValueOf(m) - c1 := make(chan int) - c2 := make(chan int) - mv.SetMapIndex(ValueOf(c1), ValueOf(c2)) - x, ok := m[c1] - if x != c2 { - t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m) - } - if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { - t.Errorf("#6 MapIndex(c1) = %#x want %p", p, c2) - } - } - { - // convert identical underlying types - // TODO(rsc): Should be able to define MyBuffer here. - // 6l prints very strange messages about .this.Bytes etc - // when we do that though, so MyBuffer is defined - // at top level. - m := make(map[*MyBuffer]*bytes.Buffer) - mv := ValueOf(m) - b1 := new(MyBuffer) - b2 := new(bytes.Buffer) - mv.SetMapIndex(ValueOf(b1), ValueOf(b2)) - x, ok := m[b1] - if x != b2 { - t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) - } - if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#7 MapIndex(b1) = %#x want %p", p, b2) - } - } - -} - -func TestImplicitSetConversion(t *testing.T) { - // Assume TestImplicitMapConversion covered the basics. - // Just make sure conversions are being applied at all. - var r io.Reader - b := new(bytes.Buffer) - rv := ValueOf(&r).Elem() - rv.Set(ValueOf(b)) - if r != b { - t.Errorf("after Set: r=%T(%v)", r, r) - } -} - -func TestImplicitSendConversion(t *testing.T) { - c := make(chan io.Reader, 10) - b := new(bytes.Buffer) - ValueOf(c).Send(ValueOf(b)) - if bb := <-c; bb != b { - t.Errorf("Received %p != %p", bb, b) - } -} - -func TestImplicitCallConversion(t *testing.T) { - // Arguments must be assignable to parameter types. - fv := ValueOf(io.WriteString) - b := new(bytes.Buffer) - fv.Call([]Value{ValueOf(b), ValueOf("hello world")}) - if b.String() != "hello world" { - t.Errorf("After call: string=%q want %q", b.String(), "hello world") - } -} - -func TestImplicitAppendConversion(t *testing.T) { - // Arguments must be assignable to the slice's element type. - s := []io.Reader{} - sv := ValueOf(&s).Elem() - b := new(bytes.Buffer) - sv.Set(Append(sv, ValueOf(b))) - if len(s) != 1 || s[0] != b { - t.Errorf("after append: s=%v want [%p]", s, b) - } -} - -var implementsTests = []struct { - x interface{} - t interface{} - b bool -}{ - {new(*bytes.Buffer), new(io.Reader), true}, - {new(bytes.Buffer), new(io.Reader), false}, - {new(*bytes.Buffer), new(io.ReaderAt), false}, - {new(*ast.Ident), new(ast.Expr), true}, -} - -func TestImplements(t *testing.T) { - for _, tt := range implementsTests { - xv := TypeOf(tt.x).Elem() - xt := TypeOf(tt.t).Elem() - if b := xv.Implements(xt); b != tt.b { - t.Errorf("(%s).Implements(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b) - } - } -} - -var assignableTests = []struct { - x interface{} - t interface{} - b bool -}{ - {new(chan int), new(<-chan int), true}, - {new(<-chan int), new(chan int), false}, - {new(*int), new(IntPtr), true}, - {new(IntPtr), new(*int), true}, - {new(IntPtr), new(IntPtr1), false}, - // test runs implementsTests too -} - -type IntPtr *int -type IntPtr1 *int - -func TestAssignableTo(t *testing.T) { - for _, tt := range append(assignableTests, implementsTests...) { - xv := TypeOf(tt.x).Elem() - xt := TypeOf(tt.t).Elem() - if b := xv.AssignableTo(xt); b != tt.b { - t.Errorf("(%s).AssignableTo(%s) = %v, want %v", xv.String(), xt.String(), b, tt.b) - } - } -} diff --git a/src/pkg/reflect/tostring_test.go b/src/pkg/reflect/tostring_test.go deleted file mode 100644 index e416fd84d..000000000 --- a/src/pkg/reflect/tostring_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// 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. - -// Formatting of reflection types and values for debugging. -// Not defined as methods so they do not need to be linked into most binaries; -// the functions are not used by the library itself, only in tests. - -package reflect_test - -import ( - . "reflect" - "strconv" -) - -// valueToString returns a textual representation of the reflection value val. -// For debugging only. -func valueToString(val Value) string { - var str string - if !val.IsValid() { - return "<zero Value>" - } - typ := val.Type() - switch val.Kind() { - case Int, Int8, Int16, Int32, Int64: - return strconv.FormatInt(val.Int(), 10) - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return strconv.FormatUint(val.Uint(), 10) - case Float32, Float64: - return strconv.FormatFloat(val.Float(), 'g', -1, 64) - case Complex64, Complex128: - c := val.Complex() - return strconv.FormatFloat(real(c), 'g', -1, 64) + "+" + strconv.FormatFloat(imag(c), 'g', -1, 64) + "i" - case String: - return val.String() - case Bool: - if val.Bool() { - return "true" - } else { - return "false" - } - case Ptr: - v := val - str = typ.String() + "(" - if v.IsNil() { - str += "0" - } else { - str += "&" + valueToString(v.Elem()) - } - str += ")" - return str - case Array, Slice: - v := val - str += typ.String() - str += "{" - for i := 0; i < v.Len(); i++ { - if i > 0 { - str += ", " - } - str += valueToString(v.Index(i)) - } - str += "}" - return str - case Map: - t := typ - str = t.String() - str += "{" - str += "<can't iterate on maps>" - str += "}" - return str - case Chan: - str = typ.String() - return str - case Struct: - t := typ - v := val - str += t.String() - str += "{" - for i, n := 0, v.NumField(); i < n; i++ { - if i > 0 { - str += ", " - } - str += valueToString(v.Field(i)) - } - str += "}" - return str - case Interface: - return typ.String() + "(" + valueToString(val.Elem()) + ")" - case Func: - v := val - return typ.String() + "(" + strconv.FormatUint(uint64(v.Pointer()), 10) + ")" - default: - panic("valueToString: can't print type " + typ.String()) - } -} diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go deleted file mode 100644 index 40d76f99d..000000000 --- a/src/pkg/reflect/type.go +++ /dev/null @@ -1,1926 +0,0 @@ -// 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 reflect implements run-time reflection, allowing a program to -// 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. -// -// A call to ValueOf returns a Value representing the run-time data. -// Zero takes a Type and returns a Value representing a zero value -// for that type. -// -// See "The Laws of Reflection" for an introduction to reflection in Go: -// http://golang.org/doc/articles/laws_of_reflection.html -package reflect - -import ( - "runtime" - "strconv" - "sync" - "unsafe" -) - -// Type is the representation of a Go type. -// -// 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 -// inappropriate to the kind of type causes a run-time panic. -type Type interface { - // Methods applicable to all types. - - // Align returns the alignment in bytes of a value of - // this type when allocated in memory. - Align() int - - // FieldAlign returns the alignment in bytes of a value of - // this type when used as a field in a struct. - FieldAlign() int - - // Method returns the i'th method in the type's method set. - // It panics if i is not in the range [0, NumMethod()). - // - // For a non-interface type T or *T, the returned Method's Type and Func - // fields describe a function whose first argument is the receiver. - // - // For an interface type, the returned Method's Type field gives the - // method signature, without a receiver, and the Func field is nil. - Method(int) Method - - // MethodByName returns the method with that name in the type's - // method set and a boolean indicating if the method was found. - // - // For a non-interface type T or *T, the returned Method's Type and Func - // fields describe a function whose first argument is the receiver. - // - // For an interface type, the returned Method's Type field gives the - // method signature, without a receiver, and the Func field is nil. - MethodByName(string) (Method, bool) - - // NumMethod returns the number of methods in the type's method set. - NumMethod() int - - // Name returns the type's name within its package. - // It returns an empty string for unnamed types. - Name() string - - // PkgPath returns a named type's package path, that is, the import path - // that uniquely identifies the package, such as "encoding/base64". - // If the type was predeclared (string, error) or unnamed (*T, struct{}, []int), - // the package path will be the empty string. - PkgPath() string - - // Size returns the number of bytes needed to store - // a value of the given type; it is analogous to unsafe.Sizeof. - Size() uintptr - - // 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, - // compare the Types directly. - String() string - - // Kind returns the specific kind of this type. - Kind() Kind - - // Implements returns true if the type implements the interface type u. - Implements(u Type) bool - - // AssignableTo returns true if a value of the type is assignable to type u. - AssignableTo(u Type) bool - - // ConvertibleTo returns true if a value of the type is convertible to type u. - ConvertibleTo(u Type) bool - - // Methods applicable only to some types, depending on Kind. - // The methods allowed for each kind are: - // - // Int*, Uint*, Float*, Complex*: Bits - // Array: Elem, Len - // Chan: ChanDir, Elem - // Func: In, NumIn, Out, NumOut, IsVariadic. - // Map: Key, Elem - // Ptr: Elem - // Slice: Elem - // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField - - // Bits returns the size of the type in bits. - // It panics if the type's Kind is not one of the - // sized or unsized Int, Uint, Float, or Complex kinds. - Bits() int - - // ChanDir returns a channel type's direction. - // It panics if the type's Kind is not Chan. - ChanDir() ChanDir - - // IsVariadic returns true if a function type's final input parameter - // 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 - // - // t.NumIn() == 2 - // t.In(0) is the reflect.Type for "int" - // t.In(1) is the reflect.Type for "[]float64" - // t.IsVariadic() == true - // - // IsVariadic panics if the type's Kind is not Func. - IsVariadic() bool - - // Elem returns a type's element type. - // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice. - Elem() Type - - // Field returns a struct type's i'th field. - // It panics if the type's Kind is not Struct. - // It panics if i is not in the range [0, NumField()). - Field(i int) StructField - - // FieldByIndex returns the nested field corresponding - // 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 - - // FieldByName returns the struct field with the given name - // and a boolean indicating if the field was found. - FieldByName(name string) (StructField, bool) - - // FieldByNameFunc returns the first struct field with a name - // that satisfies the match function and a boolean indicating if - // the field was found. - FieldByNameFunc(match func(string) bool) (StructField, bool) - - // In returns the type of a function type's i'th input parameter. - // It panics if the type's Kind is not Func. - // It panics if i is not in the range [0, NumIn()). - In(i int) Type - - // Key returns a map type's key type. - // It panics if the type's Kind is not Map. - Key() Type - - // Len returns an array type's length. - // It panics if the type's Kind is not Array. - Len() int - - // NumField returns a struct type's field count. - // It panics if the type's Kind is not Struct. - NumField() int - - // NumIn returns a function type's input parameter count. - // It panics if the type's Kind is not Func. - NumIn() int - - // NumOut returns a function type's output parameter count. - // It panics if the type's Kind is not Func. - NumOut() int - - // Out returns the type of a function type's i'th output parameter. - // It panics if the type's Kind is not Func. - // It panics if i is not in the range [0, NumOut()). - Out(i int) Type - - common() *rtype - uncommon() *uncommonType -} - -// BUG(rsc): FieldByName and related functions consider struct field names to be equal -// if the names are equal, even if they are unexported names originating -// in different packages. The practical effect of this is that the result of -// t.FieldByName("x") is not well defined if the struct type t contains -// multiple fields named x (embedded from different packages). -// FieldByName may return one of the fields named x or may report that there are none. -// See golang.org/issue/4876 for more details. - -/* - * These data structures are known to the compiler (../../cmd/gc/reflect.c). - * A few are known to ../runtime/type.go to convey to debuggers. - * They are also known to ../runtime/type.h. - */ - -// A Kind represents the specific kind of type that a Type represents. -// The zero Kind is not a valid kind. -type Kind uint - -const ( - Invalid Kind = iota - Bool - Int - Int8 - Int16 - Int32 - Int64 - Uint - Uint8 - Uint16 - Uint32 - Uint64 - Uintptr - Float32 - Float64 - Complex64 - Complex128 - Array - Chan - Func - Interface - Map - Ptr - Slice - String - Struct - UnsafePointer -) - -// rtype is the common implementation of most values. -// It is embedded in other, public struct types, but always -// with a unique tag like `reflect:"array"` or `reflect:"ptr"` -// so that code cannot convert from, say, *arrayType to *ptrType. -type rtype struct { - size uintptr // size in bytes - hash uint32 // hash of type; avoids computation in hash tables - _ uint8 // unused/padding - align uint8 // alignment of variable with this type - fieldAlign uint8 // alignment of struct field with this type - kind uint8 // enumeration for C - alg *uintptr // algorithm table (../runtime/runtime.h:/Alg) - gc unsafe.Pointer // garbage collection data - string *string // string form; unnecessary but undeniably useful - *uncommonType // (relatively) uncommon fields - ptrToThis *rtype // type for pointer to this type, if used in binary or has methods - zero unsafe.Pointer // pointer to zero value -} - -// Method on non-interface type -type method struct { - name *string // name of method - pkgPath *string // nil for exported Names; otherwise import path - mtyp *rtype // method type (without receiver) - typ *rtype // .(*FuncType) underneath (with receiver) - ifn unsafe.Pointer // fn used in interface call (one-word receiver) - tfn unsafe.Pointer // fn used for normal method call -} - -// uncommonType is present only for types with names or methods -// (if T is a named type, the uncommonTypes for T and *T have methods). -// Using a pointer to this struct reduces the overall size required -// to describe an unnamed type with no methods. -type uncommonType struct { - name *string // name of type - pkgPath *string // import path; nil for built-in types like int, string - methods []method // methods associated with type -} - -// ChanDir represents a channel type's direction. -type ChanDir int - -const ( - RecvDir ChanDir = 1 << iota // <-chan - SendDir // chan<- - BothDir = RecvDir | SendDir // chan -) - -// arrayType represents a fixed array type. -type arrayType struct { - rtype `reflect:"array"` - elem *rtype // array element type - slice *rtype // slice type - len uintptr -} - -// chanType represents a channel type. -type chanType struct { - rtype `reflect:"chan"` - elem *rtype // channel element type - dir uintptr // channel direction (ChanDir) -} - -// funcType represents a function type. -type funcType struct { - rtype `reflect:"func"` - dotdotdot bool // last input parameter is ... - in []*rtype // input parameter types - out []*rtype // output parameter types -} - -// imethod represents a method on an interface type -type imethod struct { - name *string // name of method - pkgPath *string // nil for exported Names; otherwise import path - typ *rtype // .(*FuncType) underneath -} - -// interfaceType represents an interface type. -type interfaceType struct { - rtype `reflect:"interface"` - methods []imethod // sorted by hash -} - -// mapType represents a map type. -type mapType struct { - rtype `reflect:"map"` - key *rtype // map key type - elem *rtype // map element (value) type - bucket *rtype // internal bucket structure - hmap *rtype // internal map header -} - -// ptrType represents a pointer type. -type ptrType struct { - rtype `reflect:"ptr"` - elem *rtype // pointer element (pointed at) type -} - -// sliceType represents a slice type. -type sliceType struct { - rtype `reflect:"slice"` - elem *rtype // slice element type -} - -// Struct field -type structField struct { - name *string // nil for embedded fields - pkgPath *string // nil for exported Names; otherwise import path - typ *rtype // type of field - tag *string // nil if no tag - offset uintptr // byte offset of field within struct -} - -// structType represents a struct type. -type structType struct { - rtype `reflect:"struct"` - fields []structField // sorted by offset -} - -// NOTE: These are copied from ../runtime/mgc0.h. -// They must be kept in sync. -const ( - _GC_END = iota - _GC_PTR - _GC_APTR - _GC_ARRAY_START - _GC_ARRAY_NEXT - _GC_CALL - _GC_CHAN_PTR - _GC_STRING - _GC_EFACE - _GC_IFACE - _GC_SLICE - _GC_REGION - _GC_NUM_INSTR -) - -/* - * The compiler knows the exact layout of all the data structures above. - * The compiler does not know about the data structures and methods below. - */ - -// Method represents a single method. -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. - // The combination of PkgPath and Name uniquely identifies a method - // in a method set. - // See http://golang.org/ref/spec#Uniqueness_of_identifiers - Name string - PkgPath string - - Type Type // method type - Func Value // func with receiver as first argument - Index int // index for Type.Method -} - -// High bit says whether type has -// embedded pointers,to help garbage collector. -const ( - kindMask = 0x7f - kindNoPointers = 0x80 -) - -func (k Kind) String() string { - if int(k) < len(kindNames) { - return kindNames[k] - } - return "kind" + strconv.Itoa(int(k)) -} - -var kindNames = []string{ - Invalid: "invalid", - Bool: "bool", - Int: "int", - Int8: "int8", - Int16: "int16", - Int32: "int32", - Int64: "int64", - Uint: "uint", - Uint8: "uint8", - Uint16: "uint16", - Uint32: "uint32", - Uint64: "uint64", - Uintptr: "uintptr", - Float32: "float32", - Float64: "float64", - Complex64: "complex64", - Complex128: "complex128", - Array: "array", - Chan: "chan", - Func: "func", - Interface: "interface", - Map: "map", - Ptr: "ptr", - Slice: "slice", - String: "string", - Struct: "struct", - UnsafePointer: "unsafe.Pointer", -} - -func (t *uncommonType) uncommon() *uncommonType { - return t -} - -func (t *uncommonType) PkgPath() string { - if t == nil || t.pkgPath == nil { - return "" - } - return *t.pkgPath -} - -func (t *uncommonType) Name() string { - if t == nil || t.name == nil { - return "" - } - return *t.name -} - -func (t *rtype) String() string { return *t.string } - -func (t *rtype) Size() uintptr { return t.size } - -func (t *rtype) Bits() int { - if t == nil { - panic("reflect: Bits of nil Type") - } - k := t.Kind() - if k < Int || k > Complex128 { - panic("reflect: Bits of non-arithmetic Type " + t.String()) - } - return int(t.size) * 8 -} - -func (t *rtype) Align() int { return int(t.align) } - -func (t *rtype) FieldAlign() int { return int(t.fieldAlign) } - -func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) } - -func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 } - -func (t *rtype) common() *rtype { return t } - -func (t *uncommonType) Method(i int) (m Method) { - if t == nil || i < 0 || i >= len(t.methods) { - panic("reflect: Method index out of range") - } - p := &t.methods[i] - if p.name != nil { - m.Name = *p.name - } - fl := flag(Func) << flagKindShift - if p.pkgPath != nil { - m.PkgPath = *p.pkgPath - fl |= flagRO - } - mt := p.typ - m.Type = mt - fn := unsafe.Pointer(&p.tfn) - m.Func = Value{mt, fn, 0, fl} - m.Index = i - return -} - -func (t *uncommonType) NumMethod() int { - if t == nil { - return 0 - } - return len(t.methods) -} - -func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { - if t == nil { - return - } - var p *method - for i := range t.methods { - p = &t.methods[i] - if p.name != nil && *p.name == name { - return t.Method(i), true - } - } - return -} - -// TODO(rsc): 6g supplies these, but they are not -// as efficient as they could be: they have commonType -// as the receiver instead of *rtype. -func (t *rtype) NumMethod() int { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.NumMethod() - } - return t.uncommonType.NumMethod() -} - -func (t *rtype) Method(i int) (m Method) { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.Method(i) - } - return t.uncommonType.Method(i) -} - -func (t *rtype) MethodByName(name string) (m Method, ok bool) { - if t.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(t)) - return tt.MethodByName(name) - } - return t.uncommonType.MethodByName(name) -} - -func (t *rtype) PkgPath() string { - return t.uncommonType.PkgPath() -} - -func (t *rtype) Name() string { - return t.uncommonType.Name() -} - -func (t *rtype) ChanDir() ChanDir { - if t.Kind() != Chan { - panic("reflect: ChanDir of non-chan type") - } - tt := (*chanType)(unsafe.Pointer(t)) - return ChanDir(tt.dir) -} - -func (t *rtype) IsVariadic() bool { - if t.Kind() != Func { - panic("reflect: IsVariadic of non-func type") - } - tt := (*funcType)(unsafe.Pointer(t)) - return tt.dotdotdot -} - -func (t *rtype) Elem() Type { - switch t.Kind() { - case Array: - tt := (*arrayType)(unsafe.Pointer(t)) - return toType(tt.elem) - case Chan: - tt := (*chanType)(unsafe.Pointer(t)) - return toType(tt.elem) - case Map: - tt := (*mapType)(unsafe.Pointer(t)) - return toType(tt.elem) - case Ptr: - tt := (*ptrType)(unsafe.Pointer(t)) - return toType(tt.elem) - case Slice: - tt := (*sliceType)(unsafe.Pointer(t)) - return toType(tt.elem) - } - panic("reflect: Elem of invalid type") -} - -func (t *rtype) Field(i int) StructField { - if t.Kind() != Struct { - panic("reflect: Field of non-struct type") - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.Field(i) -} - -func (t *rtype) FieldByIndex(index []int) StructField { - if t.Kind() != Struct { - panic("reflect: FieldByIndex of non-struct type") - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByIndex(index) -} - -func (t *rtype) FieldByName(name string) (StructField, bool) { - if t.Kind() != Struct { - panic("reflect: FieldByName of non-struct type") - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByName(name) -} - -func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { - if t.Kind() != Struct { - panic("reflect: FieldByNameFunc of non-struct type") - } - tt := (*structType)(unsafe.Pointer(t)) - return tt.FieldByNameFunc(match) -} - -func (t *rtype) In(i int) Type { - if t.Kind() != Func { - panic("reflect: In of non-func type") - } - tt := (*funcType)(unsafe.Pointer(t)) - return toType(tt.in[i]) -} - -func (t *rtype) Key() Type { - if t.Kind() != Map { - panic("reflect: Key of non-map type") - } - tt := (*mapType)(unsafe.Pointer(t)) - return toType(tt.key) -} - -func (t *rtype) Len() int { - if t.Kind() != Array { - panic("reflect: Len of non-array type") - } - tt := (*arrayType)(unsafe.Pointer(t)) - return int(tt.len) -} - -func (t *rtype) NumField() int { - if t.Kind() != Struct { - panic("reflect: NumField of non-struct type") - } - tt := (*structType)(unsafe.Pointer(t)) - return len(tt.fields) -} - -func (t *rtype) NumIn() int { - if t.Kind() != Func { - panic("reflect: NumIn of non-func type") - } - tt := (*funcType)(unsafe.Pointer(t)) - return len(tt.in) -} - -func (t *rtype) NumOut() int { - if t.Kind() != Func { - panic("reflect: NumOut of non-func type") - } - tt := (*funcType)(unsafe.Pointer(t)) - return len(tt.out) -} - -func (t *rtype) Out(i int) Type { - if t.Kind() != Func { - panic("reflect: Out of non-func type") - } - tt := (*funcType)(unsafe.Pointer(t)) - return toType(tt.out[i]) -} - -func (d ChanDir) String() string { - switch d { - case SendDir: - return "chan<-" - case RecvDir: - return "<-chan" - case BothDir: - return "chan" - } - return "ChanDir" + strconv.Itoa(int(d)) -} - -// Method returns the i'th method in the type's method set. -func (t *interfaceType) Method(i int) (m Method) { - if i < 0 || i >= len(t.methods) { - return - } - p := &t.methods[i] - m.Name = *p.name - if p.pkgPath != nil { - m.PkgPath = *p.pkgPath - } - m.Type = toType(p.typ) - m.Index = i - return -} - -// NumMethod returns the number of interface methods in the type's method set. -func (t *interfaceType) NumMethod() int { return len(t.methods) } - -// MethodByName method with the given name in the type's method set. -func (t *interfaceType) MethodByName(name string) (m Method, ok bool) { - if t == nil { - return - } - var p *imethod - for i := range t.methods { - p = &t.methods[i] - if *p.name == name { - return t.Method(i), true - } - } - return -} - -// A StructField describes a single field in a struct. -type StructField struct { - // Name is the field name. - // PkgPath is the package path that qualifies a lower case (unexported) - // field name. It is empty for upper case (exported) field names. - // See http://golang.org/ref/spec#Uniqueness_of_identifiers - Name string - PkgPath string - - Type Type // field type - Tag StructTag // field tag string - Offset uintptr // offset within struct, in bytes - Index []int // index sequence for Type.FieldByIndex - Anonymous bool // is an embedded field -} - -// A StructTag is the tag string in a struct field. -// -// By convention, tag strings are a concatenation of -// optionally space-separated key:"value" pairs. -// Each key is a non-empty string consisting of non-control -// characters other than space (U+0020 ' '), quote (U+0022 '"'), -// and colon (U+003A ':'). Each value is quoted using U+0022 '"' -// characters and Go string literal syntax. -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. -func (tag StructTag) Get(key string) string { - for tag != "" { - // skip leading space - i := 0 - for i < len(tag) && tag[i] == ' ' { - i++ - } - tag = tag[i:] - if tag == "" { - break - } - - // scan to colon. - // a space or a quote is a syntax error - i = 0 - for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' { - i++ - } - if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { - break - } - name := string(tag[:i]) - tag = tag[i+1:] - - // scan quoted string to find value - i = 1 - for i < len(tag) && tag[i] != '"' { - if tag[i] == '\\' { - i++ - } - i++ - } - if i >= len(tag) { - break - } - qvalue := string(tag[:i+1]) - tag = tag[i+1:] - - if key == name { - value, _ := strconv.Unquote(qvalue) - return value - } - } - return "" -} - -// Field returns the i'th struct field. -func (t *structType) Field(i int) (f StructField) { - if i < 0 || i >= len(t.fields) { - return - } - p := &t.fields[i] - f.Type = toType(p.typ) - if p.name != nil { - f.Name = *p.name - } else { - t := f.Type - if t.Kind() == Ptr { - t = t.Elem() - } - f.Name = t.Name() - f.Anonymous = true - } - if p.pkgPath != nil { - f.PkgPath = *p.pkgPath - } - if p.tag != nil { - f.Tag = StructTag(*p.tag) - } - 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, - // 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 - // postponed that ugliness until there is a demonstrated - // need for the performance. This is issue 2320. - f.Index = []int{i} - return -} - -// TODO(gri): Should there be an error/bool indicator if the index -// is wrong for FieldByIndex? - -// FieldByIndex returns the nested field corresponding to index. -func (t *structType) FieldByIndex(index []int) (f StructField) { - f.Type = toType(&t.rtype) - for i, x := range index { - if i > 0 { - ft := f.Type - if ft.Kind() == Ptr && ft.Elem().Kind() == Struct { - ft = ft.Elem() - } - f.Type = ft - } - f = f.Type.Field(x) - } - return -} - -// A fieldScan represents an item on the fieldByNameFunc scan work list. -type fieldScan struct { - typ *structType - index []int -} - -// FieldByNameFunc returns the struct field with a name that satisfies the -// match function and a boolean to indicate if the field was found. -func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) { - // This uses the same condition that the Go language does: there must be a unique instance - // of the match at a given depth level. If there are multiple instances of a match at the - // same depth, they annihilate each other and inhibit any possible match at a lower level. - // The algorithm is breadth first search, one depth level at a time. - - // The current and next slices are work queues: - // current lists the fields to visit on this depth level, - // and next lists the fields on the next lower level. - current := []fieldScan{} - next := []fieldScan{{typ: t}} - - // nextCount records the number of times an embedded type has been - // encountered and considered for queueing in the 'next' slice. - // We only queue the first one, but we increment the count on each. - // If a struct type T can be reached more than once at a given depth level, - // then it annihilates itself and need not be considered at all when we - // process that next depth level. - var nextCount map[*structType]int - - // visited records the structs that have been considered already. - // Embedded pointer fields can create cycles in the graph of - // reachable embedded types; visited avoids following those cycles. - // It also avoids duplicated effort: if we didn't find the field in an - // embedded type T at level 2, we won't find it in one at level 4 either. - visited := map[*structType]bool{} - - for len(next) > 0 { - current, next = next, current[:0] - count := nextCount - nextCount = nil - - // Process all the fields at this depth, now listed in 'current'. - // The loop queues embedded fields found in 'next', for processing during the next - // iteration. The multiplicity of the 'current' field counts is recorded - // in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'. - for _, scan := range current { - t := scan.typ - if visited[t] { - // We've looked through this type before, at a higher level. - // That higher level would shadow the lower level we're now at, - // so this one can't be useful to us. Ignore it. - continue - } - visited[t] = true - for i := range t.fields { - f := &t.fields[i] - // Find name and type for field f. - var fname string - var ntyp *rtype - if f.name != nil { - fname = *f.name - } else { - // Anonymous field of type T or *T. - // Name taken from type. - ntyp = f.typ - if ntyp.Kind() == Ptr { - ntyp = ntyp.Elem().common() - } - fname = ntyp.Name() - } - - // Does it match? - if match(fname) { - // Potential match - if count[t] > 1 || ok { - // Name appeared multiple times at this level: annihilate. - return StructField{}, false - } - result = t.Field(i) - result.Index = nil - result.Index = append(result.Index, scan.index...) - result.Index = append(result.Index, i) - ok = true - continue - } - - // Queue embedded struct fields for processing with next level, - // but only if we haven't seen a match yet at this level and only - // if the embedded types haven't already been queued. - if ok || ntyp == nil || ntyp.Kind() != Struct { - continue - } - styp := (*structType)(unsafe.Pointer(ntyp)) - if nextCount[styp] > 0 { - nextCount[styp] = 2 // exact multiple doesn't matter - continue - } - if nextCount == nil { - nextCount = map[*structType]int{} - } - nextCount[styp] = 1 - if count[t] > 1 { - nextCount[styp] = 2 // exact multiple doesn't matter - } - var index []int - index = append(index, scan.index...) - index = append(index, i) - next = append(next, fieldScan{styp, index}) - } - } - if ok { - break - } - } - return -} - -// FieldByName returns the struct field with the given name -// and a boolean to indicate if the field was found. -func (t *structType) FieldByName(name string) (f StructField, present bool) { - // Quick check for top-level name, or struct without anonymous fields. - hasAnon := false - if name != "" { - for i := range t.fields { - tf := &t.fields[i] - if tf.name == nil { - hasAnon = true - continue - } - if *tf.name == name { - return t.Field(i), true - } - } - } - if !hasAnon { - return - } - return t.FieldByNameFunc(func(s string) bool { return s == name }) -} - -// TypeOf returns the reflection Type of the value in the interface{}. -// TypeOf(nil) returns nil. -func TypeOf(i interface{}) Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - return toType(eface.typ) -} - -// ptrMap is the cache for PtrTo. -var ptrMap struct { - sync.RWMutex - m map[*rtype]*ptrType -} - -// garbage collection bytecode program for pointer to memory without pointers. -// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. -type ptrDataGC struct { - width uintptr // sizeof(ptr) - op uintptr // _GC_APTR - off uintptr // 0 - end uintptr // _GC_END -} - -var ptrDataGCProg = ptrDataGC{ - width: unsafe.Sizeof((*byte)(nil)), - op: _GC_APTR, - off: 0, - end: _GC_END, -} - -// garbage collection bytecode program for pointer to memory with pointers. -// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. -type ptrGC struct { - width uintptr // sizeof(ptr) - op uintptr // _GC_PTR - off uintptr // 0 - elemgc unsafe.Pointer // element gc type - end uintptr // _GC_END -} - -// PtrTo returns the pointer type with element t. -// For example, if t represents type Foo, PtrTo(t) represents *Foo. -func PtrTo(t Type) Type { - return t.(*rtype).ptrTo() -} - -func (t *rtype) ptrTo() *rtype { - if p := t.ptrToThis; p != nil { - 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. - ptrMap.RLock() - if m := ptrMap.m; m != nil { - if p := m[t]; p != nil { - ptrMap.RUnlock() - return &p.rtype - } - } - ptrMap.RUnlock() - ptrMap.Lock() - if ptrMap.m == nil { - ptrMap.m = make(map[*rtype]*ptrType) - } - p := ptrMap.m[t] - if p != nil { - // some other goroutine won the race and created it - ptrMap.Unlock() - return &p.rtype - } - - // Create a new ptrType starting with the description - // of an *unsafe.Pointer. - p = new(ptrType) - var iptr interface{} = (*unsafe.Pointer)(nil) - prototype := *(**ptrType)(unsafe.Pointer(&iptr)) - *p = *prototype - - s := "*" + *t.string - p.string = &s - - // For the type structures linked into the binary, the - // compiler provides a good hash of the string. - // Create a good hash for the new string by using - // the FNV-1 hash's mixing function to combine the - // old hash and the new "*". - p.hash = fnv1(t.hash, '*') - - p.uncommonType = nil - p.ptrToThis = nil - p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) - p.elem = t - - if t.kind&kindNoPointers != 0 { - p.gc = unsafe.Pointer(&ptrDataGCProg) - } else { - p.gc = unsafe.Pointer(&ptrGC{ - width: p.size, - op: _GC_PTR, - off: 0, - elemgc: t.gc, - end: _GC_END, - }) - } - // INCORRECT. Uncomment to check that TestPtrToGC fails when p.gc is wrong. - //p.gc = unsafe.Pointer(&badGC{width: p.size, end: _GC_END}) - - ptrMap.m[t] = p - ptrMap.Unlock() - return &p.rtype -} - -// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function. -func fnv1(x uint32, list ...byte) uint32 { - for _, b := range list { - x = x*16777619 ^ uint32(b) - } - return x -} - -func (t *rtype) Implements(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.Implements") - } - if u.Kind() != Interface { - panic("reflect: non-interface type passed to Type.Implements") - } - return implements(u.(*rtype), t) -} - -func (t *rtype) AssignableTo(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.AssignableTo") - } - uu := u.(*rtype) - return directlyAssignable(uu, t) || implements(uu, t) -} - -func (t *rtype) ConvertibleTo(u Type) bool { - if u == nil { - panic("reflect: nil type passed to Type.ConvertibleTo") - } - uu := u.(*rtype) - return convertOp(uu, t) != nil -} - -// implements returns true if the type V implements the interface type T. -func implements(T, V *rtype) bool { - if T.Kind() != Interface { - return false - } - t := (*interfaceType)(unsafe.Pointer(T)) - if len(t.methods) == 0 { - return true - } - - // The same algorithm applies in both cases, but the - // method tables for an interface type and a concrete type - // are different, so the code is duplicated. - // In both cases the algorithm is a linear scan over the two - // lists - T's methods and V's methods - simultaneously. - // Since method tables are stored in a unique sorted order - // (alphabetical, with no duplicate method names), the scan - // through V's methods must hit a match for each of T's - // methods along the way, or else V does not implement T. - // This lets us run the scan in overall linear time instead of - // the quadratic time a naive search would require. - // See also ../runtime/iface.c. - if V.Kind() == Interface { - v := (*interfaceType)(unsafe.Pointer(V)) - i := 0 - for j := 0; j < len(v.methods); j++ { - tm := &t.methods[i] - vm := &v.methods[j] - if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ { - if i++; i >= len(t.methods) { - return true - } - } - } - return false - } - - v := V.uncommon() - if v == nil { - return false - } - i := 0 - for j := 0; j < len(v.methods); j++ { - tm := &t.methods[i] - vm := &v.methods[j] - if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ { - if i++; i >= len(t.methods) { - return true - } - } - } - return false -} - -// directlyAssignable returns true if a value x of type V can be directly -// assigned (using memmove) to a value of type T. -// http://golang.org/doc/go_spec.html#Assignability -// Ignoring the interface rules (implemented elsewhere) -// and the ideal constant rules (no ideal constants at run time). -func directlyAssignable(T, V *rtype) bool { - // x's type V is identical to T? - if T == V { - return true - } - - // Otherwise at least one of T and V must be unnamed - // and they must have the same kind. - if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() { - return false - } - - // x's type T and V must have identical underlying types. - return haveIdenticalUnderlyingType(T, V) -} - -func haveIdenticalUnderlyingType(T, V *rtype) bool { - if T == V { - return true - } - - kind := T.Kind() - if kind != V.Kind() { - return false - } - - // Non-composite types of equal kind have same underlying type - // (the predefined instance of the type). - if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer { - return true - } - - // Composite types. - switch kind { - case Array: - return T.Elem() == V.Elem() && T.Len() == V.Len() - - case Chan: - // Special case: - // x is a bidirectional channel value, T is a channel type, - // and x's type V and T have identical element types. - if V.ChanDir() == BothDir && T.Elem() == V.Elem() { - return true - } - - // Otherwise continue test for identical underlying type. - return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem() - - case Func: - t := (*funcType)(unsafe.Pointer(T)) - v := (*funcType)(unsafe.Pointer(V)) - if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) { - return false - } - for i, typ := range t.in { - if typ != v.in[i] { - return false - } - } - for i, typ := range t.out { - if typ != v.out[i] { - return false - } - } - return true - - case Interface: - t := (*interfaceType)(unsafe.Pointer(T)) - v := (*interfaceType)(unsafe.Pointer(V)) - if len(t.methods) == 0 && len(v.methods) == 0 { - return true - } - // Might have the same methods but still - // need a run time conversion. - return false - - case Map: - return T.Key() == V.Key() && T.Elem() == V.Elem() - - case Ptr, Slice: - return T.Elem() == V.Elem() - - case Struct: - t := (*structType)(unsafe.Pointer(T)) - v := (*structType)(unsafe.Pointer(V)) - if len(t.fields) != len(v.fields) { - return false - } - for i := range t.fields { - tf := &t.fields[i] - vf := &v.fields[i] - if tf.name != vf.name && (tf.name == nil || vf.name == nil || *tf.name != *vf.name) { - return false - } - if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) { - return false - } - if tf.typ != vf.typ { - return false - } - if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) { - return false - } - if tf.offset != vf.offset { - return false - } - } - return true - } - - return false -} - -// typelinks is implemented in package runtime. -// It returns a slice of all the 'typelink' information in the binary, -// which is to say a slice of known types, sorted by string. -// Note that strings are not unique identifiers for types: -// there can be more than one with a given string. -// Only types we might want to look up are included: -// channels, maps, slices, and arrays. -func typelinks() []*rtype - -// typesByString returns the subslice of typelinks() whose elements have -// the given string representation. -// It may be empty (no known types with that string) or may have -// multiple elements (multiple types with that string). -func typesByString(s string) []*rtype { - typ := typelinks() - - // We are looking for the first index i where the string becomes >= s. - // This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s). - i, j := 0, len(typ) - for i < j { - h := i + (j-i)/2 // avoid overflow when computing h - // i ≤ h < j - if !(*typ[h].string >= s) { - i = h + 1 // preserves f(i-1) == false - } else { - j = h // preserves f(j) == true - } - } - // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. - - // Having found the first, linear scan forward to find the last. - // We could do a second binary search, but the caller is going - // to do a linear scan anyway. - j = i - for j < len(typ) && *typ[j].string == s { - j++ - } - - // This slice will be empty if the string is not found. - return typ[i:j] -} - -// The lookupCache caches ChanOf, MapOf, and SliceOf lookups. -var lookupCache struct { - sync.RWMutex - m map[cacheKey]*rtype -} - -// A cacheKey is the key for use in the lookupCache. -// Four values describe any of the types we are looking for: -// type kind, one or two subtypes, and an extra integer. -type cacheKey struct { - kind Kind - t1 *rtype - t2 *rtype - extra uintptr -} - -// cacheGet looks for a type under the key k in the lookupCache. -// If it finds one, it returns that type. -// If not, it returns nil with the cache locked. -// The caller is expected to use cachePut to unlock the cache. -func cacheGet(k cacheKey) Type { - lookupCache.RLock() - t := lookupCache.m[k] - lookupCache.RUnlock() - if t != nil { - return t - } - - lookupCache.Lock() - t = lookupCache.m[k] - if t != nil { - lookupCache.Unlock() - return t - } - - if lookupCache.m == nil { - lookupCache.m = make(map[cacheKey]*rtype) - } - - return nil -} - -// cachePut stores the given type in the cache, unlocks the cache, -// and returns the type. It is expected that the cache is locked -// because cacheGet returned nil. -func cachePut(k cacheKey, t *rtype) Type { - lookupCache.m[k] = t - lookupCache.Unlock() - return t -} - -// garbage collection bytecode program for chan. -// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. -type chanGC struct { - width uintptr // sizeof(map) - op uintptr // _GC_CHAN_PTR - off uintptr // 0 - typ *rtype // map type - end uintptr // _GC_END -} - -type badGC struct { - width uintptr - end uintptr -} - -// ChanOf returns the channel type with the given direction and element type. -// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. -// -// The gc runtime imposes a limit of 64 kB on channel element types. -// If t's size is equal to or exceeds this limit, ChanOf panics. -func ChanOf(dir ChanDir, t Type) Type { - typ := t.(*rtype) - - // Look in cache. - ckey := cacheKey{Chan, typ, nil, uintptr(dir)} - if ch := cacheGet(ckey); ch != nil { - return ch - } - - // This restriction is imposed by the gc compiler and the runtime. - if typ.size >= 1<<16 { - lookupCache.Unlock() - panic("reflect.ChanOf: element size too large") - } - - // Look in known types. - // TODO: Precedence when constructing string. - var s string - switch dir { - default: - lookupCache.Unlock() - panic("reflect.ChanOf: invalid dir") - case SendDir: - s = "chan<- " + *typ.string - case RecvDir: - s = "<-chan " + *typ.string - case BothDir: - s = "chan " + *typ.string - } - for _, tt := range typesByString(s) { - ch := (*chanType)(unsafe.Pointer(tt)) - if ch.elem == typ && ch.dir == uintptr(dir) { - return cachePut(ckey, tt) - } - } - - // Make a channel type. - var ichan interface{} = (chan unsafe.Pointer)(nil) - prototype := *(**chanType)(unsafe.Pointer(&ichan)) - ch := new(chanType) - *ch = *prototype - ch.string = &s - ch.hash = fnv1(typ.hash, 'c', byte(dir)) - ch.elem = typ - ch.uncommonType = nil - ch.ptrToThis = nil - ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) - - ch.gc = unsafe.Pointer(&chanGC{ - width: ch.size, - op: _GC_CHAN_PTR, - off: 0, - typ: &ch.rtype, - end: _GC_END, - }) - - // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong. - //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END}) - - return cachePut(ckey, &ch.rtype) -} - -func ismapkey(*rtype) bool // implemented in runtime - -// MapOf returns the map type with the given key and element types. -// For example, if k represents int and e represents string, -// MapOf(k, e) represents map[int]string. -// -// If the key type is not a valid map key type (that is, if it does -// not implement Go's == operator), MapOf panics. -func MapOf(key, elem Type) Type { - ktyp := key.(*rtype) - etyp := elem.(*rtype) - - if !ismapkey(ktyp) { - panic("reflect.MapOf: invalid key type " + ktyp.String()) - } - - // Look in cache. - ckey := cacheKey{Map, ktyp, etyp, 0} - if mt := cacheGet(ckey); mt != nil { - return mt - } - - // Look in known types. - s := "map[" + *ktyp.string + "]" + *etyp.string - for _, tt := range typesByString(s) { - mt := (*mapType)(unsafe.Pointer(tt)) - if mt.key == ktyp && mt.elem == etyp { - return cachePut(ckey, tt) - } - } - - // Make a map type. - var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) - prototype := *(**mapType)(unsafe.Pointer(&imap)) - mt := new(mapType) - *mt = *prototype - mt.string = &s - mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash)) - mt.key = ktyp - mt.elem = etyp - mt.bucket = bucketOf(ktyp, etyp) - mt.hmap = hMapOf(mt.bucket) - mt.uncommonType = nil - mt.ptrToThis = nil - mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) - mt.gc = unsafe.Pointer(&ptrGC{ - width: unsafe.Sizeof(uintptr(0)), - op: _GC_PTR, - off: 0, - elemgc: mt.hmap.gc, - end: _GC_END, - }) - - // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues - // fail when mt.gc is wrong. - //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END}) - - return cachePut(ckey, &mt.rtype) -} - -// Make sure these routines stay in sync with ../../pkg/runtime/hashmap.c! -// 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 -// for possible debugging use. -const ( - _BUCKETSIZE = 8 - _MAXKEYSIZE = 128 - _MAXVALSIZE = 128 -) - -func bucketOf(ktyp, etyp *rtype) *rtype { - if ktyp.size > _MAXKEYSIZE { - ktyp = PtrTo(ktyp).(*rtype) - } - if etyp.size > _MAXVALSIZE { - etyp = PtrTo(etyp).(*rtype) - } - ptrsize := unsafe.Sizeof(uintptr(0)) - - gc := make([]uintptr, 1) // first entry is size, filled in at the end - offset := _BUCKETSIZE * unsafe.Sizeof(uint8(0)) // topbits - gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow - offset += ptrsize - - if runtime.GOARCH == "amd64p32" { - offset += 4 - } - - // keys - if ktyp.kind&kindNoPointers == 0 { - gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size) - gc = appendGCProgram(gc, ktyp) - gc = append(gc, _GC_ARRAY_NEXT) - } - offset += _BUCKETSIZE * ktyp.size - - // values - if etyp.kind&kindNoPointers == 0 { - gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, etyp.size) - gc = appendGCProgram(gc, etyp) - gc = append(gc, _GC_ARRAY_NEXT) - } - offset += _BUCKETSIZE * etyp.size - - gc = append(gc, _GC_END) - gc[0] = offset - gc[3] = uintptr(unsafe.Pointer(&gc[0])) // set self pointer - - b := new(rtype) - b.size = offset - b.gc = unsafe.Pointer(&gc[0]) - s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" - b.string = &s - return b -} - -// Take the GC program for "t" and append it to the GC program "gc". -func appendGCProgram(gc []uintptr, t *rtype) []uintptr { - p := t.gc - p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size -loop: - for { - var argcnt int - switch *(*uintptr)(p) { - case _GC_END: - // Note: _GC_END not included in append - break loop - case _GC_ARRAY_NEXT: - argcnt = 0 - case _GC_APTR, _GC_STRING, _GC_EFACE, _GC_IFACE: - argcnt = 1 - case _GC_PTR, _GC_CALL, _GC_CHAN_PTR, _GC_SLICE: - argcnt = 2 - case _GC_ARRAY_START, _GC_REGION: - argcnt = 3 - default: - 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)) - p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) - } - } - return gc -} -func hMapOf(bucket *rtype) *rtype { - ptrsize := unsafe.Sizeof(uintptr(0)) - - // make gc program & compute hmap size - gc := make([]uintptr, 1) // first entry is size, filled in at the end - offset := unsafe.Sizeof(uint(0)) // count - offset += unsafe.Sizeof(uint32(0)) // flags - offset += unsafe.Sizeof(uint32(0)) // hash0 - offset += unsafe.Sizeof(uint8(0)) // B - offset += unsafe.Sizeof(uint8(0)) // keysize - offset += unsafe.Sizeof(uint8(0)) // valuesize - offset = (offset + 1) / 2 * 2 - offset += unsafe.Sizeof(uint16(0)) // bucketsize - offset = (offset + ptrsize - 1) / ptrsize * ptrsize - gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // buckets - offset += ptrsize - gc = append(gc, _GC_PTR, offset, uintptr(bucket.gc)) // oldbuckets - offset += ptrsize - offset += ptrsize // nevacuate - gc = append(gc, _GC_END) - gc[0] = offset - - h := new(rtype) - h.size = offset - h.gc = unsafe.Pointer(&gc[0]) - s := "hmap(" + *bucket.string + ")" - h.string = &s - return h -} - -// garbage collection bytecode program for slice of non-zero-length values. -// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. -type sliceGC struct { - width uintptr // sizeof(slice) - op uintptr // _GC_SLICE - off uintptr // 0 - elemgc unsafe.Pointer // element gc program - end uintptr // _GC_END -} - -// garbage collection bytecode program for slice of zero-length values. -// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym. -type sliceEmptyGC struct { - width uintptr // sizeof(slice) - op uintptr // _GC_APTR - off uintptr // 0 - end uintptr // _GC_END -} - -var sliceEmptyGCProg = sliceEmptyGC{ - width: unsafe.Sizeof([]byte(nil)), - op: _GC_APTR, - off: 0, - end: _GC_END, -} - -// SliceOf returns the slice type with element type t. -// For example, if t represents int, SliceOf(t) represents []int. -func SliceOf(t Type) Type { - typ := t.(*rtype) - - // Look in cache. - ckey := cacheKey{Slice, typ, nil, 0} - if slice := cacheGet(ckey); slice != nil { - return slice - } - - // Look in known types. - s := "[]" + *typ.string - for _, tt := range typesByString(s) { - slice := (*sliceType)(unsafe.Pointer(tt)) - if slice.elem == typ { - return cachePut(ckey, tt) - } - } - - // Make a slice type. - var islice interface{} = ([]unsafe.Pointer)(nil) - prototype := *(**sliceType)(unsafe.Pointer(&islice)) - slice := new(sliceType) - *slice = *prototype - slice.string = &s - slice.hash = fnv1(typ.hash, '[') - slice.elem = typ - slice.uncommonType = nil - slice.ptrToThis = nil - slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) - - if typ.size == 0 { - slice.gc = unsafe.Pointer(&sliceEmptyGCProg) - } else { - slice.gc = unsafe.Pointer(&sliceGC{ - width: slice.size, - op: _GC_SLICE, - off: 0, - elemgc: typ.gc, - end: _GC_END, - }) - } - - // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong. - //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END}) - - return cachePut(ckey, &slice.rtype) -} - -// ArrayOf returns the array type with the given count and element type. -// For example, if t represents int, ArrayOf(5, t) represents [5]int. -// -// If the resulting type would be larger than the available address space, -// ArrayOf panics. -// -// TODO(rsc): Unexported for now. Export once the alg field is set correctly -// for the type. This may require significant work. -func arrayOf(count int, elem Type) Type { - typ := elem.(*rtype) - slice := SliceOf(elem) - - // Look in cache. - ckey := cacheKey{Array, typ, nil, uintptr(count)} - if slice := cacheGet(ckey); slice != nil { - return slice - } - - // Look in known types. - s := "[" + strconv.Itoa(count) + "]" + *typ.string - for _, tt := range typesByString(s) { - slice := (*sliceType)(unsafe.Pointer(tt)) - if slice.elem == typ { - return cachePut(ckey, tt) - } - } - - // Make an array type. - var iarray interface{} = [1]unsafe.Pointer{} - prototype := *(**arrayType)(unsafe.Pointer(&iarray)) - array := new(arrayType) - *array = *prototype - array.string = &s - array.hash = fnv1(typ.hash, '[') - for n := uint32(count); n > 0; n >>= 8 { - array.hash = fnv1(array.hash, byte(n)) - } - array.hash = fnv1(array.hash, ']') - array.elem = typ - max := ^uintptr(0) / typ.size - if uintptr(count) > max { - panic("reflect.ArrayOf: array size would exceed virtual address space") - } - array.size = typ.size * uintptr(count) - array.align = typ.align - array.fieldAlign = typ.fieldAlign - // TODO: array.alg - // TODO: array.gc - array.uncommonType = nil - array.ptrToThis = nil - array.zero = unsafe.Pointer(&make([]byte, array.size)[0]) - array.len = uintptr(count) - array.slice = slice.(*rtype) - - return cachePut(ckey, &array.rtype) -} - -// toType converts from a *rtype to a Type that can be returned -// to the client of package reflect. In gc, the only concern is that -// a nil *rtype must be replaced by a nil Type, but in gccgo this -// function takes care of ensuring that multiple *rtype for the same -// type are coalesced into a single Type. -func toType(t *rtype) Type { - if t == nil { - return nil - } - return t -} - -type layoutKey struct { - t *rtype // function signature - rcvr *rtype // receiver type, or nil if none -} - -type layoutType struct { - t *rtype - argSize uintptr // size of arguments - retOffset uintptr // offset of return values. -} - -var layoutCache struct { - sync.RWMutex - m map[layoutKey]layoutType -} - -// funcLayout computes a struct type representing the layout of the -// function arguments and return values for the function type t. -// If rcvr != nil, rcvr specifies the type of the receiver. -// The returned type exists only for GC, so we only fill out GC relevant info. -// Currently, that's just size and the GC program. We also fill in -// the name for possible debugging use. -func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) { - if t.Kind() != Func { - panic("reflect: funcLayout of non-func type") - } - if rcvr != nil && rcvr.Kind() == Interface { - panic("reflect: funcLayout with interface receiver " + rcvr.String()) - } - k := layoutKey{t, rcvr} - layoutCache.RLock() - if x := layoutCache.m[k]; x.t != nil { - layoutCache.RUnlock() - return x.t, x.argSize, x.retOffset - } - layoutCache.RUnlock() - layoutCache.Lock() - if x := layoutCache.m[k]; x.t != nil { - layoutCache.Unlock() - return x.t, x.argSize, x.retOffset - } - - tt := (*funcType)(unsafe.Pointer(t)) - - // compute gc program for arguments - gc := make([]uintptr, 1) // first entry is size, filled in at the end - offset := uintptr(0) - if rcvr != nil { - // Reflect uses the "interface" calling convention for - // methods, where receivers take one word of argument - // space no matter how big they actually are. - if rcvr.size > ptrSize { - // we pass a pointer to the receiver. - gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc)) - } else if rcvr.pointers() { - // rcvr is a one-word pointer object. Its gc program - // is just what we need here. - gc = appendGCProgram(gc, rcvr) - } - offset += ptrSize - } - for _, arg := range tt.in { - offset = align(offset, uintptr(arg.align)) - if arg.pointers() { - gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc)) - } - offset += arg.size - } - argSize = offset - if runtime.GOARCH == "amd64p32" { - offset = align(offset, 8) - } - offset = align(offset, ptrSize) - retOffset = offset - for _, res := range tt.out { - offset = align(offset, uintptr(res.align)) - if res.pointers() { - gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc)) - } - offset += res.size - } - gc = append(gc, _GC_END) - gc[0] = offset - - // build dummy rtype holding gc program - x := new(rtype) - x.size = offset - x.gc = unsafe.Pointer(&gc[0]) - var s string - if rcvr != nil { - s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" - } else { - s = "funcargs(" + *t.string + ")" - } - x.string = &s - - // cache result for future callers - if layoutCache.m == nil { - layoutCache.m = make(map[layoutKey]layoutType) - } - layoutCache.m[k] = layoutType{ - t: x, - argSize: argSize, - retOffset: retOffset, - } - layoutCache.Unlock() - return x, argSize, retOffset -} diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go deleted file mode 100644 index 576cbc398..000000000 --- a/src/pkg/reflect/value.go +++ /dev/null @@ -1,2684 +0,0 @@ -// 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 reflect - -import ( - "math" - "runtime" - "strconv" - "unsafe" -) - -const bigEndian = false // can be smarter if we find a big-endian machine -const ptrSize = unsafe.Sizeof((*byte)(nil)) -const cannotSet = "cannot set value obtained from unexported struct field" - -// TODO: This will have to go away when -// the new gc goes in. -func memmove(adst, asrc unsafe.Pointer, n uintptr) { - dst := uintptr(adst) - src := uintptr(asrc) - switch { - case src < dst && src+n > dst: - // byte copy backward - // careful: i is unsigned - for i := n; i > 0; { - i-- - *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) - } - case (n|src|dst)&(ptrSize-1) != 0: - // byte copy forward - for i := uintptr(0); i < n; i++ { - *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) - } - default: - // word copy forward - for i := uintptr(0); i < n; i += ptrSize { - *(*uintptr)(unsafe.Pointer(dst + i)) = *(*uintptr)(unsafe.Pointer(src + i)) - } - } -} - -// Value is the reflection interface to a Go value. -// -// 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 -// inappropriate to the kind of type causes a run time panic. -// -// The zero Value represents no value. -// Its IsValid method returns false, its Kind method returns Invalid, -// its String method returns "<invalid Value>", and all other methods panic. -// Most functions and methods never return an invalid value. -// If one does, its documentation states the conditions explicitly. -// -// A Value can be used concurrently by multiple goroutines provided that -// the underlying Go value can be used concurrently for the equivalent -// direct operations. -type Value struct { - // typ holds the type of the value represented by a Value. - typ *rtype - - // Pointer-valued data or, if flagIndir is set, pointer to data. - // Valid when either flagIndir is set or typ.pointers() is true. - ptr unsafe.Pointer - - // Non-pointer-valued data. When the data is smaller - // than a word, it begins at the first byte (in the memory - // address sense) of this field. - // Valid when flagIndir is not set and typ.pointers() is false. - scalar uintptr - - // flag holds metadata about the value. - // The lowest bits are flag bits: - // - flagRO: obtained via unexported field, so read-only - // - flagIndir: val holds a pointer to the data - // - flagAddr: v.CanAddr is true (implies flagIndir) - // - flagMethod: v is a method value. - // The next five bits give the Kind of the value. - // This repeats typ.Kind() except for method values. - // The remaining 23+ bits give a method number for method values. - // If flag.kind() != Func, code can assume that flagMethod is unset. - // If typ.size > ptrSize, code can assume that flagIndir is set. - flag - - // A method value represents a curried method invocation - // 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. -} - -type flag uintptr - -const ( - flagRO flag = 1 << iota - flagIndir - flagAddr - flagMethod - flagKindShift = iota - flagKindWidth = 5 // there are 27 kinds - flagKindMask flag = 1<<flagKindWidth - 1 - flagMethodShift = flagKindShift + flagKindWidth -) - -func (f flag) kind() Kind { - return Kind((f >> flagKindShift) & flagKindMask) -} - -// pointer returns the underlying pointer represented by v. -// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer -func (v Value) pointer() unsafe.Pointer { - if v.typ.size != ptrSize || !v.typ.pointers() { - panic("can't call pointer on a non-pointer Value") - } - if v.flag&flagIndir != 0 { - return *(*unsafe.Pointer)(v.ptr) - } - return v.ptr -} - -// packEface converts v to the empty interface. -func packEface(v Value) interface{} { - t := v.typ - var i interface{} - e := (*emptyInterface)(unsafe.Pointer(&i)) - // First, fill in the data portion of the interface. - switch { - case t.size > ptrSize: - // Value is indirect, and so is the interface we're making. - ptr := v.ptr - if v.flag&flagAddr != 0 { - // TODO: pass safe boolean from valueInterface so - // we don't need to copy if safe==true? - c := unsafe_New(t) - memmove(c, ptr, t.size) - ptr = c - } - e.word = iword(ptr) - case v.flag&flagIndir != 0: - // Value is indirect, but interface is direct. We need - // to load the data at v.ptr into the interface data word. - if t.pointers() { - e.word = iword(*(*unsafe.Pointer)(v.ptr)) - } else { - e.word = iword(loadScalar(v.ptr, t.size)) - } - default: - // Value is direct, and so is the interface. - if t.pointers() { - e.word = iword(v.ptr) - } else { - e.word = iword(v.scalar) - } - } - // 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. - e.typ = t - return i -} - -// unpackEface converts the empty interface i to a Value. -func unpackEface(i interface{}) Value { - e := (*emptyInterface)(unsafe.Pointer(&i)) - // NOTE: don't read e.word until we know whether it is really a pointer or not. - t := e.typ - if t == nil { - return Value{} - } - f := flag(t.Kind()) << flagKindShift - if t.size > ptrSize { - return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir} - } - if t.pointers() { - return Value{t, unsafe.Pointer(e.word), 0, f} - } - return Value{t, nil, uintptr(e.word), f} -} - -// A ValueError occurs when a Value method is invoked on -// a Value that does not support it. Such cases are documented -// in the description of each method. -type ValueError struct { - Method string - Kind Kind -} - -func (e *ValueError) Error() string { - if e.Kind == 0 { - return "reflect: call of " + e.Method + " on zero Value" - } - return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value" -} - -// methodName returns the name of the calling method, -// assumed to be two stack frames above. -func methodName() string { - pc, _, _, _ := runtime.Caller(2) - f := runtime.FuncForPC(pc) - if f == nil { - return "unknown method" - } - return f.Name() -} - -// An iword is the word that would be stored in an -// interface to represent a given value v. Specifically, if v is -// bigger than a pointer, its word is a pointer to v's data. -// Otherwise, its word holds the data stored -// in its leading bytes (so is not a pointer). -// This type is very dangerous for the garbage collector because -// it must be treated conservatively. We try to never expose it -// to the GC here so that GC remains precise. -type iword unsafe.Pointer - -// loadScalar loads n bytes at p from memory into a uintptr -// that forms the second word of an interface. The data -// must be non-pointer in nature. -func loadScalar(p unsafe.Pointer, n uintptr) uintptr { - // Run the copy ourselves instead of calling memmove - // to avoid moving w to the heap. - var w uintptr - switch n { - default: - panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value") - case 0: - case 1: - *(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p) - case 2: - *(*uint16)(unsafe.Pointer(&w)) = *(*uint16)(p) - case 3: - *(*[3]byte)(unsafe.Pointer(&w)) = *(*[3]byte)(p) - case 4: - *(*uint32)(unsafe.Pointer(&w)) = *(*uint32)(p) - case 5: - *(*[5]byte)(unsafe.Pointer(&w)) = *(*[5]byte)(p) - case 6: - *(*[6]byte)(unsafe.Pointer(&w)) = *(*[6]byte)(p) - case 7: - *(*[7]byte)(unsafe.Pointer(&w)) = *(*[7]byte)(p) - case 8: - *(*uint64)(unsafe.Pointer(&w)) = *(*uint64)(p) - } - return w -} - -// storeScalar stores n bytes from w into p. -func storeScalar(p unsafe.Pointer, w uintptr, n uintptr) { - // Run the copy ourselves instead of calling memmove - // to avoid moving w to the heap. - switch n { - default: - panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value") - case 0: - case 1: - *(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w)) - case 2: - *(*uint16)(p) = *(*uint16)(unsafe.Pointer(&w)) - case 3: - *(*[3]byte)(p) = *(*[3]byte)(unsafe.Pointer(&w)) - case 4: - *(*uint32)(p) = *(*uint32)(unsafe.Pointer(&w)) - case 5: - *(*[5]byte)(p) = *(*[5]byte)(unsafe.Pointer(&w)) - case 6: - *(*[6]byte)(p) = *(*[6]byte)(unsafe.Pointer(&w)) - case 7: - *(*[7]byte)(p) = *(*[7]byte)(unsafe.Pointer(&w)) - case 8: - *(*uint64)(p) = *(*uint64)(unsafe.Pointer(&w)) - } -} - -// emptyInterface is the header for an interface{} value. -type emptyInterface struct { - typ *rtype - word iword -} - -// nonEmptyInterface is the header for a interface value with methods. -type nonEmptyInterface struct { - // see ../runtime/iface.c:/Itab - itab *struct { - ityp *rtype // static interface type - typ *rtype // dynamic concrete type - link unsafe.Pointer - bad int32 - unused int32 - fun [100000]unsafe.Pointer // method table - } - word iword -} - -// mustBe panics if f's kind is not expected. -// Making this a method on flag instead of on Value -// (and embedding flag in Value) means that we can write -// the very clear v.mustBe(Bool) and have it compile into -// v.flag.mustBe(Bool), which will only bother to copy the -// single important word for the receiver. -func (f flag) mustBe(expected Kind) { - k := f.kind() - if k != expected { - panic(&ValueError{methodName(), k}) - } -} - -// mustBeExported panics if f records that the value was obtained using -// an unexported field. -func (f flag) mustBeExported() { - if f == 0 { - panic(&ValueError{methodName(), 0}) - } - if f&flagRO != 0 { - panic("reflect: " + methodName() + " using value obtained using unexported field") - } -} - -// mustBeAssignable panics if f records that the value is not assignable, -// which is to say that either it was obtained using an unexported field -// or it is not addressable. -func (f flag) mustBeAssignable() { - if f == 0 { - panic(&ValueError{methodName(), Invalid}) - } - // Assignable if addressable and not read-only. - if f&flagRO != 0 { - panic("reflect: " + methodName() + " using value obtained using unexported field") - } - if f&flagAddr == 0 { - panic("reflect: " + methodName() + " using unaddressable value") - } -} - -// Addr returns a pointer value representing the address of v. -// It panics if CanAddr() returns false. -// Addr is typically used to obtain a pointer to a struct field -// or slice element in order to call a method that requires a -// pointer receiver. -func (v Value) Addr() Value { - if v.flag&flagAddr == 0 { - panic("reflect.Value.Addr of unaddressable value") - } - return Value{v.typ.ptrTo(), v.ptr, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift} -} - -// Bool returns v's underlying value. -// It panics if v's kind is not Bool. -func (v Value) Bool() bool { - v.mustBe(Bool) - if v.flag&flagIndir != 0 { - return *(*bool)(v.ptr) - } - return *(*bool)(unsafe.Pointer(&v.scalar)) -} - -// Bytes returns v's underlying value. -// It panics if v's underlying value is not a slice of bytes. -func (v Value) Bytes() []byte { - v.mustBe(Slice) - if v.typ.Elem().Kind() != Uint8 { - panic("reflect.Value.Bytes of non-byte slice") - } - // Slice is always bigger than a word; assume flagIndir. - return *(*[]byte)(v.ptr) -} - -// runes returns v's underlying value. -// It panics if v's underlying value is not a slice of runes (int32s). -func (v Value) runes() []rune { - v.mustBe(Slice) - if v.typ.Elem().Kind() != Int32 { - panic("reflect.Value.Bytes of non-rune slice") - } - // Slice is always bigger than a word; assume flagIndir. - return *(*[]rune)(v.ptr) -} - -// CanAddr returns true if the value's address can be obtained with Addr. -// 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. -func (v Value) CanAddr() bool { - return v.flag&flagAddr != 0 -} - -// CanSet returns true if the value of v can be changed. -// A Value can be changed only if it is addressable and was not -// obtained by the use of unexported struct fields. -// If CanSet returns false, calling Set or any type-specific -// setter (e.g., SetBool, SetInt64) will panic. -func (v Value) CanSet() bool { - return v.flag&(flagAddr|flagRO) == flagAddr -} - -// Call calls the function v with the input arguments in. -// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]). -// Call panics if v's Kind is not Func. -// It returns the output results as Values. -// As in Go, each input argument must be assignable to the -// type of the function's corresponding input parameter. -// If v is a variadic function, Call creates the variadic slice parameter -// itself, copying in the corresponding values. -func (v Value) Call(in []Value) []Value { - v.mustBe(Func) - v.mustBeExported() - return v.call("Call", in) -} - -// CallSlice calls the variadic function v with the input arguments in, -// assigning the slice in[len(in)-1] to v's final variadic argument. -// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...). -// Call panics if v's Kind is not Func or if v is not variadic. -// It returns the output results as Values. -// As in Go, each input argument must be assignable to the -// type of the function's corresponding input parameter. -func (v Value) CallSlice(in []Value) []Value { - v.mustBe(Func) - v.mustBeExported() - return v.call("CallSlice", in) -} - -var callGC bool // for testing; see TestCallMethodJump - -var makeFuncStubFn = makeFuncStub -var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn)) -var methodValueCallFn = methodValueCall -var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn)) - -func (v Value) call(op string, in []Value) []Value { - // Get function pointer, type. - t := v.typ - var ( - fn unsafe.Pointer - rcvr Value - rcvrtype *rtype - ) - if v.flag&flagMethod != 0 { - rcvr = v - rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) - } else if v.flag&flagIndir != 0 { - fn = *(*unsafe.Pointer)(v.ptr) - } else { - fn = v.ptr - } - - if fn == nil { - panic("reflect.Value.Call: call of nil function") - } - - isSlice := op == "CallSlice" - n := t.NumIn() - if isSlice { - if !t.IsVariadic() { - panic("reflect: CallSlice of non-variadic function") - } - if len(in) < n { - panic("reflect: CallSlice with too few input arguments") - } - if len(in) > n { - panic("reflect: CallSlice with too many input arguments") - } - } else { - if t.IsVariadic() { - n-- - } - if len(in) < n { - panic("reflect: Call with too few input arguments") - } - if !t.IsVariadic() && len(in) > n { - panic("reflect: Call with too many input arguments") - } - } - for _, x := range in { - if x.Kind() == Invalid { - panic("reflect: " + op + " using zero Value argument") - } - } - for i := 0; i < n; i++ { - if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) { - panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String()) - } - } - if !isSlice && t.IsVariadic() { - // prepare slice for remaining values - m := len(in) - n - slice := MakeSlice(t.In(n), m, m) - elem := t.In(n).Elem() - for i := 0; i < m; i++ { - x := in[n+i] - if xt := x.Type(); !xt.AssignableTo(elem) { - panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op) - } - slice.Index(i).Set(x) - } - origIn := in - in = make([]Value, n+1) - copy(in[:n], origIn) - in[n] = slice - } - - nin := len(in) - if nin != t.NumIn() { - panic("reflect.Value.Call: wrong argument count") - } - nout := t.NumOut() - - // If target is makeFuncStub, short circuit the unpack onto stack / - // pack back into []Value for the args and return values. Just do the - // call directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls makeFuncStub, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - x := (*makeFuncImpl)(fn) - if x.code == makeFuncStubCode { - return x.fn(in) - } - - // If the target is methodValueCall, do its work here: add the receiver - // argument and call the real target directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls methodValueCall, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - y := (*methodValue)(fn) - if y.fn == methodValueCallCode { - rcvr = y.rcvr - rcvrtype, t, fn = methodReceiver("call", rcvr, y.method) - } - - // Compute frame type, allocate a chunk of memory for frame - frametype, _, retOffset := funcLayout(t, rcvrtype) - args := unsafe_New(frametype) - off := uintptr(0) - - // Copy inputs into args. - if rcvrtype != nil { - storeRcvr(rcvr, args) - off = ptrSize - } - for i, v := range in { - v.mustBeExported() - targ := t.In(i).(*rtype) - a := uintptr(targ.align) - off = (off + a - 1) &^ (a - 1) - n := targ.size - addr := unsafe.Pointer(uintptr(args) + off) - v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr)) - if v.flag&flagIndir != 0 { - memmove(addr, v.ptr, n) - } else if targ.pointers() { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - storeScalar(addr, v.scalar, n) - } - off += n - } - - // Call. - call(fn, args, uint32(frametype.size), uint32(retOffset)) - - // For testing; see TestCallMethodJump. - if callGC { - runtime.GC() - } - - // Copy return values out of args. - ret := make([]Value, nout) - off = retOffset - for i := 0; i < nout; i++ { - tv := t.Out(i) - a := uintptr(tv.Align()) - off = (off + a - 1) &^ (a - 1) - fl := flagIndir | flag(tv.Kind())<<flagKindShift - ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), 0, fl} - off += tv.Size() - } - - return ret -} - -// callReflect is the call implementation used by a function -// returned by MakeFunc. In many ways it is the opposite of the -// method Value.call above. The method above converts a call using Values -// into a call of a function with a concrete argument frame, while -// callReflect converts a call of a function with a concrete argument -// frame into a call using Values. -// It is in this file so that it can be next to the call method above. -// The remainder of the MakeFunc implementation is in makefunc.go. -// -// NOTE: This function must be marked as a "wrapper" in the generated code, -// so that the linker can make it work correctly for panic and recover. -// The gc compilers know to do that for the name "reflect.callReflect". -func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { - ftyp := ctxt.typ - f := ctxt.fn - - // Copy argument frame into Values. - ptr := frame - off := uintptr(0) - in := make([]Value, 0, len(ftyp.in)) - for _, arg := range ftyp.in { - typ := arg - off += -off & uintptr(typ.align-1) - addr := unsafe.Pointer(uintptr(ptr) + off) - v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift} - if typ.size > ptrSize { - // value does not fit in word. - // Must make a copy, because f might keep a reference to it, - // and we cannot let f keep a reference to the stack frame - // after this function returns, not even a read-only reference. - v.ptr = unsafe_New(typ) - memmove(v.ptr, addr, typ.size) - v.flag |= flagIndir - } else if typ.pointers() { - v.ptr = *(*unsafe.Pointer)(addr) - } else { - v.scalar = loadScalar(addr, typ.size) - } - in = append(in, v) - off += typ.size - } - - // Call underlying function. - out := f(in) - if len(out) != len(ftyp.out) { - panic("reflect: wrong return count from function created by MakeFunc") - } - - // Copy results back into argument frame. - if len(ftyp.out) > 0 { - off += -off & (ptrSize - 1) - if runtime.GOARCH == "amd64p32" { - off = align(off, 8) - } - for i, arg := range ftyp.out { - typ := arg - v := out[i] - if v.typ != typ { - panic("reflect: function created by MakeFunc using " + funcName(f) + - " returned wrong type: have " + - out[i].typ.String() + " for " + typ.String()) - } - if v.flag&flagRO != 0 { - panic("reflect: function created by MakeFunc using " + funcName(f) + - " returned value obtained from unexported field") - } - off += -off & uintptr(typ.align-1) - addr := unsafe.Pointer(uintptr(ptr) + off) - if v.flag&flagIndir != 0 { - memmove(addr, v.ptr, typ.size) - } else if typ.pointers() { - *(*unsafe.Pointer)(addr) = v.ptr - } else { - storeScalar(addr, v.scalar, typ.size) - } - off += typ.size - } - } -} - -// methodReceiver returns information about the receiver -// described by v. The Value v may or may not have the -// flagMethod bit set, so the kind cached in v.flag should -// not be used. -// The return value rcvrtype gives the method's actual receiver type. -// The return value t gives the method type signature (without the receiver). -// The return value fn is a pointer to the method code. -func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) { - i := methodIndex - if v.typ.Kind() == Interface { - tt := (*interfaceType)(unsafe.Pointer(v.typ)) - if i < 0 || i >= len(tt.methods) { - panic("reflect: internal error: invalid method index") - } - m := &tt.methods[i] - if m.pkgPath != nil { - panic("reflect: " + op + " of unexported method") - } - iface := (*nonEmptyInterface)(v.ptr) - if iface.itab == nil { - panic("reflect: " + op + " of method on nil interface value") - } - rcvrtype = iface.itab.typ - fn = unsafe.Pointer(&iface.itab.fun[i]) - t = m.typ - } else { - rcvrtype = v.typ - ut := v.typ.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { - panic("reflect: internal error: invalid method index") - } - m := &ut.methods[i] - if m.pkgPath != nil { - panic("reflect: " + op + " of unexported method") - } - fn = unsafe.Pointer(&m.ifn) - t = m.mtyp - } - return -} - -// 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. -func storeRcvr(v Value, p unsafe.Pointer) { - t := v.typ - if t.Kind() == Interface { - // the interface data word becomes the receiver word - iface := (*nonEmptyInterface)(v.ptr) - *(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word) - } else if v.flag&flagIndir != 0 { - if t.size > ptrSize { - *(*unsafe.Pointer)(p) = v.ptr - } else if t.pointers() { - *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr) - } else { - *(*uintptr)(p) = loadScalar(v.ptr, t.size) - } - } else if t.pointers() { - *(*unsafe.Pointer)(p) = v.ptr - } else { - *(*uintptr)(p) = v.scalar - } -} - -// align returns the result of rounding x up to a multiple of n. -// n must be a power of two. -func align(x, n uintptr) uintptr { - return (x + n - 1) &^ (n - 1) -} - -// callMethod is the call implementation used by a function returned -// by makeMethodValue (used by v.Method(i).Interface()). -// It is a streamlined version of the usual reflect call: the caller has -// already laid out the argument frame for us, so we don't have -// to deal with individual Values for each argument. -// It is in this file so that it can be next to the two similar functions above. -// The remainder of the makeMethodValue implementation is in makefunc.go. -// -// NOTE: This function must be marked as a "wrapper" in the generated code, -// so that the linker can make it work correctly for panic and recover. -// The gc compilers know to do that for the name "reflect.callMethod". -func callMethod(ctxt *methodValue, frame unsafe.Pointer) { - rcvr := ctxt.rcvr - rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method) - frametype, argSize, retOffset := funcLayout(t, rcvrtype) - - // Make a new frame that is one word bigger so we can store the receiver. - args := unsafe_New(frametype) - - // Copy in receiver and rest of args. - storeRcvr(rcvr, args) - memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize) - - // Call. - call(fn, args, uint32(frametype.size), uint32(retOffset)) - - // Copy return values. On amd64p32, the beginning of return values - // is 64-bit aligned, so the caller's frame layout (which doesn't have - // a receiver) is different from the layout of the fn call, which has - // a receiver. - // Ignore any changes to args and just copy return values. - callerRetOffset := retOffset - ptrSize - if runtime.GOARCH == "amd64p32" { - callerRetOffset = align(argSize-ptrSize, 8) - } - memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset), - unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset) -} - -// funcName returns the name of f, for use in error messages. -func funcName(f func([]Value) []Value) string { - pc := *(*uintptr)(unsafe.Pointer(&f)) - rf := runtime.FuncForPC(pc) - if rf != nil { - return rf.Name() - } - return "closure" -} - -// Cap returns v's capacity. -// It panics if v's Kind is not Array, Chan, or Slice. -func (v Value) Cap() int { - k := v.kind() - switch k { - case Array: - return v.typ.Len() - case Chan: - return int(chancap(v.pointer())) - case Slice: - // Slice is always bigger than a word; assume flagIndir. - return (*sliceHeader)(v.ptr).Cap - } - panic(&ValueError{"reflect.Value.Cap", k}) -} - -// Close closes the channel v. -// It panics if v's Kind is not Chan. -func (v Value) Close() { - v.mustBe(Chan) - v.mustBeExported() - chanclose(v.pointer()) -} - -// Complex returns v's underlying value, as a complex128. -// It panics if v's Kind is not Complex64 or Complex128 -func (v Value) Complex() complex128 { - k := v.kind() - switch k { - case Complex64: - if v.flag&flagIndir != 0 { - return complex128(*(*complex64)(v.ptr)) - } - return complex128(*(*complex64)(unsafe.Pointer(&v.scalar))) - case Complex128: - // complex128 is always bigger than a word; assume flagIndir. - return *(*complex128)(v.ptr) - } - panic(&ValueError{"reflect.Value.Complex", k}) -} - -// Elem returns the value that the interface v contains -// or that the pointer v points to. -// It panics if v's Kind is not Interface or Ptr. -// It returns the zero Value if v is nil. -func (v Value) Elem() Value { - k := v.kind() - switch k { - case Interface: - var eface interface{} - if v.typ.NumMethod() == 0 { - eface = *(*interface{})(v.ptr) - } else { - eface = (interface{})(*(*interface { - M() - })(v.ptr)) - } - x := unpackEface(eface) - x.flag |= v.flag & flagRO - return x - case Ptr: - ptr := v.ptr - if v.flag&flagIndir != 0 { - ptr = *(*unsafe.Pointer)(ptr) - } - // The returned value's address is v's value. - if ptr == nil { - return Value{} - } - tt := (*ptrType)(unsafe.Pointer(v.typ)) - typ := tt.elem - fl := v.flag&flagRO | flagIndir | flagAddr - fl |= flag(typ.Kind() << flagKindShift) - return Value{typ, ptr, 0, fl} - } - panic(&ValueError{"reflect.Value.Elem", k}) -} - -// Field returns the i'th field of the struct v. -// It panics if v's Kind is not Struct or i is out of range. -func (v Value) Field(i int) Value { - v.mustBe(Struct) - tt := (*structType)(unsafe.Pointer(v.typ)) - if i < 0 || i >= len(tt.fields) { - panic("reflect: Field index out of range") - } - field := &tt.fields[i] - typ := field.typ - - // Inherit permission bits from v. - fl := v.flag & (flagRO | flagIndir | flagAddr) - // Using an unexported field forces flagRO. - if field.pkgPath != nil { - fl |= flagRO - } - fl |= flag(typ.Kind()) << flagKindShift - - var ptr unsafe.Pointer - var scalar uintptr - switch { - case fl&flagIndir != 0: - // Indirect. Just bump pointer. - ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset) - case typ.pointers(): - if field.offset != 0 { - panic("field access of ptr value isn't at offset 0") - } - ptr = v.ptr - case bigEndian: - // Must be scalar. Discard leading bytes. - scalar = v.scalar << (field.offset * 8) - default: - // Must be scalar. Discard leading bytes. - scalar = v.scalar >> (field.offset * 8) - } - - return Value{typ, ptr, scalar, fl} -} - -// FieldByIndex returns the nested field corresponding to index. -// It panics if v's Kind is not struct. -func (v Value) FieldByIndex(index []int) Value { - v.mustBe(Struct) - for i, x := range index { - if i > 0 { - if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct { - if v.IsNil() { - panic("reflect: indirection through nil pointer to embedded struct") - } - v = v.Elem() - } - } - v = v.Field(x) - } - return v -} - -// FieldByName returns the struct field with the given name. -// It returns the zero Value if no field was found. -// It panics if v's Kind is not struct. -func (v Value) FieldByName(name string) Value { - v.mustBe(Struct) - if f, ok := v.typ.FieldByName(name); ok { - return v.FieldByIndex(f.Index) - } - return Value{} -} - -// FieldByNameFunc returns the struct field with a name -// that satisfies the match function. -// It panics if v's Kind is not struct. -// It returns the zero Value if no field was found. -func (v Value) FieldByNameFunc(match func(string) bool) Value { - v.mustBe(Struct) - if f, ok := v.typ.FieldByNameFunc(match); ok { - return v.FieldByIndex(f.Index) - } - return Value{} -} - -// Float returns v's underlying value, as a float64. -// It panics if v's Kind is not Float32 or Float64 -func (v Value) Float() float64 { - k := v.kind() - switch k { - case Float32: - if v.flag&flagIndir != 0 { - return float64(*(*float32)(v.ptr)) - } - return float64(*(*float32)(unsafe.Pointer(&v.scalar))) - case Float64: - if v.flag&flagIndir != 0 { - return *(*float64)(v.ptr) - } - return *(*float64)(unsafe.Pointer(&v.scalar)) - } - panic(&ValueError{"reflect.Value.Float", k}) -} - -var uint8Type = TypeOf(uint8(0)).(*rtype) - -// Index returns v's i'th element. -// It panics if v's Kind is not Array, Slice, or String or i is out of range. -func (v Value) Index(i int) Value { - k := v.kind() - switch k { - case Array: - tt := (*arrayType)(unsafe.Pointer(v.typ)) - if i < 0 || i > int(tt.len) { - panic("reflect: array index out of range") - } - typ := tt.elem - fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array - fl |= flag(typ.Kind()) << flagKindShift - offset := uintptr(i) * typ.size - - var val unsafe.Pointer - var scalar uintptr - switch { - case fl&flagIndir != 0: - // Indirect. Just bump pointer. - val = unsafe.Pointer(uintptr(v.ptr) + offset) - case typ.pointers(): - if offset != 0 { - panic("can't Index(i) with i!=0 on ptrLike value") - } - val = v.ptr - case bigEndian: - // Direct. Discard leading bytes. - scalar = v.scalar << (offset * 8) - default: - // Direct. Discard leading bytes. - scalar = v.scalar >> (offset * 8) - } - return Value{typ, val, scalar, fl} - - case Slice: - // Element flag same as Elem of Ptr. - // Addressable, indirect, possibly read-only. - fl := flagAddr | flagIndir | v.flag&flagRO - s := (*sliceHeader)(v.ptr) - if i < 0 || i >= s.Len { - panic("reflect: slice index out of range") - } - tt := (*sliceType)(unsafe.Pointer(v.typ)) - typ := tt.elem - fl |= flag(typ.Kind()) << flagKindShift - val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size) - return Value{typ, val, 0, fl} - - case String: - fl := v.flag&flagRO | flag(Uint8<<flagKindShift) - s := (*stringHeader)(v.ptr) - if i < 0 || i >= s.Len { - panic("reflect: string index out of range") - } - b := uintptr(0) - *(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i))) - return Value{uint8Type, nil, b, fl} - } - panic(&ValueError{"reflect.Value.Index", k}) -} - -// Int returns v's underlying value, as an int64. -// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64. -func (v Value) Int() int64 { - k := v.kind() - var p unsafe.Pointer - if v.flag&flagIndir != 0 { - p = v.ptr - } else { - // The escape analysis is good enough that &v.scalar - // does not trigger a heap allocation. - p = unsafe.Pointer(&v.scalar) - } - switch k { - case Int: - return int64(*(*int)(p)) - case Int8: - return int64(*(*int8)(p)) - case Int16: - return int64(*(*int16)(p)) - case Int32: - return int64(*(*int32)(p)) - case Int64: - return int64(*(*int64)(p)) - } - panic(&ValueError{"reflect.Value.Int", k}) -} - -// CanInterface returns true if Interface can be used without panicking. -func (v Value) CanInterface() bool { - if v.flag == 0 { - panic(&ValueError{"reflect.Value.CanInterface", Invalid}) - } - return v.flag&flagRO == 0 -} - -// Interface returns v's current value as an interface{}. -// It is equivalent to: -// var i interface{} = (v's underlying value) -// It panics if the Value was obtained by accessing -// unexported struct fields. -func (v Value) Interface() (i interface{}) { - return valueInterface(v, true) -} - -func valueInterface(v Value, safe bool) interface{} { - if v.flag == 0 { - panic(&ValueError{"reflect.Value.Interface", 0}) - } - if safe && v.flag&flagRO != 0 { - // Do not allow access to unexported values via Interface, - // because they might be pointers that should not be - // writable or methods or function that should not be callable. - panic("reflect.Value.Interface: cannot return value obtained from unexported field or method") - } - if v.flag&flagMethod != 0 { - v = makeMethodValue("Interface", v) - } - - if v.kind() == Interface { - // Special case: return the element inside the interface. - // Empty interface has one layout, all interfaces with - // methods have a second layout. - if v.NumMethod() == 0 { - return *(*interface{})(v.ptr) - } - return *(*interface { - M() - })(v.ptr) - } - - // TODO: pass safe to packEface so we don't need to copy if safe==true? - return packEface(v) -} - -// InterfaceData returns the interface v's value as a uintptr pair. -// It panics if v's Kind is not Interface. -func (v Value) InterfaceData() [2]uintptr { - // TODO: deprecate this - v.mustBe(Interface) - // We treat this as a read operation, so we allow - // it even for unexported data, because the caller - // has to import "unsafe" to turn it into something - // that can be abused. - // Interface value is always bigger than a word; assume flagIndir. - return *(*[2]uintptr)(v.ptr) -} - -// IsNil reports whether its argument v is nil. The argument must be -// a chan, func, interface, map, pointer, or slice value; if it is -// not, IsNil panics. Note that IsNil is not always equivalent to a -// regular comparison with nil in Go. For example, if v was created -// by calling ValueOf with an uninitialized interface variable i, -// i==nil will be true but v.IsNil will panic as v will be the zero -// Value. -func (v Value) IsNil() bool { - k := v.kind() - switch k { - case Chan, Func, Map, Ptr: - if v.flag&flagMethod != 0 { - return false - } - ptr := v.ptr - if v.flag&flagIndir != 0 { - ptr = *(*unsafe.Pointer)(ptr) - } - return ptr == nil - case Interface, Slice: - // Both interface and slice are nil if first word is 0. - // Both are always bigger than a word; assume flagIndir. - return *(*unsafe.Pointer)(v.ptr) == nil - } - panic(&ValueError{"reflect.Value.IsNil", k}) -} - -// IsValid returns true if v represents a value. -// It returns false if v is the zero Value. -// If IsValid returns false, all other methods except String panic. -// Most functions and methods never return an invalid value. -// If one does, its documentation states the conditions explicitly. -func (v Value) IsValid() bool { - return v.flag != 0 -} - -// Kind returns v's Kind. -// If v is the zero Value (IsValid returns false), Kind returns Invalid. -func (v Value) Kind() Kind { - return v.kind() -} - -// Len returns v's length. -// It panics if v's Kind is not Array, Chan, Map, Slice, or String. -func (v Value) Len() int { - k := v.kind() - switch k { - case Array: - tt := (*arrayType)(unsafe.Pointer(v.typ)) - return int(tt.len) - case Chan: - return chanlen(v.pointer()) - case Map: - return maplen(v.pointer()) - case Slice: - // Slice is bigger than a word; assume flagIndir. - return (*sliceHeader)(v.ptr).Len - case String: - // String is bigger than a word; assume flagIndir. - return (*stringHeader)(v.ptr).Len - } - panic(&ValueError{"reflect.Value.Len", k}) -} - -// MapIndex returns the value associated with key in the map v. -// It panics if v's Kind is not Map. -// It returns the zero Value if key is not found in the map or if v represents a nil map. -// As in Go, the key's value must be assignable to the map's key type. -func (v Value) MapIndex(key Value) Value { - v.mustBe(Map) - tt := (*mapType)(unsafe.Pointer(v.typ)) - - // 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 - // or the key is unexported, though, the result will be - // 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) - - var k unsafe.Pointer - if key.flag&flagIndir != 0 { - k = key.ptr - } else if key.typ.pointers() { - k = unsafe.Pointer(&key.ptr) - } else { - k = unsafe.Pointer(&key.scalar) - } - e := mapaccess(v.typ, v.pointer(), k) - if e == nil { - return Value{} - } - typ := tt.elem - fl := (v.flag | key.flag) & flagRO - fl |= flag(typ.Kind()) << flagKindShift - if typ.size > ptrSize { - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(typ) - memmove(c, e, typ.size) - return Value{typ, c, 0, fl | flagIndir} - } else if typ.pointers() { - return Value{typ, *(*unsafe.Pointer)(e), 0, fl} - } else { - return Value{typ, nil, loadScalar(e, typ.size), fl} - } -} - -// MapKeys returns a slice containing all the keys present in the map, -// in unspecified order. -// It panics if v's Kind is not Map. -// It returns an empty slice if v represents a nil map. -func (v Value) MapKeys() []Value { - v.mustBe(Map) - tt := (*mapType)(unsafe.Pointer(v.typ)) - keyType := tt.key - - fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift - - m := v.pointer() - mlen := int(0) - if m != nil { - mlen = maplen(m) - } - it := mapiterinit(v.typ, m) - a := make([]Value, mlen) - var i int - for i = 0; i < len(a); i++ { - 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 - // we can do about it. - break - } - if keyType.size > ptrSize { - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(keyType) - memmove(c, key, keyType.size) - a[i] = Value{keyType, c, 0, fl | flagIndir} - } else if keyType.pointers() { - a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl} - } else { - a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl} - } - mapiternext(it) - } - return a[:i] -} - -// Method returns a function value corresponding to v's i'th method. -// The arguments to a Call on the returned function should not include -// a receiver; the returned function will always use v as the receiver. -// Method panics if i is out of range or if v is a nil interface value. -func (v Value) Method(i int) Value { - if v.typ == nil { - panic(&ValueError{"reflect.Value.Method", Invalid}) - } - if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() { - panic("reflect: Method index out of range") - } - if v.typ.Kind() == Interface && v.IsNil() { - panic("reflect: Method on nil interface value") - } - fl := v.flag & (flagRO | flagIndir) - fl |= flag(Func) << flagKindShift - fl |= flag(i)<<flagMethodShift | flagMethod - return Value{v.typ, v.ptr, v.scalar, fl} -} - -// NumMethod returns the number of methods in the value's method set. -func (v Value) NumMethod() int { - if v.typ == nil { - panic(&ValueError{"reflect.Value.NumMethod", Invalid}) - } - if v.flag&flagMethod != 0 { - return 0 - } - return v.typ.NumMethod() -} - -// MethodByName returns a function value corresponding to the method -// of v with the given name. -// The arguments to a Call on the returned function should not include -// a receiver; the returned function will always use v as the receiver. -// It returns the zero Value if no method was found. -func (v Value) MethodByName(name string) Value { - if v.typ == nil { - panic(&ValueError{"reflect.Value.MethodByName", Invalid}) - } - if v.flag&flagMethod != 0 { - return Value{} - } - m, ok := v.typ.MethodByName(name) - if !ok { - return Value{} - } - return v.Method(m.Index) -} - -// NumField returns the number of fields in the struct v. -// It panics if v's Kind is not Struct. -func (v Value) NumField() int { - v.mustBe(Struct) - tt := (*structType)(unsafe.Pointer(v.typ)) - return len(tt.fields) -} - -// OverflowComplex returns true if the complex128 x cannot be represented by v's type. -// It panics if v's Kind is not Complex64 or Complex128. -func (v Value) OverflowComplex(x complex128) bool { - k := v.kind() - switch k { - case Complex64: - return overflowFloat32(real(x)) || overflowFloat32(imag(x)) - case Complex128: - return false - } - panic(&ValueError{"reflect.Value.OverflowComplex", k}) -} - -// OverflowFloat returns true if the float64 x cannot be represented by v's type. -// It panics if v's Kind is not Float32 or Float64. -func (v Value) OverflowFloat(x float64) bool { - k := v.kind() - switch k { - case Float32: - return overflowFloat32(x) - case Float64: - return false - } - panic(&ValueError{"reflect.Value.OverflowFloat", k}) -} - -func overflowFloat32(x float64) bool { - if x < 0 { - x = -x - } - return math.MaxFloat32 < x && x <= math.MaxFloat64 -} - -// OverflowInt returns true if the int64 x cannot be represented by v's type. -// It panics if v's Kind is not Int, Int8, int16, Int32, or Int64. -func (v Value) OverflowInt(x int64) bool { - k := v.kind() - switch k { - case Int, Int8, Int16, Int32, Int64: - bitSize := v.typ.size * 8 - trunc := (x << (64 - bitSize)) >> (64 - bitSize) - return x != trunc - } - panic(&ValueError{"reflect.Value.OverflowInt", k}) -} - -// OverflowUint returns true if the uint64 x cannot be represented by v's type. -// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. -func (v Value) OverflowUint(x uint64) bool { - k := v.kind() - switch k { - case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: - bitSize := v.typ.size * 8 - trunc := (x << (64 - bitSize)) >> (64 - bitSize) - return x != trunc - } - panic(&ValueError{"reflect.Value.OverflowUint", k}) -} - -// Pointer returns v's value as a uintptr. -// It returns uintptr instead of unsafe.Pointer so that -// code using reflect cannot obtain unsafe.Pointers -// without importing the unsafe package explicitly. -// It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer. -// -// If v's Kind is Func, the returned pointer is an underlying -// code pointer, but not necessarily enough to identify a -// single function uniquely. The only guarantee is that the -// 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 -// is 0. If the slice is empty but non-nil the return value is non-zero. -func (v Value) Pointer() uintptr { - // TODO: deprecate - k := v.kind() - switch k { - case Chan, Map, Ptr, UnsafePointer: - return uintptr(v.pointer()) - case Func: - if v.flag&flagMethod != 0 { - // As the doc comment says, the returned pointer is an - // underlying code pointer but not necessarily enough to - // identify a single function uniquely. All method expressions - // created via reflect have the same underlying code pointer, - // so their Pointers are equal. The function used here must - // match the one used in makeMethodValue. - f := methodValueCall - return **(**uintptr)(unsafe.Pointer(&f)) - } - p := v.pointer() - // Non-nil func value points at data block. - // First word of data block is actual code. - if p != nil { - p = *(*unsafe.Pointer)(p) - } - return uintptr(p) - - case Slice: - return (*SliceHeader)(v.ptr).Data - } - panic(&ValueError{"reflect.Value.Pointer", k}) -} - -// Recv receives and returns a value from the channel v. -// It panics if v's Kind is not Chan. -// The receive blocks until a value is ready. -// The boolean value ok is true if the value x corresponds to a send -// on the channel, false if it is a zero value received because the channel is closed. -func (v Value) Recv() (x Value, ok bool) { - v.mustBe(Chan) - v.mustBeExported() - return v.recv(false) -} - -// internal recv, possibly non-blocking (nb). -// v is known to be a channel. -func (v Value) recv(nb bool) (val Value, ok bool) { - tt := (*chanType)(unsafe.Pointer(v.typ)) - if ChanDir(tt.dir)&RecvDir == 0 { - panic("reflect: recv on send-only channel") - } - t := tt.elem - val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift} - var p unsafe.Pointer - if t.size > ptrSize { - p = unsafe_New(t) - val.ptr = p - val.flag |= flagIndir - } else if t.pointers() { - p = unsafe.Pointer(&val.ptr) - } else { - p = unsafe.Pointer(&val.scalar) - } - selected, ok := chanrecv(v.typ, v.pointer(), nb, p) - if !selected { - val = Value{} - } - return -} - -// Send sends x on the channel v. -// It panics if v's kind is not Chan or if x's type is not the same type as v's element type. -// As in Go, x's value must be assignable to the channel's element type. -func (v Value) Send(x Value) { - v.mustBe(Chan) - v.mustBeExported() - v.send(x, false) -} - -// internal send, possibly non-blocking. -// v is known to be a channel. -func (v Value) send(x Value, nb bool) (selected bool) { - tt := (*chanType)(unsafe.Pointer(v.typ)) - if ChanDir(tt.dir)&SendDir == 0 { - panic("reflect: send on recv-only channel") - } - x.mustBeExported() - x = x.assignTo("reflect.Value.Send", tt.elem, nil) - var p unsafe.Pointer - if x.flag&flagIndir != 0 { - p = x.ptr - } else if x.typ.pointers() { - p = unsafe.Pointer(&x.ptr) - } else { - p = unsafe.Pointer(&x.scalar) - } - return chansend(v.typ, v.pointer(), p, nb) -} - -// Set assigns x to the value v. -// It panics if CanSet returns false. -// As in Go, x's value must be assignable to v's type. -func (v Value) Set(x Value) { - v.mustBeAssignable() - x.mustBeExported() // do not let unexported x leak - var target *interface{} - if v.kind() == Interface { - target = (*interface{})(v.ptr) - } - x = x.assignTo("reflect.Set", v.typ, target) - if x.flag&flagIndir != 0 { - memmove(v.ptr, x.ptr, v.typ.size) - } else if x.typ.pointers() { - *(*unsafe.Pointer)(v.ptr) = x.ptr - } else { - memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size) - } -} - -// SetBool sets v's underlying value. -// It panics if v's Kind is not Bool or if CanSet() is false. -func (v Value) SetBool(x bool) { - v.mustBeAssignable() - v.mustBe(Bool) - *(*bool)(v.ptr) = x -} - -// SetBytes sets v's underlying value. -// It panics if v's underlying value is not a slice of bytes. -func (v Value) SetBytes(x []byte) { - v.mustBeAssignable() - v.mustBe(Slice) - if v.typ.Elem().Kind() != Uint8 { - panic("reflect.Value.SetBytes of non-byte slice") - } - *(*[]byte)(v.ptr) = x -} - -// setRunes sets v's underlying value. -// It panics if v's underlying value is not a slice of runes (int32s). -func (v Value) setRunes(x []rune) { - v.mustBeAssignable() - v.mustBe(Slice) - if v.typ.Elem().Kind() != Int32 { - panic("reflect.Value.setRunes of non-rune slice") - } - *(*[]rune)(v.ptr) = x -} - -// SetComplex sets v's underlying value to x. -// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false. -func (v Value) SetComplex(x complex128) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetComplex", k}) - case Complex64: - *(*complex64)(v.ptr) = complex64(x) - case Complex128: - *(*complex128)(v.ptr) = x - } -} - -// SetFloat sets v's underlying value to x. -// It panics if v's Kind is not Float32 or Float64, or if CanSet() is false. -func (v Value) SetFloat(x float64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetFloat", k}) - case Float32: - *(*float32)(v.ptr) = float32(x) - case Float64: - *(*float64)(v.ptr) = x - } -} - -// SetInt sets v's underlying value to x. -// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false. -func (v Value) SetInt(x int64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetInt", k}) - case Int: - *(*int)(v.ptr) = int(x) - case Int8: - *(*int8)(v.ptr) = int8(x) - case Int16: - *(*int16)(v.ptr) = int16(x) - case Int32: - *(*int32)(v.ptr) = int32(x) - case Int64: - *(*int64)(v.ptr) = x - } -} - -// SetLen sets v's length to n. -// It panics if v's Kind is not Slice or if n is negative or -// greater than the capacity of the slice. -func (v Value) SetLen(n int) { - v.mustBeAssignable() - v.mustBe(Slice) - s := (*sliceHeader)(v.ptr) - if n < 0 || n > int(s.Cap) { - panic("reflect: slice length out of range in SetLen") - } - s.Len = n -} - -// SetCap sets v's capacity to n. -// It panics if v's Kind is not Slice or if n is smaller than the length or -// greater than the capacity of the slice. -func (v Value) SetCap(n int) { - v.mustBeAssignable() - v.mustBe(Slice) - s := (*sliceHeader)(v.ptr) - if n < int(s.Len) || n > int(s.Cap) { - panic("reflect: slice capacity out of range in SetCap") - } - s.Cap = n -} - -// SetMapIndex sets the value associated with key in the map v to val. -// It panics if v's Kind is not Map. -// If val is the zero Value, SetMapIndex deletes the key from the map. -// Otherwise if v holds a nil map, SetMapIndex will panic. -// As in Go, key's value must be assignable to the map's key type, -// and val's value must be assignable to the map's value type. -func (v Value) SetMapIndex(key, val Value) { - v.mustBe(Map) - v.mustBeExported() - key.mustBeExported() - tt := (*mapType)(unsafe.Pointer(v.typ)) - key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil) - var k unsafe.Pointer - if key.flag&flagIndir != 0 { - k = key.ptr - } else if key.typ.pointers() { - k = unsafe.Pointer(&key.ptr) - } else { - k = unsafe.Pointer(&key.scalar) - } - if val.typ == nil { - mapdelete(v.typ, v.pointer(), k) - return - } - val.mustBeExported() - val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil) - var e unsafe.Pointer - if val.flag&flagIndir != 0 { - e = val.ptr - } else if val.typ.pointers() { - e = unsafe.Pointer(&val.ptr) - } else { - e = unsafe.Pointer(&val.scalar) - } - mapassign(v.typ, v.pointer(), k, e) -} - -// SetUint sets v's underlying value to x. -// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64, or if CanSet() is false. -func (v Value) SetUint(x uint64) { - v.mustBeAssignable() - switch k := v.kind(); k { - default: - panic(&ValueError{"reflect.Value.SetUint", k}) - case Uint: - *(*uint)(v.ptr) = uint(x) - case Uint8: - *(*uint8)(v.ptr) = uint8(x) - case Uint16: - *(*uint16)(v.ptr) = uint16(x) - case Uint32: - *(*uint32)(v.ptr) = uint32(x) - case Uint64: - *(*uint64)(v.ptr) = x - case Uintptr: - *(*uintptr)(v.ptr) = uintptr(x) - } -} - -// SetPointer sets the unsafe.Pointer value v to x. -// It panics if v's Kind is not UnsafePointer. -func (v Value) SetPointer(x unsafe.Pointer) { - v.mustBeAssignable() - v.mustBe(UnsafePointer) - *(*unsafe.Pointer)(v.ptr) = x -} - -// SetString sets v's underlying value to x. -// It panics if v's Kind is not String or if CanSet() is false. -func (v Value) SetString(x string) { - v.mustBeAssignable() - v.mustBe(String) - *(*string)(v.ptr) = x -} - -// Slice returns v[i:j]. -// It panics if v's Kind is not Array, Slice or String, or if v is an unaddressable array, -// or if the indexes are out of bounds. -func (v Value) Slice(i, j int) Value { - var ( - cap int - typ *sliceType - base unsafe.Pointer - ) - switch kind := v.kind(); kind { - default: - panic(&ValueError{"reflect.Value.Slice", kind}) - - case Array: - if v.flag&flagAddr == 0 { - panic("reflect.Value.Slice: slice of unaddressable array") - } - tt := (*arrayType)(unsafe.Pointer(v.typ)) - cap = int(tt.len) - typ = (*sliceType)(unsafe.Pointer(tt.slice)) - base = v.ptr - - case Slice: - typ = (*sliceType)(unsafe.Pointer(v.typ)) - s := (*sliceHeader)(v.ptr) - base = unsafe.Pointer(s.Data) - cap = s.Cap - - case String: - s := (*stringHeader)(v.ptr) - if i < 0 || j < i || j > s.Len { - panic("reflect.Value.Slice: string slice index out of bounds") - } - t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i} - return Value{v.typ, unsafe.Pointer(&t), 0, v.flag} - } - - if i < 0 || j < i || j > cap { - panic("reflect.Value.Slice: slice index out of bounds") - } - - // Declare slice so that gc can see the base pointer in it. - var x []unsafe.Pointer - - // Reinterpret as *sliceHeader to edit. - s := (*sliceHeader)(unsafe.Pointer(&x)) - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) - s.Len = j - i - s.Cap = cap - i - - fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift - return Value{typ.common(), unsafe.Pointer(&x), 0, fl} -} - -// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k]. -// It panics if v's Kind is not Array or Slice, or if v is an unaddressable array, -// or if the indexes are out of bounds. -func (v Value) Slice3(i, j, k int) Value { - var ( - cap int - typ *sliceType - base unsafe.Pointer - ) - switch kind := v.kind(); kind { - default: - panic(&ValueError{"reflect.Value.Slice3", kind}) - - case Array: - if v.flag&flagAddr == 0 { - panic("reflect.Value.Slice3: slice of unaddressable array") - } - tt := (*arrayType)(unsafe.Pointer(v.typ)) - cap = int(tt.len) - typ = (*sliceType)(unsafe.Pointer(tt.slice)) - base = v.ptr - - case Slice: - typ = (*sliceType)(unsafe.Pointer(v.typ)) - s := (*sliceHeader)(v.ptr) - base = s.Data - cap = s.Cap - } - - if i < 0 || j < i || k < j || k > cap { - panic("reflect.Value.Slice3: slice index out of bounds") - } - - // Declare slice so that the garbage collector - // can see the base pointer in it. - var x []unsafe.Pointer - - // Reinterpret as *sliceHeader to edit. - s := (*sliceHeader)(unsafe.Pointer(&x)) - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) - s.Len = j - i - s.Cap = k - i - - fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift - return Value{typ.common(), unsafe.Pointer(&x), 0, fl} -} - -// String returns the string v's underlying value, as a string. -// String is a special case because of Go's String method convention. -// Unlike the other getters, it does not panic if v's Kind is not String. -// Instead, it returns a string of the form "<T value>" where T is v's type. -func (v Value) String() string { - switch k := v.kind(); k { - case Invalid: - return "<invalid Value>" - case String: - return *(*string)(v.ptr) - } - // If you call String on a reflect.Value of other type, it's better to - // print something than to panic. Useful in debugging. - return "<" + v.typ.String() + " Value>" -} - -// TryRecv attempts to receive a value from the channel v but will not block. -// It panics if v's Kind is not Chan. -// If the receive delivers a value, x is the transferred value and ok is true. -// If the receive cannot finish without blocking, x is the zero Value and ok is false. -// If the channel is closed, x is the zero value for the channel's element type and ok is false. -func (v Value) TryRecv() (x Value, ok bool) { - v.mustBe(Chan) - v.mustBeExported() - return v.recv(true) -} - -// TrySend attempts to send x on the channel v but will not block. -// It panics if v's Kind is not Chan. -// It returns true if the value was sent, false otherwise. -// As in Go, x's value must be assignable to the channel's element type. -func (v Value) TrySend(x Value) bool { - v.mustBe(Chan) - v.mustBeExported() - return v.send(x, true) -} - -// Type returns v's type. -func (v Value) Type() Type { - f := v.flag - if f == 0 { - panic(&ValueError{"reflect.Value.Type", Invalid}) - } - if f&flagMethod == 0 { - // Easy case - return v.typ - } - - // Method value. - // v.typ describes the receiver, not the method type. - i := int(v.flag) >> flagMethodShift - if v.typ.Kind() == Interface { - // Method on interface. - tt := (*interfaceType)(unsafe.Pointer(v.typ)) - if i < 0 || i >= len(tt.methods) { - panic("reflect: internal error: invalid method index") - } - m := &tt.methods[i] - return m.typ - } - // Method on concrete type. - ut := v.typ.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { - panic("reflect: internal error: invalid method index") - } - m := &ut.methods[i] - return m.mtyp -} - -// Uint returns v's underlying value, as a uint64. -// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. -func (v Value) Uint() uint64 { - k := v.kind() - var p unsafe.Pointer - if v.flag&flagIndir != 0 { - p = v.ptr - } else { - // The escape analysis is good enough that &v.scalar - // does not trigger a heap allocation. - p = unsafe.Pointer(&v.scalar) - } - switch k { - case Uint: - return uint64(*(*uint)(p)) - case Uint8: - return uint64(*(*uint8)(p)) - case Uint16: - return uint64(*(*uint16)(p)) - case Uint32: - return uint64(*(*uint32)(p)) - case Uint64: - return uint64(*(*uint64)(p)) - case Uintptr: - return uint64(*(*uintptr)(p)) - } - panic(&ValueError{"reflect.Value.Uint", k}) -} - -// UnsafeAddr returns a pointer to v's data. -// It is for advanced clients that also import the "unsafe" package. -// It panics if v is not addressable. -func (v Value) UnsafeAddr() uintptr { - // TODO: deprecate - if v.typ == nil { - panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid}) - } - if v.flag&flagAddr == 0 { - panic("reflect.Value.UnsafeAddr of unaddressable value") - } - return uintptr(v.ptr) -} - -// StringHeader is the runtime representation of a string. -// It cannot be used safely or portably and its representation may -// change in a later release. -// Moreover, the Data field is not sufficient to guarantee the data -// it references will not be garbage collected, so programs must keep -// a separate, correctly typed pointer to the underlying data. -type StringHeader struct { - Data uintptr - Len int -} - -// stringHeader is a safe version of StringHeader used within this package. -type stringHeader struct { - Data unsafe.Pointer - Len int -} - -// SliceHeader is the runtime representation of a slice. -// It cannot be used safely or portably and its representation may -// change in a later release. -// Moreover, the Data field is not sufficient to guarantee the data -// it references will not be garbage collected, so programs must keep -// a separate, correctly typed pointer to the underlying data. -type SliceHeader struct { - Data uintptr - Len int - Cap int -} - -// sliceHeader is a safe version of SliceHeader used within this package. -type sliceHeader struct { - Data unsafe.Pointer - Len int - Cap int -} - -func typesMustMatch(what string, t1, t2 Type) { - if t1 != t2 { - panic(what + ": " + t1.String() + " != " + t2.String()) - } -} - -// grow grows the slice s so that it can hold extra more values, allocating -// more capacity if needed. It also returns the old and new slice lengths. -func grow(s Value, extra int) (Value, int, int) { - i0 := s.Len() - i1 := i0 + extra - if i1 < i0 { - panic("reflect.Append: slice overflow") - } - m := s.Cap() - if i1 <= m { - return s.Slice(0, i1), i0, i1 - } - if m == 0 { - m = extra - } else { - for m < i1 { - if i0 < 1024 { - m += m - } else { - m += m / 4 - } - } - } - t := MakeSlice(s.Type(), i1, m) - Copy(t, s) - return t, i0, i1 -} - -// Append appends the values x to a slice s and returns the resulting slice. -// As in Go, each x's value must be assignable to the slice's element type. -func Append(s Value, x ...Value) Value { - s.mustBe(Slice) - s, i0, i1 := grow(s, len(x)) - for i, j := i0, 0; i < i1; i, j = i+1, j+1 { - s.Index(i).Set(x[j]) - } - return s -} - -// AppendSlice appends a slice t to a slice s and returns the resulting slice. -// The slices s and t must have the same element type. -func AppendSlice(s, t Value) Value { - s.mustBe(Slice) - t.mustBe(Slice) - typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem()) - s, i0, i1 := grow(s, t.Len()) - Copy(s.Slice(i0, i1), t) - return s -} - -// Copy copies the contents of src into dst until either -// dst has been filled or src has been exhausted. -// It returns the number of elements copied. -// Dst and src each must have kind Slice or Array, and -// dst and src must have the same element type. -func Copy(dst, src Value) int { - dk := dst.kind() - if dk != Array && dk != Slice { - panic(&ValueError{"reflect.Copy", dk}) - } - if dk == Array { - dst.mustBeAssignable() - } - dst.mustBeExported() - - sk := src.kind() - if sk != Array && sk != Slice { - panic(&ValueError{"reflect.Copy", sk}) - } - src.mustBeExported() - - de := dst.typ.Elem() - se := src.typ.Elem() - typesMustMatch("reflect.Copy", de, se) - - n := dst.Len() - if sn := src.Len(); n > sn { - n = sn - } - - // If sk is an in-line array, cannot take its address. - // Instead, copy element by element. - // TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar)) - // if we teach the compiler that ptrs don't escape from memmove. - if src.flag&flagIndir == 0 { - for i := 0; i < n; i++ { - dst.Index(i).Set(src.Index(i)) - } - return n - } - - // Copy via memmove. - var da, sa unsafe.Pointer - if dk == Array { - da = dst.ptr - } else { - da = (*sliceHeader)(dst.ptr).Data - } - if sk == Array { - sa = src.ptr - } else { - sa = (*sliceHeader)(src.ptr).Data - } - memmove(da, sa, uintptr(n)*de.Size()) - return n -} - -// A runtimeSelect is a single case passed to rselect. -// This must match ../runtime/chan.c:/runtimeSelect -type runtimeSelect struct { - dir uintptr // 0, SendDir, or RecvDir - 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. -// 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. -//go:noescape -func rselect([]runtimeSelect) (chosen int, recvOK bool) - -// A SelectDir describes the communication direction of a select case. -type SelectDir int - -// NOTE: These values must match ../runtime/chan.c:/SelectDir. - -const ( - _ SelectDir = iota - SelectSend // case Chan <- Send - SelectRecv // case <-Chan: - SelectDefault // default -) - -// A SelectCase describes a single case in a select operation. -// The kind of case depends on Dir, the communication direction. -// -// If Dir is SelectDefault, the case represents a default case. -// Chan and Send must be zero Values. -// -// If Dir is SelectSend, the case represents a send operation. -// Normally Chan's underlying value must be a channel, and Send's underlying value must be -// assignable to the channel's element type. As a special case, if Chan is a zero Value, -// then the case is ignored, and the field Send will also be ignored and may be either zero -// or non-zero. -// -// If Dir is SelectRecv, the case represents a receive operation. -// Normally Chan's underlying value must be a channel and Send must be a zero Value. -// If Chan is a zero Value, then the case is ignored, but Send must still be a zero Value. -// When a receive operation is selected, the received Value is returned by Select. -// -type SelectCase struct { - Dir SelectDir // direction of case - Chan Value // channel to use (for send or receive) - Send Value // value to send (for send) -} - -// Select executes a select operation described by the list of cases. -// Like the Go select statement, it blocks until at least one of the cases -// can proceed, makes a uniform pseudo-random choice, -// and then executes that case. It returns the index of the chosen case -// and, if that case was a receive operation, the value received and a -// boolean indicating whether the value corresponds to a send on the channel -// (as opposed to a zero value received because the channel is closed). -func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { - // NOTE: Do not trust that caller is not modifying cases data underfoot. - // The range is safe because the caller cannot modify our copy of the len - // and each iteration makes its own copy of the value c. - runcases := make([]runtimeSelect, len(cases)) - haveDefault := false - for i, c := range cases { - rc := &runcases[i] - rc.dir = uintptr(c.Dir) - switch c.Dir { - default: - panic("reflect.Select: invalid Dir") - - case SelectDefault: // default - if haveDefault { - panic("reflect.Select: multiple default cases") - } - haveDefault = true - if c.Chan.IsValid() { - panic("reflect.Select: default case has Chan value") - } - if c.Send.IsValid() { - panic("reflect.Select: default case has Send value") - } - - case SelectSend: - ch := c.Chan - if !ch.IsValid() { - break - } - ch.mustBe(Chan) - ch.mustBeExported() - tt := (*chanType)(unsafe.Pointer(ch.typ)) - if ChanDir(tt.dir)&SendDir == 0 { - panic("reflect.Select: SendDir case using recv-only channel") - } - rc.ch = ch.pointer() - rc.typ = &tt.rtype - v := c.Send - if !v.IsValid() { - panic("reflect.Select: SendDir case missing Send value") - } - v.mustBeExported() - v = v.assignTo("reflect.Select", tt.elem, nil) - if v.flag&flagIndir != 0 { - rc.val = v.ptr - } else if v.typ.pointers() { - rc.val = unsafe.Pointer(&v.ptr) - } else { - rc.val = unsafe.Pointer(&v.scalar) - } - - case SelectRecv: - if c.Send.IsValid() { - panic("reflect.Select: RecvDir case has Send value") - } - ch := c.Chan - if !ch.IsValid() { - break - } - ch.mustBe(Chan) - ch.mustBeExported() - tt := (*chanType)(unsafe.Pointer(ch.typ)) - if ChanDir(tt.dir)&RecvDir == 0 { - panic("reflect.Select: RecvDir case using send-only channel") - } - rc.ch = ch.pointer() - rc.typ = &tt.rtype - rc.val = unsafe_New(tt.elem) - } - } - - chosen, recvOK = rselect(runcases) - if runcases[chosen].dir == uintptr(SelectRecv) { - tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) - t := tt.elem - p := runcases[chosen].val - fl := flag(t.Kind()) << flagKindShift - if t.size > ptrSize { - recv = Value{t, p, 0, fl | flagIndir} - } else if t.pointers() { - recv = Value{t, *(*unsafe.Pointer)(p), 0, fl} - } else { - recv = Value{t, nil, loadScalar(p, t.size), fl} - } - } - return chosen, recv, recvOK -} - -/* - * constructors - */ - -// implemented in package runtime -func unsafe_New(*rtype) unsafe.Pointer -func unsafe_NewArray(*rtype, int) unsafe.Pointer - -// MakeSlice creates a new zero-initialized slice value -// for the specified slice type, length, and capacity. -func MakeSlice(typ Type, len, cap int) Value { - if typ.Kind() != Slice { - panic("reflect.MakeSlice of non-slice type") - } - if len < 0 { - panic("reflect.MakeSlice: negative len") - } - if cap < 0 { - panic("reflect.MakeSlice: negative cap") - } - if len > cap { - panic("reflect.MakeSlice: len > cap") - } - - s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap} - return Value{typ.common(), unsafe.Pointer(&s), 0, flagIndir | flag(Slice)<<flagKindShift} -} - -// MakeChan creates a new channel with the specified type and buffer size. -func MakeChan(typ Type, buffer int) Value { - if typ.Kind() != Chan { - panic("reflect.MakeChan of non-chan type") - } - if buffer < 0 { - panic("reflect.MakeChan: negative buffer size") - } - if typ.ChanDir() != BothDir { - panic("reflect.MakeChan: unidirectional channel type") - } - ch := makechan(typ.(*rtype), uint64(buffer)) - return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift} -} - -// MakeMap creates a new map of the specified type. -func MakeMap(typ Type) Value { - if typ.Kind() != Map { - panic("reflect.MakeMap of non-map type") - } - m := makemap(typ.(*rtype)) - return Value{typ.common(), m, 0, flag(Map) << flagKindShift} -} - -// 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() -} - -// ValueOf returns a new Value initialized to the concrete value -// stored in the interface i. ValueOf(nil) returns the zero Value. -func ValueOf(i interface{}) Value { - if i == nil { - return Value{} - } - - // TODO(rsc): Eliminate this terrible hack. - // In the call to unpackEface, i.typ doesn't escape, - // and i.word is an integer. So it looks like - // i doesn't escape. But really it does, - // because i.word is actually a pointer. - escapes(i) - - return unpackEface(i) -} - -// Zero returns a Value representing the zero value for the specified type. -// The result is different from the zero value of the Value struct, -// which represents no value at all. -// For example, Zero(TypeOf(42)) returns a Value with Kind Int and value 0. -// The returned value is neither addressable nor settable. -func Zero(typ Type) Value { - if typ == nil { - panic("reflect: Zero(nil)") - } - t := typ.common() - fl := flag(t.Kind()) << flagKindShift - if t.size <= ptrSize { - return Value{t, nil, 0, fl} - } - return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir} -} - -// 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). -func New(typ Type) Value { - if typ == nil { - panic("reflect: New(nil)") - } - ptr := unsafe_New(typ.(*rtype)) - fl := flag(Ptr) << flagKindShift - return Value{typ.common().ptrTo(), ptr, 0, fl} -} - -// NewAt returns a Value representing a pointer to a value of the -// specified type, using p as that pointer. -func NewAt(typ Type, p unsafe.Pointer) Value { - fl := flag(Ptr) << flagKindShift - return Value{typ.common().ptrTo(), p, 0, fl} -} - -// assignTo returns a value v that can be assigned directly to typ. -// It panics if v is not assignable to typ. -// For a conversion to an interface type, target is a suggested scratch space to use. -func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { - if v.flag&flagMethod != 0 { - v = makeMethodValue(context, v) - } - - switch { - case directlyAssignable(dst, v.typ): - // Overwrite type so that they match. - // Same memory layout, so no harm done. - v.typ = dst - fl := v.flag & (flagRO | flagAddr | flagIndir) - fl |= flag(dst.Kind()) << flagKindShift - return Value{dst, v.ptr, v.scalar, fl} - - case implements(dst, v.typ): - if target == nil { - target = new(interface{}) - } - x := valueInterface(v, false) - if dst.NumMethod() == 0 { - *target = x - } else { - ifaceE2I(dst, x, unsafe.Pointer(target)) - } - return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift} - } - - // Failed. - panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String()) -} - -// Convert returns the value v converted to type t. -// If the usual Go conversion rules do not allow conversion -// of the value v to type t, Convert panics. -func (v Value) Convert(t Type) Value { - if v.flag&flagMethod != 0 { - v = makeMethodValue("Convert", v) - } - op := convertOp(t.common(), v.typ) - if op == nil { - panic("reflect.Value.Convert: value of type " + v.typ.String() + " cannot be converted to type " + t.String()) - } - return op(v, t) -} - -// convertOp returns the function to convert a value of type src -// to a value of type dst. If the conversion is illegal, convertOp returns nil. -func convertOp(dst, src *rtype) func(Value, Type) Value { - switch src.Kind() { - case Int, Int8, Int16, Int32, Int64: - switch dst.Kind() { - case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtInt - case Float32, Float64: - return cvtIntFloat - case String: - return cvtIntString - } - - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - switch dst.Kind() { - case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtUint - case Float32, Float64: - return cvtUintFloat - case String: - return cvtUintString - } - - case Float32, Float64: - switch dst.Kind() { - case Int, Int8, Int16, Int32, Int64: - return cvtFloatInt - case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: - return cvtFloatUint - case Float32, Float64: - return cvtFloat - } - - case Complex64, Complex128: - switch dst.Kind() { - case Complex64, Complex128: - return cvtComplex - } - - case String: - if dst.Kind() == Slice && dst.Elem().PkgPath() == "" { - switch dst.Elem().Kind() { - case Uint8: - return cvtStringBytes - case Int32: - return cvtStringRunes - } - } - - case Slice: - if dst.Kind() == String && src.Elem().PkgPath() == "" { - switch src.Elem().Kind() { - case Uint8: - return cvtBytesString - case Int32: - return cvtRunesString - } - } - } - - // dst and src have same underlying type. - if haveIdenticalUnderlyingType(dst, src) { - return cvtDirect - } - - // dst and src are unnamed pointer types with same underlying base type. - if dst.Kind() == Ptr && dst.Name() == "" && - src.Kind() == Ptr && src.Name() == "" && - haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) { - return cvtDirect - } - - if implements(dst, src) { - if src.Kind() == Interface { - return cvtI2I - } - return cvtT2I - } - - return nil -} - -// makeInt returns a Value of type t equal to bits (possibly truncated), -// where t is a signed or unsigned int type. -func makeInt(f flag, bits uint64, t Type) Value { - typ := t.common() - if typ.size > ptrSize { - // Assume ptrSize >= 4, so this must be uint64. - ptr := unsafe_New(typ) - *(*uint64)(unsafe.Pointer(ptr)) = bits - return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift} - } - var s uintptr - switch typ.size { - case 1: - *(*uint8)(unsafe.Pointer(&s)) = uint8(bits) - case 2: - *(*uint16)(unsafe.Pointer(&s)) = uint16(bits) - case 4: - *(*uint32)(unsafe.Pointer(&s)) = uint32(bits) - case 8: - *(*uint64)(unsafe.Pointer(&s)) = uint64(bits) - } - return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift} -} - -// makeFloat returns a Value of type t equal to v (possibly truncated to float32), -// where t is a float32 or float64 type. -func makeFloat(f flag, v float64, t Type) Value { - typ := t.common() - if typ.size > ptrSize { - // Assume ptrSize >= 4, so this must be float64. - ptr := unsafe_New(typ) - *(*float64)(unsafe.Pointer(ptr)) = v - return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift} - } - - var s uintptr - switch typ.size { - case 4: - *(*float32)(unsafe.Pointer(&s)) = float32(v) - case 8: - *(*float64)(unsafe.Pointer(&s)) = v - } - return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift} -} - -// makeComplex returns a Value of type t equal to v (possibly truncated to complex64), -// where t is a complex64 or complex128 type. -func makeComplex(f flag, v complex128, t Type) Value { - typ := t.common() - if typ.size > ptrSize { - ptr := unsafe_New(typ) - switch typ.size { - case 8: - *(*complex64)(unsafe.Pointer(ptr)) = complex64(v) - case 16: - *(*complex128)(unsafe.Pointer(ptr)) = v - } - return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift} - } - - // Assume ptrSize <= 8 so this must be complex64. - var s uintptr - *(*complex64)(unsafe.Pointer(&s)) = complex64(v) - return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift} -} - -func makeString(f flag, v string, t Type) Value { - ret := New(t).Elem() - ret.SetString(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -func makeBytes(f flag, v []byte, t Type) Value { - ret := New(t).Elem() - ret.SetBytes(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -func makeRunes(f flag, v []rune, t Type) Value { - ret := New(t).Elem() - ret.setRunes(v) - ret.flag = ret.flag&^flagAddr | f - return ret -} - -// These conversion functions are returned by convertOp -// for classes of conversions. For example, the first function, cvtInt, -// takes any value v of signed int type and returns the value converted -// to type t, where t is any signed or unsigned int type. - -// convertOp: intXX -> [u]intXX -func cvtInt(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(v.Int()), t) -} - -// convertOp: uintXX -> [u]intXX -func cvtUint(v Value, t Type) Value { - return makeInt(v.flag&flagRO, v.Uint(), t) -} - -// convertOp: floatXX -> intXX -func cvtFloatInt(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(int64(v.Float())), t) -} - -// convertOp: floatXX -> uintXX -func cvtFloatUint(v Value, t Type) Value { - return makeInt(v.flag&flagRO, uint64(v.Float()), t) -} - -// convertOp: intXX -> floatXX -func cvtIntFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, float64(v.Int()), t) -} - -// convertOp: uintXX -> floatXX -func cvtUintFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, float64(v.Uint()), t) -} - -// convertOp: floatXX -> floatXX -func cvtFloat(v Value, t Type) Value { - return makeFloat(v.flag&flagRO, v.Float(), t) -} - -// convertOp: complexXX -> complexXX -func cvtComplex(v Value, t Type) Value { - return makeComplex(v.flag&flagRO, v.Complex(), t) -} - -// convertOp: intXX -> string -func cvtIntString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Int()), t) -} - -// convertOp: uintXX -> string -func cvtUintString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Uint()), t) -} - -// convertOp: []byte -> string -func cvtBytesString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.Bytes()), t) -} - -// convertOp: string -> []byte -func cvtStringBytes(v Value, t Type) Value { - return makeBytes(v.flag&flagRO, []byte(v.String()), t) -} - -// convertOp: []rune -> string -func cvtRunesString(v Value, t Type) Value { - return makeString(v.flag&flagRO, string(v.runes()), t) -} - -// convertOp: string -> []rune -func cvtStringRunes(v Value, t Type) Value { - return makeRunes(v.flag&flagRO, []rune(v.String()), t) -} - -// convertOp: direct copy -func cvtDirect(v Value, typ Type) Value { - f := v.flag - t := typ.common() - ptr := v.ptr - if f&flagAddr != 0 { - // indirect, mutable word - make a copy - c := unsafe_New(t) - memmove(c, ptr, t.size) - ptr = c - f &^= flagAddr - } - return Value{t, ptr, v.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f? -} - -// convertOp: concrete -> interface -func cvtT2I(v Value, typ Type) Value { - target := new(interface{}) - x := valueInterface(v, false) - if typ.NumMethod() == 0 { - *target = x - } else { - ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target)) - } - return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift} -} - -// convertOp: interface -> interface -func cvtI2I(v Value, typ Type) Value { - if v.IsNil() { - ret := Zero(typ) - ret.flag |= v.flag & flagRO - return ret - } - return cvtT2I(v.Elem(), typ) -} - -// implemented in ../pkg/runtime -func chancap(ch unsafe.Pointer) int -func chanclose(ch unsafe.Pointer) -func chanlen(ch unsafe.Pointer) int - -//go:noescape -func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool) - -//go:noescape -func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool - -func makechan(typ *rtype, size uint64) (ch unsafe.Pointer) -func makemap(t *rtype) (m unsafe.Pointer) -func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) -func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) -func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer) -func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer -func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer) -func mapiternext(it unsafe.Pointer) -func maplen(m unsafe.Pointer) int - -func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32) -func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) - -// Dummy annotation marking that the value x escapes, -// for use in cases where the reflect code is so clever that -// the compiler cannot follow. -func escapes(x interface{}) { - if dummy.b { - dummy.x = x - } -} - -var dummy struct { - b bool - x interface{} -} |