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

cmd/compile: calling string(...) on generic slices fails regardless of type constraints. #50421

Open
tmr232 opened this issue Jan 4, 2022 · 6 comments
Assignees
Milestone

Comments

@tmr232
Copy link

@tmr232 tmr232 commented Jan 4, 2022

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

$ go version
go version go1.18beta1 windows/amd64

Does this issue reproduce with the latest release?

Yes (1.18 beta)

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

go env Output
$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\tamir.bahar\AppData\Local\go-build
set GOENV=C:\Users\tamir.bahar\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\tamir.bahar\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\tamir.bahar\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.18beta1
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=NUL
set GOWORK=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\TAMIR~1.BAH\AppData\Local\Temp\go-build3924345009=/tmp/go-build -gno-record-gcc-switches

What did you do?

Compile the following code:

func toString[T byte|rune](slice []T) string {
   return string(slice)
}

What did you expect to see?

Since string(...) can take either a []byte or a []rune, I expected the code to compile successfully.

What did you see instead?

Compilation fails with:

cannot convert slice (variable of type []T) to type string

See https://gotipplay.golang.org/p/ZgvdU6Xv9jB

@ALTree
Copy link
Member

@ALTree ALTree commented Jan 4, 2022

@ALTree ALTree added this to the Go1.18 milestone Jan 4, 2022
@griesemer griesemer self-assigned this Jan 4, 2022
@griesemer
Copy link
Contributor

@griesemer griesemer commented Jan 4, 2022

Pet the current spec rules on generic conversions, this conversion is not permitted.

Note that the following code does work:

func toString[T []byte|[]rune](slice T) string {
        return string(slice)
}

Maybe the rules need to be relaxed.
@ianlancetaylor for additional input.

@tmr232
Copy link
Author

@tmr232 tmr232 commented Jan 4, 2022

Thanks!

As motivation for the rule relaxation, I'll present my use-case.

I have a generic type Iterator[T] that represents a Python-like iterator (it can be any other collection that's generic over the element type), and I want to convert it to a string.

Due to the current rules, I cannot just write the following:

func ToString[T rune | uint8](iter Iterator[T]) string {
	return string(ToSlice(iter))
}

Trying to work around it doesn't work either:

func sliceToString[T []rune | []uint8](slice T) string {
	return string(slice)
}

func ToString[T rune | uint8](iter Iterator[T]) string {
	return sliceToString(ToSlice(iter))
}

And fails with

[]T does not implement []rune|[]uint8

Which is hard for me to understand as T is either rune or uint8, making []T effectively []rune|[]uint8.

This means that I'll have to write 2 toString functions. One for rune and one for uint8.
It's not that bad in that one case, but I think it would also mean that code that is generic over string-elements would either need to be written twice (once for uint8 and once for rune), or that it will need non-generic free-functions for converting back to string.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 4, 2022

Thanks. We're not going to change this for 1.18. In the long run I think we should probably permit this, but let's leave real consideration for later. Thanks.

@ianlancetaylor ianlancetaylor removed this from the Go1.18 milestone Jan 4, 2022
@ianlancetaylor ianlancetaylor added this to the Go1.19 milestone Jan 4, 2022
@go101
Copy link

@go101 go101 commented Jan 5, 2022

Per the current spec rules on generic conversions, this conversion is not permitted.

@griesemer Could you more specific on which line in the current spec disallows this conversion? I only found this line

A non-constant value x can be converted to type T in any of these cases:

  • x is an integer or a slice of bytes or runes and T is a string type.

The line doesn't mention type parameters.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jan 5, 2022

In your example slice is not a slice of bytes or runes, it is a slice of T, which is a type parameter. The rule you mention ("x is an integer or a slice of bytes or runes and T is a string type") doesn't apply. I'm being pedantic, but that is what the spec is: pedantic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants