Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f07f25f1ba | ||
|
|
c93b836c77 | ||
|
|
371103f0d1 | ||
|
|
8bd7afbe62 | ||
|
|
8ea3a493f4 | ||
|
|
f2abd346c0 | ||
|
|
c784713aca | ||
|
|
14acf618af | ||
|
|
fbee2baf9d | ||
|
|
2819b4167b | ||
|
|
2af660cb1f | ||
|
|
8323068414 | ||
|
|
5b62f9fdb6 | ||
|
|
4f66e3fe6c | ||
|
|
1335b4c64f | ||
|
|
da03c922ca | ||
|
|
9620116c30 | ||
|
|
dd7197f2a2 |
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
19
_test/issue-1311.go
Normal 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
32
_test/issue-1315.go
Normal 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
29
_test/issue-1320.go
Normal 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
|
||||
42
_test/issue-1326.go
Normal file
42
_test/issue-1326.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
type Option interface {
|
||||
apply(*T)
|
||||
}
|
||||
|
||||
type T struct {
|
||||
s string
|
||||
}
|
||||
|
||||
type opt struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (o *opt) apply(t *T) {
|
||||
println(o.name)
|
||||
}
|
||||
|
||||
func BuildOptions() []Option {
|
||||
return []Option{
|
||||
&opt{"opt1"},
|
||||
&opt{"opt2"},
|
||||
}
|
||||
}
|
||||
|
||||
func NewT(name string, options ...Option) *T {
|
||||
t := &T{name}
|
||||
for _, opt := range options {
|
||||
opt.apply(t)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := NewT("hello", BuildOptions()...)
|
||||
println(t.s)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// opt1
|
||||
// opt2
|
||||
// hello
|
||||
16
_test/issue-1328.go
Normal file
16
_test/issue-1328.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func main() {
|
||||
script := "hello"
|
||||
sumRaw := sha1.Sum([]byte(script))
|
||||
sum := hex.EncodeToString(sumRaw[:])
|
||||
println(sum)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
|
||||
42
_test/issue-1330.go
Normal file
42
_test/issue-1330.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type wrappedConn struct {
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func main() {
|
||||
_, err := net.Listen("tcp", "127.0.0.1:49153")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dialer := &net.Dialer{
|
||||
LocalAddr: &net.TCPAddr{
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
Port: 0,
|
||||
},
|
||||
}
|
||||
|
||||
conn, err := dialer.Dial("tcp", "127.0.0.1:49153")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
t := &wrappedConn{conn}
|
||||
var w io.Writer = t
|
||||
if n, err := w.Write([]byte("hello")); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
17
_test/issue-1332.go
Normal file
17
_test/issue-1332.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func run(fn func(name string)) { fn("test") }
|
||||
|
||||
type T2 struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (t *T2) f(s string) { println(s, t.name) }
|
||||
|
||||
func main() {
|
||||
t2 := &T2{"foo"}
|
||||
run(t2.f)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test foo
|
||||
37
_test/issue-1333.go
Normal file
37
_test/issue-1333.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
func mock(name string) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprint(rw, "Hello ", name)
|
||||
}
|
||||
}
|
||||
|
||||
func client(uri string) {
|
||||
resp, err := http.Get(uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
mux.Handle("/", mock("foo"))
|
||||
client(server.URL)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Hello foo
|
||||
26
_test/issue-1337.go
Normal file
26
_test/issue-1337.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func f(i interface{}) {
|
||||
switch at := i.(type) {
|
||||
case int, int8:
|
||||
println("integer", at)
|
||||
case io.Reader:
|
||||
println("reader")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
func main() {
|
||||
var fd *os.File
|
||||
var r io.Reader = fd
|
||||
f(r)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// reader
|
||||
// bye
|
||||
27
_test/issue-1361.go
Normal file
27
_test/issue-1361.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type obj struct {
|
||||
num float64
|
||||
}
|
||||
|
||||
type Fun func(o *obj) (r *obj, err error)
|
||||
|
||||
func numFun(fn func(f float64) float64) Fun {
|
||||
return func(o *obj) (*obj, error) {
|
||||
return &obj{fn(o.num)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := numFun(math.Cos)
|
||||
r, err := f(&obj{})
|
||||
fmt.Println(r, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{1} <nil>
|
||||
16
_test/issue-1364.go
Normal file
16
_test/issue-1364.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value interface{}
|
||||
var err error
|
||||
value, err = strconv.ParseFloat("123", 64)
|
||||
fmt.Println(value, err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 123 <nil>
|
||||
18
_test/issue-1365.go
Normal file
18
_test/issue-1365.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
func genInt() (int, error) { return 3, nil }
|
||||
|
||||
func getInt() (value int) {
|
||||
value, err := genInt()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
println(getInt())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
16
_test/issue-1368.go
Normal file
16
_test/issue-1368.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
const dollar byte = 36
|
||||
|
||||
func main() {
|
||||
var c byte = 36
|
||||
switch true {
|
||||
case c == dollar:
|
||||
println("ok")
|
||||
default:
|
||||
println("not ok")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
18
_test/issue-1371.go
Normal file
18
_test/issue-1371.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type node struct {
|
||||
parent *node
|
||||
child []*node
|
||||
key string
|
||||
}
|
||||
|
||||
func main() {
|
||||
root := &node{key: "root"}
|
||||
root.child = nil
|
||||
fmt.Println("root:", root)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// root: &{<nil> [] root}
|
||||
38
_test/issue-1375.go
Normal file
38
_test/issue-1375.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Option func(*Struct)
|
||||
|
||||
func WithOption(opt string) Option {
|
||||
return func(s *Struct) {
|
||||
s.opt = opt
|
||||
}
|
||||
}
|
||||
|
||||
type Struct struct {
|
||||
opt string
|
||||
}
|
||||
|
||||
func New(opts ...Option) *Struct {
|
||||
s := new(Struct)
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Struct) ShowOption() {
|
||||
fmt.Println(s.opt)
|
||||
}
|
||||
|
||||
func main() {
|
||||
opts := []Option{
|
||||
WithOption("test"),
|
||||
}
|
||||
s := New(opts...)
|
||||
s.ShowOption()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// test
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
19
_test/var16.go
Normal file
19
_test/var16.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
func getArray() ([]int, error) { println("getArray"); return []int{1, 2}, nil }
|
||||
|
||||
func getNum() (int, error) { println("getNum"); return 3, nil }
|
||||
|
||||
func main() {
|
||||
if a, err := getNum(); err != nil {
|
||||
println("#1", a)
|
||||
} else if a, err := getArray(); err != nil {
|
||||
println("#2", a)
|
||||
}
|
||||
println("#3")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// getNum
|
||||
// getArray
|
||||
// #3
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1824,6 +1832,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
|
||||
setFNext(c, clauses[i+1])
|
||||
}
|
||||
}
|
||||
sbn.start = clauses[0].start
|
||||
n.start = n.child[0].start
|
||||
n.child[0].tnext = sbn.start
|
||||
|
||||
@@ -2019,7 +2028,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"))
|
||||
@@ -2047,12 +2061,18 @@ func compDefineX(sc *scope, n *node) error {
|
||||
}
|
||||
|
||||
for i, t := range types {
|
||||
index := sc.add(t)
|
||||
sc.sym[n.child[i].ident] = &symbol{index: index, kind: varSym, typ: t}
|
||||
var index int
|
||||
id := n.child[i].ident
|
||||
if sym, _, ok := sc.lookup(id); ok && sym.kind == varSym && sym.typ.equals(t) {
|
||||
// Reuse symbol in case of a variable redeclaration with the same type.
|
||||
index = sym.index
|
||||
} else {
|
||||
index = sc.add(t)
|
||||
sc.sym[id] = &symbol{index: index, kind: varSym, typ: t}
|
||||
}
|
||||
n.child[i].typ = t
|
||||
n.child[i].findex = index
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2468,8 +2488,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 {
|
||||
|
||||
@@ -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:]...)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -52,6 +52,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
file.Name() == "io0.go" || // use random number
|
||||
file.Name() == "issue-1093.go" || // expect error
|
||||
file.Name() == "issue-1276.go" || // expect error
|
||||
file.Name() == "issue-1330.go" || // expect error
|
||||
file.Name() == "op1.go" || // expect error
|
||||
file.Name() == "op7.go" || // expect error
|
||||
file.Name() == "op9.go" || // expect error
|
||||
@@ -145,7 +146,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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
254
interp/run.go
254
interp/run.go
@@ -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())
|
||||
@@ -1058,7 +1086,7 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
for i, m := range methods {
|
||||
if m == nil {
|
||||
// First direct method lookup on field.
|
||||
if r := methodByName(v, names[i]); r.IsValid() {
|
||||
if r := methodByName(v, names[i], indexes[i]); r.IsValid() {
|
||||
w.Field(i + 1).Set(r)
|
||||
continue
|
||||
}
|
||||
@@ -1083,69 +1111,119 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// methodByName return the method corresponding to name on value, or nil if not found.
|
||||
// methodByName returns the method corresponding to name on value, or nil if not found.
|
||||
// The search is extended on valueInterface wrapper if present.
|
||||
func methodByName(value reflect.Value, name string) reflect.Value {
|
||||
// If valid, the returned value is a method function with the receiver already set
|
||||
// (no need to pass it at call).
|
||||
func methodByName(value reflect.Value, name string, index []int) (v reflect.Value) {
|
||||
if vi, ok := value.Interface().(valueInterface); ok {
|
||||
if v := getConcreteValue(vi.value).MethodByName(name); v.IsValid() {
|
||||
return v
|
||||
if v = getConcreteValue(vi.value).MethodByName(name); v.IsValid() {
|
||||
return
|
||||
}
|
||||
}
|
||||
return value.MethodByName(name)
|
||||
if v = value.MethodByName(name); v.IsValid() {
|
||||
return
|
||||
}
|
||||
for value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
if checkFieldIndex(value.Type(), index) {
|
||||
value = value.FieldByIndex(index)
|
||||
}
|
||||
if v = value.MethodByName(name); v.IsValid() {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func checkFieldIndex(typ reflect.Type, index []int) bool {
|
||||
if len(index) == 0 {
|
||||
return false
|
||||
}
|
||||
t := typ
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
i := index[0]
|
||||
if i >= t.NumField() {
|
||||
return false
|
||||
}
|
||||
if len(index) > 1 {
|
||||
return checkFieldIndex(t.Field(i).Type, index[1:])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
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)
|
||||
fnext := getExec(n.fnext)
|
||||
hasVariadicArgs := n.action == aCallSlice // callSlice implies variadic call with ellipsis.
|
||||
|
||||
// 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 hasVariadicArgs || !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 hasVariadicArgs || !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)
|
||||
@@ -1153,11 +1231,12 @@ func call(n *node) {
|
||||
switch {
|
||||
case isEmptyInterface(arg):
|
||||
values = append(values, genValue(c))
|
||||
case isInterfaceSrc(arg) && n.action != aCallSlice:
|
||||
// callSlice implies variadic call with ellipsis, do not wrap in valueInterface.
|
||||
case isInterfaceSrc(arg) && !hasVariadicArgs:
|
||||
values = append(values, genValueInterface(c))
|
||||
case isInterfaceBin(arg):
|
||||
values = append(values, genInterfaceWrapper(c, arg.rtype))
|
||||
case isFuncSrc(arg) && !hasVariadicArgs:
|
||||
values = append(values, genValueNode(c))
|
||||
default:
|
||||
values = append(values, genValue(c))
|
||||
}
|
||||
@@ -1165,10 +1244,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 +1257,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 +1279,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:]
|
||||
@@ -1325,12 +1406,22 @@ func call(n *node) {
|
||||
}
|
||||
default:
|
||||
val := v(f)
|
||||
// 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 {
|
||||
dest[i].Set(val)
|
||||
if val.IsZero() && dest[i].Kind() != reflect.Interface {
|
||||
// Work around a recursive struct zero interface issue.
|
||||
// Once there is a better way to handle this case, the dest can just be set.
|
||||
continue
|
||||
}
|
||||
if nod, ok := val.Interface().(*node); ok && nod.recv != nil {
|
||||
// An interpreted method is passed as value in a function call.
|
||||
// It must be wrapped now, otherwise the receiver will be missing
|
||||
// at the method call (#1332).
|
||||
// TODO (marc): wrapping interpreted functions should be always done
|
||||
// everywhere at runtime to simplify the whole code,
|
||||
// but it requires deeper refactoring.
|
||||
dest[i] = genFunctionWrapper(nod)(f)
|
||||
continue
|
||||
}
|
||||
dest[i].Set(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1404,7 +1495,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,11 +1657,16 @@ func callBin(n *node) {
|
||||
}
|
||||
out := callFn(value(f), in)
|
||||
for i := 0; i < len(out); i++ {
|
||||
if out[i].Type().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])
|
||||
r := out[i]
|
||||
if r.Kind() == reflect.Func {
|
||||
getFrame(f, n.level).data[n.findex+i] = r
|
||||
continue
|
||||
}
|
||||
dest := getFrame(f, n.level).data[n.findex+i]
|
||||
if _, ok := dest.Interface().(valueInterface); ok {
|
||||
r = reflect.ValueOf(valueInterface{value: r})
|
||||
}
|
||||
dest.Set(r)
|
||||
}
|
||||
return tnext
|
||||
}
|
||||
@@ -1882,7 +1978,7 @@ func getMethodByName(n *node) {
|
||||
}
|
||||
return next
|
||||
}
|
||||
m, li := val.node.typ.lookupMethod(name)
|
||||
m, li := typ.lookupMethod(name)
|
||||
if m == nil {
|
||||
panic(n.cfgErrorf("method not found: %s", name))
|
||||
}
|
||||
@@ -2291,9 +2387,13 @@ func _return(n *node) {
|
||||
}
|
||||
values[i] = genValueInterface(c)
|
||||
case valueT:
|
||||
if t.rtype.Kind() == reflect.Interface {
|
||||
switch t.rtype.Kind() {
|
||||
case reflect.Interface:
|
||||
values[i] = genInterfaceWrapper(c, t.rtype)
|
||||
break
|
||||
continue
|
||||
case reflect.Func:
|
||||
values[i] = genFunctionWrapper(c)
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
@@ -2533,7 +2633,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 +2711,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,13 +2967,22 @@ func _case(n *node) {
|
||||
if typ.cat == nilT && v.IsNil() {
|
||||
return tnext
|
||||
}
|
||||
if typ.TypeOf().String() == t.String() {
|
||||
destValue(f).Set(v.Elem())
|
||||
rtyp := typ.TypeOf()
|
||||
if rtyp == nil {
|
||||
return fnext
|
||||
}
|
||||
elem := v.Elem()
|
||||
if rtyp.String() == t.String() && implementsInterface(v, typ) {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
ival := v.Interface()
|
||||
if ival != nil && typ.TypeOf().String() == reflect.TypeOf(ival).String() {
|
||||
destValue(f).Set(v.Elem())
|
||||
if ival != nil && rtyp.String() == reflect.TypeOf(ival).String() {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
if typ.cat == valueT && rtyp.Kind() == reflect.Interface && elem.IsValid() && elem.Type().Implements(rtyp) {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
return fnext
|
||||
@@ -2891,12 +3000,37 @@ func _case(n *node) {
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO(mpl): probably needs to be fixed for empty interfaces, like above.
|
||||
// match against multiple types: assign var to interface value
|
||||
n.exec = func(f *frame) bltn {
|
||||
val := srcValue(f)
|
||||
if v := srcValue(f).Interface().(valueInterface).node; v != nil {
|
||||
if t := val.Type(); t.Kind() == reflect.Interface {
|
||||
for _, typ := range types {
|
||||
if typ.cat == nilT && val.IsNil() {
|
||||
return tnext
|
||||
}
|
||||
rtyp := typ.TypeOf()
|
||||
if rtyp == nil {
|
||||
continue
|
||||
}
|
||||
elem := val.Elem()
|
||||
if rtyp.String() == t.String() && implementsInterface(val, typ) {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
ival := val.Interface()
|
||||
if ival != nil && rtyp.String() == reflect.TypeOf(ival).String() {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
if typ.cat == valueT && rtyp.Kind() == reflect.Interface && elem.IsValid() && elem.Type().Implements(rtyp) {
|
||||
destValue(f).Set(elem)
|
||||
return tnext
|
||||
}
|
||||
}
|
||||
return fnext
|
||||
}
|
||||
if v := val.Interface().(valueInterface).node; v != nil {
|
||||
for _, typ := range types {
|
||||
if v.typ.id() == typ.id() {
|
||||
destValue(f).Set(val)
|
||||
@@ -2935,6 +3069,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 +3319,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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -854,6 +854,14 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t.cat == valueT {
|
||||
switch t.rtype.Kind() {
|
||||
case reflect.Array, reflect.Ptr:
|
||||
t = valueTOf(reflect.SliceOf(t.rtype.Elem()), withScope(sc))
|
||||
}
|
||||
break
|
||||
}
|
||||
if t.cat == ptrT {
|
||||
t = t.val
|
||||
}
|
||||
@@ -1819,6 +1827,7 @@ func (t *itype) refType(ctx *refTypeContext) reflect.Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldFix := []int{} // Slice of field indices to fix for recursivity.
|
||||
t.rtype = reflect.StructOf(fields)
|
||||
if ctx.isComplete() {
|
||||
for _, s := range ctx.defined {
|
||||
@@ -1826,6 +1835,9 @@ func (t *itype) refType(ctx *refTypeContext) reflect.Type {
|
||||
f := s.rtype.Field(i)
|
||||
if strings.HasSuffix(f.Type.String(), "unsafe2.dummy") {
|
||||
unsafe2.SetFieldType(s.rtype, i, ctx.rect.fixDummy(s.rtype.Field(i).Type))
|
||||
if name == s.path+"/"+s.name {
|
||||
fieldFix = append(fieldFix, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1834,13 +1846,16 @@ func (t *itype) refType(ctx *refTypeContext) reflect.Type {
|
||||
// The rtype has now been built, we can go back and rebuild
|
||||
// all the recursive types that relied on this type.
|
||||
// However, as we are keyed by type name, if two or more (recursive) fields at
|
||||
// the same depth level are of the same type, they "mask" each other, and only one
|
||||
// of them is in ctx.refs, which means this pass below does not fully do the job.
|
||||
// Which is why we have the pass above that is done one last time, for all fields,
|
||||
// one the recursion has been fully resolved.
|
||||
// the same depth level are of the same type, or a "variation" of the same type
|
||||
// (slice of, map of, etc), they "mask" each other, and only one
|
||||
// of them is in ctx.refs. That is why the code around here is a bit convoluted,
|
||||
// and we need both the loop above, around all the struct fields, and the loop
|
||||
// below, around the ctx.refs.
|
||||
for _, f := range ctx.refs[name] {
|
||||
ftyp := f.typ.field[f.idx].typ.refType(&refTypeContext{defined: ctx.defined, rebuilding: true})
|
||||
unsafe2.SetFieldType(f.typ.rtype, f.idx, ftyp)
|
||||
for _, index := range fieldFix {
|
||||
ftyp := f.typ.field[index].typ.refType(&refTypeContext{defined: ctx.defined, rebuilding: true})
|
||||
unsafe2.SetFieldType(f.typ.rtype, index, ftyp)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if z, _ := t.zero(); z.IsValid() {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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() {
|
||||
@@ -408,7 +408,7 @@ func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
v := value(f)
|
||||
if v.Interface().(valueInterface).node == nil {
|
||||
if vi, ok := v.Interface().(valueInterface); ok && vi.node == nil {
|
||||
// Uninitialized interface value, set it to a correct zero value.
|
||||
v.Set(zeroInterfaceValue())
|
||||
v = value(f)
|
||||
@@ -421,7 +421,11 @@ func genValueNode(n *node) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
|
||||
return func(f *frame) reflect.Value {
|
||||
return reflect.ValueOf(&node{rval: value(f)})
|
||||
v := value(f)
|
||||
if _, ok := v.Interface().(*node); ok {
|
||||
return v
|
||||
}
|
||||
return reflect.ValueOf(&node{rval: v})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,7 +434,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 +452,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 +472,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 +490,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:
|
||||
|
||||
48
stdlib/go1_16_go_build_constraint.go
Normal file
48
stdlib/go1_16_go_build_constraint.go
Normal 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()
|
||||
}
|
||||
49
stdlib/go1_17_go_build_constraint.go
Normal file
49
stdlib/go1_17_go_build_constraint.go
Normal 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()
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user