Skip to content

Commit

Permalink
Merge branch 'master' into bugfix/mismatch-assign-panic
Browse files Browse the repository at this point in the history
  • Loading branch information
mvertes authored Jul 19, 2024
2 parents d44bdad + 94de0aa commit f4b4d84
Show file tree
Hide file tree
Showing 196 changed files with 1,234 additions and 3,262 deletions.
51 changes: 51 additions & 0 deletions _test/issue-1618.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"fmt"
"runtime"
"sync"
)

func humanizeBytes(bytes uint64) string {
const (
_ = iota
kB uint64 = 1 << (10 * iota)
mB
gB
tB
pB
)

switch {
case bytes < kB:
return fmt.Sprintf("%dB", bytes)
case bytes < mB:
return fmt.Sprintf("%.2fKB", float64(bytes)/float64(kB))
case bytes < gB:
return fmt.Sprintf("%.2fMB", float64(bytes)/float64(mB))
case bytes < tB:
return fmt.Sprintf("%.2fGB", float64(bytes)/float64(gB))
case bytes < pB:
return fmt.Sprintf("%.2fTB", float64(bytes)/float64(tB))
default:
return fmt.Sprintf("%dB", bytes)
}
}

func main() {
i := 0
wg := sync.WaitGroup{}

for {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("#%d: alloc = %s, routines = %d, gc = %d\n", i, humanizeBytes(m.Alloc), runtime.NumGoroutine(), m.NumGC)

wg.Add(1)
go func() {
wg.Done()
}()
wg.Wait()
i = i + 1
}
}
23 changes: 23 additions & 0 deletions _test/issue-1640.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"errors"
)

func ShortVariableDeclarations() (i int, err error) {
r, err := 1, errors.New("test")
i = r
return
}

func main() {
_, er := ShortVariableDeclarations()
if er != nil {
println("ShortVariableDeclarations ok")
} else {
println("ShortVariableDeclarations not ok")
}
}

// Output:
// ShortVariableDeclarations ok
13 changes: 13 additions & 0 deletions _test/map31.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

func main() {
myMap := map[string]int{"a":2}

for s, _ := range myMap {
_ = s
}
println("ok")
}

// Output:
// ok
4 changes: 2 additions & 2 deletions extract/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ func init() {
if W.WString == nil {
return ""
}
{{end -}}
{{$m.Ret}} W.W{{$m.Name}}{{$m.Arg}}
{{end}}
{{- $m.Ret}} W.W{{$m.Name}}{{$m.Arg -}}
}
{{end}}
{{end}}
Expand Down
7 changes: 5 additions & 2 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
var k, v, o *node
if len(n.anc.child) == 4 {
k, v, o = n.anc.child[0], n.anc.child[1], n.anc.child[2]
if v.ident == "_" {
v = nil // Do not assign to _ value.
}
} else {
k, o = n.anc.child[0], n.anc.child[1]
}
Expand Down Expand Up @@ -659,7 +662,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
var sym *symbol
var level int

if dest.rval.IsValid() && isConstType(dest.typ) {
if dest.rval.IsValid() && !dest.rval.CanSet() && isConstType(dest.typ) {
err = n.cfgErrorf("cannot assign to %s (%s constant)", dest.rval, dest.typ.str)
break
}
Expand All @@ -686,7 +689,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
if dest.typ.incomplete {
return
}
if sc.global {
if sc.global || sc.isRedeclared(dest) {
// Do not overload existing symbols (defined in GTA) in global scope.
sym, _, _ = sc.lookup(dest.ident)
}
Expand Down
4 changes: 0 additions & 4 deletions interp/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,6 @@ func (dbg *Debugger) enterCall(nFunc, nCall *node, f *frame) {
switch nFunc.kind {
case funcLit:
f.debug.kind = frameCall
if nFunc.frame != nil {
nFunc.frame.debug.kind = frameClosure
nFunc.frame.debug.node = nFunc
}

case funcDecl:
f.debug.kind = frameCall
Expand Down
11 changes: 3 additions & 8 deletions interp/interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ type node struct {
tnext *node // true branch successor (CFG)
fnext *node // false branch successor (CFG)
interp *Interpreter // interpreter context
frame *frame // frame pointer used for closures only (TODO: suppress this)
index int64 // node index (dot display)
findex int // index of value in frame or frame size (func def, type def)
level int // number of frame indirections to access value
Expand Down Expand Up @@ -138,7 +137,7 @@ func newFrame(anc *frame, length int, id uint64) *frame {

func (f *frame) runid() uint64 { return atomic.LoadUint64(&f.id) }
func (f *frame) setrunid(id uint64) { atomic.StoreUint64(&f.id, id) }
func (f *frame) clone(fork bool) *frame {
func (f *frame) clone() *frame {
f.mutex.RLock()
defer f.mutex.RUnlock()
nf := &frame{
Expand All @@ -150,12 +149,8 @@ func (f *frame) clone(fork bool) *frame {
done: f.done,
debug: f.debug,
}
if fork {
nf.data = make([]reflect.Value, len(f.data))
copy(nf.data, f.data)
} else {
nf.data = f.data
}
nf.data = make([]reflect.Value, len(f.data))
copy(nf.data, f.data)
return nf
}

Expand Down
1 change: 1 addition & 0 deletions interp/interp_consistent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "time0.go" || // display time (similar to random number)
file.Name() == "factor.go" || // bench
file.Name() == "fib.go" || // bench
file.Name() == "issue-1618.go" || // bench (infinite running)

file.Name() == "type5.go" || // used to illustrate a limitation with no workaround, related to the fact that the reflect package does not allow the creation of named types
file.Name() == "type6.go" || // used to illustrate a limitation with no workaround, related to the fact that the reflect package does not allow the creation of named types
Expand Down
24 changes: 24 additions & 0 deletions interp/interp_eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1906,3 +1906,27 @@ func TestIssue1383(t *testing.T) {
t.Fatal(err)
}
}

func TestIssue1623(t *testing.T) {
var f float64
var j int
var s string = "foo"

i := interp.New(interp.Options{})
if err := i.Use(interp.Exports{
"pkg/pkg": map[string]reflect.Value{
"F": reflect.ValueOf(&f).Elem(),
"J": reflect.ValueOf(&j).Elem(),
"S": reflect.ValueOf(&s).Elem(),
},
}); err != nil {
t.Fatal(err)
}
i.ImportUsed()

runTests(t, i, []testCase{
{desc: "pkg.F = 2.0", src: "pkg.F = 2.0; pkg.F", res: "2"},
{desc: "pkg.J = 3", src: "pkg.J = 3; pkg.J", res: "3"},
{desc: `pkg.S = "bar"`, src: `pkg.S = "bar"; pkg.S`, res: "bar"},
})
}
66 changes: 30 additions & 36 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -988,9 +988,6 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
funcType := n.typ.TypeOf()

return func(f *frame) reflect.Value {
if n.frame != nil { // Use closure context if defined.
f = n.frame
}
return reflect.MakeFunc(funcType, func(in []reflect.Value) []reflect.Value {
// Allocate and init local frame. All values to be settable and addressable.
fr := newFrame(f, len(def.types), f.runid())
Expand Down Expand Up @@ -1292,14 +1289,13 @@ func call(n *node) {
}

n.exec = func(f *frame) bltn {
var def *node
var ok bool

f.mutex.Lock()
bf := value(f)

if def, ok = bf.Interface().(*node); ok {
def, ok := bf.Interface().(*node)
if ok {
bf = def.rval
}
f.mutex.Unlock()

// Call bin func if defined
if bf.IsValid() {
Expand Down Expand Up @@ -1343,12 +1339,7 @@ func call(n *node) {
return tnext
}

anc := f
// Get closure frame context (if any)
if def.frame != nil {
anc = def.frame
}
nf := newFrame(anc, len(def.types), anc.runid())
nf := newFrame(f, len(def.types), f.runid())
var vararg reflect.Value

// Init return values
Expand Down Expand Up @@ -1409,6 +1400,13 @@ func call(n *node) {
}
runCfg(def.child[3].start, nf, def, n)

// Set return values
for i, v := range rvalues {
if v != nil {
v(f).Set(nf.data[i])
}
}

// Handle branching according to boolean result
if fnext != nil && !nf.data[0].Bool() {
return fnext
Expand Down Expand Up @@ -1887,27 +1885,22 @@ func getIndexMap2(n *node) {
}
}

const fork = true // Duplicate frame in frame.clone().

// getFunc compiles a closure function generator for anonymous functions.
func getFunc(n *node) {
i := n.findex
l := n.level
next := getExec(n.tnext)
numRet := len(n.typ.ret)

n.exec = func(f *frame) bltn {
fr := f.clone(fork)
nod := *n
nod.val = &nod
nod.frame = fr
def := &nod
numRet := len(def.typ.ret)
fr := f.clone()
o := getFrame(f, l).data[i]

fct := reflect.MakeFunc(nod.typ.TypeOf(), func(in []reflect.Value) []reflect.Value {
fct := reflect.MakeFunc(n.typ.TypeOf(), func(in []reflect.Value) []reflect.Value {
// Allocate and init local frame. All values to be settable and addressable.
fr2 := newFrame(fr, len(def.types), fr.runid())
fr2 := newFrame(fr, len(n.types), fr.runid())
d := fr2.data
for i, t := range def.types {
for i, t := range n.types {
d[i] = reflect.New(t).Elem()
}
d = d[numRet:]
Expand All @@ -1918,7 +1911,7 @@ func getFunc(n *node) {
// In case of unused arg, there may be not even a frame entry allocated, just skip.
break
}
typ := def.typ.arg[i]
typ := n.typ.arg[i]
switch {
case isEmptyInterface(typ) || typ.TypeOf() == valueInterfaceType:
d[i].Set(arg)
Expand All @@ -1930,12 +1923,19 @@ func getFunc(n *node) {
}

// Interpreter code execution.
runCfg(def.child[3].start, fr2, def, n)
runCfg(n.child[3].start, fr2, n, n)

f.mutex.Lock()
getFrame(f, l).data[i] = o
f.mutex.Unlock()

return fr2.data[:numRet]
})

f.mutex.Lock()
getFrame(f, l).data[i] = fct
f.mutex.Unlock()

return next
}
}
Expand All @@ -1946,11 +1946,9 @@ func getMethod(n *node) {
next := getExec(n.tnext)

n.exec = func(f *frame) bltn {
fr := f.clone(!fork)
nod := *(n.val.(*node))
nod.val = &nod
nod.recv = n.recv
nod.frame = fr
getFrame(f, l).data[i] = genFuncValue(&nod)(f)
return next
}
Expand Down Expand Up @@ -2021,11 +2019,9 @@ func getMethodByName(n *node) {
panic(n.cfgErrorf("method not found: %s", name))
}

fr := f.clone(!fork)
nod := *m
nod.val = &nod
nod.recv = &receiver{nil, val.value, li}
nod.frame = fr
getFrame(f, l).data[i] = genFuncValue(&nod)(f)
return next
}
Expand Down Expand Up @@ -2912,11 +2908,10 @@ func rangeMap(n *node) {
index2 := index0 - 1 // iterator for range, always just behind index0
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
value := genValue(n.child[len(n.child)-2]) // map value

var value func(*frame) reflect.Value
if len(n.child) == 4 {
index1 := n.child[1].findex // map value location in frame
value = genValue(n.child[2]) // map
if len(n.child) == 4 && n.child[1].ident != "_" {
index1 := n.child[1].findex // map value location in frame
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
Expand All @@ -2927,7 +2922,6 @@ func rangeMap(n *node) {
return tnext
}
} else {
value = genValue(n.child[1]) // map
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
Expand Down
8 changes: 8 additions & 0 deletions interp/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ func (s *scope) lookup(ident string) (*symbol, int, bool) {
return nil, 0, false
}

func (s *scope) isRedeclared(n *node) bool {
if !isNewDefine(n, s) {
return false
}
// Existing symbol in the scope indicates a redeclaration.
return s.sym[n.ident] != nil
}

func (s *scope) rangeChanType(n *node) *itype {
if sym, _, found := s.lookup(n.child[1].ident); found {
if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {
Expand Down
Loading

0 comments on commit f4b4d84

Please sign in to comment.