func (b *ResolvedBinding) FindRefs(lookup *TypeLookup) ([]*BoundReference, error) {
	if !b.Exp.HasRef() {
		return nil, nil
	}
	return b.Exp.FindTypedRefs(nil, b.Type, lookup)
}
Finds all of the expressions in this binding which are reference expressions,
with types attached.

This is distsinct from Exp.FindRefs() in that it propagates type information,
which is relevant if any type conversions are taking place.  However, any
references inside a type a untyped map will not have complete type
information.
package syntax
import (
	"fmt"
	"sort"
	"strings"
)
type (
	ResolvedBinding struct {
		Exp Exp `json:"expression"`
		Type Type `json:"type"`
	}
	ResolvedBindingMap map[string]*ResolvedBinding
	BoundReference struct {
		Exp  *RefExp
		Type Type
	}
)
type bindingError struct {
	Msg string
	Err error
}
func (err *bindingError) Error() string {
	if e := err.Err; e == nil {
		return err.Msg
	} else {
		var buf strings.Builder
		buf.Grow(len(err.Msg) + 25)
		err.writeTo(&buf)
		return buf.String()
	}
}
func (err *bindingError) Unwrap() error {
	if err == nil {
		return err
	}
	return err.Err
}
func (err *bindingError) writeTo(w stringWriter) {
	if e := err.Err; e == nil {
		mustWriteString(w, err.Msg)
	} else {
		mustWriteString(w, err.Msg)
		if len(err.Msg) > 20 {
			mustWriteString(w, ":\n\t")
		} else {
			mustWriteString(w, ": ")
		}
		if ew, ok := e.(errorWriter); ok {
			ew.writeTo(w)
		} else {
			mustWriteString(w, e.Error())
		}
	}
}
func (bindings *BindStms) resolve(self, calls map[string]*ResolvedBinding,
	lookup *TypeLookup) (map[string]*ResolvedBinding, error) {
	if len(bindings.List) == 0 {
		return nil, nil
	}
	result := make(map[string]*ResolvedBinding, len(bindings.List))
	var errs ErrorList
	for _, binding := range bindings.List {
		if binding.Id == "*" {
			continue
		}
		tid := binding.Tname
		r, err := resolveExp(binding.Exp, tid, self, calls, lookup)
		if err != nil {
			errs = append(errs, &bindingError{
				Msg: "BindingError: parameter " + binding.Id,
				Err: err,
			})
		}
		result[binding.Id] = r
	}
	return result, errs.If()
}
func resolveExp(exp Exp, tname TypeId, self, siblings map[string]*ResolvedBinding,
	lookup *TypeLookup) (*ResolvedBinding, error) {
	t := lookup.Get(tname)
	if t == nil {
		return nil, fmt.Errorf("unknown type " + tname.String())
	}
	rexp, err := exp.resolveRefs(self, siblings, lookup)
	if err != nil {
		return &ResolvedBinding{
			Exp:  exp,
			Type: t,
		}, err
	}
	fexp, err := rexp.filter(t, lookup)
	if err != nil {
		return &ResolvedBinding{
			Exp:  fexp,
			Type: t,
		}, err
	}
	if s, ok := fexp.(*SplitExp); ok {
		if it, err := lookup.AddDim(t, s.Source.CallMode()); err == nil {
			if s.Type != nil && s.Type.IsAssignableFrom(it, lookup) == nil {
				s.Type = it
			} else if ok {
				s.Type = it
			}
		}
	}
	return &ResolvedBinding{
		Exp:  fexp,
		Type: t,
	}, err
}
func bindingType(p string, t Type, lookup *TypeLookup) (Type, error) {
	if p == "" {
		return t, nil
	}
	switch t := t.(type) {
	case *TypedMapType:
		r, err := bindingType(p, t.Elem, lookup)
		if r != nil {
			return lookup.GetMap(r), err
		}
		return r, err
	case *ArrayType:
		r, err := bindingType(p, t.Elem, lookup)
		if r != nil {
			return lookup.GetArray(r, t.Dim), err
		}
		return r, err
	case *StructType:
		element := p
		rest := ""
		if i := strings.IndexRune(p, '.'); i > 0 {
			element = p[:i]
			rest = p[i+1:]
		}
		member := t.Table[element]
		if member == nil {
			return t, &bindingError{
				Msg: "no member " + element + " in " + t.Id,
			}
		}
		return bindingType(rest, lookup.Get(member.Tname), lookup)
	}
	return t, &bindingError{
		Msg: "can't resolve path through " + t.TypeId().str(),
	}
}
func (b *ResolvedBinding) BindingPath(p string,
	forks map[*CallStm]CollectionIndex,
	lookup *TypeLookup) (*ResolvedBinding, error) {
	t, err := bindingType(p, b.Type, lookup)
	if err != nil {
		return b, err
	}
	e, err := b.Exp.BindingPath(p, forks, lookup)
	if err != nil || (e == b.Exp && t == b.Type) {
		return b, err
	}
	return &ResolvedBinding{
		Exp:  e,
		Type: t,
	}, nil
}
func (*BoundReference) KnownLength() bool {
	return false
}
func (*BoundReference) ArrayLength() int {
	return -1
}
func (*BoundReference) Keys() map[string]Exp {
	return nil
}
func (b *BoundReference) CallMode() CallMode {
	switch b.Type.(type) {
	case *ArrayType:
		return ModeArrayCall
	case *TypedMapType:
		return ModeMapCall
	case nullType:
		return ModeNullMapCall
	default:
		return ModeSingleCall
	}
}
func (b *BoundReference) GoString() string {
	if b == nil || b.Exp == nil {
		return "null ref"
	}
	if b.Type == nil {
		return b.Exp.GoString() + " (unknown type)"
	}
	return b.Exp.GoString() + " (" + b.Type.TypeId().str() + ")"
}