func (check typecheck) typeAssertionExpr(n *node, typ *itype) error {
	if n.typ.TypeOf().Kind() != reflect.Interface {
		return n.cfgErrorf("invalid type assertion: non-interface type %s on left", n.typ.id())
	}
	ims := n.typ.methods()
	if len(ims) == 0 {
		return nil
	}
	if isInterface(typ) {
		return nil
	}
	for name := range ims {
		im := lookupFieldOrMethod(n.typ, name)
		tm := lookupFieldOrMethod(typ, name)
		if im == nil {
			continue
		}
		if tm == nil {
			return n.cfgErrorf("impossible type assertion: %s does not implement %s (missing %v method)", typ.id(), n.typ.id(), name)
		}
		if tm.recv != nil && tm.recv.TypeOf().Kind() == reflect.Ptr && typ.TypeOf().Kind() != reflect.Ptr {
			return n.cfgErrorf("impossible type assertion: %s does not implement %s as %q method has a pointer receiver", typ.id(), n.typ.id(), name)
		}
		err := n.cfgErrorf("impossible type assertion: %s does not implement %s", typ.id(), n.typ.id())
		if im.numIn() != tm.numIn() || im.numOut() != tm.numOut() {
			return err
		}
		for i := 0; i < im.numIn(); i++ {
			if !im.in(i).equals(tm.in(i)) {
				return err
			}
		}
		for i := 0; i < im.numOut(); i++ {
			if !im.out(i).equals(tm.out(i)) {
				return err
			}
		}
	}
	return nil
}
typeAssertionExpr type checks a type assert 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
}
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
}
func (check typecheck) mapLitExpr(child []*node, ktyp, vtyp *itype) error {
	visited := make(map[interface{}]bool, len(child))
	for _, c := range child {
		if c.kind != keyValueExpr {
			return c.cfgErrorf("missing key in map literal")
		}
		key, val := c.child[0], c.child[1]
		if err := check.assignment(key, ktyp, "map literal"); err != nil {
			return err
		}
		if key.rval.IsValid() {
			kval := key.rval.Interface()
			if visited[kval] {
				return c.cfgErrorf("duplicate key %s in map literal", kval)
			}
			visited[kval] = true
		}
		if err := check.assignment(val, vtyp, "map literal"); err != nil {
			return err
		}
	}
	return nil
}
func (check typecheck) structLitExpr(child []*node, typ *itype) error {
	if len(child) == 0 {
		return nil
	}
	if child[0].kind == keyValueExpr {
		visited := make([]bool, len(typ.field))
		for _, c := range child {
			if c.kind != keyValueExpr {
				return c.cfgErrorf("mixture of field:value and value elements in struct literal")
			}
			key, val := c.child[0], c.child[1]
			name := key.ident
			if name == "" {
				return c.cfgErrorf("invalid field name %s in struct literal", key.typ.id())
			}
			i := typ.fieldIndex(name)
			if i < 0 {
				return c.cfgErrorf("unknown field %s in struct literal", name)
			}
			field := typ.field[i]
			if err := check.assignment(val, field.typ, "struct literal"); err != nil {
				return err
			}
			if visited[i] {
				return c.cfgErrorf("duplicate field name %s in struct literal", name)
			}
			visited[i] = true
		}
		return nil
	}
	for i, c := range child {
		if c.kind == keyValueExpr {
			return c.cfgErrorf("mixture of field:value and value elements in struct literal")
		}
		if i >= len(typ.field) {
			return c.cfgErrorf("too many values in struct literal")
		}
		field := typ.field[i]
		if err := check.assignment(c, field.typ, "struct literal"); err != nil {
			return err
		}
	}
	if len(child) < len(typ.field) {
		return child[len(child)-1].cfgErrorf("too few values in struct literal")
	}
	return nil
}
func (check typecheck) structBinLitExpr(child []*node, typ reflect.Type) error {
	if len(child) == 0 {
		return nil
	}
	if child[0].kind == keyValueExpr {
		visited := make(map[string]bool, typ.NumField())
		for _, c := range child {
			if c.kind != keyValueExpr {
				return c.cfgErrorf("mixture of field:value and value elements in struct literal")
			}
			key, val := c.child[0], c.child[1]
			name := key.ident
			if name == "" {
				return c.cfgErrorf("invalid field name %s in struct literal", key.typ.id())
			}
			field, ok := typ.FieldByName(name)
			if !ok {
				return c.cfgErrorf("unknown field %s in struct literal", name)
			}
			if err := check.assignment(val, &itype{cat: valueT, rtype: field.Type}, "struct literal"); err != nil {
				return err
			}
			if visited[field.Name] {
				return c.cfgErrorf("duplicate field name %s in struct literal", name)
			}
			visited[field.Name] = true
		}
		return nil
	}
	for i, c := range child {
		if c.kind == keyValueExpr {
			return c.cfgErrorf("mixture of field:value and value elements in struct literal")
		}
		if i >= typ.NumField() {
			return c.cfgErrorf("too many values in struct literal")
		}
		field := typ.Field(i)
		if !canExport(field.Name) {
			return c.cfgErrorf("implicit assignment to unexported field %s in %s literal", field.Name, typ)
		}
		if err := check.assignment(c, &itype{cat: valueT, rtype: field.Type}, "struct literal"); err != nil {
			return err
		}
	}
	if len(child) < typ.NumField() {
		return child[len(child)-1].cfgErrorf("too few values in struct literal")
	}
	return nil
}
func (check typecheck) sliceExpr(n *node) error {
	c, child := n.child[0], n.child[1:]
	t := c.typ.TypeOf()
	var low, high, max *node
	if len(child) >= 1 {
		if n.action == aSlice {
			low = child[0]
		} else {
			high = child[0]
		}
	}
	if len(child) >= 2 {
		if n.action == aSlice {
			high = child[1]
		} else {
			max = child[1]
		}
	}
	if len(child) == 3 && n.action == aSlice {
		max = child[2]
	}
	l := -1
	valid := false
	switch t.Kind() {
	case reflect.String:
		valid = true
		if c.rval.IsValid() {
			l = len(vString(c.rval))
		}
		if max != nil {
			return max.cfgErrorf("invalid operation: 3-index slice of string")
		}
	case reflect.Array:
		valid = true
		l = t.Len()
	case reflect.Slice:
		valid = true
	case reflect.Ptr:
		if t.Elem().Kind() == reflect.Array {
			valid = true
			l = t.Elem().Len()
		}
	}
	if !valid {
		return c.cfgErrorf("cannot slice type %s", c.typ.id())
	}
	var ind [3]int64
	for i, nod := range []*node{low, high, max} {
		x := int64(-1)
		switch {
		case nod != nil:
			max := -1
			if l >= 0 {
				max = l + 1
			}
			if err := check.index(nod, max); err != nil {
				return err
			}
			if nod.rval.IsValid() {
				x = vInt(nod.rval)
			}
		case i == 0:
			x = 0
		case l >= 0:
			x = int64(l)
		}
		ind[i] = x
	}
	for i, x := range ind[:len(ind)-1] {
		if x <= 0 {
			continue
		}
		for _, y := range ind[i+1:] {
			if y < 0 || x <= y {
				continue
			}
			return n.cfgErrorf("invalid index values, must be low <= high <= max")
		}
	}
	return nil
}