func assignable(t, u types.Type) bool { if t == nil || u == nil { return false } if t, ok := t.(*types.Basic); ok && t.Info&types.IsUntyped != 0 { // TODO: consider representability of const values switch u := underlying(u).(type) { case *types.Interface: return u.Empty() case *types.Basic: int := t.Info&types.IsInteger != 0 float := t.Info&types.IsFloat != 0 complex := t.Info&types.IsComplex != 0 switch { case u.Info&types.IsBoolean != 0: return t.Info&types.IsBoolean != 0 case u.Info&types.IsInteger != 0: return int case u.Info&types.IsFloat != 0: return int || float case u.Info&types.IsComplex != 0: return int || float || complex case u.Info&types.IsString != 0: return t.Info&types.IsString != 0 } } return false } return types.IsAssignableTo(t, u) }
// TODO: use the version from ssa or go/types func intuitiveMethodSet(T types.Type) []*types.Selection { var result []*types.Selection mset := types.NewMethodSet(T) if _, ok := T.Underlying().(*types.Interface); ok { for i, n := 0, mset.Len(); i < n; i++ { result = append(result, mset.At(i)) } } else { pmset := types.NewMethodSet(types.NewPointer(T)) for i, n := 0, pmset.Len(); i < n; i++ { meth := pmset.At(i) if m := mset.Lookup(meth.Obj.GetPkg(), meth.Obj.GetName()); m != nil { meth = m } result = append(result, meth) } } return result }
// 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.GetName()) // (ignore f.Pkg) hash += h.Hash(f.GetType()) } 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.GetPkg(). m := t.Method(i) hash += 3*hashString(m.GetName()) + 5*h.Hash(m.GetType()) } 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))) case *types.Tuple: return h.hashTuple(t) } panic(t) }