reflect: add limited support for all type kinds

This commit makes sure all Go types can be encoded in the interface type
code, so that Type.Kind() always returns a proper type kind for any
non-nil interface.
This commit is contained in:
Ayke van Laethem
2019-01-20 17:30:27 +01:00
parent 101f2e519b
commit dfef168139
6 changed files with 377 additions and 66 deletions
+48 -18
View File
@@ -4,10 +4,26 @@ import (
"unsafe"
)
// A Kind is the number that the compiler uses for this type.
// The compiler uses a compact encoding to store type information. Unlike the
// main Go compiler, most of the types are stored directly in the type code.
//
// Not used directly. These types are all replaced with the number the compiler
// uses internally for the type.
// Type code bit allocation:
// xxxxx0: basic types, where xxxxx is the basic type number (never 0).
// The higher bits indicate the named type, if any.
// nxxx1: complex types, where n indicates whether this is a named type (named
// if set) and xxx contains the type kind number:
// 0 (0001): Chan
// 1 (0011): Interface
// 2 (0101): Ptr
// 3 (0111): Slice
// 4 (1001): Array
// 5 (1011): Func
// 6 (1101): Map
// 7 (1111): Struct
// The higher bits are either the contents of the type depending on the
// type (if n is clear) or indicate the number of the named type (if n
// is set).
type Kind uintptr
// Copied from reflect/type.go
@@ -32,13 +48,13 @@ const (
Complex128
String
UnsafePointer
Array
Chan
Func
Interface
Map
Ptr
Slice
Array
Func
Map
Struct
)
@@ -80,8 +96,22 @@ func (k Kind) String() string {
return "string"
case UnsafePointer:
return "unsafe.Pointer"
case Chan:
return "chan"
case Interface:
return "interface"
case Ptr:
return "ptr"
case Slice:
return "slice"
case Array:
return "array"
case Func:
return "func"
case Map:
return "map"
case Struct:
return "struct"
default:
return "invalid"
}
@@ -89,7 +119,7 @@ func (k Kind) String() string {
// basicType returns a new Type for this kind if Kind is a basic type.
func (k Kind) basicType() Type {
return Type(k << 2 | 0)
return Type(k << 1)
}
// The typecode as used in an interface{}.
@@ -104,22 +134,22 @@ func (t Type) String() string {
}
func (t Type) Kind() Kind {
if t % 4 == 0 {
// Basic type
return Kind(t >> 2)
} else if t % 4 == 1 {
// Slice
return Slice
if t % 2 == 0 {
// basic type
return Kind((t >> 1) % 32)
} else {
return Invalid // TODO
return Kind(t >> 1) % 8 + 19
}
}
func (t Type) Elem() Type {
switch t.Kind() {
case Slice:
return t >> 2
default: // not implemented: Array, Chan, Map, Ptr
case Chan, Ptr, Slice:
if (t >> 4) % 2 != 0 {
panic("unimplemented: (reflect.Type).Elem() for named types")
}
return t >> 5
default: // not implemented: Array, Map
panic("unimplemented: (reflect.Type).Elem()")
}
}
@@ -164,7 +194,7 @@ func (t Type) Size() uintptr {
return 16
case String:
return unsafe.Sizeof(StringHeader{})
case UnsafePointer:
case UnsafePointer, Chan, Map, Ptr:
return unsafe.Sizeof(uintptr(0))
case Slice:
return unsafe.Sizeof(SliceHeader{})
+31 -4
View File
@@ -31,16 +31,38 @@ func (v Value) Kind() Kind {
}
func (v Value) IsNil() bool {
panic("unimplemented: (reflect.Value).IsNil()")
switch v.Kind() {
case Chan, Map, Ptr:
return v.value == nil
case Func:
if v.value == nil {
return true
}
fn := (*funcHeader)(v.value)
return fn.Code == nil
case Slice:
if v.value == nil {
return true
}
slice := (*SliceHeader)(v.value)
return slice.Data == 0
case Interface:
panic("unimplemented: (reflect.Value).IsNil()")
default:
panic(&ValueError{"IsNil"})
}
}
func (v Value) Pointer() uintptr {
switch v.Kind() {
case UnsafePointer:
case Chan, Map, Ptr, UnsafePointer:
return uintptr(v.value)
case Chan, Func, Map, Ptr, Slice:
case Slice:
slice := (*SliceHeader)(v.value)
return slice.Data
case Func:
panic("unimplemented: (reflect.Value).Pointer()")
default:
default: // not implemented: Func
panic(&ValueError{"Pointer"})
}
}
@@ -322,6 +344,11 @@ func MakeSlice(typ Type, len, cap int) Value {
panic("unimplemented: reflect.MakeSlice()")
}
type funcHeader struct {
Context unsafe.Pointer
Code unsafe.Pointer
}
type SliceHeader struct {
Data uintptr
Len uintptr