Skip to content
92 changes: 92 additions & 0 deletions src/internal/reflectlite/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,98 @@ func (t *RawType) FieldAlign() int {
return t.Align()
}

// 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

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
117 changes: 99 additions & 18 deletions src/internal/reflectlite/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,21 @@ 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) Value {
if ro {
v.flags |= valueFlagRO
} else {
v.flags &^= valueFlagRO
}
return v
}

func (v Value) checkRO() {
if v.isRO() {
if v.IsRO() {
panic("reflect: value is not settable")
}
}
Expand Down Expand Up @@ -297,7 +306,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 +1494,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 rtype := typ.(*RawType); rtype.Kind() {
case Complex64, Complex128:
return cvtComplex(src, rtype), true
}
Comment thread
dgryski marked this conversation as resolved.

case Slice:
switch rtype := typ.(*RawType); rtype.Kind() {
Expand Down Expand Up @@ -1534,6 +1541,12 @@ func convertOp(src Value, typ Type) (Value, bool) {
return cvtStringRunes(src, rtype), true
}
}

case Pointer:
rtype := typ.(*RawType)
if rtype.Kind() == Pointer && !src.typecode.isNamed() && !rtype.isNamed() && src.typecode.elem().underlying() == rtype.elem().underlying() {
return cvtDirect(src, rtype), true
}
Comment thread
dgryski marked this conversation as resolved.
}

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

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