Skip to content

Commit

Permalink
interp: fix type in assign of shift operations
Browse files Browse the repository at this point in the history
Type checking on shift operands was failing for untyped variable values.

Fix propagation of type in assignment. Optimize assignment of arithmetic
operations on variables by skipping the assign and writing directly to
destination frame value in the operator function.

Skip some slow tests when given -short test option.

Fixes #917.
  • Loading branch information
mvertes committed Oct 23, 2020
1 parent d47821b commit 9520a92
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
15 changes: 15 additions & 0 deletions _test/assign16.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

type H struct {
bits uint
}

func main() {
h := &H{8}
var x uint = (1 << h.bits) >> 6

println(x)
}

// Output:
// 4
10 changes: 6 additions & 4 deletions _test/select1.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package main

import "time"
import "fmt"
import (
"fmt"
"time"
)

func main() {
c1 := make(chan string)
c2 := make(chan string)

go func() {
time.Sleep(1e9)
time.Sleep(1e7)
c1 <- "one"
}()
go func() {
time.Sleep(2e9)
time.Sleep(2e7)
c2 <- "two"
}()

Expand Down
18 changes: 18 additions & 0 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.gen = nop
src.findex = dest.findex
src.level = level
case n.action == aAssign && len(n.child) < 4 && !src.rval.IsValid() && isArithmeticAction(src):
// Optimize single assignments from some arithmetic operations.
// Skip the assign operation entirely, the source frame index is set
// to destination index, avoiding extra memory alloc and duplication.
src.typ = dest.typ
src.findex = dest.findex
src.level = level
n.gen = nop
case src.kind == basicLit && !src.rval.IsValid():
// Assign to nil.
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
Expand Down Expand Up @@ -2449,3 +2457,13 @@ func isValueUntyped(v reflect.Value) bool {
}
return t.String() == t.Kind().String()
}

// isArithmeticAction returns true if the node action is an arithmetic operator.
func isArithmeticAction(n *node) bool {
switch n.action {
case aAdd, aAnd, aAndNot, aBitNot, aMul, aQuo, aRem, aShl, aShr, aSub, aXor:
return true
default:
return false
}
}
15 changes: 15 additions & 0 deletions interp/interp_eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,9 @@ func TestConcurrentEvals(t *testing.T) {
// called by EvalWithContext is sequential. And that there is no data race for the
// interp package global vars or the interpreter fields in this case.
func TestConcurrentEvals2(t *testing.T) {
if testing.Short() {
return
}
pin, pout := io.Pipe()
defer func() {
_ = pin.Close()
Expand Down Expand Up @@ -1045,6 +1048,9 @@ func TestConcurrentEvals2(t *testing.T) {
// - when calling Interpreter.Use, the symbols given as argument should be
// copied when being inserted into interp.binPkg, and not directly used as-is.
func TestConcurrentEvals3(t *testing.T) {
if testing.Short() {
return
}
allDone := make(chan bool)
runREPL := func() {
done := make(chan error)
Expand Down Expand Up @@ -1123,6 +1129,9 @@ func TestConcurrentComposite2(t *testing.T) {
}

func testConcurrentComposite(t *testing.T, filePath string) {
if testing.Short() {
return
}
pin, pout := io.Pipe()
i := interp.New(interp.Options{Stdout: pout})
i.Use(stdlib.Symbols)
Expand Down Expand Up @@ -1160,6 +1169,9 @@ func testConcurrentComposite(t *testing.T, filePath string) {
}

func TestEvalScanner(t *testing.T) {
if testing.Short() {
return
}
type testCase struct {
desc string
src []string
Expand Down Expand Up @@ -1333,6 +1345,9 @@ func applyCIMultiplier(timeout time.Duration) time.Duration {
}

func TestREPLDivision(t *testing.T) {
if testing.Short() {
return
}
_ = os.Setenv("YAEGI_PROMPT", "1")
defer func() {
_ = os.Setenv("YAEGI_PROMPT", "0")
Expand Down
2 changes: 1 addition & 1 deletion interp/typecheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (check typecheck) shift(n *node) error {
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()

var v0 constant.Value
if c0.typ.untyped {
if c0.typ.untyped && c0.rval.IsValid() {
v0 = constant.ToInt(c0.rval.Interface().(constant.Value))
c0.rval = reflect.ValueOf(v0)
}
Expand Down

0 comments on commit 9520a92

Please sign in to comment.