-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/tools/gopls: design UX around version skew resulting from the forward compatibility proposal #61185
Comments
In case of VS Code Go, the extension reads the build info of gopls and if the go version used to build the gopls is too old to handle the go version used in the project (i.e. minor version comparison), it shows a popup message and asks users to rebuild gopls. This is based on the assumption that gopls built with go1.N can work with go1.N and a few older versions of go. We didn't hear much about version skew issues since we implemented this feature. If gopls implements a similar logic (and vscode go should remove this check to avoid double popups), I think that would mostly work. |
@hyangah does VS Code actually read the go.mod file to get its go version? |
I don't see in the list above the option of gopls rebuilding and reinvoking itself as needed. It could do something like
and then reinvoke /some/gopls/cache/go1.N/gopls. |
@rsc I considered that, but there's a chicken and egg problem which would require careful treatment: we can't know the required Go version until we've resolved the user's workspace and environment, which happens during the LSP handshake. It's doable, but would require a fair bit of work to splice in a different gopls version during a session. However, we could just say that "gopls is always built with the latest toolchain", and upgrade whenever there is a newer toolchain available. Added that as an option. I'm a bit concerned about having gopls download and install new binaries (even if those binaries are go/gopls itself). At least with the forward compatibility proposal there is an explicit act of running the Go command on a module that requires a newer toolchain. In this case, the upgrade would be triggered by the presence of a newer version, which feels different. Of course, some IDEs auto-upgrade binaries, but that is thus far not a bridge we have crossed with gopls, which should generally be more conservative than any individual IDE. It may have to be opt-in. |
Extension runs Complicated cases include, however, multi-module workspaces, nested module, multi-root (vscode's) workspaces, zero-config gopls handling multiple modules, etc. And, in case, users update go.mod file (either the 'go' line, or by updating the dependencies) in the middle of a session. In that case, gopls will be in a better position to detect that and notify editors/users. |
Re: gopls self-updating. Another aspect we need to keep in mind is the compatibility between the editor and the gopls. LSP sometimes makes incompatible changes and we also sometimes have custom gopls commands. Editors and users (can) have all the information about the compatibility. I am afraid go and even gopls may not want to know about editors' versions. |
@hyangah to be clear I think gopls should only rebuild itself, not upgrade itself. For example, right now I am working with a user who is stuck on v0.11.0, because they are running into performance edge cases of v0.12.x. It's already frustrating enough when we break users, and we would never want to re-break them when they intentionally downgrade! |
Note that in many editors, the editor (or its plugin) manages the lifetime of the language server and expects the connection with the language server (over stdio) to be stable after the initial hand-shake. And the initial hand-shake needs to be done within a certain deadline. We observed a similar pattern with |
I think I’m hitting this very issue. I have go1.21.5 installed, but decided to try a Go 1.22 feature (the servemux change) for a specific project. This is my transcript:
So the triggering condition seems to be that the language version and toolchain directive both are on Go 1.22, while gopls was built with Go 1.21.5. Re-installing gopls with Go 1.22 fixes the problem, but it was not obvious that version skew was what broke gopls (there was some time between switching to Go 1.22 and the next time I needed a gopls feature). Is there anything we can do to at least produce a good error message? (PS: If this is a separate issue after all, feel free to split it into a new one or let me know and I can file a separate one.) |
This issue follows up on discussion in https://go.dev/cl/507975, where go/types is being updated to fail type-checking if the required Go version (as configured by
types.Config.GoVersion
) is greater than the Go version of the standard library (e.g. the version used to compile gopls).This is the right change for go/types, because an older version of the type checker cannot type check code that was written for a newer version of Go.
However, we aim for an invariant in gopls that "if the Go command works, gopls works" (see also #57979). Previously, we didn't have to worry about the impact of version skew on this invariant, because the version of
go
in the user's environment is usually the same as the version of go used to compile gopls. So if gopls was producing confusing errors, the go command would also produce confusing errors.But with forward compatibility (#57001), I think it will frequently be the case that the go command will work correctly, because it was automatically upgraded, yet gopls will fail.
We need to design and test an appropriate UX when users encounter this skew. Some questions to consider:
go 1.N
in itsgo.mod
file, whenever version1.N
of go is released, so thatgo install golang.org/x/tools/gopls@latest
will always have a version of gopls compatible with all published versions of Go?types.Config.GoVersion
?CC @golang/tools-team
The text was updated successfully, but these errors were encountered: