// Needed by the prettyprinter code for interface inspection.
for _, typ := range []string{
- "type:runtime._type",
+ "type:internal/abi.Type",
"type:internal/abi.ArrayType",
"type:internal/abi.ChanType",
"type:runtime.functype",
}
want := map[string]bool{
- "runtime._type": true,
+ "internal/abi.Type": true,
"internal/abi.ArrayType": true,
"internal/abi.ChanType": true,
"runtime.functype": true,
// to describe a non-defined type with no methods.
type uncommonType = abi.UncommonType
-// rtype is the common implementation of most values.
-// It is embedded in other struct types.
+// rtype is a wrapper that allows us to define exactly the type.Reflect methods.
type rtype struct {
t *abi.Type
}
// typehash, but we want to report the topmost type in
// the error text (e.g. in a struct with a field of slice type
// we want to report the struct, not the slice).
- panic(errorString("hash of unhashable type " + t.string()))
+ panic(errorString("hash of unhashable type " + toRType(t).string()))
}
if isDirectIface(t) {
return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
}
if t.Equal == nil {
// See comment in interhash above.
- panic(errorString("hash of unhashable type " + t.string()))
+ panic(errorString("hash of unhashable type " + toRType(t).string()))
}
if isDirectIface(t) {
return c1 * typehash(t, unsafe.Pointer(&a.data), h^c0)
case kindArray:
a := (*arraytype)(unsafe.Pointer(t))
for i := uintptr(0); i < a.Len; i++ {
- h = typehash(toType(a.Elem), add(p, i*a.Elem.Size_), h)
+ h = typehash(a.Elem, add(p, i*a.Elem.Size_), h)
}
return h
case kindStruct:
default:
// Should never happen, as typehash should only be called
// with comparable types.
- panic(errorString("hash of unhashable type " + t.string()))
+ panic(errorString("hash of unhashable type " + toRType(t).string()))
}
}
}
eq := t.Equal
if eq == nil {
- panic(errorString("comparing uncomparable type " + t.string()))
+ panic(errorString("comparing uncomparable type " + toRType(t).string()))
}
if isDirectIface(t) {
// Direct interface types are ptr, chan, map, func, and single-element structs/arrays thereof.
t := tab._type
eq := t.Equal
if eq == nil {
- panic(errorString("comparing uncomparable type " + t.string()))
+ panic(errorString("comparing uncomparable type " + toRType(t).string()))
}
if isDirectIface(t) {
// See comment in efaceeq.
if at.Len != 1 {
throw("can't happen")
}
- cgoCheckArg(toType(at.Elem), p, at.Elem.Kind_&kindDirectIface == 0, top, msg)
+ cgoCheckArg(at.Elem, p, at.Elem.Kind_&kindDirectIface == 0, top, msg)
return
}
for i := uintptr(0); i < at.Len; i++ {
- cgoCheckArg(toType(at.Elem), p, true, top, msg)
+ cgoCheckArg(at.Elem, p, true, top, msg)
p = add(p, at.Elem.Size_)
}
case kindChan, kindMap:
at := (*arraytype)(unsafe.Pointer(typ))
for i := uintptr(0); i < at.Len; i++ {
if off < at.Elem.Size_ {
- cgoCheckUsingType(toType(at.Elem), src, off, size)
+ cgoCheckUsingType(at.Elem, src, off, size)
}
src = add(src, at.Elem.Size_)
skipped := off
default:
// Elements contain pointers.
c = new(hchan)
- c.buf = mallocgc(mem, toType(elem), true)
+ c.buf = mallocgc(mem, elem, true)
}
c.elemsize = uint16(elem.Size_)
- c.elemtype = toType(elem)
+ c.elemtype = elem
c.dataqsiz = uint(size)
lockInit(&c.lock, lockRankHchan)
func (e *TypeAssertionError) Error() string {
inter := "interface"
if e._interface != nil {
- inter = e._interface.string()
+ inter = toRType(e._interface).string()
}
- as := e.asserted.string()
+ as := toRType(e.asserted).string()
if e.concrete == nil {
return "interface conversion: " + inter + " is nil, not " + as
}
- cs := e.concrete.string()
+ cs := toRType(e.concrete).string()
if e.missingMethod == "" {
msg := "interface conversion: " + inter + " is " + cs + ", not " + as
if cs == as {
// provide slightly clearer error message
- if e.concrete.pkgpath() != e.asserted.pkgpath() {
+ if toRType(e.concrete).pkgpath() != toRType(e.asserted).pkgpath() {
msg += " (types from different packages)"
} else {
msg += " (types from different scopes)"
func printanycustomtype(i any) {
eface := efaceOf(&i)
- typestring := eface._type.string()
+ typestring := toRType(eface._type).string()
switch eface._type.Kind_ {
case kindString:
dumpint(tagType)
dumpint(uint64(uintptr(unsafe.Pointer(t))))
dumpint(uint64(t.Size_))
- if x := t.uncommon(); x == nil || t.nameOff(x.PkgPath).name() == "" {
- dumpstr(t.string())
+ rt := toRType(t)
+ if x := t.Uncommon(); x == nil || rt.nameOff(x.PkgPath).name() == "" {
+ dumpstr(rt.string())
} else {
- pkgpath := t.nameOff(x.PkgPath).name()
- name := t.name()
+ pkgpath := rt.nameOff(x.PkgPath).name()
+ name := rt.name()
dumpint(uint64(uintptr(len(pkgpath)) + 1 + uintptr(len(name))))
dwrite(unsafe.Pointer(unsafe.StringData(pkgpath)), uintptr(len(pkgpath)))
dwritebyte('.')
if canfail {
return nil
}
- name := inter.typ.nameOff(inter.mhdr[0].Name)
+ name := toRType(&inter.typ).nameOff(inter.mhdr[0].Name)
panic(&TypeAssertionError{nil, typ, &inter.typ, name.name()})
}
func (m *itab) init() string {
inter := m.inter
typ := m._type
- x := typ.uncommon()
+ x := typ.Uncommon()
// both inter and typ have method sorted by name,
// and interface names are unique,
imethods:
for k := 0; k < ni; k++ {
i := &inter.mhdr[k]
- itype := inter.typ.typeOff(i.Typ)
- name := inter.typ.nameOff(i.Name)
+ itype := toRType(&inter.typ).typeOff(i.Typ)
+ name := toRType(&inter.typ).nameOff(i.Name)
iname := name.name()
ipkg := name.pkgPath()
if ipkg == "" {
}
for ; j < nt; j++ {
t := &xmhdr[j]
- tname := typ.nameOff(t.Name)
- if typ.typeOff(t.Mtyp) == itype && tname.name() == iname {
+ rtyp := toRType(typ)
+ tname := rtyp.nameOff(t.Name)
+ if rtyp.typeOff(t.Mtyp) == itype && tname.name() == iname {
pkgPath := tname.pkgPath()
if pkgPath == "" {
- pkgPath = typ.nameOff(x.PkgPath).name()
+ pkgPath = rtyp.nameOff(x.PkgPath).name()
}
if tname.isExported() || pkgPath == ipkg {
if m != nil {
- ifn := typ.textOff(t.Ifn)
+ ifn := rtyp.textOff(t.Ifn)
if k == 0 {
fun0 = ifn // we'll set m.fun[0] at the end
} else {
// anywhere in the bulk barrier or memmove.
//
//go:nosplit
-func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+func typedmemmove(typ *abi.Type, dst, src unsafe.Pointer) {
if dst == src {
return
}
throw("runtime: typeBitsBulkBarrier without type")
}
if typ.Size_ != size {
- println("runtime: typeBitsBulkBarrier with type ", typ.string(), " of size ", typ.Size_, " but memory size", size)
+ println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " of size ", typ.Size_, " but memory size", size)
throw("runtime: invalid typeBitsBulkBarrier")
}
if typ.Kind_&kindGCProg != 0 {
- println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog")
+ println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " with GC prog")
throw("runtime: invalid typeBitsBulkBarrier")
}
if !writeBarrier.needed {
throw("runtime.SetFinalizer: first argument is nil")
}
if etyp.Kind_&kindMask != kindPtr {
- throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
+ throw("runtime.SetFinalizer: first argument is " + toRType(etyp).string() + ", not pointer")
}
ot := (*ptrtype)(unsafe.Pointer(etyp))
if ot.elem == nil {
}
if ftyp.Kind_&kindMask != kindFunc {
- throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
+ throw("runtime.SetFinalizer: second argument is " + toRType(ftyp).string() + ", not a function")
}
ft := (*functype)(unsafe.Pointer(ftyp))
if ft.dotdotdot() {
- throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
+ throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string() + " because dotdotdot")
}
if ft.inCount != 1 {
- throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
+ throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string())
}
fint := ft.in()[0]
switch {
// ok - same type
goto okarg
case fint.Kind_&kindMask == kindPtr:
- if (fint.uncommon() == nil || etyp.uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
+ if (fint.Uncommon() == nil || etyp.Uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
// ok - not same type, but both pointers,
// one or the other is unnamed, and same element type, so assignable.
goto okarg
goto okarg
}
}
- throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
+ throw("runtime.SetFinalizer: cannot pass " + toRType(etyp).string() + " to finalizer " + toRType(ftyp).string())
okarg:
// compute size needed for return parameters
nret := uintptr(0)
if typ == nil {
print("tracealloc(", p, ", ", hex(size), ")\n")
} else {
- print("tracealloc(", p, ", ", hex(size), ", ", typ.string(), ")\n")
+ print("tracealloc(", p, ", ", hex(size), ", ", toRType(typ).string(), ")\n")
}
if gp.m.curg == nil || gp == gp.m.curg {
goroutineheader(gp)
case string:
throw(text + ": " + r)
default:
- throw(text + ": type " + efaceOf(&r)._type.string())
+ throw(text + ": type " + toRType(efaceOf(&r)._type).string())
}
}()
for p != nil {
syms = make(map[string]any, len(md.ptab))
for _, ptab := range md.ptab {
symName := resolveNameOff(unsafe.Pointer(md.types), ptab.name)
- t := (*_type)(unsafe.Pointer(md.types)).typeOff(ptab.typ)
+ t := toRType((*_type)(unsafe.Pointer(md.types))).typeOff(ptab.typ) // TODO can this stack of conversions be simpler?
var val any
valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val))
(*valp)[0] = unsafe.Pointer(t)
//
//go:linkname reflect_resolveTypeOff reflect.resolveTypeOff
func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
- return unsafe.Pointer((*_type)(rtype).typeOff(typeOff(off)))
+ return unsafe.Pointer(toRType((*_type)(rtype)).typeOff(typeOff(off)))
}
// reflect_resolveTextOff resolves a function pointer offset from a base type.
//
//go:linkname reflect_resolveTextOff reflect.resolveTextOff
func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
- return (*_type)(rtype).textOff(textOff(off))
+ return toRType((*_type)(rtype)).textOff(textOff(off))
}
//
//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)))
+ return unsafe.Pointer(toRType((*_type)(rtype)).typeOff(typeOff(off)))
}
// reflect_addReflectOff adds a pointer to the reflection offset lookup map.
}
// Pointer-sized types such as maps and channels are currently
// not supported.
- panic("compileCallabck: type " + t.string() + " is currently not supported for use in system callbacks")
+ panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks")
}
// assignReg attempts to assign a single register for an
type typeOff = abi.TypeOff
type textOff = abi.TextOff
-// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
-// ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
-// ../reflect/type.go:/^type.rtype.
-// ../internal/reflectlite/type.go:/^type.rtype.
-type _type struct {
- abi.Type
+type _type = abi.Type
+
+// rtype is a wrapper that allows us to define additional methods.
+type rtype struct {
+ *abi.Type // embedding is okay here (unlike reflect) because none of this is public
}
-func (t *_type) string() string {
+func (t rtype) string() string {
s := t.nameOff(t.Str).name()
if t.TFlag&abi.TFlagExtraStar != 0 {
return s[1:]
return s
}
-func (t *_type) uncommon() *uncommontype {
+func (t rtype) uncommon() *uncommontype {
return t.Uncommon()
}
-func (t *_type) name() string {
+func (t rtype) name() string {
if t.TFlag&abi.TFlagNamed == 0 {
return ""
}
// available. This is not the same as the reflect package's PkgPath
// method, in that it returns the package path for struct and interface
// types, not just named types.
-func (t *_type) pkgpath() string {
+func (t rtype) pkgpath() string {
if u := t.uncommon(); u != nil {
return t.nameOff(u.PkgPath).name()
}
switch t.Kind_ & kindMask {
case kindStruct:
- st := (*structtype)(unsafe.Pointer(t))
+ st := (*structtype)(unsafe.Pointer(t.Type))
return st.pkgPath.name()
case kindInterface:
- it := (*interfacetype)(unsafe.Pointer(t))
+ it := (*interfacetype)(unsafe.Pointer(t.Type))
return it.pkgpath.name()
}
return ""
return name{(*byte)(res)}
}
-func (t *_type) nameOff(off nameOff) name {
- return resolveNameOff(unsafe.Pointer(t), off)
+func (t rtype) nameOff(off nameOff) name {
+ return resolveNameOff(unsafe.Pointer(t.Type), off)
}
func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
return (*_type)(unsafe.Pointer(res))
}
-func (t *_type) typeOff(off typeOff) *_type {
- return resolveTypeOff(unsafe.Pointer(t), off)
+func (t rtype) typeOff(off typeOff) *_type {
+ return resolveTypeOff(unsafe.Pointer(t.Type), off)
}
-func (t *_type) textOff(off textOff) unsafe.Pointer {
+func (t rtype) textOff(off textOff) unsafe.Pointer {
if off == -1 {
// -1 is the sentinel value for unreachable code.
// See cmd/link/internal/ld/data.go:relocsym.
return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
}
- base := uintptr(unsafe.Pointer(t))
+ base := uintptr(unsafe.Pointer(t.Type))
var md *moduledata
for next := &firstmoduledata; next != nil; next = next.next {
if base >= next.types && base < next.etypes {
t2 *_type
}
-func toType(t *abi.Type) *_type {
- return (*_type)(unsafe.Pointer(t))
+func toRType(t *abi.Type) rtype {
+ return rtype{t}
}
// typesEqual reports whether two types are equal.
if kind != v.Kind_&kindMask {
return false
}
- if t.string() != v.string() {
+ rt, rv := toRType(t), toRType(v)
+ if rt.string() != rv.string() {
return false
}
- ut := t.uncommon()
- uv := v.uncommon()
+ ut := t.Uncommon()
+ uv := v.Uncommon()
if ut != nil || uv != nil {
if ut == nil || uv == nil {
return false
}
- pkgpatht := t.nameOff(ut.PkgPath).name()
- pkgpathv := v.nameOff(uv.PkgPath).name()
+ pkgpatht := rt.nameOff(ut.PkgPath).name()
+ pkgpathv := rv.nameOff(uv.PkgPath).name()
if pkgpatht != pkgpathv {
return false
}
case kindArray:
at := (*arraytype)(unsafe.Pointer(t))
av := (*arraytype)(unsafe.Pointer(v))
- return typesEqual(toType(at.Elem), toType(av.Elem), seen) && at.Len == av.Len
+ return typesEqual(at.Elem, av.Elem, seen) && at.Len == av.Len
case kindChan:
ct := (*chantype)(unsafe.Pointer(t))
cv := (*chantype)(unsafe.Pointer(v))
- return ct.Dir == cv.Dir && typesEqual(toType(ct.Elem), toType(cv.Elem), seen)
+ return ct.Dir == cv.Dir && typesEqual(ct.Elem, cv.Elem, seen)
case kindFunc:
ft := (*functype)(unsafe.Pointer(t))
fv := (*functype)(unsafe.Pointer(v))