Source file src/runtime/type.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Runtime type representation.
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/abi"
    11  	"unsafe"
    12  )
    13  
    14  // tflag is documented in reflect/type.go.
    15  //
    16  // tflag values must be kept in sync with copies in:
    17  //
    18  //	cmd/compile/internal/reflectdata/reflect.go
    19  //	cmd/link/internal/ld/decodesym.go
    20  //	reflect/type.go
    21  //	internal/reflectlite/type.go
    22  type tflag uint8
    23  
    24  const (
    25  	tflagUncommon      tflag = 1 << 0
    26  	tflagExtraStar     tflag = 1 << 1
    27  	tflagNamed         tflag = 1 << 2
    28  	tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
    29  )
    30  
    31  // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
    32  // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
    33  // ../reflect/type.go:/^type.rtype.
    34  // ../internal/reflectlite/type.go:/^type.rtype.
    35  type _type struct {
    36  	size       uintptr
    37  	ptrdata    uintptr // size of memory prefix holding all pointers
    38  	hash       uint32
    39  	tflag      tflag
    40  	align      uint8
    41  	fieldAlign uint8
    42  	kind       uint8
    43  	// function for comparing objects of this type
    44  	// (ptr to object A, ptr to object B) -> ==?
    45  	equal func(unsafe.Pointer, unsafe.Pointer) bool
    46  	// gcdata stores the GC type data for the garbage collector.
    47  	// If the KindGCProg bit is set in kind, gcdata is a GC program.
    48  	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
    49  	gcdata    *byte
    50  	str       nameOff
    51  	ptrToThis typeOff
    52  }
    53  
    54  func (t *_type) string() string {
    55  	s := t.nameOff(t.str).name()
    56  	if t.tflag&tflagExtraStar != 0 {
    57  		return s[1:]
    58  	}
    59  	return s
    60  }
    61  
    62  func (t *_type) uncommon() *uncommontype {
    63  	if t.tflag&tflagUncommon == 0 {
    64  		return nil
    65  	}
    66  	switch t.kind & kindMask {
    67  	case kindStruct:
    68  		type u struct {
    69  			structtype
    70  			u uncommontype
    71  		}
    72  		return &(*u)(unsafe.Pointer(t)).u
    73  	case kindPtr:
    74  		type u struct {
    75  			ptrtype
    76  			u uncommontype
    77  		}
    78  		return &(*u)(unsafe.Pointer(t)).u
    79  	case kindFunc:
    80  		type u struct {
    81  			functype
    82  			u uncommontype
    83  		}
    84  		return &(*u)(unsafe.Pointer(t)).u
    85  	case kindSlice:
    86  		type u struct {
    87  			slicetype
    88  			u uncommontype
    89  		}
    90  		return &(*u)(unsafe.Pointer(t)).u
    91  	case kindArray:
    92  		type u struct {
    93  			arraytype
    94  			u uncommontype
    95  		}
    96  		return &(*u)(unsafe.Pointer(t)).u
    97  	case kindChan:
    98  		type u struct {
    99  			chantype
   100  			u uncommontype
   101  		}
   102  		return &(*u)(unsafe.Pointer(t)).u
   103  	case kindMap:
   104  		type u struct {
   105  			maptype
   106  			u uncommontype
   107  		}
   108  		return &(*u)(unsafe.Pointer(t)).u
   109  	case kindInterface:
   110  		type u struct {
   111  			interfacetype
   112  			u uncommontype
   113  		}
   114  		return &(*u)(unsafe.Pointer(t)).u
   115  	default:
   116  		type u struct {
   117  			_type
   118  			u uncommontype
   119  		}
   120  		return &(*u)(unsafe.Pointer(t)).u
   121  	}
   122  }
   123  
   124  func (t *_type) name() string {
   125  	if t.tflag&tflagNamed == 0 {
   126  		return ""
   127  	}
   128  	s := t.string()
   129  	i := len(s) - 1
   130  	sqBrackets := 0
   131  	for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
   132  		switch s[i] {
   133  		case ']':
   134  			sqBrackets++
   135  		case '[':
   136  			sqBrackets--
   137  		}
   138  		i--
   139  	}
   140  	return s[i+1:]
   141  }
   142  
   143  // pkgpath returns the path of the package where t was defined, if
   144  // available. This is not the same as the reflect package's PkgPath
   145  // method, in that it returns the package path for struct and interface
   146  // types, not just named types.
   147  func (t *_type) pkgpath() string {
   148  	if u := t.uncommon(); u != nil {
   149  		return t.nameOff(u.pkgpath).name()
   150  	}
   151  	switch t.kind & kindMask {
   152  	case kindStruct:
   153  		st := (*structtype)(unsafe.Pointer(t))
   154  		return st.pkgPath.name()
   155  	case kindInterface:
   156  		it := (*interfacetype)(unsafe.Pointer(t))
   157  		return it.pkgpath.name()
   158  	}
   159  	return ""
   160  }
   161  
   162  // reflectOffs holds type offsets defined at run time by the reflect package.
   163  //
   164  // When a type is defined at run time, its *rtype data lives on the heap.
   165  // There are a wide range of possible addresses the heap may use, that
   166  // may not be representable as a 32-bit offset. Moreover the GC may
   167  // one day start moving heap memory, in which case there is no stable
   168  // offset that can be defined.
   169  //
   170  // To provide stable offsets, we add pin *rtype objects in a global map
   171  // and treat the offset as an identifier. We use negative offsets that
   172  // do not overlap with any compile-time module offsets.
   173  //
   174  // Entries are created by reflect.addReflectOff.
   175  var reflectOffs struct {
   176  	lock mutex
   177  	next int32
   178  	m    map[int32]unsafe.Pointer
   179  	minv map[unsafe.Pointer]int32
   180  }
   181  
   182  func reflectOffsLock() {
   183  	lock(&reflectOffs.lock)
   184  	if raceenabled {
   185  		raceacquire(unsafe.Pointer(&reflectOffs.lock))
   186  	}
   187  }
   188  
   189  func reflectOffsUnlock() {
   190  	if raceenabled {
   191  		racerelease(unsafe.Pointer(&reflectOffs.lock))
   192  	}
   193  	unlock(&reflectOffs.lock)
   194  }
   195  
   196  func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
   197  	if off == 0 {
   198  		return name{}
   199  	}
   200  	base := uintptr(ptrInModule)
   201  	for md := &firstmoduledata; md != nil; md = md.next {
   202  		if base >= md.types && base < md.etypes {
   203  			res := md.types + uintptr(off)
   204  			if res > md.etypes {
   205  				println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
   206  				throw("runtime: name offset out of range")
   207  			}
   208  			return name{(*byte)(unsafe.Pointer(res))}
   209  		}
   210  	}
   211  
   212  	// No module found. see if it is a run time name.
   213  	reflectOffsLock()
   214  	res, found := reflectOffs.m[int32(off)]
   215  	reflectOffsUnlock()
   216  	if !found {
   217  		println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
   218  		for next := &firstmoduledata; next != nil; next = next.next {
   219  			println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
   220  		}
   221  		throw("runtime: name offset base pointer out of range")
   222  	}
   223  	return name{(*byte)(res)}
   224  }
   225  
   226  func (t *_type) nameOff(off nameOff) name {
   227  	return resolveNameOff(unsafe.Pointer(t), off)
   228  }
   229  
   230  func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
   231  	if off == 0 || off == -1 {
   232  		// -1 is the sentinel value for unreachable code.
   233  		// See cmd/link/internal/ld/data.go:relocsym.
   234  		return nil
   235  	}
   236  	base := uintptr(ptrInModule)
   237  	var md *moduledata
   238  	for next := &firstmoduledata; next != nil; next = next.next {
   239  		if base >= next.types && base < next.etypes {
   240  			md = next
   241  			break
   242  		}
   243  	}
   244  	if md == nil {
   245  		reflectOffsLock()
   246  		res := reflectOffs.m[int32(off)]
   247  		reflectOffsUnlock()
   248  		if res == nil {
   249  			println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
   250  			for next := &firstmoduledata; next != nil; next = next.next {
   251  				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
   252  			}
   253  			throw("runtime: type offset base pointer out of range")
   254  		}
   255  		return (*_type)(res)
   256  	}
   257  	if t := md.typemap[off]; t != nil {
   258  		return t
   259  	}
   260  	res := md.types + uintptr(off)
   261  	if res > md.etypes {
   262  		println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
   263  		throw("runtime: type offset out of range")
   264  	}
   265  	return (*_type)(unsafe.Pointer(res))
   266  }
   267  
   268  func (t *_type) typeOff(off typeOff) *_type {
   269  	return resolveTypeOff(unsafe.Pointer(t), off)
   270  }
   271  
   272  func (t *_type) textOff(off textOff) unsafe.Pointer {
   273  	if off == -1 {
   274  		// -1 is the sentinel value for unreachable code.
   275  		// See cmd/link/internal/ld/data.go:relocsym.
   276  		return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
   277  	}
   278  	base := uintptr(unsafe.Pointer(t))
   279  	var md *moduledata
   280  	for next := &firstmoduledata; next != nil; next = next.next {
   281  		if base >= next.types && base < next.etypes {
   282  			md = next
   283  			break
   284  		}
   285  	}
   286  	if md == nil {
   287  		reflectOffsLock()
   288  		res := reflectOffs.m[int32(off)]
   289  		reflectOffsUnlock()
   290  		if res == nil {
   291  			println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
   292  			for next := &firstmoduledata; next != nil; next = next.next {
   293  				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
   294  			}
   295  			throw("runtime: text offset base pointer out of range")
   296  		}
   297  		return res
   298  	}
   299  	res := md.textAddr(uint32(off))
   300  	return unsafe.Pointer(res)
   301  }
   302  
   303  func (t *functype) in() []*_type {
   304  	// See funcType in reflect/type.go for details on data layout.
   305  	uadd := uintptr(unsafe.Sizeof(functype{}))
   306  	if t.typ.tflag&tflagUncommon != 0 {
   307  		uadd += unsafe.Sizeof(uncommontype{})
   308  	}
   309  	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
   310  }
   311  
   312  func (t *functype) out() []*_type {
   313  	// See funcType in reflect/type.go for details on data layout.
   314  	uadd := uintptr(unsafe.Sizeof(functype{}))
   315  	if t.typ.tflag&tflagUncommon != 0 {
   316  		uadd += unsafe.Sizeof(uncommontype{})
   317  	}
   318  	outCount := t.outCount & (1<<15 - 1)
   319  	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
   320  }
   321  
   322  func (t *functype) dotdotdot() bool {
   323  	return t.outCount&(1<<15) != 0
   324  }
   325  
   326  type nameOff int32
   327  type typeOff int32
   328  type textOff int32
   329  
   330  type method struct {
   331  	name nameOff
   332  	mtyp typeOff
   333  	ifn  textOff
   334  	tfn  textOff
   335  }
   336  
   337  type uncommontype struct {
   338  	pkgpath nameOff
   339  	mcount  uint16 // number of methods
   340  	xcount  uint16 // number of exported methods
   341  	moff    uint32 // offset from this uncommontype to [mcount]method
   342  	_       uint32 // unused
   343  }
   344  
   345  type imethod struct {
   346  	name nameOff
   347  	ityp typeOff
   348  }
   349  
   350  type interfacetype struct {
   351  	typ     _type
   352  	pkgpath name
   353  	mhdr    []imethod
   354  }
   355  
   356  type maptype struct {
   357  	typ    _type
   358  	key    *_type
   359  	elem   *_type
   360  	bucket *_type // internal type representing a hash bucket
   361  	// function for hashing keys (ptr to key, seed) -> hash
   362  	hasher     func(unsafe.Pointer, uintptr) uintptr
   363  	keysize    uint8  // size of key slot
   364  	elemsize   uint8  // size of elem slot
   365  	bucketsize uint16 // size of bucket
   366  	flags      uint32
   367  }
   368  
   369  // Note: flag values must match those used in the TMAP case
   370  // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
   371  func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
   372  	return mt.flags&1 != 0
   373  }
   374  func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself
   375  	return mt.flags&2 != 0
   376  }
   377  func (mt *maptype) reflexivekey() bool { // true if k==k for all keys
   378  	return mt.flags&4 != 0
   379  }
   380  func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite
   381  	return mt.flags&8 != 0
   382  }
   383  func (mt *maptype) hashMightPanic() bool { // true if hash function might panic
   384  	return mt.flags&16 != 0
   385  }
   386  
   387  type arraytype struct {
   388  	typ   _type
   389  	elem  *_type
   390  	slice *_type
   391  	len   uintptr
   392  }
   393  
   394  type chantype struct {
   395  	typ  _type
   396  	elem *_type
   397  	dir  uintptr
   398  }
   399  
   400  type slicetype struct {
   401  	typ  _type
   402  	elem *_type
   403  }
   404  
   405  type functype struct {
   406  	typ      _type
   407  	inCount  uint16
   408  	outCount uint16
   409  }
   410  
   411  type ptrtype struct {
   412  	typ  _type
   413  	elem *_type
   414  }
   415  
   416  type structfield struct {
   417  	name   name
   418  	typ    *_type
   419  	offset uintptr
   420  }
   421  
   422  type structtype struct {
   423  	typ     _type
   424  	pkgPath name
   425  	fields  []structfield
   426  }
   427  
   428  // name is an encoded type name with optional extra data.
   429  // See reflect/type.go for details.
   430  type name struct {
   431  	bytes *byte
   432  }
   433  
   434  func (n name) data(off int) *byte {
   435  	return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
   436  }
   437  
   438  func (n name) isExported() bool {
   439  	return (*n.bytes)&(1<<0) != 0
   440  }
   441  
   442  func (n name) isEmbedded() bool {
   443  	return (*n.bytes)&(1<<3) != 0
   444  }
   445  
   446  func (n name) readvarint(off int) (int, int) {
   447  	v := 0
   448  	for i := 0; ; i++ {
   449  		x := *n.data(off + i)
   450  		v += int(x&0x7f) << (7 * i)
   451  		if x&0x80 == 0 {
   452  			return i + 1, v
   453  		}
   454  	}
   455  }
   456  
   457  func (n name) name() (s string) {
   458  	if n.bytes == nil {
   459  		return ""
   460  	}
   461  	i, l := n.readvarint(1)
   462  	if l == 0 {
   463  		return ""
   464  	}
   465  	hdr := (*stringStruct)(unsafe.Pointer(&s))
   466  	hdr.str = unsafe.Pointer(n.data(1 + i))
   467  	hdr.len = l
   468  	return
   469  }
   470  
   471  func (n name) tag() (s string) {
   472  	if *n.data(0)&(1<<1) == 0 {
   473  		return ""
   474  	}
   475  	i, l := n.readvarint(1)
   476  	i2, l2 := n.readvarint(1 + i + l)
   477  	hdr := (*stringStruct)(unsafe.Pointer(&s))
   478  	hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
   479  	hdr.len = l2
   480  	return
   481  }
   482  
   483  func (n name) pkgPath() string {
   484  	if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
   485  		return ""
   486  	}
   487  	i, l := n.readvarint(1)
   488  	off := 1 + i + l
   489  	if *n.data(0)&(1<<1) != 0 {
   490  		i2, l2 := n.readvarint(off)
   491  		off += i2 + l2
   492  	}
   493  	var nameOff nameOff
   494  	copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
   495  	pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
   496  	return pkgPathName.name()
   497  }
   498  
   499  func (n name) isBlank() bool {
   500  	if n.bytes == nil {
   501  		return false
   502  	}
   503  	_, l := n.readvarint(1)
   504  	return l == 1 && *n.data(2) == '_'
   505  }
   506  
   507  // typelinksinit scans the types from extra modules and builds the
   508  // moduledata typemap used to de-duplicate type pointers.
   509  func typelinksinit() {
   510  	if firstmoduledata.next == nil {
   511  		return
   512  	}
   513  	typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
   514  
   515  	modules := activeModules()
   516  	prev := modules[0]
   517  	for _, md := range modules[1:] {
   518  		// Collect types from the previous module into typehash.
   519  	collect:
   520  		for _, tl := range prev.typelinks {
   521  			var t *_type
   522  			if prev.typemap == nil {
   523  				t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
   524  			} else {
   525  				t = prev.typemap[typeOff(tl)]
   526  			}
   527  			// Add to typehash if not seen before.
   528  			tlist := typehash[t.hash]
   529  			for _, tcur := range tlist {
   530  				if tcur == t {
   531  					continue collect
   532  				}
   533  			}
   534  			typehash[t.hash] = append(tlist, t)
   535  		}
   536  
   537  		if md.typemap == nil {
   538  			// If any of this module's typelinks match a type from a
   539  			// prior module, prefer that prior type by adding the offset
   540  			// to this module's typemap.
   541  			tm := make(map[typeOff]*_type, len(md.typelinks))
   542  			pinnedTypemaps = append(pinnedTypemaps, tm)
   543  			md.typemap = tm
   544  			for _, tl := range md.typelinks {
   545  				t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
   546  				for _, candidate := range typehash[t.hash] {
   547  					seen := map[_typePair]struct{}{}
   548  					if typesEqual(t, candidate, seen) {
   549  						t = candidate
   550  						break
   551  					}
   552  				}
   553  				md.typemap[typeOff(tl)] = t
   554  			}
   555  		}
   556  
   557  		prev = md
   558  	}
   559  }
   560  
   561  type _typePair struct {
   562  	t1 *_type
   563  	t2 *_type
   564  }
   565  
   566  // typesEqual reports whether two types are equal.
   567  //
   568  // Everywhere in the runtime and reflect packages, it is assumed that
   569  // there is exactly one *_type per Go type, so that pointer equality
   570  // can be used to test if types are equal. There is one place that
   571  // breaks this assumption: buildmode=shared. In this case a type can
   572  // appear as two different pieces of memory. This is hidden from the
   573  // runtime and reflect package by the per-module typemap built in
   574  // typelinksinit. It uses typesEqual to map types from later modules
   575  // back into earlier ones.
   576  //
   577  // Only typelinksinit needs this function.
   578  func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
   579  	tp := _typePair{t, v}
   580  	if _, ok := seen[tp]; ok {
   581  		return true
   582  	}
   583  
   584  	// mark these types as seen, and thus equivalent which prevents an infinite loop if
   585  	// the two types are identical, but recursively defined and loaded from
   586  	// different modules
   587  	seen[tp] = struct{}{}
   588  
   589  	if t == v {
   590  		return true
   591  	}
   592  	kind := t.kind & kindMask
   593  	if kind != v.kind&kindMask {
   594  		return false
   595  	}
   596  	if t.string() != v.string() {
   597  		return false
   598  	}
   599  	ut := t.uncommon()
   600  	uv := v.uncommon()
   601  	if ut != nil || uv != nil {
   602  		if ut == nil || uv == nil {
   603  			return false
   604  		}
   605  		pkgpatht := t.nameOff(ut.pkgpath).name()
   606  		pkgpathv := v.nameOff(uv.pkgpath).name()
   607  		if pkgpatht != pkgpathv {
   608  			return false
   609  		}
   610  	}
   611  	if kindBool <= kind && kind <= kindComplex128 {
   612  		return true
   613  	}
   614  	switch kind {
   615  	case kindString, kindUnsafePointer:
   616  		return true
   617  	case kindArray:
   618  		at := (*arraytype)(unsafe.Pointer(t))
   619  		av := (*arraytype)(unsafe.Pointer(v))
   620  		return typesEqual(at.elem, av.elem, seen) && at.len == av.len
   621  	case kindChan:
   622  		ct := (*chantype)(unsafe.Pointer(t))
   623  		cv := (*chantype)(unsafe.Pointer(v))
   624  		return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
   625  	case kindFunc:
   626  		ft := (*functype)(unsafe.Pointer(t))
   627  		fv := (*functype)(unsafe.Pointer(v))
   628  		if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
   629  			return false
   630  		}
   631  		tin, vin := ft.in(), fv.in()
   632  		for i := 0; i < len(tin); i++ {
   633  			if !typesEqual(tin[i], vin[i], seen) {
   634  				return false
   635  			}
   636  		}
   637  		tout, vout := ft.out(), fv.out()
   638  		for i := 0; i < len(tout); i++ {
   639  			if !typesEqual(tout[i], vout[i], seen) {
   640  				return false
   641  			}
   642  		}
   643  		return true
   644  	case kindInterface:
   645  		it := (*interfacetype)(unsafe.Pointer(t))
   646  		iv := (*interfacetype)(unsafe.Pointer(v))
   647  		if it.pkgpath.name() != iv.pkgpath.name() {
   648  			return false
   649  		}
   650  		if len(it.mhdr) != len(iv.mhdr) {
   651  			return false
   652  		}
   653  		for i := range it.mhdr {
   654  			tm := &it.mhdr[i]
   655  			vm := &iv.mhdr[i]
   656  			// Note the mhdr array can be relocated from
   657  			// another module. See #17724.
   658  			tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
   659  			vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
   660  			if tname.name() != vname.name() {
   661  				return false
   662  			}
   663  			if tname.pkgPath() != vname.pkgPath() {
   664  				return false
   665  			}
   666  			tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
   667  			vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
   668  			if !typesEqual(tityp, vityp, seen) {
   669  				return false
   670  			}
   671  		}
   672  		return true
   673  	case kindMap:
   674  		mt := (*maptype)(unsafe.Pointer(t))
   675  		mv := (*maptype)(unsafe.Pointer(v))
   676  		return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
   677  	case kindPtr:
   678  		pt := (*ptrtype)(unsafe.Pointer(t))
   679  		pv := (*ptrtype)(unsafe.Pointer(v))
   680  		return typesEqual(pt.elem, pv.elem, seen)
   681  	case kindSlice:
   682  		st := (*slicetype)(unsafe.Pointer(t))
   683  		sv := (*slicetype)(unsafe.Pointer(v))
   684  		return typesEqual(st.elem, sv.elem, seen)
   685  	case kindStruct:
   686  		st := (*structtype)(unsafe.Pointer(t))
   687  		sv := (*structtype)(unsafe.Pointer(v))
   688  		if len(st.fields) != len(sv.fields) {
   689  			return false
   690  		}
   691  		if st.pkgPath.name() != sv.pkgPath.name() {
   692  			return false
   693  		}
   694  		for i := range st.fields {
   695  			tf := &st.fields[i]
   696  			vf := &sv.fields[i]
   697  			if tf.name.name() != vf.name.name() {
   698  				return false
   699  			}
   700  			if !typesEqual(tf.typ, vf.typ, seen) {
   701  				return false
   702  			}
   703  			if tf.name.tag() != vf.name.tag() {
   704  				return false
   705  			}
   706  			if tf.offset != vf.offset {
   707  				return false
   708  			}
   709  			if tf.name.isEmbedded() != vf.name.isEmbedded() {
   710  				return false
   711  			}
   712  		}
   713  		return true
   714  	default:
   715  		println("runtime: impossible type kind", kind)
   716  		throw("runtime: impossible type kind")
   717  		return false
   718  	}
   719  }
   720  

View as plain text