From 4ea4ce9e0399e7401d72897037c823939d8151ad Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 26 Jul 2013 18:21:14 -0700 Subject: [PATCH] go.tools/go/types: added missing implicit conversion checks R=adonovan, r CC=golang-dev https://golang.org/cl/11934047 --- go/types/check_test.go | 1 + go/types/expr.go | 57 +++++++------ go/types/testdata/const1.src | 157 +++++++++++++++++++++++++++++++++++ go/types/testdata/shifts.src | 2 +- 4 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 go/types/testdata/const1.src diff --git a/go/types/check_test.go b/go/types/check_test.go index 69e8e404..596aecf3 100644 --- a/go/types/check_test.go +++ b/go/types/check_test.go @@ -51,6 +51,7 @@ var tests = [][]string{ {"testdata/decls2a.src", "testdata/decls2b.src"}, {"testdata/decls3.src"}, {"testdata/const0.src"}, + {"testdata/const1.src"}, {"testdata/constdecl.src"}, {"testdata/vardecl.src"}, {"testdata/expr0.src"}, diff --git a/go/types/expr.go b/go/types/expr.go index 341ac85f..c7a28570 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -9,6 +9,7 @@ package types import ( "go/ast" "go/token" + "math" "code.google.com/p/go.tools/go/exact" ) @@ -155,6 +156,19 @@ func isComparison(op token.Token) bool { return false } +func fitsFloat32(x exact.Value) bool { + f, _ := exact.Float64Val(x) + // We assume that float32(f) returns an Inf if f + // cannot be represented as a float32, or if f + // is an Inf. This is not supported by the spec. + return !math.IsInf(float64(float32(f)), 0) +} + +func fitsFloat64(x exact.Value) bool { + f, _ := exact.Float64Val(x) + return !math.IsInf(f, 0) +} + func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool { switch x.Kind() { case exact.Unknown: @@ -196,15 +210,8 @@ func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool { return 0 <= x && x <= 1<= 0 && n <= int(s) case Uint64: return exact.Sign(x) >= 0 && n <= 64 - case Float32: - return true // TODO(gri) fix this - case Float64: - return true // TODO(gri) fix this - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this + case Float32, Complex64: + return fitsFloat32(x) + case Float64, Complex128: + return fitsFloat64(x) case UntypedInt, UntypedFloat, UntypedComplex: return true } case exact.Float: switch as { - case Float32: - return true // TODO(gri) fix this - case Float64: - return true // TODO(gri) fix this - case Complex64: - return true // TODO(gri) fix this - case Complex128: - return true // TODO(gri) fix this + case Float32, Complex64: + return fitsFloat32(x) + case Float64, Complex128: + return fitsFloat64(x) case UntypedFloat, UntypedComplex: return true } @@ -245,9 +244,9 @@ func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool { case exact.Complex: switch as { case Complex64: - return true // TODO(gri) fix this + return fitsFloat32(exact.Real(x)) && fitsFloat32(exact.Imag(x)) case Complex128: - return true // TODO(gri) fix this + return fitsFloat64(exact.Real(x)) && fitsFloat64(exact.Imag(x)) case UntypedComplex: return true } @@ -540,9 +539,9 @@ func (check *checker) shift(x, y *operand, op token.Token) { if x.mode == constant { if y.mode == constant { // rhs must be within reasonable bounds - const stupidShift = 1024 + const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64 s, ok := exact.Uint64Val(y.val) - if !ok || s >= stupidShift { + if !ok || s > stupidShift { check.invalidOp(y.pos(), "%s: stupid shift", y) x.mode = invalid return diff --git a/go/types/testdata/const1.src b/go/types/testdata/const1.src new file mode 100644 index 00000000..e528cb07 --- /dev/null +++ b/go/types/testdata/const1.src @@ -0,0 +1,157 @@ +// Copyright 2012 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. + +// implicit constant conversions + +package const1 + +// TODO(gri) add int/uint/uintptr sizes and tests + +const ( + minInt8 = -1<<(8< 0) + _ = assert(smallestFloat64 > 0) +) + +const ( + maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23) + maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52) +) + +var ( + _ int8 = minInt8 /* ERROR "overflows" */ - 1 + _ int8 = minInt8 + _ int8 = maxInt8 + _ int8 = maxInt8 /* ERROR "overflows" */ + 1 + _ int8 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ int16 = minInt16 /* ERROR "overflows" */ - 1 + _ int16 = minInt16 + _ int16 = maxInt16 + _ int16 = maxInt16 /* ERROR "overflows" */ + 1 + _ int16 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ int32 = minInt32 /* ERROR "overflows" */ - 1 + _ int32 = minInt32 + _ int32 = maxInt32 + _ int32 = maxInt32 /* ERROR "overflows" */ + 1 + _ int32 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ int64 = minInt64 /* ERROR "overflows" */ - 1 + _ int64 = minInt64 + _ int64 = maxInt64 + _ int64 = maxInt64 /* ERROR "overflows" */ + 1 + _ int64 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ uint8 = 0 /* ERROR "overflows" */ - 1 + _ uint8 = 0 + _ uint8 = maxUint8 + _ uint8 = maxUint8 /* ERROR "overflows" */ + 1 + _ uint8 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ uint16 = 0 /* ERROR "overflows" */ - 1 + _ uint16 = 0 + _ uint16 = maxUint16 + _ uint16 = maxUint16 /* ERROR "overflows" */ + 1 + _ uint16 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ uint32 = 0 /* ERROR "overflows" */ - 1 + _ uint32 = 0 + _ uint32 = maxUint32 + _ uint32 = maxUint32 /* ERROR "overflows" */ + 1 + _ uint32 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ uint64 = 0 /* ERROR "overflows" */ - 1 + _ uint64 = 0 + _ uint64 = maxUint64 + _ uint64 = maxUint64 /* ERROR "overflows" */ + 1 + _ uint64 = smallestFloat64 /* ERROR "overflows" */ +) + +var ( + _ float32 = minInt64 + _ float64 = minInt64 + _ complex64 = minInt64 + _ complex128 = minInt64 +) + +var ( + _ float32 = maxUint64 + _ float64 = maxUint64 + _ complex64 = maxUint64 + _ complex128 = maxUint64 +) + +// TODO(gri) find smaller deltas below + +const delta32 = maxFloat32 >> 23 + +var ( + _ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32) + _ float32 = -maxFloat32 + _ float32 = maxFloat32 + _ float32 = maxFloat32 /* ERROR "overflow" */ + delta32 +) + +const delta64 = maxFloat64 >> 52 + +var ( + _ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64) + _ float64 = -maxFloat64 + _ float64 = maxFloat64 + _ float64 = maxFloat64 /* ERROR "overflow" */ + delta64 +) + +var ( + _ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32) + _ complex64 = -maxFloat32 + _ complex64 = maxFloat32 + _ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32 +) + +var ( + _ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64) + _ complex128 = -maxFloat64 + _ complex128 = maxFloat64 + _ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64 +) \ No newline at end of file diff --git a/go/types/testdata/shifts.src b/go/types/testdata/shifts.src index 12ca3781..bea4d233 100644 --- a/go/types/testdata/shifts.src +++ b/go/types/testdata/shifts.src @@ -15,7 +15,7 @@ func shifts1() { v2 = 1<