fix: implement variadic using a type category to avoid corruption

This commit is contained in:
Marc Vertes
2019-09-10 13:12:03 +02:00
committed by Traefiker Bot
parent 2f0279f0f5
commit 82dd3f2953
4 changed files with 24 additions and 15 deletions

10
_test/variadic4.go Normal file
View File

@@ -0,0 +1,10 @@
package main
func variadic(s ...string) {}
func f(s string) { println(s + "bar") }
func main() { f("foo") }
// Output:
// foobar

View File

@@ -89,7 +89,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
case stringT:
ktyp = sc.getType("int")
vtyp = sc.getType("byte")
case arrayT:
case arrayT, variadicT:
ktyp = sc.getType("int")
vtyp = o.typ.val
}
@@ -260,9 +260,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if typ, err = nodeType(interp, sc, c.lastChild()); err != nil {
return false
}
if typ.variadic {
typ = &itype{cat: arrayT, val: typ}
}
for _, cc := range c.child[:len(c.child)-1] {
sc.sym[cc.ident] = &symbol{index: sc.add(typ), kind: varSym, typ: typ}
}
@@ -1584,7 +1581,7 @@ func variadicPos(n *node) int {
return -1
}
last := len(n.child[0].typ.arg) - 1
if n.child[0].typ.arg[last].variadic {
if n.child[0].typ.arg[last].cat == variadicT {
return last
}
return -1

View File

@@ -614,7 +614,7 @@ func call(n *node) {
if c.kind == basicLit {
var argType reflect.Type
if variadic >= 0 && i >= variadic {
argType = n.child[0].typ.arg[variadic].TypeOf()
argType = n.child[0].typ.arg[variadic].val.TypeOf()
} else {
argType = n.child[0].typ.arg[i].TypeOf()
}

View File

@@ -44,6 +44,7 @@ const (
uint64T
uintptrT
valueT
variadicT
maxT
)
@@ -82,6 +83,7 @@ var cats = [...]string{
uint64T: "uint64T",
uintptrT: "uintptrT",
valueT: "valueT",
variadicT: "variadicT",
}
func (c tcat) String() string {
@@ -102,17 +104,16 @@ type structField struct {
// itype defines the internal representation of types in the interpreter
type itype struct {
cat tcat // Type category
field []structField // Array of struct fields if StrucT or InterfaceT
field []structField // Array of struct fields if structT or interfaceT
key *itype // Type of key element if MapT or nil
val *itype // Type of value element if ChanT, MapT, PtrT, AliasT or ArrayT
arg []*itype // Argument types if FuncT or nil
ret []*itype // Return types if FuncT or nil
val *itype // Type of value element if chanT, mapT, ptrT, aliasT, arrayT or variadicT
arg []*itype // Argument types if funcT or nil
ret []*itype // Return types if funcT or nil
method []*node // Associated methods or nil
name string // name of type within its package for a defined type
pkgPath string // for a defined type, the package import path
size int // Size of array if ArrayT
rtype reflect.Type // Reflection type if ValueT, or nil
variadic bool // true if type is variadic
incomplete bool // true if type must be parsed again (out of order declarations)
untyped bool // true for a literal value (string or number)
sizedef bool // true if array size is computed from type definition
@@ -280,10 +281,11 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.incomplete = t.val.incomplete
case ellipsisExpr:
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
t.cat = variadicT
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
t.variadic = true
t.incomplete = t.val.incomplete
case funcLit:
t, err = nodeType(interp, sc, n.child[2])
@@ -720,7 +722,7 @@ func (t *itype) Type(name string) reflect.Type {
}
switch t.cat {
case arrayT:
case arrayT, variadicT:
if t.size > 0 {
t.rtype = reflect.ArrayOf(t.size, t.val.Type(name))
} else {
@@ -774,7 +776,7 @@ func (t *itype) frameType() (r reflect.Type) {
panic(err)
}
switch t.cat {
case arrayT:
case arrayT, variadicT:
if t.size > 0 {
r = reflect.ArrayOf(t.size, t.val.frameType())
} else {