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 { func (v Value) CanInterface() bool {
// No Value types of private data can be constructed at the moment. return v.isExported()
return true
} }
func (v Value) CanAddr() bool { func (v Value) CanAddr() bool {
@ -502,6 +501,9 @@ func (v Value) Index(i int) Value {
// Extract a character from a string. // Extract a character from a string.
// A string is never stored directly in the interface, but always as a // A string is never stored directly in the interface, but always as a
// pointer to the string value. // 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) s := *(*stringHeader)(v.value)
if uint(i) >= uint(s.len) { if uint(i) >= uint(s.len) {
panic("reflect: string index out of range") panic("reflect: string index out of range")
@ -509,6 +511,7 @@ func (v Value) Index(i int) Value {
return Value{ return Value{
typecode: Uint8.basicType(), typecode: Uint8.basicType(),
value: unsafe.Pointer(uintptr(*(*uint8)(unsafe.Pointer(uintptr(s.data) + uintptr(i))))), value: unsafe.Pointer(uintptr(*(*uint8)(unsafe.Pointer(uintptr(s.data) + uintptr(i))))),
flags: v.flags & valueFlagExported,
} }
case Array: case Array:
// Extract an element from the 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() { if rv.CanAddr() {
print(" addrable=true") print(" addrable=true")
} }
if !rv.CanInterface() {
print(" caninterface=false")
}
if !rt.Comparable() { if !rt.Comparable() {
print(" comparable=false") print(" comparable=false")
} }

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

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