// hashFor computes the hash of t. func (h Hasher) hashFor(t types.Type) uint32 { // See IsIdentical for rationale. switch t := t.(type) { case *types.Basic: return uint32(t.Kind()) case *types.Array: return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) case *types.Slice: return 9049 + 2*h.Hash(t.Elem()) case *types.Struct: var hash uint32 = 9059 for i, n := 0, t.NumFields(); i < n; i++ { f := t.Field(i) if f.Anonymous() { hash += 8861 } hash += hashString(t.Tag(i)) hash += hashString(f.Name()) // (ignore f.Pkg) hash += h.Hash(f.Type()) } return hash case *types.Pointer: return 9067 + 2*h.Hash(t.Elem()) case *types.Signature: var hash uint32 = 9091 if t.IsVariadic() { hash *= 8863 } return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) case *types.Interface: var hash uint32 = 9103 for i, n := 0, t.NumMethods(); i < n; i++ { // See go/types.identicalMethods for rationale. // Method order is not significant. // Ignore m.Pkg(). m := t.Method(i) hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) } return hash case *types.Map: return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) case *types.Chan: return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) case *types.Named: // Not safe with a copying GC; objects may move. return uint32(uintptr(unsafe.Pointer(t.Obj()))) } panic("unexpected type") }
// methods constructs and returns the method set for // a named type or unnamed struct type. func (c *compiler) methods(t types.Type) *methodset { if m, ok := c.methodsets[t]; ok { return m } methods := new(methodset) c.methodsets[t] = methods switch t := t.(type) { case *types.Named: for i := 0; i < t.NumMethods(); i++ { f := c.methodfunc(t.Method(i)) if f.Type().(*types.Signature).Recv().Type() == t { methods.nonptr = append(methods.nonptr, f) f := c.promoteMethod(f, types.NewPointer(t), []int{-1}) methods.ptr = append(methods.ptr, f) } else { methods.ptr = append(methods.ptr, f) } } case *types.Struct: // No-op, handled in loop below. default: panic(fmt.Errorf("non Named/Struct: %#v", t)) } // Traverse embedded types, build forwarding methods if // original type is in the main package (otherwise just // declaring them). var curr []selectorCandidate if typ, ok := t.Underlying().Deref().(*types.Struct); ok { curr = append(curr, selectorCandidate{nil, typ}) } for len(curr) > 0 { var next []selectorCandidate for _, candidate := range curr { typ := candidate.Type var isptr bool if ptr, ok := typ.(*types.Pointer); ok { isptr = true typ = ptr.Elem() } if named, ok := typ.(*types.Named); ok { named.ForEachMethod(func(m *types.Func) { m = c.methodfunc(m) if methods.lookup(m.Name(), true) != nil { return } sig := m.Type().(*types.Signature) indices := candidate.Indices[:] if isptr || sig.Recv().Type() == named { indices = append(indices, -1) if isptr && sig.Recv().Type() == named { indices = append(indices, -1) } f := c.promoteMethod(m, t, indices) methods.nonptr = append(methods.nonptr, f) f = c.promoteMethod(m, types.NewPointer(t), indices) methods.ptr = append(methods.ptr, f) } else { // The method set of *S also includes // promoted methods with receiver *T. f := c.promoteMethod(m, types.NewPointer(t), indices) methods.ptr = append(methods.ptr, f) } }) typ = named.Underlying() } switch typ := typ.(type) { case *types.Interface: for i := 0; i < typ.NumMethods(); i++ { m := typ.Method(i) if methods.lookup(m.Name(), true) == nil { indices := candidate.Indices[:] indices = append(indices, -1) // always load f := c.promoteInterfaceMethod(typ, i, t, indices) methods.nonptr = append(methods.nonptr, f) f = c.promoteInterfaceMethod(typ, i, types.NewPointer(t), indices) methods.ptr = append(methods.ptr, f) } } case *types.Struct: indices := candidate.Indices[:] if isptr { indices = append(indices, -1) } for i := 0; i < typ.NumFields(); i++ { field := typ.Field(i) if field.IsAnonymous { indices := append(indices[:], i) ftype := field.Type candidate := selectorCandidate{indices, ftype} next = append(next, candidate) } } } } curr = next } return methods }