Compare commits

...

6 Commits

Author SHA1 Message Date
Marc Vertes
5b62f9fdb6 interp: fix setting of interface value from nested function calls
Fixes #1320 and #1294.
2021-11-30 15:44:05 +01:00
Marc Vertes
4f66e3fe6c interp: fix type switch when the case type is an interpreted interface
Fixes #1315.

With this PR, the package gopkg.in/yaml.v3 works in yaegi (fixes #1296).
2021-11-26 12:24:07 +01:00
Marc Vertes
1335b4c64f stdlib: add wrappers for go/build/constraint package 2021-11-26 12:10:08 +01:00
Marc Vertes
da03c922ca interp: get rid of deprecated stdlib package ioutil
No functional change.
2021-11-26 11:58:07 +01:00
Marc Vertes
9620116c30 interp: replace value.Type().Kind() by value.Kind()
No functional change. Just simpler and faster.
2021-11-26 11:42:07 +01:00
Marc Vertes
dd7197f2a2 interp: fix assign of multiple return function call
A runtime builtin assignFromCall is added to handle multiple values returned at once. It is necessary if some of the values require to be set to interface values in the caller space, which is performed by reflect.Set in assignFromCall.
 
Fixes #1311.
2021-11-19 15:30:05 +01:00
32 changed files with 343 additions and 91 deletions

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net"
"net/http"
@@ -13,7 +13,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net"
"net/http"
@@ -21,7 +21,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -13,7 +13,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -40,7 +40,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -40,7 +40,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"net/http"
"net/http/httptest"
@@ -41,7 +41,7 @@ func client(uri string) {
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,12 +2,11 @@ package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
file, err := ioutil.TempFile("", "yeagibench")
file, err := os.CreateTemp("", "yeagibench")
if err != nil {
panic(err)
}
@@ -23,7 +22,7 @@ func main() {
panic(err)
}
b, err := ioutil.ReadFile(file.Name())
b, err := os.ReadFile(file.Name())
if err != nil {
panic(err)
}

View File

@@ -2,7 +2,7 @@ package main
import (
"fmt"
"io/ioutil"
"io"
"log"
"strings"
)
@@ -10,7 +10,7 @@ import (
func main() {
r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")
b, err := ioutil.ReadAll(r)
b, err := io.ReadAll(r)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,7 +2,6 @@ package main
import (
"io"
"io/ioutil"
"os"
)
@@ -13,7 +12,7 @@ type sink interface {
func newSink() sink {
// return os.Stdout // Stdout is special in yaegi tests
file, err := ioutil.TempFile("", "yaegi-test.*")
file, err := os.CreateTemp("", "yaegi-test.*")
if err != nil {
panic(err)
}

View File

@@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"os"
)
@@ -37,7 +36,7 @@ func (s *Sink2) Close() error { println("in Close", s.name); retu
func newS2(name string) Sink { return Sink1{name} }
func main() {
tmpfile, err := ioutil.TempFile("", "xxx")
tmpfile, err := os.CreateTemp("", "xxx")
if err != nil {
panic(err)
}

19
_test/issue-1311.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T struct {
v interface{}
}
func f() (ret int64, err error) {
ret += 2
return
}
func main() {
t := &T{}
t.v, _ = f()
println(t.v.(int64))
}
// Output:
// 2

32
_test/issue-1315.go Normal file
View File

@@ -0,0 +1,32 @@
package main
type Intf interface {
M()
}
type T struct {
s string
}
func (t *T) M() { println("in M") }
func f(i interface{}) {
switch j := i.(type) {
case Intf:
j.M()
default:
println("default")
}
}
func main() {
var i Intf
var k interface{} = 1
i = &T{"hello"}
f(i)
f(k)
}
// Output:
// in M
// default

29
_test/issue-1320.go Normal file
View File

@@ -0,0 +1,29 @@
package main
type Pooler interface {
Get() string
}
type baseClient struct {
connPool Pooler
}
type connPool struct {
name string
}
func (c *connPool) Get() string { return c.name }
func newBaseClient(i int, p Pooler) *baseClient {
return &baseClient{connPool: p}
}
func newConnPool() *connPool { return &connPool{name: "connPool"} }
func main() {
b := newBaseClient(0, newConnPool())
println(b.connPool.(*connPool).name)
}
// Output:
// connPool

View File

@@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"strings"
)
@@ -36,7 +35,7 @@ type pipe struct {
func newReadAutoCloser(r io.Reader) readAutoCloser {
if _, ok := r.(io.Closer); !ok {
return readAutoCloser{ioutil.NopCloser(r)}
return readAutoCloser{io.NopCloser(r)}
}
return readAutoCloser{r.(io.ReadCloser)}
}
@@ -44,7 +43,7 @@ func newReadAutoCloser(r io.Reader) readAutoCloser {
func main() {
p := &pipe{}
p.Reader = newReadAutoCloser(strings.NewReader("test"))
b, err := ioutil.ReadAll(p.Reader)
b, err := io.ReadAll(p.Reader)
if err != nil {
log.Fatal(err)
}

View File

@@ -2,11 +2,11 @@ package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
_, err := ioutil.ReadFile("__NotExisting__")
_, err := os.ReadFile("__NotExisting__")
if err != nil {
fmt.Println(err.Error())
}

View File

@@ -4,7 +4,6 @@ import (
"flag"
"fmt"
"go/build"
"io/ioutil"
"os"
"reflect"
"strconv"
@@ -135,7 +134,7 @@ func isFile(path string) bool {
}
func runFile(i *interp.Interpreter, path string, noAutoImport bool) error {
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
if err != nil {
return err
}

View File

@@ -3,7 +3,6 @@ package main
import (
"bytes"
"context"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -38,7 +37,7 @@ func applyCIMultiplier(timeout time.Duration) time.Duration {
}
func TestYaegiCmdCancel(t *testing.T) {
tmp, err := ioutil.TempDir("", "yaegi-")
tmp, err := os.MkdirTemp("", "yaegi-")
if err != nil {
t.Fatalf("failed to create tmp directory: %v", err)
}

View File

@@ -3,8 +3,8 @@ package main
import (
"bytes"
"go/format"
"io/ioutil"
"log"
"os"
"strings"
"text/template"
)
@@ -1183,7 +1183,7 @@ func main() {
log.Fatal(err)
}
if err = ioutil.WriteFile("op.go", source, 0o666); err != nil {
if err = os.WriteFile("op.go", source, 0o666); err != nil {
log.Fatal(err)
}
}

View File

@@ -64,6 +64,9 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
if err != nil {
return false
}
if n.scope == nil {
n.scope = sc
}
switch n.kind {
case binaryExpr, unaryExpr, parenExpr:
if isBoolAction(n) {
@@ -662,7 +665,12 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
if r := lc.child[0].typ.numOut(); r != l {
err = n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, lc.child[0].name(), r)
}
n.gen = nop
if isBinCall(lc, sc) {
n.gen = nop
} else {
// TODO (marc): skip if no conversion or wrapping is needed.
n.gen = assignFromCall
}
case indexExpr:
lc.gen = getIndexMap2
n.gen = nop
@@ -970,7 +978,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
n.typ = c0.typ
n.findex = sc.add(n.typ)
}
case isBinCall(n):
case isBinCall(n, sc):
err = check.arguments(n, n.child[1:], n.child[0], n.action == aCallSlice)
if err != nil {
break
@@ -2019,7 +2027,12 @@ func compDefineX(sc *scope, n *node) error {
if len(types) != l {
return n.cfgErrorf("assignment mismatch: %d variables but %s returns %d values", l, src.child[0].name(), len(types))
}
n.gen = nop
if isBinCall(src, sc) {
n.gen = nop
} else {
// TODO (marc): skip if no conversion or wrapping is needed.
n.gen = assignFromCall
}
case indexExpr:
types = append(types, src.typ, sc.getType("bool"))
@@ -2468,8 +2481,19 @@ func isCall(n *node) bool {
return n.action == aCall || n.action == aCallSlice
}
func isBinCall(n *node) bool {
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
func isBinCall(n *node, sc *scope) bool {
if !isCall(n) || len(n.child) == 0 {
return false
}
c0 := n.child[0]
if c0.typ == nil {
// If called early in parsing, child type may not be known yet.
c0.typ, _ = nodeType(n.interp, sc, c0)
if c0.typ == nil {
return false
}
}
return c0.typ.cat == valueT && c0.typ.rtype.Kind() == reflect.Func
}
func isOffsetof(n *node) bool {

View File

@@ -3,7 +3,6 @@ package interp
import (
"fmt"
"io"
"io/ioutil"
"log"
"os/exec"
"path/filepath"
@@ -69,7 +68,7 @@ func (nopCloser) Close() error { return nil }
// dotWriter returns an output stream to a dot(1) co-process where to write data in .dot format.
func dotWriter(dotCmd string) io.WriteCloser {
if dotCmd == "" {
return nopCloser{ioutil.Discard}
return nopCloser{io.Discard}
}
fields := strings.Fields(dotCmd)
cmd := exec.Command(fields[0], fields[1:]...)

View File

@@ -2,7 +2,7 @@ package interp_test
import (
"go/build"
"io/ioutil"
"io"
"os"
"os/exec"
"path/filepath"
@@ -26,7 +26,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
}
baseDir := filepath.Join("..", "_test")
files, err := ioutil.ReadDir(baseDir)
files, err := os.ReadDir(baseDir)
if err != nil {
t.Fatal(err)
}
@@ -145,7 +145,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
if err = w.Close(); err != nil {
t.Fatal(err)
}
outInterp, err := ioutil.ReadAll(r)
outInterp, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}

View File

@@ -6,7 +6,6 @@ import (
"context"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
@@ -885,7 +884,7 @@ func TestMultiEval(t *testing.T) {
if err = w.Close(); err != nil {
t.Fatal(err)
}
outInterp, err := ioutil.ReadAll(r)
outInterp, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
@@ -916,7 +915,7 @@ func TestMultiEvalNoName(t *testing.T) {
t.Fatal(err)
}
for k, v := range names {
data, err := ioutil.ReadFile(filepath.Join(f.Name(), v))
data, err := os.ReadFile(filepath.Join(f.Name(), v))
if err != nil {
t.Fatal(err)
}

View File

@@ -5,7 +5,6 @@ import (
"go/build"
"go/parser"
"go/token"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -26,7 +25,7 @@ func TestFile(t *testing.T) {
_ = os.Setenv("YAEGI_SPECIAL_STDIO", "1")
baseDir := filepath.Join("..", "_test")
files, err := ioutil.ReadDir(baseDir)
files, err := os.ReadDir(baseDir)
if err != nil {
t.Fatal(err)
}

View File

@@ -3,7 +3,7 @@ package interp
import (
"context"
"go/ast"
"io/ioutil"
"os"
"reflect"
"runtime"
"runtime/debug"
@@ -28,7 +28,7 @@ func (interp *Interpreter) CompilePath(path string) (*Program, error) {
return nil, err
}
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}

View File

@@ -616,6 +616,34 @@ func convert(n *node) {
}
}
// assignFromCall assigns values from a function call.
func assignFromCall(n *node) {
ncall := n.lastChild()
l := len(n.child) - 1
if n.anc.kind == varDecl && n.child[l-1].isType(n.scope) {
// Ignore the type in the assignment if it is part of a variable declaration.
l--
}
dvalue := make([]func(*frame) reflect.Value, l)
for i := range dvalue {
if n.child[i].ident == "_" {
continue
}
dvalue[i] = genValue(n.child[i])
}
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
for i, v := range dvalue {
if v == nil {
continue
}
s := f.data[ncall.findex+i]
v(f).Set(s)
}
return next
}
}
func assign(n *node) {
next := getExec(n.tnext)
dvalue := make([]func(*frame) reflect.Value, n.nleft)
@@ -957,7 +985,7 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
} else {
// Copy method receiver as first argument.
src, dest := rcvr(f), d[numRet]
sk, dk := src.Type().Kind(), dest.Type().Kind()
sk, dk := src.Kind(), dest.Kind()
switch {
case sk == reflect.Ptr && dk != reflect.Ptr:
dest.Set(src.Elem())
@@ -1097,27 +1125,28 @@ func methodByName(value reflect.Value, name string) reflect.Value {
func call(n *node) {
goroutine := n.anc.kind == goStmt
var method bool
value := genValue(n.child[0])
c0 := n.child[0]
value := genValue(c0)
var values []func(*frame) reflect.Value
recvIndexLater := false
switch {
case n.child[0].recv != nil:
case c0.recv != nil:
// Compute method receiver value.
values = append(values, genValueRecv(n.child[0]))
values = append(values, genValueRecv(c0))
method = true
case len(n.child[0].child) > 0 && n.child[0].child[0].typ != nil && isInterfaceSrc(n.child[0].child[0].typ):
case len(c0.child) > 0 && c0.child[0].typ != nil && isInterfaceSrc(c0.child[0].typ):
recvIndexLater = true
values = append(values, genValueBinRecv(n.child[0], &receiver{node: n.child[0].child[0]}))
values = append(values, genValueBinRecv(c0, &receiver{node: c0.child[0]}))
value = genValueBinMethodOnInterface(n, value)
method = true
case n.child[0].action == aMethod:
case c0.action == aMethod:
// Add a place holder for interface method receiver.
values = append(values, nil)
method = true
}
numRet := len(n.child[0].typ.ret)
numRet := len(c0.typ.ret)
variadic := variadicPos(n)
child := n.child[1:]
tnext := getExec(n.tnext)
@@ -1125,27 +1154,40 @@ func call(n *node) {
// Compute input argument value functions.
for i, c := range child {
var arg *itype
if variadic >= 0 && i >= variadic {
arg = c0.typ.arg[variadic].val
} else {
arg = c0.typ.arg[i]
}
switch {
case isBinCall(c):
case isBinCall(c, c.scope):
// Handle nested function calls: pass returned values as arguments.
numOut := c.child[0].typ.rtype.NumOut()
for j := 0; j < numOut; j++ {
ind := c.findex + j
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
if !isInterfaceSrc(arg) || isEmptyInterface(arg) {
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
continue
}
values = append(values, func(f *frame) reflect.Value {
return reflect.ValueOf(valueInterface{value: f.data[ind]})
})
}
case isRegularCall(c):
// Arguments are return values of a nested function call.
for j := range c.child[0].typ.ret {
cc0 := c.child[0]
for j := range cc0.typ.ret {
ind := c.findex + j
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
if !isInterfaceSrc(arg) || isEmptyInterface(arg) {
values = append(values, func(f *frame) reflect.Value { return f.data[ind] })
continue
}
values = append(values, func(f *frame) reflect.Value {
return reflect.ValueOf(valueInterface{node: cc0.typ.ret[j].node, value: f.data[ind]})
})
}
default:
var arg *itype
if variadic >= 0 && i >= variadic {
arg = n.child[0].typ.arg[variadic].val
} else {
arg = n.child[0].typ.arg[i]
}
if c.kind == basicLit || c.rval.IsValid() {
argType := arg.TypeOf()
convertLiteralValue(c, argType)
@@ -1165,10 +1207,11 @@ func call(n *node) {
}
// Compute output argument value functions.
rtypes := n.child[0].typ.ret
rtypes := c0.typ.ret
rvalues := make([]func(*frame) reflect.Value, len(rtypes))
switch n.anc.kind {
case defineXStmt, assignXStmt:
l := n.level
for i := range rvalues {
c := n.anc.child[i]
switch {
@@ -1177,7 +1220,8 @@ func call(n *node) {
case isInterfaceSrc(c.typ) && !isEmptyInterface(c.typ) && !isInterfaceSrc(rtypes[i]):
rvalues[i] = genValueInterfaceValue(c)
default:
rvalues[i] = genValue(c)
j := n.findex + i
rvalues[i] = func(f *frame) reflect.Value { return getFrame(f, l).data[j] }
}
}
case returnStmt:
@@ -1198,7 +1242,7 @@ func call(n *node) {
if n.anc.kind == deferStmt {
// Store function call in frame for deferred execution.
value = genFunctionWrapper(n.child[0])
value = genFunctionWrapper(c0)
if method {
// The receiver is already passed in the function wrapper, skip it.
values = values[1:]
@@ -1328,7 +1372,7 @@ func call(n *node) {
// The !val.IsZero is to work around a recursive struct zero interface
// issue. Once there is a better way to handle this case, the dest
// can just be set.
if !val.IsZero() || dest[i].Type().Kind() == reflect.Interface {
if !val.IsZero() || dest[i].Kind() == reflect.Interface {
dest[i].Set(val)
}
}
@@ -1404,7 +1448,7 @@ func callBin(n *node) {
}
switch {
case isBinCall(c):
case isBinCall(c, c.scope):
// Handle nested function calls: pass returned values as arguments
numOut := c.child[0].typ.rtype.NumOut()
for j := 0; j < numOut; j++ {
@@ -1566,7 +1610,7 @@ func callBin(n *node) {
}
out := callFn(value(f), in)
for i := 0; i < len(out); i++ {
if out[i].Type().Kind() == reflect.Func {
if out[i].Kind() == reflect.Func {
getFrame(f, n.level).data[n.findex+i] = out[i]
} else {
getFrame(f, n.level).data[n.findex+i].Set(out[i])
@@ -2533,7 +2577,7 @@ func doCompositeBinStruct(n *node, hasType bool) {
}
d := value(f)
switch {
case d.Type().Kind() == reflect.Ptr:
case d.Kind() == reflect.Ptr:
d.Set(s.Addr())
default:
d.Set(s)
@@ -2611,7 +2655,7 @@ func doComposite(n *node, hasType bool, keyed bool) {
}
d := value(f)
switch {
case d.Type().Kind() == reflect.Ptr:
case d.Kind() == reflect.Ptr:
d.Set(a.Addr())
case destInterface:
if len(destType(n).field) > 0 {
@@ -2867,12 +2911,13 @@ func _case(n *node) {
if typ.cat == nilT && v.IsNil() {
return tnext
}
if typ.TypeOf().String() == t.String() {
rtyp := typ.TypeOf()
if rtyp != nil && rtyp.String() == t.String() && implementsInterface(v, typ) {
destValue(f).Set(v.Elem())
return tnext
}
ival := v.Interface()
if ival != nil && typ.TypeOf().String() == reflect.TypeOf(ival).String() {
if ival != nil && rtyp != nil && rtyp.String() == reflect.TypeOf(ival).String() {
destValue(f).Set(v.Elem())
return tnext
}
@@ -2935,6 +2980,22 @@ func _case(n *node) {
}
}
func implementsInterface(v reflect.Value, t *itype) bool {
rt := v.Type()
if t.cat == valueT {
return rt.Implements(t.rtype)
}
vt := &itype{cat: valueT, rtype: rt}
if vt.methods().contains(t.methods()) {
return true
}
vi, ok := v.Interface().(valueInterface)
if !ok {
return false
}
return vi.node != nil && vi.node.typ.methods().contains(t.methods())
}
func appendSlice(n *node) {
dest := genValueOutput(n, n.typ.rtype)
next := getExec(n.tnext)
@@ -3169,7 +3230,7 @@ func _len(n *node) {
val := value
value = func(f *frame) reflect.Value {
v := val(f).Elem()
for v.Type().Kind() == reflect.Ptr {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v

View File

@@ -1,7 +1,6 @@
package interp
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -50,7 +49,7 @@ func Test_effectivePkg(t *testing.T) {
func Test_pkgDir(t *testing.T) {
// create GOPATH
goPath, err := ioutil.TempDir("", "pkdir")
goPath, err := os.MkdirTemp("", "pkdir")
if err != nil {
t.Fatal(err)
}

View File

@@ -850,7 +850,7 @@ func (check typecheck) builtin(name string, n *node, child []*node, ellipsis boo
return params[0].nod.cfgErrorf("first argument to delete must be map; have %s", typ.id())
}
ktyp := params[1].Type()
if !ktyp.assignableTo(typ.key) {
if typ.key != nil && !ktyp.assignableTo(typ.key) {
return params[1].nod.cfgErrorf("cannot use %s as type %s in delete", ktyp.id(), typ.key.id())
}
case bltnMake:

View File

@@ -147,7 +147,7 @@ func genValueAsFunctionWrapper(n *node) func(*frame) reflect.Value {
return reflect.New(typ).Elem()
}
vn, ok := v.Interface().(*node)
if ok && vn.rval.IsValid() && vn.rval.Type().Kind() == reflect.Func {
if ok && vn.rval.Kind() == reflect.Func {
// The node value is already a callable func, no need to wrap it.
return vn.rval
}
@@ -160,7 +160,7 @@ func genValueAs(n *node, t reflect.Type) func(*frame) reflect.Value {
return func(f *frame) reflect.Value {
v := value(f)
switch v.Type().Kind() {
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice, reflect.UnsafePointer:
if v.IsNil() {
return reflect.New(t).Elem()
@@ -338,13 +338,13 @@ func getConcreteValue(val reflect.Value) reflect.Value {
if v.NumMethod() > 0 {
return v
}
if v.Type().Kind() != reflect.Struct {
if v.Kind() != reflect.Struct {
return v
}
// Search a concrete value in fields of an emulated interface.
for i := v.NumField() - 1; i >= 0; i-- {
vv := v.Field(i)
if vv.Type().Kind() == reflect.Interface {
if vv.Kind() == reflect.Interface {
vv = vv.Elem()
}
if vv.IsValid() {
@@ -430,7 +430,7 @@ func vInt(v reflect.Value) (i int64) {
i, _ = constant.Int64Val(constant.ToInt(c))
return i
}
switch v.Type().Kind() {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = v.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -448,7 +448,7 @@ func vUint(v reflect.Value) (i uint64) {
i, _ = constant.Uint64Val(constant.ToInt(c))
return i
}
switch v.Type().Kind() {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = uint64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -468,7 +468,7 @@ func vComplex(v reflect.Value) (c complex128) {
img, _ := constant.Float64Val(constant.Imag(c))
return complex(rel, img)
}
switch v.Type().Kind() {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
c = complex(float64(v.Int()), 0)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -486,7 +486,7 @@ func vFloat(v reflect.Value) (i float64) {
i, _ = constant.Float64Val(constant.ToFloat(c))
return i
}
switch v.Type().Kind() {
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = float64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:

View File

@@ -0,0 +1,48 @@
// Code generated by 'yaegi extract go/build/constraint'. DO NOT EDIT.
// +build go1.16,!go1.17
package stdlib
import (
"go/build/constraint"
"reflect"
)
func init() {
Symbols["go/build/constraint/constraint"] = map[string]reflect.Value{
// function, constant and variable definitions
"IsGoBuild": reflect.ValueOf(constraint.IsGoBuild),
"IsPlusBuild": reflect.ValueOf(constraint.IsPlusBuild),
"Parse": reflect.ValueOf(constraint.Parse),
"PlusBuildLines": reflect.ValueOf(constraint.PlusBuildLines),
// type definitions
"AndExpr": reflect.ValueOf((*constraint.AndExpr)(nil)),
"Expr": reflect.ValueOf((*constraint.Expr)(nil)),
"NotExpr": reflect.ValueOf((*constraint.NotExpr)(nil)),
"OrExpr": reflect.ValueOf((*constraint.OrExpr)(nil)),
"SyntaxError": reflect.ValueOf((*constraint.SyntaxError)(nil)),
"TagExpr": reflect.ValueOf((*constraint.TagExpr)(nil)),
// interface wrapper definitions
"_Expr": reflect.ValueOf((*_go_build_constraint_Expr)(nil)),
}
}
// _go_build_constraint_Expr is an interface wrapper for Expr type
type _go_build_constraint_Expr struct {
IValue interface{}
WEval func(ok func(tag string) bool) bool
WString func() string
}
func (W _go_build_constraint_Expr) Eval(ok func(tag string) bool) bool {
return W.WEval(ok)
}
func (W _go_build_constraint_Expr) String() string {
if W.WString == nil {
return ""
}
return W.WString()
}

View File

@@ -0,0 +1,49 @@
// Code generated by 'yaegi extract go/build/constraint'. DO NOT EDIT.
//go:build go1.17
// +build go1.17
package stdlib
import (
"go/build/constraint"
"reflect"
)
func init() {
Symbols["go/build/constraint/constraint"] = map[string]reflect.Value{
// function, constant and variable definitions
"IsGoBuild": reflect.ValueOf(constraint.IsGoBuild),
"IsPlusBuild": reflect.ValueOf(constraint.IsPlusBuild),
"Parse": reflect.ValueOf(constraint.Parse),
"PlusBuildLines": reflect.ValueOf(constraint.PlusBuildLines),
// type definitions
"AndExpr": reflect.ValueOf((*constraint.AndExpr)(nil)),
"Expr": reflect.ValueOf((*constraint.Expr)(nil)),
"NotExpr": reflect.ValueOf((*constraint.NotExpr)(nil)),
"OrExpr": reflect.ValueOf((*constraint.OrExpr)(nil)),
"SyntaxError": reflect.ValueOf((*constraint.SyntaxError)(nil)),
"TagExpr": reflect.ValueOf((*constraint.TagExpr)(nil)),
// interface wrapper definitions
"_Expr": reflect.ValueOf((*_go_build_constraint_Expr)(nil)),
}
}
// _go_build_constraint_Expr is an interface wrapper for Expr type
type _go_build_constraint_Expr struct {
IValue interface{}
WEval func(ok func(tag string) bool) bool
WString func() string
}
func (W _go_build_constraint_Expr) Eval(ok func(tag string) bool) bool {
return W.WEval(ok)
}
func (W _go_build_constraint_Expr) String() string {
if W.WString == nil {
return ""
}
return W.WString()
}

View File

@@ -32,7 +32,7 @@ func init() {
//go:generate ../internal/cmd/extract/extract encoding/base64 encoding/binary encoding/csv encoding/gob
//go:generate ../internal/cmd/extract/extract encoding/hex encoding/json encoding/pem encoding/xml
//go:generate ../internal/cmd/extract/extract errors expvar flag fmt
//go:generate ../internal/cmd/extract/extract go/ast go/build go/constant go/doc go/format go/importer
//go:generate ../internal/cmd/extract/extract go/ast go/build go/build/constraint go/constant go/doc go/format go/importer
//go:generate ../internal/cmd/extract/extract go/parser go/printer go/scanner go/token go/types
//go:generate ../internal/cmd/extract/extract hash hash/adler32 hash/crc32 hash/crc64 hash/fnv hash/maphash
//go:generate ../internal/cmd/extract/extract html html/template

View File

@@ -31,7 +31,7 @@ func slice(i interface{}, l int) interface{} {
}
v := reflect.ValueOf(i)
if v.Type().Kind() != reflect.Ptr {
if v.Kind() != reflect.Ptr {
panic(errors.New("first argument to unsafe.Slice must be pointer"))
}
if v.IsNil() {