fix: correct automatic type conversion for untyped constants

This commit is contained in:
Marc Vertes
2019-09-25 15:02:04 +02:00
committed by Traefiker Bot
parent 8db7a815e3
commit 03596dac45
4 changed files with 71 additions and 21 deletions

10
_test/shift3.go Normal file
View File

@@ -0,0 +1,10 @@
package main
const a = 1.0
const b = a + 3
func main() { println(b << (1)) }
// Output:
// 8

View File

@@ -3,6 +3,7 @@ package interp
import (
"fmt"
"log"
"math"
"path"
"reflect"
"unicode"
@@ -403,7 +404,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
case aShlAssign, aShrAssign:
if !(isInt(t0) && isUint(t1)) {
if !(dest.isInteger() && src.isNatural()) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
default:
@@ -521,7 +522,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
case aShl, aShr:
if !(isInt(t0) && isUint(t1)) {
if !(c0.isInteger() && c1.isNatural()) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
n.typ = c0.typ
@@ -1506,7 +1507,57 @@ func wireChild(n *node) {
}
}
// last returns the last child of a node
// isInteger returns true if node type is integer, false otherwise
func (n *node) isInteger() bool {
if isInt(n.typ.TypeOf()) {
return true
}
if n.typ.untyped && n.rval.IsValid() {
t := n.rval.Type()
if isInt(t) {
return true
}
if isFloat(t) {
// untyped float constant with null decimal part is ok
f := n.rval.Float()
if f == math.Round(f) {
n.rval = reflect.ValueOf(int(f))
n.typ.rtype = n.rval.Type()
return true
}
}
}
return false
}
// isNatural returns true if node type is natural, false otherwise
func (n *node) isNatural() bool {
if isUint(n.typ.TypeOf()) {
return true
}
if n.typ.untyped && n.rval.IsValid() {
t := n.rval.Type()
if isUint(t) {
return true
}
if isInt(t) && n.rval.Int() >= 0 {
// positive untyped integer constant is ok
return true
}
if isFloat(t) {
// positive untyped float constant with null decimal part is ok
f := n.rval.Float()
if f == math.Round(f) && f >= 0 {
n.rval = reflect.ValueOf(uint(f))
n.typ.rtype = n.rval.Type()
return true
}
}
}
return false
}
// lastChild returns the last child of a node
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
func isKey(n *node) bool {

View File

@@ -44,11 +44,13 @@ func TestEvalArithmetic(t *testing.T) {
{desc: "rem_FI", src: "8.0 % 4", err: "1:28: illegal operand types for '%' operator"},
{desc: "shl_II", src: "1 << 8", res: "256"},
{desc: "shl_IN", src: "1 << -1", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1 << 1.0", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1.0 << 1", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1 << 1.0", res: "2"},
{desc: "shl_IF1", src: "1 << 1.1", err: "1:28: illegal operand types for '<<' operator"},
{desc: "shl_IF", src: "1.0 << 1", res: "2"},
{desc: "shr_II", src: "1 >> 8", res: "0"},
{desc: "shr_IN", src: "1 >> -1", err: "1:28: illegal operand types for '>>' operator"},
{desc: "shr_IF", src: "1 >> 1.0", err: "1:28: illegal operand types for '>>' operator"},
{desc: "shr_IF", src: "1 >> 1.0", res: "0"},
{desc: "shr_IF1", src: "1 >> 1.1", err: "1:28: illegal operand types for '>>' operator"},
})
}

View File

@@ -215,14 +215,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.name = "float64"
t.untyped = true
case int:
if isShiftOperand(n) && v >= 0 {
t.cat = uintT
t.name = "uint"
n.rval = reflect.ValueOf(uint(v))
} else {
t.cat = intT
t.name = "int"
}
t.cat = intT
t.name = "int"
t.untyped = true
case uint:
t.cat = uintT
@@ -909,13 +903,6 @@ func isShiftNode(n *node) bool {
return false
}
func isShiftOperand(n *node) bool {
if isShiftNode(n.anc) {
return n.anc.lastChild() == n
}
return false
}
func isInterface(t *itype) bool { return t.cat == interfaceT || t.TypeOf().Kind() == reflect.Interface }
func isStruct(t *itype) bool { return t.TypeOf().Kind() == reflect.Struct }