Beispiel #1
0
// testMainSlice emits to fn code to construct a slice of type slice
// (one of []testing.Internal{Test,Benchmark,Example}) for all
// functions in testfuncs.  It returns the slice value.
//
func testMainSlice(fn *Function, testfuncs []*Function, slice types.Type) Value {
	if testfuncs == nil {
		return nilConst(slice)
	}

	tElem := slice.(*types.Slice).Elem()
	tPtrString := types.NewPointer(tString)
	tPtrElem := types.NewPointer(tElem)
	tPtrFunc := types.NewPointer(funcField(slice))

	// TODO(adonovan): fix: populate the
	// testing.InternalExample.Output field correctly so that tests
	// work correctly under the interpreter.  This requires that we
	// do this step using ASTs, not *ssa.Functions---quite a
	// redesign.  See also the fake runExample in go/ssa/interp.

	// Emit: array = new [n]testing.InternalTest
	tArray := types.NewArray(tElem, int64(len(testfuncs)))
	array := emitNew(fn, tArray, token.NoPos)
	array.Comment = "test main"
	for i, testfunc := range testfuncs {
		// Emit: pitem = &array[i]
		ia := &IndexAddr{X: array, Index: intConst(int64(i))}
		ia.setType(tPtrElem)
		pitem := fn.emit(ia)

		// Emit: pname = &pitem.Name
		fa := &FieldAddr{X: pitem, Field: 0} // .Name
		fa.setType(tPtrString)
		pname := fn.emit(fa)

		// Emit: *pname = "testfunc"
		emitStore(fn, pname, stringConst(testfunc.Name()), token.NoPos)

		// Emit: pfunc = &pitem.F
		fa = &FieldAddr{X: pitem, Field: 1} // .F
		fa.setType(tPtrFunc)
		pfunc := fn.emit(fa)

		// Emit: *pfunc = testfunc
		emitStore(fn, pfunc, testfunc, token.NoPos)
	}

	// Emit: slice array[:]
	sl := &Slice{X: array}
	sl.setType(slice)
	return fn.emit(sl)
}
Beispiel #2
0
// IntuitiveMethodSet returns the intuitive method set of a type T,
// which is the set of methods you can call on an addressable value of
// that type.
//
// The result always contains MethodSet(T), and is exactly MethodSet(T)
// for interface types and for pointer-to-concrete types.
// For all other concrete types T, the result additionally
// contains each method belonging to *T if there is no identically
// named method on T itself.
//
// This corresponds to user intuition about method sets;
// this function is intended only for user interfaces.
//
// The order of the result is as for types.MethodSet(T).
//
func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection {
	isPointerToConcrete := func(T types.Type) bool {
		ptr, ok := T.(*types.Pointer)
		return ok && !types.IsInterface(ptr.Elem())
	}

	var result []*types.Selection
	mset := msets.MethodSet(T)
	if types.IsInterface(T) || isPointerToConcrete(T) {
		for i, n := 0, mset.Len(); i < n; i++ {
			result = append(result, mset.At(i))
		}
	} else {
		// T is some other concrete type.
		// Report methods of T and *T, preferring those of T.
		pmset := msets.MethodSet(types.NewPointer(T))
		for i, n := 0, pmset.Len(); i < n; i++ {
			meth := pmset.At(i)
			if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
				meth = m
			}
			result = append(result, meth)
		}

	}
	return result
}
Beispiel #3
0
func (c *funcContext) makeReceiver(x ast.Expr, sel *types.Selection) *expression {
	if !sel.Obj().Exported() {
		c.p.dependencies[sel.Obj()] = true
	}

	recvType := sel.Recv()
	for _, index := range sel.Index()[:len(sel.Index())-1] {
		if ptr, isPtr := recvType.(*types.Pointer); isPtr {
			recvType = ptr.Elem()
		}
		s := recvType.Underlying().(*types.Struct)
		recvType = s.Field(index).Type()
		x = c.newIdent(c.formatExpr("%e.%s", x, fieldName(s, index)).String(), recvType)
	}

	_, isPointer := recvType.Underlying().(*types.Pointer)
	methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type()
	_, pointerExpected := methodsRecvType.(*types.Pointer)
	if !isPointer && pointerExpected {
		recvType = types.NewPointer(recvType)
		x = c.setType(&ast.UnaryExpr{Op: token.AND, X: x}, recvType)
	}

	recv := c.translateExpr(x)
	if isWrapped(recvType) {
		recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv)
	}
	return recv
}
Beispiel #4
0
func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) {
	g.Printf("@interface %s%s : NSObject {\n", g.namePrefix, obj.Name())
	g.Printf("}\n")
	g.Printf("@property(strong, readonly) id _ref;\n")
	g.Printf("\n")
	g.Printf("- (id)initWithRef:(id)ref;\n")

	// accessors to exported fields.
	for _, f := range exportedFields(t) {
		if t := f.Type(); !g.isSupported(t) {
			g.Printf("// skipped field %s.%s with unsupported type: %T\n\n", obj.Name(), f.Name(), t)
			continue
		}
		name, typ := f.Name(), g.objcFieldType(f.Type())
		g.Printf("- (%s)%s;\n", typ, lowerFirst(name))
		g.Printf("- (void)set%s:(%s)v;\n", name, typ)
	}

	// exported methods
	for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) {
		if !g.isSigSupported(m.Type()) {
			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
			continue
		}
		s := g.funcSummary(m)
		g.Printf("- %s;\n", lowerFirst(s.asMethod(g)))
	}
	g.Printf("@end\n")
}
Beispiel #5
0
// emitImplicitSelections emits to f code to apply the sequence of
// implicit field selections specified by indices to base value v, and
// returns the selected value.
//
// If v is the address of a struct, the result will be the address of
// a field; if it is the value of a struct, the result will be the
// value of a field.
//
func emitImplicitSelections(f *Function, v Value, indices []int) Value {
	for _, index := range indices {
		fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)

		if isPointer(v.Type()) {
			instr := &FieldAddr{
				X:     v,
				Field: index,
			}
			instr.setType(types.NewPointer(fld.Type()))
			v = f.emit(instr)
			// Load the field's value iff indirectly embedded.
			if isPointer(fld.Type()) {
				v = emitLoad(f, v)
			}
		} else {
			instr := &Field{
				X:     v,
				Field: index,
			}
			instr.setType(fld.Type())
			v = f.emit(instr)
		}
	}
	return v
}
Beispiel #6
0
// emitFieldSelection emits to f code to select the index'th field of v.
//
// If wantAddr, the input must be a pointer-to-struct and the result
// will be the field's address; otherwise the result will be the
// field's value.
// Ident id is used for position and debug info.
//
func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
	fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
	if isPointer(v.Type()) {
		instr := &FieldAddr{
			X:     v,
			Field: index,
		}
		instr.setPos(id.Pos())
		instr.setType(types.NewPointer(fld.Type()))
		v = f.emit(instr)
		// Load the field's value iff we don't want its address.
		if !wantAddr {
			v = emitLoad(f, v)
		}
	} else {
		instr := &Field{
			X:     v,
			Field: index,
		}
		instr.setPos(id.Pos())
		instr.setType(fld.Type())
		v = f.emit(instr)
	}
	emitDebugRef(f, id, v, wantAddr)
	return v
}
Beispiel #7
0
// lockPath returns a typePath describing the location of a lock value
// contained in typ. If there is no contained lock, it returns nil.
func lockPath(tpkg *types.Package, typ types.Type) typePath {
	if typ == nil {
		return nil
	}

	// We're only interested in the case in which the underlying
	// type is a struct. (Interfaces and pointers are safe to copy.)
	styp, ok := typ.Underlying().(*types.Struct)
	if !ok {
		return nil
	}

	// We're looking for cases in which a reference to this type
	// can be locked, but a value cannot. This differentiates
	// embedded interfaces from embedded values.
	if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil {
		if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil {
			return []types.Type{typ}
		}
	}

	nfields := styp.NumFields()
	for i := 0; i < nfields; i++ {
		ftyp := styp.Field(i).Type()
		subpath := lockPath(tpkg, ftyp)
		if subpath != nil {
			return append(subpath, typ)
		}
	}

	return nil
}
Beispiel #8
0
// emitNew emits to f a new (heap Alloc) instruction allocating an
// object of type typ.  pos is the optional source location.
//
func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc {
	v := &Alloc{Heap: true}
	v.setType(types.NewPointer(typ))
	v.setPos(pos)
	f.emit(v)
	return v
}
Beispiel #9
0
// PointerType = "*" ("any" | Type) .
func (p *parser) parsePointerType(pkg *types.Package) types.Type {
	p.expect('*')
	if p.tok == scanner.Ident {
		p.expectKeyword("any")
		return types.Typ[types.UnsafePointer]
	}
	return types.NewPointer(p.parseType(pkg))
}
Beispiel #10
0
// addLocal creates an anonymous local variable of type typ, adds it
// to function f and returns it.  pos is the optional source location.
//
func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc {
	v := &Alloc{}
	v.setType(types.NewPointer(typ))
	v.setPos(pos)
	f.Locals = append(f.Locals, v)
	f.emit(v)
	return v
}
func getMethods(pkg *types.Package, typename string) map[string]*types.Func {
	r := make(map[string]*types.Func)
	mset := types.NewMethodSet(types.NewPointer(pkg.Scope().Lookup(typename).Type()))
	for i := 0; i < mset.Len(); i++ {
		fn := mset.At(i).Obj().(*types.Func)
		r[fn.Name()] = fn
	}
	return r
}
Beispiel #12
0
// memberFromObject populates package pkg with a member for the
// typechecker object obj.
//
// For objects from Go source code, syntax is the associated syntax
// tree (for funcs and vars only); it will be used during the build
// phase.
//
func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
	name := obj.Name()
	switch obj := obj.(type) {
	case *types.TypeName:
		pkg.Members[name] = &Type{
			object: obj,
			pkg:    pkg,
		}

	case *types.Const:
		c := &NamedConst{
			object: obj,
			Value:  NewConst(obj.Val(), obj.Type()),
			pkg:    pkg,
		}
		pkg.values[obj] = c.Value
		pkg.Members[name] = c

	case *types.Var:
		g := &Global{
			Pkg:    pkg,
			name:   name,
			object: obj,
			typ:    types.NewPointer(obj.Type()), // address
			pos:    obj.Pos(),
		}
		pkg.values[obj] = g
		pkg.Members[name] = g

	case *types.Func:
		sig := obj.Type().(*types.Signature)
		if sig.Recv() == nil && name == "init" {
			pkg.ninit++
			name = fmt.Sprintf("init#%d", pkg.ninit)
		}
		fn := &Function{
			name:      name,
			object:    obj,
			Signature: sig,
			syntax:    syntax,
			pos:       obj.Pos(),
			Pkg:       pkg,
			Prog:      pkg.Prog,
		}
		if syntax == nil {
			fn.Synthetic = "loaded from gc object file"
		}

		pkg.values[obj] = fn
		if sig.Recv() == nil {
			pkg.Members[name] = fn // package-level function
		}

	default: // (incl. *types.Package)
		panic("unexpected Object type: " + obj.String())
	}
}
Beispiel #13
0
// addSpilledParam declares a parameter that is pre-spilled to the
// stack; the function body will load/store the spilled location.
// Subsequent lifting will eliminate spills where possible.
//
func (f *Function) addSpilledParam(obj types.Object) {
	param := f.addParamObj(obj)
	spill := &Alloc{Comment: obj.Name()}
	spill.setType(types.NewPointer(obj.Type()))
	spill.setPos(obj.Pos())
	f.objects[obj] = spill
	f.Locals = append(f.Locals, spill)
	f.emit(spill)
	f.emit(&Store{Addr: spill, Val: param})
}
Beispiel #14
0
func (g *ObjcGen) genStructM(obj *types.TypeName, t *types.Struct) {
	fields := exportedFields(t)
	methods := exportedMethodSet(types.NewPointer(obj.Type()))

	g.Printf("\n")
	oinf := g.ostructs[obj]
	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
	g.Printf("}\n\n")
	g.Printf("- (id)initWithRef:(id)ref {\n")
	g.Indent()
	g.Printf("self = [super init];\n")
	g.Printf("if (self) { __ref = ref; }\n")
	g.Printf("return self;\n")
	g.Outdent()
	g.Printf("}\n\n")
	if oinf != nil {
		g.Printf("- (id)init {\n")
		g.Indent()
		g.Printf("self = [super init];\n")
		g.Printf("if (self) {\n")
		g.Indent()
		g.Printf("__ref = go_seq_from_refnum(new_%s_%s());\n", g.pkgPrefix, obj.Name())
		g.Outdent()
		g.Printf("}\n")
		g.Printf("return self;\n")
		g.Outdent()
		g.Printf("}\n\n")
	}

	for _, f := range fields {
		if !g.isSupported(f.Type()) {
			g.Printf("// skipped unsupported field %s with type %T\n\n", f.Name(), f)
			continue
		}
		g.genGetter(obj.Name(), f)
		g.genSetter(obj.Name(), f)
	}

	for _, m := range methods {
		if !g.isSigSupported(m.Type()) {
			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
			continue
		}
		s := g.funcSummary(g.ostructs[obj], m)
		g.Printf("- %s {\n", s.asMethod(g))
		g.Indent()
		g.genFunc(s, obj.Name())
		g.Outdent()
		g.Printf("}\n\n")
	}
	g.Printf("@end\n\n")
}
Beispiel #15
0
func main() {
	// Parse one file.
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "input.go", input, 0)
	if err != nil {
		log.Fatal(err) // parse error
	}
	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("hello", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err) // type error
	}

	//!+implements
	// Find all named types at package level.
	var allNamed []*types.Named
	for _, name := range pkg.Scope().Names() {
		if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
			allNamed = append(allNamed, obj.Type().(*types.Named))
		}
	}

	// Test assignability of all distinct pairs of
	// named types (T, U) where U is an interface.
	for _, T := range allNamed {
		for _, U := range allNamed {
			if T == U || !types.IsInterface(U) {
				continue
			}
			if types.AssignableTo(T, U) {
				fmt.Printf("%s satisfies %s\n", T, U)
			} else if !types.IsInterface(T) &&
				types.AssignableTo(types.NewPointer(T), U) {
				fmt.Printf("%s satisfies %s\n", types.NewPointer(T), U)
			}
		}
	}
	//!-implements
}
func (cache *MethodSetCache) lookupNamed(named *types.Named) struct{ value, pointer *types.MethodSet } {
	if cache.named == nil {
		cache.named = make(map[*types.Named]struct{ value, pointer *types.MethodSet })
	}
	// Avoid recomputing mset(*T) for each distinct Pointer
	// instance whose underlying type is a named type.
	msets, ok := cache.named[named]
	if !ok {
		msets.value = types.NewMethodSet(named)
		msets.pointer = types.NewMethodSet(types.NewPointer(named))
		cache.named[named] = msets
	}
	return msets
}
Beispiel #17
0
func (g *goGen) genStruct(obj *types.TypeName, T *types.Struct) {
	fields := exportedFields(T)
	methods := exportedMethodSet(types.NewPointer(obj.Type()))

	for _, f := range fields {
		if t := f.Type(); !g.isSupported(t) {
			g.Printf("// skipped field %s.%s with unsupported type: %T\n\n", obj.Name(), f.Name(), t)
			continue
		}
		g.Printf("//export proxy%s_%s_%s_Set\n", g.pkgPrefix, obj.Name(), f.Name())
		g.Printf("func proxy%s_%s_%s_Set(refnum C.int32_t, v C.%s) {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type()))
		g.Indent()
		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
		g.genRead("_v", "v", f.Type(), modeRetained)
		g.Printf("ref.Get().(*%s%s).%s = _v\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
		g.Outdent()
		g.Printf("}\n\n")

		g.Printf("//export proxy%s_%s_%s_Get\n", g.pkgPrefix, obj.Name(), f.Name())
		g.Printf("func proxy%s_%s_%s_Get(refnum C.int32_t) C.%s {\n", g.pkgPrefix, obj.Name(), f.Name(), g.cgoType(f.Type()))
		g.Indent()
		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
		g.Printf("v := ref.Get().(*%s%s).%s\n", g.pkgName(g.Pkg), obj.Name(), f.Name())
		g.genWrite("_v", "v", f.Type(), modeRetained)
		g.Printf("return _v\n")
		g.Outdent()
		g.Printf("}\n\n")
	}

	for _, m := range methods {
		if !g.isSigSupported(m.Type()) {
			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
			continue
		}
		g.genFuncSignature(m, obj.Name())
		g.Indent()
		g.Printf("ref := _seq.FromRefNum(int32(refnum))\n")
		g.Printf("v := ref.Get().(*%s%s)\n", g.pkgName(g.Pkg), obj.Name())
		g.genFuncBody(m, "v.")
		g.Outdent()
		g.Printf("}\n\n")
	}
	// Export constructor for ObjC and Java default no-arg constructors
	g.Printf("//export new_%s_%s\n", g.Pkg.Name(), obj.Name())
	g.Printf("func new_%s_%s() C.int32_t {\n", g.Pkg.Name(), obj.Name())
	g.Indent()
	g.Printf("return C.int32_t(_seq.ToRefNum(new(%s%s)))\n", g.pkgName(g.Pkg), obj.Name())
	g.Outdent()
	g.Printf("}\n")
}
Beispiel #18
0
func (g *ObjcGen) genStructH(obj *types.TypeName, t *types.Struct) {
	g.Printf("@interface %s%s : ", g.namePrefix, obj.Name())
	oinf := g.ostructs[obj]
	if oinf != nil {
		var prots []string
		for _, sup := range oinf.supers {
			if !sup.Protocol {
				g.Printf(sup.Name)
			} else {
				prots = append(prots, sup.Name)
			}
		}
		if len(prots) > 0 {
			g.Printf(" <%s>", strings.Join(prots, ", "))
		}
	} else {
		g.Printf("NSObject <goSeqRefInterface>")
	}
	g.Printf(" {\n")
	g.Printf("}\n")
	g.Printf("@property(strong, readonly) id _ref;\n")
	g.Printf("\n")
	g.Printf("- (id)initWithRef:(id)ref;\n")
	if oinf != nil {
		g.Printf("- (id)init;\n")
	}

	// accessors to exported fields.
	for _, f := range exportedFields(t) {
		if t := f.Type(); !g.isSupported(t) {
			g.Printf("// skipped field %s.%s with unsupported type: %T\n\n", obj.Name(), f.Name(), t)
			continue
		}
		name, typ := f.Name(), g.objcFieldType(f.Type())
		g.Printf("- (%s)%s;\n", typ, objcNameReplacer(lowerFirst(name)))
		g.Printf("- (void)set%s:(%s)v;\n", name, typ)
	}

	// exported methods
	for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) {
		if !g.isSigSupported(m.Type()) {
			g.Printf("// skipped method %s.%s with unsupported parameter or return types\n\n", obj.Name(), m.Name())
			continue
		}
		s := g.funcSummary(g.ostructs[obj], m)
		g.Printf("- %s;\n", objcNameReplacer(lowerFirst(s.asMethod(g))))
	}
	g.Printf("@end\n")
}
Beispiel #19
0
// Type =
//	BasicType | TypeName | ArrayType | SliceType | StructType |
//      PointerType | FuncType | InterfaceType | MapType | ChanType |
//      "(" Type ")" .
//
// BasicType   = ident .
// TypeName    = ExportedName .
// SliceType   = "[" "]" Type .
// PointerType = "*" Type .
// FuncType    = "func" Signature .
//
func (p *parser) parseType(parent *types.Package) types.Type {
	switch p.tok {
	case scanner.Ident:
		switch p.lit {
		default:
			return p.parseBasicType()
		case "struct":
			return p.parseStructType(parent)
		case "func":
			// FuncType
			p.next()
			return p.parseSignature(nil)
		case "interface":
			return p.parseInterfaceType(parent)
		case "map":
			return p.parseMapType(parent)
		case "chan":
			return p.parseChanType(parent)
		}
	case '@':
		// TypeName
		pkg, name := p.parseExportedName()
		return declTypeName(pkg, name).Type()
	case '[':
		p.next() // look ahead
		if p.tok == ']' {
			// SliceType
			p.next()
			return types.NewSlice(p.parseType(parent))
		}
		return p.parseArrayType(parent)
	case '*':
		// PointerType
		p.next()
		return types.NewPointer(p.parseType(parent))
	case '<':
		return p.parseChanType(parent)
	case '(':
		// "(" Type ")"
		p.next()
		typ := p.parseType(parent)
		p.expect(')')
		return typ
	}
	p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
	return nil
}
Beispiel #20
0
func (g *objcGen) genRead(toName, fromName string, t types.Type, mode varMode) {
	if isErrorType(t) {
		g.genRead(toName, fromName, types.Typ[types.String], mode)
		return
	}
	switch t := t.(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.String:
			g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName)
		case types.Bool:
			g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName)
		default:
			g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName)
		}
	case *types.Slice:
		switch e := t.Elem().(type) {
		case *types.Basic:
			switch e.Kind() {
			case types.Uint8: // Byte.
				g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, g.toCFlag(mode == modeRetained))
			default:
				g.errorf("unsupported type: %s", t)
			}
		default:
			g.errorf("unsupported type: %s", t)
		}
	case *types.Pointer:
		switch t := t.Elem().(type) {
		case *types.Named:
			g.genRefRead(toName, fromName, types.NewPointer(t))
		default:
			g.errorf("unsupported type %s", t)
		}
	case *types.Named:
		switch t.Underlying().(type) {
		case *types.Interface, *types.Pointer:
			g.genRefRead(toName, fromName, t)
		default:
			g.errorf("unsupported, direct named type %s", t)
		}
	default:
		g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName)
	}
}
Beispiel #21
0
// IntuitiveMethodSet returns the intuitive method set of a type, T.
//
// The result contains MethodSet(T) and additionally, if T is a
// concrete type, methods belonging to *T if there is no identically
// named method on T itself.  This corresponds to user intuition about
// method sets; this function is intended only for user interfaces.
//
// The order of the result is as for types.MethodSet(T).
//
func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection {
	var result []*types.Selection
	mset := msets.MethodSet(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 := msets.MethodSet(types.NewPointer(T))
		for i, n := 0, pmset.Len(); i < n; i++ {
			meth := pmset.At(i)
			if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil {
				meth = m
			}
			result = append(result, meth)
		}
	}
	return result
}
Beispiel #22
0
func methodDocComment(prog *loader.Program, tname *types.TypeName, methodName string) (string, error) {
	t := tname.Type()
	if !types.IsInterface(t) {
		// Use the pointer type to get as many methods as possible.
		t = types.NewPointer(t)
	}

	mset := types.NewMethodSet(t)
	sel := mset.Lookup(nil, methodName)
	if sel == nil {
		return "", errgo.Newf("cannot find method %v on %v", methodName, t)
	}
	obj := sel.Obj()
	decl, err := findDecl(prog, obj.Pos())
	if err != nil {
		return "", errgo.Mask(err)
	}
	switch decl := decl.(type) {
	case *ast.GenDecl:
		if decl.Tok != token.TYPE {
			return "", errgo.Newf("found non-type decl %#v", decl)
		}
		for _, spec := range decl.Specs {
			tspec := spec.(*ast.TypeSpec)
			it := tspec.Type.(*ast.InterfaceType)
			for _, m := range it.Methods.List {
				for _, id := range m.Names {
					if id.Pos() == obj.Pos() {
						return m.Doc.Text(), nil
					}
				}
			}
		}
		return "", errgo.Newf("method definition not found in type")
	case *ast.FuncDecl:
		if decl.Name.Pos() != obj.Pos() {
			return "", errgo.Newf("method definition not found (at %#v)", prog.Fset.Position(obj.Pos()))
		}
		return decl.Doc.Text(), nil
	default:
		return "", errgo.Newf("unexpected declaration %T found", decl)
	}
}
Beispiel #23
0
// ExampleMethodSet prints the method sets of various types.
func ExampleMethodSet() {
	// Parse a single source file.
	const input = `
package temperature
import "fmt"
type Celsius float64
func (c Celsius) String() string  { return fmt.Sprintf("%g°C", c) }
func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
`
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "celsius.go", input, 0)
	if err != nil {
		log.Fatal(err)
	}

	// Type-check a package consisting of this file.
	// Type information for the imported packages
	// comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	// Print the method sets of Celsius and *Celsius.
	celsius := pkg.Scope().Lookup("Celsius").Type()
	for _, t := range []types.Type{celsius, types.NewPointer(celsius)} {
		fmt.Printf("Method set of %s:\n", t)
		mset := types.NewMethodSet(t)
		for i := 0; i < mset.Len(); i++ {
			fmt.Println(mset.At(i))
		}
		fmt.Println()
	}

	// Output:
	// Method set of temperature.Celsius:
	// method (temperature.Celsius) String() string
	//
	// Method set of *temperature.Celsius:
	// method (*temperature.Celsius) SetF(f float64)
	// method (*temperature.Celsius) String() string
}
Beispiel #24
0
// combinedMethodSet returns the method set for a named type T
// merged with all the methods of *T that have different names than
// the methods of T.
//
// combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
// but doesn't require a MethodSetCache.
// TODO(gri) If this functionality doesn't change over time, consider
// just calling IntuitiveMethodSet eventually.
func combinedMethodSet(T *types.Named) []*types.Selection {
	// method set for T
	mset := types.NewMethodSet(T)
	var res []*types.Selection
	for i, n := 0, mset.Len(); i < n; i++ {
		res = append(res, mset.At(i))
	}

	// add all *T methods with names different from T methods
	pmset := types.NewMethodSet(types.NewPointer(T))
	for i, n := 0, pmset.Len(); i < n; i++ {
		pm := pmset.At(i)
		if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
			res = append(res, pm)
		}
	}

	return res
}
Beispiel #25
0
func (c *funcContext) makeReceiver(e *ast.SelectorExpr) *expression {
	sel, _ := c.p.SelectionOf(e)
	if !sel.Obj().Exported() {
		c.p.dependencies[sel.Obj()] = true
	}

	x := e.X
	recvType := sel.Recv()
	if len(sel.Index()) > 1 {
		for _, index := range sel.Index()[:len(sel.Index())-1] {
			if ptr, isPtr := recvType.(*types.Pointer); isPtr {
				recvType = ptr.Elem()
			}
			s := recvType.Underlying().(*types.Struct)
			recvType = s.Field(index).Type()
		}

		fakeSel := &ast.SelectorExpr{X: x, Sel: ast.NewIdent("o")}
		c.p.additionalSelections[fakeSel] = &fakeSelection{
			kind:  types.FieldVal,
			recv:  sel.Recv(),
			index: sel.Index()[:len(sel.Index())-1],
			typ:   recvType,
		}
		x = c.setType(fakeSel, recvType)
	}

	_, isPointer := recvType.Underlying().(*types.Pointer)
	methodsRecvType := sel.Obj().Type().(*types.Signature).Recv().Type()
	_, pointerExpected := methodsRecvType.(*types.Pointer)
	if !isPointer && pointerExpected {
		recvType = types.NewPointer(recvType)
		x = c.setType(&ast.UnaryExpr{Op: token.AND, X: x}, recvType)
	}

	recv := c.translateExpr(x)
	if isWrapped(recvType) {
		recv = c.formatExpr("new %s(%s)", c.typeName(methodsRecvType), recv)
	}
	return recv
}
Beispiel #26
0
func (g *objcGen) genStructH(obj *types.TypeName, t *types.Struct) {
	g.Printf("@interface %s%s : NSObject {\n", g.namePrefix, obj.Name())
	g.Printf("}\n")
	g.Printf("@property(strong, readonly) id _ref;\n")
	g.Printf("\n")
	g.Printf("- (id)initWithRef:(id)ref;\n")

	// accessors to exported fields.
	for _, f := range exportedFields(t) {
		name, typ := f.Name(), g.objcFieldType(f.Type())
		g.Printf("- (%s)%s;\n", typ, lowerFirst(name))
		g.Printf("- (void)set%s:(%s)v;\n", name, typ)
	}

	// exported methods
	for _, m := range exportedMethodSet(types.NewPointer(obj.Type())) {
		s := g.funcSummary(m)
		g.Printf("- %s;\n", lowerFirst(s.asMethod(g)))
	}
	g.Printf("@end\n")
}
Beispiel #27
0
func (g *objcGen) genStructM(obj *types.TypeName, t *types.Struct) {
	fields := exportedFields(t)
	methods := exportedMethodSet(types.NewPointer(obj.Type()))

	desc := fmt.Sprintf("_GO_%s_%s", g.pkgName, obj.Name())
	g.Printf("#define %s_DESCRIPTOR_ \"go.%s.%s\"\n", desc, g.pkgName, obj.Name())
	for i, f := range fields {
		g.Printf("#define %s_FIELD_%s_GET_ (0x%x0f)\n", desc, f.Name(), i)
		g.Printf("#define %s_FIELD_%s_SET_ (0x%x1f)\n", desc, f.Name(), i)
	}
	for i, m := range methods {
		g.Printf("#define %s_%s_ (0x%x0c)\n", desc, m.Name(), i)
	}

	g.Printf("\n")
	g.Printf("@implementation %s%s {\n", g.namePrefix, obj.Name())
	g.Printf("}\n\n")
	g.Printf("- (id)initWithRef:(id)ref {\n")
	g.Indent()
	g.Printf("self = [super init];\n")
	g.Printf("if (self) { __ref = ref; }\n")
	g.Printf("return self;\n")
	g.Outdent()
	g.Printf("}\n\n")

	for _, f := range fields {
		g.genGetter(desc, f)
		g.genSetter(desc, f)
	}

	for _, m := range methods {
		s := g.funcSummary(m)
		g.Printf("- %s {\n", s.asMethod(g))
		g.Indent()
		g.genFunc(desc+"_DESCRIPTOR_", desc+"_"+m.Name()+"_", s, true)
		g.Outdent()
		g.Printf("}\n\n")
	}
	g.Printf("@end\n")
}
Beispiel #28
0
// findNamedFunc returns the named function whose FuncDecl.Ident is at
// position pos.
//
func findNamedFunc(pkg *Package, pos token.Pos) *Function {
	// Look at all package members and method sets of named types.
	// Not very efficient.
	for _, mem := range pkg.Members {
		switch mem := mem.(type) {
		case *Function:
			if mem.Pos() == pos {
				return mem
			}
		case *Type:
			mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
			for i, n := 0, mset.Len(); i < n; i++ {
				// Don't call Program.Method: avoid creating wrappers.
				obj := mset.At(i).Obj().(*types.Func)
				if obj.Pos() == pos {
					return pkg.values[obj].(*Function)
				}
			}
		}
	}
	return nil
}
Beispiel #29
0
func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.Node, obj *types.Var, expKind string, wantAddr bool) {
	// The prefix of all assertions messages.
	prefix := fmt.Sprintf("VarValue(%s @ L%d)",
		obj, prog.Fset.Position(ref[0].Pos()).Line)

	v, gotAddr := prog.VarValue(obj, pkg, ref)

	// Kind is the concrete type of the ssa Value.
	gotKind := "nil"
	if v != nil {
		gotKind = fmt.Sprintf("%T", v)[len("*ssa."):]
	}

	// fmt.Printf("%s = %v (kind %q; expect %q) wantAddr=%t gotAddr=%t\n", prefix, v, gotKind, expKind, wantAddr, gotAddr) // debugging

	// Check the kinds match.
	// "nil" indicates expected failure (e.g. optimized away).
	if expKind != gotKind {
		t.Errorf("%s concrete type == %s, want %s", prefix, gotKind, expKind)
	}

	// Check the types match.
	// If wantAddr, the expected type is the object's address.
	if v != nil {
		expType := obj.Type()
		if wantAddr {
			expType = types.NewPointer(expType)
			if !gotAddr {
				t.Errorf("%s: got value, want address", prefix)
			}
		} else if gotAddr {
			t.Errorf("%s: got address, want value", prefix)
		}
		if !types.Identical(v.Type(), expType) {
			t.Errorf("%s.Type() == %s, want %s", prefix, v.Type(), expType)
		}
	}
}
Beispiel #30
0
func (w *Walker) emitType(obj *types.TypeName) {
	name := obj.Name()
	typ := obj.Type()
	switch typ := typ.Underlying().(type) {
	case *types.Struct:
		w.emitStructType(name, typ)
	case *types.Interface:
		w.emitIfaceType(name, typ)
		return // methods are handled by emitIfaceType
	default:
		w.emitf("type %s %s", name, w.typeString(typ.Underlying()))
	}

	// emit methods with value receiver
	var methodNames map[string]bool
	vset := types.NewMethodSet(typ)
	for i, n := 0, vset.Len(); i < n; i++ {
		m := vset.At(i)
		if m.Obj().Exported() {
			w.emitMethod(m)
			if methodNames == nil {
				methodNames = make(map[string]bool)
			}
			methodNames[m.Obj().Name()] = true
		}
	}

	// emit methods with pointer receiver; exclude
	// methods that we have emitted already
	// (the method set of *T includes the methods of T)
	pset := types.NewMethodSet(types.NewPointer(typ))
	for i, n := 0, pset.Len(); i < n; i++ {
		m := pset.At(i)
		if m.Obj().Exported() && !methodNames[m.Obj().Name()] {
			w.emitMethod(m)
		}
	}
}