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 {
		n := c
		switch {
		case c.kind == keyValueExpr:
			if err := check.index(c.child[0], length); err != nil {
				return c.cfgErrorf("index %s must be integer constant", c.child[0].typ.id())
			}
			n = c.child[1]
			index = int(vInt(c.child[0].rval))
		case cat == arrayT && index >= length:
			return c.cfgErrorf("index %d is out of bounds (>= %d)", index, length)
		}
		if visited[index] {
			return n.cfgErrorf("duplicate index %d in array or slice literal", index)
		}
		visited[index] = true
		index++
		if err := check.assignment(n, typ, "array or slice literal"); err != nil {
			return err
		}
	}
	return nil
}
arrayLitExpr type checks an array composite literal expression.
package interp
import (
	"errors"
	"go/constant"
	"math"
	"reflect"
)
type opPredicates map[action]func(reflect.Type) bool
type typecheck struct{}
func (check typecheck) op(p opPredicates, a action, n, c *node, t reflect.Type) error {
	if pred := p[a]; pred != nil {
		if !pred(t) {
			return n.cfgErrorf("invalid operation: operator %v not defined on %s", n.action, c.typ.id())
		}
	} else {
		return n.cfgErrorf("invalid operation: unknown operator %v", n.action)
	}
	return nil
}
func (check typecheck) assignment(n *node, typ *itype, context string) error {
	if n.typ == nil {
		return n.cfgErrorf("invalid type in %s", context)
	}
	if n.typ.untyped {
		if typ == nil || isInterface(typ) {
			if typ == nil && n.typ.cat == nilT {
				return n.cfgErrorf("use of untyped nil in %s", context)
			}
			typ = n.typ.defaultType(n.rval)
		}
		if err := check.convertUntyped(n, typ); err != nil {
			return err
		}
	}
	if typ == nil {
		return nil
	}
	if typ.isIndirectRecursive() || n.typ.isIndirectRecursive() {
		return nil
	}
	if !n.typ.assignableTo(typ) {
		if context == "" {
			return n.cfgErrorf("cannot use type %s as type %s", n.typ.id(), typ.id())
		}
		return n.cfgErrorf("cannot use type %s as type %s in %s", n.typ.id(), typ.id(), context)
	}
	return nil
}
func (check typecheck) assignExpr(n, dest, src *node) error {
	if n.action == aAssign {
		isConst := n.anc.kind == constDecl
		if !isConst {
			dest.typ = dest.typ.defaultType(src.rval)
		}
		return check.assignment(src, dest.typ, "assignment")
	}
	if n.nleft > 1 || n.nright > 1 {
		return n.cfgErrorf("assignment operation %s requires single-valued expressions", n.action)
	}
	return check.binaryExpr(n)
}
func (check typecheck) addressExpr(n *node) error {
	c0 := n.child[0]
	found := false
	for !found {
		switch c0.kind {
		case parenExpr:
			c0 = c0.child[0]
			continue
		case selectorExpr:
			c0 = c0.child[1]
			continue
		case starExpr:
			c0 = c0.child[0]
			continue
		case indexExpr, sliceExpr:
			c := c0.child[0]
			if isArray(c.typ) || isMap(c.typ) {
				c0 = c
				found = true
				continue
			}
		case compositeLitExpr, identExpr:
			found = true
			continue
		}
		return n.cfgErrorf("invalid operation: cannot take address of %s [kind: %s]", c0.typ.id(), kinds[c0.kind])
	}
	return nil
}
func (check typecheck) starExpr(n *node) error {
	if n.typ.TypeOf().Kind() != reflect.Ptr {
		return n.cfgErrorf("invalid operation: cannot indirect %q", n.name())
	}
	return nil
}
var unaryOpPredicates = opPredicates{
	aPos:    isNumber,
	aNeg:    isNumber,
	aBitNot: isInt,
	aNot:    isBoolean,
}
func (check typecheck) unaryExpr(n *node) error {
	c0 := n.child[0]
	t0 := c0.typ.TypeOf()
	if n.action == aRecv {
		if !isChan(c0.typ) {
			return n.cfgErrorf("invalid operation: cannot receive from non-channel %s", c0.typ.id())
		}
		if isSendChan(c0.typ) {
			return n.cfgErrorf("invalid operation: cannot receive from send-only channel %s", c0.typ.id())
		}
		return nil
	}
	return check.op(unaryOpPredicates, n.action, n, c0, t0)
}
func (check typecheck) shift(n *node) error {
	c0, c1 := n.child[0], n.child[1]
	t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
	var v0 constant.Value
	if c0.typ.untyped && c0.rval.IsValid() {
		v0 = constant.ToInt(c0.rval.Interface().(constant.Value))
		c0.rval = reflect.ValueOf(v0)
	}
	if !(c0.typ.untyped && v0 != nil && v0.Kind() == constant.Int || isInt(t0)) {
		return n.cfgErrorf("invalid operation: shift of type %v", c0.typ.id())
	}
	switch {
	case c1.typ.untyped:
		if err := check.convertUntyped(c1, &itype{cat: uintT, name: "uint"}); err != nil {
			return n.cfgErrorf("invalid operation: shift count type %v, must be integer", c1.typ.id())
		}
	case isInt(t1):
	default:
		return n.cfgErrorf("invalid operation: shift count type %v, must be integer", c1.typ.id())
	}
	return nil
}
func (check typecheck) comparison(n *node) error {
	c0, c1 := n.child[0], n.child[1]
	if !c0.typ.assignableTo(c1.typ) && !c1.typ.assignableTo(c0.typ) {
		return n.cfgErrorf("invalid operation: mismatched types %s and %s", c0.typ.id(), c1.typ.id())
	}
	ok := false
	switch n.action {
	case aEqual, aNotEqual:
		ok = c0.typ.comparable() && c1.typ.comparable() || c0.typ.isNil() && c1.typ.hasNil() || c1.typ.isNil() && c0.typ.hasNil()
	case aLower, aLowerEqual, aGreater, aGreaterEqual:
		ok = c0.typ.ordered() && c1.typ.ordered()
	}
	if !ok {
		typ := c0.typ
		if typ.isNil() {
			typ = c1.typ
		}
		return n.cfgErrorf("invalid operation: operator %v not defined on %s", n.action, typ.id(), ".")
	}
	return nil
}
var binaryOpPredicates = opPredicates{
	aAdd: func(typ reflect.Type) bool { return isNumber(typ) || isString(typ) },
	aSub: isNumber,
	aMul: isNumber,
	aQuo: isNumber,
	aRem: isInt,
	aAnd:    isInt,
	aOr:     isInt,
	aXor:    isInt,
	aAndNot: isInt,
	aLand: isBoolean,
	aLor:  isBoolean,
}
func (check typecheck) binaryExpr(n *node) error {
	c0, c1 := n.child[0], n.child[1]
	a := n.action
	if isAssignAction(a) {
		a--
	}
	if isShiftAction(a) {
		return check.shift(n)
	}
	switch n.action {
	case aAdd:
		if n.typ == nil {
			break
		}
		k, k0, k1 := isNumber(n.typ.TypeOf()), isNumber(c0.typ.TypeOf()), isNumber(c1.typ.TypeOf())
		if k != k0 || k != k1 {
			return n.cfgErrorf("cannot use type %s as type %s in assignment", c0.typ.id(), n.typ.id())
		}
	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() {
			return nil
		}
	}
	_ = check.convertUntyped(c0, c1.typ)
	_ = check.convertUntyped(c1, c0.typ)
	if isComparisonAction(a) {
		return check.comparison(n)
	}
	if !c0.typ.equals(c1.typ) {
		return n.cfgErrorf("invalid operation: mismatched types %s and %s", c0.typ.id(), c1.typ.id())
	}
	t0 := c0.typ.TypeOf()
	return check.op(binaryOpPredicates, a, n, c0, t0)
}
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
	}
	if !isInt(n.typ.TypeOf()) {
		return n.cfgErrorf("index %s must be integer", n.typ.id())
	}
	if !n.rval.IsValid() || max < 1 {
		return nil
	}
	if int(vInt(n.rval)) >= max {
		return n.cfgErrorf("index %s is out of bounds", n.typ.id())
	}
	return nil
}