go.tools/go/types: report correctly rounded constant values
Also: - better documentation of exact.Float64Val - minor rearrangement in go/importer (unrelated) LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/70200047
This commit is contained in:
parent
fccaf8c467
commit
e3ab342481
|
|
@ -244,7 +244,9 @@ func Uint64Val(x Value) (uint64, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
|
// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
|
||||||
// x must be numeric but not Complex, or Unknown.
|
// 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
|
||||||
|
// matches the sign of x, even for 0.
|
||||||
// If x is Unknown, the result is (0, false).
|
// If x is Unknown, the result is (0, false).
|
||||||
func Float64Val(x Value) (float64, bool) {
|
func Float64Val(x Value) (float64, bool) {
|
||||||
switch x := x.(type) {
|
switch x := x.(type) {
|
||||||
|
|
|
||||||
|
|
@ -137,9 +137,6 @@ func (p *exporter) value(x exact.Value) {
|
||||||
tag = trueTag
|
tag = trueTag
|
||||||
}
|
}
|
||||||
p.int(tag)
|
p.int(tag)
|
||||||
case exact.String:
|
|
||||||
p.int(stringTag)
|
|
||||||
p.string(exact.StringVal(x))
|
|
||||||
case exact.Int:
|
case exact.Int:
|
||||||
if i, ok := exact.Int64Val(x); ok {
|
if i, ok := exact.Int64Val(x); ok {
|
||||||
p.int(int64Tag)
|
p.int(int64Tag)
|
||||||
|
|
@ -155,6 +152,9 @@ func (p *exporter) value(x exact.Value) {
|
||||||
p.int(complexTag)
|
p.int(complexTag)
|
||||||
p.fraction(exact.Real(x))
|
p.fraction(exact.Real(x))
|
||||||
p.fraction(exact.Imag(x))
|
p.fraction(exact.Imag(x))
|
||||||
|
case exact.String:
|
||||||
|
p.int(stringTag)
|
||||||
|
p.string(exact.StringVal(x))
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected value kind %d", kind))
|
panic(fmt.Sprintf("unexpected value kind %d", kind))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,6 @@ func (p *importer) value() exact.Value {
|
||||||
return exact.MakeBool(false)
|
return exact.MakeBool(false)
|
||||||
case trueTag:
|
case trueTag:
|
||||||
return exact.MakeBool(true)
|
return exact.MakeBool(true)
|
||||||
case stringTag:
|
|
||||||
return exact.MakeString(p.string())
|
|
||||||
case int64Tag:
|
case int64Tag:
|
||||||
return exact.MakeInt64(p.int64())
|
return exact.MakeInt64(p.int64())
|
||||||
case floatTag:
|
case floatTag:
|
||||||
|
|
@ -141,6 +139,8 @@ func (p *importer) value() exact.Value {
|
||||||
re := p.fraction()
|
re := p.fraction()
|
||||||
im := p.fraction()
|
im := p.fraction()
|
||||||
return exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
|
return exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
|
||||||
|
case stringTag:
|
||||||
|
return exact.MakeString(p.string())
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected value kind %d", kind))
|
panic(fmt.Sprintf("unexpected value kind %d", kind))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// TODO(gri) This file needs to be expanded significantly.
|
|
||||||
|
|
||||||
package types_test
|
package types_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -89,6 +87,28 @@ func TestValuesInfo(t *testing.T) {
|
||||||
{`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
|
{`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
|
||||||
{`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
|
{`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
|
||||||
{`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
|
{`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
|
||||||
|
|
||||||
|
{`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
|
||||||
|
{`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
|
||||||
|
{`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
|
||||||
|
{`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
|
||||||
|
{`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
|
||||||
|
{`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
|
||||||
|
{`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
|
||||||
|
{`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
|
||||||
|
|
||||||
|
{`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`},
|
||||||
|
{`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
|
||||||
|
{`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`},
|
||||||
|
{`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
|
||||||
|
{`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`},
|
||||||
|
{`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`},
|
||||||
|
{`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `0`},
|
||||||
|
{`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `0`},
|
||||||
|
{`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `0`},
|
||||||
|
{`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
|
||||||
|
{`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `0`},
|
||||||
|
{`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ func (check *checker) conversion(x *operand, T Type) {
|
||||||
if isInterface(T) || constArg && !isConstType(T) {
|
if isInterface(T) || constArg && !isConstType(T) {
|
||||||
final = defaultType(x.typ)
|
final = defaultType(x.typ)
|
||||||
}
|
}
|
||||||
|
check.updateExprType(x.expr, final, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
x.typ = T
|
x.typ = T
|
||||||
check.updateExprType(x.expr, final, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *operand) convertibleTo(conf *Config, T Type) bool {
|
func (x *operand) convertibleTo(conf *Config, T Type) bool {
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,14 @@ func (check *checker) updateExprType(x ast.Expr, typ Type, final bool) {
|
||||||
check.recordTypeAndValue(x, typ, old.val)
|
check.recordTypeAndValue(x, typ, old.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateExprVal updates the value of x to val.
|
||||||
|
func (check *checker) updateExprVal(x ast.Expr, val exact.Value) {
|
||||||
|
if info, ok := check.untyped[x]; ok {
|
||||||
|
info.val = val
|
||||||
|
check.untyped[x] = info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// convertUntyped attempts to set the type of an untyped value to the target type.
|
// convertUntyped attempts to set the type of an untyped value to the target type.
|
||||||
func (check *checker) convertUntyped(x *operand, target Type) {
|
func (check *checker) convertUntyped(x *operand, target Type) {
|
||||||
if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
|
if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
|
||||||
|
|
@ -494,6 +502,10 @@ func (check *checker) convertUntyped(x *operand, target Type) {
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// expression value may have been rounded - update if needed
|
||||||
|
// TODO(gri) A floating-point value may silently underflow to
|
||||||
|
// zero. If it was negative, the sign is lost. See issue 6898.
|
||||||
|
check.updateExprVal(x.expr, x.val)
|
||||||
} else {
|
} else {
|
||||||
// Non-constant untyped values may appear as the
|
// Non-constant untyped values may appear as the
|
||||||
// result of comparisons (untyped bool), intermediate
|
// result of comparisons (untyped bool), intermediate
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue