Compare commits

...

10 Commits

Author SHA1 Message Date
Nicholas Wiersma
83676577ac fix: use the import path for types
When running GTA, the type `path` was set to `rpath`. This equates to the package path (`github.com/traefik/yaegi`) in most cases. In the vendored case the `rpath` is the sub package path `something/vendor/github.com/traefik/yaegi` causing issues in typecheck and likely further down the line. By using the `importPath` it makes this consistent.

**Note:** I have no clue how to test this decently. I am open to options here.

Potentially Fixes #916
2020-11-05 13:42:03 +01:00
mpl
f0fc907269 extract: support building/running yaegi with Go devel
Fixes #928
2020-11-05 11:40:04 +01:00
Marc Vertes
61f4704925 interp: fix CFG in case of for loop with empty init and cond
Refactor `for` variants for clarity. Ensure all possible 8 combinations
are covered.

Fixes #942.
2020-11-05 11:00:04 +01:00
Marc Vertes
b1ccfbf47f interp: apply type conversion on untyped variable at run
Fixes #938.
2020-11-04 18:16:04 +01:00
Marc Vertes
0ed4b362dc interp: implement conversion for interpreter function types
Interpreter function types are represented internally by the AST node
of their definition. The conversion operation creates a new node with
the type field pointing to the target type.

Fixes #936.
2020-11-03 17:48:03 +01:00
Marc Vertes
98807387a4 interp: resolve type for untyped shift expressions
A non-constant shift expression can be untyped, requiring to apply a
type from inherited context. This change insures that such context is
propagated during CFG pre-order walk, to be used if necessary.
    
Fixes #927.
2020-11-02 18:08:04 +01:00
Marc Vertes
c817823ba1 interp: fix incorrect infinite loop on for statement
Add a for statement variant for the case of a "for" with an init, no
condition and no post-increment.

Fixes #933.
2020-11-02 17:52:03 +01:00
mpl
3cb8bca81a interp: on panic, look for node where offending exec originated from
The execution flow is such that a node can end up running several chained exec
funcs, some of which actually originate from other nodes. For example, in:

var m []int // L0
println("hello world") // L1
m[0] = 1 // L2

the offending code is on a node on line 2 (out of range error). However, since
the assignment to m is part of the execution flow of the variable m, we'll get
the panic when running all the chained exec funcs attached to the node for m on
line 0.

Which is why, when that happens, we need to look for the actual node (the one on
L2) where the offending instruction originates from, in order to
properly report the origin of the panic.

Fixes #546
2020-11-02 10:26:04 +01:00
Marc Vertes
a38d19288f interp: fix testing for nil interface values
Fixes #924.
2020-10-30 16:20:04 +01:00
Marc Vertes
7f8ffa6719 interp: handle explicit nil values in literal composite values
Fixes #922.
2020-10-27 11:24:04 +01:00
241 changed files with 618 additions and 303 deletions

15
_test/composite14.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
type T struct {
b []byte
}
func main() {
t := T{nil}
fmt.Println(t)
}
// Output:
// {[]}

21
_test/convert0.go Normal file
View File

@@ -0,0 +1,21 @@
package main
type T struct {
v int
}
type comparator func(T, T) bool
func sort(items []T, comp comparator) {
println("in sort")
}
func compT(t0, t1 T) bool { return t0.v < t1.v }
func main() {
a := []T{}
sort(a, comparator(compT))
}
// Output:
// in sort

16
_test/for15.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func f() int { println("in f"); return 1 }
func main() {
for i := f(); ; {
println("in loop")
if i > 0 {
break
}
}
}
// Output:
// in f
// in loop

16
_test/for16.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func main() {
max := 1
for ; ; max-- {
if max == 0 {
break
}
println("in for")
}
println("bye")
}
// Output:
// in for
// bye

28
_test/nil3.go Normal file
View File

@@ -0,0 +1,28 @@
package main
type I interface {
Hello()
}
type T struct {
h I
}
func (t *T) Hello() { println("Hello") }
func main() {
t := &T{}
println(t.h != nil)
println(t.h == nil)
t.h = t
println(t.h != nil)
println(t.h == nil)
t.h.Hello()
}
// Output:
// false
// true
// true
// false
// Hello

View File

@@ -0,0 +1,13 @@
package main
import (
"fmt"
"guthib.com/bat/baz"
)
func main() {
t := baz.NewT()
fmt.Printf("%s", t.A3)
}

View File

@@ -0,0 +1,22 @@
package baz
func NewT() *T {
return &T{
A1: make([]U, 0),
A3: "foobar",
}
}
type T struct {
A1 []U
A3 string
}
type U struct {
B1 V
B2 V
}
type V struct {
C1 string
}

View File

@@ -93,6 +93,12 @@ func TestPackages(t *testing.T) {
expected: "Yo hello",
evalFile: "./_pkg12/src/guthib.com/foo/main.go",
},
{
desc: "eval main with vendor",
goPath: "./_pkg13/",
expected: "foobar",
evalFile: "./_pkg13/src/guthib.com/foo/bar/main.go",
},
}
for _, test := range testCases {

View File

@@ -436,10 +436,12 @@ func GetMinor(part string) string {
return minor
}
const defaultMinorVersion = 15
func genBuildTags() (string, error) {
version := runtime.Version()
if version == "devel" {
return "", nil
if strings.HasPrefix(version, "devel") {
return "", fmt.Errorf("extracting only supported with stable releases of Go, not %v", version)
}
parts := strings.Split(version, ".")
@@ -452,6 +454,11 @@ func genBuildTags() (string, error) {
return "", fmt.Errorf("failed to parse version: %v", err)
}
// Only append an upper bound if we are not on the latest go
if minor >= defaultMinorVersion {
return currentGoVersion, nil
}
nextGoVersion := parts[0] + "." + strconv.Itoa(minor+1)
return currentGoVersion + ",!" + nextGoVersion, nil

View File

@@ -84,11 +84,12 @@ func main() {
oFile = strings.ReplaceAll(importPath, "/", "_") + ".go"
}
prefix := runtime.Version()
if runtime.Version() != "devel" {
parts := strings.Split(runtime.Version(), ".")
prefix = parts[0] + "_" + extract.GetMinor(parts[1])
version := runtime.Version()
if strings.HasPrefix(version, "devel") {
log.Fatalf("extracting only supported with stable releases of Go, not %v", version)
}
parts := strings.Split(version, ".")
prefix := parts[0] + "_" + extract.GetMinor(parts[1])
f, err := os.Create(prefix + "_" + oFile)
if err != nil {

View File

@@ -51,12 +51,14 @@ const (
fieldList
fileStmt
forStmt0 // for {}
forStmt1 // for cond {}
forStmt2 // for init; cond; {}
forStmt3 // for ; cond; post {}
forStmt3a // for init; ; post {}
forStmt4 // for init; cond; post {}
forRangeStmt // for range
forStmt1 // for init; ; {}
forStmt2 // for cond {}
forStmt3 // for init; cond; {}
forStmt4 // for ; ; post {}
forStmt5 // for ; cond; post {}
forStmt6 // for init; ; post {}
forStmt7 // for init; cond; post {}
forRangeStmt // for range {}
funcDecl
funcLit
funcType
@@ -134,8 +136,10 @@ var kinds = [...]string{
forStmt1: "forStmt1",
forStmt2: "forStmt2",
forStmt3: "forStmt3",
forStmt3a: "forStmt3a",
forStmt4: "forStmt4",
forStmt5: "forStmt5",
forStmt6: "forStmt6",
forStmt7: "forStmt7",
forRangeStmt: "forRangeStmt",
funcDecl: "funcDecl",
funcType: "funcType",
@@ -654,23 +658,23 @@ func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error
case *ast.ForStmt:
// Disambiguate variants of FOR statements with a node kind per variant
var kind nkind
if a.Cond == nil {
if a.Init != nil && a.Post != nil {
kind = forStmt3a
} else {
kind = forStmt0
}
} else {
switch {
case a.Init == nil && a.Post == nil:
kind = forStmt1
case a.Init != nil && a.Post == nil:
kind = forStmt2
case a.Init == nil && a.Post != nil:
kind = forStmt3
default:
kind = forStmt4
}
switch {
case a.Cond == nil && a.Init == nil && a.Post == nil:
kind = forStmt0
case a.Cond == nil && a.Init != nil && a.Post == nil:
kind = forStmt1
case a.Cond != nil && a.Init == nil && a.Post == nil:
kind = forStmt2
case a.Cond != nil && a.Init != nil && a.Post == nil:
kind = forStmt3
case a.Cond == nil && a.Init == nil && a.Post != nil:
kind = forStmt4
case a.Cond != nil && a.Init == nil && a.Post != nil:
kind = forStmt5
case a.Cond == nil && a.Init != nil && a.Post != nil:
kind = forStmt6
case a.Cond != nil && a.Init != nil && a.Post != nil:
kind = forStmt7
}
st.push(addChild(&root, anc, pos, kind, aNop), nod)

View File

@@ -66,6 +66,41 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
return false
}
switch n.kind {
case binaryExpr, unaryExpr, parenExpr:
if isBoolAction(n) {
break
}
// Gather assigned type if set, to give context for type propagation at post-order.
switch n.anc.kind {
case assignStmt, defineStmt:
a := n.anc
i := childPos(n) - a.nright
if len(a.child) > a.nright+a.nleft {
i--
}
dest := a.child[i]
if dest.typ != nil && !isInterface(dest.typ) {
// Interface type are not propagated, and will be resolved at post-order.
n.typ = dest.typ
}
case binaryExpr, unaryExpr, parenExpr:
n.typ = n.anc.typ
}
case defineStmt:
// Determine type of variables initialized at declaration, so it can be propagated.
if n.nleft+n.nright == len(n.child) {
// No type was specified on the left hand side, it will resolved at post-order.
break
}
n.typ, err = nodeType(interp, sc, n.child[n.nleft])
if err != nil {
break
}
for i := 0; i < n.nleft; i++ {
n.child[i].typ = n.typ
}
case blockStmt:
if n.anc != nil && n.anc.kind == rangeStmt {
// For range block: ensure that array or map type is propagated to iterators
@@ -285,11 +320,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
}
case forStmt0, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.child[0]
case forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.lastChild()
@@ -447,7 +478,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
var atyp *itype
if n.nleft+n.nright < len(n.child) {
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
return
break
}
}
@@ -644,7 +675,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
switch n.action {
case aRem, aShl, aShr:
case aRem:
n.typ = c0.typ
case aShl, aShr:
if c0.typ.untyped {
break
}
n.typ = c0.typ
case aEqual, aNotEqual:
n.typ = sc.getType("bool")
@@ -860,7 +896,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.gen = nop
n.findex = -1
n.typ = c0.typ
n.rval = c1.rval.Convert(c0.typ.rtype)
if c, ok := c1.rval.Interface().(constant.Value); ok {
i, _ := constant.Int64Val(constant.ToInt(c))
n.rval = reflect.ValueOf(i).Convert(c0.typ.rtype)
} else {
n.rval = c1.rval.Convert(c0.typ.rtype)
}
default:
n.gen = convert
n.typ = c0.typ
@@ -1005,7 +1046,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = n.start
sc = sc.pop()
case forStmt1: // for cond {}
case forStmt1: // for init; ; {}
init, body := n.child[0], n.child[1]
n.start = init.start
init.tnext = body.start
body.tnext = n.start
sc = sc.pop()
case forStmt2: // for cond {}
cond, body := n.child[0], n.child[1]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1024,7 +1072,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt2: // for init; cond; {}
case forStmt3: // for init; cond; {}
init, cond, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1046,7 +1094,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt3: // for ; cond; post {}
case forStmt4: // for ; ; post {}
post, body := n.child[0], n.child[1]
n.start = body.start
post.tnext = body.start
body.tnext = post.start
sc = sc.pop()
case forStmt5: // for ; cond; post {}
cond, post, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1066,7 +1121,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = post.start
sc = sc.pop()
case forStmt3a: // for init; ; post {}
case forStmt6: // for init; ; post {}
init, post, body := n.child[0], n.child[1], n.child[2]
n.start = init.start
init.tnext = body.start
@@ -1074,7 +1129,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
post.tnext = body.start
sc = sc.pop()
case forStmt4: // for init; cond; post {}
case forStmt7: // for init; cond; post {}
init, cond, post, body := n.child[0], n.child[1], n.child[2], n.child[3]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -2467,3 +2522,12 @@ func isArithmeticAction(n *node) bool {
return false
}
}
func isBoolAction(n *node) bool {
switch n.action {
case aEqual, aGreater, aGreaterEqual, aLand, aLor, aLower, aLowerEqual, aNot, aNotEqual:
return true
default:
return false
}
}

View File

@@ -145,7 +145,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
elementType := sc.getType(typeName)
if elementType == nil {
// Add type if necessary, so method can be registered
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn.child[0], scope: sc}}
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn.child[0], scope: sc}}
elementType = sc.sym[typeName].typ
}
rcvrtype = &itype{cat: ptrT, val: elementType, incomplete: elementType.incomplete, node: rtn, scope: sc}
@@ -154,7 +154,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
rcvrtype = sc.getType(typeName)
if rcvrtype == nil {
// Add type if necessary, so method can be registered
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn, scope: sc}}
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn, scope: sc}}
rcvrtype = sc.sym[typeName].typ
}
}
@@ -254,12 +254,12 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
}
if n.child[1].kind == identExpr {
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: importPath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
copy(n.typ.method, typ.method)
} else {
n.typ = typ
n.typ.name = typeName
n.typ.path = rpath
n.typ.path = importPath
}
asImportName := filepath.Join(typeName, baseName)

View File

@@ -71,6 +71,17 @@ func TestEvalArithmetic(t *testing.T) {
})
}
func TestEvalShift(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{
{src: "a, b, m := uint32(1), uint32(2), uint32(0); m = a + (1 << b)", res: "5"},
{src: "c := uint(1); d := uint(+(-(1 << c)))", res: "18446744073709551614"},
{src: "e, f := uint32(0), uint32(0); f = 1 << -(e * 2)", res: "1"},
{src: "p := uint(0xdead); byte((1 << (p & 7)) - 1)", res: "31"},
{pre: func() { eval(t, i, "const k uint = 1 << 17") }, src: "int(k)", res: "131072"},
})
}
func TestEvalStar(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{

View File

@@ -108,10 +108,53 @@ func (interp *Interpreter) run(n *node, cf *frame) {
runCfg(n.start, f)
}
// originalExecNode looks in the tree of nodes for the node which has exec,
// aside from n, in order to know where n "inherited" that exec from.
func originalExecNode(n *node, exec bltn) *node {
execAddr := reflect.ValueOf(exec).Pointer()
var originalNode *node
seen := make(map[int64]struct{})
root := n
for {
root = root.anc
if root == nil {
break
}
if _, ok := seen[root.index]; ok {
continue
}
root.Walk(func(wn *node) bool {
if _, ok := seen[wn.index]; ok {
return true
}
seen[wn.index] = struct{}{}
if wn.index == n.index {
return true
}
if wn.exec == nil {
return true
}
if reflect.ValueOf(wn.exec).Pointer() == execAddr {
originalNode = wn
return false
}
return true
}, nil)
if originalNode != nil {
break
}
}
return originalNode
}
// Functions set to run during execution of CFG.
// runCfg executes a node AST by walking its CFG and running node builtin at each step.
func runCfg(n *node, f *frame) {
var exec bltn
defer func() {
f.mutex.Lock()
f.recovered = recover()
@@ -119,14 +162,18 @@ func runCfg(n *node, f *frame) {
val[0].Call(val[1:])
}
if f.recovered != nil {
fmt.Println(n.cfgErrorf("panic"))
oNode := originalExecNode(n, exec)
if oNode == nil {
oNode = n
}
fmt.Println(oNode.cfgErrorf("panic"))
f.mutex.Unlock()
panic(f.recovered)
}
f.mutex.Unlock()
}()
for exec := n.exec; exec != nil && f.runid() == n.interp.runid(); {
for exec = n.exec; exec != nil && f.runid() == n.interp.runid(); {
exec = exec(f)
}
}
@@ -343,6 +390,21 @@ func convert(n *node) {
return
}
if n.child[0].typ.cat == funcT && c.typ.cat == funcT {
value := genValue(c)
n.exec = func(f *frame) bltn {
n, ok := value(f).Interface().(*node)
if !ok || !n.typ.convertibleTo(c.typ) {
panic("cannot convert")
}
n1 := *n
n1.typ = c.typ
dest(f).Set(reflect.ValueOf(&n1))
return next
}
return
}
var value func(*frame) reflect.Value
if c.typ.cat == funcT {
value = genFunctionWrapper(c)
@@ -1719,6 +1781,11 @@ func neg(n *node) {
dest(f).SetInt(-value(f).Int())
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.exec = func(f *frame) bltn {
dest(f).SetUint(-value(f).Uint())
return next
}
case reflect.Float32, reflect.Float64:
n.exec = func(f *frame) bltn {
dest(f).SetFloat(-value(f).Float())
@@ -2104,16 +2171,20 @@ func doComposite(n *node, hasType bool, keyed bool) {
val = c
fieldIndex = i
}
convertLiteralValue(val, typ.field[fieldIndex].typ.TypeOf())
ft := typ.field[fieldIndex].typ
rft := ft.TypeOf()
convertLiteralValue(val, rft)
switch {
case val.typ.cat == nilT:
values[fieldIndex] = func(*frame) reflect.Value { return reflect.New(rft).Elem() }
case val.typ.cat == funcT:
values[fieldIndex] = genFunctionWrapper(val)
case isArray(val.typ) && val.typ.val != nil && val.typ.val.cat == interfaceT:
values[fieldIndex] = genValueInterfaceArray(val)
case isRecursiveType(typ.field[fieldIndex].typ, typ.field[fieldIndex].typ.rtype):
values[fieldIndex] = genValueRecursiveInterface(val, typ.field[fieldIndex].typ.rtype)
case isInterface(typ.field[fieldIndex].typ):
values[fieldIndex] = genInterfaceWrapper(val, typ.field[fieldIndex].typ.rtype)
case isRecursiveType(ft, rft):
values[fieldIndex] = genValueRecursiveInterface(val, rft)
case isInterface(ft):
values[fieldIndex] = genInterfaceWrapper(val, rft)
default:
values[fieldIndex] = genValue(val)
}
@@ -3087,9 +3158,9 @@ func isNil(n *node) {
fnext := getExec(n.fnext)
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
vi := value(f).Interface().(valueInterface)
if (vi == valueInterface{} ||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
v := value(f)
vi, ok := v.Interface().(valueInterface)
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
dest(f).SetBool(true)
return tnext
}
@@ -3109,7 +3180,12 @@ func isNil(n *node) {
} else {
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
dest(f).SetBool(value(f).Interface().(valueInterface) == valueInterface{})
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
dest(f).SetBool(v.IsNil())
}
return tnext
}
} else {
@@ -3136,9 +3212,9 @@ func isNotNil(n *node) {
fnext := getExec(n.fnext)
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
vi := value(f).Interface().(valueInterface)
if (vi == valueInterface{} ||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
v := value(f)
vi, ok := v.Interface().(valueInterface)
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
dest(f).SetBool(false)
return fnext
}
@@ -3158,7 +3234,12 @@ func isNotNil(n *node) {
} else {
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
dest(f).SetBool(!(value(f).Interface().(valueInterface) == valueInterface{}))
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(!(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT))
} else {
dest(f).SetBool(!v.IsNil())
}
return tnext
}
} else {

View File

@@ -217,6 +217,7 @@ var binaryOpPredicates = opPredicates{
// binaryExpr type checks a binary expression.
func (check typecheck) binaryExpr(n *node) error {
c0, c1 := n.child[0], n.child[1]
a := n.action
if isAssignAction(a) {
a--
@@ -226,6 +227,21 @@ func (check typecheck) binaryExpr(n *node) error {
return check.shift(n)
}
switch n.action {
case aRem:
if zeroConst(c1) {
return n.cfgErrorf("invalid operation: division by zero")
}
case aQuo:
if zeroConst(c1) {
return n.cfgErrorf("invalid operation: division by zero")
}
if c0.rval.IsValid() && c1.rval.IsValid() {
// Avoid constant conversions below to ensure correct constant integer quotient.
return nil
}
}
_ = check.convertUntyped(c0, c1.typ)
_ = check.convertUntyped(c1, c0.typ)
@@ -241,16 +257,13 @@ func (check typecheck) binaryExpr(n *node) error {
if err := check.op(binaryOpPredicates, a, n, c0, t0); err != nil {
return err
}
switch n.action {
case aQuo, aRem:
if (c0.typ.untyped || isInt(t0)) && c1.typ.untyped && constant.Sign(c1.rval.Interface().(constant.Value)) == 0 {
return n.cfgErrorf("invalid operation: division by zero")
}
}
return nil
}
func zeroConst(n *node) bool {
return n.typ.untyped && constant.Sign(n.rval.Interface().(constant.Value)) == 0
}
func (check typecheck) index(n *node, max int) error {
if err := check.convertUntyped(n, &itype{cat: intT, name: "int"}); err != nil {
return err
@@ -621,16 +634,13 @@ func (check typecheck) conversion(n *node, typ *itype) error {
if !ok {
return n.cfgErrorf("cannot convert expression of type %s to type %s", n.typ.id(), typ.id())
}
if n.typ.untyped {
if isInterface(typ) || c != nil && !isConstType(typ) {
typ = n.typ.defaultType()
}
if err := check.convertUntyped(n, typ); err != nil {
return err
}
if !n.typ.untyped || c == nil {
return nil
}
return nil
if isInterface(typ) || !isConstType(typ) {
typ = n.typ.defaultType()
}
return check.convertUntyped(n, typ)
}
type param struct {

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract archive/tar'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract archive/zip'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract bufio'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract bytes'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/bzip2'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/flate'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/gzip'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/lzw'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/zlib'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/heap'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/list'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/ring'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract context'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/aes'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/cipher'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/des'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/dsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/ecdsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/elliptic'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/hmac'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/md5'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rand'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rc4'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha1'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha256'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha512'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/subtle'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/x509'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/x509/pkix'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract database/sql'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract database/sql/driver'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/dwarf'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/elf'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/gosym'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/macho'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/pe'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/plan9obj'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/ascii85'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/asn1'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/base32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/base64'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/binary'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/csv'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/gob'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/hex'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/json'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/pem'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/xml'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract expvar'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract flag'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract fmt'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/ast'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/build'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/constant'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/doc'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/format'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/importer'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/parser'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/printer'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/scanner'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/token'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/types'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/adler32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/crc32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/crc64'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/fnv'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/maphash'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract html'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract html/template'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/color'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/color/palette'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/draw'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/gif'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/jpeg'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image/png'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract index/suffixarray'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

Some files were not shown because too many files have changed in this diff Show More