// Insert inserts the given declaration into the current scope. func (s *Scope) Insert(decl ast.Decl) error { // Early return for first-time declarations. ident := decl.Name() if ident == nil { // Anonymous function parameter declaration. return nil } name := ident.String() prev, ok := s.Decls[name] if !ok { s.Decls[name] = decl return nil } prevIdent := prev.Name() if prevIdent.NamePos == ident.NamePos { // Identifier already added to scope. return nil } // Previously declared. if !types.Equal(prev.Type(), decl.Type()) { return errors.Newf(ident.Start(), "redefinition of %q with type %q instead of %q", name, decl.Type(), prev.Type()) } // The last tentative definition becomes the definition, unless defined // explicitly (e.g. having an initializer or function body). if !s.IsDef(prev) { s.Decls[name] = decl return nil } // Definition already present in scope. if s.IsDef(decl) { // TODO: Consider adding support for multiple errors (and potentially // warnings and notifications). // // If support for notifications are added, add a note of the previous declaration. // errors.Notef(prevIdent.Start(), "previous definition of %q", name) return errors.Newf(ident.Start(), "redefinition of %q", name) } // Declaration of previously declared identifier. return nil }
// IsDef reports whether the given declaration is a definition. func IsDef(decl ast.Decl) bool { if _, ok := decl.(*ast.VarDecl); ok { return true } return decl.Value() != nil }
// isTentativeDef reports whether the given global variable or function // declaration is a tentative definition. func isTentativeDef(n ast.Decl) bool { ident := n.Name() def := ident.Decl.Name() return ident.Start() != def.Start() }