@@ -52,8 +52,10 @@ import (
5252 "strings"
5353
5454 "golang.org/x/tools/go/types/objectpath"
55+ "golang.org/x/tools/gopls/internal/util/bug"
5556 "golang.org/x/tools/gopls/internal/util/frob"
5657 "golang.org/x/tools/gopls/internal/util/safetoken"
58+ "golang.org/x/tools/internal/typesinternal"
5759)
5860
5961// An Index records the non-empty method sets of all package-level
@@ -223,16 +225,40 @@ func (b *indexBuilder) build(fset *token.FileSet, pkg *types.Package) *Index {
223225 return
224226 }
225227
226- m .Posn = objectPos (method )
227- m .PkgPath = b .string (method .Pkg ().Path ())
228-
229228 // Instantiations of generic methods don't have an
230229 // object path, so we use the generic.
231- if p , err := objectpathFor (method .Origin ()); err != nil {
232- panic (err ) // can't happen for a method of a package-level type
233- } else {
234- m .ObjectPath = b .string (string (p ))
230+ p , err := objectpathFor (method .Origin ())
231+ if err != nil {
232+ // This should never happen for a method of a package-level type.
233+ // ...but it does (golang/go#70418).
234+ // Refine the crash into various bug reports.
235+ report := func () {
236+ bug .Reportf ("missing object path for %s" , method .FullName ())
237+ }
238+ sig := method .Signature ()
239+ if sig .Recv () == nil {
240+ report ()
241+ return
242+ }
243+ _ , named := typesinternal .ReceiverNamed (sig .Recv ())
244+ switch {
245+ case named == nil :
246+ report ()
247+ case sig .TypeParams ().Len () > 0 :
248+ report ()
249+ case method .Origin () != method :
250+ report () // instantiated?
251+ case sig .RecvTypeParams ().Len () > 0 :
252+ report () // generic?
253+ default :
254+ report ()
255+ }
256+ return
235257 }
258+
259+ m .Posn = objectPos (method )
260+ m .PkgPath = b .string (method .Pkg ().Path ())
261+ m .ObjectPath = b .string (string (p ))
236262 }
237263
238264 // We ignore aliases, though in principle they could define a
0 commit comments