// representableConst reports whether x can be represented as // value of the given basic type and for the configuration // provided (only needed for int/uint sizes). // // If rounded != nil, *rounded is set to the rounded value of x for // representable floating-point and complex values, and to an Int // value for integer values; it is left alone otherwise. // It is ok to provide the addressof the first argument for rounded. func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool { if x.Kind() == constant.Unknown { return true // avoid follow-up errors } 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(conf.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(conf.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: unreachable() } } // x does not fit into int64 switch n := constant.BitLen(x); typ.kind { case Uint, Uintptr: var s = uint(conf.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: 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: unreachable() } case isString(typ): return x.Kind() == constant.String case isBoolean(typ): return x.Kind() == constant.Bool } return false }
// representableConst reports whether x can be represented as // value of the given basic type kind and for the configuration // provided (only needed for int/uint sizes). // // If rounded != nil, *rounded is set to the rounded value of x for // representable floating-point values; it is left alone otherwise. // It is ok to provide the addressof the first argument for rounded. func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *constant.Value) bool { switch x.Kind() { case constant.Unknown: return true case constant.Bool: return as == Bool || as == UntypedBool case constant.Int: if x, ok := constant.Int64Val(x); ok { switch as { case Int: var s = uint(conf.sizeof(Typ[as])) * 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: return true case Uint, Uintptr: if s := uint(conf.sizeof(Typ[as])) * 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 case Float32, Float64, Complex64, Complex128, UntypedInt, UntypedFloat, UntypedComplex: return true } } n := constant.BitLen(x) switch as { case Uint, Uintptr: var s = uint(conf.sizeof(Typ[as])) * 8 return constant.Sign(x) >= 0 && n <= int(s) case Uint64: return constant.Sign(x) >= 0 && n <= 64 case Float32, Complex64: if rounded == nil { return fitsFloat32(x) } r := roundFloat32(x) if r != nil { *rounded = r return true } case Float64, Complex128: if rounded == nil { return fitsFloat64(x) } r := roundFloat64(x) if r != nil { *rounded = r return true } case UntypedInt, UntypedFloat, UntypedComplex: return true } case constant.Float: switch as { case Float32, Complex64: if rounded == nil { return fitsFloat32(x) } r := roundFloat32(x) if r != nil { *rounded = r return true } case Float64, Complex128: if rounded == nil { return fitsFloat64(x) } r := roundFloat64(x) if r != nil { *rounded = r return true } case UntypedFloat, UntypedComplex: return true } case constant.Complex: switch as { 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 } case constant.String: return as == String || as == UntypedString default: unreachable() } return false }