From 459aaad458b412a6f787a33264172045047ef840 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 Jun 2014 09:12:52 -0700 Subject: [PATCH] go.tools/go/types: fix float32 conversions Pending CL 93550043. For submission after the 1.3 release. Fixes golang/go#8066. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/95580045 --- go/exact/exact.go | 16 ++++++++++++++++ go/types/expr.go | 17 +++++------------ go/types/stdlib_test.go | 1 - go/types/testdata/issues.src | 7 +++++++ 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/go/exact/exact.go b/go/exact/exact.go index cfc27e09..f6eb358b 100644 --- a/go/exact/exact.go +++ b/go/exact/exact.go @@ -245,6 +245,22 @@ func Uint64Val(x Value) (uint64, bool) { panic(fmt.Sprintf("%v not an Int", x)) } +// Float32Val is like Float64Val but for float32 instead of float64. +func Float32Val(x Value) (float32, bool) { + switch x := x.(type) { + case int64Val: + f := float32(x) + return f, int64Val(f) == x + case intVal: + return new(big.Rat).SetFrac(x.val, int1).Float32() + case floatVal: + return x.val.Float32() + case unknownVal: + return 0, false + } + panic(fmt.Sprintf("%v not a Float", x)) +} + // Float64Val returns the nearest Go float64 value of x and whether the result is exact; // x must be numeric but not Complex, or Unknown. For values too small (too close to 0) // to represent as float64, Float64Val silently underflows to 0. The result sign always diff --git a/go/types/expr.go b/go/types/expr.go index c143c138..d21217c6 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -149,21 +149,14 @@ func isComparison(op token.Token) bool { } func fitsFloat32(x exact.Value) bool { - f, _ := exact.Float64Val(x) - // spec: "In all non-constant conversions involving floating-point - // or complex values, if the result type cannot represent the value - // the conversion succeeds but the result value is implementation- - // dependent." - // - // We assume that float32(f) returns an Inf if f is too large for - // a float32, or if f is an Inf; and that it returns 0 for values - // with too small a magnitude. - return !math.IsInf(float64(float32(f)), 0) + f32, _ := exact.Float32Val(x) + f := float64(f32) + return !math.IsInf(f, 0) } func roundFloat32(x exact.Value) exact.Value { - f, _ := exact.Float64Val(x) - f = float64(float32(f)) + f32, _ := exact.Float32Val(x) + f := float64(f32) if !math.IsInf(f, 0) { return exact.MakeFloat64(f) } diff --git a/go/types/stdlib_test.go b/go/types/stdlib_test.go index 174c6cee..86da7797 100644 --- a/go/types/stdlib_test.go +++ b/go/types/stdlib_test.go @@ -119,7 +119,6 @@ func TestStdTest(t *testing.T) { testTestDir(t, filepath.Join(runtime.GOROOT(), "test"), "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore "sigchld.go", // don't work on Windows; testTestDir should consult build tags - "float_lit2.go", // TODO(gri) float32 constant conversion requires (missing) Rat.Float32 ) } diff --git a/go/types/testdata/issues.src b/go/types/testdata/issues.src index abcd11e1..9e333ab8 100644 --- a/go/types/testdata/issues.src +++ b/go/types/testdata/issues.src @@ -14,3 +14,10 @@ func issue7035() { fmt := new(T) _ = fmt.X } + +func issue8066() { + const ( + _ = float32(340282356779733661637539395458142568447) + _ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ ) + ) +}