package types
import (
"go/constant"
"go/token"
. "internal/types/errors"
"math"
)
func (check *Checker ) overflow (x *operand , opPos token .Pos ) {
assert (x .mode == constant_ )
if x .val .Kind () == constant .Unknown {
check .error (atPos (opPos ), InvalidConstVal , "constant result is not representable" )
return
}
if isTyped (x .typ ) {
check .representable (x , under (x .typ ).(*Basic ))
return
}
const prec = 512
if x .val .Kind () == constant .Int && constant .BitLen (x .val ) > prec {
op := opName (x .expr )
if op != "" {
op += " "
}
check .errorf (atPos (opPos ), InvalidConstVal , "constant %soverflow" , op )
x .val = constant .MakeUnknown ()
}
}
func representableConst(x constant .Value , check *Checker , typ *Basic , rounded *constant .Value ) bool {
if x .Kind () == constant .Unknown {
return true
}
var conf *Config
if check != nil {
conf = check .conf
}
sizeof := func (T Type ) int64 {
s := conf .sizeof (T )
return s
}
switch {
case isInteger (typ ):
x := constant .ToInt (x )
if x .Kind () != constant .Int {
return false
}
if rounded != nil {
*rounded = x
}
if x , ok := constant .Int64Val (x ); ok {
switch typ .kind {
case Int :
var s = uint (sizeof (typ )) * 8
return int64 (-1 )<<(s -1 ) <= x && x <= int64 (1 )<<(s -1 )-1
case Int8 :
const s = 8
return -1 <<(s -1 ) <= x && x <= 1 <<(s -1 )-1
case Int16 :
const s = 16
return -1 <<(s -1 ) <= x && x <= 1 <<(s -1 )-1
case Int32 :
const s = 32
return -1 <<(s -1 ) <= x && x <= 1 <<(s -1 )-1
case Int64 , UntypedInt :
return true
case Uint , Uintptr :
if s := uint (sizeof (typ )) * 8 ; s < 64 {
return 0 <= x && x <= int64 (1 )<<s -1
}
return 0 <= x
case Uint8 :
const s = 8
return 0 <= x && x <= 1 <<s -1
case Uint16 :
const s = 16
return 0 <= x && x <= 1 <<s -1
case Uint32 :
const s = 32
return 0 <= x && x <= 1 <<s -1
case Uint64 :
return 0 <= x
default :
panic ("unreachable" )
}
}
switch n := constant .BitLen (x ); typ .kind {
case Uint , Uintptr :
var s = uint (sizeof (typ )) * 8
return constant .Sign (x ) >= 0 && n <= int (s )
case Uint64 :
return constant .Sign (x ) >= 0 && n <= 64
case UntypedInt :
return true
}
case isFloat (typ ):
x := constant .ToFloat (x )
if x .Kind () != constant .Float {
return false
}
switch typ .kind {
case Float32 :
if rounded == nil {
return fitsFloat32 (x )
}
r := roundFloat32 (x )
if r != nil {
*rounded = r
return true
}
case Float64 :
if rounded == nil {
return fitsFloat64 (x )
}
r := roundFloat64 (x )
if r != nil {
*rounded = r
return true
}
case UntypedFloat :
return true
default :
panic ("unreachable" )
}
case isComplex (typ ):
x := constant .ToComplex (x )
if x .Kind () != constant .Complex {
return false
}
switch typ .kind {
case Complex64 :
if rounded == nil {
return fitsFloat32 (constant .Real (x )) && fitsFloat32 (constant .Imag (x ))
}
re := roundFloat32 (constant .Real (x ))
im := roundFloat32 (constant .Imag (x ))
if re != nil && im != nil {
*rounded = constant .BinaryOp (re , token .ADD , constant .MakeImag (im ))
return true
}
case Complex128 :
if rounded == nil {
return fitsFloat64 (constant .Real (x )) && fitsFloat64 (constant .Imag (x ))
}
re := roundFloat64 (constant .Real (x ))
im := roundFloat64 (constant .Imag (x ))
if re != nil && im != nil {
*rounded = constant .BinaryOp (re , token .ADD , constant .MakeImag (im ))
return true
}
case UntypedComplex :
return true
default :
panic ("unreachable" )
}
case isString (typ ):
return x .Kind () == constant .String
case isBoolean (typ ):
return x .Kind () == constant .Bool
}
return false
}
func fitsFloat32(x constant .Value ) bool {
f32 , _ := constant .Float32Val (x )
f := float64 (f32 )
return !math .IsInf (f , 0 )
}
func roundFloat32(x constant .Value ) constant .Value {
f32 , _ := constant .Float32Val (x )
f := float64 (f32 )
if !math .IsInf (f , 0 ) {
return constant .MakeFloat64 (f )
}
return nil
}
func fitsFloat64(x constant .Value ) bool {
f , _ := constant .Float64Val (x )
return !math .IsInf (f , 0 )
}
func roundFloat64(x constant .Value ) constant .Value {
f , _ := constant .Float64Val (x )
if !math .IsInf (f , 0 ) {
return constant .MakeFloat64 (f )
}
return nil
}
func (check *Checker ) representable (x *operand , typ *Basic ) {
v , code := check .representation (x , typ )
if code != 0 {
check .invalidConversion (code , x , typ )
x .mode = invalid
return
}
assert (v != nil )
x .val = v
}
func (check *Checker ) representation (x *operand , typ *Basic ) (constant .Value , Code ) {
assert (x .mode == constant_ )
v := x .val
if !representableConst (x .val , check , typ , &v ) {
if isNumeric (x .typ ) && isNumeric (typ ) {
if !isInteger (x .typ ) && isInteger (typ ) {
return nil , TruncatedFloat
} else {
return nil , NumericOverflow
}
}
return nil , InvalidConstVal
}
return v , 0
}
func (check *Checker ) invalidConversion (code Code , x *operand , target Type ) {
msg := "cannot convert %s to type %s"
switch code {
case TruncatedFloat :
msg = "%s truncated to %s"
case NumericOverflow :
msg = "%s overflows %s"
}
check .errorf (x , code , msg , x , target )
}
func (check *Checker ) convertUntyped (x *operand , target Type ) {
newType , val , code := check .implicitTypeAndValue (x , target )
if code != 0 {
t := target
if !isTypeParam (target ) {
t = safeUnderlying (target )
}
check .invalidConversion (code , x , t )
x .mode = invalid
return
}
if val != nil {
x .val = val
check .updateExprVal (x .expr , val )
}
if newType != x .typ {
x .typ = newType
check .updateExprType (x .expr , newType , false )
}
}
The pages are generated with Golds v0.7.0-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .