gopls version

Build info
----------
golang.org/x/tools/gopls v0.20.0
    golang.org/x/tools/gopls@v0.20.0 h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4=
    github.com/BurntSushi/toml@v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
    github.com/fatih/camelcase@v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
    github.com/fatih/gomodifytags@v1.17.1-0.20250423142747-f3939df9aa3c h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg=
    github.com/fatih/structtag@v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
    github.com/fsnotify/fsnotify@v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
    github.com/google/go-cmp@v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
    golang.org/x/exp/typeparams@v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
    golang.org/x/mod@v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
    golang.org/x/sync@v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
    golang.org/x/sys@v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
    golang.org/x/telemetry@v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
    golang.org/x/text@v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
    golang.org/x/tools@v0.35.1-0.20250728180453-01a3475a31bc h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM=
    golang.org/x/vuln@v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
    honnef.co/go/tools@v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw=
    mvdan.cc/gofumpt@v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
    mvdan.cc/xurls/v2@v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
go: go1.24.6

go env

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN='/home/caleb/bin'
GOCACHE='/home/caleb/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/caleb/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3694712078=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/caleb/w/liftoff/go.mod'
GOMODCACHE='/home/caleb/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/caleb/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/caleb/3p/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/caleb/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/caleb/3p/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

(This seems very similar to, or perhaps a dupe of, #40278, judging by the description. However, gopls definitely doesn't seem to do what is described there.)

It's unfortunately quite common that I need to deal with packages with name collisions. The main offender is cmp and github.com/google/go-cmp/cmp, though there are some others as well.

When I encounter this situation, gopls is much less helpful than it normally is when dealing with non-colliding packages:

  • Once I've imported one package, I can't get completions about names for the other package.
  • Once I've imported one package, gopls doesn't add the colliding package import. I need to manually add the import with an alias.

Here is a concrete scenario: I create a file that imports cmp. (Let's say it uses cmp.Or somewhere.)

What did you see happen?

If I type cmp. and then invoke completion, I only get suggestions from the stdlib's cmp package. If I type cmp.Di and invoke completion, there are no suggestions, even though go-cmp is a dependency of my module. If I type cmp.Diff and hit save, it's just a compile error; no import is added.

What did you expect to see?

It would be nice if gopls helped me here. For example:

  • If I type cmp.Di, it could show me Diff as a completion since that's available from a different cmp than the cmp I already have imported into my package.
  • If I type cmp.Diff and hit save, it could realize that because I'm referring to a different cmp than the one I've imported, it should import github.com/google/go-cmp/cmp, give it an alias (say gocmp), and then change my text to gocmp.Diff.

There are probably some other ways for this UX to work. I'd just like to avoid needing to manually add the import and alias.

Furthermore, I'd like to be able to provide gopls with my preferences about standard collision resolution. When cmp and github.com/google/go-cmp/cmp are both imported, I always want the latter to be aliased as gocmp, regardless of which import was added first.

Editor and settings

I'm using neovim and its LSP support.

Logs

This is a feature request, not a bug report, but I can capture logs if you want. There's nothing interesting or unexpected there AFAICT.

Comment From: findleyr

Remilestoning for the backlog, I think this has been a long-standing missing feature. However, I do think it's a good idea.

@pjweinb I know you've looked at the goimports code recently. Perhaps this is just a trivial extension of its resolution logic?

Comment From: pjweinb

I'll look at it. If one types cmp. it will probably offer stdlib choices, but if one types cmp.D it should realize that there's no match in the stdlib, and look harder. And I'll look at https://github.com/golang/go/issues/40278 too, which looks like it aged out.