func (t *Tuple) At(i int) Component {
	if i >= len(t.components) {
		return errorf("index out of range")
	}
	return t.components[i]
}
At returns the variable at index i.
package gotypes
import (
	"bytes"
	"errors"
	"fmt"
	"go/token"
	"go/types"
	"strconv"
	"github.com/mmcloughlin/avo/operand"
)
type Signature struct {
	pkg     *types.Package
	sig     *types.Signature
	params  *Tuple
	results *Tuple
}
func NewSignature(pkg *types.Package, sig *types.Signature) *Signature {
	s := &Signature{
		pkg: pkg,
		sig: sig,
	}
	s.init()
	return s
}
func NewSignatureVoid() *Signature {
	return NewSignature(nil, types.NewSignature(nil, nil, nil, false))
}
func LookupSignature(pkg *types.Package, name string) (*Signature, error) {
	scope := pkg.Scope()
	obj := scope.Lookup(name)
	if obj == nil {
		return nil, fmt.Errorf("could not find function \"%s\"", name)
	}
	s, ok := obj.Type().(*types.Signature)
	if !ok {
		return nil, fmt.Errorf("object \"%s\" does not have signature type", name)
	}
	return NewSignature(pkg, s), nil
}
func ParseSignature(expr string) (*Signature, error) {
	return ParseSignatureInPackage(nil, expr)
}
func ParseSignatureInPackage(pkg *types.Package, expr string) (*Signature, error) {
	tv, err := types.Eval(token.NewFileSet(), pkg, token.NoPos, expr)
	if err != nil {
		return nil, err
	}
	if tv.Value != nil {
		return nil, errors.New("signature expression should have nil value")
	}
	s, ok := tv.Type.(*types.Signature)
	if !ok {
		return nil, errors.New("provided type is not a function signature")
	}
	return NewSignature(pkg, s), nil
}
func (s *Signature) Params() *Tuple { return s.params }
func (s *Signature) Results() *Tuple { return s.results }
func (s *Signature) Bytes() int { return s.Params().Bytes() + s.Results().Bytes() }
func (s *Signature) String() string {
	var buf bytes.Buffer
	types.WriteSignature(&buf, s.sig, func(pkg *types.Package) string {
		if pkg == s.pkg {
			return ""
		}
		return pkg.Name()
	})
	return buf.String()
}
func (s *Signature) init() {
	p := s.sig.Params()
	r := s.sig.Results()
	vs := tuplevars(p)
	vs = append(vs, types.NewParam(token.NoPos, nil, "sentinel", types.Typ[types.Uint64]))
	paramsoffsets := Sizes.Offsetsof(vs)
	paramssize := paramsoffsets[p.Len()]
	s.params = newTuple(p, paramsoffsets, paramssize, "arg")
	vs = tuplevars(r)
	resultsoffsets := Sizes.Offsetsof(vs)
	var resultssize int64
	if n := len(vs); n > 0 {
		resultssize = resultsoffsets[n-1] + Sizes.Sizeof(vs[n-1].Type())
	}
	for i := range resultsoffsets {
		resultsoffsets[i] += paramssize
	}
	s.results = newTuple(r, resultsoffsets, resultssize, "ret")
}
type Tuple struct {
	components []Component
	byname     map[string]Component
	size       int
}
func newTuple(t *types.Tuple, offsets []int64, size int64, defaultprefix string) *Tuple {
	tuple := &Tuple{
		byname: map[string]Component{},
		size:   int(size),
	}
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		name := v.Name()
		if name == "" {
			name = defaultprefix
			if i > 0 {
				name += strconv.Itoa(i)
			}
		}
		addr := operand.NewParamAddr(name, int(offsets[i]))
		c := NewComponent(v.Type(), addr)
		tuple.components = append(tuple.components, c)
		if v.Name() != "" {
			tuple.byname[v.Name()] = c
		}
	}
	return tuple
}
func (t *Tuple) Lookup(name string) Component {
	e := t.byname[name]
	if e == nil {
		return errorf("unknown variable \"%s\"", name)
	}
	return e
}