From 4a66c27f3b70dd779e6afc736f9364107bfbc642 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Mon, 25 May 2026 11:07:52 -0700 Subject: [PATCH 01/10] reflect: add Type.ConvertibleTo --- src/internal/reflectlite/type.go | 87 ++++++++++++++++++++++++++++++++ src/reflect/type.go | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index 4fd02e67ba..6462b3a0cf 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -754,6 +754,93 @@ func (t *RawType) FieldAlign() int { return t.Align() } +// ConvertibleTo returns wheather a value of type t can be converted to a variable of of type u + +func (r *RawType) ConvertibleTo(u *RawType) bool { + + // This logic is mostly copied from Value.CanConvert + + // Don't need to do anything + if r.underlying() == u.underlying() { + return true + } + + switch r.Kind() { + case Int, Int8, Int16, Int32, Int64: + switch u.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + case Float32, Float64: + return true + case String: + return true + } + + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + switch u.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + case Float32, Float64: + return true + case String: + return true + } + + case Float32, Float64: + switch u.Kind() { + case Int, Int8, Int16, Int32, Int64: + return true + case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + case Float32, Float64: + return true + } + + case Complex64, Complex128: + switch u.Kind() { + case Complex64, Complex128: + return true + } + + case Slice: + switch u.Kind() { + case Array: + // This may fail at runtime if there isn't room + if r.elem() == u.elem() { + return true + } + + case Pointer: + // This may fail at runtime if there isn't room + if u.elem().Kind() == Array { + return true + } + + case String: + // bytes or runes + if r.elem().Kind() == Uint8 || r.elem().Kind() == Int32 { + return true + } + + } + + case String: + // bytes or runes + if u.elem().Kind() == Uint8 || u.elem().Kind() == Int32 { + return true + } + + } + + // TODO(dgryski): Unimplemented + // struct types + // channels + // + + return false + +} + // AssignableTo returns whether a value of type t can be assigned to a variable // of type u. func (t *RawType) AssignableTo(u Type) bool { diff --git a/src/reflect/type.go b/src/reflect/type.go index 884f89dc84..9357cef526 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -402,7 +402,7 @@ func (t *rawType) CanSeq2() bool { } func (t *rawType) ConvertibleTo(u Type) bool { - panic("unimplemented: (reflect.Type).ConvertibleTo()") + return t.RawType.Convertibleto(u.(*rawType).RawType) } func (t *rawType) Elem() Type { From 35e2b9ea1491dc22b3278ccb7ef978fa8feafdd6 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Mon, 25 May 2026 11:14:02 -0700 Subject: [PATCH 02/10] reflect: add converting complex --- src/internal/reflectlite/value.go | 39 +++++++++++++++++++++++++------ src/reflect/type.go | 2 +- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index 5650c1266b..e754859858 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -1485,13 +1485,11 @@ func convertOp(src Value, typ Type) (Value, bool) { return cvtFloat(src, rtype), true } - /* - case Complex64, Complex128: - switch src.Kind() { - case Complex64, Complex128: - return cvtComplex - } - */ + case Complex64, Complex128: + switch src.Kind() { + case Complex64, Complex128: + return cvtComplex(src, typ.(*RawType)), true + } case Slice: switch rtype := typ.(*RawType); rtype.Kind() { @@ -1578,6 +1576,10 @@ func cvtFloat(v Value, t *RawType) Value { return makeFloat(v.flags, v.Float(), t) } +func cvtComplex(v Value, t *RawType) Value { + return makeComplex(v.flags, v.Complex(), t) +} + //go:linkname stringToBytes runtime.stringToBytes func stringToBytes(x string) []byte @@ -1661,6 +1663,29 @@ func makeFloat32(flags valueFlags, f float32, t *RawType) Value { return v } +func makeComplex(flags valueFlags, f complex128, t *RawType) Value { + size := t.Size() + + v := Value{ + typecode: t, + flags: flags, + } + + ptr := unsafe.Pointer(&v.value) + if size > unsafe.Sizeof(uintptr(0)) { + ptr = alloc(size, nil) + v.value = ptr + } + + switch size { + case 8: + *(*complex64)(ptr) = complex64(f) + case 16: + *(*complex128)(ptr) = f + } + return v +} + func cvtIntString(src Value, t *RawType) Value { panic("cvtUintString: unimplemented") } diff --git a/src/reflect/type.go b/src/reflect/type.go index 9357cef526..777db1a81e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -402,7 +402,7 @@ func (t *rawType) CanSeq2() bool { } func (t *rawType) ConvertibleTo(u Type) bool { - return t.RawType.Convertibleto(u.(*rawType).RawType) + return t.RawType.ConvertibleTo(&(u.(*rawType).RawType)) } func (t *rawType) Elem() Type { From dd6cc1a81fb474a22f0ca02839b74a31c6bfd942 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Mon, 25 May 2026 11:52:09 -0700 Subject: [PATCH 03/10] reflect: add some more complex conversion tests --- src/reflect/convert_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/reflect/convert_test.go b/src/reflect/convert_test.go index 601bae5883..919d13b43a 100644 --- a/src/reflect/convert_test.go +++ b/src/reflect/convert_test.go @@ -181,6 +181,14 @@ func TestTinyConvert(t *testing.T) { {V(float32(167)), V(float64(167))}, {V(float64(168)), V(float32(168))}, {V(float64(169)), V(float64(169))}, + + {V(float64(1.5)), V(int(1))}, + + // complex + {V(complex64(1i)), V(complex64(1i))}, + {V(complex64(2i)), V(complex128(2i))}, + {V(complex128(3i)), V(complex64(3i))}, + {V(complex128(4i)), V(complex128(4i))}, } for _, tt := range tests { From 210bfd5e9cd9f640650106252e49b5c714ff4380 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Tue, 26 May 2026 12:02:14 -0700 Subject: [PATCH 04/10] reflect: add string <-> []rune conversions --- src/internal/reflectlite/value.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index e754859858..c3df0992db 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -1694,12 +1694,28 @@ func cvtUintString(src Value, t *RawType) Value { panic("cvtUintString: unimplemented") } -func cvtStringRunes(src Value, t *RawType) Value { - panic("cvsStringRunes: unimplemented") +//go:linkname stringToRunes runtime.stringToRunes +func stringToRunes(s string) []rune + +func cvtStringRunes(v Value, t *RawType) Value { + b := stringToRunes(*(*string)(v.value)) + return Value{ + typecode: t, + value: unsafe.Pointer(&b), + flags: v.flags, + } } -func cvtRunesString(src Value, t *RawType) Value { - panic("cvsRunesString: unimplemented") +//go:linkname stringFromRunes runtime.stringFromRunes +func stringFromRunes(r []rune) string + +func cvtRunesString(v Value, t *RawType) Value { + s := stringFromRunes(*(*[]rune)(v.value)) + return Value{ + typecode: t, + value: unsafe.Pointer(&s), + flags: v.flags, + } } //go:linkname slicePanic runtime.slicePanic From 45b75365871214aa23d12f1c0fc15423e38cd2b5 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Tue, 26 May 2026 13:45:18 -0700 Subject: [PATCH 05/10] reflect: add (u)int -> string conversions --- src/internal/reflectlite/value.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index c3df0992db..c4fcb5956f 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -1686,12 +1686,25 @@ func makeComplex(flags valueFlags, f complex128, t *RawType) Value { return v } -func cvtIntString(src Value, t *RawType) Value { - panic("cvtUintString: unimplemented") +//go:linkname stringFromUnicode runtime.stringFromUnicode +func stringFromUnicode(x rune) string + +func cvtIntString(v Value, t *RawType) Value { + b := stringFromUnicode(rune(v.Int())) + return Value{ + typecode: t, + value: unsafe.Pointer(&b), + flags: v.flags, + } } -func cvtUintString(src Value, t *RawType) Value { - panic("cvtUintString: unimplemented") +func cvtUintString(v Value, t *RawType) Value { + b := stringFromUnicode(rune(v.Uint())) + return Value{ + typecode: t, + value: unsafe.Pointer(&b), + flags: v.flags, + } } //go:linkname stringToRunes runtime.stringToRunes From afd6df42fda2a916667e850ce967176fae3c6f7c Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Tue, 26 May 2026 14:28:08 -0700 Subject: [PATCH 06/10] reflect: fix (u)int -> string conversions for invalid code points --- src/internal/reflectlite/value.go | 19 +++++--- src/reflect/convert_test.go | 80 +++++++++++++++++++++++++++++++ src/runtime/string.go | 4 +- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index c4fcb5956f..7d6d54f107 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -1690,20 +1690,27 @@ func makeComplex(flags valueFlags, f complex128, t *RawType) Value { func stringFromUnicode(x rune) string func cvtIntString(v Value, t *RawType) Value { - b := stringFromUnicode(rune(v.Int())) + s := "\uFFFD" + if x := v.Int(); int64(rune(x)) == x { + s = string(rune(x)) + } return Value{ typecode: t, - value: unsafe.Pointer(&b), - flags: v.flags, + value: unsafe.Pointer(&s), + flags: v.flags | valueFlagRO, } } func cvtUintString(v Value, t *RawType) Value { - b := stringFromUnicode(rune(v.Uint())) + s := "\uFFFD" + if x := v.Uint(); uint64(rune(x)) == x { + s = string(rune(x)) + } + return Value{ typecode: t, - value: unsafe.Pointer(&b), - flags: v.flags, + value: unsafe.Pointer(&s), + flags: v.flags | valueFlagRO, } } diff --git a/src/reflect/convert_test.go b/src/reflect/convert_test.go index 919d13b43a..ef6e118675 100644 --- a/src/reflect/convert_test.go +++ b/src/reflect/convert_test.go @@ -189,6 +189,86 @@ func TestTinyConvert(t *testing.T) { {V(complex64(2i)), V(complex128(2i))}, {V(complex128(3i)), V(complex64(3i))}, {V(complex128(4i)), V(complex128(4i))}, + + // string + {V(string("hello")), V(string("hello"))}, + {V(string("bytes1")), V([]byte("bytes1"))}, + {V([]byte("bytes2")), V(string("bytes2"))}, + {V([]byte("bytes3")), V([]byte("bytes3"))}, + {V(string("runes♝")), V([]rune("runes♝"))}, + {V([]rune("runes♕")), V(string("runes♕"))}, + {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, + {V(int('a')), V(string("a"))}, + {V(int8('a')), V(string("a"))}, + {V(int16('a')), V(string("a"))}, + {V(int32('a')), V(string("a"))}, + {V(int64('a')), V(string("a"))}, + {V(uint('a')), V(string("a"))}, + {V(uint8('a')), V(string("a"))}, + {V(uint16('a')), V(string("a"))}, + {V(uint32('a')), V(string("a"))}, + {V(uint64('a')), V(string("a"))}, + {V(uintptr('a')), V(string("a"))}, + {V(int(-1)), V(string("\uFFFD"))}, + {V(int8(-2)), V(string("\uFFFD"))}, + {V(int16(-3)), V(string("\uFFFD"))}, + {V(int32(-4)), V(string("\uFFFD"))}, + {V(int64(-5)), V(string("\uFFFD"))}, + {V(int64(-1 << 32)), V(string("\uFFFD"))}, + {V(int64(1 << 32)), V(string("\uFFFD"))}, + {V(uint(0x110001)), V(string("\uFFFD"))}, + {V(uint32(0x110002)), V(string("\uFFFD"))}, + {V(uint64(0x110003)), V(string("\uFFFD"))}, + {V(uint64(1 << 32)), V(string("\uFFFD"))}, + {V(uintptr(0x110004)), V(string("\uFFFD"))}, + + // named string + {V(MyString("hello")), V(string("hello"))}, + {V(string("hello")), V(MyString("hello"))}, + {V(string("hello")), V(string("hello"))}, + {V(MyString("hello")), V(MyString("hello"))}, + {V(MyString("bytes1")), V([]byte("bytes1"))}, + {V([]byte("bytes2")), V(MyString("bytes2"))}, + {V([]byte("bytes3")), V([]byte("bytes3"))}, + {V(MyString("runes♝")), V([]rune("runes♝"))}, + {V([]rune("runes♕")), V(MyString("runes♕"))}, + {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, + {V([]rune("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, + {V(MyRunes("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, + {V(int('a')), V(MyString("a"))}, + {V(int8('a')), V(MyString("a"))}, + {V(int16('a')), V(MyString("a"))}, + {V(int32('a')), V(MyString("a"))}, + {V(int64('a')), V(MyString("a"))}, + {V(uint('a')), V(MyString("a"))}, + {V(uint8('a')), V(MyString("a"))}, + {V(uint16('a')), V(MyString("a"))}, + {V(uint32('a')), V(MyString("a"))}, + {V(uint64('a')), V(MyString("a"))}, + {V(uintptr('a')), V(MyString("a"))}, + {V(int(-1)), V(MyString("\uFFFD"))}, + {V(int8(-2)), V(MyString("\uFFFD"))}, + {V(int16(-3)), V(MyString("\uFFFD"))}, + {V(int32(-4)), V(MyString("\uFFFD"))}, + {V(int64(-5)), V(MyString("\uFFFD"))}, + {V(uint(0x110001)), V(MyString("\uFFFD"))}, + {V(uint32(0x110002)), V(MyString("\uFFFD"))}, + {V(uint64(0x110003)), V(MyString("\uFFFD"))}, + {V(uintptr(0x110004)), V(MyString("\uFFFD"))}, + + // named []byte + {V(string("bytes1")), V(MyBytes("bytes1"))}, + {V(MyBytes("bytes2")), V(string("bytes2"))}, + {V(MyBytes("bytes3")), V(MyBytes("bytes3"))}, + {V(MyString("bytes1")), V(MyBytes("bytes1"))}, + {V(MyBytes("bytes2")), V(MyString("bytes2"))}, + + // named []rune + {V(string("runes♝")), V(MyRunes("runes♝"))}, + {V(MyRunes("runes♕")), V(string("runes♕"))}, + {V(MyRunes("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, + {V(MyString("runes♝")), V(MyRunes("runes♝"))}, + {V(MyRunes("runes♕")), V(MyString("runes♕"))}, } for _, tt := range tests { diff --git a/src/runtime/string.go b/src/runtime/string.go index d4ee5e3c1a..cdc31cb16c 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -153,7 +153,9 @@ func stringNext(s string, it *stringIterator) (bool, int, rune) { } // Convert a Unicode code point into an array of bytes and its length. -func encodeUTF8(x rune) ([4]byte, uintptr) { +func encodeUTF8(r rune) ([4]byte, uintptr) { + x := uint32(r) + // https://stackoverflow.com/questions/6240055/manually-converting-unicode-codepoints-into-utf-8-and-utf-16 // Note: this code can probably be optimized (in size and speed). switch { From 9c463842e9108cadbf369f3fa70a165a88c89125 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Tue, 26 May 2026 14:58:04 -0700 Subject: [PATCH 07/10] refleect: more conversion tests --- src/reflect/convert_test.go | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/reflect/convert_test.go b/src/reflect/convert_test.go index ef6e118675..ec3f363442 100644 --- a/src/reflect/convert_test.go +++ b/src/reflect/convert_test.go @@ -269,6 +269,51 @@ func TestTinyConvert(t *testing.T) { {V(MyRunes("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, {V(MyString("runes♝")), V(MyRunes("runes♝"))}, {V(MyRunes("runes♕")), V(MyString("runes♕"))}, + + // slice to array + {V([]byte(nil)), V([0]byte{})}, + {V([]byte{}), V([0]byte{})}, + {V([]byte{1}), V([1]byte{1})}, + {V([]byte{1, 2}), V([2]byte{1, 2})}, + {V([]byte{1, 2, 3}), V([3]byte{1, 2, 3})}, + {V(MyBytes([]byte(nil))), V([0]byte{})}, + {V(MyBytes{}), V([0]byte{})}, + {V(MyBytes{1}), V([1]byte{1})}, + {V(MyBytes{1, 2}), V([2]byte{1, 2})}, + {V(MyBytes{1, 2, 3}), V([3]byte{1, 2, 3})}, + {V([]byte(nil)), V(MyBytesArray0{})}, + {V([]byte{}), V(MyBytesArray0([0]byte{}))}, + {V([]byte{1, 2, 3, 4}), V(MyBytesArray([4]byte{1, 2, 3, 4}))}, + {V(MyBytes{}), V(MyBytesArray0([0]byte{}))}, + {V(MyBytes{5, 6, 7, 8}), V(MyBytesArray([4]byte{5, 6, 7, 8}))}, + {V([]MyByte{}), V([0]MyByte{})}, + {V([]MyByte{1, 2}), V([2]MyByte{1, 2})}, + + // slice to array pointer + {V([]byte(nil)), V((*[0]byte)(nil))}, + {V([]byte{}), V(new([0]byte))}, + {V([]byte{7}), V(&[1]byte{7})}, + {V(MyBytes([]byte(nil))), V((*[0]byte)(nil))}, + {V(MyBytes([]byte{})), V(new([0]byte))}, + {V(MyBytes([]byte{9})), V(&[1]byte{9})}, + {V([]byte(nil)), V(MyBytesArrayPtr0(nil))}, + {V([]byte{}), V(MyBytesArrayPtr0(new([0]byte)))}, + {V([]byte{1, 2, 3, 4}), V(MyBytesArrayPtr(&[4]byte{1, 2, 3, 4}))}, + {V(MyBytes([]byte{})), V(MyBytesArrayPtr0(new([0]byte)))}, + {V(MyBytes([]byte{5, 6, 7, 8})), V(MyBytesArrayPtr(&[4]byte{5, 6, 7, 8}))}, + + {V([]byte(nil)), V((*MyBytesArray0)(nil))}, + {V([]byte{}), V((*MyBytesArray0)(new([0]byte)))}, + {V([]byte{1, 2, 3, 4}), V(&MyBytesArray{1, 2, 3, 4})}, + {V(MyBytes([]byte(nil))), V((*MyBytesArray0)(nil))}, + {V(MyBytes([]byte{})), V((*MyBytesArray0)(new([0]byte)))}, + {V(MyBytes([]byte{5, 6, 7, 8})), V(&MyBytesArray{5, 6, 7, 8})}, + /* + {V(new([0]byte)), V(new(MyBytesArray0))}, + {V(new(MyBytesArray0)), V(new([0]byte))}, + {V(MyBytesArrayPtr0(nil)), V((*[0]byte)(nil))}, + {V((*[0]byte)(nil)), V(MyBytesArrayPtr0(nil))}, + */ } for _, tt := range tests { From 552e9b0c43cdcdf9d3450d43e8bf41942f8c14bf Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Fri, 29 May 2026 13:47:37 -0700 Subject: [PATCH 08/10] reflect: use TestConvert from all_test.go and make it pass This PR removes convert_test.go which was a minimal version of this test. --- src/internal/reflectlite/type.go | 24 ++- src/internal/reflectlite/value.go | 32 ++- src/reflect/all_test.go | 157 ++++++++------- src/reflect/convert_test.go | 325 ------------------------------ src/reflect/value_test.go | 2 +- 5 files changed, 130 insertions(+), 410 deletions(-) delete mode 100644 src/reflect/convert_test.go diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index 6462b3a0cf..9dd1455dcb 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -760,11 +760,6 @@ func (r *RawType) ConvertibleTo(u *RawType) bool { // This logic is mostly copied from Value.CanConvert - // Don't need to do anything - if r.underlying() == u.underlying() { - return true - } - switch r.Kind() { case Int, Int8, Int16, Int32, Int64: switch u.Kind() { @@ -812,13 +807,13 @@ func (r *RawType) ConvertibleTo(u *RawType) bool { case Pointer: // This may fail at runtime if there isn't room - if u.elem().Kind() == Array { + if u.elem().Kind() == Array && r.elem() == u.elem().elem() { return true } case String: // bytes or runes - if r.elem().Kind() == Uint8 || r.elem().Kind() == Int32 { + if !r.elem().isNamed() && (r.elem().Kind() == Uint8 || r.elem().Kind() == Int32) { return true } @@ -826,16 +821,27 @@ func (r *RawType) ConvertibleTo(u *RawType) bool { case String: // bytes or runes - if u.elem().Kind() == Uint8 || u.elem().Kind() == Int32 { + if u.Kind() == Slice && !u.elem().isNamed() && (u.elem().Kind() == Uint8 || u.elem().Kind() == Int32) { + return true + } + + case Pointer: + if !r.isNamed() && u.Kind() == Pointer && !u.isNamed() && r.elem().underlying() == u.elem().underlying() { return true } + } + if r.underlying() == u.underlying() { + return true + } + + if u.Kind() == Interface && u.NumMethod() == 0 { + return true } // TODO(dgryski): Unimplemented // struct types // channels - // return false diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index 7d6d54f107..a2acac4018 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -47,12 +47,20 @@ func (v Value) isExported() bool { return v.flags&valueFlagExported != 0 } -func (v Value) isRO() bool { +func (v Value) IsRO() bool { return v.flags&(valueFlagRO) != 0 } +func (v *Value) MakeRO(ro bool) { + if ro { + v.flags |= valueFlagRO + } else { + v.flags &^= valueFlagRO + } +} + func (v Value) checkRO() { - if v.isRO() { + if v.IsRO() { panic("reflect: value is not settable") } } @@ -297,7 +305,7 @@ func (v Value) IsValid() bool { } func (v Value) CanInterface() bool { - return v.isExported() && !v.isRO() + return v.isExported() && !v.IsRO() } func (v Value) CanAddr() bool { @@ -1532,6 +1540,12 @@ func convertOp(src Value, typ Type) (Value, bool) { return cvtStringRunes(src, rtype), true } } + + case Pointer: + rtype := typ.(*RawType) + if rtype.Kind() == Pointer && !rtype.isNamed() { + return cvtDirect(src, rtype), true + } } // TODO(dgryski): Unimplemented: @@ -1576,6 +1590,14 @@ func cvtFloat(v Value, t *RawType) Value { return makeFloat(v.flags, v.Float(), t) } +func cvtDirect(v Value, t *RawType) Value { + return Value{ + typecode: t, + value: v.value, + flags: v.flags, + } +} + func cvtComplex(v Value, t *RawType) Value { return makeComplex(v.flags, v.Complex(), t) } @@ -1697,7 +1719,7 @@ func cvtIntString(v Value, t *RawType) Value { return Value{ typecode: t, value: unsafe.Pointer(&s), - flags: v.flags | valueFlagRO, + flags: v.flags, } } @@ -1710,7 +1732,7 @@ func cvtUintString(v Value, t *RawType) Value { return Value{ typecode: t, value: unsafe.Pointer(&s), - flags: v.flags | valueFlagRO, + flags: v.flags, } } diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index a755278623..325f9fb87f 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4249,8 +4249,6 @@ type BytesChan chan []byte type BytesChanRecv <-chan []byte type BytesChanSend chan<- []byte -/* - var convertTests = []struct { in Value out Value @@ -4286,7 +4284,7 @@ var convertTests = []struct { } } } -*/ /* + */ {V(int8(1)), V(int8(1))}, {V(int8(2)), V(uint8(2))}, {V(uint8(3)), V(int8(3))}, @@ -4602,37 +4600,41 @@ var convertTests = []struct { {V((func())(nil)), V(MyFunc(nil))}, {V((MyFunc)(nil)), V((func())(nil))}, - // structs with different tags - {V(struct { - x int `some:"foo"` - }{}), V(struct { - x int `some:"bar"` - }{})}, + /* + + // structs with different tags + {V(struct { + x int `some:"foo"` + }{}), V(struct { + x int `some:"bar"` + }{})}, - {V(struct { - x int `some:"bar"` - }{}), V(struct { - x int `some:"foo"` - }{})}, + {V(struct { + x int `some:"bar"` + }{}), V(struct { + x int `some:"foo"` + }{})}, - {V(MyStruct{}), V(struct { - x int `some:"foo"` - }{})}, + {V(MyStruct{}), V(struct { + x int `some:"foo"` + }{})}, - {V(struct { - x int `some:"foo"` - }{}), V(MyStruct{})}, + {V(struct { + x int `some:"foo"` + }{}), V(MyStruct{})}, - {V(MyStruct{}), V(struct { - x int `some:"bar"` - }{})}, + {V(MyStruct{}), V(struct { + x int `some:"bar"` + }{})}, - {V(struct { - x int `some:"bar"` - }{}), V(MyStruct{})}, + {V(struct { + x int `some:"bar"` + }{}), V(MyStruct{})}, - {V(MyStruct1{}), V(MyStruct2{})}, - {V(MyStruct2{}), V(MyStruct1{})}, + + {V(MyStruct1{}), V(MyStruct2{})}, + {V(MyStruct2{}), V(MyStruct1{})}, + */ // can convert *byte and *MyByte {V((*byte)(nil)), V((*MyByte)(nil))}, @@ -4674,46 +4676,59 @@ var convertTests = []struct { {V(new(io.Reader)), V(new(io.Reader))}, {V(new(io.Writer)), V(new(io.Writer))}, - // channels - {V(IntChan(nil)), V((chan<- int)(nil))}, - {V(IntChan(nil)), V((<-chan int)(nil))}, - {V((chan int)(nil)), V(IntChanRecv(nil))}, - {V((chan int)(nil)), V(IntChanSend(nil))}, - {V(IntChanRecv(nil)), V((<-chan int)(nil))}, - {V((<-chan int)(nil)), V(IntChanRecv(nil))}, - {V(IntChanSend(nil)), V((chan<- int)(nil))}, - {V((chan<- int)(nil)), V(IntChanSend(nil))}, - {V(IntChan(nil)), V((chan int)(nil))}, - {V((chan int)(nil)), V(IntChan(nil))}, - {V((chan int)(nil)), V((<-chan int)(nil))}, - {V((chan int)(nil)), V((chan<- int)(nil))}, - {V(BytesChan(nil)), V((chan<- []byte)(nil))}, - {V(BytesChan(nil)), V((<-chan []byte)(nil))}, - {V((chan []byte)(nil)), V(BytesChanRecv(nil))}, - {V((chan []byte)(nil)), V(BytesChanSend(nil))}, - {V(BytesChanRecv(nil)), V((<-chan []byte)(nil))}, - {V((<-chan []byte)(nil)), V(BytesChanRecv(nil))}, - {V(BytesChanSend(nil)), V((chan<- []byte)(nil))}, - {V((chan<- []byte)(nil)), V(BytesChanSend(nil))}, - {V(BytesChan(nil)), V((chan []byte)(nil))}, - {V((chan []byte)(nil)), V(BytesChan(nil))}, - {V((chan []byte)(nil)), V((<-chan []byte)(nil))}, - {V((chan []byte)(nil)), V((chan<- []byte)(nil))}, - - // cannot convert other instances (channels) - {V(IntChan(nil)), V(IntChan(nil))}, - {V(IntChanRecv(nil)), V(IntChanRecv(nil))}, - {V(IntChanSend(nil)), V(IntChanSend(nil))}, - {V(BytesChan(nil)), V(BytesChan(nil))}, - {V(BytesChanRecv(nil)), V(BytesChanRecv(nil))}, - {V(BytesChanSend(nil)), V(BytesChanSend(nil))}, - - // interfaces - {V(int(1)), EmptyInterfaceV(int(1))}, - {V(string("hello")), EmptyInterfaceV(string("hello"))}, - {V(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, - {ReadWriterV(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, - {V(new(bytes.Buffer)), ReadWriterV(new(bytes.Buffer))}, + /* + + // channels + {V(IntChan(nil)), V((chan<- int)(nil))}, + {V(IntChan(nil)), V((<-chan int)(nil))}, + {V((chan int)(nil)), V(IntChanRecv(nil))}, + {V((chan int)(nil)), V(IntChanSend(nil))}, + {V(IntChanRecv(nil)), V((<-chan int)(nil))}, + {V((<-chan int)(nil)), V(IntChanRecv(nil))}, + {V(IntChanSend(nil)), V((chan<- int)(nil))}, + {V((chan<- int)(nil)), V(IntChanSend(nil))}, + {V(IntChan(nil)), V((chan int)(nil))}, + {V((chan int)(nil)), V(IntChan(nil))}, + {V((chan int)(nil)), V((<-chan int)(nil))}, + {V((chan int)(nil)), V((chan<- int)(nil))}, + {V(BytesChan(nil)), V((chan<- []byte)(nil))}, + {V(BytesChan(nil)), V((<-chan []byte)(nil))}, + {V((chan []byte)(nil)), V(BytesChanRecv(nil))}, + {V((chan []byte)(nil)), V(BytesChanSend(nil))}, + {V(BytesChanRecv(nil)), V((<-chan []byte)(nil))}, + {V((<-chan []byte)(nil)), V(BytesChanRecv(nil))}, + {V(BytesChanSend(nil)), V((chan<- []byte)(nil))}, + {V((chan<- []byte)(nil)), V(BytesChanSend(nil))}, + {V(BytesChan(nil)), V((chan []byte)(nil))}, + {V((chan []byte)(nil)), V(BytesChan(nil))}, + {V((chan []byte)(nil)), V((<-chan []byte)(nil))}, + {V((chan []byte)(nil)), V((chan<- []byte)(nil))}, + + // cannot convert other instances (channels) + {V(IntChan(nil)), V(IntChan(nil))}, + {V(IntChanRecv(nil)), V(IntChanRecv(nil))}, + {V(IntChanSend(nil)), V(IntChanSend(nil))}, + {V(BytesChan(nil)), V(BytesChan(nil))}, + {V(BytesChanRecv(nil)), V(BytesChanRecv(nil))}, + {V(BytesChanSend(nil)), V(BytesChanSend(nil))}, + + // interfaces + {V(int(1)), EmptyInterfaceV(int(1))}, + {V(string("hello")), EmptyInterfaceV(string("hello"))}, + {V(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, + {ReadWriterV(new(bytes.Buffer)), ReaderV(new(bytes.Buffer))}, + {V(new(bytes.Buffer)), ReadWriterV(new(bytes.Buffer))}, + */ + +} + +func IsRO(v Value) bool { + return v.IsRO() +} + +func MakeRO(v Value) Value { + v.MakeRO(true) + return v } func TestConvert(t *testing.T) { @@ -4804,6 +4819,8 @@ func TestConvert(t *testing.T) { } } +/* + func TestConvertPanic(t *testing.T) { s := make([]byte, 4) p := new([8]byte) @@ -4848,6 +4865,8 @@ func TestConvertSlice2Array(t *testing.T) { } } +*/ + var gFloat32 float32 const snan uint32 = 0x7f800001 @@ -4870,8 +4889,6 @@ func TestConvertNaNs(t *testing.T) { } } -*/ - type ComparableStruct struct { X int } diff --git a/src/reflect/convert_test.go b/src/reflect/convert_test.go deleted file mode 100644 index ec3f363442..0000000000 --- a/src/reflect/convert_test.go +++ /dev/null @@ -1,325 +0,0 @@ -package reflect_test - -import ( - . "reflect" - "testing" -) - -func TestTinyConvert(t *testing.T) { - - V := ValueOf - - var tests = []struct { - have, want Value - }{ - {V(int8(1)), V(int8(1))}, - {V(int8(2)), V(uint8(2))}, - {V(uint8(3)), V(int8(3))}, - {V(int8(4)), V(int16(4))}, - {V(int16(5)), V(int8(5))}, - {V(int8(6)), V(uint16(6))}, - {V(uint16(7)), V(int8(7))}, - {V(int8(8)), V(int32(8))}, - {V(int32(9)), V(int8(9))}, - {V(int8(10)), V(uint32(10))}, - {V(uint32(11)), V(int8(11))}, - {V(int8(12)), V(int64(12))}, - {V(int64(13)), V(int8(13))}, - {V(int8(14)), V(uint64(14))}, - {V(uint64(15)), V(int8(15))}, - {V(int8(16)), V(int(16))}, - {V(int(17)), V(int8(17))}, - {V(int8(18)), V(uint(18))}, - {V(uint(19)), V(int8(19))}, - {V(int8(20)), V(uintptr(20))}, - {V(uintptr(21)), V(int8(21))}, - {V(int8(22)), V(float32(22))}, - {V(float32(23)), V(int8(23))}, - {V(int8(24)), V(float64(24))}, - {V(float64(25)), V(int8(25))}, - {V(uint8(26)), V(uint8(26))}, - {V(uint8(27)), V(int16(27))}, - {V(int16(28)), V(uint8(28))}, - {V(uint8(29)), V(uint16(29))}, - {V(uint16(30)), V(uint8(30))}, - {V(uint8(31)), V(int32(31))}, - {V(int32(32)), V(uint8(32))}, - {V(uint8(33)), V(uint32(33))}, - {V(uint32(34)), V(uint8(34))}, - {V(uint8(35)), V(int64(35))}, - {V(int64(36)), V(uint8(36))}, - {V(uint8(37)), V(uint64(37))}, - {V(uint64(38)), V(uint8(38))}, - {V(uint8(39)), V(int(39))}, - {V(int(40)), V(uint8(40))}, - {V(uint8(41)), V(uint(41))}, - {V(uint(42)), V(uint8(42))}, - {V(uint8(43)), V(uintptr(43))}, - {V(uintptr(44)), V(uint8(44))}, - {V(uint8(45)), V(float32(45))}, - {V(float32(46)), V(uint8(46))}, - {V(uint8(47)), V(float64(47))}, - {V(float64(48)), V(uint8(48))}, - {V(int16(49)), V(int16(49))}, - {V(int16(50)), V(uint16(50))}, - {V(uint16(51)), V(int16(51))}, - {V(int16(52)), V(int32(52))}, - {V(int32(53)), V(int16(53))}, - {V(int16(54)), V(uint32(54))}, - {V(uint32(55)), V(int16(55))}, - {V(int16(56)), V(int64(56))}, - {V(int64(57)), V(int16(57))}, - {V(int16(58)), V(uint64(58))}, - {V(uint64(59)), V(int16(59))}, - {V(int16(60)), V(int(60))}, - {V(int(61)), V(int16(61))}, - {V(int16(62)), V(uint(62))}, - {V(uint(63)), V(int16(63))}, - {V(int16(64)), V(uintptr(64))}, - {V(uintptr(65)), V(int16(65))}, - {V(int16(66)), V(float32(66))}, - {V(float32(67)), V(int16(67))}, - {V(int16(68)), V(float64(68))}, - {V(float64(69)), V(int16(69))}, - {V(uint16(70)), V(uint16(70))}, - {V(uint16(71)), V(int32(71))}, - {V(int32(72)), V(uint16(72))}, - {V(uint16(73)), V(uint32(73))}, - {V(uint32(74)), V(uint16(74))}, - {V(uint16(75)), V(int64(75))}, - {V(int64(76)), V(uint16(76))}, - {V(uint16(77)), V(uint64(77))}, - {V(uint64(78)), V(uint16(78))}, - {V(uint16(79)), V(int(79))}, - {V(int(80)), V(uint16(80))}, - {V(uint16(81)), V(uint(81))}, - {V(uint(82)), V(uint16(82))}, - {V(uint16(83)), V(uintptr(83))}, - {V(uintptr(84)), V(uint16(84))}, - {V(uint16(85)), V(float32(85))}, - {V(float32(86)), V(uint16(86))}, - {V(uint16(87)), V(float64(87))}, - {V(float64(88)), V(uint16(88))}, - {V(int32(89)), V(int32(89))}, - {V(int32(90)), V(uint32(90))}, - {V(uint32(91)), V(int32(91))}, - {V(int32(92)), V(int64(92))}, - {V(int64(93)), V(int32(93))}, - {V(int32(94)), V(uint64(94))}, - {V(uint64(95)), V(int32(95))}, - {V(int32(96)), V(int(96))}, - {V(int(97)), V(int32(97))}, - {V(int32(98)), V(uint(98))}, - {V(uint(99)), V(int32(99))}, - {V(int32(100)), V(uintptr(100))}, - {V(uintptr(101)), V(int32(101))}, - {V(int32(102)), V(float32(102))}, - {V(float32(103)), V(int32(103))}, - {V(int32(104)), V(float64(104))}, - {V(float64(105)), V(int32(105))}, - {V(uint32(106)), V(uint32(106))}, - {V(uint32(107)), V(int64(107))}, - {V(int64(108)), V(uint32(108))}, - {V(uint32(109)), V(uint64(109))}, - {V(uint64(110)), V(uint32(110))}, - {V(uint32(111)), V(int(111))}, - {V(int(112)), V(uint32(112))}, - {V(uint32(113)), V(uint(113))}, - {V(uint(114)), V(uint32(114))}, - {V(uint32(115)), V(uintptr(115))}, - {V(uintptr(116)), V(uint32(116))}, - {V(uint32(117)), V(float32(117))}, - {V(float32(118)), V(uint32(118))}, - {V(uint32(119)), V(float64(119))}, - {V(float64(120)), V(uint32(120))}, - {V(int64(121)), V(int64(121))}, - {V(int64(122)), V(uint64(122))}, - {V(uint64(123)), V(int64(123))}, - {V(int64(124)), V(int(124))}, - {V(int(125)), V(int64(125))}, - {V(int64(126)), V(uint(126))}, - {V(uint(127)), V(int64(127))}, - {V(int64(128)), V(uintptr(128))}, - {V(uintptr(129)), V(int64(129))}, - {V(int64(130)), V(float32(130))}, - {V(float32(131)), V(int64(131))}, - {V(int64(132)), V(float64(132))}, - {V(float64(133)), V(int64(133))}, - {V(uint64(134)), V(uint64(134))}, - {V(uint64(135)), V(int(135))}, - {V(int(136)), V(uint64(136))}, - {V(uint64(137)), V(uint(137))}, - {V(uint(138)), V(uint64(138))}, - {V(uint64(139)), V(uintptr(139))}, - {V(uintptr(140)), V(uint64(140))}, - {V(uint64(141)), V(float32(141))}, - {V(float32(142)), V(uint64(142))}, - {V(uint64(143)), V(float64(143))}, - {V(float64(144)), V(uint64(144))}, - {V(int(145)), V(int(145))}, - {V(int(146)), V(uint(146))}, - {V(uint(147)), V(int(147))}, - {V(int(148)), V(uintptr(148))}, - {V(uintptr(149)), V(int(149))}, - {V(int(150)), V(float32(150))}, - {V(float32(151)), V(int(151))}, - {V(int(152)), V(float64(152))}, - {V(float64(153)), V(int(153))}, - {V(uint(154)), V(uint(154))}, - {V(uint(155)), V(uintptr(155))}, - {V(uintptr(156)), V(uint(156))}, - {V(uint(157)), V(float32(157))}, - {V(float32(158)), V(uint(158))}, - {V(uint(159)), V(float64(159))}, - {V(float64(160)), V(uint(160))}, - {V(uintptr(161)), V(uintptr(161))}, - {V(uintptr(162)), V(float32(162))}, - {V(float32(163)), V(uintptr(163))}, - {V(uintptr(164)), V(float64(164))}, - {V(float64(165)), V(uintptr(165))}, - {V(float32(166)), V(float32(166))}, - {V(float32(167)), V(float64(167))}, - {V(float64(168)), V(float32(168))}, - {V(float64(169)), V(float64(169))}, - - {V(float64(1.5)), V(int(1))}, - - // complex - {V(complex64(1i)), V(complex64(1i))}, - {V(complex64(2i)), V(complex128(2i))}, - {V(complex128(3i)), V(complex64(3i))}, - {V(complex128(4i)), V(complex128(4i))}, - - // string - {V(string("hello")), V(string("hello"))}, - {V(string("bytes1")), V([]byte("bytes1"))}, - {V([]byte("bytes2")), V(string("bytes2"))}, - {V([]byte("bytes3")), V([]byte("bytes3"))}, - {V(string("runes♝")), V([]rune("runes♝"))}, - {V([]rune("runes♕")), V(string("runes♕"))}, - {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V(int('a')), V(string("a"))}, - {V(int8('a')), V(string("a"))}, - {V(int16('a')), V(string("a"))}, - {V(int32('a')), V(string("a"))}, - {V(int64('a')), V(string("a"))}, - {V(uint('a')), V(string("a"))}, - {V(uint8('a')), V(string("a"))}, - {V(uint16('a')), V(string("a"))}, - {V(uint32('a')), V(string("a"))}, - {V(uint64('a')), V(string("a"))}, - {V(uintptr('a')), V(string("a"))}, - {V(int(-1)), V(string("\uFFFD"))}, - {V(int8(-2)), V(string("\uFFFD"))}, - {V(int16(-3)), V(string("\uFFFD"))}, - {V(int32(-4)), V(string("\uFFFD"))}, - {V(int64(-5)), V(string("\uFFFD"))}, - {V(int64(-1 << 32)), V(string("\uFFFD"))}, - {V(int64(1 << 32)), V(string("\uFFFD"))}, - {V(uint(0x110001)), V(string("\uFFFD"))}, - {V(uint32(0x110002)), V(string("\uFFFD"))}, - {V(uint64(0x110003)), V(string("\uFFFD"))}, - {V(uint64(1 << 32)), V(string("\uFFFD"))}, - {V(uintptr(0x110004)), V(string("\uFFFD"))}, - - // named string - {V(MyString("hello")), V(string("hello"))}, - {V(string("hello")), V(MyString("hello"))}, - {V(string("hello")), V(string("hello"))}, - {V(MyString("hello")), V(MyString("hello"))}, - {V(MyString("bytes1")), V([]byte("bytes1"))}, - {V([]byte("bytes2")), V(MyString("bytes2"))}, - {V([]byte("bytes3")), V([]byte("bytes3"))}, - {V(MyString("runes♝")), V([]rune("runes♝"))}, - {V([]rune("runes♕")), V(MyString("runes♕"))}, - {V([]rune("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V([]rune("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, - {V(MyRunes("runes🙈🙉🙊")), V([]rune("runes🙈🙉🙊"))}, - {V(int('a')), V(MyString("a"))}, - {V(int8('a')), V(MyString("a"))}, - {V(int16('a')), V(MyString("a"))}, - {V(int32('a')), V(MyString("a"))}, - {V(int64('a')), V(MyString("a"))}, - {V(uint('a')), V(MyString("a"))}, - {V(uint8('a')), V(MyString("a"))}, - {V(uint16('a')), V(MyString("a"))}, - {V(uint32('a')), V(MyString("a"))}, - {V(uint64('a')), V(MyString("a"))}, - {V(uintptr('a')), V(MyString("a"))}, - {V(int(-1)), V(MyString("\uFFFD"))}, - {V(int8(-2)), V(MyString("\uFFFD"))}, - {V(int16(-3)), V(MyString("\uFFFD"))}, - {V(int32(-4)), V(MyString("\uFFFD"))}, - {V(int64(-5)), V(MyString("\uFFFD"))}, - {V(uint(0x110001)), V(MyString("\uFFFD"))}, - {V(uint32(0x110002)), V(MyString("\uFFFD"))}, - {V(uint64(0x110003)), V(MyString("\uFFFD"))}, - {V(uintptr(0x110004)), V(MyString("\uFFFD"))}, - - // named []byte - {V(string("bytes1")), V(MyBytes("bytes1"))}, - {V(MyBytes("bytes2")), V(string("bytes2"))}, - {V(MyBytes("bytes3")), V(MyBytes("bytes3"))}, - {V(MyString("bytes1")), V(MyBytes("bytes1"))}, - {V(MyBytes("bytes2")), V(MyString("bytes2"))}, - - // named []rune - {V(string("runes♝")), V(MyRunes("runes♝"))}, - {V(MyRunes("runes♕")), V(string("runes♕"))}, - {V(MyRunes("runes🙈🙉🙊")), V(MyRunes("runes🙈🙉🙊"))}, - {V(MyString("runes♝")), V(MyRunes("runes♝"))}, - {V(MyRunes("runes♕")), V(MyString("runes♕"))}, - - // slice to array - {V([]byte(nil)), V([0]byte{})}, - {V([]byte{}), V([0]byte{})}, - {V([]byte{1}), V([1]byte{1})}, - {V([]byte{1, 2}), V([2]byte{1, 2})}, - {V([]byte{1, 2, 3}), V([3]byte{1, 2, 3})}, - {V(MyBytes([]byte(nil))), V([0]byte{})}, - {V(MyBytes{}), V([0]byte{})}, - {V(MyBytes{1}), V([1]byte{1})}, - {V(MyBytes{1, 2}), V([2]byte{1, 2})}, - {V(MyBytes{1, 2, 3}), V([3]byte{1, 2, 3})}, - {V([]byte(nil)), V(MyBytesArray0{})}, - {V([]byte{}), V(MyBytesArray0([0]byte{}))}, - {V([]byte{1, 2, 3, 4}), V(MyBytesArray([4]byte{1, 2, 3, 4}))}, - {V(MyBytes{}), V(MyBytesArray0([0]byte{}))}, - {V(MyBytes{5, 6, 7, 8}), V(MyBytesArray([4]byte{5, 6, 7, 8}))}, - {V([]MyByte{}), V([0]MyByte{})}, - {V([]MyByte{1, 2}), V([2]MyByte{1, 2})}, - - // slice to array pointer - {V([]byte(nil)), V((*[0]byte)(nil))}, - {V([]byte{}), V(new([0]byte))}, - {V([]byte{7}), V(&[1]byte{7})}, - {V(MyBytes([]byte(nil))), V((*[0]byte)(nil))}, - {V(MyBytes([]byte{})), V(new([0]byte))}, - {V(MyBytes([]byte{9})), V(&[1]byte{9})}, - {V([]byte(nil)), V(MyBytesArrayPtr0(nil))}, - {V([]byte{}), V(MyBytesArrayPtr0(new([0]byte)))}, - {V([]byte{1, 2, 3, 4}), V(MyBytesArrayPtr(&[4]byte{1, 2, 3, 4}))}, - {V(MyBytes([]byte{})), V(MyBytesArrayPtr0(new([0]byte)))}, - {V(MyBytes([]byte{5, 6, 7, 8})), V(MyBytesArrayPtr(&[4]byte{5, 6, 7, 8}))}, - - {V([]byte(nil)), V((*MyBytesArray0)(nil))}, - {V([]byte{}), V((*MyBytesArray0)(new([0]byte)))}, - {V([]byte{1, 2, 3, 4}), V(&MyBytesArray{1, 2, 3, 4})}, - {V(MyBytes([]byte(nil))), V((*MyBytesArray0)(nil))}, - {V(MyBytes([]byte{})), V((*MyBytesArray0)(new([0]byte)))}, - {V(MyBytes([]byte{5, 6, 7, 8})), V(&MyBytesArray{5, 6, 7, 8})}, - /* - {V(new([0]byte)), V(new(MyBytesArray0))}, - {V(new(MyBytesArray0)), V(new([0]byte))}, - {V(MyBytesArrayPtr0(nil)), V((*[0]byte)(nil))}, - {V((*[0]byte)(nil)), V(MyBytesArrayPtr0(nil))}, - */ - } - - for _, tt := range tests { - got := tt.have.Convert(tt.want.Type()) - if !DeepEqual(got.Interface(), tt.want.Interface()) { - t.Errorf("Failed to Convert() %T(%v) -> %T(%v), got %T(%v)", tt.have.Interface(), tt.have, tt.want.Interface(), tt.want, got.Interface(), got) - } - } -} diff --git a/src/reflect/value_test.go b/src/reflect/value_test.go index 999c115cb7..9efc36f774 100644 --- a/src/reflect/value_test.go +++ b/src/reflect/value_test.go @@ -628,7 +628,7 @@ func TestAssignableTo(t *testing.T) { } } -func TestConvert(t *testing.T) { +func TestConvertBasic(t *testing.T) { v := ValueOf(int64(3)) c := v.Convert(TypeOf(byte(0))) From ec6264be56bf6eeeae55ac1e5c85407d7b7ae94a Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Fri, 29 May 2026 15:09:57 -0700 Subject: [PATCH 09/10] reflect: address Copilot review feedback --- src/internal/reflectlite/type.go | 3 +-- src/internal/reflectlite/value.go | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index 9dd1455dcb..5ced5d3573 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -754,8 +754,7 @@ func (t *RawType) FieldAlign() int { return t.Align() } -// ConvertibleTo returns wheather a value of type t can be converted to a variable of of type u - +// ConvertibleTo returns whether a value of type t can be converted to a variable of type u func (r *RawType) ConvertibleTo(u *RawType) bool { // This logic is mostly copied from Value.CanConvert diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index a2acac4018..5909a3f058 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -1494,9 +1494,9 @@ func convertOp(src Value, typ Type) (Value, bool) { } case Complex64, Complex128: - switch src.Kind() { + switch rtype := typ.(*RawType); rtype.Kind() { case Complex64, Complex128: - return cvtComplex(src, typ.(*RawType)), true + return cvtComplex(src, rtype), true } case Slice: @@ -1543,7 +1543,7 @@ func convertOp(src Value, typ Type) (Value, bool) { case Pointer: rtype := typ.(*RawType) - if rtype.Kind() == Pointer && !rtype.isNamed() { + if rtype.Kind() == Pointer && !src.typecode.isNamed() && !rtype.isNamed() && src.typecode.elem().underlying() == rtype.elem().underlying() { return cvtDirect(src, rtype), true } } @@ -1708,9 +1708,6 @@ func makeComplex(flags valueFlags, f complex128, t *RawType) Value { return v } -//go:linkname stringFromUnicode runtime.stringFromUnicode -func stringFromUnicode(x rune) string - func cvtIntString(v Value, t *RawType) Value { s := "\uFFFD" if x := v.Int(); int64(rune(x)) == x { From 640360f8d25ab92071d1f8533e7dc006bf0de971 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Mon, 8 Jun 2026 12:21:07 -0700 Subject: [PATCH 10/10] reflect: fix pointer receiver for MakeRO --- src/internal/reflectlite/value.go | 3 ++- src/reflect/all_test.go | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go index 5909a3f058..36cdac11e9 100644 --- a/src/internal/reflectlite/value.go +++ b/src/internal/reflectlite/value.go @@ -51,12 +51,13 @@ func (v Value) IsRO() bool { return v.flags&(valueFlagRO) != 0 } -func (v *Value) MakeRO(ro bool) { +func (v Value) MakeRO(ro bool) Value { if ro { v.flags |= valueFlagRO } else { v.flags &^= valueFlagRO } + return v } func (v Value) checkRO() { diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 325f9fb87f..7584c62055 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4727,8 +4727,7 @@ func IsRO(v Value) bool { } func MakeRO(v Value) Value { - v.MakeRO(true) - return v + return Value{v.MakeRO(true)} } func TestConvert(t *testing.T) {