Description
What version of Go are you using (go version
)?
$ go version go version go1.18.2 linux/amd64
Does this issue reproduce with the latest release?
1.18.2 is the latest at the time of writing; I have not tried on tip/other branches or versions.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/iburton/.cache/go-build" GOENV="/home/iburton/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/iburton/go/pkg/mod" GONOPROXY="" GONOSUMDB=//elided GOOS="linux" GOPATH="/home/iburton/go" GOPRIVATE="" GOPROXY=//elided GOROOT="/home/iburton/.gvm/versions/go1.18.2.linux.amd64" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/home/iburton/.gvm/versions/go1.18.2.linux.amd64/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.18.2" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD=//elided GOWORK="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3437891855=/tmp/go-build -gno-record-gcc-switches"
What did you do?
Working in a module that specifies 1.16 as minimum, tried adding a file with
//go:build go1.18
For a file that should only be built/included when go1.18 or newer is used.
What did you expect to see?
The build and my editor (vscode + gopls) to work and not fail
What did you see instead?
type instantiation requires go1.18 or later compilerUnsupportedFeature
Context
Well I had an entirely different bug report written until just before I submitted it when I realized what I think is a documentation issue.
The TLDR on the issue was I had a module with go 1.16
and wanted to add some code/files that used generics guarded by a build flag such as mentioned:
From cmd/go
During a particular build, the following words are satisfied:
- a term for each Go major release, through the current version:
"go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on.
With the above error from gopls/go build when I used generics, but not when I stopped using them (and left the 1.18 restriction) I thought this was a bug until I finally found a line in the module reference
For packages within the module, the compiler rejects use of language features introduced after the version specified by the go directive. For example, if a module has the directive go 1.12, its packages may not use numeric literals like 1_000_000, which were introduced in Go 1.13.
I'm not sure why it isn't allowed if such a file is guarded with build flag/constraints (the module reference doesn't mention those at all). But I'm assuming this is the cause of what I'm seeing. I had looked at the 1.18 release notes, the generics proposal, go/build, go help build
and various other places and didn't find anything mentioning the disabling of features like this, other than in the module ref above. It was obvious to me code using or expecting to work with 1.16 would not work with generics or any language feature introduced after, but if such code lives in a separate file that is guarded (just like you'd do for anything else say based on OS or ARCH) I didn't understand why that wasn't working.
Perhaps more documentation can be added to go/build and cmd friends that mentions this? And maybe a better error if this comes up, something like:
X language feature cannot be used due to go directive in go.mod, Go version build flags included, see 'go help build' or 'go help mod' for more information
While I'm at it, if the use of a language feature is guarded with flags why not allow its use? If I have a module that says 1.16 is the minimum but code in its own file that won't be included in a 1.16 build why not allow the (rest of the module) code to still build? Perhaps there was a good reason or maybe build flags based on Go version were over looked relative to this module (compiler?) restriction? I don't want to move the entire module to 1.18 for a relatively small bit of optional code, for the time being, so using a build flag I thought was the proper solution.
Thank you!
Activity
heschi commentedon May 13, 2022
cc @ianlancetaylor @griesemer maybe?
ianlancetaylor commentedon May 13, 2022
I'm not clear on exactly what you did to see the error, and I'm not clear on exactly what error you saw.
If I set the version in go.mod to 1.17 and run
go build
on code that uses generics, I seeThat seems clear enough to me and I don't think there is anything to change. But perhaps you are doing something different and seeing a different message.
iaburton commentedon May 14, 2022
@ianlancetaylor Apologizes for it being unclear!
The error I saw was
type instantiation requires go1.18 or later
, from gopls, but also go build.When you set the version in go.mod to 1.17, where you still building with 1.18?
I think I can simplify the explanation. And why I was so confused.
Lets say you have a file like this, along with a go.mod that is version 1.16 or 1.17 (anything below the build flag you'll note at the top)
https://go.dev/play/p/w-39eBj77SR
If you build that file
go test -v
you'll see it prints 1.18.2. That makes sense, since in the playground is set to 1.18 but in our hypothetical module it'll still print 1.18.2 (even with go mod set to 1.16 or 1.17). It has to, as the build flag restricts it to only 1.18.xThis is of course assuming you're building with at least that Go version, as I was, developing my module with a similar file.
So the confusion comes in when I add generics, and it starts telling me I need to use 1.18 or later. But as just discussed
Therefore I had to be using 1.18. Why would the error tell me to use 1.18 when that is in fact what I was using. Again, the code worked fine without said language feature, it wasn't until I used a language feature after 1.16 did it fail.
This is why I thought it was a bug at first (it builds with 1.18 sometimes but not others?). The file builds fine and is clearly being included as it should when I compile with 1.18 and the build flag is being honored (runtime.Version prints 1.18.2). But I use a feature and then it fails telling me to use 1.18.
I thought to myself. Until I hit that link above (this one, the relevant snippet is quoted in my OP) that says language features are gated by the version in the go.mod, not the version of Go I was building with, nor the version of Go in my build flag
//go:build go1.18
The fact that isn't mentioned in
go help build
,go help mod
or the other places I looked was why I deleted my bug report and changed this to a documentation issue. I think it should be mentioned elsewhere that even using build flags to specify Go versions a file should (or should not) be included in is not enough to "gate" a feature when using modules (I don't remember this restriction existing before modules, perhaps that is why it's only listed in the module ref?).So to be clear, I don't want readers to think I simply had a module with 1.16 and I was arbitrarily using features introduced after the fact. I knew that wouldn't work. Said features were only in files with a 1.18 build flag, aka "please only include when go1.18 is being used". It was like Go was including my 1.18 only file, then telling me I need to use 1.18.
This brings me back to my question (out of curiosity), now that I understand the problem I ran into.
Why is the restriction there in the first place? The file is guarded with a 1.18 build flag, it cannot interfere with those building against 1.16 or 1.17, and would only be included for those using 1.18. And I suppose a follow up to this would be; how do I develop my module to use said features gradually? There doesn't seem to be a way outside of releasing an entirely new version of the module with the Go directive in the mod set to 1.18. Do I have that correct?
Thanks again!
ianlancetaylor commentedon May 14, 2022
We don't want to change the compiler behavior based on the build tags of the file being compiled.
Also, it doesn't seem likely to be a big use case. If a package is to support Go 1.16, it can't use generics. It seems unlikely that anybody would write the same functionality in two different ways, one with generics and one without. And we don't want to encourage a package providing a different API depending on the compiler version being used. That's not a grea user experience.
I see the error in go/types; changing to a go/types bug report to provide a clearer error message for this case. CC @griesemer
[-]go/build|cmd/go: Documentation on disabled languages features despite build flags[/-][+]go/types: error "type instantiation requires go1.18 or later" is unclear when go version comes from go.mod[/+]zalegrala commentedon May 23, 2022
I believe I'm bumping into this restriction also, using the same
go
version as in the original post.A Google Cloud Function I'm developing is has
go 1.16
in thego.mod
, due to the runtime restriction available on the platform. However, we also import a module withgo 1.17
, which imports another module withgo 1.18
that has begun to include generics. While we wait for Google to update the supported version on their platform, we'd like to make use of the module, and for the handful of methods that need to be updated, a build constraint to ignore or include a certaingo
version of the same package would be handy.For this particular case, the file containing the generics implementation has the build constraint
//go:build go1.18
. This file seems to be included even when my projectgo.mod
specifies that the Cloud Function gets built withgo1.16
. Adding an additional constraint is necessary to avoid the file being parsed and throwing the error in the OP, along with a couple others that seem specific to this code. The updated build constraint is//go:build go1.18 && !go.1.16
, but should the first build constraint be limiting the file parsing without needing the second?Further errors that may be related to this issue.
gopherbot commentedon May 24, 2022
Change https://go.dev/cl/407896 mentions this issue:
cmd/compile/internal/types2: mention go.mod file when using undeclared any
cmd/compile/internal/types2: mention go.mod file when using undeclare…
iaburton commentedon May 24, 2022
I think this still gets at the crux of my original issue; that it seems logical (at least to me) that you'd be able to use build flags/constraints to 'gate' language version feature/changes (otherwise the Go version build flags become less useful and its more difficult to write modules that transition to newer versions). Like my original post noted I don't remember this restriction existing before modules, but I could be wrong. It's not like changes on the scale of generics come to Go very often.
ncruces commentedon Jun 29, 2022
This forces module authors to maintain two major versions of a module, or delaying adoption of generics, even for compatible changes like adding a function, whereas the standard library gets away with doing it in a point release, because it goes bundled with the compiler.