Skip to content

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

Open
@iaburton

Description

@iaburton

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

added
NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
on May 13, 2022
added this to the Backlog milestone on May 13, 2022
heschi

heschi commented on May 13, 2022

@heschi
Contributor
ianlancetaylor

ianlancetaylor commented on May 13, 2022

@ianlancetaylor
Contributor

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.

added
WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.
on May 13, 2022
iaburton

iaburton commented on May 14, 2022

@iaburton
Author

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

ianlancetaylor commented on May 14, 2022

@ianlancetaylor
Contributor

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

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[/+] on May 14, 2022
added
NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.
on May 14, 2022
removed
NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
on May 14, 2022
removed
DocumentationIssues describing a change to documentation.
WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.
on May 14, 2022
zalegrala

zalegrala commented on May 23, 2022

@zalegrala

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

gopherbot commented on May 24, 2022

@gopherbot
Contributor

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

iaburton

iaburton commented on May 24, 2022

@iaburton
Author

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.

ncruces

ncruces commented on Jun 29, 2022

@ncruces
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ianlancetaylor@iaburton@ncruces@gopherbot@heschi

        Issue actions

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