// 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") }
func (tm *LLVMTypeMap) Sizeof(typ types.Type) int64 { switch typ := typ.Underlying().(type) { case *types.Basic: switch typ.Kind() { case types.Int, types.Uint: return int64(tm.target.TypeAllocSize(tm.inttype)) case types.Uintptr, types.UnsafePointer: return int64(tm.target.PointerSize()) case types.String: return 2 * int64(tm.target.PointerSize()) } return types.DefaultSizeof(typ) case *types.Array: eltsize := tm.Sizeof(typ.Elem()) eltalign := tm.Alignof(typ.Elem()) var eltpad int64 if eltsize%eltalign != 0 { eltpad = eltalign - (eltsize % eltalign) } return (eltsize + eltpad) * typ.Len() case *types.Slice: return 3 * int64(tm.target.PointerSize()) case *types.Struct: n := typ.NumFields() if n == 0 { return 0 } fields := make([]*types.Var, n) for i := range fields { fields[i] = typ.Field(i) } offsets := tm.Offsetsof(fields) return offsets[n-1] + tm.Sizeof(fields[n-1].Type()) case *types.Interface: return int64((2 + typ.NumMethods()) * tm.target.PointerSize()) } return int64(tm.target.PointerSize()) }
// 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 }
// matchArgTypeInternal is the internal version of matchArgType. It carries a map // remembering what types are in progress so we don't recur when faced with recursive // types or mutually recursive types. func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool { // %v, %T accept any argument type. if t == anyType { return true } if typ == nil { // external call typ = f.pkg.types[arg].Type if typ == nil { return true // probably a type check problem } } // If the type implements fmt.Formatter, we have nothing to check. // But (see issue 6259) that's not easy to verify, so instead we see // if its method set contains a Format function. We could do better, // even now, but we don't need to be 100% accurate. Wait for 6259 to // be fixed instead. TODO. if f.hasMethod(typ, "Format") { return true } // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? if t&argString != 0 { if types.AssertableTo(errorType, typ) || types.AssertableTo(stringerType, typ) { return true } } typ = typ.Underlying() if inProgress[typ] { // We're already looking at this type. The call that started it will take care of it. return true } inProgress[typ] = true switch typ := typ.(type) { case *types.Signature: return t&argPointer != 0 case *types.Map: // Recur: map[int]int matches %d. return t&argPointer != 0 || (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)) case *types.Chan: return t&argPointer != 0 case *types.Array: // Same as slice. if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { return true // %s matches []byte } // Recur: []int matches %d. return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress) case *types.Slice: // Same as array. if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { return true // %s matches []byte } // Recur: []int matches %d. But watch out for // type T []T // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below. return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress) case *types.Pointer: // Ugly, but dealing with an edge case: a known pointer to an invalid type, // probably something from a failed import. if typ.Elem().String() == "invalid type" { if *verbose { f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg)) } return true // special case } // If it's actually a pointer with %p, it prints as one. if t == argPointer { return true } // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct. if str, ok := typ.Elem().Underlying().(*types.Struct); ok { return f.matchStructArgType(t, str, arg, inProgress) } // The rest can print with %p as pointers, or as integers with %x etc. return t&(argInt|argPointer) != 0 case *types.Struct: return f.matchStructArgType(t, typ, arg, inProgress) case *types.Interface: // If the static type of the argument is empty interface, there's little we can do. // Example: // func f(x interface{}) { fmt.Printf("%s", x) } // Whether x is valid for %s depends on the type of the argument to f. One day // we will be able to do better. For now, we assume that empty interface is OK // but non-empty interfaces, with Stringer and Error handled above, are errors. return typ.NumMethods() == 0 case *types.Basic: switch typ.Kind() { case types.UntypedBool, types.Bool: return t&argBool != 0 case types.UntypedInt, types.Int, types.Int8, types.Int16, types.Int32, types.Int64, types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr: return t&argInt != 0 case types.UntypedFloat, types.Float32, types.Float64: return t&argFloat != 0 case types.UntypedComplex, types.Complex64, types.Complex128: return t&argComplex != 0 case types.UntypedString, types.String: return t&argString != 0 case types.UnsafePointer: return t&(argPointer|argInt) != 0 case types.UntypedRune: return t&(argInt|argRune) != 0 case types.UntypedNil: return t&argPointer != 0 // TODO? case types.Invalid: if *verbose { f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg)) } return true // Probably a type check problem. } panic("unreachable") } return false }
func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) { switch typ := typ.(type) { case *types.Basic: s := typ.Name() switch typ.Kind() { case types.UnsafePointer: s = "unsafe.Pointer" case types.UntypedBool: s = "ideal-bool" case types.UntypedInt: s = "ideal-int" case types.UntypedRune: // "ideal-char" for compatibility with old tool // TODO(gri) change to "ideal-rune" s = "ideal-char" case types.UntypedFloat: s = "ideal-float" case types.UntypedComplex: s = "ideal-complex" case types.UntypedString: s = "ideal-string" case types.UntypedNil: panic("should never see untyped nil type") default: switch s { case "byte": s = "uint8" case "rune": s = "int32" } } buf.WriteString(s) case *types.Array: fmt.Fprintf(buf, "[%d]", typ.Len()) w.writeType(buf, typ.Elem()) case *types.Slice: buf.WriteString("[]") w.writeType(buf, typ.Elem()) case *types.Struct: buf.WriteString("struct") case *types.Pointer: buf.WriteByte('*') w.writeType(buf, typ.Elem()) case *types.Tuple: panic("should never see a tuple type") case *types.Signature: buf.WriteString("func") w.writeSignature(buf, typ) case *types.Interface: buf.WriteString("interface{") if typ.NumMethods() > 0 { buf.WriteByte(' ') buf.WriteString(strings.Join(sortedMethodNames(typ), ", ")) buf.WriteByte(' ') } buf.WriteString("}") case *types.Map: buf.WriteString("map[") w.writeType(buf, typ.Key()) buf.WriteByte(']') w.writeType(buf, typ.Elem()) case *types.Chan: var s string switch typ.Dir() { case ast.SEND: s = "chan<- " case ast.RECV: s = "<-chan " default: s = "chan " } buf.WriteString(s) w.writeType(buf, typ.Elem()) case *types.Named: obj := typ.Obj() pkg := obj.Pkg() if pkg != nil && pkg != w.current { buf.WriteString(pkg.Name()) buf.WriteByte('.') } buf.WriteString(typ.Obj().Name()) default: panic(fmt.Sprintf("unknown type %T", typ)) } }