func (check *Checker) funcType(generic *Scope, sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
	scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
	scope.isFunc = true
	check.recordScope(ftyp, scope)
	if generic == nil {
		generic = scope
	}
	recvList, _ := check.collectParams(generic, scope, recvPar, false)
	params, variadic := check.collectParams(generic, scope, ftyp.Params, true)
	results, _ := check.collectParams(generic, scope, ftyp.Results, false)
	if recvPar != nil {
		var recv *Var
		switch len(recvList) {
		case 0:
			check.error(recvPar.Pos(), "method is missing receiver")
			recv = NewParam(0, nil, "", Typ[Invalid])  
		default:
			check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
			fallthrough  
		case 1:
			recv = recvList[0]
		}
		if t, _ := deref(recv.typ); t != Typ[Invalid] {
			var err string
			if I, ok := t.(*Instance); ok {
				t = I.Named()
			}
			if T, ok := t.(*Named); ok {
				if T.obj.pkg != check.pkg {
					err = "type not defined in this package"
				} else {
					switch u := T.underlying.(type) {
					case *Basic:
						if u.kind == UnsafePointer {
							err = "unsafe.Pointer"
						}
					case *Pointer, *Interface:
						err = "pointer or interface type"
					}
				}
			} else {
				err = "basic or unnamed type"
			}
			if err != "" {
				check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
			}
		}
		sig.recv = recv
	}
	sig.scope = scope
	sig.params = NewTuple(params...)
	sig.results = NewTuple(results...)
	sig.variadic = variadic
}
funcType type-checks a function or method type.
package types
import (
	"sort"
	"strconv"
	"github.com/faiface/generics/go/ast"
	"github.com/faiface/generics/go/constant"
	"github.com/faiface/generics/go/token"
)
func (check *Checker) ident(scope *Scope, x *operand, e *ast.Ident, def *Named, path []*TypeName) {
	x.mode = invalid
	x.expr = e
	scope, obj := scope.LookupParent(e.Name, check.pos)
	if obj == nil {
		if e.Name == "_" {
			check.errorf(e.Pos(), "cannot use _ as value or type")
		} else {
			check.errorf(e.Pos(), "undeclared name: %s", e.Name)
		}
		return
	}
	check.recordUse(e, obj)
	check.objDecl(obj, def, path)
	typ := obj.Type()
	assert(typ != nil)
	if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
		delete(check.unusedDotImports[scope], pkg)
	}
	switch obj := obj.(type) {
	case *PkgName:
		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
		return
	case *Const:
		check.addDeclDep(obj)
		if typ == Typ[Invalid] {
			return
		}
		if obj == universeIota {
			if check.iota == nil {
				check.errorf(e.Pos(), "cannot use iota outside constant declaration")
				return
			}
			x.val = check.iota
		} else {
			x.val = obj.val
		}
		assert(x.val != nil)
		x.mode = constant_
	case *TypeName:
		x.mode = typexpr
		for i, prev := range path {
			if prev == obj {
				check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
				for _, obj := range path[i:] {
					check.errorf(obj.Pos(), "\t%s refers to", obj.Name())  
				}
				check.errorf(obj.Pos(), "\t%s", obj.Name())
				typ = Typ[Invalid]
				break
			}
		}
	case *Var:
		if obj.pkg == check.pkg {
			obj.used = true
		}
		check.addDeclDep(obj)
		if typ == Typ[Invalid] {
			return
		}
		x.mode = variable
	case *Func:
		check.addDeclDep(obj)
		x.mode = value
	case *Builtin:
		x.id = obj.id
		x.mode = builtin
	case *Nil:
		x.mode = value
	default:
		unreachable()
	}
	x.typ = typ
}
func (check *Checker) typExpr(scope *Scope, e ast.Expr, def *Named, path []*TypeName, uninstantiatedOk bool) (T Type) {
	if trace {
		check.trace(e.Pos(), "%s", e)
		check.indent++
		defer func() {
			check.indent--
			check.trace(e.Pos(), "=> %s", T)
		}()
	}
	T = check.typExprInternal(scope, e, def, path, uninstantiatedOk)
	assert(isTyped(T))
	check.recordTypeAndValue(e, typexpr, T, nil)
	return
}
func (check *Checker) typ(scope *Scope, e ast.Expr, uninstantiatedOk bool) Type {
	return check.typExpr(scope, e, nil, nil, uninstantiatedOk)
}