Skip to content
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

go/types: error "type instantiation requires go1.18 or later" is unclear when go version comes from go.mod #52880

Open
iaburton opened this issue May 12, 2022 · 7 comments
Labels
NeedsInvestigation
Milestone

Comments

@iaburton
Copy link

@iaburton iaburton commented May 12, 2022

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!

@heschi heschi added the NeedsDecision label May 13, 2022
@heschi heschi added this to the Backlog milestone May 13, 2022
@heschi
Copy link
Contributor

@heschi heschi commented May 13, 2022

cc @ianlancetaylor @griesemer maybe?

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented 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 see

/x.go:3:8: type parameter requires go1.18 or later (-lang was set to go1.17; check go.mod)
./x.go:3:10: undeclared name: any (requires version go1.18 or later)

That 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.

@ianlancetaylor ianlancetaylor added the WaitingForInfo label May 13, 2022
@iaburton
Copy link
Author

@iaburton iaburton commented May 14, 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 see

/x.go:3:8: type parameter requires go1.18 or later (-lang was set to go1.17; check go.mod)
./x.go:3:10: undeclared name: any (requires version go1.18 or later)

That 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.

@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.x
This 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

  1. I was building with 1.18.2
  2. The file had a build flag with 1.18

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.

But I am

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
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented May 14, 2022

Why is the restriction there in the first place?

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

@ianlancetaylor ianlancetaylor changed the title 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 May 14, 2022
@ianlancetaylor ianlancetaylor added the NeedsInvestigation label May 14, 2022
@gopherbot gopherbot removed the NeedsDecision label May 14, 2022
@ianlancetaylor ianlancetaylor removed Documentation WaitingForInfo labels May 14, 2022
@zalegrala
Copy link

@zalegrala zalegrala commented 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 the go.mod, due to the runtime restriction available on the platform. However, we also import a module with go 1.17, which imports another module with go 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 certain go 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 project go.mod specifies that the Cloud Function gets built with go1.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.

undeclared name: any (requires version go1.18 or later)
function instantiation requires go1.18 or later (-lang was set to go1.16; check go.mod)
type parameter requires go1.18 or later (-lang was set to go1.16; check go.mod)

@gopherbot
Copy link

@gopherbot gopherbot commented May 24, 2022

Change https://go.dev/cl/407896 mentions this issue: cmd/compile/internal/types2: mention go.mod file when using undeclared any

gopherbot pushed a commit that referenced this issue May 24, 2022
…d any

Use the existing versionErrorf mechanism to report use of undeclared
any and comparable.

Also, port versionErrorf mechanism to go/types and use it in this
case as well.

Adjust tests as needed.

For #52880.

Change-Id: I6a646f16a849692ee0cb57e362d5f3d77e2c25f9
Reviewed-on: https://go-review.googlesource.com/c/go/+/407896
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
@iaburton
Copy link
Author

@iaburton iaburton commented May 24, 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 the go.mod, due to the runtime restriction available on the platform. However, we also import a module with go 1.17, which imports another module with go 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 certain go 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 project go.mod specifies that the Cloud Function gets built with go1.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?

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation
Projects
None yet
Development

No branches or pull requests

5 participants