Source file src/go/types/const.go

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

View as plain text