Example #1
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
}
Example #2
0
func (c *funcContext) initType(o types.Object) {
	if _, isInterface := o.Type().Underlying().(*types.Interface); !isInterface {
		writeMethodSet := func(t types.Type) {
			methodSet := types.NewMethodSet(t)
			if methodSet.Len() == 0 {
				return
			}
			methods := make([]string, methodSet.Len())
			for i := range methods {
				method := methodSet.At(i)
				pkgPath := ""
				if !method.Obj().Exported() {
					pkgPath = method.Obj().Pkg().Path()
				}
				t := method.Type().(*types.Signature)
				embeddedIndex := -1
				if len(method.Index()) > 1 {
					embeddedIndex = method.Index()[0]
				}
				methods[i] = fmt.Sprintf(`["%s", "%s", %s, %s, %t, %d]`, method.Obj().Name(), pkgPath, c.typeArray(t.Params()), c.typeArray(t.Results()), t.Variadic(), embeddedIndex)
			}
			c.Printf("%s.methods = [%s];", c.typeName(t), strings.Join(methods, ", "))
		}
		writeMethodSet(o.Type())
		writeMethodSet(types.NewPointer(o.Type()))
	}
	switch t := o.Type().Underlying().(type) {
	case *types.Array, *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Slice, *types.Signature, *types.Struct:
		c.Printf("%s.init(%s);", c.objectName(o), c.initArgs(t))
	}
}
Example #3
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
}
Example #4
0
// Smoke test to ensure that imported methods get the correct package.
func TestCorrectMethodPackage(t *testing.T) {
	// This package does not handle gccgo export data.
	if runtime.Compiler == "gccgo" {
		return
	}

	imports := make(map[string]*types.Package)
	_, err := Import(imports, "net/http")
	if err != nil {
		t.Fatal(err)
	}

	mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
	mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
	sel := mset.Lookup(nil, "Lock")
	lock := sel.Obj().(*types.Func)
	if got, want := lock.Pkg().Path(), "sync"; got != want {
		t.Errorf("got package path %q; want %q", got, want)
	}
}
Example #5
0
func FindImplentations(i *types.Interface, pkg *types.Package) []string {
	var names []string

	scope := pkg.Scope()
	allNames := scope.Names()

	for _, name := range allNames {
		obj := scope.Lookup(name)
		if typeName, ok := obj.(*types.TypeName); ok {
			if types.Implements(typeName.Type(), i) {
				names = append(names, typeName.Name())
			} else {
				println(typeName.Name(), "cannot be an ensurer")
				println(types.NewMethodSet(typeName.Type()).String())
			}
		}
	}

	return names
}
Example #6
0
func (r *implementsResult) display(printf printfFunc) {
	if isInterface(r.t) {
		if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset
			printf(r.pos, "empty interface type %s", r.t)
			return
		}

		printf(r.pos, "interface type %s", r.t)
		// Show concrete types first; use two passes.
		for _, sub := range r.to {
			if !isInterface(sub) {
				printf(deref(sub).(*types.Named).Obj(), "\tis implemented by %s type %s",
					typeKind(sub), sub)
			}
		}
		for _, sub := range r.to {
			if isInterface(sub) {
				printf(deref(sub).(*types.Named).Obj(), "\tis implemented by %s type %s", typeKind(sub), sub)
			}
		}

		for _, super := range r.from {
			printf(super.(*types.Named).Obj(), "\timplements %s", super)
		}
	} else {
		if r.from != nil {
			printf(r.pos, "%s type %s", typeKind(r.t), r.t)
			for _, super := range r.from {
				printf(super.(*types.Named).Obj(), "\timplements %s", super)
			}
		}
		if r.fromPtr != nil {
			printf(r.pos, "pointer type *%s", r.t)
			for _, psuper := range r.fromPtr {
				printf(psuper.(*types.Named).Obj(), "\timplements %s", psuper)
			}
		} else if r.from == nil {
			printf(r.pos, "%s type %s implements only interface{}", typeKind(r.t), r.t)
		}
	}
}
Example #7
0
// Visit implements the ast.Visitor interface.
func (f *File) Visit(node ast.Node) ast.Visitor {
	switch n := node.(type) {
	case *ast.GenDecl:
		// Variables, constants, types.
		for _, spec := range n.Specs {
			switch spec := spec.(type) {
			case *ast.ValueSpec:
				if constantFlag && n.Tok == token.CONST || variableFlag && n.Tok == token.VAR {
					for _, ident := range spec.Names {
						if f.match(ident.Name) {
							f.printNode(n, ident, f.nameURL(ident.Name))
							break
						}
					}
				}
			case *ast.TypeSpec:
				// If there is only one Spec, there are probably no parens and the
				// comment we want appears before the type keyword, bound to
				// the GenDecl. If the Specs are parenthesized, the comment we want
				// is bound to the Spec. Hence we dig into the GenDecl to the Spec,
				// but only if there are no parens.
				node := ast.Node(n)
				if n.Lparen.IsValid() {
					node = spec
				}
				if f.match(spec.Name.Name) {
					if typeFlag {
						f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
					} else {
						switch spec.Type.(type) {
						case *ast.InterfaceType:
							if interfaceFlag {
								f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
							}
						case *ast.StructType:
							if structFlag {
								f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
							}
						}
					}
					if f.doPrint && f.objs[spec.Name] != nil && f.objs[spec.Name].Type() != nil {
						ms := types.NewMethodSet(f.objs[spec.Name].Type()) //.Type().MethodSet()
						if ms.Len() == 0 {
							ms = types.NewMethodSet(types.NewPointer(f.objs[spec.Name].Type())) //.MethodSet()
						}
						f.methodSet(ms)
					}
				}
			case *ast.ImportSpec:
				continue // Don't care.
			}
		}
	case *ast.FuncDecl:
		// Methods, top-level functions.
		if f.match(n.Name.Name) {
			n.Body = nil // Do not print the function body.
			if methodFlag && n.Recv != nil {
				f.printNode(n, n.Name, f.methodURL(n.Recv.List[0].Type, n.Name.Name))
			} else if functionFlag && n.Recv == nil {
				f.printNode(n, n.Name, f.nameURL(n.Name.Name))
			}
		}
	}
	return f
}
Example #8
0
func (l langType) EmitTypeInfo() string {
	ret := "class TypeInfo{\n"
	pte := pogo.TypesEncountered
	pteKeys := pogo.TypesEncountered.Keys()

	ret += "public static function getName(id:Int):String {\nswitch(id){" + "\n"
	for k := range pteKeys {
		v := pte.At(pteKeys[k])
		ret += "case " + fmt.Sprintf("%d", v) + `: return "` + pteKeys[k].String() + `";` + "\n"
	}
	ret += `default: return "UNKNOWN";}}` + "\n"

	ret += "public static function typeString(i:Interface):String {\nreturn getName(i.typ);\n}\n"

	ret += "public static function getId(name:String):Int {\nswitch(name){" + "\n"
	for k := range pteKeys {
		v := pte.At(pteKeys[k])
		ret += `case "` + pteKeys[k].String() + `": return ` + fmt.Sprintf("%d", v) + `;` + "\n"
	}
	ret += "default: return -1;}}\n"

	//emulation of: func IsAssignableTo(V, T Type) bool
	ret += "public static function isAssignableTo(v:Int,t:Int):Bool {\nif(v==t) return true;\nswitch(v){" + "\n"
	for V := range pteKeys {
		v := pte.At(pteKeys[V])
		ret += `case ` + fmt.Sprintf("%d", v) + `: switch(t){` + "\n"
		for T := range pteKeys {
			t := pte.At(pteKeys[T])
			if v != t && types.AssignableTo(pteKeys[V], pteKeys[T]) {
				ret += `case ` + fmt.Sprintf("%d", t) + `: return true;` + "\n"
			}
		}
		ret += "default: return false;}\n"
	}
	ret += "default: return false;}}\n"

	//emulation of: func IsIdentical(x, y Type) bool
	ret += "public static function isIdentical(v:Int,t:Int):Bool {\nif(v==t) return true;\nswitch(v){" + "\n"
	for V := range pteKeys {
		v := pte.At(pteKeys[V])
		ret += `case ` + fmt.Sprintf("%d", v) + `: switch(t){` + "\n"
		for T := range pteKeys {
			t := pte.At(pteKeys[T])
			if v != t && types.Identical(pteKeys[V], pteKeys[T]) {
				ret += `case ` + fmt.Sprintf("%d", t) + `: return true;` + "\n"
			}
		}
		ret += "default: return false;}\n"
	}
	ret += "default: return false;}}\n"

	//function to answer the question is the type a concrete value?
	ret += "public static function isConcrete(t:Int):Bool {\nswitch(t){" + "\n"
	for T := range pteKeys {
		t := pte.At(pteKeys[T])
		switch pteKeys[T].Underlying().(type) {
		case *types.Interface:
			ret += `case ` + fmt.Sprintf("%d", t) + `: return false;` + "\n"
		default:
			ret += `case ` + fmt.Sprintf("%d", t) + `: return true;` + "\n"
		}
	}
	ret += "default: return false;}}\n"

	// function to give the zero value for each type
	ret += "public static function zeroValue(t:Int):Dynamic {\nswitch(t){" + "\n"
	for T := range pteKeys {
		t := pte.At(pteKeys[T])
		ret += `case ` + fmt.Sprintf("%d", t) + `: return `
		ret += l.LangType(pteKeys[T], true, "EmitTypeInfo()") + ";\n"
	}
	ret += "default: return null;}}\n"

	ret += "public static function method(t:Int,m:String):Dynamic {\nswitch(t){" + "\n"

	tta := pogo.TypesWithMethodSets() //[]types.Type

	for T := range tta {
		t := pte.At(tta[T])
		if t != nil { // it is used?
			ret += `case ` + fmt.Sprintf("%d", t) + `: switch(m){` + "\n"
			ms := types.NewMethodSet(tta[T])
			for m := 0; m < ms.Len(); m++ {
				funcObj, ok := ms.At(m).Obj().(*types.Func)
				pkgName := "unknown"
				if ok && funcObj.Pkg() != nil {
					line := ""
					ss := strings.Split(funcObj.Pkg().Name(), "/")
					pkgName = ss[len(ss)-1]
					if strings.HasPrefix(pkgName, "_") { // exclude functions in haxe for now
						// TODO NoOp for now... so haxe types cant be "Involked" when held in interface types
						// *** need to deal with getters and setters
						// *** also with calling parameters which are different for a Haxe API
					} else {
						line = `case "` + funcObj.Name() + `": return `
						fnToCall := l.LangName(ms.At(m).Recv().String(),
							funcObj.Name())
						ovPkg, _, isOv := l.PackageOverloaded(funcObj.Pkg().Name())
						if isOv {
							fnToCall = strings.Replace(fnToCall, "_"+funcObj.Pkg().Name()+"_", "_"+ovPkg+"_", -1) // NOTE this is not a fool-proof method
						}
						line += `Go_` + fnToCall + `.call` + "; "
					}
					ret += line
				}
				ret += fmt.Sprintf("// %v %v %v %v\n",
					ms.At(m).Obj().Name(),
					ms.At(m).Kind(),
					ms.At(m).Index(),
					ms.At(m).Indirect())
			}
			ret += "default:}\n"
		}
	}
	ret += "default:}\n Scheduler.panicFromHaxe( " + `"no method found!"` + "); return null;}\n" // TODO improve error

	return ret + "}"
}
Example #9
0
func Write(pkg *types.Package, out io.Writer, sizes types.Sizes) {
	fmt.Fprintf(out, "package %s\n", pkg.Name())

	e := &exporter{pkg: pkg, imports: make(map[*types.Package]bool), out: out}

	for _, imp := range pkg.Imports() {
		e.addImport(imp)
	}

	for _, name := range pkg.Scope().Names() {
		obj := pkg.Scope().Lookup(name)

		_, isTypeName := obj.(*types.TypeName)
		if obj.Exported() || isTypeName {
			e.toExport = append(e.toExport, obj)
		}
	}

	for i := 0; i < len(e.toExport); i++ {
		switch o := e.toExport[i].(type) {
		case *types.TypeName:
			fmt.Fprintf(out, "type %s %s\n", e.makeName(o), e.makeType(o.Type().Underlying()))
			if _, isInterface := o.Type().Underlying().(*types.Interface); !isInterface {
				writeMethods := func(t types.Type) {
					methods := types.NewMethodSet(t)
					for i := 0; i < methods.Len(); i++ {
						m := methods.At(i)
						if len(m.Index()) > 1 {
							continue // method of embedded field
						}
						out.Write([]byte("func (? " + e.makeType(m.Recv()) + ") " + e.makeName(m.Obj()) + e.makeSignature(m.Type()) + "\n"))
					}
				}
				writeMethods(o.Type())
				writeMethods(types.NewPointer(o.Type()))
			}
		case *types.Func:
			out.Write([]byte("func " + e.makeName(o) + e.makeSignature(o.Type()) + "\n"))
		case *types.Const:
			optType := ""
			basic, isBasic := o.Type().(*types.Basic)
			if !isBasic || basic.Info()&types.IsUntyped == 0 {
				optType = " " + e.makeType(o.Type())
			}

			basic = o.Type().Underlying().(*types.Basic)
			var val string
			switch {
			case basic.Info()&types.IsBoolean != 0:
				val = strconv.FormatBool(exact.BoolVal(o.Val()))
			case basic.Info()&types.IsInteger != 0:
				if basic.Kind() == types.Uint64 {
					d, _ := exact.Uint64Val(o.Val())
					val = fmt.Sprintf("%#x", d)
					break
				}
				d, _ := exact.Int64Val(o.Val())
				if basic.Kind() == types.UntypedRune {
					switch {
					case d < 0 || d > unicode.MaxRune:
						val = fmt.Sprintf("('\\x00' + %d)", d)
					case d > 0xffff:
						val = fmt.Sprintf("'\\U%08x'", d)
					default:
						val = fmt.Sprintf("'\\u%04x'", d)
					}
					break
				}
				val = fmt.Sprintf("%#x", d)
			case basic.Info()&types.IsFloat != 0:
				f, _ := exact.Float64Val(o.Val())
				val = strconv.FormatFloat(f, 'b', -1, 64)
			case basic.Info()&types.IsComplex != 0:
				r, _ := exact.Float64Val(exact.Real(o.Val()))
				i, _ := exact.Float64Val(exact.Imag(o.Val()))
				val = fmt.Sprintf("(%s+%si)", strconv.FormatFloat(r, 'b', -1, 64), strconv.FormatFloat(i, 'b', -1, 64))
			case basic.Info()&types.IsString != 0:
				val = fmt.Sprintf("%#v", exact.StringVal(o.Val()))
			default:
				panic("Unhandled constant type: " + basic.String())
			}
			out.Write([]byte("const " + e.makeName(o) + optType + " = " + val + "\n"))
		case *types.Var:
			out.Write([]byte("var " + e.makeName(o) + " " + e.makeType(o.Type()) + "\n"))
		default:
			panic(fmt.Sprintf("Unhandled object: %T\n", o))
		}
	}

	fmt.Fprintf(out, "$$\n")
}