feature: refactor numeric constants and detect overflow

This commit is contained in:
Nicholas Wiersma
2020-06-18 09:20:04 +02:00
committed by GitHub
parent 5cbbf9339c
commit 1fe91be882
9 changed files with 452 additions and 55 deletions

16
_test/const13.go Normal file
View File

@@ -0,0 +1,16 @@
package main
import (
"fmt"
)
func main() {
const tooBig = 1267650600228229401496703205376
const huge = 1 << 100
const large = huge >> 38
fmt.Println(large)
}
// Output:
// 4611686018427387904

View File

@@ -5,6 +5,7 @@ import (
"go/format"
"io/ioutil"
"log"
"strings"
"text/template"
)
@@ -12,7 +13,11 @@ const model = `package interp
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
import "reflect"
import (
"go/constant"
"go/token"
"reflect"
)
// Arithmetic operators
{{range $name, $op := .Arithmetic}}
@@ -176,9 +181,22 @@ func {{$name}}(n *node) {
func {{$name}}Const(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
{{- if $op.Shift}}
s, _ := constant.Uint64Val(vConstantValue(v1))
v := constant.Shift(vConstantValue(v0), token.{{tokenFromName $name}}, uint(s))
n.rval.Set(reflect.ValueOf(v))
{{- else}}
v := constant.BinaryOp(vConstantValue(v0), token.{{tokenFromName $name}}, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
{{- end}}
{{- if $op.Str}}
case isString(t):
n.rval.SetString(v0.String() {{$op.Name}} v1.String())
@@ -354,23 +372,35 @@ func {{$name}}(n *node) {
{{end}}
{{range $name, $op := .Unary}}
func {{$name}}Const(n *node) {
v0 := n.child[0].rval
isConst := v0.IsValid() && isConstantValue(v0.Type())
t := n.typ.rtype
v := n.child[0].rval
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
{{- if $op.Bool}}
n.rval.SetBool({{$op.Name}} v.Bool())
if isConst {
v := constant.UnaryOp(token.{{tokenFromName $name}}, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
} else {
n.rval.SetBool({{$op.Name}} v0.Bool())
}
{{- else}}
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt({{$op.Name}} v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint({{$op.Name}} v.Uint())
switch {
case isConst:
v := constant.UnaryOp(token.{{tokenFromName $name}}, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
case isInt(t):
n.rval.SetInt({{$op.Name}} v0.Int())
case isUint(t):
n.rval.SetUint({{$op.Name}} v0.Uint())
{{- if $op.Float}}
case reflect.Float32, reflect.Float64:
n.rval.SetFloat({{$op.Name}} v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex({{$op.Name}} v.Complex())
case isFloat(t):
n.rval.SetFloat({{$op.Name}} v0.Float())
case isComplex(t):
n.rval.SetComplex({{$op.Name}} v0.Complex())
{{- end}}
}
{{- end}}
@@ -822,6 +852,22 @@ type Op struct {
func main() {
base := template.New("goexports")
base.Funcs(template.FuncMap{
"tokenFromName": func(name string) string {
switch name {
case "andNot":
return "AND_NOT"
case "neg":
return "SUB"
case "pos":
return "ADD"
case "bitNot":
return "XOR"
default:
return strings.ToUpper(name)
}
},
})
parse, err := base.Parse(model)
if err != nil {
log.Fatal(err)

View File

@@ -3,6 +3,7 @@ package interp
import (
"fmt"
"go/ast"
"go/constant"
"go/parser"
"go/scanner"
"go/token"
@@ -474,14 +475,14 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
v, _, _, _ := strconv.UnquoteChar(a.Value[1:len(a.Value)-1], '\'')
n.rval = reflect.ValueOf(v)
case token.FLOAT:
v, _ := strconv.ParseFloat(a.Value, 64)
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
n.rval = reflect.ValueOf(v)
case token.IMAG:
v, _ := strconv.ParseFloat(a.Value[:len(a.Value)-1], 64)
n.rval = reflect.ValueOf(complex(0, v))
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
n.rval = reflect.ValueOf(v)
case token.INT:
v, _ := strconv.ParseInt(a.Value, 0, 0)
n.rval = reflect.ValueOf(int(v))
v := constant.MakeFromLiteral(a.Value, a.Kind, 0)
n.rval = reflect.ValueOf(v)
case token.STRING:
v, _ := strconv.Unquote(a.Value)
n.rval = reflect.ValueOf(v)

View File

@@ -2,6 +2,7 @@ package interp
import (
"fmt"
"go/constant"
"log"
"math"
"reflect"
@@ -543,8 +544,11 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
case !src.rval.IsValid():
// Assign to nil.
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
case n.anc.kind == constDecl:
// Possible conversion from const to actual type will be handled later
default:
// Convert literal value to destination type.
convertConstantValue(src)
src.rval = src.rval.Convert(dest.typ.TypeOf())
src.typ = dest.typ
}
@@ -559,6 +563,12 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
dest.gen = nop // skip getIndexMap
}
if n.anc.kind == constDecl {
if !dest.typ.untyped {
// If the dest is untyped, any constant rval needs to be converted
convertConstantValue(src)
}
n.gen = nop
n.findex = -1
sc.sym[dest.ident].kind = constSym
if childPos(n) == len(n.anc.child)-1 {
sc.iota = 0
@@ -1082,7 +1092,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
n.rval = sym.rval
n.kind = basicLit
case n.ident == "iota":
n.rval = reflect.ValueOf(sc.iota)
n.rval = reflect.ValueOf(constant.Make(int64(sc.iota)))
n.kind = basicLit
case n.ident == "nil":
n.kind = basicLit
@@ -1791,13 +1801,13 @@ func compDefineX(sc *scope, n *node) error {
}
// TODO used for allocation optimization, temporarily disabled
//func isAncBranch(n *node) bool {
// func isAncBranch(n *node) bool {
// switch n.anc.kind {
// case If0, If1, If2, If3:
// return true
// }
// return false
//}
// }
func childPos(n *node) int {
for i, c := range n.anc.child {
@@ -1966,6 +1976,20 @@ func (n *node) isInteger() bool {
return true
}
}
if isConstantValue(t) {
c := n.rval.Interface().(constant.Value)
switch c.Kind() {
case constant.Int:
return true
case constant.Float:
f, _ := constant.Float64Val(c)
if f == math.Trunc(f) {
n.rval = reflect.ValueOf(constant.ToInt(c))
n.typ.rtype = n.rval.Type()
return true
}
}
}
}
return false
}
@@ -1993,6 +2017,23 @@ func (n *node) isNatural() bool {
return true
}
}
if isConstantValue(t) {
c := n.rval.Interface().(constant.Value)
switch c.Kind() {
case constant.Int:
i, _ := constant.Int64Val(c)
if i >= 0 {
return true
}
case constant.Float:
f, _ := constant.Float64Val(c)
if f == math.Trunc(f) {
n.rval = reflect.ValueOf(constant.ToInt(c))
n.typ.rtype = n.rval.Type()
return true
}
}
}
}
return false
}

View File

@@ -40,8 +40,8 @@ func TestEvalArithmetic(t *testing.T) {
{desc: "sub_FI", src: "7.2 - 3", res: "4.2"},
{desc: "sub_IF", src: "7 - 3.2", res: "3.8"},
{desc: "mul_II", src: "2 * 3", res: "6"},
{desc: "mul_FI", src: "2.2 * 3", res: "6.6000000000000005"},
{desc: "mul_IF", src: "3 * 2.2", res: "6.6000000000000005"},
{desc: "mul_FI", src: "2.2 * 3", res: "6.6"},
{desc: "mul_IF", src: "3 * 2.2", res: "6.6"},
{desc: "rem_FI", src: "8.2 % 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"},

View File

@@ -2,7 +2,11 @@ package interp
// Code generated by 'go run ../internal/genop/genop.go'. DO NOT EDIT.
import "reflect"
import (
"go/constant"
"go/token"
"reflect"
)
// Arithmetic operators
@@ -150,9 +154,16 @@ func add(n *node) {
func addConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.ADD, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isString(t):
n.rval.SetString(v0.String() + v1.String())
case isComplex(t):
@@ -234,9 +245,16 @@ func and(n *node) {
func andConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.AND, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) & vUint(v1))
case isInt(t):
@@ -312,9 +330,16 @@ func andNot(n *node) {
func andNotConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.AND_NOT, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) &^ vUint(v1))
case isInt(t):
@@ -442,9 +467,16 @@ func mul(n *node) {
func mulConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.MUL, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isComplex(t):
n.rval.SetComplex(vComplex(v0) * vComplex(v1))
case isFloat(t):
@@ -524,9 +556,16 @@ func or(n *node) {
func orConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.OR, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) | vUint(v1))
case isInt(t):
@@ -654,9 +693,16 @@ func quo(n *node) {
func quoConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.QUO, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isComplex(t):
n.rval.SetComplex(vComplex(v0) / vComplex(v1))
case isFloat(t):
@@ -736,9 +782,16 @@ func rem(n *node) {
func remConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.REM, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) % vUint(v1))
case isInt(t):
@@ -814,9 +867,17 @@ func shl(n *node) {
func shlConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
s, _ := constant.Uint64Val(vConstantValue(v1))
v := constant.Shift(vConstantValue(v0), token.SHL, uint(s))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) << vUint(v1))
case isInt(t):
@@ -892,9 +953,17 @@ func shr(n *node) {
func shrConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
s, _ := constant.Uint64Val(vConstantValue(v1))
v := constant.Shift(vConstantValue(v0), token.SHR, uint(s))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) >> vUint(v1))
case isInt(t):
@@ -1022,9 +1091,16 @@ func sub(n *node) {
func subConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.SUB, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isComplex(t):
n.rval.SetComplex(vComplex(v0) - vComplex(v1))
case isFloat(t):
@@ -1104,9 +1180,16 @@ func xor(n *node) {
func xorConst(n *node) {
v0, v1 := n.child[0].rval, n.child[1].rval
isConst := (v0.IsValid() && isConstantValue(v0.Type())) && (v1.IsValid() && isConstantValue(v1.Type()))
t := n.typ.rtype
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch {
case isConst:
v := constant.BinaryOp(vConstantValue(v0), token.XOR, vConstantValue(v1))
n.rval.Set(reflect.ValueOf(v))
case isUint(t):
n.rval.SetUint(vUint(v0) ^ vUint(v1))
case isInt(t):
@@ -1865,53 +1948,83 @@ func inc(n *node) {
}
func bitNotConst(n *node) {
v0 := n.child[0].rval
isConst := v0.IsValid() && isConstantValue(v0.Type())
t := n.typ.rtype
v := n.child[0].rval
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(^v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(^v.Uint())
switch {
case isConst:
v := constant.UnaryOp(token.XOR, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
case isInt(t):
n.rval.SetInt(^v0.Int())
case isUint(t):
n.rval.SetUint(^v0.Uint())
}
}
func negConst(n *node) {
v0 := n.child[0].rval
isConst := v0.IsValid() && isConstantValue(v0.Type())
t := n.typ.rtype
v := n.child[0].rval
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(-v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(-v.Uint())
case reflect.Float32, reflect.Float64:
n.rval.SetFloat(-v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex(-v.Complex())
switch {
case isConst:
v := constant.UnaryOp(token.SUB, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
case isInt(t):
n.rval.SetInt(-v0.Int())
case isUint(t):
n.rval.SetUint(-v0.Uint())
case isFloat(t):
n.rval.SetFloat(-v0.Float())
case isComplex(t):
n.rval.SetComplex(-v0.Complex())
}
}
func notConst(n *node) {
v0 := n.child[0].rval
isConst := v0.IsValid() && isConstantValue(v0.Type())
t := n.typ.rtype
v := n.child[0].rval
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
n.rval.SetBool(!v.Bool())
if isConst {
v := constant.UnaryOp(token.NOT, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
} else {
n.rval.SetBool(!v0.Bool())
}
}
func posConst(n *node) {
v0 := n.child[0].rval
isConst := v0.IsValid() && isConstantValue(v0.Type())
t := n.typ.rtype
v := n.child[0].rval
if isConst {
t = constVal
}
n.rval = reflect.New(t).Elem()
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n.rval.SetInt(+v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.rval.SetUint(+v.Uint())
case reflect.Float32, reflect.Float64:
n.rval.SetFloat(+v.Float())
case reflect.Complex64, reflect.Complex128:
n.rval.SetComplex(+v.Complex())
switch {
case isConst:
v := constant.UnaryOp(token.ADD, vConstantValue(v0), 0)
n.rval.Set(reflect.ValueOf(v))
case isInt(t):
n.rval.SetInt(+v0.Int())
case isUint(t):
n.rval.SetUint(+v0.Uint())
case isFloat(t):
n.rval.SetFloat(+v0.Float())
case isComplex(t):
n.rval.SetComplex(+v0.Complex())
}
}

View File

@@ -4,6 +4,7 @@ package interp
import (
"fmt"
"go/constant"
"log"
"reflect"
)
@@ -1204,6 +1205,7 @@ func getIndexMap(n *node) {
z := reflect.New(n.child[0].typ.frameType().Elem()).Elem()
if n.child[1].rval.IsValid() { // constant map index
convertConstantValue(n.child[1])
mi := n.child[1].rval
switch {
@@ -1297,6 +1299,7 @@ func getIndexMap2(n *node) {
return
}
if n.child[1].rval.IsValid() { // constant map index
convertConstantValue(n.child[1])
mi := n.child[1].rval
switch {
case !doValue:
@@ -2632,6 +2635,9 @@ func convertLiteralValue(n *node, t reflect.Type) {
// Skip non-constant values, undefined target type or interface target type.
case n.rval.IsValid():
// Convert constant value to target type.
if n.typ != nil {
convertConstantValue(n)
}
n.rval = n.rval.Convert(t)
default:
// Create a zero value of target type.
@@ -2639,6 +2645,111 @@ func convertLiteralValue(n *node, t reflect.Type) {
}
}
func convertConstantValue(n *node) {
if !n.rval.IsValid() {
return
}
c, ok := n.rval.Interface().(constant.Value)
if !ok {
return
}
t := n.typ
for t != nil && t.cat == aliasT {
// If it is an alias, get the actual type
t = t.val
}
v := n.rval
switch t.cat {
case intT, int8T, int16T, int32T, int64T:
i, _ := constant.Int64Val(c)
l := constant.BitLen(c)
switch t.cat {
case intT:
if l > 64 {
panic(fmt.Sprintf("constant %s overflows int", c.ExactString()))
}
v = reflect.ValueOf(int(i))
case int8T:
if l > 8 {
panic(fmt.Sprintf("constant %s overflows int8", c.ExactString()))
}
v = reflect.ValueOf(int8(i))
case int16T:
if l > 16 {
panic(fmt.Sprintf("constant %s overflows int16", c.ExactString()))
}
v = reflect.ValueOf(int16(i))
case int32T:
if l > 32 {
panic(fmt.Sprintf("constant %s overflows int32", c.ExactString()))
}
v = reflect.ValueOf(int32(i))
case int64T:
if l > 64 {
panic(fmt.Sprintf("constant %s overflows int64", c.ExactString()))
}
v = reflect.ValueOf(i)
}
case uintT, uint8T, uint16T, uint32T, uint64T:
i, _ := constant.Uint64Val(c)
l := constant.BitLen(c)
switch t.cat {
case uintT:
if l > 64 {
panic(fmt.Sprintf("constant %s overflows uint", c.ExactString()))
}
v = reflect.ValueOf(uint(i))
case uint8T:
if l > 8 {
panic(fmt.Sprintf("constant %s overflows uint8", c.ExactString()))
}
v = reflect.ValueOf(uint8(i))
case uint16T:
if l > 16 {
panic(fmt.Sprintf("constant %s overflows uint16", c.ExactString()))
}
v = reflect.ValueOf(uint16(i))
case uint32T:
if l > 32 {
panic(fmt.Sprintf("constant %s overflows uint32", c.ExactString()))
}
v = reflect.ValueOf(uint32(i))
case uint64T:
if l > 64 {
panic(fmt.Sprintf("constant %s overflows uint64", c.ExactString()))
}
v = reflect.ValueOf(i)
case uintptrT:
if l > 64 {
panic(fmt.Sprintf("constant %s overflows uintptr", c.ExactString()))
}
v = reflect.ValueOf(i)
}
case float32T:
f, _ := constant.Float32Val(c)
v = reflect.ValueOf(f)
case float64T:
f, _ := constant.Float64Val(c)
v = reflect.ValueOf(f)
case complex64T:
r, _ := constant.Float32Val(constant.Real(c))
i, _ := constant.Float32Val(constant.Imag(c))
v = reflect.ValueOf(complex(r, i))
case complex128T:
r, _ := constant.Float64Val(constant.Real(c))
i, _ := constant.Float64Val(constant.Imag(c))
v = reflect.ValueOf(complex(r, i))
case boolT:
b := constant.BoolVal(c)
v = reflect.ValueOf(b)
case stringT:
s := constant.StringVal(c)
v = reflect.ValueOf(s)
}
n.rval = v
}
// Write to a channel
func send(n *node) {
next := getExec(n.tnext)

View File

@@ -1,6 +1,8 @@
package interp
import (
"fmt"
"go/constant"
"reflect"
"strconv"
)
@@ -152,10 +154,16 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
case arrayType:
t.cat = arrayT
if len(n.child) > 1 {
v := n.child[0].rval
switch {
case n.child[0].rval.IsValid():
case v.IsValid():
// constant size
t.size = int(n.child[0].rval.Int())
if isConstantValue(v.Type()) {
c := v.Interface().(constant.Value)
t.size = constToInt(c)
} else {
t.size = int(v.Int())
}
case n.child[0].kind == ellipsisExpr:
// [...]T expression
t.size = arrayTypeLen(n.anc)
@@ -165,6 +173,8 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
if sym.typ != nil && sym.typ.cat == intT {
if v, ok := sym.rval.Interface().(int); ok {
t.size = v
} else if c, ok := sym.rval.Interface().(constant.Value); ok {
t.size = constToInt(c)
} else {
t.incomplete = true
}
@@ -231,6 +241,23 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.cat = stringT
t.name = "string"
t.untyped = true
case constant.Value:
switch v.Kind() {
case constant.Int:
t.cat = intT
t.name = "int"
t.untyped = true
case constant.Float:
t.cat = float64T
t.name = "float64"
t.untyped = true
case constant.Complex:
t.cat = complex128T
t.name = "complex128"
t.untyped = true
default:
err = n.cfgErrorf("missing support for type %v", n.rval)
}
default:
err = n.cfgErrorf("missing support for type %T: %v", v, n.rval)
}
@@ -1063,6 +1090,7 @@ func exportName(s string) string {
}
var interf = reflect.TypeOf((*interface{})(nil)).Elem()
var constVal = reflect.TypeOf((*constant.Value)(nil)).Elem()
// RefType returns a reflect.Type representation from an interpereter type.
// In simple cases, reflect types are directly mapped from the interpreter
@@ -1198,6 +1226,14 @@ func (t *itype) implements(it *itype) bool {
return t.methods().contains(it.methods())
}
func constToInt(c constant.Value) int {
if constant.BitLen(c) > 64 {
panic(fmt.Sprintf("constant %s overflows int64", c.ExactString()))
}
i, _ := constant.Int64Val(c)
return int(i)
}
func defRecvType(n *node) *itype {
if n.kind != funcDecl || len(n.child[0].child) == 0 {
return nil
@@ -1311,5 +1347,8 @@ func isByteArray(t reflect.Type) bool {
func isFloat32(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float32 }
func isFloat64(t reflect.Type) bool { return t != nil && t.Kind() == reflect.Float64 }
func isNumber(t reflect.Type) bool { return isInt(t) || isFloat(t) || isComplex(t) }
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
func isNumber(t reflect.Type) bool {
return isInt(t) || isFloat(t) || isComplex(t) || isConstantValue(t)
}
func isString(t reflect.Type) bool { return t != nil && t.Kind() == reflect.String }
func isConstantValue(t reflect.Type) bool { return t != nil && t.Implements(constVal) }

View File

@@ -1,6 +1,7 @@
package interp
import (
"go/constant"
"reflect"
)
@@ -96,6 +97,7 @@ func genValueAs(n *node, t reflect.Type) func(*frame) reflect.Value {
func genValue(n *node) func(*frame) reflect.Value {
switch n.kind {
case basicLit:
convertConstantValue(n)
v := n.rval
if !v.IsValid() {
v = reflect.New(interf).Elem()
@@ -111,6 +113,7 @@ func genValue(n *node) func(*frame) reflect.Value {
return func(f *frame) reflect.Value { return v }
default:
if n.rval.IsValid() {
convertConstantValue(n)
v := n.rval
return func(f *frame) reflect.Value { return v }
}
@@ -277,6 +280,10 @@ func vInt(v reflect.Value) (i int64) {
case reflect.Complex64, reflect.Complex128:
i = int64(real(v.Complex()))
}
if v.Type().Implements(constVal) {
c := v.Interface().(constant.Value)
i, _ = constant.Int64Val(constant.ToInt(c))
}
return
}
@@ -291,6 +298,11 @@ func vUint(v reflect.Value) (i uint64) {
case reflect.Complex64, reflect.Complex128:
i = uint64(real(v.Complex()))
}
if v.Type().Implements(constVal) {
c := v.Interface().(constant.Value)
iv, _ := constant.Int64Val(constant.ToInt(c))
i = uint64(iv)
}
return
}
@@ -305,6 +317,13 @@ func vComplex(v reflect.Value) (c complex128) {
case reflect.Complex64, reflect.Complex128:
c = v.Complex()
}
if v.Type().Implements(constVal) {
con := v.Interface().(constant.Value)
con = constant.ToComplex(con)
rel, _ := constant.Float64Val(constant.Real(con))
img, _ := constant.Float64Val(constant.Imag(con))
c = complex(rel, img)
}
return
}
@@ -319,6 +338,17 @@ func vFloat(v reflect.Value) (i float64) {
case reflect.Complex64, reflect.Complex128:
i = real(v.Complex())
}
if v.Type().Implements(constVal) {
c := v.Interface().(constant.Value)
i, _ = constant.Float64Val(constant.ToFloat(c))
}
return
}
func vConstantValue(v reflect.Value) (c constant.Value) {
if v.Type().Implements(constVal) {
c = v.Interface().(constant.Value)
}
return
}