Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/types/methodset_test.go

Documentation: go/types

     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/internal/typeparams"
    11  	. "go/types"
    12  )
    13  
    14  func TestNewMethodSet(t *testing.T) {
    15  	type method struct {
    16  		name     string
    17  		index    []int
    18  		indirect bool
    19  	}
    20  
    21  	// Tests are expressed src -> methods, for simplifying the composite literal.
    22  	// Should be kept in sync with TestLookupFieldOrMethod.
    23  	tests := map[string][]method{
    24  		// Named types
    25  		"var a T; type T struct{}; func (T) f() {}":   {{"f", []int{0}, false}},
    26  		"var a *T; type T struct{}; func (T) f() {}":  {{"f", []int{0}, true}},
    27  		"var a T; type T struct{}; func (*T) f() {}":  {},
    28  		"var a *T; type T struct{}; func (*T) f() {}": {{"f", []int{0}, true}},
    29  
    30  		// Interfaces
    31  		"var a T; type T interface{ f() }":                           {{"f", []int{0}, true}},
    32  		"var a T1; type ( T1 T2; T2 interface{ f() } )":              {{"f", []int{0}, true}},
    33  		"var a T1; type ( T1 interface{ T2 }; T2 interface{ f() } )": {{"f", []int{0}, true}},
    34  
    35  		// Embedding
    36  		"var a struct{ E }; type E interface{ f() }":            {{"f", []int{0, 0}, true}},
    37  		"var a *struct{ E }; type E interface{ f() }":           {{"f", []int{0, 0}, true}},
    38  		"var a struct{ E }; type E struct{}; func (E) f() {}":   {{"f", []int{0, 0}, false}},
    39  		"var a struct{ *E }; type E struct{}; func (E) f() {}":  {{"f", []int{0, 0}, true}},
    40  		"var a struct{ E }; type E struct{}; func (*E) f() {}":  {},
    41  		"var a struct{ *E }; type E struct{}; func (*E) f() {}": {{"f", []int{0, 0}, true}},
    42  
    43  		// collisions
    44  		"var a struct{ E1; *E2 }; type ( E1 interface{ f() }; E2 struct{ f int })":            {},
    45  		"var a struct{ E1; *E2 }; type ( E1 struct{ f int }; E2 struct{} ); func (E2) f() {}": {},
    46  	}
    47  
    48  	genericTests := map[string][]method{
    49  		// By convention, look up a in the scope of "g"
    50  		"type C interface{ f() }; func g[T C](a T){}":                       {{"f", []int{0}, true}},
    51  		"type C interface{ f() }; func g[T C]() { var a T; _ = a }":         {{"f", []int{0}, true}},
    52  		"type C interface{ f() }; func g[T C]() { var a struct{T}; _ = a }": {{"f", []int{0, 0}, true}},
    53  
    54  		// Issue #45639.
    55  		"type C interface{ f() }; func g[T C]() { type Y T; var a Y; _ = a }": {},
    56  	}
    57  
    58  	check := func(src string, methods []method, generic bool) {
    59  		pkgName := "p"
    60  		if generic {
    61  			// The generic_ prefix causes pkgFor to allow generic code.
    62  			pkgName = "generic_p"
    63  		}
    64  		pkg, err := pkgFor("test", "package "+pkgName+";"+src, nil)
    65  		if err != nil {
    66  			t.Errorf("%s: incorrect test case: %s", src, err)
    67  			return
    68  		}
    69  
    70  		scope := pkg.Scope()
    71  		if generic {
    72  			fn := pkg.Scope().Lookup("g").(*Func)
    73  			scope = fn.Scope()
    74  		}
    75  		obj := scope.Lookup("a")
    76  		if obj == nil {
    77  			t.Errorf("%s: incorrect test case - no object a", src)
    78  			return
    79  		}
    80  
    81  		ms := NewMethodSet(obj.Type())
    82  		if got, want := ms.Len(), len(methods); got != want {
    83  			t.Errorf("%s: got %d methods, want %d", src, got, want)
    84  			return
    85  		}
    86  		for i, m := range methods {
    87  			sel := ms.At(i)
    88  			if got, want := sel.Obj().Name(), m.name; got != want {
    89  				t.Errorf("%s [method %d]: got name = %q at, want %q", src, i, got, want)
    90  			}
    91  			if got, want := sel.Index(), m.index; !sameSlice(got, want) {
    92  				t.Errorf("%s [method %d]: got index = %v, want %v", src, i, got, want)
    93  			}
    94  			if got, want := sel.Indirect(), m.indirect; got != want {
    95  				t.Errorf("%s [method %d]: got indirect = %v, want %v", src, i, got, want)
    96  			}
    97  		}
    98  	}
    99  
   100  	for src, methods := range tests {
   101  		check(src, methods, false)
   102  	}
   103  
   104  	if typeparams.Enabled {
   105  		for src, methods := range genericTests {
   106  			check(src, methods, true)
   107  		}
   108  	}
   109  }
   110  

View as plain text