// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. // Copyright 2023 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. // This file implements functions for untyped constant operands. package types import ( "go/constant" "go/token" . "internal/types/errors" "math" ) // overflow checks that the constant x is representable by its type. // For untyped constants, it checks that the value doesn't become // arbitrarily large. func (check *Checker) overflow(x *operand, opPos token.Pos) { assert(x.mode == constant_) if x.val.Kind() == constant.Unknown { // TODO(gri) We should report exactly what went wrong. At the // moment we don't have the (go/constant) API for that. // See also TODO in go/constant/value.go. check.error(atPos(opPos), InvalidConstVal, "constant result is not representable") return } // Typed constants must be representable in // their type after each constant operation. // x.typ cannot be a type parameter (type // parameters cannot be constant types). if isTyped(x.typ) { check.representable(x, under(x.typ).(*Basic)) return } // Untyped integer values must not grow arbitrarily. const prec = 512 // 512 is the constant precision 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() } } // 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. // // The check parameter may be nil if representableConst is invoked // (indirectly) through an exported API call (AssignableTo, ConvertibleTo) // because we don't need the Checker's config for those calls. func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool { if x.Kind() == constant.Unknown { return true // avoid follow-up errors } 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)<= 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 } 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 } // representable checks that a constant operand is representable in the given // basic type. 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 } // representation returns the representation of the constant operand x as the // basic type typ. // // If no such representation is possible, it returns a non-zero error code. 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) { // numeric conversion : error msg // // integer -> integer : overflows // integer -> float : overflows (actually not possible) // float -> integer : truncated // float -> float : overflows // 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) } // convertUntyped attempts to set the type of an untyped value to the target type. 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) } }