func (f *File) validResults(results *ast.FieldList) *Error { if results == nil || results.List == nil { return nil } if results.NumFields() != 1 { err := fmt.Sprint("ERROR: can only return at most one result, not:", results.NumFields()) return &Error{errors.New(err), results.Pos()} } result := results.List[0] if result == nil { return nil } if result.Names != nil { return &Error{errors.New(fmt.Sprint("ERROR: can only return nonnamed result, not:", result.Names)), result.Pos()} } typ := f.Info.TypeOf(result.Type) if err := f.validResultType(typ); err != nil { err.Pos = result.Pos() if f.validVarDeclType(typ) == nil { err.Err = errors.New(fmt.Sprint(err.Err) + ", type only valid as a var decl, or param") } else if f.validParamType(typ) == nil { err.Err = errors.New(fmt.Sprint(err.Err) + ", type only valid as func param type") } return err } return nil }
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 }
func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) sig, ok := typ.(*Signature) if !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { methods = append(methods, &Method{QualifiedName{check.pkg, name.Name}, sig}) } } else { // embedded interface utyp := underlying(typ) if ityp, ok := utyp.(*Interface); ok { methods = append(methods, ityp.Methods...) } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", typ) } } } // Check for double declarations. // The parser inserts methods into an interface-local scope, so local // double declarations are reported by the parser already. We need to // check again for conflicts due to embedded interfaces. This will lead // to a 2nd error message if the double declaration was reported before // by the parser. // TODO(gri) clean this up a bit seen := make(map[string]bool) for _, m := range methods { if seen[m.Name] { check.errorf(list.Pos(), "multiple methods named %s", m.Name) return // keep multiple entries, lookup will only return the first entry } seen[m.Name] = true } return }
func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) if _, ok := typ.(*Signature); !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { obj := name.Obj obj.Type = typ methods = append(methods, obj) } } else { // embedded interface utyp := underlying(typ) if ityp, ok := utyp.(*Interface); ok { methods = append(methods, ityp.Methods...) } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", typ) } } } // check for double declarations methods.Sort() prev := "" for _, obj := range methods { if obj.Name == prev { check.errorf(list.Pos(), "multiple methods named %s", prev) return // keep multiple entries, lookup will only return the first entry } } return }
func (check *checker) collectMethods(list *ast.FieldList) (methods ObjSet) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) sig, ok := typ.(*Signature) if !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { // TODO(gri) provide correct declaration info obj := &Func{check.pkg, name.Name, sig, nil} if alt := methods.Insert(obj); alt != nil { check.errorf(list.Pos(), "multiple methods named %s", name.Name) } check.register(name, obj) } } else { // embedded interface utyp := typ.Underlying() if ityp, ok := utyp.(*Interface); ok { for _, obj := range ityp.methods.entries { if alt := methods.Insert(obj); alt != nil { check.errorf(list.Pos(), "multiple methods named %s", obj.Name()) } } } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", 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 }
func (f *File) validParams(params *ast.FieldList) *Error { if params == nil { panic("ERROR: params fieldlist should never be nil") } if params.List == nil { return nil } for i := 0; i < params.NumFields(); i++ { field := params.List[i] if field == nil { return &Error{errors.New(fmt.Sprint("ERROR nil field, anonymous fields not allowed!!")), params.Pos()} } if len(field.Names) != 1 { panic("ERROR len(field.Names) != 1!!") } name := field.Names[0] if name == nil { panic("ERROR name == nil, this shouldn't occur") } typ := f.Info.TypeOf(field.Type) if e := f.validParamType(typ); e != nil { e.Pos = field.Pos() return e } } return nil }