]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: redefine _type to abi.Type; add rtype for methods.
authorDavid Chase <drchase@google.com>
Mon, 24 Apr 2023 19:45:33 +0000 (15:45 -0400)
committerDavid Chase <drchase@google.com>
Thu, 11 May 2023 04:50:30 +0000 (04:50 +0000)
Change-Id: I1c478b704d84811caa209006c657dda82d9c4cf9
Reviewed-on: https://go-review.googlesource.com/c/go/+/488435
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
19 files changed:
src/cmd/link/internal/ld/dwarf.go
src/cmd/link/internal/ld/dwarf_test.go
src/reflect/type.go
src/runtime/alg.go
src/runtime/cgocall.go
src/runtime/cgocheck.go
src/runtime/chan.go
src/runtime/error.go
src/runtime/heapdump.go
src/runtime/iface.go
src/runtime/mbarrier.go
src/runtime/mbitmap.go
src/runtime/mfinal.go
src/runtime/mprof.go
src/runtime/panic.go
src/runtime/plugin.go
src/runtime/runtime1.go
src/runtime/syscall_windows.go
src/runtime/type.go

index b9383e28b9d510c94abe5122fb5c15fdfc316ee7..238262cffea7757da67804f78564f3af898dc12b 100644 (file)
@@ -1802,7 +1802,7 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
 
        // 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",
index c8715922d8a1414a754c5fdcbc4a1dfa1bfdb2d8..15682dff3d4348a083608ffe0885751495c1abca 100644 (file)
@@ -56,7 +56,7 @@ func TestRuntimeTypesPresent(t *testing.T) {
        }
 
        want := map[string]bool{
-               "runtime._type":          true,
+               "internal/abi.Type":      true,
                "internal/abi.ArrayType": true,
                "internal/abi.ChanType":  true,
                "runtime.functype":       true,
index d2fde0b3aea66c6f8567c91359580ba46c316a6c..b817e811aacdb94638a3da237bd5cbb72f814dc3 100644 (file)
@@ -279,8 +279,7 @@ const Ptr = Pointer
 // 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
 }
index e40eb9b47b869b28537a9465ca5c0b83e5db02b9..4eda9d4e75c5942125437b2c4e0df19452f256e6 100644 (file)
@@ -106,7 +106,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr {
                // 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)
@@ -123,7 +123,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
        }
        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)
@@ -174,7 +174,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
        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:
@@ -189,7 +189,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
        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()))
        }
 }
 
@@ -247,7 +247,7 @@ func efaceeq(t *_type, x, y unsafe.Pointer) bool {
        }
        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.
@@ -264,7 +264,7 @@ func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
        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.
index e2e37284a212ecaf7de79c4e48613d2b1f8198c4..04ab9faa3db8cb4fb8adadf0929808199618b1a9 100644 (file)
@@ -466,11 +466,11 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
                        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:
index 1acf0f9233c3efa5cc656790924fa62a95342aa5..2cfbdeebb5b50c870951c0bf20fd75c6fb23e2ff 100644 (file)
@@ -249,7 +249,7 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
                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
index 0a8578d4356c384a75bb59e2c8614f194312c98f..98e08366701ce4de9e01d2b87714d26e00a763c5 100644 (file)
@@ -104,11 +104,11 @@ func makechan(t *chantype, size int) *hchan {
        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)
 
index 9bad50d90b5b46e07f56cf116d85ccc5ddc8d8a5..3590ccd965715eda61568affdb79d41ad3905de1 100644 (file)
@@ -30,18 +30,18 @@ func (*TypeAssertionError) RuntimeError() {}
 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)"
@@ -256,7 +256,7 @@ func printany(i any) {
 
 func printanycustomtype(i any) {
        eface := efaceOf(&i)
-       typestring := eface._type.string()
+       typestring := toRType(eface._type).string()
 
        switch eface._type.Kind_ {
        case kindString:
index d06ddfc0feb62e8ec64cfeba61d6442f9c83a1ee..6a042ea9cff7973c669e62f7910f1f714f39c1e4 100644 (file)
@@ -194,11 +194,12 @@ func dumptype(t *_type) {
        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('.')
index 67e98b08cecc3a92649b294da061466b0126b796..34d223f7f19c570d4e666c57b5411cd0919c0d8f 100644 (file)
@@ -41,7 +41,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
                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()})
        }
 
@@ -192,7 +192,7 @@ func (t *itabTableType) add(m *itab) {
 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,
@@ -207,8 +207,8 @@ func (m *itab) init() string {
 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 == "" {
@@ -216,15 +216,16 @@ imethods:
                }
                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 {
index ed6df2d55ea530a8b983b6ba77ccfd060a6af9f4..4bcc170ef953abeadd6fcf1073e821b77d3509a0 100644 (file)
@@ -155,7 +155,7 @@ import (
 // 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
        }
index f8ce5fd0064c3af34726c92517d197a9a415f7af..76f9a4eb9fed60b540461803ffcd749b27a505ee 100644 (file)
@@ -683,11 +683,11 @@ func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) {
                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 {
index e25c06bcf82c83b5709e7aeb1765623b0473b978..d302d7fd97acbe2bec0a1385aad7c3aca4f30284 100644 (file)
@@ -372,7 +372,7 @@ func SetFinalizer(obj any, finalizer any) {
                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 {
@@ -431,14 +431,14 @@ func SetFinalizer(obj any, finalizer any) {
        }
 
        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 {
@@ -446,7 +446,7 @@ func SetFinalizer(obj any, finalizer any) {
                // 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
@@ -461,7 +461,7 @@ func SetFinalizer(obj any, finalizer any) {
                        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)
index dfaa369740bc5c39588afb7f9452aaabdd4ba078..174ceb0a1f49c60ad36fa0d8e4f78d304eec74cc 100644 (file)
@@ -1230,7 +1230,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
        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)
index cefab56902f34614f935ec828cb395da78080396..751ad998c9943ad94f2f7b69354141985e106a85 100644 (file)
@@ -573,7 +573,7 @@ func preprintpanics(p *_panic) {
                case string:
                        throw(text + ": " + r)
                default:
-                       throw(text + ": type " + efaceOf(&r)._type.string())
+                       throw(text + ": type " + toRType(efaceOf(&r)._type).string())
                }
        }()
        for p != nil {
index d2ad1ed21cafce1d26b31ac521ba40ee405559b4..690f85750b27c4219efc57493780af59ed22e7a6 100644 (file)
@@ -79,7 +79,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*ini
        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)
index 65bed433c3e0f9d7f490a3cc82d4c1aa23a6ff42..0fa34ba0887f79304af015543bd4d24c75f40fa8 100644 (file)
@@ -608,14 +608,14 @@ func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointe
 //
 //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))
 
 }
 
@@ -630,7 +630,7 @@ func reflectlite_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Po
 //
 //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.
index 37f86d0d7fd1173701696f057258d7905898e87f..352a007e32db265cb7f08aa9ae094d92aa689715 100644 (file)
@@ -200,7 +200,7 @@ func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool {
        }
        // 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
index 3e86888ff63faf94e54b22a98cb5eaf9848e7ade..8737284ddbab82c2f5a1c55740f2e65a3cadf4de 100644 (file)
@@ -15,15 +15,14 @@ type nameOff = abi.NameOff
 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:]
@@ -31,11 +30,11 @@ func (t *_type) string() string {
        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 ""
        }
@@ -58,16 +57,16 @@ func (t *_type) name() string {
 // 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 ""
@@ -137,8 +136,8 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
        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 {
@@ -179,17 +178,17 @@ 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 {
@@ -440,8 +439,8 @@ type _typePair struct {
        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.
@@ -474,17 +473,18 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
        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
                }
@@ -498,11 +498,11 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
        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))