const.go raw

   1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
   2  // Source: ../../cmd/compile/internal/types2/const.go
   3  
   4  // Copyright 2023 The Go Authors. All rights reserved.
   5  // Use of this source code is governed by a BSD-style
   6  // license that can be found in the LICENSE file.
   7  
   8  // This file implements functions for untyped constant operands.
   9  
  10  package types
  11  
  12  import (
  13  	"go/constant"
  14  	"go/token"
  15  	. "internal/types/errors"
  16  	"math"
  17  )
  18  
  19  // overflow checks that the constant x is representable by its type.
  20  // For untyped constants, it checks that the value doesn't become
  21  // arbitrarily large.
  22  func (check *Checker) overflow(x *operand, opPos token.Pos) {
  23  	assert(x.mode == constant_)
  24  
  25  	if x.val.Kind() == constant.Unknown {
  26  		// TODO(gri) We should report exactly what went wrong. At the
  27  		//           moment we don't have the (go/constant) API for that.
  28  		//           See also TODO in go/constant/value.go.
  29  		check.error(atPos(opPos), InvalidConstVal, "constant result is not representable")
  30  		return
  31  	}
  32  
  33  	// Typed constants must be representable in
  34  	// their type after each constant operation.
  35  	// x.typ cannot be a type parameter (type
  36  	// parameters cannot be constant types).
  37  	if isTyped(x.typ) {
  38  		check.representable(x, under(x.typ).(*Basic))
  39  		return
  40  	}
  41  
  42  	// Untyped integer values must not grow arbitrarily.
  43  	const prec = 512 // 512 is the constant precision
  44  	if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
  45  		op := opName(x.expr)
  46  		if op != "" {
  47  			op += " "
  48  		}
  49  		check.errorf(atPos(opPos), InvalidConstVal, "constant %soverflow", op)
  50  		x.val = constant.MakeUnknown()
  51  	}
  52  }
  53  
  54  // representableConst reports whether x can be represented as
  55  // value of the given basic type and for the configuration
  56  // provided (only needed for int/uint sizes).
  57  //
  58  // If rounded != nil, *rounded is set to the rounded value of x for
  59  // representable floating-point and complex values, and to an Int
  60  // value for integer values; it is left alone otherwise.
  61  // It is ok to provide the addressof the first argument for rounded.
  62  //
  63  // The check parameter may be nil if representableConst is invoked
  64  // (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
  65  // because we don't need the Checker's config for those calls.
  66  func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
  67  	if x.Kind() == constant.Unknown {
  68  		return true // avoid follow-up errors
  69  	}
  70  
  71  	var conf *Config
  72  	if check != nil {
  73  		conf = check.conf
  74  	}
  75  
  76  	sizeof := func(T Type) int64 {
  77  		s := conf.sizeof(T)
  78  		return s
  79  	}
  80  
  81  	switch {
  82  	case isInteger(typ):
  83  		x := constant.ToInt(x)
  84  		if x.Kind() != constant.Int {
  85  			return false
  86  		}
  87  		if rounded != nil {
  88  			*rounded = x
  89  		}
  90  		if x, ok := constant.Int64Val(x); ok {
  91  			switch typ.kind {
  92  			case Int:
  93  				var s = uint(sizeof(typ)) * 8
  94  				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
  95  			case Int8:
  96  				const s = 8
  97  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
  98  			case Int16:
  99  				const s = 16
 100  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
 101  			case Int32:
 102  				const s = 32
 103  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
 104  			case Int64, UntypedInt:
 105  				return true
 106  			case Uint, Uintptr:
 107  				if s := uint(sizeof(typ)) * 8; s < 64 {
 108  					return 0 <= x && x <= int64(1)<<s-1
 109  				}
 110  				return 0 <= x
 111  			case Uint8:
 112  				const s = 8
 113  				return 0 <= x && x <= 1<<s-1
 114  			case Uint16:
 115  				const s = 16
 116  				return 0 <= x && x <= 1<<s-1
 117  			case Uint32:
 118  				const s = 32
 119  				return 0 <= x && x <= 1<<s-1
 120  			case Uint64:
 121  				return 0 <= x
 122  			default:
 123  				panic("unreachable")
 124  			}
 125  		}
 126  		// x does not fit into int64
 127  		switch n := constant.BitLen(x); typ.kind {
 128  		case Uint, Uintptr:
 129  			var s = uint(sizeof(typ)) * 8
 130  			return constant.Sign(x) >= 0 && n <= int(s)
 131  		case Uint64:
 132  			return constant.Sign(x) >= 0 && n <= 64
 133  		case UntypedInt:
 134  			return true
 135  		}
 136  
 137  	case isFloat(typ):
 138  		x := constant.ToFloat(x)
 139  		if x.Kind() != constant.Float {
 140  			return false
 141  		}
 142  		switch typ.kind {
 143  		case Float32:
 144  			if rounded == nil {
 145  				return fitsFloat32(x)
 146  			}
 147  			r := roundFloat32(x)
 148  			if r != nil {
 149  				*rounded = r
 150  				return true
 151  			}
 152  		case Float64:
 153  			if rounded == nil {
 154  				return fitsFloat64(x)
 155  			}
 156  			r := roundFloat64(x)
 157  			if r != nil {
 158  				*rounded = r
 159  				return true
 160  			}
 161  		case UntypedFloat:
 162  			return true
 163  		default:
 164  			panic("unreachable")
 165  		}
 166  
 167  	case isComplex(typ):
 168  		x := constant.ToComplex(x)
 169  		if x.Kind() != constant.Complex {
 170  			return false
 171  		}
 172  		switch typ.kind {
 173  		case Complex64:
 174  			if rounded == nil {
 175  				return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
 176  			}
 177  			re := roundFloat32(constant.Real(x))
 178  			im := roundFloat32(constant.Imag(x))
 179  			if re != nil && im != nil {
 180  				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
 181  				return true
 182  			}
 183  		case Complex128:
 184  			if rounded == nil {
 185  				return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
 186  			}
 187  			re := roundFloat64(constant.Real(x))
 188  			im := roundFloat64(constant.Imag(x))
 189  			if re != nil && im != nil {
 190  				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
 191  				return true
 192  			}
 193  		case UntypedComplex:
 194  			return true
 195  		default:
 196  			panic("unreachable")
 197  		}
 198  
 199  	case isString(typ):
 200  		return x.Kind() == constant.String
 201  
 202  	case isBoolean(typ):
 203  		return x.Kind() == constant.Bool
 204  	}
 205  
 206  	return false
 207  }
 208  
 209  func fitsFloat32(x constant.Value) bool {
 210  	f32, _ := constant.Float32Val(x)
 211  	f := float64(f32)
 212  	return !math.IsInf(f, 0)
 213  }
 214  
 215  func roundFloat32(x constant.Value) constant.Value {
 216  	f32, _ := constant.Float32Val(x)
 217  	f := float64(f32)
 218  	if !math.IsInf(f, 0) {
 219  		return constant.MakeFloat64(f)
 220  	}
 221  	return nil
 222  }
 223  
 224  func fitsFloat64(x constant.Value) bool {
 225  	f, _ := constant.Float64Val(x)
 226  	return !math.IsInf(f, 0)
 227  }
 228  
 229  func roundFloat64(x constant.Value) constant.Value {
 230  	f, _ := constant.Float64Val(x)
 231  	if !math.IsInf(f, 0) {
 232  		return constant.MakeFloat64(f)
 233  	}
 234  	return nil
 235  }
 236  
 237  // representable checks that a constant operand is representable in the given
 238  // basic type.
 239  func (check *Checker) representable(x *operand, typ *Basic) {
 240  	v, code := check.representation(x, typ)
 241  	if code != 0 {
 242  		check.invalidConversion(code, x, typ)
 243  		x.mode = invalid
 244  		return
 245  	}
 246  	assert(v != nil)
 247  	x.val = v
 248  }
 249  
 250  // representation returns the representation of the constant operand x as the
 251  // basic type typ.
 252  //
 253  // If no such representation is possible, it returns a non-zero error code.
 254  func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
 255  	assert(x.mode == constant_)
 256  	v := x.val
 257  	if !representableConst(x.val, check, typ, &v) {
 258  		if isNumeric(x.typ) && isNumeric(typ) {
 259  			// numeric conversion : error msg
 260  			//
 261  			// integer -> integer : overflows
 262  			// integer -> float   : overflows (actually not possible)
 263  			// float   -> integer : truncated
 264  			// float   -> float   : overflows
 265  			//
 266  			if !isInteger(x.typ) && isInteger(typ) {
 267  				return nil, TruncatedFloat
 268  			} else {
 269  				return nil, NumericOverflow
 270  			}
 271  		}
 272  		return nil, InvalidConstVal
 273  	}
 274  	return v, 0
 275  }
 276  
 277  func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
 278  	msg := "cannot convert %s to type %s"
 279  	switch code {
 280  	case TruncatedFloat:
 281  		msg = "%s truncated to %s"
 282  	case NumericOverflow:
 283  		msg = "%s overflows %s"
 284  	}
 285  	check.errorf(x, code, msg, x, target)
 286  }
 287  
 288  // convertUntyped attempts to set the type of an untyped value to the target type.
 289  func (check *Checker) convertUntyped(x *operand, target Type) {
 290  	newType, val, code := check.implicitTypeAndValue(x, target)
 291  	if code != 0 {
 292  		t := target
 293  		if !isTypeParam(target) {
 294  			t = safeUnderlying(target)
 295  		}
 296  		check.invalidConversion(code, x, t)
 297  		x.mode = invalid
 298  		return
 299  	}
 300  	if val != nil {
 301  		x.val = val
 302  		check.updateExprVal(x.expr, val)
 303  	}
 304  	if newType != x.typ {
 305  		x.typ = newType
 306  		check.updateExprType(x.expr, newType, false)
 307  	}
 308  }
 309