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

Open
xaoctech opened this issue Dec 20, 2021 · 7 comments
Open

spec: function type inference ignores type parameter constraints #50272

xaoctech opened this issue Dec 20, 2021 · 7 comments
Assignees
Labels
generics NeedsInvestigation
Milestone

Comments

@xaoctech
Copy link

@xaoctech xaoctech commented Dec 20, 2021

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

@danscales danscales commented Dec 20, 2021

@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 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 label Dec 20, 2021
@xaoctech
Copy link
Author

@xaoctech xaoctech commented Dec 20, 2021

@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

@findleyr findleyr commented Dec 20, 2021

@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

@gopherbot gopherbot commented Dec 20, 2021

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

@findleyr
Copy link
Contributor

@findleyr findleyr commented Dec 20, 2021

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 label Dec 20, 2021
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Dec 20, 2021

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 removed this from the Go1.18 milestone Dec 20, 2021
@ianlancetaylor ianlancetaylor added this to the Go1.19 milestone 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
generics NeedsInvestigation
Projects
None yet
Development

No branches or pull requests

6 participants