Repository: goplus/gop
Pull request #525 (2020-08-04 15:42:39)

cl: fix unbound const int call interface{} convert to int #514
const int 类型在转换为 interface{} 调用时确定为 int 类型。
Go+ source
```
v := reflect.ValueOf(100)
println(v.Kind())
--------------- output
int
```
generate Golang code
```
package main

import (
	fmt "fmt"
	reflect "reflect"
)

var v reflect.Value

func main() { 
//line ./main.gop:10
	v = reflect.ValueOf(100)
//line ./main.gop:11
	fmt.Println((reflect.Value).Kind(v))
}
```

已知问题：因为目前 const int 使用的是 int64/uint64 存储，所以在 interface{} 调用转换为 int 时检查 overflows 仅在 32 位环境（gophers)下有效，在 64 位下无效。



codecov-commenter: # [Codecov](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=h1) Report
> Merging [#525](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=desc) into [master](https://codecov.io/gh/goplus/gop/commit/d1270b0b8db722e0a11cbcea315ee98664300350&el=desc) will **decrease** coverage by `0.06%`.
> The diff coverage is `60.86%`.

[![Impacted file tree graph](https://codecov.io/gh/goplus/gop/pull/525/graphs/tree.svg?width=650&height=150&src=pr&token=4qln9Wk3Pn)](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #525      +/-   ##
==========================================
- Coverage   89.57%   89.50%   -0.07%     
==========================================
  Files          40       40              
  Lines        9896     9918      +22     
==========================================
+ Hits         8864     8877      +13     
- Misses        758      762       +4     
- Partials      274      279       +5     
```


| [Impacted Files](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [cl/value.go](https://codecov.io/gh/goplus/gop/pull/525/diff?src=pr&el=tree#diff-Y2wvdmFsdWUuZ28=) | `80.78% <60.86%> (-1.85%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=footer). Last update [d1270b0...c302922](https://codecov.io/gh/goplus/gop/pull/525?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/cl/stmt.go b/cl/stmt.go
index 34bfbea5..4930d7bb 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -467,6 +467,14 @@ func compileReturnStmt(ctx *blockCtx, expr *ast.ReturnStmt) {
 
 func compileExprStmt(ctx *blockCtx, expr *ast.ExprStmt) {
 	compileExpr(ctx, expr.X)()
+	if ctx.infer.Len() > 0 {
+		in := ctx.infer.Get(-1)
+		if v, ok := in.(*constVal); ok {
+			for i := 0; i < v.NumValues(); i++ {
+				checkType(exec.TyEmptyInterface, v.Value(i), ctx.out)
+			}
+		}
+	}
 	ctx.infer.PopN(1)
 }
 
diff --git a/cl/value.go b/cl/value.go
index d91fa272..e3be3aa2 100644
--- a/cl/value.go
+++ b/cl/value.go
@@ -17,7 +17,9 @@
 package cl
 
 import (
+	"math"
 	"reflect"
+	"strconv"
 
 	"github.com/goplus/gop/ast/astutil"
 	"github.com/goplus/gop/exec.spec"
@@ -370,6 +372,25 @@ func kindOf(t reflect.Type) exec.Kind {
 	return kind
 }
 
+const (
+	intSize = strconv.IntSize
+)
+
+func isOverflowsIntByInt64(v int64, intSize int) bool {
+	if intSize == 32 {
+		return v < int64(math.MinInt32) || v > int64(math.MaxInt32)
+	}
+	return false
+}
+
+func isOverflowsIntByUint64(v uint64, intSize int) bool {
+	if intSize == 32 {
+		return v > uint64(math.MaxInt32)
+	} else {
+		return v > uint64(math.MaxInt64)
+	}
+}
+
 func boundConst(v interface{}, t reflect.Type) interface{} {
 	kind := kindOf(t)
 	if v == nil {
@@ -383,7 +404,22 @@ func boundConst(v interface{}, t reflect.Type) interface{} {
 	if t == st {
 		return v
 	}
-	if kind == reflect.Complex128 || kind == reflect.Complex64 {
+	if kind == reflect.Interface {
+		skind := sval.Kind()
+		if skind == reflect.Uint64 {
+			v := sval.Uint()
+			if isOverflowsIntByUint64(v, intSize) {
+				log.Panicf("constant %v overflows int\n", v)
+			}
+			return int(v)
+		} else if skind == reflect.Int64 {
+			v := sval.Int()
+			if isOverflowsIntByInt64(v, intSize) {
+				log.Panicf("constant %v overflows int\n", v)
+			}
+			return int(v)
+		}
+	} else if kind == reflect.Complex128 || kind == reflect.Complex64 {
 		if skind := sval.Kind(); skind >= reflect.Int && skind <= reflect.Float64 {
 			fval := sval.Convert(exec.TyFloat64).Float()
 			return complex(fval, 0)
diff --git a/cmd/internal/repl/replcmd.go b/cmd/internal/repl/replcmd.go
index 07c81475..ed458993 100644
--- a/cmd/internal/repl/replcmd.go
+++ b/cmd/internal/repl/replcmd.go
@@ -82,6 +82,9 @@ func runCmd(cmd *base.Command, args []string) {
 			fmt.Printf("Problem reading line: %v\n", err)
 			continue
 		}
+		if line != "" {
+			state.AppendHistory(line)
+		}
 		repl.Run(line)
 	}
 }
diff --git a/repl/repl.go b/repl/repl.go
index d97e15cd..fb92dfac 100644
--- a/repl/repl.go
+++ b/repl/repl.go
@@ -133,6 +133,10 @@ func (r *REPL) run(newLine string) (err error) {
 	// "currentip - 1" is the index of `return`
 	// next time it will replace by new code from newLine
 	r.ip = currentIP - 1
+	size := ctx.Len()
+	for i := 0; i < size; i++ {
+		r.term.Printf("%v\n", ctx.Get(i-size))
+	}
 	return
 }
 


Test patch:
diff --git a/cl/expr_test.go b/cl/expr_test.go
index 15d29d24..5e4c7a18 100644
--- a/cl/expr_test.go
+++ b/cl/expr_test.go
@@ -160,6 +160,40 @@ func TestUnbound(t *testing.T) {
 	)
 }
 
+func TestUnboundInt(t *testing.T) {
+	cltest.Expect(t, `
+	import "reflect"
+	printf("%T",100)
+	`,
+		"int",
+	)
+	cltest.Expect(t, `
+	import "reflect"
+	printf("%T",-100)
+	`,
+		"int",
+	)
+}
+
+func TestOverflowsInt(t *testing.T) {
+	cltest.Expect(t, `
+	println(9223372036854775807)
+	`,
+		"9223372036854775807\n",
+	)
+	cltest.Expect(t, `
+	println(-9223372036854775808)
+	`,
+		"-9223372036854775808\n",
+	)
+	cltest.Expect(t, `
+	println(9223372036854775808)
+	`,
+		"",
+		nil,
+	)
+}
+
 func TestPanic(t *testing.T) {
 	cltest.Expect(t,
 		`panic("Helo")`,
diff --git a/cl/gopkg_test.go b/cl/gopkg_test.go
index 5b5a06f9..038ad3d1 100644
--- a/cl/gopkg_test.go
+++ b/cl/gopkg_test.go
@@ -48,8 +48,8 @@ func TestPkgConst(t *testing.T) {
 		{"Int2", qspec.ConstUnboundInt, 1024},
 		{"Int3", qspec.ConstUnboundInt, -10000000},
 		{"Int4", qspec.ConstUnboundInt, 10000000},
-		{"MinInt64", reflect.Int64, int64(math.MinInt64)},
-		{"MaxUint64", reflect.Uint64, uint64(math.MaxUint64)},
+		{"MinInt64", qspec.ConstUnboundInt, math.MinInt64},
+		{"MaxInt64", qspec.ConstUnboundInt, math.MaxInt64},
 		{"Pi", qspec.ConstUnboundFloat, math.Pi},
 		{"Complex", qspec.ConstUnboundComplex, 1 + 2i},
 	}
diff --git a/cl/value_test.go b/cl/value_test.go
index 3d4a8268..be3222df 100644
--- a/cl/value_test.go
+++ b/cl/value_test.go
@@ -48,4 +48,22 @@ func TestValue(t *testing.T) {
 	_ = c.Value(0)
 }
 
+func TestOverflowsIntBy(t *testing.T) {
+	if isOverflowsIntByInt64(1<<63-1, 64) {
+		t.Fatal("not overflows", 1<<63-1)
+	}
+	if !isOverflowsIntByInt64(1<<31, 32) {
+		t.Fatal("overflows", 1<<31)
+	}
+	if isOverflowsIntByUint64(1<<63-1, 64) {
+		t.Fatal("not overflows", uint64(1<<63-1))
+	}
+	if !isOverflowsIntByUint64(1<<64-1, 64) {
+		t.Fatal("not overflows", uint64(1<<64-1))
+	}
+	if !isOverflowsIntByUint64(1<<32, 32) {
+		t.Fatal("overflows", 1<<32)
+	}
+}
+
 // -----------------------------------------------------------------------------