| // 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" | |
| "golang.org/x/exp/typeparams" | |
| ) | |
| const src = ` | |
| //!+input | |
| package p | |
| type Pair[L, R any] struct { | |
| left L | |
| right R | |
| } | |
| func (p Pair[L, _]) Left() L { | |
| return p.left | |
| } | |
| func (p Pair[_, R]) Right() R { | |
| return p.right | |
| } | |
| var IntPair Pair[int, int] | |
| //!-input | |
| ` | |
| // !+printmethods | |
| func PrintMethods(pkg *types.Package) { | |
| // Look up *Named types in the package scope. | |
| lookup := func(name string) *types.Named { | |
| return pkg.Scope().Lookup(name).Type().(*types.Named) | |
| } | |
| Pair := lookup("Pair") | |
| IntPair := lookup("IntPair") | |
| PrintMethodSet("Pair", Pair) | |
| PrintMethodSet("Pair[int, int]", IntPair) | |
| LeftObj, _, _ := types.LookupFieldOrMethod(Pair, false, pkg, "Left") | |
| LeftRecvType := LeftObj.Type().(*types.Signature).Recv().Type() | |
| PrintMethodSet("Pair[L, _]", LeftRecvType) | |
| } | |
| func PrintMethodSet(name string, typ types.Type) { | |
| fmt.Println(name + ":") | |
| methodSet := types.NewMethodSet(typ) | |
| for i := 0; i < methodSet.Len(); i++ { | |
| method := methodSet.At(i).Obj() | |
| fmt.Println(method) | |
| } | |
| fmt.Println() | |
| } | |
| //!-printmethods | |
| /* | |
| //!+printoutput | |
| Pair: | |
| func (p.Pair[L, _]).Left() L | |
| func (p.Pair[_, R]).Right() R | |
| Pair[int, int]: | |
| func (p.Pair[int, int]).Left() int | |
| func (p.Pair[int, int]).Right() int | |
| Pair[L, _]: | |
| func (p.Pair[L, _]).Left() L | |
| func (p.Pair[L, _]).Right() _ | |
| //!-printoutput | |
| */ | |
| // !+compareorigins | |
| func CompareOrigins(pkg *types.Package) { | |
| Pair := pkg.Scope().Lookup("Pair").Type().(*types.Named) | |
| IntPair := pkg.Scope().Lookup("IntPair").Type().(*types.Named) | |
| Left, _, _ := types.LookupFieldOrMethod(Pair, false, pkg, "Left") | |
| LeftInt, _, _ := types.LookupFieldOrMethod(IntPair, false, pkg, "Left") | |
| fmt.Println("Pair.Left == Pair[int, int].Left:", Left == LeftInt) | |
| origin := typeparams.OriginMethod(LeftInt.(*types.Func)) | |
| fmt.Println("Pair.Left == OriginMethod(Pair[int, int].Left):", Left == origin) | |
| } | |
| //!-compareorigins | |
| /* | |
| //!+compareoutput | |
| Pair.Left == Pair[int, int].Left: false | |
| Pair.Left == OriginMethod(Pair[int, int].Left): true | |
| //!-compareoutput | |
| */ | |
| func main() { | |
| fset := token.NewFileSet() | |
| f, err := parser.ParseFile(fset, "hello.go", src, 0) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| conf := types.Config{} | |
| pkg, err := conf.Check("p", fset, []*ast.File{f}, nil) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| fmt.Println("=== PrintMethods ===") | |
| PrintMethods(pkg) | |
| fmt.Println("=== CompareOrigins ===") | |
| CompareOrigins(pkg) | |
| } |