Skip to content
93 changes: 93 additions & 0 deletions src/internal/reflectlite/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,99 @@ 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 {
Comment thread
dgryski marked this conversation as resolved.
Outdated

// This logic is mostly copied from Value.CanConvert

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 && r.elem() == u.elem().elem() {
return true
}

case String:
// bytes or runes
if !r.elem().isNamed() && (r.elem().Kind() == Uint8 || r.elem().Kind() == Int32) {
return true
}

}

case String:
// bytes or runes
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

}

// AssignableTo returns whether a value of type t can be assigned to a variable
// of type u.
func (t *RawType) AssignableTo(u Type) bool {
Expand Down
119 changes: 101 additions & 18 deletions src/internal/reflectlite/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be a pointer receiver here? None of the other functions are.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

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")
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -1485,13 +1493,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
}
Comment thread
dgryski marked this conversation as resolved.

case Slice:
switch rtype := typ.(*RawType); rtype.Kind() {
Expand Down Expand Up @@ -1534,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
}
Comment thread
dgryski marked this conversation as resolved.
}

// TODO(dgryski): Unimplemented:
Expand Down Expand Up @@ -1578,6 +1590,18 @@ 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)
}

//go:linkname stringToBytes runtime.stringToBytes
func stringToBytes(x string) []byte

Expand Down Expand Up @@ -1661,20 +1685,79 @@ func makeFloat32(flags valueFlags, f float32, t *RawType) Value {
return v
}

func cvtIntString(src Value, t *RawType) Value {
panic("cvtUintString: unimplemented")
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
}

//go:linkname stringFromUnicode runtime.stringFromUnicode
func stringFromUnicode(x rune) string
Comment thread
dgryski marked this conversation as resolved.
Outdated

func cvtIntString(v Value, t *RawType) Value {
s := "\uFFFD"
if x := v.Int(); int64(rune(x)) == x {
s = string(rune(x))
}
return Value{
typecode: t,
value: unsafe.Pointer(&s),
flags: v.flags,
}
}

func cvtUintString(src Value, t *RawType) Value {
panic("cvtUintString: unimplemented")
func cvtUintString(v Value, t *RawType) Value {
s := "\uFFFD"
if x := v.Uint(); uint64(rune(x)) == x {
s = string(rune(x))
}

return Value{
typecode: t,
value: unsafe.Pointer(&s),
flags: v.flags,
}
}

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
Expand Down
Loading
Loading