go.tools/go/types: do rounding in constant numeric conversions
- cleaned up surrounding code - adjusted error message positions for too few/many argument errors - added more conversion tests - added all tests under test/ken to std tests R=adonovan, r TBR=adonovan CC=golang-dev https://golang.org/cl/12711043
This commit is contained in:
parent
508ae115ae
commit
d13d94afe7
|
@ -173,7 +173,6 @@ func IsAssignableTo(V, T Type) bool {
|
||||||
return x.isAssignableTo(nil, T) // config not needed for non-constant x
|
return x.isAssignableTo(nil, T) // config not needed for non-constant x
|
||||||
}
|
}
|
||||||
|
|
||||||
// BUG(gri): Conversions of constants only change the type, not the value (e.g., int(1.1) is wrong).
|
|
||||||
// BUG(gri): Some built-ins don't check parameters fully, yet (e.g. append).
|
// BUG(gri): Some built-ins don't check parameters fully, yet (e.g. append).
|
||||||
// BUG(gri): Use of labels is only partially checked.
|
// BUG(gri): Use of labels is only partially checked.
|
||||||
// BUG(gri): Unused variables and imports are not reported.
|
// BUG(gri): Unused variables and imports are not reported.
|
||||||
|
|
|
@ -26,13 +26,29 @@ func (check *checker) call(x *operand, e *ast.CallExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if x.mode == typexpr {
|
if x.mode == typexpr {
|
||||||
check.conversion(x, e, x.typ)
|
// conversion
|
||||||
|
T := x.typ
|
||||||
|
x.mode = invalid
|
||||||
|
switch n := len(e.Args); n {
|
||||||
|
case 0:
|
||||||
|
check.errorf(e.Rparen, "missing argument in conversion to %s", T)
|
||||||
|
case 1:
|
||||||
|
check.expr(x, e.Args[0])
|
||||||
|
if x.mode != invalid {
|
||||||
|
check.conversion(x, T)
|
||||||
|
if x.mode != invalid {
|
||||||
|
check.conversions[e] = true // for cap/len checking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
|
||||||
|
}
|
||||||
|
x.expr = e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if sig, ok := x.typ.Underlying().(*Signature); ok {
|
if sig, ok := x.typ.Underlying().(*Signature); ok {
|
||||||
// function/method call
|
// function/method call
|
||||||
|
|
||||||
passSlice := false
|
passSlice := false
|
||||||
if e.Ellipsis.IsValid() {
|
if e.Ellipsis.IsValid() {
|
||||||
// last argument is of the form x...
|
// last argument is of the form x...
|
||||||
|
@ -84,7 +100,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr) {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
if n < sig.params.Len() {
|
if n < sig.params.Len() {
|
||||||
check.errorf(e.Fun.Pos(), "too few arguments in call to %s", e.Fun)
|
check.errorf(e.Rparen, "too few arguments in call to %s", e.Fun)
|
||||||
// ok to continue
|
// ok to continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,41 +6,18 @@
|
||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import "code.google.com/p/go.tools/go/exact"
|
||||||
"go/ast"
|
|
||||||
|
|
||||||
"code.google.com/p/go.tools/go/exact"
|
// Conversion type-checks the conversion T(x).
|
||||||
)
|
// The result is in x.
|
||||||
|
func (check *checker) conversion(x *operand, T Type) {
|
||||||
// conversion typechecks the type conversion conv to type typ.
|
|
||||||
// The result of the conversion is returned via x.
|
|
||||||
// If the conversion has type errors, the returned
|
|
||||||
// x is marked as invalid (x.mode == invalid).
|
|
||||||
//
|
|
||||||
func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
|
|
||||||
var final Type // declare before gotos
|
|
||||||
|
|
||||||
// all conversions have one argument
|
|
||||||
if len(conv.Args) != 1 {
|
|
||||||
check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
|
|
||||||
goto Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate argument
|
|
||||||
check.expr(x, conv.Args[0])
|
|
||||||
if x.mode == invalid {
|
|
||||||
goto Error
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.mode == constant && isConstType(typ) {
|
|
||||||
// constant conversion
|
|
||||||
typ := typ.Underlying().(*Basic)
|
|
||||||
// For now just implement string(x) where x is an integer,
|
|
||||||
// as a temporary work-around for issue 4982, which is a
|
|
||||||
// common issue.
|
|
||||||
if typ.kind == String {
|
|
||||||
switch {
|
switch {
|
||||||
case x.isInteger():
|
case x.mode == constant && isConstType(T):
|
||||||
|
// constant conversion
|
||||||
|
switch t := T.Underlying().(*Basic); {
|
||||||
|
case isRepresentableConst(x.val, check.conf, t.kind, &x.val):
|
||||||
|
// nothing to do
|
||||||
|
case x.isInteger() && isString(t):
|
||||||
codepoint := int64(-1)
|
codepoint := int64(-1)
|
||||||
if i, ok := exact.Int64Val(x.val); ok {
|
if i, ok := exact.Int64Val(x.val); ok {
|
||||||
codepoint = i
|
codepoint = i
|
||||||
|
@ -49,46 +26,37 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
|
||||||
// conversion. This is the same as converting any other out-of-range
|
// conversion. This is the same as converting any other out-of-range
|
||||||
// value - let string(codepoint) do the work.
|
// value - let string(codepoint) do the work.
|
||||||
x.val = exact.MakeString(string(codepoint))
|
x.val = exact.MakeString(string(codepoint))
|
||||||
case isString(x.typ):
|
|
||||||
// nothing to do
|
|
||||||
default:
|
default:
|
||||||
goto ErrorMsg
|
x.mode = invalid
|
||||||
}
|
}
|
||||||
}
|
case x.isConvertible(check.conf, T):
|
||||||
// TODO(gri) verify the remaining conversions.
|
|
||||||
} else {
|
|
||||||
// non-constant conversion
|
// non-constant conversion
|
||||||
if !x.isConvertible(check.conf, typ) {
|
|
||||||
goto ErrorMsg
|
|
||||||
}
|
|
||||||
x.mode = value
|
x.mode = value
|
||||||
|
default:
|
||||||
|
x.mode = invalid
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.mode == invalid {
|
||||||
|
check.errorf(x.pos(), "cannot convert %s to %s", x, T)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// The conversion argument types are final. For untyped values the
|
// The conversion argument types are final. For untyped values the
|
||||||
// conversion provides the type, per the spec: "A constant may be
|
// conversion provides the type, per the spec: "A constant may be
|
||||||
// given a type explicitly by a constant declaration or conversion,...".
|
// given a type explicitly by a constant declaration or conversion,...".
|
||||||
final = x.typ
|
final := x.typ
|
||||||
if isUntyped(final) {
|
if isUntyped(final) {
|
||||||
final = typ
|
final = T
|
||||||
// For conversions to interfaces, use the argument type's
|
// For conversions to interfaces, use the argument type's
|
||||||
// default type instead. Keep untyped nil for untyped nil
|
// default type instead. Keep untyped nil for untyped nil
|
||||||
// arguments.
|
// arguments.
|
||||||
if _, ok := typ.Underlying().(*Interface); ok {
|
if _, ok := T.Underlying().(*Interface); ok {
|
||||||
final = defaultType(x.typ)
|
final = defaultType(x.typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x.typ = T
|
||||||
check.updateExprType(x.expr, final, true)
|
check.updateExprType(x.expr, final, true)
|
||||||
|
|
||||||
check.conversions[conv] = true // for cap/len checking
|
|
||||||
x.expr = conv
|
|
||||||
x.typ = typ
|
|
||||||
return
|
|
||||||
|
|
||||||
ErrorMsg:
|
|
||||||
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
|
|
||||||
Error:
|
|
||||||
x.mode = invalid
|
|
||||||
x.expr = conv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *operand) isConvertible(conf *Config, T Type) bool {
|
func (x *operand) isConvertible(conf *Config, T Type) bool {
|
||||||
|
|
|
@ -158,18 +158,46 @@ func isComparison(op token.Token) bool {
|
||||||
|
|
||||||
func fitsFloat32(x exact.Value) bool {
|
func fitsFloat32(x exact.Value) bool {
|
||||||
f, _ := exact.Float64Val(x)
|
f, _ := exact.Float64Val(x)
|
||||||
// We assume that float32(f) returns an Inf if f
|
// spec: "In all non-constant conversions involving floating-point
|
||||||
// cannot be represented as a float32, or if f
|
// or complex values, if the result type cannot represent the value
|
||||||
// is an Inf. This is not supported by the spec.
|
// the conversion succeeds but the result value is implementation-
|
||||||
|
// dependent."
|
||||||
|
//
|
||||||
|
// We assume that float32(f) returns an Inf if f cannot be represented
|
||||||
|
// as a float32, or if f is an Inf.
|
||||||
return !math.IsInf(float64(float32(f)), 0)
|
return !math.IsInf(float64(float32(f)), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func roundFloat32(x exact.Value) exact.Value {
|
||||||
|
f, _ := exact.Float64Val(x)
|
||||||
|
f = float64(float32(f))
|
||||||
|
if !math.IsInf(f, 0) {
|
||||||
|
return exact.MakeFloat64(f)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func fitsFloat64(x exact.Value) bool {
|
func fitsFloat64(x exact.Value) bool {
|
||||||
f, _ := exact.Float64Val(x)
|
f, _ := exact.Float64Val(x)
|
||||||
return !math.IsInf(f, 0)
|
return !math.IsInf(f, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool {
|
func roundFloat64(x exact.Value) exact.Value {
|
||||||
|
f, _ := exact.Float64Val(x)
|
||||||
|
if !math.IsInf(f, 0) {
|
||||||
|
return exact.MakeFloat64(f)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isRepresentableConst reports whether x can be represented as
|
||||||
|
// value of the given basic type kind 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 values; it is left alone otherwise.
|
||||||
|
// It is ok to provide the addressof the first argument for rounded.
|
||||||
|
func isRepresentableConst(x exact.Value, conf *Config, as BasicKind, rounded *exact.Value) bool {
|
||||||
switch x.Kind() {
|
switch x.Kind() {
|
||||||
case exact.Unknown:
|
case exact.Unknown:
|
||||||
return true
|
return true
|
||||||
|
@ -224,9 +252,23 @@ func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool {
|
||||||
case Uint64:
|
case Uint64:
|
||||||
return exact.Sign(x) >= 0 && n <= 64
|
return exact.Sign(x) >= 0 && n <= 64
|
||||||
case Float32, Complex64:
|
case Float32, Complex64:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat32(x)
|
return fitsFloat32(x)
|
||||||
|
}
|
||||||
|
r := roundFloat32(x)
|
||||||
|
if r != nil {
|
||||||
|
*rounded = r
|
||||||
|
return true
|
||||||
|
}
|
||||||
case Float64, Complex128:
|
case Float64, Complex128:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat64(x)
|
return fitsFloat64(x)
|
||||||
|
}
|
||||||
|
r := roundFloat64(x)
|
||||||
|
if r != nil {
|
||||||
|
*rounded = r
|
||||||
|
return true
|
||||||
|
}
|
||||||
case UntypedInt, UntypedFloat, UntypedComplex:
|
case UntypedInt, UntypedFloat, UntypedComplex:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -234,9 +276,23 @@ func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool {
|
||||||
case exact.Float:
|
case exact.Float:
|
||||||
switch as {
|
switch as {
|
||||||
case Float32, Complex64:
|
case Float32, Complex64:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat32(x)
|
return fitsFloat32(x)
|
||||||
|
}
|
||||||
|
r := roundFloat32(x)
|
||||||
|
if r != nil {
|
||||||
|
*rounded = r
|
||||||
|
return true
|
||||||
|
}
|
||||||
case Float64, Complex128:
|
case Float64, Complex128:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat64(x)
|
return fitsFloat64(x)
|
||||||
|
}
|
||||||
|
r := roundFloat64(x)
|
||||||
|
if r != nil {
|
||||||
|
*rounded = r
|
||||||
|
return true
|
||||||
|
}
|
||||||
case UntypedFloat, UntypedComplex:
|
case UntypedFloat, UntypedComplex:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -244,9 +300,25 @@ func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool {
|
||||||
case exact.Complex:
|
case exact.Complex:
|
||||||
switch as {
|
switch as {
|
||||||
case Complex64:
|
case Complex64:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x))
|
return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x))
|
||||||
|
}
|
||||||
|
re := roundFloat32(exact.Real(x))
|
||||||
|
im := roundFloat32(exact.Imag(x))
|
||||||
|
if re != nil && im != nil {
|
||||||
|
*rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
|
||||||
|
return true
|
||||||
|
}
|
||||||
case Complex128:
|
case Complex128:
|
||||||
|
if rounded == nil {
|
||||||
return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x))
|
return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x))
|
||||||
|
}
|
||||||
|
re := roundFloat64(exact.Real(x))
|
||||||
|
im := roundFloat64(exact.Imag(x))
|
||||||
|
if re != nil && im != nil {
|
||||||
|
*rounded = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
|
||||||
|
return true
|
||||||
|
}
|
||||||
case UntypedComplex:
|
case UntypedComplex:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -270,7 +342,7 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isRepresentableConst(x.val, check.conf, typ.kind) {
|
if !isRepresentableConst(x.val, check.conf, typ.kind, &x.val) {
|
||||||
var msg string
|
var msg string
|
||||||
if isNumeric(x.typ) && isNumeric(typ) {
|
if isNumeric(x.typ) && isNumeric(typ) {
|
||||||
msg = "%s overflows (or cannot be accurately represented as) %s"
|
msg = "%s overflows (or cannot be accurately represented as) %s"
|
||||||
|
@ -512,7 +584,7 @@ func (check *checker) shift(x, y *operand, op token.Token) {
|
||||||
|
|
||||||
// The lhs must be of integer type or be representable
|
// The lhs must be of integer type or be representable
|
||||||
// as an integer; otherwise the shift has no chance.
|
// as an integer; otherwise the shift has no chance.
|
||||||
if !isInteger(x.typ) && (!untypedx || !isRepresentableConst(x.val, nil, UntypedInt)) {
|
if !isInteger(x.typ) && (!untypedx || !isRepresentableConst(x.val, nil, UntypedInt, nil)) {
|
||||||
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
|
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
return
|
return
|
||||||
|
|
|
@ -184,7 +184,7 @@ func (x *operand) isAssignableTo(conf *Config, T Type) bool {
|
||||||
switch t := Tu.(type) {
|
switch t := Tu.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if x.mode == constant {
|
if x.mode == constant {
|
||||||
return isRepresentableConst(x.val, conf, t.kind)
|
return isRepresentableConst(x.val, conf, t.kind, nil)
|
||||||
}
|
}
|
||||||
// The result of a comparison is an untyped boolean,
|
// The result of a comparison is an untyped boolean,
|
||||||
// but may not be a constant.
|
// but may not be a constant.
|
||||||
|
@ -205,5 +205,5 @@ func (x *operand) isAssignableTo(conf *Config, T Type) bool {
|
||||||
func (x *operand) isInteger() bool {
|
func (x *operand) isInteger() bool {
|
||||||
return x.mode == invalid ||
|
return x.mode == invalid ||
|
||||||
isInteger(x.typ) ||
|
isInteger(x.typ) ||
|
||||||
x.mode == constant && isRepresentableConst(x.val, nil, UntypedInt) // no *Config required for UntypedInt
|
x.mode == constant && isRepresentableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,9 +105,10 @@ func TestStdtest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStdfixed(t *testing.T) {
|
func TestStdfixed(t *testing.T) {
|
||||||
testTestDir(t, filepath.Join(runtime.GOROOT(), "test/fixedbugs"),
|
testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
|
||||||
"bug050.go", "bug088.go", "bug106.go", // TODO(gri) parser loses comments when bailing out early
|
"bug050.go", "bug088.go", "bug106.go", // TODO(gri) parser loses comments when bailing out early
|
||||||
"bug222.go", "bug282.go", "bug306.go", // TODO(gri) parser loses comments when bailing out early
|
"bug222.go", "bug282.go", "bug306.go", // TODO(gri) parser loses comments when bailing out early
|
||||||
|
"issue4776.go", // TODO(gri) parser loses comments when bailing out early
|
||||||
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
|
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
|
||||||
"bug251.go", // TODO(gri) incorrect cycle checks for interface types
|
"bug251.go", // TODO(gri) incorrect cycle checks for interface types
|
||||||
"bug165.go", // TODO(gri) isComparable not working for incomplete struct type
|
"bug165.go", // TODO(gri) isComparable not working for incomplete struct type
|
||||||
|
@ -123,6 +124,10 @@ func TestStdfixed(t *testing.T) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStdken(t *testing.T) {
|
||||||
|
testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
|
||||||
|
}
|
||||||
|
|
||||||
// Package paths of excluded packages.
|
// Package paths of excluded packages.
|
||||||
var excluded = map[string]bool{
|
var excluded = map[string]bool{
|
||||||
"builtin": true,
|
"builtin": true,
|
||||||
|
|
|
@ -56,138 +56,249 @@ const (
|
||||||
maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
|
maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ int8 = minInt8 /* ERROR "overflows" */ - 1
|
_ int8 = minInt8 /* ERROR "overflows" */ - 1
|
||||||
_ int8 = minInt8
|
_ int8 = minInt8
|
||||||
_ int8 = maxInt8
|
_ int8 = maxInt8
|
||||||
_ int8 = maxInt8 /* ERROR "overflows" */ + 1
|
_ int8 = maxInt8 /* ERROR "overflows" */ + 1
|
||||||
_ int8 = smallestFloat64 /* ERROR "overflows" */
|
_ int8 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = int8(minInt8)
|
||||||
|
_ = int8(maxInt8)
|
||||||
|
_ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = int8(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ int16 = minInt16 /* ERROR "overflows" */ - 1
|
_ int16 = minInt16 /* ERROR "overflows" */ - 1
|
||||||
_ int16 = minInt16
|
_ int16 = minInt16
|
||||||
_ int16 = maxInt16
|
_ int16 = maxInt16
|
||||||
_ int16 = maxInt16 /* ERROR "overflows" */ + 1
|
_ int16 = maxInt16 /* ERROR "overflows" */ + 1
|
||||||
_ int16 = smallestFloat64 /* ERROR "overflows" */
|
_ int16 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = int16(minInt16)
|
||||||
|
_ = int16(maxInt16)
|
||||||
|
_ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = int16(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ int32 = minInt32 /* ERROR "overflows" */ - 1
|
_ int32 = minInt32 /* ERROR "overflows" */ - 1
|
||||||
_ int32 = minInt32
|
_ int32 = minInt32
|
||||||
_ int32 = maxInt32
|
_ int32 = maxInt32
|
||||||
_ int32 = maxInt32 /* ERROR "overflows" */ + 1
|
_ int32 = maxInt32 /* ERROR "overflows" */ + 1
|
||||||
_ int32 = smallestFloat64 /* ERROR "overflows" */
|
_ int32 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = int32(minInt32)
|
||||||
|
_ = int32(maxInt32)
|
||||||
|
_ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = int32(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ int64 = minInt64 /* ERROR "overflows" */ - 1
|
_ int64 = minInt64 /* ERROR "overflows" */ - 1
|
||||||
_ int64 = minInt64
|
_ int64 = minInt64
|
||||||
_ int64 = maxInt64
|
_ int64 = maxInt64
|
||||||
_ int64 = maxInt64 /* ERROR "overflows" */ + 1
|
_ int64 = maxInt64 /* ERROR "overflows" */ + 1
|
||||||
_ int64 = smallestFloat64 /* ERROR "overflows" */
|
_ int64 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = int64(minInt64)
|
||||||
|
_ = int64(maxInt64)
|
||||||
|
_ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = int64(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ int = minInt /* ERROR "overflows" */ - 1
|
_ int = minInt /* ERROR "overflows" */ - 1
|
||||||
_ int = minInt
|
_ int = minInt
|
||||||
_ int = maxInt
|
_ int = maxInt
|
||||||
_ int = maxInt /* ERROR "overflows" */ + 1
|
_ int = maxInt /* ERROR "overflows" */ + 1
|
||||||
_ int = smallestFloat64 /* ERROR "overflows" */
|
_ int = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = int(minInt /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = int(minInt)
|
||||||
|
_ = int(maxInt)
|
||||||
|
_ = int(maxInt /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = int(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uint8 = 0 /* ERROR "overflows" */ - 1
|
_ uint8 = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uint8 = 0
|
_ uint8 = 0
|
||||||
_ uint8 = maxUint8
|
_ uint8 = maxUint8
|
||||||
_ uint8 = maxUint8 /* ERROR "overflows" */ + 1
|
_ uint8 = maxUint8 /* ERROR "overflows" */ + 1
|
||||||
_ uint8 = smallestFloat64 /* ERROR "overflows" */
|
_ uint8 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uint8(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uint8(0)
|
||||||
|
_ = uint8(maxUint8)
|
||||||
|
_ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uint16 = 0 /* ERROR "overflows" */ - 1
|
_ uint16 = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uint16 = 0
|
_ uint16 = 0
|
||||||
_ uint16 = maxUint16
|
_ uint16 = maxUint16
|
||||||
_ uint16 = maxUint16 /* ERROR "overflows" */ + 1
|
_ uint16 = maxUint16 /* ERROR "overflows" */ + 1
|
||||||
_ uint16 = smallestFloat64 /* ERROR "overflows" */
|
_ uint16 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uint16(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uint16(0)
|
||||||
|
_ = uint16(maxUint16)
|
||||||
|
_ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uint32 = 0 /* ERROR "overflows" */ - 1
|
_ uint32 = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uint32 = 0
|
_ uint32 = 0
|
||||||
_ uint32 = maxUint32
|
_ uint32 = maxUint32
|
||||||
_ uint32 = maxUint32 /* ERROR "overflows" */ + 1
|
_ uint32 = maxUint32 /* ERROR "overflows" */ + 1
|
||||||
_ uint32 = smallestFloat64 /* ERROR "overflows" */
|
_ uint32 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uint32(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uint32(0)
|
||||||
|
_ = uint32(maxUint32)
|
||||||
|
_ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uint64 = 0 /* ERROR "overflows" */ - 1
|
_ uint64 = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uint64 = 0
|
_ uint64 = 0
|
||||||
_ uint64 = maxUint64
|
_ uint64 = maxUint64
|
||||||
_ uint64 = maxUint64 /* ERROR "overflows" */ + 1
|
_ uint64 = maxUint64 /* ERROR "overflows" */ + 1
|
||||||
_ uint64 = smallestFloat64 /* ERROR "overflows" */
|
_ uint64 = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uint64(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uint64(0)
|
||||||
|
_ = uint64(maxUint64)
|
||||||
|
_ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uint = 0 /* ERROR "overflows" */ - 1
|
_ uint = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uint = 0
|
_ uint = 0
|
||||||
_ uint = maxUint
|
_ uint = maxUint
|
||||||
_ uint = maxUint /* ERROR "overflows" */ + 1
|
_ uint = maxUint /* ERROR "overflows" */ + 1
|
||||||
_ uint = smallestFloat64 /* ERROR "overflows" */
|
_ uint = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uint(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uint(0)
|
||||||
|
_ = uint(maxUint)
|
||||||
|
_ = uint(maxUint /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uint(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ uintptr = 0 /* ERROR "overflows" */ - 1
|
_ uintptr = 0 /* ERROR "overflows" */ - 1
|
||||||
_ uintptr = 0
|
_ uintptr = 0
|
||||||
_ uintptr = maxUintptr
|
_ uintptr = maxUintptr
|
||||||
_ uintptr = maxUintptr /* ERROR "overflows" */ + 1
|
_ uintptr = maxUintptr /* ERROR "overflows" */ + 1
|
||||||
_ uintptr = smallestFloat64 /* ERROR "overflows" */
|
_ uintptr = smallestFloat64 /* ERROR "overflows" */
|
||||||
|
|
||||||
|
_ = uintptr(0 /* ERROR "cannot convert" */ - 1)
|
||||||
|
_ = uintptr(0)
|
||||||
|
_ = uintptr(maxUintptr)
|
||||||
|
_ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
|
||||||
|
_ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ float32 = minInt64
|
_ float32 = minInt64
|
||||||
_ float64 = minInt64
|
_ float64 = minInt64
|
||||||
_ complex64 = minInt64
|
_ complex64 = minInt64
|
||||||
_ complex128 = minInt64
|
_ complex128 = minInt64
|
||||||
|
|
||||||
|
_ = float32(minInt64)
|
||||||
|
_ = float64(minInt64)
|
||||||
|
_ = complex64(minInt64)
|
||||||
|
_ = complex128(minInt64)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ float32 = maxUint64
|
_ float32 = maxUint64
|
||||||
_ float64 = maxUint64
|
_ float64 = maxUint64
|
||||||
_ complex64 = maxUint64
|
_ complex64 = maxUint64
|
||||||
_ complex128 = maxUint64
|
_ complex128 = maxUint64
|
||||||
|
|
||||||
|
_ = float32(maxUint64)
|
||||||
|
_ = float64(maxUint64)
|
||||||
|
_ = complex64(maxUint64)
|
||||||
|
_ = complex128(maxUint64)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(gri) find smaller deltas below
|
// TODO(gri) find smaller deltas below
|
||||||
|
|
||||||
const delta32 = maxFloat32 >> 23
|
const delta32 = maxFloat32/(1 << 23)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
|
_ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
|
||||||
_ float32 = -maxFloat32
|
_ float32 = -maxFloat32
|
||||||
_ float32 = maxFloat32
|
_ float32 = maxFloat32
|
||||||
_ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
|
_ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
|
||||||
|
|
||||||
|
_ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
|
||||||
|
_ = float32(-maxFloat32)
|
||||||
|
_ = float32(maxFloat32)
|
||||||
|
_ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
|
||||||
)
|
)
|
||||||
|
|
||||||
const delta64 = maxFloat64 >> 52
|
const delta64 = maxFloat64/(1 << 52)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
|
_ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
|
||||||
_ float64 = -maxFloat64
|
_ float64 = -maxFloat64
|
||||||
_ float64 = maxFloat64
|
_ float64 = maxFloat64
|
||||||
_ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
|
_ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
|
||||||
|
|
||||||
|
_ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
|
||||||
|
_ = float64(-maxFloat64)
|
||||||
|
_ = float64(maxFloat64)
|
||||||
|
_ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
|
_ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
|
||||||
_ complex64 = -maxFloat32
|
_ complex64 = -maxFloat32
|
||||||
_ complex64 = maxFloat32
|
_ complex64 = maxFloat32
|
||||||
_ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
|
_ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
|
||||||
|
|
||||||
|
_ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
|
||||||
|
_ = complex64(-maxFloat32)
|
||||||
|
_ = complex64(maxFloat32)
|
||||||
|
_ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
_ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
|
_ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
|
||||||
_ complex128 = -maxFloat64
|
_ complex128 = -maxFloat64
|
||||||
_ complex128 = maxFloat64
|
_ complex128 = maxFloat64
|
||||||
_ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
|
_ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
|
||||||
|
|
||||||
|
_ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
|
||||||
|
_ = complex128(-maxFloat64)
|
||||||
|
_ = complex128(maxFloat64)
|
||||||
|
_ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialization of typed constant and conversion are the same:
|
||||||
|
const (
|
||||||
|
f32 = 1 + smallestFloat32
|
||||||
|
x32 float32 = f32
|
||||||
|
y32 = float32(f32)
|
||||||
|
_ = assert(x32 - y32 == 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
f64 = 1 + smallestFloat64
|
||||||
|
x64 float64 = f64
|
||||||
|
y64 = float64(f64)
|
||||||
|
_ = assert(x64 - y64 == 0)
|
||||||
)
|
)
|
|
@ -8,10 +8,12 @@ package conversions
|
||||||
|
|
||||||
// argument count
|
// argument count
|
||||||
var (
|
var (
|
||||||
_ = int /* ERROR "one argument" */ ()
|
_ = int() /* ERROR "missing argument" */
|
||||||
_ = int /* ERROR "one argument" */ (1, 2)
|
_ = int(1, 2 /* ERROR "too many arguments" */ )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// numeric constant conversions are in const1.src.
|
||||||
|
|
||||||
func string_conversions() {
|
func string_conversions() {
|
||||||
const A = string(65)
|
const A = string(65)
|
||||||
assert(A == "A")
|
assert(A == "A")
|
||||||
|
@ -25,16 +27,11 @@ func string_conversions() {
|
||||||
type mystring string
|
type mystring string
|
||||||
const _ mystring = mystring("foo")
|
const _ mystring = mystring("foo")
|
||||||
|
|
||||||
const _ = string /* ERROR "cannot convert" */ (true)
|
const _ = string(true /* ERROR "cannot convert" */ )
|
||||||
const _ = string /* ERROR "cannot convert" */ (1.2)
|
const _ = string(1.2 /* ERROR "cannot convert" */ )
|
||||||
const _ = string /* ERROR "cannot convert" */ (nil)
|
const _ = string(nil /* ERROR "cannot convert" */ )
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
var (
|
|
||||||
_ = int8(0)
|
|
||||||
)
|
|
||||||
|
|
||||||
func interface_conversions() {
|
func interface_conversions() {
|
||||||
type E interface{}
|
type E interface{}
|
||||||
|
|
||||||
|
@ -63,20 +60,20 @@ func interface_conversions() {
|
||||||
_ = E(i1)
|
_ = E(i1)
|
||||||
_ = E(i2)
|
_ = E(i2)
|
||||||
|
|
||||||
_ = I1 /* ERROR "cannot convert" */ (0)
|
_ = I1(0 /* ERROR "cannot convert" */ )
|
||||||
_ = I1(nil)
|
_ = I1(nil)
|
||||||
_ = I1(i1)
|
_ = I1(i1)
|
||||||
_ = I1 /* ERROR "cannot convert" */ (e)
|
_ = I1(e /* ERROR "cannot convert" */ )
|
||||||
_ = I1(i2)
|
_ = I1(i2)
|
||||||
|
|
||||||
_ = I2(nil)
|
_ = I2(nil)
|
||||||
_ = I2 /* ERROR "cannot convert" */ (i1)
|
_ = I2(i1 /* ERROR "cannot convert" */ )
|
||||||
_ = I2(i2)
|
_ = I2(i2)
|
||||||
_ = I2 /* ERROR "cannot convert" */ (i3)
|
_ = I2(i3 /* ERROR "cannot convert" */ )
|
||||||
|
|
||||||
_ = I3(nil)
|
_ = I3(nil)
|
||||||
_ = I3 /* ERROR "cannot convert" */ (i1)
|
_ = I3(i1 /* ERROR "cannot convert" */ )
|
||||||
_ = I3 /* ERROR "cannot convert" */ (i2)
|
_ = I3(i2 /* ERROR "cannot convert" */ )
|
||||||
_ = I3(i3)
|
_ = I3(i3)
|
||||||
|
|
||||||
// TODO(gri) add more tests, improve error message
|
// TODO(gri) add more tests, improve error message
|
||||||
|
|
|
@ -317,7 +317,7 @@ func _calls() {
|
||||||
f1(0)
|
f1(0)
|
||||||
f1(x)
|
f1(x)
|
||||||
f1(10.0)
|
f1(10.0)
|
||||||
f1 /* ERROR "too few arguments" */ ()
|
f1() /* ERROR "too few arguments" */
|
||||||
f1(x, y /* ERROR "too many arguments" */ )
|
f1(x, y /* ERROR "too many arguments" */ )
|
||||||
f1(s /* ERROR "cannot pass" */ )
|
f1(s /* ERROR "cannot pass" */ )
|
||||||
f1(x ... /* ERROR "cannot use ..." */ )
|
f1(x ... /* ERROR "cannot use ..." */ )
|
||||||
|
@ -325,15 +325,15 @@ func _calls() {
|
||||||
f1(g1())
|
f1(g1())
|
||||||
// f1(g2()) // TODO(gri) missing position in error message
|
// f1(g2()) // TODO(gri) missing position in error message
|
||||||
|
|
||||||
f2 /* ERROR "too few arguments" */ ()
|
f2() /* ERROR "too few arguments" */
|
||||||
f2 /* ERROR "too few arguments" */ (3.14)
|
f2(3.14) /* ERROR "too few arguments" */
|
||||||
f2(3.14, "foo")
|
f2(3.14, "foo")
|
||||||
f2(x /* ERROR "cannot pass" */ , "foo")
|
f2(x /* ERROR "cannot pass" */ , "foo")
|
||||||
f2(g0 /* ERROR "used as value" */ ())
|
f2(g0 /* ERROR "used as value" */ ())
|
||||||
f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot pass" */ ())
|
f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
|
||||||
f2(g2())
|
f2(g2())
|
||||||
|
|
||||||
fs /* ERROR "too few arguments" */ ()
|
fs() /* ERROR "too few arguments" */
|
||||||
fs(g0 /* ERROR "used as value" */ ())
|
fs(g0 /* ERROR "used as value" */ ())
|
||||||
fs(g1 /* ERROR "cannot pass" */ ())
|
fs(g1 /* ERROR "cannot pass" */ ())
|
||||||
fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
|
fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
|
||||||
|
|
|
@ -54,7 +54,7 @@ func assignments() {
|
||||||
|
|
||||||
g := func(int, bool){}
|
g := func(int, bool){}
|
||||||
var m map[int]int
|
var m map[int]int
|
||||||
g/* ERROR "too few arguments" */ (m[0])
|
g(m[0]) /* ERROR "too few arguments" */
|
||||||
|
|
||||||
// assignments to _
|
// assignments to _
|
||||||
_ = nil /* ERROR "use of untyped nil" */
|
_ = nil /* ERROR "use of untyped nil" */
|
||||||
|
|
Loading…
Reference in New Issue