Exemple #1
0
func encodeType(t types.Type) Type {
	t = t.Underlying()
	switch t.(type) {
	case *types.Basic:
		b := t.(*types.Basic)
		untyped := (b.Info() & types.IsUntyped) != 0
		return NewBasic(basicKindString(b), untyped)
	case *types.Pointer:
		p := t.(*types.Pointer)
		pt := encodeType(p.Elem())
		return NewPointer(pt)
	case *types.Array:
		a := t.(*types.Array)
		at := encodeType(a.Elem())
		return NewArray(at, a.Len())
	case *types.Slice:
		s := t.(*types.Slice)
		st := encodeType(s.Elem())
		return NewSlice(st)
	case *types.Signature:
		sig := t.(*types.Signature)
		v := sig.Recv()
		var vt *Type
		if v != nil {
			t := encodeType(v.Type())
			vt = &t
		}
		return NewSignature(
			sig.Variadic(),
			vt,
			tupleToSlice(sig.Params()),
			tupleToSlice(sig.Results()))
	case *types.Named:
		n := t.(*types.Named)
		return NewNamed(
			n.Obj().Pkg().Name(),
			n.Obj().Name(),
			n.Underlying())
	case *types.Interface:
		i := t.(*types.Interface)
		if i.Empty() {
			return NewInterface()
		} else {
			return NewUnsupported("Interfaces")
		}
	case *types.Tuple:
		return NewUnsupported("Tuples")
	case *types.Map:
		return NewUnsupported("Maps")
	case *types.Chan:
		return NewUnsupported("Channels")
	case *types.Struct:
		return NewUnsupported("Structs")
	default:
		return NewUnsupported(t.String())
	}
}
Exemple #2
0
// indirect(typ) assumes that typ is a pointer type,
// or named alias thereof, and returns its base type.
// Panic ensures if it is not a pointer.
//
func indirectType(ptr types.Type) types.Type {
	if v, ok := underlyingType(ptr).(*types.Pointer); ok {
		return v.Base
	}
	// When debugging it is convenient to comment out this line
	// and let it continue to print the (illegal) SSA form.
	panic("indirect() of non-pointer type: " + ptr.String())
	return nil
}
func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType {
	var pos token.Pos
	if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named
		pos = nt.Obj().Pos()
	}
	return serial.ImplementsType{
		Name: T.String(),
		Pos:  fset.Position(pos).String(),
		Kind: typeKind(T),
	}
}
Exemple #4
0
func newVar(p *Package, typ types.Type, objname, name, doc string) *Var {
	sym := p.syms.symtype(typ)
	if sym == nil {
		panic(fmt.Errorf("could not find symbol for type [%s]!", typ.String()))
	}
	return &Var{
		pkg:  p,
		sym:  sym,
		id:   p.Name() + "_" + objname,
		doc:  doc,
		name: name,
	}
}
Exemple #5
0
func (f *File) validResultType(typ types.Type) *Error {
	switch typ.(type) {
	default:
		name := typ.String()
		if named, ok := typ.(*types.Named); ok {
			name = named.Obj().Name()
		}
		return &Error{errors.New(fmt.Sprint("Invalid result type:", name)), 0}
	case *types.Basic:
		typ := typ.(*types.Basic)
		switch typ.Kind() {
		default:

			return &Error{errors.New(fmt.Sprint("Invalid basic type for result type :", typ.Info())), 0}
		case types.Bool:
			return nil
		case types.Int:
			return nil
		case types.Int8:
			return nil
		case types.Int16:
			return nil
		case types.Int32:
			return nil
		case types.Int64:
			return nil
		case types.Uint:
			return nil
		case types.Uint8:
			return nil
		case types.Uint16:
			return nil
		case types.Uint32:
			return nil
		case types.Uint64:
			return nil
		case types.Float32:
			return nil
		case types.Float64:
			return nil
		}
	}
}
Exemple #6
0
// writeSignature writes to w the signature sig in declaration syntax.
// Derived from types.Signature.String().
//
func writeSignature(w io.Writer, name string, sig *types.Signature, params []*Parameter) {
	io.WriteString(w, "func ")
	if sig.Recv != nil {
		io.WriteString(w, "(")
		if n := params[0].Name(); n != "" {
			io.WriteString(w, n)
			io.WriteString(w, " ")
		}
		io.WriteString(w, params[0].Type().String())
		io.WriteString(w, ") ")
		params = params[1:]
	}
	io.WriteString(w, name)
	io.WriteString(w, "(")
	for i, v := range params {
		if i > 0 {
			io.WriteString(w, ", ")
		}
		io.WriteString(w, v.Name())
		io.WriteString(w, " ")
		if sig.IsVariadic && i == len(params)-1 {
			io.WriteString(w, "...")
			io.WriteString(w, underlyingType(v.Type()).(*types.Slice).Elt.String())
		} else {
			io.WriteString(w, v.Type().String())
		}
	}
	io.WriteString(w, ")")
	if res := sig.Results; res != nil {
		io.WriteString(w, " ")
		var t types.Type
		if len(res) == 1 && res[0].Name == "" {
			t = res[0].Type
		} else {
			t = &types.Result{Values: res}
		}
		io.WriteString(w, t.String())
	}
}
Exemple #7
0
// typeString returns a string representation of n.
func typeString(typ types.Type) string {
	return filepath.ToSlash(typ.String())
}
Exemple #8
0
// appendComponentsRecursive implements componentsOfType.
// Recursion is required to correct handle structs and arrays,
// which can contain arbitrary other types.
func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component {
	s := t.String()
	size := int(arch.sizes.Sizeof(t))
	kind := asmKindForType(t, size)
	cc = append(cc, newComponent(suffix, kind, s, off, size, suffix))

	switch kind {
	case 8:
		if arch.ptrSize() == 4 {
			w1, w2 := "lo", "hi"
			if arch.bigEndian {
				w1, w2 = w2, w1
			}
			cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix))
			cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix))
		}

	case asmEmptyInterface:
		cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize()), "interface type", off, arch.ptrSize(), suffix))
		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix))

	case asmInterface:
		cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize()), "interface itable", off, arch.ptrSize(), suffix))
		cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize()), "interface data", off+arch.ptrSize(), arch.ptrSize(), suffix))

	case asmSlice:
		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "slice base", off, arch.ptrSize(), suffix))
		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "slice len", off+arch.ptrSize(), arch.intSize(), suffix))
		cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize()), "slice cap", off+arch.ptrSize()+arch.intSize(), arch.intSize(), suffix))

	case asmString:
		cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize()), "string base", off, arch.ptrSize(), suffix))
		cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize()), "string len", off+arch.ptrSize(), arch.intSize(), suffix))

	case asmComplex:
		fsize := size / 2
		cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix))
		cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix))

	case asmStruct:
		tu := t.Underlying().(*types.Struct)
		fields := make([]*types.Var, tu.NumFields())
		for i := 0; i < tu.NumFields(); i++ {
			fields[i] = tu.Field(i)
		}
		offsets := arch.sizes.Offsetsof(fields)
		for i, f := range fields {
			cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
		}

	case asmArray:
		tu := t.Underlying().(*types.Array)
		elem := tu.Elem()
		// Calculate offset of each element array.
		fields := []*types.Var{
			types.NewVar(token.NoPos, nil, "fake0", elem),
			types.NewVar(token.NoPos, nil, "fake1", elem),
		}
		offsets := arch.sizes.Offsetsof(fields)
		elemoff := int(offsets[1])
		for i := 0; i < int(tu.Len()); i++ {
			cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
		}
	}

	return cc
}
Exemple #9
0
func encodeType(t types.Type) Type {
	// First see if it's a Named type. If so, wrap in Named and recurse with the
	// underlying type.
	if n, isNamed := t.(*types.Named); isNamed {

		// When n.Obj().Pkg() is nil the Named type is defined in the universe. We
		// represent that with an empty package name slice.
		var pkgSegments []string = []string{}
		if n.Obj().Pkg() != nil {
			pkgSegments = strings.Split(n.Obj().Pkg().Path(), "/")
		}
		return NewNamed(
			pkgSegments,
			n.Obj().Name(),
			encodeType(n.Underlying()))
	}

	switch t.Underlying().(type) {
	case *types.Basic:
		b := t.(*types.Basic)
		untyped := (b.Info() & types.IsUntyped) != 0
		return NewBasic(basicKindString(b), untyped)
	case *types.Pointer:
		p := t.(*types.Pointer)
		pt := encodeType(p.Elem())
		return NewPointer(pt)
	case *types.Array:
		a := t.(*types.Array)
		at := encodeType(a.Elem())
		return NewArray(at, a.Len())
	case *types.Slice:
		s := t.(*types.Slice)
		st := encodeType(s.Elem())
		return NewSlice(st)
	case *types.Signature:
		sig := t.(*types.Signature)
		v := sig.Recv()
		var vt *Type
		if v != nil {
			t := encodeType(v.Type())
			vt = &t
		}
		return NewSignature(
			sig.Variadic(),
			vt,
			tupleToSlice(sig.Params()),
			tupleToSlice(sig.Results()))
	case *types.Interface:
		i := t.(*types.Interface)
		if i.Empty() {
			return NewInterface()
		} else {
			return NewUnsupported("Interfaces")
		}
	case *types.Struct:
		s := t.(*types.Struct)
		fields := []StructField{}
		for i := 0; i < s.NumFields(); i++ {
			f := s.Field(i)
			fields = append(fields, NewStructField(f.Name(), encodeType(f.Type())))
		}
		return NewStruct(fields)
	case *types.Tuple:
		return NewUnsupported("Tuples")
	case *types.Map:
		return NewUnsupported("Maps")
	case *types.Chan:
		return NewUnsupported("Channels")
	default:
		return NewUnsupported(t.String())
	}
}
Exemple #10
0
// walkType adds the type, and any necessary child types.
func (b *Builder) walkType(u types.Universe, useName *types.Name, in tc.Type) *types.Type {
	// Most of the cases are underlying types of the named type.
	name := tcNameToName(in.String())
	if useName != nil {
		name = *useName
	}

	switch t := in.(type) {
	case *tc.Struct:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Struct
		for i := 0; i < t.NumFields(); i++ {
			f := t.Field(i)
			m := types.Member{
				Name:         f.Name(),
				Embedded:     f.Anonymous(),
				Tags:         t.Tag(i),
				Type:         b.walkType(u, nil, f.Type()),
				CommentLines: splitLines(b.priorCommentLines(f.Pos(), 1).Text()),
			}
			out.Members = append(out.Members, m)
		}
		return out
	case *tc.Map:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Map
		out.Elem = b.walkType(u, nil, t.Elem())
		out.Key = b.walkType(u, nil, t.Key())
		return out
	case *tc.Pointer:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Pointer
		out.Elem = b.walkType(u, nil, t.Elem())
		return out
	case *tc.Slice:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Slice
		out.Elem = b.walkType(u, nil, t.Elem())
		return out
	case *tc.Array:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Array
		out.Elem = b.walkType(u, nil, t.Elem())
		// TODO: need to store array length, otherwise raw type name
		// cannot be properly written.
		return out
	case *tc.Chan:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Chan
		out.Elem = b.walkType(u, nil, t.Elem())
		// TODO: need to store direction, otherwise raw type name
		// cannot be properly written.
		return out
	case *tc.Basic:
		out := u.Type(types.Name{
			Package: "",
			Name:    t.Name(),
		})
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Unsupported
		return out
	case *tc.Signature:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Func
		out.Signature = b.convertSignature(u, t)
		return out
	case *tc.Interface:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Interface
		t.Complete()
		for i := 0; i < t.NumMethods(); i++ {
			if out.Methods == nil {
				out.Methods = map[string]*types.Type{}
			}
			out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
		}
		return out
	case *tc.Named:
		switch t.Underlying().(type) {
		case *tc.Named, *tc.Basic, *tc.Map, *tc.Slice:
			name := tcNameToName(t.String())
			out := u.Type(name)
			if out.Kind != types.Unknown {
				return out
			}
			out.Kind = types.Alias
			out.Underlying = b.walkType(u, nil, t.Underlying())
			return out
		default:
			// tc package makes everything "named" with an
			// underlying anonymous type--we remove that annoying
			// "feature" for users. This flattens those types
			// together.
			name := tcNameToName(t.String())
			if out := u.Type(name); out.Kind != types.Unknown {
				return out // short circuit if we've already made this.
			}
			out := b.walkType(u, &name, t.Underlying())
			if len(out.Methods) == 0 {
				// If the underlying type didn't already add
				// methods, add them. (Interface types will
				// have already added methods.)
				for i := 0; i < t.NumMethods(); i++ {
					if out.Methods == nil {
						out.Methods = map[string]*types.Type{}
					}
					out.Methods[t.Method(i).Name()] = b.walkType(u, nil, t.Method(i).Type())
				}
			}
			return out
		}
	default:
		out := u.Type(name)
		if out.Kind != types.Unknown {
			return out
		}
		out.Kind = types.Unsupported
		glog.Warningf("Making unsupported type entry %q for: %#v\n", out, t)
		return out
	}
}
Exemple #11
0
//Extract rpc services and methods by analysing type definitions
func (g *Generator) Extract() error {
	rpcmethods := map[string]*RPCMethod{}

	for _, obj := range g.pkg.defs {
		if obj == nil {
			continue
		}

	DEFSWITCH:
		switch t := obj.Type().(type) {

		//as per "net/rpc" are we looking for methods with the following:
		// [x] the fn is a method (has receiver)
		// [x] the method's type is exported.
		// [x] the method is exported.
		// [x] the method has two arguments...
		// [x] both exported (or builtin) types.
		// [x] the method's second argument is a pointer.
		// [x] the method has return type error.
		case *types.Signature:

			//needs to be a method (have a receiver) and be exported
			if t.Recv() == nil || !obj.Exported() {
				break
			}

			//receiver must be named and exported
			var recvt types.Type
			if recvpt, ok := t.Recv().Type().(*types.Pointer); ok {
				recvt = recvpt.Elem()
			} else {
				recvt = t.Recv().Type()
			}

			recv, ok := recvt.(*types.Named)
			if ok {
				if !recv.Obj().Exported() {
					break
				}
			}

			//method must have two params
			if t.Params().Len() != 2 {
				break
			}

			//all param types must be exported or builtin
			for i := 0; i < t.Params().Len(); i++ {
				var paramt types.Type
				if parampt, ok := t.Params().At(i).Type().(*types.Pointer); ok {
					paramt = parampt.Elem()
				} else {

					//second arg must be a pointer
					if i == 1 {
						break DEFSWITCH
					}

					paramt = t.Params().At(i).Type()
				}

				//if param type is Named, it must be exported, else it must be buildin
				if paramnamedt, ok := paramt.(*types.Named); ok {
					if !paramnamedt.Obj().Exported() {
						break DEFSWITCH
					}

				} else if strings.Contains(paramt.String(), ".") {
					break DEFSWITCH
				}
			}

			//must have one result: error
			if t.Results().Len() != 1 || t.Results().At(0).Type().String() != "error" {
				break
			}

			rpcmethods[obj.Name()] = &RPCMethod{
				input:  t.Params().At(0).Type(),
				output: t.Params().At(1).Type().(*types.Pointer).Elem(), //this is checked above
				recv:   recv,
				sig:    t,
			}
		}
	}

	for n, rpcm := range rpcmethods {
		rpcs, ok := g.services[rpcm.recv.Obj().Name()]
		if !ok {
			rpcs = &RPCService{
				methods: map[string]*RPCMethod{},
			}

			g.services[rpcm.recv.Obj().Name()] = rpcs
		}

		rpcs.methods[n] = rpcm
	}

	log.Printf("%+v", g.services["Arith"].methods)

	return nil
}
Exemple #12
0
func validType(T types.Type) bool {
	return T != nil &&
		T != types.Typ[types.Invalid] &&
		!strings.Contains(T.String(), "invalid type") // good but not foolproof
}
Exemple #13
0
// hashType returns a hash for t such that
// types.IsIdentical(x, y) => hashType(x) == hashType(y).
func hashType(t types.Type) int {
	return hashString(t.String()) // TODO(gri): provide a better hash
}
Exemple #14
0
// Bar200 converts a type to a string.
func Bar200(t types.Type) string { return t.String() }
Exemple #15
0
func findMethod(prog *ssa.Program, meth *types.Func, typ types.Type) *ssa.Function {
	if meth != nil {
		fmt.Fprintf(os.Stderr, "     ^ finding method for type: %s pkg: %s name: %s\n", typ.String(), meth.Pkg().Name(), meth.Name())
	}
	return prog.LookupMethod(typ, meth.Pkg(), meth.Name())
}
Exemple #16
0
func equalType(x, y types.Type) error {
	if reflect.TypeOf(x) != reflect.TypeOf(y) {
		return fmt.Errorf("unequal kinds: %T vs %T", x, y)
	}
	switch x := x.(type) {
	case *types.Interface:
		y := y.(*types.Interface)
		// TODO(gri): enable separate emission of Embedded interfaces
		// and ExplicitMethods then use this logic.
		// if x.NumEmbeddeds() != y.NumEmbeddeds() {
		// 	return fmt.Errorf("unequal number of embedded interfaces: %d vs %d",
		// 		x.NumEmbeddeds(), y.NumEmbeddeds())
		// }
		// for i := 0; i < x.NumEmbeddeds(); i++ {
		// 	xi := x.Embedded(i)
		// 	yi := y.Embedded(i)
		// 	if xi.String() != yi.String() {
		// 		return fmt.Errorf("mismatched %th embedded interface: %s vs %s",
		// 			i, xi, yi)
		// 	}
		// }
		// if x.NumExplicitMethods() != y.NumExplicitMethods() {
		// 	return fmt.Errorf("unequal methods: %d vs %d",
		// 		x.NumExplicitMethods(), y.NumExplicitMethods())
		// }
		// for i := 0; i < x.NumExplicitMethods(); i++ {
		// 	xm := x.ExplicitMethod(i)
		// 	ym := y.ExplicitMethod(i)
		// 	if xm.Name() != ym.Name() {
		// 		return fmt.Errorf("mismatched %th method: %s vs %s", i, xm, ym)
		// 	}
		// 	if err := equalType(xm.Type(), ym.Type()); err != nil {
		// 		return fmt.Errorf("mismatched %s method: %s", xm.Name(), err)
		// 	}
		// }
		if x.NumMethods() != y.NumMethods() {
			return fmt.Errorf("unequal methods: %d vs %d",
				x.NumMethods(), y.NumMethods())
		}
		for i := 0; i < x.NumMethods(); i++ {
			xm := x.Method(i)
			ym := y.Method(i)
			if xm.Name() != ym.Name() {
				return fmt.Errorf("mismatched %dth method: %s vs %s", i, xm, ym)
			}
			if err := equalType(xm.Type(), ym.Type()); err != nil {
				return fmt.Errorf("mismatched %s method: %s", xm.Name(), err)
			}
		}
	case *types.Array:
		y := y.(*types.Array)
		if x.Len() != y.Len() {
			return fmt.Errorf("unequal array lengths: %d vs %d", x.Len(), y.Len())
		}
		if err := equalType(x.Elem(), y.Elem()); err != nil {
			return fmt.Errorf("array elements: %s", err)
		}
	case *types.Basic:
		y := y.(*types.Basic)
		if x.Kind() != y.Kind() {
			return fmt.Errorf("unequal basic types: %s vs %s", x, y)
		}
	case *types.Chan:
		y := y.(*types.Chan)
		if x.Dir() != y.Dir() {
			return fmt.Errorf("unequal channel directions: %d vs %d", x.Dir(), y.Dir())
		}
		if err := equalType(x.Elem(), y.Elem()); err != nil {
			return fmt.Errorf("channel elements: %s", err)
		}
	case *types.Map:
		y := y.(*types.Map)
		if err := equalType(x.Key(), y.Key()); err != nil {
			return fmt.Errorf("map keys: %s", err)
		}
		if err := equalType(x.Elem(), y.Elem()); err != nil {
			return fmt.Errorf("map values: %s", err)
		}
	case *types.Named:
		y := y.(*types.Named)
		if x.String() != y.String() {
			return fmt.Errorf("unequal named types: %s vs %s", x, y)
		}
	case *types.Pointer:
		y := y.(*types.Pointer)
		if err := equalType(x.Elem(), y.Elem()); err != nil {
			return fmt.Errorf("pointer elements: %s", err)
		}
	case *types.Signature:
		y := y.(*types.Signature)
		if err := equalType(x.Params(), y.Params()); err != nil {
			return fmt.Errorf("parameters: %s", err)
		}
		if err := equalType(x.Results(), y.Results()); err != nil {
			return fmt.Errorf("results: %s", err)
		}
		if x.Variadic() != y.Variadic() {
			return fmt.Errorf("unequal varidicity: %t vs %t",
				x.Variadic(), y.Variadic())
		}
		if (x.Recv() != nil) != (y.Recv() != nil) {
			return fmt.Errorf("unequal receivers: %s vs %s", x.Recv(), y.Recv())
		}
		if x.Recv() != nil {
			// TODO(adonovan): fix: this assertion fires for interface methods.
			// The type of the receiver of an interface method is a named type
			// if the Package was loaded from export data, or an unnamed (interface)
			// type if the Package was produced by type-checking ASTs.
			// if err := equalType(x.Recv().Type(), y.Recv().Type()); err != nil {
			// 	return fmt.Errorf("receiver: %s", err)
			// }
		}
	case *types.Slice:
		y := y.(*types.Slice)
		if err := equalType(x.Elem(), y.Elem()); err != nil {
			return fmt.Errorf("slice elements: %s", err)
		}
	case *types.Struct:
		y := y.(*types.Struct)
		if x.NumFields() != y.NumFields() {
			return fmt.Errorf("unequal struct fields: %d vs %d",
				x.NumFields(), y.NumFields())
		}
		for i := 0; i < x.NumFields(); i++ {
			xf := x.Field(i)
			yf := y.Field(i)
			if xf.Name() != yf.Name() {
				return fmt.Errorf("mismatched fields: %s vs %s", xf, yf)
			}
			if err := equalType(xf.Type(), yf.Type()); err != nil {
				return fmt.Errorf("struct field %s: %s", xf.Name(), err)
			}
			if x.Tag(i) != y.Tag(i) {
				return fmt.Errorf("struct field %s has unequal tags: %q vs %q",
					xf.Name(), x.Tag(i), y.Tag(i))
			}
		}
	case *types.Tuple:
		y := y.(*types.Tuple)
		if x.Len() != y.Len() {
			return fmt.Errorf("unequal tuple lengths: %d vs %d", x.Len(), y.Len())
		}
		for i := 0; i < x.Len(); i++ {
			if err := equalType(x.At(i).Type(), y.At(i).Type()); err != nil {
				return fmt.Errorf("tuple element %d: %s", i, err)
			}
		}
	}
	return nil
}
Exemple #17
0
// isTargetType returns true if a given type is identical to the target
// types to be checked.
func (v *visitor) isTargetType(t types.Type) bool {
	// Cannot use types.Identical since t and targetType are
	// obtained from different programs(?).
	return t.String() == v.targetType.String()
}