github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/go/types/methodset_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types_test 6 7 import ( 8 "testing" 9 10 "go/ast" 11 "go/parser" 12 "go/token" 13 . "go/types" 14 ) 15 16 func TestNewMethodSet(t *testing.T) { 17 type method struct { 18 name string 19 index []int 20 indirect bool 21 } 22 23 // Tests are expressed src -> methods, for simplifying the composite literal. 24 // Should be kept in sync with TestLookupFieldOrMethod. 25 tests := map[string][]method{ 26 // Named types 27 "var a T; type T struct{}; func (T) f() {}": {{"f", []int{0}, false}}, 28 "var a *T; type T struct{}; func (T) f() {}": {{"f", []int{0}, true}}, 29 "var a T; type T struct{}; func (*T) f() {}": {}, 30 "var a *T; type T struct{}; func (*T) f() {}": {{"f", []int{0}, true}}, 31 32 // Generic named types 33 "var a T[int]; type T[P any] struct{}; func (T[P]) f() {}": {{"f", []int{0}, false}}, 34 "var a *T[int]; type T[P any] struct{}; func (T[P]) f() {}": {{"f", []int{0}, true}}, 35 "var a T[int]; type T[P any] struct{}; func (*T[P]) f() {}": {}, 36 "var a *T[int]; type T[P any] struct{}; func (*T[P]) f() {}": {{"f", []int{0}, true}}, 37 38 // Interfaces 39 "var a T; type T interface{ f() }": {{"f", []int{0}, true}}, 40 "var a T1; type ( T1 T2; T2 interface{ f() } )": {{"f", []int{0}, true}}, 41 "var a T1; type ( T1 interface{ T2 }; T2 interface{ f() } )": {{"f", []int{0}, true}}, 42 43 // Generic interfaces 44 "var a T[int]; type T[P any] interface{ f() }": {{"f", []int{0}, true}}, 45 "var a T1[int]; type ( T1[P any] T2[P]; T2[P any] interface{ f() } )": {{"f", []int{0}, true}}, 46 "var a T1[int]; type ( T1[P any] interface{ T2[P] }; T2[P any] interface{ f() } )": {{"f", []int{0}, true}}, 47 48 // Embedding 49 "var a struct{ E }; type E interface{ f() }": {{"f", []int{0, 0}, true}}, 50 "var a *struct{ E }; type E interface{ f() }": {{"f", []int{0, 0}, true}}, 51 "var a struct{ E }; type E struct{}; func (E) f() {}": {{"f", []int{0, 0}, false}}, 52 "var a struct{ *E }; type E struct{}; func (E) f() {}": {{"f", []int{0, 0}, true}}, 53 "var a struct{ E }; type E struct{}; func (*E) f() {}": {}, 54 "var a struct{ *E }; type E struct{}; func (*E) f() {}": {{"f", []int{0, 0}, true}}, 55 56 // Embedding of generic types 57 "var a struct{ E[int] }; type E[P any] interface{ f() }": {{"f", []int{0, 0}, true}}, 58 "var a *struct{ E[int] }; type E[P any] interface{ f() }": {{"f", []int{0, 0}, true}}, 59 "var a struct{ E[int] }; type E[P any] struct{}; func (E[P]) f() {}": {{"f", []int{0, 0}, false}}, 60 "var a struct{ *E[int] }; type E[P any] struct{}; func (E[P]) f() {}": {{"f", []int{0, 0}, true}}, 61 "var a struct{ E[int] }; type E[P any] struct{}; func (*E[P]) f() {}": {}, 62 "var a struct{ *E[int] }; type E[P any] struct{}; func (*E[P]) f() {}": {{"f", []int{0, 0}, true}}, 63 64 // collisions 65 "var a struct{ E1; *E2 }; type ( E1 interface{ f() }; E2 struct{ f int })": {}, 66 "var a struct{ E1; *E2 }; type ( E1 struct{ f int }; E2 struct{} ); func (E2) f() {}": {}, 67 68 // recursive generic types; see go.dev/issue/52715 69 "var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (N[P]) m() {}": {{"m", []int{0, 0}, true}}, 70 "var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (T[P]) m() {}": {{"m", []int{0}, false}}, 71 } 72 73 tParamTests := map[string][]method{ 74 // By convention, look up a in the scope of "g" 75 "type C interface{ f() }; func g[T C](a T){}": {{"f", []int{0}, true}}, 76 "type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}}, 77 78 // go.dev/issue/43621: We don't allow this anymore. Keep this code in case we 79 // decide to revisit this decision. 80 // "type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}}, 81 82 // go.dev/issue/45639: We also don't allow this anymore. 83 // "type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {}, 84 } 85 86 check := func(src string, methods []method, generic bool) { 87 pkg := mustTypecheck("package p;"+src, nil, nil) 88 89 scope := pkg.Scope() 90 if generic { 91 fn := pkg.Scope().Lookup("g").(*Func) 92 scope = fn.Scope() 93 } 94 obj := scope.Lookup("a") 95 if obj == nil { 96 t.Errorf("%s: incorrect test case - no object a", src) 97 return 98 } 99 100 ms := NewMethodSet(obj.Type()) 101 if got, want := ms.Len(), len(methods); got != want { 102 t.Errorf("%s: got %d methods, want %d", src, got, want) 103 return 104 } 105 for i, m := range methods { 106 sel := ms.At(i) 107 if got, want := sel.Obj().Name(), m.name; got != want { 108 t.Errorf("%s [method %d]: got name = %q at, want %q", src, i, got, want) 109 } 110 if got, want := sel.Index(), m.index; !sameSlice(got, want) { 111 t.Errorf("%s [method %d]: got index = %v, want %v", src, i, got, want) 112 } 113 if got, want := sel.Indirect(), m.indirect; got != want { 114 t.Errorf("%s [method %d]: got indirect = %v, want %v", src, i, got, want) 115 } 116 } 117 } 118 119 for src, methods := range tests { 120 check(src, methods, false) 121 } 122 123 for src, methods := range tParamTests { 124 check(src, methods, true) 125 } 126 } 127 128 // Test for go.dev/issue/52715 129 func TestNewMethodSet_RecursiveGeneric(t *testing.T) { 130 const src = ` 131 package pkg 132 133 type Tree[T any] struct { 134 *Node[T] 135 } 136 137 type Node[T any] struct { 138 *Tree[T] 139 } 140 141 type Instance = *Tree[int] 142 ` 143 144 fset := token.NewFileSet() 145 f, err := parser.ParseFile(fset, "foo.go", src, 0) 146 if err != nil { 147 panic(err) 148 } 149 pkg := NewPackage("pkg", f.Name.Name) 150 if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil { 151 panic(err) 152 } 153 154 T := pkg.Scope().Lookup("Instance").Type() 155 _ = NewMethodSet(T) // verify that NewMethodSet terminates 156 }