Example #1
0
// 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")
}
Example #2
0
// 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
}