mirror of
https://github.com/autc04/Retro68.git
synced 2024-07-10 20:29:11 +00:00
754 lines
19 KiB
Go
754 lines
19 KiB
Go
// 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.
|
|
|
|
// Package reflectlite implements lightweight version of reflect, not using
|
|
// any package except for "runtime" and "unsafe".
|
|
package reflectlite
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// Type is the representation of a Go type.
|
|
//
|
|
// Not all methods apply to all kinds of types. Restrictions,
|
|
// if any, are noted in the documentation for each method.
|
|
// Use the Kind method to find out the kind of type before
|
|
// calling kind-specific methods. Calling a method
|
|
// inappropriate to the kind of type causes a run-time panic.
|
|
//
|
|
// Type values are comparable, such as with the == operator,
|
|
// so they can be used as map keys.
|
|
// Two Type values are equal if they represent identical types.
|
|
type Type interface {
|
|
// Methods applicable to all types.
|
|
|
|
// Name returns the type's name within its package for a defined type.
|
|
// For other (non-defined) types it returns the empty string.
|
|
Name() string
|
|
|
|
// PkgPath returns a defined type's package path, that is, the import path
|
|
// that uniquely identifies the package, such as "encoding/base64".
|
|
// If the type was predeclared (string, error) or not defined (*T, struct{},
|
|
// []int, or A where A is an alias for a non-defined type), the package path
|
|
// will be the empty string.
|
|
PkgPath() string
|
|
|
|
// Size returns the number of bytes needed to store
|
|
// a value of the given type; it is analogous to unsafe.Sizeof.
|
|
Size() uintptr
|
|
|
|
// Kind returns the specific kind of this type.
|
|
Kind() Kind
|
|
|
|
// Implements reports whether the type implements the interface type u.
|
|
Implements(u Type) bool
|
|
|
|
// AssignableTo reports whether a value of the type is assignable to type u.
|
|
AssignableTo(u Type) bool
|
|
|
|
// Comparable reports whether values of this type are comparable.
|
|
Comparable() bool
|
|
|
|
// String returns a string representation of the type.
|
|
// The string representation may use shortened package names
|
|
// (e.g., base64 instead of "encoding/base64") and is not
|
|
// guaranteed to be unique among types. To test for type identity,
|
|
// compare the Types directly.
|
|
String() string
|
|
|
|
// Elem returns a type's element type.
|
|
// It panics if the type's Kind is not Ptr.
|
|
Elem() Type
|
|
|
|
common() *rtype
|
|
uncommon() *uncommonType
|
|
}
|
|
|
|
/*
|
|
* These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
|
|
* A few are known to ../runtime/type.go to convey to debuggers.
|
|
* They are also known to ../runtime/type.go.
|
|
*/
|
|
|
|
// A Kind represents the specific kind of type that a Type represents.
|
|
// The zero Kind is not a valid kind.
|
|
type Kind uint
|
|
|
|
const (
|
|
Invalid Kind = iota
|
|
Bool
|
|
Int
|
|
Int8
|
|
Int16
|
|
Int32
|
|
Int64
|
|
Uint
|
|
Uint8
|
|
Uint16
|
|
Uint32
|
|
Uint64
|
|
Uintptr
|
|
Float32
|
|
Float64
|
|
Complex64
|
|
Complex128
|
|
Array
|
|
Chan
|
|
Func
|
|
Interface
|
|
Map
|
|
Pointer
|
|
Slice
|
|
String
|
|
Struct
|
|
UnsafePointer
|
|
)
|
|
|
|
const Ptr = Pointer
|
|
|
|
// tflag is used by an rtype to signal what extra type information is
|
|
// available in the memory directly following the rtype value.
|
|
//
|
|
// tflag values must be kept in sync with copies in:
|
|
// go/types.cc
|
|
// runtime/type.go
|
|
type tflag uint8
|
|
|
|
const (
|
|
// tflagRegularMemory means that equal and hash functions can treat
|
|
// this type as a single region of t.size bytes.
|
|
tflagRegularMemory tflag = 1 << 3
|
|
)
|
|
|
|
// rtype is the common implementation of most values.
|
|
// It is embedded in other struct types.
|
|
//
|
|
// rtype must be kept in sync with ../runtime/type.go:/^type._type.
|
|
type rtype struct {
|
|
size uintptr
|
|
ptrdata uintptr // number of bytes in the type that can contain pointers
|
|
hash uint32 // hash of type; avoids computation in hash tables
|
|
tflag tflag // extra type information flags
|
|
align uint8 // alignment of variable with this type
|
|
fieldAlign uint8 // alignment of struct field with this type
|
|
kind uint8 // enumeration for C
|
|
// function for comparing objects of this type
|
|
// (ptr to object A, ptr to object B) -> ==?
|
|
equal func(unsafe.Pointer, unsafe.Pointer) bool
|
|
gcdata *byte // garbage collection data
|
|
string *string // string form; unnecessary but undeniably useful
|
|
*uncommonType // (relatively) uncommon fields
|
|
ptrToThis *rtype // type for pointer to this type, may be zero
|
|
}
|
|
|
|
// Method on non-interface type
|
|
type method struct {
|
|
name *string // name of method
|
|
pkgPath *string // nil for exported Names; otherwise import path
|
|
mtyp *rtype // method type (without receiver)
|
|
typ *rtype // .(*FuncType) underneath (with receiver)
|
|
tfn unsafe.Pointer // fn used for normal method call
|
|
}
|
|
|
|
// uncommonType is present only for defined types or types with methods
|
|
// (if T is a defined type, the uncommonTypes for T and *T have methods).
|
|
// Using a pointer to this struct reduces the overall size required
|
|
// to describe a non-defined type with no methods.
|
|
type uncommonType struct {
|
|
name *string // name of type
|
|
pkgPath *string // import path; nil for built-in types like int, string
|
|
methods []method // methods associated with type
|
|
}
|
|
|
|
// chanDir represents a channel type's direction.
|
|
type chanDir int
|
|
|
|
const (
|
|
recvDir chanDir = 1 << iota // <-chan
|
|
sendDir // chan<-
|
|
bothDir = recvDir | sendDir // chan
|
|
)
|
|
|
|
// arrayType represents a fixed array type.
|
|
type arrayType struct {
|
|
rtype
|
|
elem *rtype // array element type
|
|
slice *rtype // slice type
|
|
len uintptr
|
|
}
|
|
|
|
// chanType represents a channel type.
|
|
type chanType struct {
|
|
rtype
|
|
elem *rtype // channel element type
|
|
dir uintptr // channel direction (chanDir)
|
|
}
|
|
|
|
// funcType represents a function type.
|
|
type funcType struct {
|
|
rtype
|
|
dotdotdot bool // last input parameter is ...
|
|
in []*rtype // input parameter types
|
|
out []*rtype // output parameter types
|
|
}
|
|
|
|
// imethod represents a method on an interface type
|
|
type imethod struct {
|
|
name *string // name of method
|
|
pkgPath *string // nil for exported Names; otherwise import path
|
|
typ *rtype // .(*FuncType) underneath
|
|
}
|
|
|
|
// interfaceType represents an interface type.
|
|
type interfaceType struct {
|
|
rtype
|
|
methods []imethod // sorted by hash
|
|
}
|
|
|
|
// mapType represents a map type.
|
|
type mapType struct {
|
|
rtype
|
|
key *rtype // map key type
|
|
elem *rtype // map element (value) type
|
|
bucket *rtype // internal bucket structure
|
|
keysize uint8 // size of key slot
|
|
valuesize uint8 // size of value slot
|
|
bucketsize uint16 // size of bucket
|
|
flags uint32
|
|
}
|
|
|
|
// ptrType represents a pointer type.
|
|
type ptrType struct {
|
|
rtype
|
|
elem *rtype // pointer element (pointed at) type
|
|
}
|
|
|
|
// sliceType represents a slice type.
|
|
type sliceType struct {
|
|
rtype
|
|
elem *rtype // slice element type
|
|
}
|
|
|
|
// Struct field
|
|
type structField struct {
|
|
name *string // name is always non-empty
|
|
pkgPath *string // nil for exported Names; otherwise import path
|
|
typ *rtype // type of field
|
|
tag *string // nil if no tag
|
|
offsetEmbed uintptr // byte offset of field<<1 | isAnonymous
|
|
}
|
|
|
|
func (f *structField) offset() uintptr {
|
|
return f.offsetEmbed >> 1
|
|
}
|
|
|
|
func (f *structField) embedded() bool {
|
|
return f.offsetEmbed&1 != 0
|
|
}
|
|
|
|
// structType represents a struct type.
|
|
type structType struct {
|
|
rtype
|
|
fields []structField // sorted by offset
|
|
}
|
|
|
|
/*
|
|
* The compiler knows the exact layout of all the data structures above.
|
|
* The compiler does not know about the data structures and methods below.
|
|
*/
|
|
|
|
const (
|
|
kindDirectIface = 1 << 5
|
|
kindGCProg = 1 << 6 // Type.gc points to GC program
|
|
kindMask = (1 << 5) - 1
|
|
)
|
|
|
|
// String returns the name of k.
|
|
func (k Kind) String() string {
|
|
if int(k) < len(kindNames) {
|
|
return kindNames[k]
|
|
}
|
|
return kindNames[0]
|
|
}
|
|
|
|
var kindNames = []string{
|
|
Invalid: "invalid",
|
|
Bool: "bool",
|
|
Int: "int",
|
|
Int8: "int8",
|
|
Int16: "int16",
|
|
Int32: "int32",
|
|
Int64: "int64",
|
|
Uint: "uint",
|
|
Uint8: "uint8",
|
|
Uint16: "uint16",
|
|
Uint32: "uint32",
|
|
Uint64: "uint64",
|
|
Uintptr: "uintptr",
|
|
Float32: "float32",
|
|
Float64: "float64",
|
|
Complex64: "complex64",
|
|
Complex128: "complex128",
|
|
Array: "array",
|
|
Chan: "chan",
|
|
Func: "func",
|
|
Interface: "interface",
|
|
Map: "map",
|
|
Ptr: "ptr",
|
|
Slice: "slice",
|
|
String: "string",
|
|
Struct: "struct",
|
|
UnsafePointer: "unsafe.Pointer",
|
|
}
|
|
|
|
func (t *uncommonType) exportedMethods() []method {
|
|
allm := t.methods
|
|
allExported := true
|
|
for _, m := range allm {
|
|
if m.pkgPath != nil {
|
|
allExported = false
|
|
break
|
|
}
|
|
}
|
|
var methods []method
|
|
if allExported {
|
|
methods = allm
|
|
} else {
|
|
methods = make([]method, 0, len(allm))
|
|
for _, m := range allm {
|
|
if m.pkgPath == nil {
|
|
methods = append(methods, m)
|
|
}
|
|
}
|
|
methods = methods[:len(methods):len(methods)]
|
|
}
|
|
|
|
return methods
|
|
}
|
|
|
|
func (t *uncommonType) uncommon() *uncommonType {
|
|
return t
|
|
}
|
|
|
|
func (t *uncommonType) PkgPath() string {
|
|
if t == nil || t.pkgPath == nil {
|
|
return ""
|
|
}
|
|
return *t.pkgPath
|
|
}
|
|
|
|
func (t *uncommonType) Name() string {
|
|
if t == nil || t.name == nil {
|
|
return ""
|
|
}
|
|
return *t.name
|
|
}
|
|
|
|
func (t *rtype) String() string {
|
|
// For gccgo, strip out quoted strings.
|
|
s := *t.string
|
|
var q bool
|
|
r := make([]byte, len(s))
|
|
j := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == '\t' {
|
|
q = !q
|
|
} else if !q {
|
|
r[j] = s[i]
|
|
j++
|
|
}
|
|
}
|
|
return string(r[:j])
|
|
}
|
|
|
|
func (t *rtype) Size() uintptr { return t.size }
|
|
|
|
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
|
|
|
|
func (t *rtype) pointers() bool { return t.ptrdata != 0 }
|
|
|
|
func (t *rtype) common() *rtype { return t }
|
|
|
|
func (t *rtype) exportedMethods() []method {
|
|
ut := t.uncommon()
|
|
if ut == nil {
|
|
return nil
|
|
}
|
|
return ut.exportedMethods()
|
|
}
|
|
|
|
func (t *rtype) NumMethod() int {
|
|
if t.Kind() == Interface {
|
|
tt := (*interfaceType)(unsafe.Pointer(t))
|
|
return tt.NumMethod()
|
|
}
|
|
return len(t.exportedMethods())
|
|
}
|
|
|
|
func (t *rtype) PkgPath() string {
|
|
return t.uncommonType.PkgPath()
|
|
}
|
|
|
|
func (t *rtype) hasName() bool {
|
|
return t.uncommonType != nil && t.uncommonType.name != nil
|
|
}
|
|
|
|
func (t *rtype) Name() string {
|
|
return t.uncommonType.Name()
|
|
}
|
|
|
|
func (t *rtype) chanDir() chanDir {
|
|
if t.Kind() != Chan {
|
|
panic("reflect: chanDir of non-chan type")
|
|
}
|
|
tt := (*chanType)(unsafe.Pointer(t))
|
|
return chanDir(tt.dir)
|
|
}
|
|
|
|
func (t *rtype) Elem() Type {
|
|
switch t.Kind() {
|
|
case Array:
|
|
tt := (*arrayType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Chan:
|
|
tt := (*chanType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Map:
|
|
tt := (*mapType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Ptr:
|
|
tt := (*ptrType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Slice:
|
|
tt := (*sliceType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
}
|
|
panic("reflect: Elem of invalid type")
|
|
}
|
|
|
|
func (t *rtype) In(i int) Type {
|
|
if t.Kind() != Func {
|
|
panic("reflect: In of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return toType(tt.in[i])
|
|
}
|
|
|
|
func (t *rtype) Key() Type {
|
|
if t.Kind() != Map {
|
|
panic("reflect: Key of non-map type")
|
|
}
|
|
tt := (*mapType)(unsafe.Pointer(t))
|
|
return toType(tt.key)
|
|
}
|
|
|
|
func (t *rtype) Len() int {
|
|
if t.Kind() != Array {
|
|
panic("reflect: Len of non-array type")
|
|
}
|
|
tt := (*arrayType)(unsafe.Pointer(t))
|
|
return int(tt.len)
|
|
}
|
|
|
|
func (t *rtype) NumField() int {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: NumField of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return len(tt.fields)
|
|
}
|
|
|
|
func (t *rtype) NumIn() int {
|
|
if t.Kind() != Func {
|
|
panic("reflect: NumIn of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return len(tt.in)
|
|
}
|
|
|
|
func (t *rtype) NumOut() int {
|
|
if t.Kind() != Func {
|
|
panic("reflect: NumOut of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return len(tt.out)
|
|
}
|
|
|
|
func (t *rtype) Out(i int) Type {
|
|
if t.Kind() != Func {
|
|
panic("reflect: Out of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return toType(tt.out[i])
|
|
}
|
|
|
|
// add returns p+x.
|
|
//
|
|
// The whySafe string is ignored, so that the function still inlines
|
|
// as efficiently as p+x, but all call sites should use the string to
|
|
// record why the addition is safe, which is to say why the addition
|
|
// does not cause x to advance to the very end of p's allocation
|
|
// and therefore point incorrectly at the next block in memory.
|
|
func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
|
|
return unsafe.Pointer(uintptr(p) + x)
|
|
}
|
|
|
|
// NumMethod returns the number of interface methods in the type's method set.
|
|
func (t *interfaceType) NumMethod() int { return len(t.methods) }
|
|
|
|
// TypeOf returns the reflection Type that represents the dynamic type of i.
|
|
// If i is a nil interface value, TypeOf returns nil.
|
|
func TypeOf(i any) Type {
|
|
eface := *(*emptyInterface)(unsafe.Pointer(&i))
|
|
return toType(eface.typ)
|
|
}
|
|
|
|
func (t *rtype) Implements(u Type) bool {
|
|
if u == nil {
|
|
panic("reflect: nil type passed to Type.Implements")
|
|
}
|
|
if u.Kind() != Interface {
|
|
panic("reflect: non-interface type passed to Type.Implements")
|
|
}
|
|
return implements(u.(*rtype), t)
|
|
}
|
|
|
|
func (t *rtype) AssignableTo(u Type) bool {
|
|
if u == nil {
|
|
panic("reflect: nil type passed to Type.AssignableTo")
|
|
}
|
|
uu := u.(*rtype)
|
|
return directlyAssignable(uu, t) || implements(uu, t)
|
|
}
|
|
|
|
func (t *rtype) Comparable() bool {
|
|
switch t.Kind() {
|
|
case Bool, Int, Int8, Int16, Int32, Int64,
|
|
Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
|
|
Float32, Float64, Complex64, Complex128,
|
|
Chan, Interface, Ptr, String, UnsafePointer:
|
|
return true
|
|
|
|
case Func, Map, Slice:
|
|
return false
|
|
|
|
case Array:
|
|
return (*arrayType)(unsafe.Pointer(t)).elem.Comparable()
|
|
|
|
case Struct:
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
for i := range tt.fields {
|
|
if !tt.fields[i].typ.Comparable() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
|
|
default:
|
|
panic("reflectlite: impossible")
|
|
}
|
|
}
|
|
|
|
// implements reports whether the type V implements the interface type T.
|
|
func implements(T, V *rtype) bool {
|
|
if T.Kind() != Interface {
|
|
return false
|
|
}
|
|
t := (*interfaceType)(unsafe.Pointer(T))
|
|
if len(t.methods) == 0 {
|
|
return true
|
|
}
|
|
|
|
// The same algorithm applies in both cases, but the
|
|
// method tables for an interface type and a concrete type
|
|
// are different, so the code is duplicated.
|
|
// In both cases the algorithm is a linear scan over the two
|
|
// lists - T's methods and V's methods - simultaneously.
|
|
// Since method tables are stored in a unique sorted order
|
|
// (alphabetical, with no duplicate method names), the scan
|
|
// through V's methods must hit a match for each of T's
|
|
// methods along the way, or else V does not implement T.
|
|
// This lets us run the scan in overall linear time instead of
|
|
// the quadratic time a naive search would require.
|
|
// See also ../runtime/iface.go.
|
|
if V.Kind() == Interface {
|
|
v := (*interfaceType)(unsafe.Pointer(V))
|
|
i := 0
|
|
for j := 0; j < len(v.methods); j++ {
|
|
tm := &t.methods[i]
|
|
vm := &v.methods[j]
|
|
if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.typ).common(), toType(tm.typ).common()) {
|
|
if i++; i >= len(t.methods) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
v := V.uncommon()
|
|
if v == nil {
|
|
return false
|
|
}
|
|
i := 0
|
|
for j := 0; j < len(v.methods); j++ {
|
|
tm := &t.methods[i]
|
|
vm := &v.methods[j]
|
|
if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.mtyp).common(), toType(tm.typ).common()) {
|
|
if i++; i >= len(t.methods) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// directlyAssignable reports whether a value x of type V can be directly
|
|
// assigned (using memmove) to a value of type T.
|
|
// https://golang.org/doc/go_spec.html#Assignability
|
|
// Ignoring the interface rules (implemented elsewhere)
|
|
// and the ideal constant rules (no ideal constants at run time).
|
|
func directlyAssignable(T, V *rtype) bool {
|
|
// x's type V is identical to T?
|
|
if rtypeEqual(T, V) {
|
|
return true
|
|
}
|
|
|
|
// Otherwise at least one of T and V must not be defined
|
|
// and they must have the same kind.
|
|
if T.hasName() && V.hasName() || T.Kind() != V.Kind() {
|
|
return false
|
|
}
|
|
|
|
// x's type T and V must have identical underlying types.
|
|
return haveIdenticalUnderlyingType(T, V, true)
|
|
}
|
|
|
|
func haveIdenticalType(T, V Type, cmpTags bool) bool {
|
|
if cmpTags {
|
|
return T == V
|
|
}
|
|
|
|
if T.Name() != V.Name() || T.Kind() != V.Kind() {
|
|
return false
|
|
}
|
|
|
|
return haveIdenticalUnderlyingType(T.common(), V.common(), false)
|
|
}
|
|
|
|
func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
|
|
if rtypeEqual(T, V) {
|
|
return true
|
|
}
|
|
|
|
kind := T.Kind()
|
|
if kind != V.Kind() {
|
|
return false
|
|
}
|
|
|
|
// Non-composite types of equal kind have same underlying type
|
|
// (the predefined instance of the type).
|
|
if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
|
|
return true
|
|
}
|
|
|
|
// Composite types.
|
|
switch kind {
|
|
case Array:
|
|
return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
|
|
|
case Chan:
|
|
// Special case:
|
|
// x is a bidirectional channel value, T is a channel type,
|
|
// and x's type V and T have identical element types.
|
|
if V.chanDir() == bothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
|
|
return true
|
|
}
|
|
|
|
// Otherwise continue test for identical underlying type.
|
|
return V.chanDir() == T.chanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
|
|
|
case Func:
|
|
t := (*funcType)(unsafe.Pointer(T))
|
|
v := (*funcType)(unsafe.Pointer(V))
|
|
if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
|
|
return false
|
|
}
|
|
for i, typ := range t.in {
|
|
if !haveIdenticalType(typ, v.in[i], cmpTags) {
|
|
return false
|
|
}
|
|
}
|
|
for i, typ := range t.out {
|
|
if !haveIdenticalType(typ, v.out[i], cmpTags) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
|
|
case Interface:
|
|
t := (*interfaceType)(unsafe.Pointer(T))
|
|
v := (*interfaceType)(unsafe.Pointer(V))
|
|
if len(t.methods) == 0 && len(v.methods) == 0 {
|
|
return true
|
|
}
|
|
// Might have the same methods but still
|
|
// need a run time conversion.
|
|
return false
|
|
|
|
case Map:
|
|
return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
|
|
|
case Ptr, Slice:
|
|
return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
|
|
|
|
case Struct:
|
|
t := (*structType)(unsafe.Pointer(T))
|
|
v := (*structType)(unsafe.Pointer(V))
|
|
if len(t.fields) != len(v.fields) {
|
|
return false
|
|
}
|
|
for i := range t.fields {
|
|
tf := &t.fields[i]
|
|
vf := &v.fields[i]
|
|
if tf.name != vf.name && (tf.name == nil || vf.name == nil || *tf.name != *vf.name) {
|
|
return false
|
|
}
|
|
if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) {
|
|
return false
|
|
}
|
|
if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
|
|
return false
|
|
}
|
|
if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
|
|
return false
|
|
}
|
|
if tf.offsetEmbed != vf.offsetEmbed {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// toType converts from a *rtype to a Type that can be returned
|
|
// to the client of package reflect. In gc, the only concern is that
|
|
// a nil *rtype must be replaced by a nil Type, but in gccgo this
|
|
// function takes care of ensuring that multiple *rtype for the same
|
|
// type are coalesced into a single Type.
|
|
func toType(t *rtype) Type {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
return t
|
|
}
|
|
|
|
// ifaceIndir reports whether t is stored indirectly in an interface value.
|
|
func ifaceIndir(t *rtype) bool {
|
|
return t.kind&kindDirectIface == 0
|
|
}
|