func (p *printer) signature(params, result *ast.FieldList) { if params != nil { p.parameters(params) } else { p.print(token.LPAREN, token.RPAREN) } n := result.NumFields() if result != nil && result.Entangled != nil { n++ } if n > 0 { // result != nil p.print(blank) if n == 1 && result.List[0].Names == nil { // single anonymous result; no ()'s p.expr(stripParensAlways(result.List[0].Type)) return } p.parameters(result) } }
// filterFieldList removes unexported fields (field names) from the field list // in place and reports whether fields were removed. Anonymous fields are // recorded with the parent type. filterType is called with the types of // all remaining fields. // func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) { if fields == nil { return } list := fields.List j := 0 for _, field := range list { keepField := false if n := len(field.Names); n == 0 { // anonymous field fname := r.recordAnonymousField(parent, field.Type) if ast.IsExported(fname) { keepField = true } else if ityp != nil && fname == "error" { // possibly the predeclared error interface; keep // it for now but remember this interface so that // it can be fixed if error is also defined locally keepField = true r.remember(ityp) } } else { field.Names = filterIdentList(field.Names) if len(field.Names) < n { removedFields = true } if len(field.Names) > 0 { keepField = true } } if keepField { r.filterType(nil, field.Type) list[j] = field j++ } } if j < len(list) { removedFields = true } fields.List = list[0:j] return }
func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, entangled *Var, variadic bool) { if list == nil { return } var named, anonymous bool for i, field := range append(list.List, list.Entangled) { isEntangled := i == len(list.List) if isEntangled && field == nil { continue } 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) if isEntangled { if IsOptionable(typ) { typ = NewOptional(typ) } else if typ != Typ[Bool] { check.error(field.Pos(), "entangled type must be interface, map, channel, function, pointer or bool") } } // 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) if isEntangled { entangled = par } else { params = append(params, par) } } named = true } else { // anonymous parameter par := NewParam(ftype.Pos(), check.pkg, "", typ) check.recordImplicit(field, par) if isEntangled { entangled = par } else { 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, entangledRecvList, _ := check.collectParams(scope, recvPar, false) if entangledRecvList != nil { check.error(entangledRecvList.Pos(), "entangled variable in method receiver") } params, entangledParam, variadic := check.collectParams(scope, ftyp.Params, true) if entangledParam != nil && variadic { check.error(entangledRecvList.Pos(), "variadic function cannot have entangled parameters") } results, entangledResult, _ := 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, *T or ?*T where T is a type name." // (ignore invalid types - error was reported before) t := recv.typ if isOptional(t) { t = t.Underlying().(*Optional).Elem() } if t, _ := deref(t); 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 = NewTupleEntangled(append(params, entangledParam)...) sig.results = NewTupleEntangled(append(results, entangledResult)...) sig.variadic = variadic }