func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) { if list == nil { return } var named, anonymous bool for i, field := range list.List { ftype := field.Type if t, _ := ftype.(*ast.Ellipsis); t != nil { ftype = t.Elt if variadicOk && i == len(list.List)-1 { variadic = true } else { check.invalidAST(field.Pos(), "... not permitted") // ignore ... and continue } } typ := check.typ(ftype) // The parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag. if len(field.Names) > 0 { // named parameter for _, name := range field.Names { if name.Name == "" { check.invalidAST(name.Pos(), "anonymous parameter") // ok to continue } par := NewParam(name.Pos(), check.pkg, name.Name, typ) check.declare(scope, name, par, scope.pos) params = append(params, par) } named = true } else { // anonymous parameter par := NewParam(ftype.Pos(), check.pkg, "", typ) check.recordImplicit(field, par) params = append(params, par) anonymous = true } } if named && anonymous { check.invalidAST(list.Pos(), "list contains both named and anonymous parameters") // ok to continue } // For a variadic function, change the last parameter's type from T to []T. if variadic && len(params) > 0 { last := params[len(params)-1] last.typ = &Slice{elem: last.typ} } return }
// funcType type-checks a function or method type. func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { scope := NewScope(check.scope, token.NoPos, token.NoPos, "function") check.recordScope(ftyp, scope) recvList, _ := check.collectParams(scope, recvPar, false) params, variadic := check.collectParams(scope, ftyp.Params, true) results, _ := check.collectParams(scope, ftyp.Results, false) if recvPar != nil { // recv parameter list present (may be empty) // spec: "The receiver is specified via an extra parameter section preceding the // method name. That parameter section must declare a single parameter, the receiver." var recv *Var switch len(recvList) { case 0: check.error(recvPar.Pos(), "method is missing receiver") recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below default: // more than one receiver check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") fallthrough // continue with first receiver case 1: recv = recvList[0] } // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) if t, _ := deref(recv.typ); t != Typ[Invalid] { var err string if T, _ := t.(*Named); T != nil { // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." if T.obj.pkg != check.pkg { err = "type not defined in this package" } else { // TODO(gri) This is not correct if the underlying type is unknown yet. switch u := T.underlying.(type) { case *Basic: // unsafe.Pointer is treated like a regular pointer 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) // ok to continue } } sig.recv = recv } sig.scope = scope sig.params = NewTuple(params...) sig.results = NewTuple(results...) sig.variadic = variadic }