]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: move functions for untyped constants into const.go
authorRobert Griesemer <gri@golang.org>
Mon, 8 May 2023 21:42:19 +0000 (14:42 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 8 May 2023 22:12:00 +0000 (22:12 +0000)
No changes to the moved functions.
Generate const.go for go/types.

Change-Id: I5ac412cecd9f618676a01138aed36428bbce3311
Reviewed-on: https://go-review.googlesource.com/c/go/+/493715
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/const.go [new file with mode: 0644]
src/cmd/compile/internal/types2/expr.go
src/go/types/const.go [new file with mode: 0644]
src/go/types/expr.go
src/go/types/generate_test.go

diff --git a/src/cmd/compile/internal/types2/const.go b/src/cmd/compile/internal/types2/const.go
new file mode 100644 (file)
index 0000000..9be578c
--- /dev/null
@@ -0,0 +1,307 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements functions for untyped constant operands.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "go/constant"
+       "go/token"
+       . "internal/types/errors"
+       "math"
+)
+
+// overflow checks that the constant x is representable by its type.
+// For untyped constants, it checks that the value doesn't become
+// arbitrarily large.
+func (check *Checker) overflow(x *operand, opPos syntax.Pos) {
+       assert(x.mode == constant_)
+
+       if x.val.Kind() == constant.Unknown {
+               // TODO(gri) We should report exactly what went wrong. At the
+               //           moment we don't have the (go/constant) API for that.
+               //           See also TODO in go/constant/value.go.
+               check.error(atPos(opPos), InvalidConstVal, "constant result is not representable")
+               return
+       }
+
+       // Typed constants must be representable in
+       // their type after each constant operation.
+       // x.typ cannot be a type parameter (type
+       // parameters cannot be constant types).
+       if isTyped(x.typ) {
+               check.representable(x, under(x.typ).(*Basic))
+               return
+       }
+
+       // Untyped integer values must not grow arbitrarily.
+       const prec = 512 // 512 is the constant precision
+       if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
+               op := opName(x.expr)
+               if op != "" {
+                       op += " "
+               }
+               check.errorf(atPos(opPos), InvalidConstVal, "constant %soverflow", op)
+               x.val = constant.MakeUnknown()
+       }
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point and complex values, and to an Int
+// value for integer values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+//
+// The check parameter may be nil if representableConst is invoked
+// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
+// because we don't need the Checker's config for those calls.
+func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
+       if x.Kind() == constant.Unknown {
+               return true // avoid follow-up errors
+       }
+
+       var conf *Config
+       if check != nil {
+               conf = check.conf
+       }
+
+       sizeof := func(T Type) int64 {
+               s := conf.sizeof(T)
+               assert(s == 4 || s == 8)
+               return s
+       }
+
+       switch {
+       case isInteger(typ):
+               x := constant.ToInt(x)
+               if x.Kind() != constant.Int {
+                       return false
+               }
+               if rounded != nil {
+                       *rounded = x
+               }
+               if x, ok := constant.Int64Val(x); ok {
+                       switch typ.kind {
+                       case Int:
+                               var s = uint(sizeof(typ)) * 8
+                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+                       case Int8:
+                               const s = 8
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int16:
+                               const s = 16
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int32:
+                               const s = 32
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int64, UntypedInt:
+                               return true
+                       case Uint, Uintptr:
+                               if s := uint(sizeof(typ)) * 8; s < 64 {
+                                       return 0 <= x && x <= int64(1)<<s-1
+                               }
+                               return 0 <= x
+                       case Uint8:
+                               const s = 8
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint16:
+                               const s = 16
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint32:
+                               const s = 32
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint64:
+                               return 0 <= x
+                       default:
+                               unreachable()
+                       }
+               }
+               // x does not fit into int64
+               switch n := constant.BitLen(x); typ.kind {
+               case Uint, Uintptr:
+                       var s = uint(sizeof(typ)) * 8
+                       return constant.Sign(x) >= 0 && n <= int(s)
+               case Uint64:
+                       return constant.Sign(x) >= 0 && n <= 64
+               case UntypedInt:
+                       return true
+               }
+
+       case isFloat(typ):
+               x := constant.ToFloat(x)
+               if x.Kind() != constant.Float {
+                       return false
+               }
+               switch typ.kind {
+               case Float32:
+                       if rounded == nil {
+                               return fitsFloat32(x)
+                       }
+                       r := roundFloat32(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case Float64:
+                       if rounded == nil {
+                               return fitsFloat64(x)
+                       }
+                       r := roundFloat64(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case UntypedFloat:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isComplex(typ):
+               x := constant.ToComplex(x)
+               if x.Kind() != constant.Complex {
+                       return false
+               }
+               switch typ.kind {
+               case Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
+                       }
+                       re := roundFloat32(constant.Real(x))
+                       im := roundFloat32(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
+                       }
+                       re := roundFloat64(constant.Real(x))
+                       im := roundFloat64(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case UntypedComplex:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isString(typ):
+               return x.Kind() == constant.String
+
+       case isBoolean(typ):
+               return x.Kind() == constant.Bool
+       }
+
+       return false
+}
+
+func fitsFloat32(x constant.Value) bool {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x constant.Value) constant.Value {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+func fitsFloat64(x constant.Value) bool {
+       f, _ := constant.Float64Val(x)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x constant.Value) constant.Value {
+       f, _ := constant.Float64Val(x)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+// representable checks that a constant operand is representable in the given
+// basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+       v, code := check.representation(x, typ)
+       if code != 0 {
+               check.invalidConversion(code, x, typ)
+               x.mode = invalid
+               return
+       }
+       assert(v != nil)
+       x.val = v
+}
+
+// representation returns the representation of the constant operand x as the
+// basic type typ.
+//
+// If no such representation is possible, it returns a non-zero error code.
+func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
+       assert(x.mode == constant_)
+       v := x.val
+       if !representableConst(x.val, check, typ, &v) {
+               if isNumeric(x.typ) && isNumeric(typ) {
+                       // numeric conversion : error msg
+                       //
+                       // integer -> integer : overflows
+                       // integer -> float   : overflows (actually not possible)
+                       // float   -> integer : truncated
+                       // float   -> float   : overflows
+                       //
+                       if !isInteger(x.typ) && isInteger(typ) {
+                               return nil, TruncatedFloat
+                       } else {
+                               return nil, NumericOverflow
+                       }
+               }
+               return nil, InvalidConstVal
+       }
+       return v, 0
+}
+
+func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
+       msg := "cannot convert %s to type %s"
+       switch code {
+       case TruncatedFloat:
+               msg = "%s truncated to %s"
+       case NumericOverflow:
+               msg = "%s overflows %s"
+       }
+       check.errorf(x, code, msg, x, target)
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+       newType, val, code := check.implicitTypeAndValue(x, target)
+       if code != 0 {
+               t := target
+               if !isTypeParam(target) {
+                       t = safeUnderlying(target)
+               }
+               check.invalidConversion(code, x, t)
+               x.mode = invalid
+               return
+       }
+       if val != nil {
+               x.val = val
+               check.updateExprVal(x.expr, val)
+       }
+       if newType != x.typ {
+               x.typ = newType
+               check.updateExprType(x.expr, newType, false)
+       }
+}
index 4dc46d4a486f8b94febc30f12acb00d51c4f8097..0f473293bc755c4594676a6187c22d4f5b1b7862 100644 (file)
@@ -12,7 +12,6 @@ import (
        "go/constant"
        "go/token"
        . "internal/types/errors"
-       "math"
 )
 
 /*
@@ -84,41 +83,6 @@ func (check *Checker) op(m opPredicates, x *operand, op syntax.Operator) bool {
        return true
 }
 
-// overflow checks that the constant x is representable by its type.
-// For untyped constants, it checks that the value doesn't become
-// arbitrarily large.
-func (check *Checker) overflow(x *operand, pos syntax.Pos) {
-       assert(x.mode == constant_)
-
-       if x.val.Kind() == constant.Unknown {
-               // TODO(gri) We should report exactly what went wrong. At the
-               //           moment we don't have the (go/constant) API for that.
-               //           See also TODO in go/constant/value.go.
-               check.error(pos, InvalidConstVal, "constant result is not representable")
-               return
-       }
-
-       // Typed constants must be representable in
-       // their type after each constant operation.
-       // x.typ cannot be a type parameter (type
-       // parameters cannot be constant types).
-       if isTyped(x.typ) {
-               check.representable(x, under(x.typ).(*Basic))
-               return
-       }
-
-       // Untyped integer values must not grow arbitrarily.
-       const prec = 512 // 512 is the constant precision
-       if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
-               op := opName(x.expr)
-               if op != "" {
-                       op += " "
-               }
-               check.errorf(pos, InvalidConstVal, "constant %soverflow", op)
-               x.val = constant.MakeUnknown()
-       }
-}
-
 // opPos returns the position of the operator if x is an operation;
 // otherwise it returns the start position of x.
 func opPos(x syntax.Expr) syntax.Pos {
@@ -263,241 +227,6 @@ func isComparison(op syntax.Operator) bool {
        return false
 }
 
-func fitsFloat32(x constant.Value) bool {
-       f32, _ := constant.Float32Val(x)
-       f := float64(f32)
-       return !math.IsInf(f, 0)
-}
-
-func roundFloat32(x constant.Value) constant.Value {
-       f32, _ := constant.Float32Val(x)
-       f := float64(f32)
-       if !math.IsInf(f, 0) {
-               return constant.MakeFloat64(f)
-       }
-       return nil
-}
-
-func fitsFloat64(x constant.Value) bool {
-       f, _ := constant.Float64Val(x)
-       return !math.IsInf(f, 0)
-}
-
-func roundFloat64(x constant.Value) constant.Value {
-       f, _ := constant.Float64Val(x)
-       if !math.IsInf(f, 0) {
-               return constant.MakeFloat64(f)
-       }
-       return nil
-}
-
-// representableConst reports whether x can be represented as
-// value of the given basic type and for the configuration
-// provided (only needed for int/uint sizes).
-//
-// If rounded != nil, *rounded is set to the rounded value of x for
-// representable floating-point and complex values, and to an Int
-// value for integer values; it is left alone otherwise.
-// It is ok to provide the addressof the first argument for rounded.
-//
-// The check parameter may be nil if representableConst is invoked
-// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
-// because we don't need the Checker's config for those calls.
-func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
-       if x.Kind() == constant.Unknown {
-               return true // avoid follow-up errors
-       }
-
-       var conf *Config
-       if check != nil {
-               conf = check.conf
-       }
-
-       sizeof := func(T Type) int64 {
-               s := conf.sizeof(T)
-               assert(s == 4 || s == 8)
-               return s
-       }
-
-       switch {
-       case isInteger(typ):
-               x := constant.ToInt(x)
-               if x.Kind() != constant.Int {
-                       return false
-               }
-               if rounded != nil {
-                       *rounded = x
-               }
-               if x, ok := constant.Int64Val(x); ok {
-                       switch typ.kind {
-                       case Int:
-                               var s = uint(sizeof(typ)) * 8
-                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
-                       case Int8:
-                               const s = 8
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int16:
-                               const s = 16
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int32:
-                               const s = 32
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int64, UntypedInt:
-                               return true
-                       case Uint, Uintptr:
-                               if s := uint(sizeof(typ)) * 8; s < 64 {
-                                       return 0 <= x && x <= int64(1)<<s-1
-                               }
-                               return 0 <= x
-                       case Uint8:
-                               const s = 8
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint16:
-                               const s = 16
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint32:
-                               const s = 32
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint64:
-                               return 0 <= x
-                       default:
-                               unreachable()
-                       }
-               }
-               // x does not fit into int64
-               switch n := constant.BitLen(x); typ.kind {
-               case Uint, Uintptr:
-                       var s = uint(sizeof(typ)) * 8
-                       return constant.Sign(x) >= 0 && n <= int(s)
-               case Uint64:
-                       return constant.Sign(x) >= 0 && n <= 64
-               case UntypedInt:
-                       return true
-               }
-
-       case isFloat(typ):
-               x := constant.ToFloat(x)
-               if x.Kind() != constant.Float {
-                       return false
-               }
-               switch typ.kind {
-               case Float32:
-                       if rounded == nil {
-                               return fitsFloat32(x)
-                       }
-                       r := roundFloat32(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case Float64:
-                       if rounded == nil {
-                               return fitsFloat64(x)
-                       }
-                       r := roundFloat64(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case UntypedFloat:
-                       return true
-               default:
-                       unreachable()
-               }
-
-       case isComplex(typ):
-               x := constant.ToComplex(x)
-               if x.Kind() != constant.Complex {
-                       return false
-               }
-               switch typ.kind {
-               case Complex64:
-                       if rounded == nil {
-                               return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
-                       }
-                       re := roundFloat32(constant.Real(x))
-                       im := roundFloat32(constant.Imag(x))
-                       if re != nil && im != nil {
-                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
-                               return true
-                       }
-               case Complex128:
-                       if rounded == nil {
-                               return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
-                       }
-                       re := roundFloat64(constant.Real(x))
-                       im := roundFloat64(constant.Imag(x))
-                       if re != nil && im != nil {
-                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
-                               return true
-                       }
-               case UntypedComplex:
-                       return true
-               default:
-                       unreachable()
-               }
-
-       case isString(typ):
-               return x.Kind() == constant.String
-
-       case isBoolean(typ):
-               return x.Kind() == constant.Bool
-       }
-
-       return false
-}
-
-// representable checks that a constant operand is representable in the given
-// basic type.
-func (check *Checker) representable(x *operand, typ *Basic) {
-       v, code := check.representation(x, typ)
-       if code != 0 {
-               check.invalidConversion(code, x, typ)
-               x.mode = invalid
-               return
-       }
-       assert(v != nil)
-       x.val = v
-}
-
-// representation returns the representation of the constant operand x as the
-// basic type typ.
-//
-// If no such representation is possible, it returns a non-zero error code.
-func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
-       assert(x.mode == constant_)
-       v := x.val
-       if !representableConst(x.val, check, typ, &v) {
-               if isNumeric(x.typ) && isNumeric(typ) {
-                       // numeric conversion : error msg
-                       //
-                       // integer -> integer : overflows
-                       // integer -> float   : overflows (actually not possible)
-                       // float   -> integer : truncated
-                       // float   -> float   : overflows
-                       //
-                       if !isInteger(x.typ) && isInteger(typ) {
-                               return nil, TruncatedFloat
-                       } else {
-                               return nil, NumericOverflow
-                       }
-               }
-               return nil, InvalidConstVal
-       }
-       return v, 0
-}
-
-func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
-       msg := "cannot convert %s to type %s"
-       switch code {
-       case TruncatedFloat:
-               msg = "%s truncated to %s"
-       case NumericOverflow:
-               msg = "%s overflows %s"
-       }
-       check.errorf(x, code, msg, x, target)
-}
-
 // updateExprType updates the type of x to typ and invokes itself
 // recursively for the operands of x, depending on expression kind.
 // If typ is still an untyped and not the final type, updateExprType
@@ -656,28 +385,6 @@ func (check *Checker) updateExprVal(x syntax.Expr, val constant.Value) {
        }
 }
 
-// convertUntyped attempts to set the type of an untyped value to the target type.
-func (check *Checker) convertUntyped(x *operand, target Type) {
-       newType, val, code := check.implicitTypeAndValue(x, target)
-       if code != 0 {
-               t := target
-               if !isTypeParam(target) {
-                       t = safeUnderlying(target)
-               }
-               check.invalidConversion(code, x, t)
-               x.mode = invalid
-               return
-       }
-       if val != nil {
-               x.val = val
-               check.updateExprVal(x.expr, val)
-       }
-       if newType != x.typ {
-               x.typ = newType
-               check.updateExprType(x.expr, newType, false)
-       }
-}
-
 // implicitTypeAndValue returns the implicit type of x when used in a context
 // where the target type is expected. If no such implicit conversion is
 // possible, it returns a nil Type and non-zero error code.
diff --git a/src/go/types/const.go b/src/go/types/const.go
new file mode 100644 (file)
index 0000000..66fa608
--- /dev/null
@@ -0,0 +1,308 @@
+// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements functions for untyped constant operands.
+
+package types
+
+import (
+       "go/constant"
+       "go/token"
+       . "internal/types/errors"
+       "math"
+)
+
+// overflow checks that the constant x is representable by its type.
+// For untyped constants, it checks that the value doesn't become
+// arbitrarily large.
+func (check *Checker) overflow(x *operand, opPos token.Pos) {
+       assert(x.mode == constant_)
+
+       if x.val.Kind() == constant.Unknown {
+               // TODO(gri) We should report exactly what went wrong. At the
+               //           moment we don't have the (go/constant) API for that.
+               //           See also TODO in go/constant/value.go.
+               check.error(atPos(opPos), InvalidConstVal, "constant result is not representable")
+               return
+       }
+
+       // Typed constants must be representable in
+       // their type after each constant operation.
+       // x.typ cannot be a type parameter (type
+       // parameters cannot be constant types).
+       if isTyped(x.typ) {
+               check.representable(x, under(x.typ).(*Basic))
+               return
+       }
+
+       // Untyped integer values must not grow arbitrarily.
+       const prec = 512 // 512 is the constant precision
+       if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
+               op := opName(x.expr)
+               if op != "" {
+                       op += " "
+               }
+               check.errorf(atPos(opPos), InvalidConstVal, "constant %soverflow", op)
+               x.val = constant.MakeUnknown()
+       }
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point and complex values, and to an Int
+// value for integer values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+//
+// The check parameter may be nil if representableConst is invoked
+// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
+// because we don't need the Checker's config for those calls.
+func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
+       if x.Kind() == constant.Unknown {
+               return true // avoid follow-up errors
+       }
+
+       var conf *Config
+       if check != nil {
+               conf = check.conf
+       }
+
+       sizeof := func(T Type) int64 {
+               s := conf.sizeof(T)
+               assert(s == 4 || s == 8)
+               return s
+       }
+
+       switch {
+       case isInteger(typ):
+               x := constant.ToInt(x)
+               if x.Kind() != constant.Int {
+                       return false
+               }
+               if rounded != nil {
+                       *rounded = x
+               }
+               if x, ok := constant.Int64Val(x); ok {
+                       switch typ.kind {
+                       case Int:
+                               var s = uint(sizeof(typ)) * 8
+                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+                       case Int8:
+                               const s = 8
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int16:
+                               const s = 16
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int32:
+                               const s = 32
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int64, UntypedInt:
+                               return true
+                       case Uint, Uintptr:
+                               if s := uint(sizeof(typ)) * 8; s < 64 {
+                                       return 0 <= x && x <= int64(1)<<s-1
+                               }
+                               return 0 <= x
+                       case Uint8:
+                               const s = 8
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint16:
+                               const s = 16
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint32:
+                               const s = 32
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint64:
+                               return 0 <= x
+                       default:
+                               unreachable()
+                       }
+               }
+               // x does not fit into int64
+               switch n := constant.BitLen(x); typ.kind {
+               case Uint, Uintptr:
+                       var s = uint(sizeof(typ)) * 8
+                       return constant.Sign(x) >= 0 && n <= int(s)
+               case Uint64:
+                       return constant.Sign(x) >= 0 && n <= 64
+               case UntypedInt:
+                       return true
+               }
+
+       case isFloat(typ):
+               x := constant.ToFloat(x)
+               if x.Kind() != constant.Float {
+                       return false
+               }
+               switch typ.kind {
+               case Float32:
+                       if rounded == nil {
+                               return fitsFloat32(x)
+                       }
+                       r := roundFloat32(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case Float64:
+                       if rounded == nil {
+                               return fitsFloat64(x)
+                       }
+                       r := roundFloat64(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case UntypedFloat:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isComplex(typ):
+               x := constant.ToComplex(x)
+               if x.Kind() != constant.Complex {
+                       return false
+               }
+               switch typ.kind {
+               case Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
+                       }
+                       re := roundFloat32(constant.Real(x))
+                       im := roundFloat32(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
+                       }
+                       re := roundFloat64(constant.Real(x))
+                       im := roundFloat64(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case UntypedComplex:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isString(typ):
+               return x.Kind() == constant.String
+
+       case isBoolean(typ):
+               return x.Kind() == constant.Bool
+       }
+
+       return false
+}
+
+func fitsFloat32(x constant.Value) bool {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x constant.Value) constant.Value {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+func fitsFloat64(x constant.Value) bool {
+       f, _ := constant.Float64Val(x)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x constant.Value) constant.Value {
+       f, _ := constant.Float64Val(x)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+// representable checks that a constant operand is representable in the given
+// basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+       v, code := check.representation(x, typ)
+       if code != 0 {
+               check.invalidConversion(code, x, typ)
+               x.mode = invalid
+               return
+       }
+       assert(v != nil)
+       x.val = v
+}
+
+// representation returns the representation of the constant operand x as the
+// basic type typ.
+//
+// If no such representation is possible, it returns a non-zero error code.
+func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
+       assert(x.mode == constant_)
+       v := x.val
+       if !representableConst(x.val, check, typ, &v) {
+               if isNumeric(x.typ) && isNumeric(typ) {
+                       // numeric conversion : error msg
+                       //
+                       // integer -> integer : overflows
+                       // integer -> float   : overflows (actually not possible)
+                       // float   -> integer : truncated
+                       // float   -> float   : overflows
+                       //
+                       if !isInteger(x.typ) && isInteger(typ) {
+                               return nil, TruncatedFloat
+                       } else {
+                               return nil, NumericOverflow
+                       }
+               }
+               return nil, InvalidConstVal
+       }
+       return v, 0
+}
+
+func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
+       msg := "cannot convert %s to type %s"
+       switch code {
+       case TruncatedFloat:
+               msg = "%s truncated to %s"
+       case NumericOverflow:
+               msg = "%s overflows %s"
+       }
+       check.errorf(x, code, msg, x, target)
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+       newType, val, code := check.implicitTypeAndValue(x, target)
+       if code != 0 {
+               t := target
+               if !isTypeParam(target) {
+                       t = safeUnderlying(target)
+               }
+               check.invalidConversion(code, x, t)
+               x.mode = invalid
+               return
+       }
+       if val != nil {
+               x.val = val
+               check.updateExprVal(x.expr, val)
+       }
+       if newType != x.typ {
+               x.typ = newType
+               check.updateExprType(x.expr, newType, false)
+       }
+}
index 59f0b7481a5ec9d06265c6201d5f8c7793423b42..b0e1422b0161ac3776b7156ed8992b97180b75f7 100644 (file)
@@ -13,7 +13,6 @@ import (
        "go/internal/typeparams"
        "go/token"
        . "internal/types/errors"
-       "math"
 )
 
 /*
@@ -85,41 +84,6 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
        return true
 }
 
-// overflow checks that the constant x is representable by its type.
-// For untyped constants, it checks that the value doesn't become
-// arbitrarily large.
-func (check *Checker) overflow(x *operand, opPos token.Pos) {
-       assert(x.mode == constant_)
-
-       if x.val.Kind() == constant.Unknown {
-               // TODO(gri) We should report exactly what went wrong. At the
-               //           moment we don't have the (go/constant) API for that.
-               //           See also TODO in go/constant/value.go.
-               check.error(atPos(opPos), InvalidConstVal, "constant result is not representable")
-               return
-       }
-
-       // Typed constants must be representable in
-       // their type after each constant operation.
-       // x.typ cannot be a type parameter (type
-       // parameters cannot be constant types).
-       if isTyped(x.typ) {
-               check.representable(x, under(x.typ).(*Basic))
-               return
-       }
-
-       // Untyped integer values must not grow arbitrarily.
-       const prec = 512 // 512 is the constant precision
-       if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
-               op := opName(x.expr)
-               if op != "" {
-                       op += " "
-               }
-               check.errorf(atPos(opPos), InvalidConstVal, "constant %soverflow", op)
-               x.val = constant.MakeUnknown()
-       }
-}
-
 // opName returns the name of the operation if x is an operation
 // that might overflow; otherwise it returns the empty string.
 func opName(e ast.Expr) string {
@@ -251,241 +215,6 @@ func isComparison(op token.Token) bool {
        return false
 }
 
-func fitsFloat32(x constant.Value) bool {
-       f32, _ := constant.Float32Val(x)
-       f := float64(f32)
-       return !math.IsInf(f, 0)
-}
-
-func roundFloat32(x constant.Value) constant.Value {
-       f32, _ := constant.Float32Val(x)
-       f := float64(f32)
-       if !math.IsInf(f, 0) {
-               return constant.MakeFloat64(f)
-       }
-       return nil
-}
-
-func fitsFloat64(x constant.Value) bool {
-       f, _ := constant.Float64Val(x)
-       return !math.IsInf(f, 0)
-}
-
-func roundFloat64(x constant.Value) constant.Value {
-       f, _ := constant.Float64Val(x)
-       if !math.IsInf(f, 0) {
-               return constant.MakeFloat64(f)
-       }
-       return nil
-}
-
-// representableConst reports whether x can be represented as
-// value of the given basic type and for the configuration
-// provided (only needed for int/uint sizes).
-//
-// If rounded != nil, *rounded is set to the rounded value of x for
-// representable floating-point and complex values, and to an Int
-// value for integer values; it is left alone otherwise.
-// It is ok to provide the addressof the first argument for rounded.
-//
-// The check parameter may be nil if representableConst is invoked
-// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
-// because we don't need the Checker's config for those calls.
-func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
-       if x.Kind() == constant.Unknown {
-               return true // avoid follow-up errors
-       }
-
-       var conf *Config
-       if check != nil {
-               conf = check.conf
-       }
-
-       sizeof := func(T Type) int64 {
-               s := conf.sizeof(T)
-               assert(s == 4 || s == 8)
-               return s
-       }
-
-       switch {
-       case isInteger(typ):
-               x := constant.ToInt(x)
-               if x.Kind() != constant.Int {
-                       return false
-               }
-               if rounded != nil {
-                       *rounded = x
-               }
-               if x, ok := constant.Int64Val(x); ok {
-                       switch typ.kind {
-                       case Int:
-                               var s = uint(sizeof(typ)) * 8
-                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
-                       case Int8:
-                               const s = 8
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int16:
-                               const s = 16
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int32:
-                               const s = 32
-                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
-                       case Int64, UntypedInt:
-                               return true
-                       case Uint, Uintptr:
-                               if s := uint(sizeof(typ)) * 8; s < 64 {
-                                       return 0 <= x && x <= int64(1)<<s-1
-                               }
-                               return 0 <= x
-                       case Uint8:
-                               const s = 8
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint16:
-                               const s = 16
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint32:
-                               const s = 32
-                               return 0 <= x && x <= 1<<s-1
-                       case Uint64:
-                               return 0 <= x
-                       default:
-                               unreachable()
-                       }
-               }
-               // x does not fit into int64
-               switch n := constant.BitLen(x); typ.kind {
-               case Uint, Uintptr:
-                       var s = uint(sizeof(typ)) * 8
-                       return constant.Sign(x) >= 0 && n <= int(s)
-               case Uint64:
-                       return constant.Sign(x) >= 0 && n <= 64
-               case UntypedInt:
-                       return true
-               }
-
-       case isFloat(typ):
-               x := constant.ToFloat(x)
-               if x.Kind() != constant.Float {
-                       return false
-               }
-               switch typ.kind {
-               case Float32:
-                       if rounded == nil {
-                               return fitsFloat32(x)
-                       }
-                       r := roundFloat32(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case Float64:
-                       if rounded == nil {
-                               return fitsFloat64(x)
-                       }
-                       r := roundFloat64(x)
-                       if r != nil {
-                               *rounded = r
-                               return true
-                       }
-               case UntypedFloat:
-                       return true
-               default:
-                       unreachable()
-               }
-
-       case isComplex(typ):
-               x := constant.ToComplex(x)
-               if x.Kind() != constant.Complex {
-                       return false
-               }
-               switch typ.kind {
-               case Complex64:
-                       if rounded == nil {
-                               return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
-                       }
-                       re := roundFloat32(constant.Real(x))
-                       im := roundFloat32(constant.Imag(x))
-                       if re != nil && im != nil {
-                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
-                               return true
-                       }
-               case Complex128:
-                       if rounded == nil {
-                               return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
-                       }
-                       re := roundFloat64(constant.Real(x))
-                       im := roundFloat64(constant.Imag(x))
-                       if re != nil && im != nil {
-                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
-                               return true
-                       }
-               case UntypedComplex:
-                       return true
-               default:
-                       unreachable()
-               }
-
-       case isString(typ):
-               return x.Kind() == constant.String
-
-       case isBoolean(typ):
-               return x.Kind() == constant.Bool
-       }
-
-       return false
-}
-
-// representable checks that a constant operand is representable in the given
-// basic type.
-func (check *Checker) representable(x *operand, typ *Basic) {
-       v, code := check.representation(x, typ)
-       if code != 0 {
-               check.invalidConversion(code, x, typ)
-               x.mode = invalid
-               return
-       }
-       assert(v != nil)
-       x.val = v
-}
-
-// representation returns the representation of the constant operand x as the
-// basic type typ.
-//
-// If no such representation is possible, it returns a non-zero error code.
-func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
-       assert(x.mode == constant_)
-       v := x.val
-       if !representableConst(x.val, check, typ, &v) {
-               if isNumeric(x.typ) && isNumeric(typ) {
-                       // numeric conversion : error msg
-                       //
-                       // integer -> integer : overflows
-                       // integer -> float   : overflows (actually not possible)
-                       // float   -> integer : truncated
-                       // float   -> float   : overflows
-                       //
-                       if !isInteger(x.typ) && isInteger(typ) {
-                               return nil, TruncatedFloat
-                       } else {
-                               return nil, NumericOverflow
-                       }
-               }
-               return nil, InvalidConstVal
-       }
-       return v, 0
-}
-
-func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
-       msg := "cannot convert %s to type %s"
-       switch code {
-       case TruncatedFloat:
-               msg = "%s truncated to %s"
-       case NumericOverflow:
-               msg = "%s overflows %s"
-       }
-       check.errorf(x, code, msg, x, target)
-}
-
 // updateExprType updates the type of x to typ and invokes itself
 // recursively for the operands of x, depending on expression kind.
 // If typ is still an untyped and not the final type, updateExprType
@@ -620,28 +349,6 @@ func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
        }
 }
 
-// convertUntyped attempts to set the type of an untyped value to the target type.
-func (check *Checker) convertUntyped(x *operand, target Type) {
-       newType, val, code := check.implicitTypeAndValue(x, target)
-       if code != 0 {
-               t := target
-               if !isTypeParam(target) {
-                       t = safeUnderlying(target)
-               }
-               check.invalidConversion(code, x, t)
-               x.mode = invalid
-               return
-       }
-       if val != nil {
-               x.val = val
-               check.updateExprVal(x.expr, val)
-       }
-       if newType != x.typ {
-               x.typ = newType
-               check.updateExprType(x.expr, newType, false)
-       }
-}
-
 // implicitTypeAndValue returns the implicit type of x when used in a context
 // where the target type is expected. If no such implicit conversion is
 // possible, it returns a nil Type and non-zero error code.
index 939fdb38f4b2fba3fb2ba7add7a4e0ef02dacbb3..c5e114aaec97610bbf8159b20e7f4c2386e23f18 100644 (file)
@@ -98,6 +98,7 @@ var filemap = map[string]action{
        "array.go":        nil,
        "basic.go":        nil,
        "chan.go":         nil,
+       "const.go":        func(f *ast.File) { fixTokenPos(f) },
        "context.go":      nil,
        "context_test.go": nil,
        "gccgosizes.go":   nil,