From 04f7521b0aef10d523d6de006e723afd349b4b95 Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Sat, 25 Sep 2021 18:44:24 +0200 Subject: [PATCH] reflect: add Value.{CanInt, CanUint, CanFloat, CanComplex} As discussed in #47658, Value already has CanAddr and CanInterface to test if a call to Addr or Inteface, respectively, does not result in a panic. Therefore we add CanInt, CanUint, CanFloat and CanComplex to ease the test for a possible panic in calling, respectively, Int, Uint, Float and Complex. Fixes #47658 Change-Id: I58b77d77e6eec9f34234e985f631eab72b5b935e Reviewed-on: https://go-review.googlesource.com/c/go/+/352131 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Trust: David Chase Trust: Brad Fitzpatrick Reviewed-by: Keith Randall --- src/cmd/compile/internal/test/inl_test.go | 4 ++ src/reflect/all_test.go | 69 +++++++++++++++++++++++ src/reflect/value.go | 40 +++++++++++++ 3 files changed, 113 insertions(+) diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go index 89247fbabf..5fa6411ae4 100644 --- a/src/cmd/compile/internal/test/inl_test.go +++ b/src/cmd/compile/internal/test/inl_test.go @@ -127,6 +127,10 @@ func TestIntendedInlining(t *testing.T) { "ValidRune", }, "reflect": { + "Value.CanInt", + "Value.CanUint", + "Value.CanFloat", + "Value.CanComplex", "Value.CanAddr", "Value.CanSet", "Value.CanInterface", diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 22885c548f..5e10cc7a63 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -376,6 +376,75 @@ func TestMapIterSet(t *testing.T) { } } +func TestCanIntUintFloatComplex(t *testing.T) { + type integer int + type uinteger uint + type float float64 + type complex complex128 + + var ops = [...]string{"CanInt", "CanUint", "CanFloat", "CanComplex"} + + var testCases = []struct { + i interface{} + want [4]bool + }{ + // signed integer + {132, [...]bool{true, false, false, false}}, + {int8(8), [...]bool{true, false, false, false}}, + {int16(16), [...]bool{true, false, false, false}}, + {int32(32), [...]bool{true, false, false, false}}, + {int64(64), [...]bool{true, false, false, false}}, + // unsigned integer + {uint(132), [...]bool{false, true, false, false}}, + {uint8(8), [...]bool{false, true, false, false}}, + {uint16(16), [...]bool{false, true, false, false}}, + {uint32(32), [...]bool{false, true, false, false}}, + {uint64(64), [...]bool{false, true, false, false}}, + {uintptr(0xABCD), [...]bool{false, true, false, false}}, + // floating-point + {float32(256.25), [...]bool{false, false, true, false}}, + {float64(512.125), [...]bool{false, false, true, false}}, + // complex + {complex64(532.125 + 10i), [...]bool{false, false, false, true}}, + {complex128(564.25 + 1i), [...]bool{false, false, false, true}}, + // underlying + {integer(-132), [...]bool{true, false, false, false}}, + {uinteger(132), [...]bool{false, true, false, false}}, + {float(256.25), [...]bool{false, false, true, false}}, + {complex(532.125 + 10i), [...]bool{false, false, false, true}}, + // not-acceptable + {"hello world", [...]bool{false, false, false, false}}, + {new(int), [...]bool{false, false, false, false}}, + {new(uint), [...]bool{false, false, false, false}}, + {new(float64), [...]bool{false, false, false, false}}, + {new(complex64), [...]bool{false, false, false, false}}, + {new([5]int), [...]bool{false, false, false, false}}, + {new(integer), [...]bool{false, false, false, false}}, + {new(map[int]int), [...]bool{false, false, false, false}}, + {new(chan<- int), [...]bool{false, false, false, false}}, + {new(func(a int8)), [...]bool{false, false, false, false}}, + {new(struct{ i int }), [...]bool{false, false, false, false}}, + } + + for i, tc := range testCases { + v := ValueOf(tc.i) + got := [...]bool{v.CanInt(), v.CanUint(), v.CanFloat(), v.CanComplex()} + + for j := range tc.want { + if got[j] != tc.want[j] { + t.Errorf( + "#%d: v.%s() returned %t for type %T, want %t", + i, + ops[j], + got[j], + tc.i, + tc.want[j], + ) + } + } + } +} + func TestCanSetField(t *testing.T) { type embed struct{ x, X int } type Embed struct{ x, X int } diff --git a/src/reflect/value.go b/src/reflect/value.go index 786c494166..39b82a8c01 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1122,6 +1122,16 @@ func (v Value) Close() { chanclose(v.pointer()) } +// CanComplex reports whether Complex can be used without panicking. +func (v Value) CanComplex() bool { + switch v.kind() { + case Complex64, Complex128: + return true + default: + return false + } +} + // 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 { @@ -1249,6 +1259,16 @@ func (v Value) FieldByNameFunc(match func(string) bool) Value { return Value{} } +// CanFloat reports whether Float can be used without panicking. +func (v Value) CanFloat() bool { + switch v.kind() { + case Float32, Float64: + return true + default: + return false + } +} + // 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 { @@ -1310,6 +1330,16 @@ func (v Value) Index(i int) Value { panic(&ValueError{"reflect.Value.Index", v.kind()}) } +// CanInt reports whether Int can be used without panicking. +func (v Value) CanInt() bool { + switch v.kind() { + case Int, Int8, Int16, Int32, Int64: + return true + default: + return false + } +} + // 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 { @@ -2391,6 +2421,16 @@ func (v Value) Type() Type { return v.typ.typeOff(m.mtyp) } +// CanUint reports whether Uint can be used without panicking. +func (v Value) CanUint() bool { + switch v.kind() { + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + default: + return false + } +} + // 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 {