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

View as plain text