| // Copyright 2022 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build go1.18 |
| |
| package main |
| |
| import ( |
| "fmt" |
| "go/ast" |
| "go/parser" |
| "go/token" |
| "go/types" |
| "log" |
| ) |
| |
| const src = ` |
| //!+input |
| package p |
| |
| type Numeric interface{ |
| ~int | ~float64 // etc... |
| } |
| |
| func Square[N Numeric](n N) N { |
| return n*n |
| } |
| |
| type Findable interface { |
| comparable |
| } |
| |
| func Find[T Findable](s []T, v T) int { |
| for i, v2 := range s { |
| if v2 == v { |
| return i |
| } |
| } |
| return -1 |
| } |
| //!-input |
| ` |
| |
| // !+printsyntax |
| func PrintNumericSyntax(fset *token.FileSet, file *ast.File) { |
| // node is the AST node corresponding to the declaration for "Numeric." |
| node := file.Scope.Lookup("Numeric").Decl.(*ast.TypeSpec) |
| // Find the embedded syntax node. |
| embedded := node.Type.(*ast.InterfaceType).Methods.List[0].Type |
| // Use go/ast's built-in Print function to inspect the parsed syntax. |
| ast.Print(fset, embedded) |
| } |
| |
| //!-printsyntax |
| |
| /* |
| //!+outputsyntax |
| 0 *ast.BinaryExpr { |
| 1 . X: *ast.UnaryExpr { |
| 2 . . OpPos: p.go:6:2 |
| 3 . . Op: ~ |
| 4 . . X: *ast.Ident { |
| 5 . . . NamePos: p.go:6:3 |
| 6 . . . Name: "int" |
| 7 . . } |
| 8 . } |
| 9 . OpPos: p.go:6:7 |
| 10 . Op: | |
| 11 . Y: *ast.UnaryExpr { |
| 12 . . OpPos: p.go:6:9 |
| 13 . . Op: ~ |
| 14 . . X: *ast.Ident { |
| 15 . . . NamePos: p.go:6:10 |
| 16 . . . Name: "float64" |
| 17 . . } |
| 18 . } |
| 19 } |
| //!-outputsyntax |
| */ |
| |
| // !+printtypes |
| func PrintInterfaceTypes(fset *token.FileSet, file *ast.File) error { |
| conf := types.Config{} |
| pkg, err := conf.Check("hello", fset, []*ast.File{file}, nil) |
| if err != nil { |
| return err |
| } |
| |
| PrintIface(pkg, "Numeric") |
| PrintIface(pkg, "Findable") |
| |
| return nil |
| } |
| |
| func PrintIface(pkg *types.Package, name string) { |
| obj := pkg.Scope().Lookup(name) |
| fmt.Println(obj) |
| iface := obj.Type().Underlying().(*types.Interface) |
| for i := 0; i < iface.NumEmbeddeds(); i++ { |
| fmt.Printf("\tembeded: %s\n", iface.EmbeddedType(i)) |
| } |
| for i := 0; i < iface.NumMethods(); i++ { |
| fmt.Printf("\tembeded: %s\n", iface.EmbeddedType(i)) |
| } |
| fmt.Printf("\tIsComparable(): %t\n", iface.IsComparable()) |
| fmt.Printf("\tIsMethodSet(): %t\n", iface.IsMethodSet()) |
| } |
| |
| //!-printtypes |
| |
| /* |
| //!+outputtypes |
| type hello.Numeric interface{~int|~float64} |
| embeded: ~int|~float64 |
| IsComparable(): true |
| IsMethodSet(): false |
| type hello.Findable interface{comparable} |
| embeded: comparable |
| IsComparable(): true |
| IsMethodSet(): false |
| //!-outputtypes |
| */ |
| |
| func main() { |
| // Parse one file. |
| fset := token.NewFileSet() |
| f, err := parser.ParseFile(fset, "p.go", src, 0) |
| if err != nil { |
| log.Fatal(err) |
| } |
| fmt.Println("=== PrintNumericSyntax ==") |
| PrintNumericSyntax(fset, f) |
| fmt.Println("=== PrintInterfaceTypes ==") |
| if err := PrintInterfaceTypes(fset, f); err != nil { |
| log.Fatal(err) |
| } |
| } |