Source file src/go/types/const.go

     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, x.typ().Underlying().(*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  		return
    52  	}
    53  
    54  	// String values must not become arbitrarily long (go.dev/issue/78346).
    55  	const maxLen = int64(2e9) // cmd/internal/obj.MaxSymSize
    56  	if x.val.Kind() == constant.String {
    57  		len := constant.StringLen(x.val)
    58  		if len > maxLen {
    59  			check.errorf(atPos(opPos), InvalidConstVal, "constant string too long (%d bytes > %d bytes)", len, maxLen)
    60  			x.val = constant.MakeUnknown()
    61  			return
    62  		}
    63  	}
    64  }
    65  
    66  // representableConst reports whether x can be represented as
    67  // value of the given basic type and for the configuration
    68  // provided (only needed for int/uint sizes).
    69  //
    70  // If rounded != nil, *rounded is set to the rounded value of x for
    71  // representable floating-point and complex values, and to an Int
    72  // value for integer values; it is left alone otherwise.
    73  // It is ok to provide the addressof the first argument for rounded.
    74  //
    75  // The check parameter may be nil if representableConst is invoked
    76  // (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
    77  // because we don't need the Checker's config for those calls.
    78  func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
    79  	if x.Kind() == constant.Unknown {
    80  		return true // avoid follow-up errors
    81  	}
    82  
    83  	var conf *Config
    84  	if check != nil {
    85  		conf = check.conf
    86  	}
    87  
    88  	sizeof := func(T Type) int64 {
    89  		s := conf.sizeof(T)
    90  		return s
    91  	}
    92  
    93  	switch {
    94  	case isInteger(typ):
    95  		x := constant.ToInt(x)
    96  		if x.Kind() != constant.Int {
    97  			return false
    98  		}
    99  		if rounded != nil {
   100  			*rounded = x
   101  		}
   102  		if x, ok := constant.Int64Val(x); ok {
   103  			switch typ.kind {
   104  			case Int:
   105  				var s = uint(sizeof(typ)) * 8
   106  				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
   107  			case Int8:
   108  				const s = 8
   109  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
   110  			case Int16:
   111  				const s = 16
   112  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
   113  			case Int32:
   114  				const s = 32
   115  				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
   116  			case Int64, UntypedInt:
   117  				return true
   118  			case Uint, Uintptr:
   119  				if s := uint(sizeof(typ)) * 8; s < 64 {
   120  					return 0 <= x && x <= int64(1)<<s-1
   121  				}
   122  				return 0 <= x
   123  			case Uint8:
   124  				const s = 8
   125  				return 0 <= x && x <= 1<<s-1
   126  			case Uint16:
   127  				const s = 16
   128  				return 0 <= x && x <= 1<<s-1
   129  			case Uint32:
   130  				const s = 32
   131  				return 0 <= x && x <= 1<<s-1
   132  			case Uint64:
   133  				return 0 <= x
   134  			default:
   135  				panic("unreachable")
   136  			}
   137  		}
   138  		// x does not fit into int64
   139  		switch n := constant.BitLen(x); typ.kind {
   140  		case Uint, Uintptr:
   141  			var s = uint(sizeof(typ)) * 8
   142  			return constant.Sign(x) >= 0 && n <= int(s)
   143  		case Uint64:
   144  			return constant.Sign(x) >= 0 && n <= 64
   145  		case UntypedInt:
   146  			return true
   147  		}
   148  
   149  	case isFloat(typ):
   150  		x := constant.ToFloat(x)
   151  		if x.Kind() != constant.Float {
   152  			return false
   153  		}
   154  		switch typ.kind {
   155  		case Float32:
   156  			if rounded == nil {
   157  				return fitsFloat32(x)
   158  			}
   159  			r := roundFloat32(x)
   160  			if r != nil {
   161  				*rounded = r
   162  				return true
   163  			}
   164  		case Float64:
   165  			if rounded == nil {
   166  				return fitsFloat64(x)
   167  			}
   168  			r := roundFloat64(x)
   169  			if r != nil {
   170  				*rounded = r
   171  				return true
   172  			}
   173  		case UntypedFloat:
   174  			return true
   175  		default:
   176  			panic("unreachable")
   177  		}
   178  
   179  	case isComplex(typ):
   180  		x := constant.ToComplex(x)
   181  		if x.Kind() != constant.Complex {
   182  			return false
   183  		}
   184  		switch typ.kind {
   185  		case Complex64:
   186  			if rounded == nil {
   187  				return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
   188  			}
   189  			re := roundFloat32(constant.Real(x))
   190  			im := roundFloat32(constant.Imag(x))
   191  			if re != nil && im != nil {
   192  				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
   193  				return true
   194  			}
   195  		case Complex128:
   196  			if rounded == nil {
   197  				return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
   198  			}
   199  			re := roundFloat64(constant.Real(x))
   200  			im := roundFloat64(constant.Imag(x))
   201  			if re != nil && im != nil {
   202  				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
   203  				return true
   204  			}
   205  		case UntypedComplex:
   206  			return true
   207  		default:
   208  			panic("unreachable")
   209  		}
   210  
   211  	case isString(typ):
   212  		return x.Kind() == constant.String
   213  
   214  	case isBoolean(typ):
   215  		return x.Kind() == constant.Bool
   216  	}
   217  
   218  	return false
   219  }
   220  
   221  func fitsFloat32(x constant.Value) bool {
   222  	f32, _ := constant.Float32Val(x)
   223  	f := float64(f32)
   224  	return !math.IsInf(f, 0)
   225  }
   226  
   227  func roundFloat32(x constant.Value) constant.Value {
   228  	f32, _ := constant.Float32Val(x)
   229  	f := float64(f32)
   230  	if !math.IsInf(f, 0) {
   231  		return constant.MakeFloat64(f)
   232  	}
   233  	return nil
   234  }
   235  
   236  func fitsFloat64(x constant.Value) bool {
   237  	f, _ := constant.Float64Val(x)
   238  	return !math.IsInf(f, 0)
   239  }
   240  
   241  func roundFloat64(x constant.Value) constant.Value {
   242  	f, _ := constant.Float64Val(x)
   243  	if !math.IsInf(f, 0) {
   244  		return constant.MakeFloat64(f)
   245  	}
   246  	return nil
   247  }
   248  
   249  // representable checks that a constant operand is representable in the given
   250  // basic type.
   251  func (check *Checker) representable(x *operand, typ *Basic) {
   252  	v, code := check.representation(x, typ)
   253  	if code != 0 {
   254  		check.invalidConversion(code, x, typ)
   255  		x.invalidate()
   256  		return
   257  	}
   258  	assert(v != nil)
   259  	x.val = v
   260  }
   261  
   262  // representation returns the representation of the constant operand x as the
   263  // basic type typ.
   264  //
   265  // If no such representation is possible, it returns a non-zero error code.
   266  func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
   267  	assert(x.mode() == constant_)
   268  	v := x.val
   269  	if !representableConst(x.val, check, typ, &v) {
   270  		if isNumeric(x.typ()) && isNumeric(typ) {
   271  			// numeric conversion : error msg
   272  			//
   273  			// integer -> integer : overflows
   274  			// integer -> float   : overflows (actually not possible)
   275  			// float   -> integer : truncated
   276  			// float   -> float   : overflows
   277  			//
   278  			if !isInteger(x.typ()) && isInteger(typ) {
   279  				return nil, TruncatedFloat
   280  			} else {
   281  				return nil, NumericOverflow
   282  			}
   283  		}
   284  		return nil, InvalidConstVal
   285  	}
   286  	return v, 0
   287  }
   288  
   289  func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
   290  	msg := "cannot convert %s to type %s"
   291  	switch code {
   292  	case TruncatedFloat:
   293  		msg = "%s truncated to %s"
   294  	case NumericOverflow:
   295  		msg = "%s overflows %s"
   296  	}
   297  	check.errorf(x, code, msg, x, target)
   298  }
   299  
   300  // convertUntyped attempts to set the type of an untyped value to the target type.
   301  func (check *Checker) convertUntyped(x *operand, target Type) {
   302  	newType, val, code := check.implicitTypeAndValue(x, target)
   303  	if code != 0 {
   304  		t := target
   305  		if !isTypeParam(target) {
   306  			t = safeUnderlying(target)
   307  		}
   308  		check.invalidConversion(code, x, t)
   309  		x.invalidate()
   310  		return
   311  	}
   312  	if val != nil {
   313  		x.val = val
   314  		check.updateExprVal(x.expr, val)
   315  	}
   316  	if newType != x.typ() {
   317  		x.typ_ = newType
   318  		check.updateExprType(x.expr, newType, false)
   319  	}
   320  }
   321  

View as plain text