reflect: allow conversions between slices of named {byte,rune} and string

So the reflect behavior matches that of the language.

These conversions are allowed:

[]myByte <-> string
[]myRune <-> string
[]myByte <-> myString
[]myRune <-> myString

And even if the left-hand-side is named, e.g.

myBytes([]myByte) <-> string

Fixes #53523

Change-Id: I6562e72bc233a45dc7b02f75f68020831ad399ea
Reviewed-on: https://go-review.googlesource.com/c/go/+/739680
Auto-Submit: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Keith Randall 2026-01-27 11:06:18 -08:00 committed by Keith Randall
parent 481ab86aaf
commit a0796d8af6
2 changed files with 37 additions and 2 deletions

View file

@ -4177,6 +4177,9 @@ type MyBytesArray [4]byte
type MyRunes []int32
type MyFunc func()
type MyByte byte
type MyRune rune
type MyBytes2 []MyByte
type MyRunes2 []MyRune
type IntChan chan int
type IntChanRecv <-chan int
@ -4480,6 +4483,38 @@ var convertTests = []struct {
{V(MyString("runes♝")), V(MyRunes("runes♝"))},
{V(MyRunes("runes♕")), V(MyString("runes♕"))},
// []namedByte
{V(string("namedByte1")), V([]MyByte("namedByte1"))},
{V(MyString("namedByte2")), V([]MyByte("namedByte2"))},
{V([]MyByte("namedByte3")), V(string("namedByte3"))},
{V([]MyByte("namedByte4")), V(MyString("namedByte4"))},
// []namedRune
{V(string("namedRune1")), V([]MyRune("namedRune1"))},
{V(MyString("namedRune2")), V([]MyRune("namedRune2"))},
{V([]MyRune("namedRune3")), V(string("namedRune3"))},
{V([]MyRune("namedRune4")), V(MyString("namedRune4"))},
// named []namedByte
{V(string("namedByte5")), V(MyBytes2("namedByte5"))},
{V(MyString("namedByte6")), V(MyBytes2("namedByte6"))},
{V(MyBytes2("namedByte7")), V(string("namedByte7"))},
{V(MyBytes2("namedByte8")), V(MyString("namedByte8"))},
// named []namedRune
{V(string("namedRune5")), V(MyRunes2("namedRune5"))},
{V(MyString("namedRune6")), V(MyRunes2("namedRune6"))},
{V(MyRunes2("namedRune7")), V(string("namedRune7"))},
{V(MyRunes2("namedRune8")), V(MyString("namedRune8"))},
// random ok conversions of the above types
{V(MyBytes2("")), V([0]MyByte{})},
{V(MyBytes2("AA")), V([2]MyByte{65, 65})},
{V(MyBytes2("")), V([]MyByte{})},
{V([]MyByte{}), V(MyBytes2(""))},
{V([]MyRune("namedRuneA")), V(MyRunes2("namedRuneA"))},
{V(MyRunes2("namedRuneB")), V([]MyRune("namedRuneB"))},
// slice to array
{V([]byte(nil)), V([0]byte{})},
{V([]byte{}), V([0]byte{})},

View file

@ -3404,7 +3404,7 @@ func convertOp(dst, src *abi.Type) func(Value, Type) Value {
}
case String:
if dst.Kind() == abi.Slice && pkgPathFor(dst.Elem()) == "" {
if dst.Kind() == abi.Slice {
switch Kind(dst.Elem().Kind()) {
case Uint8:
return cvtStringBytes
@ -3414,7 +3414,7 @@ func convertOp(dst, src *abi.Type) func(Value, Type) Value {
}
case Slice:
if dst.Kind() == abi.String && pkgPathFor(src.Elem()) == "" {
if dst.Kind() == abi.String {
switch Kind(src.Elem().Kind()) {
case Uint8:
return cvtBytesString