Commit 9650726e authored by Marcel van Lohuizen's avatar Marcel van Lohuizen

internal/reflectlite: lite version of reflect package

to be used by errors package for checking assignability
and setting error values in As.

Updates #29934.

Change-Id: I8c1d02a2c6efa0919d54b286cfe8b4edc26da059
Reviewed-on: https://go-review.googlesource.com/c/161759
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent b9596aea
...@@ -46,6 +46,7 @@ var pkgDeps = map[string][]string{ ...@@ -46,6 +46,7 @@ var pkgDeps = map[string][]string{
"unsafe": {}, "unsafe": {},
"internal/cpu": {}, "internal/cpu": {},
"internal/bytealg": {"unsafe", "internal/cpu"}, "internal/bytealg": {"unsafe", "internal/cpu"},
"internal/reflectlite": {"runtime", "unsafe"},
"L0": { "L0": {
"errors", "errors",
...@@ -57,6 +58,7 @@ var pkgDeps = map[string][]string{ ...@@ -57,6 +58,7 @@ var pkgDeps = map[string][]string{
"unsafe", "unsafe",
"internal/cpu", "internal/cpu",
"internal/bytealg", "internal/bytealg",
"internal/reflectlite",
}, },
// L1 adds simple functions and strings processing, // L1 adds simple functions and strings processing,
......
This diff is collapsed.
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Trigger build without complete flag.
\ No newline at end of file
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflectlite
import (
"unsafe"
)
// Field returns the i'th field of the struct v.
// It panics if v's Kind is not Struct or i is out of range.
func Field(v Value, i int) Value {
if v.kind() != Struct {
panic(&ValueError{"reflect.Value.Field", v.kind()})
}
tt := (*structType)(unsafe.Pointer(v.typ))
if uint(i) >= uint(len(tt.fields)) {
panic("reflect: Field index out of range")
}
field := &tt.fields[i]
typ := field.typ
// Inherit permission bits from v, but clear flagEmbedRO.
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
// Using an unexported field forces flagRO.
if !field.name.isExported() {
if field.embedded() {
fl |= flagEmbedRO
} else {
fl |= flagStickyRO
}
}
// Either flagIndir is set and v.ptr points at struct,
// or flagIndir is not set and v.ptr is the actual struct data.
// In the former case, we want v.ptr + offset.
// In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still the correct address.
ptr := add(v.ptr, field.offset(), "same as non-reflect &v.field")
return Value{typ, ptr, fl}
}
func TField(typ Type, i int) Type {
t := typ.(*rtype)
if t.Kind() != Struct {
panic("reflect: Field of non-struct type")
}
tt := (*structType)(unsafe.Pointer(t))
return StructFieldType(tt, i)
}
// Field returns the i'th struct field.
func StructFieldType(t *structType, i int) Type {
if i < 0 || i >= len(t.fields) {
panic("reflect: Field index out of bounds")
}
p := &t.fields[i]
return toType(p.typ)
}
// Zero returns a Value representing the zero value for the specified type.
// The result is different from the zero value of the Value struct,
// which represents no value at all.
// For example, Zero(TypeOf(42)) returns a Value with Kind Int and value 0.
// The returned value is neither addressable nor settable.
func Zero(typ Type) Value {
if typ == nil {
panic("reflect: Zero(nil)")
}
t := typ.(*rtype)
fl := flag(t.Kind())
if ifaceIndir(t) {
return Value{t, unsafe_New(t), fl | flagIndir}
}
return Value{t, nil, fl}
}
// ToInterface returns v's current value as an interface{}.
// It is equivalent to:
// var i interface{} = (v's underlying value)
// It panics if the Value was obtained by accessing
// unexported struct fields.
func ToInterface(v Value) (i interface{}) {
return valueInterface(v)
}
type EmbedWithUnexpMeth struct{}
func (EmbedWithUnexpMeth) f() {}
type pinUnexpMeth interface {
f()
}
var pinUnexpMethI = pinUnexpMeth(EmbedWithUnexpMeth{})
func FirstMethodNameBytes(t Type) *byte {
_ = pinUnexpMethI
ut := t.uncommon()
if ut == nil {
panic("type has no methods")
}
m := ut.methods()[0]
mname := t.(*rtype).nameOff(m.name)
if *mname.data(0, "name flag field")&(1<<2) == 0 {
panic("method name does not have pkgPath *string")
}
return mname.bytes
}
type Buffer struct {
buf []byte
}
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflectlite_test
import (
"bytes"
"go/ast"
"go/token"
. "internal/reflectlite"
"io"
"testing"
)
func TestImplicitSetConversion(t *testing.T) {
// Assume TestImplicitMapConversion covered the basics.
// Just make sure conversions are being applied at all.
var r io.Reader
b := new(bytes.Buffer)
rv := ValueOf(&r).Elem()
rv.Set(ValueOf(b))
if r != b {
t.Errorf("after Set: r=%T(%v)", r, r)
}
}
var implementsTests = []struct {
x interface{}
t interface{}
b bool
}{
{new(*bytes.Buffer), new(io.Reader), true},
{new(bytes.Buffer), new(io.Reader), false},
{new(*bytes.Buffer), new(io.ReaderAt), false},
{new(*ast.Ident), new(ast.Expr), true},
{new(*notAnExpr), new(ast.Expr), false},
{new(*ast.Ident), new(notASTExpr), false},
{new(notASTExpr), new(ast.Expr), false},
{new(ast.Expr), new(notASTExpr), false},
{new(*notAnExpr), new(notASTExpr), true},
}
type notAnExpr struct{}
func (notAnExpr) Pos() token.Pos { return token.NoPos }
func (notAnExpr) End() token.Pos { return token.NoPos }
func (notAnExpr) exprNode() {}
type notASTExpr interface {
Pos() token.Pos
End() token.Pos
exprNode()
}
func TestImplements(t *testing.T) {
for _, tt := range implementsTests {
xv := TypeOf(tt.x).Elem()
xt := TypeOf(tt.t).Elem()
if b := xv.Implements(xt); b != tt.b {
t.Errorf("(%s).Implements(%s) = %v, want %v", TypeString(xv), TypeString(xt), b, tt.b)
}
}
}
var assignableTests = []struct {
x interface{}
t interface{}
b bool
}{
{new(chan int), new(<-chan int), true},
{new(<-chan int), new(chan int), false},
{new(*int), new(IntPtr), true},
{new(IntPtr), new(*int), true},
{new(IntPtr), new(IntPtr1), false},
{new(Ch), new(<-chan interface{}), true},
// test runs implementsTests too
}
type IntPtr *int
type IntPtr1 *int
type Ch <-chan interface{}
func TestAssignableTo(t *testing.T) {
for i, tt := range append(assignableTests, implementsTests...) {
xv := TypeOf(tt.x).Elem()
xt := TypeOf(tt.t).Elem()
if b := xv.AssignableTo(xt); b != tt.b {
t.Errorf("%d:AssignableTo: got %v, want %v", i, b, tt.b)
}
}
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Formatting of reflection types and values for debugging.
// Not defined as methods so they do not need to be linked into most binaries;
// the functions are not used by the library itself, only in tests.
package reflectlite_test
import (
. "internal/reflectlite"
"reflect"
"strconv"
)
// valueToString returns a textual representation of the reflection value val.
// For debugging only.
func valueToString(v Value) string {
return valueToStringImpl(reflect.ValueOf(ToInterface(v)))
}
func valueToStringImpl(val reflect.Value) string {
var str string
if !val.IsValid() {
return "<zero Value>"
}
typ := val.Type()
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(val.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(val.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(val.Float(), 'g', -1, 64)
case reflect.Complex64, reflect.Complex128:
c := val.Complex()
return strconv.FormatFloat(real(c), 'g', -1, 64) + "+" + strconv.FormatFloat(imag(c), 'g', -1, 64) + "i"
case reflect.String:
return val.String()
case reflect.Bool:
if val.Bool() {
return "true"
} else {
return "false"
}
case reflect.Ptr:
v := val
str = typ.String() + "("
if v.IsNil() {
str += "0"
} else {
str += "&" + valueToStringImpl(v.Elem())
}
str += ")"
return str
case reflect.Array, reflect.Slice:
v := val
str += typ.String()
str += "{"
for i := 0; i < v.Len(); i++ {
if i > 0 {
str += ", "
}
str += valueToStringImpl(v.Index(i))
}
str += "}"
return str
case reflect.Map:
str += typ.String()
str += "{"
str += "<can't iterate on maps>"
str += "}"
return str
case reflect.Chan:
str = typ.String()
return str
case reflect.Struct:
t := typ
v := val
str += t.String()
str += "{"
for i, n := 0, v.NumField(); i < n; i++ {
if i > 0 {
str += ", "
}
str += valueToStringImpl(v.Field(i))
}
str += "}"
return str
case reflect.Interface:
return typ.String() + "(" + valueToStringImpl(val.Elem()) + ")"
case reflect.Func:
return typ.String() + "(arg)"
default:
panic("valueToString: can't print type " + typ.String())
}
}
This diff is collapsed.
This diff is collapsed.
...@@ -492,6 +492,11 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { ...@@ -492,6 +492,11 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
*dst = assertE2I(inter, e) *dst = assertE2I(inter, e)
} }
//go:linkname reflectlite_ifaceE2I internal/reflectlite.ifaceE2I
func reflectlite_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
*dst = assertE2I(inter, e)
}
func iterate_itabs(fn func(*itab)) { func iterate_itabs(fn func(*itab)) {
// Note: only runs during stop the world or with itabLock held, // Note: only runs during stop the world or with itabLock held,
// so no other locks/atomics needed. // so no other locks/atomics needed.
......
...@@ -1073,6 +1073,11 @@ func reflect_unsafe_New(typ *_type) unsafe.Pointer { ...@@ -1073,6 +1073,11 @@ func reflect_unsafe_New(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true) return mallocgc(typ.size, typ, true)
} }
//go:linkname reflectlite_unsafe_New internal/reflectlite.unsafe_New
func reflectlite_unsafe_New(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true)
}
// newarray allocates an array of n elements of type typ. // newarray allocates an array of n elements of type typ.
func newarray(typ *_type, n int) unsafe.Pointer { func newarray(typ *_type, n int) unsafe.Pointer {
if n == 1 { if n == 1 {
......
...@@ -186,6 +186,11 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { ...@@ -186,6 +186,11 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
typedmemmove(typ, dst, src) typedmemmove(typ, dst, src)
} }
//go:linkname reflectlite_typedmemmove internal/reflectlite.typedmemmove
func reflectlite_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
reflect_typedmemmove(typ, dst, src)
}
// typedmemmovepartial is like typedmemmove but assumes that // typedmemmovepartial is like typedmemmove but assumes that
// dst and src point off bytes into the value and only copies size bytes. // dst and src point off bytes into the value and only copies size bytes.
//go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial //go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
......
...@@ -490,6 +490,18 @@ func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { ...@@ -490,6 +490,18 @@ func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
} }
// reflectlite_resolveNameOff resolves a name offset from a base pointer.
//go:linkname reflectlite_resolveNameOff internal/reflectlite.resolveNameOff
func reflectlite_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer {
return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes)
}
// reflectlite_resolveTypeOff resolves an *rtype offset from a base type.
//go:linkname reflectlite_resolveTypeOff internal/reflectlite.resolveTypeOff
func reflectlite_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
return unsafe.Pointer((*_type)(rtype).typeOff(typeOff(off)))
}
// reflect_addReflectOff adds a pointer to the reflection offset lookup map. // reflect_addReflectOff adds a pointer to the reflection offset lookup map.
//go:linkname reflect_addReflectOff reflect.addReflectOff //go:linkname reflect_addReflectOff reflect.addReflectOff
func reflect_addReflectOff(ptr unsafe.Pointer) int32 { func reflect_addReflectOff(ptr unsafe.Pointer) int32 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment