// 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 }
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)) } }
// 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 }
// 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) } }
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 }
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) } } }
// 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 }
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 + "}" }
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") }