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  }