Skip to content

Commit

Permalink
interp: refactor slice type management
Browse files Browse the repository at this point in the history
Add missing `sliceT` type category for consistency. Remove
`sizedef` field in `itype` struct. Rename field `size` to `length`.
Clean the various hacks used to cope with the absence of `sliceT`.
  • Loading branch information
mvertes authored Apr 13, 2021
1 parent 428b658 commit 7863456
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 64 deletions.
16 changes: 6 additions & 10 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case arrayT, variadicT:
case arrayT, sliceT, variadicT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = o.typ.val
Expand Down Expand Up @@ -525,10 +525,6 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
if dest.typ.incomplete {
return
}
if dest.typ.sizedef {
dest.typ.size = arrayTypeLen(src)
dest.typ.rtype = nil
}
if sc.global {
// Do not overload existing symbols (defined in GTA) in global scope
sym, _, _ = sc.lookup(dest.ident)
Expand Down Expand Up @@ -1054,8 +1050,8 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}

switch n.typ.cat {
case arrayT:
err = check.arrayLitExpr(child, n.typ.val, n.typ.size)
case arrayT, sliceT:
err = check.arrayLitExpr(child, n.typ)
case mapT:
err = check.mapLitExpr(child, n.typ.key, n.typ.val)
case structT:
Expand Down Expand Up @@ -2513,7 +2509,7 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
switch typ.cat {
case aliasT, ptrT:
gen = compositeGenerator(n, n.typ.val, rtyp)
case arrayT:
case arrayT, sliceT:
gen = arrayLit
case mapT:
gen = mapLit
Expand Down Expand Up @@ -2567,8 +2563,8 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
// array variable it is determined from the value's type, otherwise it is
// computed from the source definition.
func arrayTypeLen(n *node) int {
if n.typ != nil && n.typ.sizedef {
return n.typ.size
if n.typ != nil && n.typ.cat == arrayT {
return n.typ.length
}
max := -1
for i, c := range n.child[1:] {
Expand Down
20 changes: 11 additions & 9 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ func isRecursiveType(t *itype, rtype reflect.Type) bool {
return true
}
switch t.cat {
case ptrT, arrayT, mapT:
case arrayT, mapT, ptrT, sliceT:
return isRecursiveType(t.val, t.val.rtype)
default:
return false
Expand Down Expand Up @@ -1409,7 +1409,7 @@ func callBin(n *node) {
}
// empty interface, do not wrap it.
values = append(values, genValue(c))
case arrayT, variadicT:
case arrayT, sliceT, variadicT:
switch c.typ.val.cat {
case interfaceT:
if len(c.typ.val.field) > 0 {
Expand Down Expand Up @@ -2340,12 +2340,13 @@ func arrayLit(n *node) {
}

typ := n.typ.frameType()
kind := typ.Kind()
n.exec = func(f *frame) bltn {
var a reflect.Value
if n.typ.sizedef {
a, _ = n.typ.zero()
} else {
if kind == reflect.Slice {
a = reflect.MakeSlice(typ, max, max)
} else {
a, _ = n.typ.zero()
}
for i, v := range values {
a.Index(index[i]).Set(v(f))
Expand Down Expand Up @@ -2452,12 +2453,13 @@ func compositeBinSlice(n *node) {
}

typ := n.typ.frameType()
kind := typ.Kind()
n.exec = func(f *frame) bltn {
var a reflect.Value
if n.typ.sizedef {
a, _ = n.typ.zero()
} else {
if kind == reflect.Slice {
a = reflect.MakeSlice(typ, max, max)
} else {
a, _ = n.typ.zero()
}
for i, v := range values {
a.Index(index[i]).Set(v(f))
Expand Down Expand Up @@ -2947,7 +2949,7 @@ func _append(n *node) {
if len(n.child) == 3 {
c1, c2 := n.child[1], n.child[2]
if (c1.typ.cat == valueT || c2.typ.cat == valueT) && c1.typ.rtype == c2.typ.rtype ||
(c2.typ.cat == arrayT || c2.typ.cat == variadicT) && c2.typ.val.id() == n.typ.val.id() ||
(c2.typ.cat == arrayT || c2.typ.cat == sliceT || c2.typ.cat == variadicT) && c2.typ.val.id() == n.typ.val.id() ||
isByteArray(c1.typ.TypeOf()) && isString(c2.typ.TypeOf()) {
appendSlice(n)
return
Expand Down
75 changes: 34 additions & 41 deletions interp/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
int64T
mapT
ptrT
sliceT
srcPkgT
stringT
structT
Expand Down Expand Up @@ -75,6 +76,7 @@ var cats = [...]string{
int64T: "int64T",
mapT: "mapT",
ptrT: "ptrT",
sliceT: "sliceT",
srcPkgT: "srcPkgT",
stringT: "stringT",
structT: "structT",
Expand Down Expand Up @@ -109,19 +111,18 @@ type itype struct {
cat tcat // Type category
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, chanSendT, chanRecvT, mapT, ptrT, aliasT, arrayT or variadicT
val *itype // Type of value element if chanT, chanSendT, chanRecvT, mapT, ptrT, aliasT, arrayT, sliceT or variadicT
recv *itype // Receiver type for funcT or nil
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
path string // for a defined type, the package import path
size int // Size of array if ArrayT
length int // length of array if ArrayT
rtype reflect.Type // Reflection type if ValueT, or nil
incomplete bool // true if type must be parsed again (out of order declarations)
recursive bool // true if the type has an element which refer to itself
untyped bool // true for a literal value (string or number)
sizedef bool // true if array size is computed from type definition
isBinMethod bool // true if the type refers to a bin method function
node *node // root AST node of type definition
scope *scope // type declaration scope (in case of re-parse incomplete type)
Expand All @@ -141,9 +142,6 @@ func errorMethodType(sc *scope) *itype {
// nodeType returns a type definition for the corresponding AST subtree.
func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
if n.typ != nil && !n.typ.incomplete {
if n.kind == sliceExpr {
n.typ.sizedef = false
}
return n.typ, nil
}

Expand All @@ -169,29 +167,30 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.incomplete = t.val.incomplete

case arrayType:
t.cat = arrayT
c0 := n.child[0]
if len(n.child) == 1 {
// Array size is not defined.
t.cat = sliceT
if t.val, err = nodeType(interp, sc, c0); err != nil {
return nil, err
}
t.incomplete = t.val.incomplete
break
}
// Array size is defined.
t.cat = arrayT
switch v := c0.rval; {
case v.IsValid():
// Size if defined by a constant litteral value.
if isConstantValue(v.Type()) {
c := v.Interface().(constant.Value)
t.size = constToInt(c)
t.length = constToInt(c)
} else {
t.size = int(v.Int())
t.length = int(v.Int())
}
case c0.kind == ellipsisExpr:
// [...]T expression, get size from the length of composite array.
t.size = arrayTypeLen(n.anc)
t.length = arrayTypeLen(n.anc)
case c0.kind == identExpr:
sym, _, ok := sc.lookup(c0.ident)
if !ok {
Expand All @@ -207,11 +206,11 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
break
}
if v, ok := sym.rval.Interface().(int); ok {
t.size = v
t.length = v
break
}
if c, ok := sym.rval.Interface().(constant.Value); ok {
t.size = constToInt(c)
t.length = constToInt(c)
break
}
t.incomplete = true
Expand All @@ -225,12 +224,11 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
t.incomplete = true
break
}
t.size = constToInt(v)
t.length = constToInt(v)
}
if t.val, err = nodeType(interp, sc, n.child[1]); err != nil {
return nil, err
}
t.sizedef = true
t.incomplete = t.incomplete || t.val.incomplete

case basicLit:
Expand Down Expand Up @@ -503,7 +501,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
break
}
switch lt.cat {
case arrayT, mapT:
case arrayT, mapT, sliceT, variadicT:
t = lt.val
}

Expand Down Expand Up @@ -626,15 +624,14 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {

case sliceExpr:
t, err = nodeType(interp, sc, n.child[0])
if err != nil {
return nil, err
}
if t.cat == ptrT {
t = t.val
}
if err == nil && t.size != 0 {
t1 := *t
t1.size = 0
t1.sizedef = false
t1.rtype = nil
t = &t1
if t.cat == arrayT {
t = &itype{cat: sliceT, val: t.val, incomplete: t.incomplete, node: n, scope: sc}
}

case structType:
Expand Down Expand Up @@ -786,7 +783,7 @@ func (t *itype) referTo(name string, seen map[*itype]bool) bool {
}
seen[t] = true
switch t.cat {
case aliasT, arrayT, chanT, chanRecvT, chanSendT, ptrT:
case aliasT, arrayT, chanT, chanRecvT, chanSendT, ptrT, sliceT, variadicT:
return t.val.referTo(name, seen)
case funcT:
for _, a := range t.arg {
Expand Down Expand Up @@ -930,7 +927,7 @@ func isComplete(t *itype, visited map[string]bool) bool {
return true
}
fallthrough
case arrayT, chanT, chanRecvT, chanSendT, ptrT:
case arrayT, chanT, chanRecvT, chanSendT, ptrT, sliceT, variadicT:
return isComplete(t.val, visited)
case funcT:
complete := true
Expand Down Expand Up @@ -1129,11 +1126,7 @@ func (t *itype) id() (res string) {
case nilT:
res = "nil"
case arrayT:
if t.size == 0 {
res = "[]" + t.val.id()
} else {
res = "[" + strconv.Itoa(t.size) + "]" + t.val.id()
}
res = "[" + strconv.Itoa(t.length) + "]" + t.val.id()
case chanT:
res = "chan " + t.val.id()
case chanSendT:
Expand Down Expand Up @@ -1166,6 +1159,8 @@ func (t *itype) id() (res string) {
res = "map[" + t.key.id() + "]" + t.val.id()
case ptrT:
res = "*" + t.val.id()
case sliceT:
res = "[]" + t.val.id()
case structT:
res = "struct{"
for _, t := range t.field {
Expand All @@ -1178,6 +1173,8 @@ func (t *itype) id() (res string) {
res += t.rtype.PkgPath() + "."
}
res += t.rtype.Name()
case variadicT:
res = "..." + t.val.id()
}
return res
}
Expand All @@ -1191,7 +1188,7 @@ func (t *itype) zero() (v reflect.Value, err error) {
case aliasT:
v, err = t.val.zero()

case arrayT, ptrT, structT:
case arrayT, ptrT, structT, sliceT:
v = reflect.New(t.frameType()).Elem()

case valueT:
Expand Down Expand Up @@ -1438,12 +1435,10 @@ func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.T
switch t.cat {
case aliasT:
t.rtype = t.val.refType(defined, wrapRecursive)
case arrayT, variadicT:
if t.sizedef {
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined, wrapRecursive))
} else {
t.rtype = reflect.SliceOf(t.val.refType(defined, wrapRecursive))
}
case arrayT:
t.rtype = reflect.ArrayOf(t.length, t.val.refType(defined, wrapRecursive))
case sliceT, variadicT:
t.rtype = reflect.SliceOf(t.val.refType(defined, wrapRecursive))
case chanT:
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined, wrapRecursive))
case chanRecvT:
Expand Down Expand Up @@ -1518,12 +1513,10 @@ func (t *itype) frameType() (r reflect.Type) {
switch t.cat {
case aliasT:
r = t.val.frameType()
case arrayT, variadicT:
if t.sizedef {
r = reflect.ArrayOf(t.size, t.val.frameType())
} else {
r = reflect.SliceOf(t.val.frameType())
}
case arrayT:
r = reflect.ArrayOf(t.length, t.val.frameType())
case sliceT, variadicT:
r = reflect.SliceOf(t.val.frameType())
case funcT:
r = reflect.TypeOf((*node)(nil))
case interfaceT:
Expand Down
11 changes: 7 additions & 4 deletions interp/typecheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,10 @@ func (check typecheck) index(n *node, max int) error {
}

// arrayLitExpr type checks an array composite literal expression.
func (check typecheck) arrayLitExpr(child []*node, typ *itype, length int) error {
func (check typecheck) arrayLitExpr(child []*node, typ *itype) error {
cat := typ.cat
length := typ.length
typ = typ.val
visited := make(map[int]bool, len(child))
index := 0
for _, c := range child {
Expand All @@ -301,7 +304,7 @@ func (check typecheck) arrayLitExpr(child []*node, typ *itype, length int) error
}
n = c.child[1]
index = int(vInt(c.child[0].rval))
case length > 0 && index >= length:
case cat == arrayT && index >= length:
return c.cfgErrorf("index %d is out of bounds (>= %d)", index, length)
}

Expand Down Expand Up @@ -904,7 +907,7 @@ func arrayDeref(typ *itype) *itype {
return typ
}

if typ.cat == ptrT && typ.val.cat == arrayT && typ.val.sizedef {
if typ.cat == ptrT && typ.val.cat == arrayT {
return typ.val
}
return typ
Expand Down Expand Up @@ -960,7 +963,7 @@ func (check typecheck) argument(p param, ftyp *itype, i, l int, ellipsis bool) e
}
t := p.Type().TypeOf()
if t.Kind() != reflect.Slice || !(&itype{cat: valueT, rtype: t.Elem()}).assignableTo(atyp) {
return p.nod.cfgErrorf("cannot use %s as type %s", p.nod.typ.id(), (&itype{cat: arrayT, val: atyp}).id())
return p.nod.cfgErrorf("cannot use %s as type %s", p.nod.typ.id(), (&itype{cat: sliceT, val: atyp}).id())
}
return nil
}
Expand Down

0 comments on commit 7863456

Please sign in to comment.