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

spec: function type inference ignores type parameter constraints #50272

Closed
xaoctech opened this issue Dec 20, 2021 · 8 comments
Closed

spec: function type inference ignores type parameter constraints #50272

xaoctech opened this issue Dec 20, 2021 · 8 comments
Assignees
Labels
FrozenDueToAge generics Issue is related to generics NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. TypeInference Issue is related to generic type inference
Milestone

Comments

@xaoctech
Copy link

What version of Go are you using (go version)?

$ go version
go version devel go1.18-87b2a548 Sun Dec 19 20:16:45 2021 +0000 linux/amd64

Does this issue reproduce with the latest release?

No, generics are required

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/vlad/.cache/go-build"
GOENV="/home/vlad/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/vlad/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/vlad/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/vlad/sdk/gotip"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/vlad/sdk/gotip/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="devel go1.18-87b2a548 Sun Dec 19 20:16:45 2021 +0000"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
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-build3350654881=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Compile this code:

func a[T any, S []T](s S) int {
	return b(s)
}

func b[T any](s []T) int {
	return len(s)
}

func main() {
	a(make([]int, 0))
}

What did you expect to see?

The code should compile successfully

What did you see instead?

Compilation failed with type S of s does not match []T (cannot infer T) error message

This code compiles fine:

func a[T any, S []T](s S) int {
	return b([]T(s))
}

func b[T any](s []T) int {
	return len(s)
}

func main() {
	a(make([]int, 0))
}
@danscales
Copy link
Contributor

@griesemer @findleyr The error is on the b(s) line. Things also work if b(s) is replaced with b[T](s), of course.

This does seem like it should be inferable, so maybe a better error message if not possible?

@findleyr
Copy link
Contributor

findleyr commented Dec 20, 2021

I don't think we consider the structural type of a type parameter type argument during type inference, and I'm not sure we can within the current specification.

In this example, a could be rewritten as func a[T any](s []T) int -- it is not using a named slice type, just a slice type (there is no ~). Here's a slightly modified example that could be instantiated with named slice types:

func a[T any, S ~[]T](s S) int {
	return b(s)
}

func b[T any, S ~[]T](s S) int {
	return len(s)
}

func _() {
	a(make([]int, 0))
}

Note that in this example there's no way to instantiate b with a.S, because the underlying of a type parameter is its constraint interface, not its structural type. So in our current specification, I don't believe this is possible.

EDIT: the comments above about whether this is allowed in the spec were inaccurate. It is possible that we could infer these types by considering structural types.

@findleyr findleyr added this to the Go1.18 milestone Dec 20, 2021
@findleyr findleyr added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Dec 20, 2021
@xaoctech
Copy link
Author

@findleyr Don't get it

This doesn't compile with very 'helpful' S does not match []T error message:

func a[T any, S ~[]T](s S) int {
	return b(s)
}

func b[T any, S ~[]T](s S) int {
	return len(s)
}

func main() {
	a(make([]int, 0))
}

This compiles:

func a[T any, S ~[]T](s S) int {
	return b[T, S](s)
}

func b[T any, S ~[]T](s S) int {
	return len(s)
}

func main() {
	a(make([]int, 0))
}

@findleyr
Copy link
Contributor

@xaoctech sorry, you are right; I thought that we had broken this type of inference by the recent change to the definition of the underlying of type parameters. But in retrospect of course this instantiation must work.

So perhaps we can make this inference work as well, or at least produce a better error message.

@gopherbot
Copy link

Change https://golang.org/cl/373414 mentions this issue: go/types: unify the structural type of type parameters

@findleyr
Copy link
Contributor

CL 373414 "makes this work" as a proof of concept but is not principled. It will take a bit more thought to see if/how this fits within our specification of type inference (in progress in https://golang.org/cl/367954).

@ianlancetaylor ianlancetaylor added the generics Issue is related to generics label Dec 20, 2021
@ianlancetaylor
Copy link
Contributor

The suggested type inference definitely does not work today. This code is basically saying that because the constraint of the type parameter S is []T, it must be the case that the argument s of type S matches a parameter of type []T. But there is no current inference rule that says that, given a value whose type is a type parameter, we should use the type parameter's constraint when doing function type inference.

I do not think that we should change the type inference rules at all for 1.18 at this point, so I'm advancing the milestone to 1.19.

I think the right way forward is to make a language change proposal describing the exact changes to the inference rules. It's not really obvious to me at a quick glance. It would be something about adding a new rule for handling inference for a value whose type is or contains a type parameter.

@ianlancetaylor ianlancetaylor modified the milestones: Go1.18, Go1.19 Dec 20, 2021
@ianlancetaylor ianlancetaylor changed the title cmd/compile: Named slice type parameters are not recognized as slices in subsequent calls spec: function type inference ignores type parameter constraints Dec 20, 2021
@griesemer griesemer modified the milestones: Go1.19, Go1.20 Jun 23, 2022
@griesemer griesemer modified the milestones: Go1.20, Go1.21 Nov 15, 2022
@griesemer griesemer added the TypeInference Issue is related to generic type inference label Mar 7, 2023
@griesemer
Copy link
Contributor

We've been using core types of unbound type parameters since Go 1.19 at least. All these examples work now. Closing as fixed.

@golang golang locked and limited conversation to collaborators Mar 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge generics Issue is related to generics NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. TypeInference Issue is related to generic type inference
Projects
Development

No branches or pull requests

6 participants