| package main |
| |
| import ( |
| "fmt" |
| "go/ast" |
| "go/importer" |
| "go/parser" |
| "go/token" |
| "go/types" |
| "log" |
| ) |
| |
| //!+input |
| const input = `package main |
| |
| type A struct{} |
| func (*A) f() |
| |
| type B int |
| func (B) f() |
| func (*B) g() |
| |
| type I interface { f() } |
| type J interface { g() } |
| ` |
| |
| //!-input |
| |
| 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 |
| } |
| |
| /* |
| //!+output |
| $ go build golang.org/x/example/gotypes/implements |
| $ ./implements |
| *hello.A satisfies hello.I |
| hello.B satisfies hello.I |
| *hello.B satisfies hello.J |
| //!-output |
| */ |