methodset_test.go raw

   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  	"slices"
   9  	"strings"
  10  	"testing"
  11  
  12  	"go/ast"
  13  	"go/parser"
  14  	"go/token"
  15  	. "go/types"
  16  )
  17  
  18  func TestNewMethodSet(t *testing.T) {
  19  	type method struct {
  20  		name     string
  21  		index    []int
  22  		indirect bool
  23  	}
  24  
  25  	// Tests are expressed src -> methods, for simplifying the composite literal.
  26  	// Should be kept in sync with TestLookupFieldOrMethod.
  27  	tests := map[string][]method{
  28  		// Named types
  29  		"var a T; type T struct{}; func (T) f() {}":   {{"f", []int{0}, false}},
  30  		"var a *T; type T struct{}; func (T) f() {}":  {{"f", []int{0}, true}},
  31  		"var a T; type T struct{}; func (*T) f() {}":  {},
  32  		"var a *T; type T struct{}; func (*T) f() {}": {{"f", []int{0}, true}},
  33  
  34  		// Generic named types
  35  		"var a T[int]; type T[P any] struct{}; func (T[P]) f() {}":   {{"f", []int{0}, false}},
  36  		"var a *T[int]; type T[P any] struct{}; func (T[P]) f() {}":  {{"f", []int{0}, true}},
  37  		"var a T[int]; type T[P any] struct{}; func (*T[P]) f() {}":  {},
  38  		"var a *T[int]; type T[P any] struct{}; func (*T[P]) f() {}": {{"f", []int{0}, true}},
  39  
  40  		// Interfaces
  41  		"var a T; type T interface{ f() }":                           {{"f", []int{0}, true}},
  42  		"var a T1; type ( T1 T2; T2 interface{ f() } )":              {{"f", []int{0}, true}},
  43  		"var a T1; type ( T1 interface{ T2 }; T2 interface{ f() } )": {{"f", []int{0}, true}},
  44  
  45  		// Generic interfaces
  46  		"var a T[int]; type T[P any] interface{ f() }":                                     {{"f", []int{0}, true}},
  47  		"var a T1[int]; type ( T1[P any] T2[P]; T2[P any] interface{ f() } )":              {{"f", []int{0}, true}},
  48  		"var a T1[int]; type ( T1[P any] interface{ T2[P] }; T2[P any] interface{ f() } )": {{"f", []int{0}, true}},
  49  
  50  		// Embedding
  51  		"var a struct{ E }; type E interface{ f() }":            {{"f", []int{0, 0}, true}},
  52  		"var a *struct{ E }; type E interface{ f() }":           {{"f", []int{0, 0}, true}},
  53  		"var a struct{ E }; type E struct{}; func (E) f() {}":   {{"f", []int{0, 0}, false}},
  54  		"var a struct{ *E }; type E struct{}; func (E) f() {}":  {{"f", []int{0, 0}, true}},
  55  		"var a struct{ E }; type E struct{}; func (*E) f() {}":  {},
  56  		"var a struct{ *E }; type E struct{}; func (*E) f() {}": {{"f", []int{0, 0}, true}},
  57  
  58  		// Embedding of generic types
  59  		"var a struct{ E[int] }; type E[P any] interface{ f() }":               {{"f", []int{0, 0}, true}},
  60  		"var a *struct{ E[int] }; type E[P any] interface{ f() }":              {{"f", []int{0, 0}, true}},
  61  		"var a struct{ E[int] }; type E[P any] struct{}; func (E[P]) f() {}":   {{"f", []int{0, 0}, false}},
  62  		"var a struct{ *E[int] }; type E[P any] struct{}; func (E[P]) f() {}":  {{"f", []int{0, 0}, true}},
  63  		"var a struct{ E[int] }; type E[P any] struct{}; func (*E[P]) f() {}":  {},
  64  		"var a struct{ *E[int] }; type E[P any] struct{}; func (*E[P]) f() {}": {{"f", []int{0, 0}, true}},
  65  
  66  		// collisions
  67  		"var a struct{ E1; *E2 }; type ( E1 interface{ f() }; E2 struct{ f int })":            {},
  68  		"var a struct{ E1; *E2 }; type ( E1 struct{ f int }; E2 struct{} ); func (E2) f() {}": {},
  69  
  70  		// recursive generic types; see go.dev/issue/52715
  71  		"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}},
  72  		"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}},
  73  	}
  74  
  75  	tParamTests := map[string][]method{
  76  		// By convention, look up a in the scope of "g"
  77  		"type C interface{ f() }; func g[T C](a T){}":               {{"f", []int{0}, true}},
  78  		"type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}},
  79  
  80  		// go.dev/issue/43621: We don't allow this anymore. Keep this code in case we
  81  		// decide to revisit this decision.
  82  		// "type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}},
  83  
  84  		// go.dev/issue/45639: We also don't allow this anymore.
  85  		// "type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {},
  86  	}
  87  
  88  	check := func(src string, methods []method, generic bool) {
  89  		pkg := mustTypecheck("package p;"+src, nil, nil)
  90  
  91  		scope := pkg.Scope()
  92  		if generic {
  93  			fn := pkg.Scope().Lookup("g").(*Func)
  94  			scope = fn.Scope()
  95  		}
  96  		obj := scope.Lookup("a")
  97  		if obj == nil {
  98  			t.Errorf("%s: incorrect test case - no object a", src)
  99  			return
 100  		}
 101  
 102  		ms := NewMethodSet(obj.Type())
 103  		if got, want := ms.Len(), len(methods); got != want {
 104  			t.Errorf("%s: got %d methods, want %d", src, got, want)
 105  			return
 106  		}
 107  		for i, m := range methods {
 108  			sel := ms.At(i)
 109  			if got, want := sel.Obj().Name(), m.name; got != want {
 110  				t.Errorf("%s [method %d]: got name = %q at, want %q", src, i, got, want)
 111  			}
 112  			if got, want := sel.Index(), m.index; !slices.Equal(got, want) {
 113  				t.Errorf("%s [method %d]: got index = %v, want %v", src, i, got, want)
 114  			}
 115  			if got, want := sel.Indirect(), m.indirect; got != want {
 116  				t.Errorf("%s [method %d]: got indirect = %v, want %v", src, i, got, want)
 117  			}
 118  		}
 119  	}
 120  
 121  	for src, methods := range tests {
 122  		check(src, methods, false)
 123  	}
 124  
 125  	for src, methods := range tParamTests {
 126  		check(src, methods, true)
 127  	}
 128  }
 129  
 130  // Test for go.dev/issue/52715
 131  func TestNewMethodSet_RecursiveGeneric(t *testing.T) {
 132  	const src = `
 133  package pkg
 134  
 135  type Tree[T any] struct {
 136  	*Node[T]
 137  }
 138  
 139  type Node[T any] struct {
 140  	*Tree[T]
 141  }
 142  
 143  type Instance = *Tree[int]
 144  `
 145  
 146  	fset := token.NewFileSet()
 147  	f, err := parser.ParseFile(fset, "foo.go", src, 0)
 148  	if err != nil {
 149  		panic(err)
 150  	}
 151  	pkg := NewPackage("pkg", f.Name.Name)
 152  	if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
 153  		panic(err)
 154  	}
 155  
 156  	T := pkg.Scope().Lookup("Instance").Type()
 157  	_ = NewMethodSet(T) // verify that NewMethodSet terminates
 158  }
 159  
 160  func TestIssue60634(t *testing.T) {
 161  	const src = `
 162  package p
 163  type T *int
 164  func (T) m() {} // expected error: invalid receiver type
 165  `
 166  
 167  	fset := token.NewFileSet()
 168  	f, err := parser.ParseFile(fset, "p.go", src, 0)
 169  	if err != nil {
 170  		t.Fatal(err)
 171  	}
 172  
 173  	var conf Config
 174  	pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
 175  	if err == nil || !strings.Contains(err.Error(), "invalid receiver type") {
 176  		t.Fatalf("missing or unexpected error: %v", err)
 177  	}
 178  
 179  	// look up T.m and (*T).m
 180  	T := pkg.Scope().Lookup("T").Type()
 181  	name := "m"
 182  	for _, recv := range []Type{T, NewPointer(T)} {
 183  		// LookupFieldOrMethod and NewMethodSet must match:
 184  		// either both find m or neither finds it.
 185  		obj1, _, _ := LookupFieldOrMethod(recv, false, pkg, name)
 186  		mset := NewMethodSet(recv)
 187  		if (obj1 != nil) != (mset.Len() == 1) {
 188  			t.Fatalf("lookup(%v.%s): got obj = %v, mset = %v", recv, name, obj1, mset)
 189  		}
 190  		// If the method exists, both must return the same object.
 191  		if obj1 != nil {
 192  			obj2 := mset.At(0).Obj()
 193  			if obj1 != obj2 {
 194  				t.Fatalf("%v != %v", obj1, obj2)
 195  			}
 196  		}
 197  	}
 198  }
 199