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, 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  

View as plain text