Beispiel #1
0
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
}
Beispiel #2
0
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
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
// 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
}
Beispiel #7
0
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
}