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:
Robert Griesemer 2013-08-12 14:57:08 -07:00
parent 508ae115ae
commit d13d94afe7
10 changed files with 293 additions and 125 deletions

View File

@ -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.

View File

@ -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
} }

View File

@ -6,89 +6,57 @@
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. switch {
// The result of the conversion is returned via x. case x.mode == constant && isConstType(T):
// 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 // constant conversion
typ := typ.Underlying().(*Basic) switch t := T.Underlying().(*Basic); {
// For now just implement string(x) where x is an integer, case isRepresentableConst(x.val, check.conf, t.kind, &x.val):
// as a temporary work-around for issue 4982, which is a // nothing to do
// common issue. case x.isInteger() && isString(t):
if typ.kind == String { codepoint := int64(-1)
switch { if i, ok := exact.Int64Val(x.val); ok {
case x.isInteger(): codepoint = i
codepoint := int64(-1)
if i, ok := exact.Int64Val(x.val); ok {
codepoint = i
}
// If codepoint < 0 the absolute value is too large (or unknown) for
// conversion. This is the same as converting any other out-of-range
// value - let string(codepoint) do the work.
x.val = exact.MakeString(string(codepoint))
case isString(x.typ):
// nothing to do
default:
goto ErrorMsg
} }
// If codepoint < 0 the absolute value is too large (or unknown) for
// conversion. This is the same as converting any other out-of-range
// value - let string(codepoint) do the work.
x.val = exact.MakeString(string(codepoint))
default:
x.mode = invalid
} }
// TODO(gri) verify the remaining conversions. case x.isConvertible(check.conf, T):
} 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 {

View File

@ -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:
return fitsFloat32(x) if rounded == nil {
return fitsFloat32(x)
}
r := roundFloat32(x)
if r != nil {
*rounded = r
return true
}
case Float64, Complex128: case Float64, Complex128:
return fitsFloat64(x) if rounded == nil {
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:
return fitsFloat32(x) if rounded == nil {
return fitsFloat32(x)
}
r := roundFloat32(x)
if r != nil {
*rounded = r
return true
}
case Float64, Complex128: case Float64, Complex128:
return fitsFloat64(x) if rounded == nil {
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:
return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x)) if rounded == nil {
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:
return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x)) if rounded == nil {
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

View File

@ -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
} }

View File

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

View File

@ -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)
) )

View File

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

View File

@ -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" */ ())

View File

@ -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" */