reflect: implement CanInterface and fix string Index()

This commit fixes two related issues:

 1. CanInterface was unimplemented. It now uses the same check as is
    used in Interface() itself.
    This issue led to https://github.com/tinygo-org/tinygo/issues/3033
 2. Allow making an interface out of a string char element.

Doing this in one commit (instead of two) because they are shown to be
correct with the same tests.
Этот коммит содержится в:
Ayke van Laethem 2022-08-31 22:33:28 +02:00 коммит произвёл Ron Evans
родитель edaf13f951
коммит e955aa1941
3 изменённых файлов: 22 добавлений и 16 удалений

Просмотреть файл

@ -168,8 +168,7 @@ func (v Value) IsValid() bool {
}
func (v Value) CanInterface() bool {
// No Value types of private data can be constructed at the moment.
return true
return v.isExported()
}
func (v Value) CanAddr() bool {
@ -502,6 +501,9 @@ func (v Value) Index(i int) Value {
// Extract a character from a string.
// A string is never stored directly in the interface, but always as a
// pointer to the string value.
// Keeping valueFlagExported if set, but don't set valueFlagIndirect
// otherwise CanSet will return true for string elements (which is bad,
// strings are read-only).
s := *(*stringHeader)(v.value)
if uint(i) >= uint(s.len) {
panic("reflect: string index out of range")
@ -509,6 +511,7 @@ func (v Value) Index(i int) Value {
return Value{
typecode: Uint8.basicType(),
value: unsafe.Pointer(uintptr(*(*uint8)(unsafe.Pointer(uintptr(s.data) + uintptr(i))))),
flags: v.flags & valueFlagExported,
}
case Array:
// Extract an element from the array.

3
testdata/reflect.go предоставленный
Просмотреть файл

@ -415,6 +415,9 @@ func showValue(rv reflect.Value, indent string) {
if rv.CanAddr() {
print(" addrable=true")
}
if !rv.CanInterface() {
print(" caninterface=false")
}
if !rt.Comparable() {
print(" comparable=false")
}

28
testdata/reflect.txt предоставленный
Просмотреть файл

@ -236,7 +236,7 @@ reflect type: struct
tag:
embedded: true
exported: false
reflect type: interface
reflect type: interface caninterface=false
interface
nil: true
reflect type: struct
@ -245,19 +245,19 @@ reflect type: struct
tag:
embedded: false
exported: false
reflect type: uint8
reflect type: uint8 caninterface=false
uint: 42
field: 1 b
tag:
embedded: false
exported: false
reflect type: int16
reflect type: int16 caninterface=false
int: 321
field: 2 c
tag:
embedded: false
exported: false
reflect type: int8
reflect type: int8 caninterface=false
int: 123
reflect type: struct comparable=false
struct: 5
@ -265,45 +265,45 @@ reflect type: struct comparable=false
tag: foo:"bar"
embedded: false
exported: false
reflect type: int
reflect type: int caninterface=false
int: 5
field: 1 some
tag:
embedded: false
exported: false
reflect type: struct
reflect type: struct caninterface=false
struct: 2
field: 0 X
tag:
embedded: false
exported: true
reflect type: int16
reflect type: int16 caninterface=false
int: -5
field: 1 Y
tag:
embedded: false
exported: true
reflect type: int16
reflect type: int16 caninterface=false
int: 3
field: 2 zero
tag:
embedded: false
exported: false
reflect type: struct
reflect type: struct caninterface=false
struct: 0
field: 3 buf
tag:
embedded: false
exported: false
reflect type: slice comparable=false
reflect type: slice caninterface=false comparable=false
slice: uint8 2 2
pointer: true
nil: false
indexing: 0
reflect type: uint8 addrable=true
reflect type: uint8 addrable=true caninterface=false
uint: 71
indexing: 1
reflect type: uint8 addrable=true
reflect type: uint8 addrable=true caninterface=false
uint: 111
field: 4 Buf
tag:
@ -325,14 +325,14 @@ reflect type: ptr
tag: description:"chain"
embedded: false
exported: false
reflect type: ptr addrable=true
reflect type: ptr addrable=true caninterface=false
pointer: false struct
nil: true
field: 1 foo
tag:
embedded: false
exported: false
reflect type: int addrable=true
reflect type: int addrable=true caninterface=false
int: 42
reflect type: slice comparable=false
slice: interface 3 3