whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
@@ -0,0 +1,164 @@
// Copyright 2020, 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 value
import (
"reflect"
"strconv"
)
var anyType = reflect.TypeOf((*interface{})(nil)).Elem()
// TypeString is nearly identical to reflect.Type.String,
// but has an additional option to specify that full type names be used.
func TypeString(t reflect.Type, qualified bool) string {
return string(appendTypeName(nil, t, qualified, false))
}
func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte {
// BUG: Go reflection provides no way to disambiguate two named types
// of the same name and within the same package,
// but declared within the namespace of different functions.
// Use the "any" alias instead of "interface{}" for better readability.
if t == anyType {
return append(b, "any"...)
}
// Named type.
if t.Name() != "" {
if qualified && t.PkgPath() != "" {
b = append(b, '"')
b = append(b, t.PkgPath()...)
b = append(b, '"')
b = append(b, '.')
b = append(b, t.Name()...)
} else {
b = append(b, t.String()...)
}
return b
}
// Unnamed type.
switch k := t.Kind(); k {
case reflect.Bool, reflect.String, reflect.UnsafePointer,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
b = append(b, k.String()...)
case reflect.Chan:
if t.ChanDir() == reflect.RecvDir {
b = append(b, "<-"...)
}
b = append(b, "chan"...)
if t.ChanDir() == reflect.SendDir {
b = append(b, "<-"...)
}
b = append(b, ' ')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Func:
if !elideFunc {
b = append(b, "func"...)
}
b = append(b, '(')
for i := 0; i < t.NumIn(); i++ {
if i > 0 {
b = append(b, ", "...)
}
if i == t.NumIn()-1 && t.IsVariadic() {
b = append(b, "..."...)
b = appendTypeName(b, t.In(i).Elem(), qualified, false)
} else {
b = appendTypeName(b, t.In(i), qualified, false)
}
}
b = append(b, ')')
switch t.NumOut() {
case 0:
// Do nothing
case 1:
b = append(b, ' ')
b = appendTypeName(b, t.Out(0), qualified, false)
default:
b = append(b, " ("...)
for i := 0; i < t.NumOut(); i++ {
if i > 0 {
b = append(b, ", "...)
}
b = appendTypeName(b, t.Out(i), qualified, false)
}
b = append(b, ')')
}
case reflect.Struct:
b = append(b, "struct{ "...)
for i := 0; i < t.NumField(); i++ {
if i > 0 {
b = append(b, "; "...)
}
sf := t.Field(i)
if !sf.Anonymous {
if qualified && sf.PkgPath != "" {
b = append(b, '"')
b = append(b, sf.PkgPath...)
b = append(b, '"')
b = append(b, '.')
}
b = append(b, sf.Name...)
b = append(b, ' ')
}
b = appendTypeName(b, sf.Type, qualified, false)
if sf.Tag != "" {
b = append(b, ' ')
b = strconv.AppendQuote(b, string(sf.Tag))
}
}
if b[len(b)-1] == ' ' {
b = b[:len(b)-1]
} else {
b = append(b, ' ')
}
b = append(b, '}')
case reflect.Slice, reflect.Array:
b = append(b, '[')
if k == reflect.Array {
b = strconv.AppendUint(b, uint64(t.Len()), 10)
}
b = append(b, ']')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Map:
b = append(b, "map["...)
b = appendTypeName(b, t.Key(), qualified, false)
b = append(b, ']')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Ptr:
b = append(b, '*')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Interface:
b = append(b, "interface{ "...)
for i := 0; i < t.NumMethod(); i++ {
if i > 0 {
b = append(b, "; "...)
}
m := t.Method(i)
if qualified && m.PkgPath != "" {
b = append(b, '"')
b = append(b, m.PkgPath...)
b = append(b, '"')
b = append(b, '.')
}
b = append(b, m.Name...)
b = appendTypeName(b, m.Type, qualified, true)
}
if b[len(b)-1] == ' ' {
b = b[:len(b)-1]
} else {
b = append(b, ' ')
}
b = append(b, '}')
default:
panic("invalid kind: " + k.String())
}
return b
}
@@ -0,0 +1,144 @@
// Copyright 2020, 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 value
import (
"reflect"
"strings"
"testing"
)
type Named struct{}
var pkgPath = reflect.TypeOf(Named{}).PkgPath()
func TestTypeString(t *testing.T) {
tests := []struct {
in interface{}
want string
}{{
in: bool(false),
want: "bool",
}, {
in: int(0),
want: "int",
}, {
in: float64(0),
want: "float64",
}, {
in: string(""),
want: "string",
}, {
in: Named{},
want: "$PackagePath.Named",
}, {
in: (chan Named)(nil),
want: "chan $PackagePath.Named",
}, {
in: (<-chan Named)(nil),
want: "<-chan $PackagePath.Named",
}, {
in: (chan<- Named)(nil),
want: "chan<- $PackagePath.Named",
}, {
in: (func())(nil),
want: "func()",
}, {
in: (func(Named))(nil),
want: "func($PackagePath.Named)",
}, {
in: (func() Named)(nil),
want: "func() $PackagePath.Named",
}, {
in: (func(int, Named) (int, error))(nil),
want: "func(int, $PackagePath.Named) (int, error)",
}, {
in: (func(...Named))(nil),
want: "func(...$PackagePath.Named)",
}, {
in: struct{}{},
want: "struct{}",
}, {
in: struct{ Named }{},
want: "struct{ $PackagePath.Named }",
}, {
in: struct {
Named `tag`
}{},
want: "struct{ $PackagePath.Named \"tag\" }",
}, {
in: struct{ Named Named }{},
want: "struct{ Named $PackagePath.Named }",
}, {
in: struct {
Named Named `tag`
}{},
want: "struct{ Named $PackagePath.Named \"tag\" }",
}, {
in: struct {
Int int
Named Named
}{},
want: "struct{ Int int; Named $PackagePath.Named }",
}, {
in: struct {
_ int
x Named
}{},
want: "struct{ $FieldPrefix._ int; $FieldPrefix.x $PackagePath.Named }",
}, {
in: []Named(nil),
want: "[]$PackagePath.Named",
}, {
in: []*Named(nil),
want: "[]*$PackagePath.Named",
}, {
in: [10]Named{},
want: "[10]$PackagePath.Named",
}, {
in: [10]*Named{},
want: "[10]*$PackagePath.Named",
}, {
in: map[string]string(nil),
want: "map[string]string",
}, {
in: map[Named]Named(nil),
want: "map[$PackagePath.Named]$PackagePath.Named",
}, {
in: (*Named)(nil),
want: "*$PackagePath.Named",
}, {
in: (*interface{})(nil),
want: "*any",
}, {
in: (*interface{ Read([]byte) (int, error) })(nil),
want: "*interface{ Read([]uint8) (int, error) }",
}, {
in: (*interface {
F1()
F2(Named)
F3() Named
F4(int, Named) (int, error)
F5(...Named)
})(nil),
want: "*interface{ F1(); F2($PackagePath.Named); F3() $PackagePath.Named; F4(int, $PackagePath.Named) (int, error); F5(...$PackagePath.Named) }",
}}
for _, tt := range tests {
typ := reflect.TypeOf(tt.in)
wantShort := tt.want
wantShort = strings.Replace(wantShort, "$PackagePath", "value", -1)
wantShort = strings.Replace(wantShort, "$FieldPrefix.", "", -1)
if gotShort := TypeString(typ, false); gotShort != wantShort {
t.Errorf("TypeString(%v, false) mismatch:\ngot: %v\nwant: %v", typ, gotShort, wantShort)
}
wantQualified := tt.want
wantQualified = strings.Replace(wantQualified, "$PackagePath", `"`+pkgPath+`"`, -1)
wantQualified = strings.Replace(wantQualified, "$FieldPrefix", `"`+pkgPath+`"`, -1)
if gotQualified := TypeString(typ, true); gotQualified != wantQualified {
t.Errorf("TypeString(%v, true) mismatch:\ngot: %v\nwant: %v", typ, gotQualified, wantQualified)
}
}
}
@@ -0,0 +1,34 @@
// Copyright 2018, 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 value
import (
"reflect"
"unsafe"
)
// Pointer is an opaque typed pointer and is guaranteed to be comparable.
type Pointer struct {
p unsafe.Pointer
t reflect.Type
}
// PointerOf returns a Pointer from v, which must be a
// reflect.Ptr, reflect.Slice, or reflect.Map.
func PointerOf(v reflect.Value) Pointer {
// The proper representation of a pointer is unsafe.Pointer,
// which is necessary if the GC ever uses a moving collector.
return Pointer{unsafe.Pointer(v.Pointer()), v.Type()}
}
// IsNil reports whether the pointer is nil.
func (p Pointer) IsNil() bool {
return p.p == nil
}
// Uintptr returns the pointer as a uintptr.
func (p Pointer) Uintptr() uintptr {
return uintptr(p.p)
}
@@ -0,0 +1,106 @@
// Copyright 2017, 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 value
import (
"fmt"
"math"
"reflect"
"sort"
)
// SortKeys sorts a list of map keys, deduplicating keys if necessary.
// The type of each value must be comparable.
func SortKeys(vs []reflect.Value) []reflect.Value {
if len(vs) == 0 {
return vs
}
// Sort the map keys.
sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) })
// Deduplicate keys (fails for NaNs).
vs2 := vs[:1]
for _, v := range vs[1:] {
if isLess(vs2[len(vs2)-1], v) {
vs2 = append(vs2, v)
}
}
return vs2
}
// isLess is a generic function for sorting arbitrary map keys.
// The inputs must be of the same type and must be comparable.
func isLess(x, y reflect.Value) bool {
switch x.Type().Kind() {
case reflect.Bool:
return !x.Bool() && y.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return x.Int() < y.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return x.Uint() < y.Uint()
case reflect.Float32, reflect.Float64:
// NOTE: This does not sort -0 as less than +0
// since Go maps treat -0 and +0 as equal keys.
fx, fy := x.Float(), y.Float()
return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy)
case reflect.Complex64, reflect.Complex128:
cx, cy := x.Complex(), y.Complex()
rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy)
if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) {
return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy)
}
return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry)
case reflect.Ptr, reflect.UnsafePointer, reflect.Chan:
return x.Pointer() < y.Pointer()
case reflect.String:
return x.String() < y.String()
case reflect.Array:
for i := 0; i < x.Len(); i++ {
if isLess(x.Index(i), y.Index(i)) {
return true
}
if isLess(y.Index(i), x.Index(i)) {
return false
}
}
return false
case reflect.Struct:
for i := 0; i < x.NumField(); i++ {
if isLess(x.Field(i), y.Field(i)) {
return true
}
if isLess(y.Field(i), x.Field(i)) {
return false
}
}
return false
case reflect.Interface:
vx, vy := x.Elem(), y.Elem()
if !vx.IsValid() || !vy.IsValid() {
return !vx.IsValid() && vy.IsValid()
}
tx, ty := vx.Type(), vy.Type()
if tx == ty {
return isLess(x.Elem(), y.Elem())
}
if tx.Kind() != ty.Kind() {
return vx.Kind() < vy.Kind()
}
if tx.String() != ty.String() {
return tx.String() < ty.String()
}
if tx.PkgPath() != ty.PkgPath() {
return tx.PkgPath() < ty.PkgPath()
}
// This can happen in rare situations, so we fallback to just comparing
// the unique pointer for a reflect.Type. This guarantees deterministic
// ordering within a program, but it is obviously not stable.
return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer()
default:
// Must be Func, Map, or Slice; which are not comparable.
panic(fmt.Sprintf("%T is not comparable", x.Type()))
}
}
@@ -0,0 +1,159 @@
// Copyright 2017, 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 value_test
import (
"math"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/value"
)
func TestSortKeys(t *testing.T) {
type (
MyString string
MyArray [2]int
MyStruct struct {
A MyString
B MyArray
C chan float64
}
EmptyStruct struct{}
)
opts := []cmp.Option{
cmp.Comparer(func(x, y float64) bool {
if math.IsNaN(x) && math.IsNaN(y) {
return true
}
return x == y
}),
cmp.Comparer(func(x, y complex128) bool {
rx, ix, ry, iy := real(x), imag(x), real(y), imag(y)
if math.IsNaN(rx) && math.IsNaN(ry) {
rx, ry = 0, 0
}
if math.IsNaN(ix) && math.IsNaN(iy) {
ix, iy = 0, 0
}
return rx == ry && ix == iy
}),
cmp.Comparer(func(x, y chan bool) bool { return true }),
cmp.Comparer(func(x, y chan int) bool { return true }),
cmp.Comparer(func(x, y chan float64) bool { return true }),
cmp.Comparer(func(x, y chan interface{}) bool { return true }),
cmp.Comparer(func(x, y *int) bool { return true }),
}
tests := []struct {
in map[interface{}]bool // Set of keys to sort
want []interface{}
}{{
in: map[interface{}]bool{1: true, 2: true, 3: true},
want: []interface{}{1, 2, 3},
}, {
in: map[interface{}]bool{
nil: true,
true: true,
false: true,
-5: true,
-55: true,
-555: true,
uint(1): true,
uint(11): true,
uint(111): true,
"abc": true,
"abcd": true,
"abcde": true,
"foo": true,
"bar": true,
MyString("abc"): true,
MyString("abcd"): true,
MyString("abcde"): true,
new(int): true,
new(int): true,
make(chan bool): true,
make(chan bool): true,
make(chan int): true,
make(chan interface{}): true,
math.Inf(+1): true,
math.Inf(-1): true,
1.2345: true,
12.345: true,
123.45: true,
1234.5: true,
0 + 0i: true,
1 + 0i: true,
2 + 0i: true,
0 + 1i: true,
0 + 2i: true,
0 + 3i: true,
[2]int{2, 3}: true,
[2]int{4, 0}: true,
[2]int{2, 4}: true,
MyArray([2]int{2, 4}): true,
EmptyStruct{}: true,
MyStruct{
"bravo", [2]int{2, 3}, make(chan float64),
}: true,
MyStruct{
"alpha", [2]int{3, 3}, make(chan float64),
}: true,
},
want: []interface{}{
nil, false, true,
-555, -55, -5, uint(1), uint(11), uint(111),
math.Inf(-1), 1.2345, 12.345, 123.45, 1234.5, math.Inf(+1),
(0 + 0i), (0 + 1i), (0 + 2i), (0 + 3i), (1 + 0i), (2 + 0i),
[2]int{2, 3}, [2]int{2, 4}, [2]int{4, 0}, MyArray([2]int{2, 4}),
make(chan bool), make(chan bool), make(chan int), make(chan interface{}),
new(int), new(int),
"abc", "abcd", "abcde", "bar", "foo",
MyString("abc"), MyString("abcd"), MyString("abcde"),
EmptyStruct{},
MyStruct{"alpha", [2]int{3, 3}, make(chan float64)},
MyStruct{"bravo", [2]int{2, 3}, make(chan float64)},
},
}, {
// NaN values cannot be properly deduplicated.
// This is okay since map entries with NaN in the keys cannot be
// retrieved anyways.
in: map[interface{}]bool{
math.NaN(): true,
math.NaN(): true,
complex(0, math.NaN()): true,
complex(0, math.NaN()): true,
complex(math.NaN(), 0): true,
complex(math.NaN(), 0): true,
complex(math.NaN(), math.NaN()): true,
},
want: []interface{}{
math.NaN(),
complex(math.NaN(), math.NaN()),
complex(math.NaN(), 0),
complex(0, math.NaN()),
},
}}
for i, tt := range tests {
// Intentionally pass the map via an unexported field to detect panics.
// Unfortunately, we cannot actually test the keys without using unsafe.
v := reflect.ValueOf(struct{ x map[interface{}]bool }{tt.in}).Field(0)
value.SortKeys(append(v.MapKeys(), v.MapKeys()...))
// Try again, with keys that have read-write access in reflect.
v = reflect.ValueOf(tt.in)
keys := append(v.MapKeys(), v.MapKeys()...)
var got []interface{}
for _, k := range value.SortKeys(keys) {
got = append(got, k.Interface())
}
if d := cmp.Diff(got, tt.want, opts...); d != "" {
t.Errorf("test %d, Sort() mismatch (-got +want):\n%s", i, d)
}
}
}