Compare commits

...

18 Commits

Author SHA1 Message Date
Marc Vertes
f07f25f1ba interp: handle struct with multiple recursive fields (#1372)
* interp: handle struct with multiple recursive fields

In case of a recursive struct with several recursive fields of
different type, only the first one was properly fixed when
constructing the corresponding reflect type. We now memorize and
process all fields at the same depth level.

Fixes #1371.

* Update interp/type.go

Co-authored-by: mpl <mathieu.lonjaret@gmail.com>

* fix lint

* fix comment

Co-authored-by: mpl <mathieu.lonjaret@gmail.com>
2022-04-07 14:53:23 +02:00
cclerget
c93b836c77 Prevent variadic arguments from being wrapped as function
Fixes #1375
2022-04-07 14:24:07 +02:00
Marc Vertes
371103f0d1 interp: fix switch expression (#1370)
The control flow graph was incorrect for the initial clause.

Fixes #1368.
2022-04-06 22:07:51 +02:00
Marc Vertes
8bd7afbe62 interp: fix handling of redeclaration in multi-assign expression (#1367)
* interp: fix handling of redeclaration in multi-assign expression

In a statement like `a, b := f()` if `a` was previously declared,
its symbol must be reused, a new symbol must not override its
previous value. This is now fixed.

* In case of redeclaration, reuse the existing only if the redeclared
variable has the same type. Add _test/var16.go to check this use
case.

Fixes #1365.
2022-04-06 20:01:25 +02:00
Marc Vertes
8ea3a493f4 interp: fix interface conversion from binary call (#1366)
Fixes #1364.
2022-04-06 19:51:12 +02:00
Marc Vertes
f2abd346c0 interp: fix passing binary function as parameter
Wrap binary function values in a node if passing it
as a parameter to an interperter defined function.

Fixes #1361.
2022-04-05 17:34:08 +02:00
Marc Vertes
c784713aca interp: make methods passed as value preserve receiver
Fixes #1332.
2022-04-05 16:58:09 +02:00
Marc Vertes
14acf618af interp: improve type switch on binary interfaces
Fixes #1337.
2022-01-04 10:50:08 +01:00
Marc Vertes
fbee2baf9d interp: fix wrapping of returned closure passed to runtime
Fixes #1333.
2021-12-21 17:44:06 +01:00
Marc Vertes
2819b4167b interp: fix derivation of type of slice expression of binary object
Fixes #1328.
2021-12-20 15:46:05 +01:00
Marc Vertes
2af660cb1f interp: improve method resolution on embedded fields
The capability to dereference pointers has been added to
methodByName(), improving method lookup on binary values.

Wrapping to valueInterface is performed in a missing use case at
return of function calls. It was done in the nested call, but not
at assign.

Fixes #1330.
2021-12-20 15:06:11 +01:00
Marc Vertes
8323068414 interp: fix nested calls with variadic interfaces
Fixes #1326
2021-12-08 17:16:05 +01:00
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
46 changed files with 825 additions and 125 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

42
_test/issue-1326.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

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())
}

19
_test/var16.go Normal file
View 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

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
@@ -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 {

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)
}
@@ -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)
}

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())
@@ -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

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

@@ -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() {

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() {
@@ -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:

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() {