Skip to content

x/tools/gopls: add support for a target language version, and drop support for building at legacy Go versions #50825

Closed
@findleyr

Description

@findleyr

Background

Right now the gopls team supports building gopls using the four most recent major Go versions, though technically we still maintain support for Go 1.12+. This is significantly longer than the support window of the Go project itself, which covers only the two most recent major Go versions.

In the past, we've seen evidence (in the form of bug reports or survey results) that our users are supporting older Go versions for their applications/libraries. Whether or not this is a good thing is moot: there were reasons out of our control (e.g. cloud services support windows) that caused our users to support older Go versions. Absent a strong reason to break compatibility, the gopls team continued to maintain compatibility with older Go versions because the only way to provide accurate functionality for an older Go version was to build gopls at that Go version.

This legacy support causes significant friction for the team, notably:

  • we maintain additional CI (Kokoro) that runs tests using older Go versions
  • we work around issues that only occur with older Go versions
  • we will be maintaining a compatibility layer that replicates the functionality of go.work at older Go versions
  • our tests must be tolerant of error messages produced at older Go versions
  • some of our analyzers interpret error messages, and so must also be tolerant of error messages produced at older Go versions
  • we cannot easily leverage recent language or standard library improvements in our own code
  • our feedback cycle with the standard library is ~infinite: we cannot typically wait for fixes to go/parser or go/types
  • the dependencies we integrate with (e.g. gofumpt or staticcheck) have (quite reasonably) incompatible support windows

Proposal

We should provide features that make it easier to build gopls with a recent Go version but target development at an earlier Go version. We should then begin the process of dropping support for building gopls at older Go versions. As we do this, we should document and announce the final version of gopls that supports being built at each Go version.

Eventually we should align our support window with the Go project: the two most recent Go versions. This will allow us to turn down our legacy CI.

Supporting a target language version

With Go 1.18, the types.Config.GoVersion field allows us to specify an accepted language version for go/types, analogous to the compiler -lang flag. This removes a key blocker to this proposal.

Specifically, there are three components to providing accurate gopls functionality for older target Go versions:

  1. providing compiler (=go/types) errors based on the target language version (x/tools/gopls: set types.Config.GoVersion based on go.mod #50688)
  2. warning about usage of standard library APIs that were added after the target language version (x/tools/gopls: warn about standard library API usage based on Go version #50689)
  3. building packages based on the target language version (i.e. based on the correct release tags)

Of these, (1) and (2) are now straightforward, as described by the linked issues. (3) is harder, because AFAIK x/tools/go/packages (and the go command) does not provide a way to specify release tags -- they are baked into the go binary. Issue #42504 would be useful here: gopls could do its own post-processing of build tags.

In the meantime, we can either declare that we won't be able to satisfy (3), or support using a different go command for go/packages than was used to build gopls. In principle simply using a different go version for go list should work, but may introduce difficult combinatorial problems. Using a different version of go for go/packages would actually handle both (2) and (3) above, so we should explore this option.

We should of course update our installation instructions to document this workflow.

Deriving the target language version(s)

We can derive the target language version from the applicable go.mod, the go version in PATH, or from explicit gopls configuration. We may use more than one of these sources, but ideally we would avoid any additional gopls configuration.

Dropping support for older Go versions

We can take the following steps to ease the impact on our users when we drop support for a Go version:

  • Announce plans for final versions in our release notes. Specifically, since we try to release approximately monthly, we should endeavor to announce when the next version of gopls will be the final version to support being built at a given Go version.
  • Surface this information when upgrading gopls in VS Code.
  • Make VS Code aware of the gopls compatibility matrix, so that it doesn't try to upgrade to an unsupported version.
  • Explain all of this in our documentation.

CC @golang/tools-team

Metadata

Metadata

Assignees

Labels

ToolsThis label describes issues relating to any tools in the x/tools repository.goplsIssues related to the Go language server, gopls.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions