interp: fix computation of ellipsis array length

Fixes #1287.
This commit is contained in:
Marc Vertes
2021-10-20 14:36:05 +02:00
committed by GitHub
parent 229ddfdae1
commit f46ef67180
4 changed files with 52 additions and 15 deletions

View File

@@ -6,16 +6,18 @@ const (
zero = iota
one
two
three
)
func main() {
a := [...]string{
zero: "zero",
one: "one",
two: "two",
zero: "zero",
one: "one",
three: "three",
three + 2: "five",
}
fmt.Printf("%v %T\n", a, a)
}
// Output:
// [zero one two] [3]string
// [zero one three five] [6]string

View File

@@ -286,11 +286,11 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
case compositeLitExpr:
if len(n.child) > 0 && n.child[0].isType(sc) {
// Get type from 1st child
// Get type from 1st child.
if n.typ, err = nodeType(interp, sc, n.child[0]); err != nil {
return false
}
// Indicate that the first child is the type
// Indicate that the first child is the type.
n.nleft = 1
} else {
// Get type from ancestor (implicit type)
@@ -2626,23 +2626,54 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
// arrayTypeLen returns the node's array length. If the expression is an
// array variable it is determined from the value's type, otherwise it is
// computed from the source definition.
func arrayTypeLen(n *node) int {
func arrayTypeLen(n *node, sc *scope) (int, error) {
if n.typ != nil && n.typ.cat == arrayT {
return n.typ.length
return n.typ.length, nil
}
max := -1
for i, c := range n.child[1:] {
r := i
if c.kind == keyValueExpr {
if v := c.child[0].rval; v.IsValid() {
r = int(c.child[0].rval.Int())
for _, c := range n.child[1:] {
var r int
if c.kind != keyValueExpr {
r = max + 1
max = r
continue
}
c0 := c.child[0]
v := c0.rval
if v.IsValid() {
r = int(v.Int())
} else {
// Resolve array key value as a constant.
if c0.kind == identExpr {
// Key is defined by a symbol which must be a constant integer.
sym, _, ok := sc.lookup(c0.ident)
if !ok {
return 0, c0.cfgErrorf("undefined: %s", c0.ident)
}
if sym.kind != constSym {
return 0, c0.cfgErrorf("non-constant array bound %q", c0.ident)
}
r = int(vInt(sym.rval))
} else {
// Key is defined by a numeric constant expression.
if _, err := c0.interp.cfg(c0, sc, sc.pkgID, sc.pkgName); err != nil {
return 0, err
}
cv, ok := c0.rval.Interface().(constant.Value)
if !ok {
return 0, c0.cfgErrorf("non-constant expression")
}
r = constToInt(cv)
}
}
if r > max {
max = r
}
}
return max + 1
return max + 1, nil
}
// isValueUntyped returns true if value is untyped.

View File

@@ -445,6 +445,7 @@ func TestEvalCompositeArray(t *testing.T) {
{src: `a := [1]int{1, 2}`, err: "1:43: index 1 is out of bounds (>= 1)"},
{src: `b := [l]int{1, 2}`, res: "[1 2 0 0 0 0 0 0 0 0]"},
{src: `i := 10; a := [i]int{1, 2}`, err: "1:43: non-constant array bound \"i\""},
{src: `c := [...]float64{1, 3: 3.4, 5}`, res: "[1 0 0 3.4 5]"},
})
}

View File

@@ -438,7 +438,10 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
}
case c0.kind == ellipsisExpr:
// [...]T expression, get size from the length of composite array.
length = arrayTypeLen(n.anc)
length, err = arrayTypeLen(n.anc, sc)
if err != nil {
incomplete = true
}
case c0.kind == identExpr:
sym, _, ok := sc.lookup(c0.ident)
if !ok {