From a2838ec5f20b56e94a18c873ab4b68397355e214 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 24 Apr 2023 15:45:33 -0400 Subject: [PATCH] runtime: redefine _type to abi.Type; add rtype for methods. Change-Id: I1c478b704d84811caa209006c657dda82d9c4cf9 Reviewed-on: https://go-review.googlesource.com/c/go/+/488435 Reviewed-by: Keith Randall Run-TryBot: David Chase TryBot-Result: Gopher Robot Reviewed-by: Keith Randall --- src/cmd/link/internal/ld/dwarf.go | 2 +- src/cmd/link/internal/ld/dwarf_test.go | 2 +- src/reflect/type.go | 3 +- src/runtime/alg.go | 12 +++--- src/runtime/cgocall.go | 4 +- src/runtime/cgocheck.go | 2 +- src/runtime/chan.go | 4 +- src/runtime/error.go | 10 ++--- src/runtime/heapdump.go | 9 +++-- src/runtime/iface.go | 17 ++++---- src/runtime/mbarrier.go | 2 +- src/runtime/mbitmap.go | 4 +- src/runtime/mfinal.go | 12 +++--- src/runtime/mprof.go | 2 +- src/runtime/panic.go | 2 +- src/runtime/plugin.go | 2 +- src/runtime/runtime1.go | 6 +-- src/runtime/syscall_windows.go | 2 +- src/runtime/type.go | 54 +++++++++++++------------- 19 files changed, 76 insertions(+), 75 deletions(-) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index b9383e28b9..238262cffe 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -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", diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index c8715922d8..15682dff3d 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -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, diff --git a/src/reflect/type.go b/src/reflect/type.go index d2fde0b3ae..b817e811aa 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -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 } diff --git a/src/runtime/alg.go b/src/runtime/alg.go index e40eb9b47b..4eda9d4e75 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -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. diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index e2e37284a2..04ab9faa3d 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -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: diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go index 1acf0f9233..2cfbdeebb5 100644 --- a/src/runtime/cgocheck.go +++ b/src/runtime/cgocheck.go @@ -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 diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 0a8578d435..98e0836670 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -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) diff --git a/src/runtime/error.go b/src/runtime/error.go index 9bad50d90b..3590ccd965 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -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: diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index d06ddfc0fe..6a042ea9cf 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -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('.') diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 67e98b08ce..34d223f7f1 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -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 { diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go index ed6df2d55e..4bcc170ef9 100644 --- a/src/runtime/mbarrier.go +++ b/src/runtime/mbarrier.go @@ -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 } diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index f8ce5fd006..76f9a4eb9f 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -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 { diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index e25c06bcf8..d302d7fd97 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -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) diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index dfaa369740..174ceb0a1f 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -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) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index cefab56902..751ad998c9 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -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 { diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go index d2ad1ed21c..690f85750b 100644 --- a/src/runtime/plugin.go +++ b/src/runtime/plugin.go @@ -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) diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 65bed433c3..0fa34ba088 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -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. diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 37f86d0d7f..352a007e32 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -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 diff --git a/src/runtime/type.go b/src/runtime/type.go index 3e86888ff6..8737284ddb 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -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)) -- 2.50.0