// The spec requires at least 256 bits; typical implementations use 512 bits.
const prec = 512
+// TODO(gri) Consider storing "error" information in an unknownVal so clients
+// can provide better error messages. For instance, if a number is
+// too large (incl. infinity), that could be recorded in unknownVal.
+// See also #20583 and #42695 for use cases.
+
type (
unknownVal struct{}
boolVal bool
if x.Sign() == 0 {
return floatVal0
}
+ if x.IsInf() {
+ return unknownVal{}
+ }
return floatVal{x}
}
func makeComplex(re, im Value) Value {
+ if re.Kind() == Unknown || im.Kind() == Unknown {
+ return unknownVal{}
+ }
return complexVal{re, im}
}
`1_2_3.123 = 123.123`,
`0123.01_23 = 123.0123`,
+ `1e-1000000000 = 0`,
+ `1e+1000000000 = ?`,
+ `6e5518446744 = ?`,
+ `-6e5518446744 = ?`,
+
// hexadecimal floats
`0x0.p+0 = 0.`,
`0Xdeadcafe.p-10 = 0xdeadcafe/1024`,
`0.e+1i = 0i`,
`123.E-1_0i = 123e-10i`,
`01_23.e123i = 123e123i`,
+
+ `1e-1000000000i = 0i`,
+ `1e+1000000000i = ?`,
+ `6e5518446744i = ?`,
+ `-6e5518446744i = ?`,
}
func testNumbers(t *testing.T, kind token.Token, tests []string) {
x := MakeFromLiteral(a[0], kind, 0)
var y Value
- if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
- n := MakeFromLiteral(a[1][:i], token.INT, 0)
- d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
- y = BinaryOp(n, token.QUO, d)
+ if a[1] == "?" {
+ y = MakeUnknown()
} else {
- y = MakeFromLiteral(a[1], kind, 0)
+ if i := strings.Index(a[1], "/"); i >= 0 && kind == token.FLOAT {
+ n := MakeFromLiteral(a[1][:i], token.INT, 0)
+ d := MakeFromLiteral(a[1][i+1:], token.INT, 0)
+ y = BinaryOp(n, token.QUO, d)
+ } else {
+ y = MakeFromLiteral(a[1], kind, 0)
+ }
+ if y.Kind() == Unknown {
+ panic(fmt.Sprintf("invalid test case: %s %d", test, y.Kind()))
+ }
}
xk := x.Kind()
yk := y.Kind()
- if xk != yk || xk == Unknown {
+ if xk != yk {
t.Errorf("%s: got kind %d != %d", test, xk, yk)
continue
}
+ if yk == Unknown {
+ continue
+ }
+
if !Compare(x, token.EQL, y) {
t.Errorf("%s: %s != %s", test, x, y)
}
`1i * 1i = -1`,
`? * 0 = ?`,
`0 * ? = ?`,
+ `0 * 1e+1000000000 = ?`,
`0 / 0 = "division_by_zero"`,
`10 / 2 = 5`,
`5i / 3i = 5/3`,
`? / 0 = ?`,
`0 / ? = ?`,
+ `0 * 1e+1000000000i = ?`,
`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
`10 % 3 = 1`,
}
// The binary expression e may be nil. It's passed in for better error messages only.
-func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token) {
+func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token, opPos token.Pos) {
var y operand
check.expr(x, lhs)
op = token.QUO_ASSIGN
}
x.val = constant.BinaryOp(xval, op, yval)
+ // report error if valid operands lead to an invalid result
+ if xval.Kind() != constant.Unknown && yval.Kind() != constant.Unknown && x.val.Kind() == constant.Unknown {
+ // TODO(gri) We should report exactly what went wrong. At the
+ // moment we don't have the (go/constant) API for that.
+ // See also TODO in go/constant/value.go.
+ check.errorf(atPos(e.OpPos), _InvalidConstVal, "constant result not representable")
+ // TODO(gri) Should we mark operands with unknown values as invalid?
+ }
// Typed constants must be representable in
// their type after each constant operation.
if isTyped(typ) {
}
case *ast.BinaryExpr:
- check.binary(x, e, e.X, e.Y, e.Op)
+ check.binary(x, e, e.X, e.Y, e.Op, e.OpPos)
if x.mode == invalid {
goto Error
}
--- /dev/null
+// Copyright 2020 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.
+
+package issue20583
+
+const (
+ _ = 6e886451608 /* ERROR malformed constant */ /2
+ _ = 6e886451608i /* ERROR malformed constant */ /2
+ _ = 0 * 1e+1000000000 // ERROR malformed constant
+
+ x = 1e100000000
+ _ = x*x*x*x*x*x* /* ERROR not representable */ x
+)
}
Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
- check.binary(&x, nil, s.X, Y, op)
+ check.binary(&x, nil, s.X, Y, op, s.TokPos)
if x.mode == invalid {
return
}
return
}
var x operand
- check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
+ check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
if x.mode == invalid {
return
}