reflect: add Overflow methods to Type

This CL adds new methods synonymous with the method of the same name
in reflect.Value to reflect.Type: OverflowComplex, OverflowFloat,
OverflowInt, OverflowUint.

Fixes #60427
This commit is contained in:
Jes Cok 2024-02-27 18:32:25 +08:00
parent ccbc725f2d
commit f7f4f2bb6f
4 changed files with 118 additions and 1 deletions

4
api/next/60427.txt Normal file
View File

@ -0,0 +1,4 @@
pkg reflect, method (Type) OverflowComplex(complex128) bool #60427
pkg reflect, method (Type) OverflowFloat(float64) bool #60427
pkg reflect, method (Type) OverflowInt(int64) bool #60427
pkg reflect, method (Type) OverflowUint(uint64) bool #60427

View File

@ -0,0 +1,6 @@
The new methods synonymous with the method of the same name in [`reflect.Value`](/reflect.Value)
are added to [`reflect.Type`](/reflect.Type):
1. [`OverflowComplex`](/reflect.Type#OverflowComplex)
2. [`OverflowFloat`](/reflect.Type#OverflowFloat)
3. [`OverflowInt`](/reflect.Type#OverflowInt)
4. [`OverflowUint`](/reflect.Type#OverflowUint)

View File

@ -4827,7 +4827,7 @@ func TestComparable(t *testing.T) {
}
}
func TestOverflow(t *testing.T) {
func TestValueOverflow(t *testing.T) {
if ovf := V(float64(0)).OverflowFloat(1e300); ovf {
t.Errorf("%v wrongly overflows float64", 1e300)
}
@ -4866,6 +4866,45 @@ func TestOverflow(t *testing.T) {
}
}
func TestTypeOverflow(t *testing.T) {
if ovf := TypeFor[float64]().OverflowFloat(1e300); ovf {
t.Errorf("%v wrongly overflows float64", 1e300)
}
maxFloat32 := float64((1<<24 - 1) << (127 - 23))
if ovf := TypeFor[float32]().OverflowFloat(maxFloat32); ovf {
t.Errorf("%v wrongly overflows float32", maxFloat32)
}
ovfFloat32 := float64((1<<24-1)<<(127-23) + 1<<(127-52))
if ovf := TypeFor[float32]().OverflowFloat(ovfFloat32); !ovf {
t.Errorf("%v should overflow float32", ovfFloat32)
}
if ovf := TypeFor[float32]().OverflowFloat(-ovfFloat32); !ovf {
t.Errorf("%v should overflow float32", -ovfFloat32)
}
maxInt32 := int64(0x7fffffff)
if ovf := TypeFor[int32]().OverflowInt(maxInt32); ovf {
t.Errorf("%v wrongly overflows int32", maxInt32)
}
if ovf := TypeFor[int32]().OverflowInt(-1 << 31); ovf {
t.Errorf("%v wrongly overflows int32", -int64(1)<<31)
}
ovfInt32 := int64(1 << 31)
if ovf := TypeFor[int32]().OverflowInt(ovfInt32); !ovf {
t.Errorf("%v should overflow int32", ovfInt32)
}
maxUint32 := uint64(0xffffffff)
if ovf := TypeFor[uint32]().OverflowUint(maxUint32); ovf {
t.Errorf("%v wrongly overflows uint32", maxUint32)
}
ovfUint32 := uint64(1 << 32)
if ovf := TypeFor[uint32]().OverflowUint(ovfUint32); !ovf {
t.Errorf("%v should overflow uint32", ovfUint32)
}
}
func checkSameType(t *testing.T, x Type, y any) {
if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) {
t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))

View File

@ -227,6 +227,22 @@ type Type interface {
common() *abi.Type
uncommon() *uncommonType
// OverflowComplex reports whether the complex128 x cannot be represented by type t.
// It panics if t's Kind is not Complex64 or Complex128.
OverflowComplex(x complex128) bool
// OverflowFloat reports whether the float64 x cannot be represented by type t.
// It panics if t's Kind is not Float32 or Float64.
OverflowFloat(x float64) bool
// OverflowInt reports whether the int64 x cannot be represented by type t.
// It panics if t's Kind is not Int, Int8, Int16, Int32, or Int64.
OverflowInt(x int64) bool
// OverflowUint reports whether the uint64 x cannot be represented by type t.
// It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
OverflowUint(x uint64) bool
}
// BUG(rsc): FieldByName and related functions consider struct field names to be equal
@ -297,6 +313,58 @@ type rtype struct {
t abi.Type
}
// OverflowComplex reports whether the complex128 x cannot be represented by type t.
// It panics if t's Kind is not Complex64 or Complex128.
func (t *rtype) OverflowComplex(x complex128) bool {
k := t.Kind()
switch k {
case Complex64:
return overflowFloat32(real(x)) || overflowFloat32(imag(x))
case Complex128:
return false
}
panic("reflect: OverflowComplexof non-complex type " + t.String())
}
// OverflowFloat reports whether the float64 x cannot be represented by type t.
// It panics if t's Kind is not Float32 or Float64.
func (t *rtype) OverflowFloat(x float64) bool {
k := t.Kind()
switch k {
case Float32:
return overflowFloat32(x)
case Float64:
return false
}
panic("reflect: OverflowFloat non-float type " + t.String())
}
// OverflowInt reports whether the int64 x cannot be represented by type t.
// It panics if t's Kind is not Int, Int8, Int16, Int32, or Int64.
func (t *rtype) OverflowInt(x int64) bool {
k := t.Kind()
switch k {
case Int, Int8, Int16, Int32, Int64:
bitSize := t.Size() * 8
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
panic("reflect: OverflowInt non-int type " + t.String())
}
// OverflowUint reports whether the uint64 x cannot be represented by type t.
// It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (t *rtype) OverflowUint(x uint64) bool {
k := t.Kind()
switch k {
case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64:
bitSize := t.Size() * 8 // ok to use v.typ_ directly as Size doesn't escape
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
panic("reflect: OverflowUint non-uint type " + t.String())
}
func (t *rtype) common() *abi.Type {
return &t.t
}