github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/refactor/satisfy/find_test.go (about)

     1  // Copyright 2022 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 satisfy_test
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/importer"
    11  	"go/parser"
    12  	"go/token"
    13  	"go/types"
    14  	"reflect"
    15  	"sort"
    16  	"testing"
    17  
    18  	"golang.org/x/tools/internal/typeparams"
    19  	"golang.org/x/tools/refactor/satisfy"
    20  )
    21  
    22  // This test exercises various operations on core types of type parameters.
    23  // (It also provides pretty decent coverage of the non-generic operations.)
    24  func TestGenericCoreOperations(t *testing.T) {
    25  	if !typeparams.Enabled {
    26  		t.Skip("!typeparams.Enabled")
    27  	}
    28  
    29  	const src = `package foo
    30  
    31  import "unsafe"
    32  
    33  type I interface { f() }
    34  
    35  type impl struct{}
    36  func (impl) f() {}
    37  
    38  // A big pile of single-serving types that implement I.
    39  type A struct{impl}
    40  type B struct{impl}
    41  type C struct{impl}
    42  type D struct{impl}
    43  type E struct{impl}
    44  type F struct{impl}
    45  type G struct{impl}
    46  type H struct{impl}
    47  type J struct{impl}
    48  type K struct{impl}
    49  type L struct{impl}
    50  type M struct{impl}
    51  type N struct{impl}
    52  type O struct{impl}
    53  type P struct{impl}
    54  type Q struct{impl}
    55  type R struct{impl}
    56  type S struct{impl}
    57  type T struct{impl}
    58  type U struct{impl}
    59  type V struct{impl}
    60  
    61  type Generic[T any] struct{impl}
    62  func (Generic[T]) g(T) {}
    63  
    64  type GI[T any] interface{
    65  	g(T)
    66  }
    67  
    68  func _[Slice interface{ []I }](s Slice) Slice {
    69  	s[0] = L{} // I <- L
    70  	return append(s, A{}) // I <- A
    71  }
    72  
    73  func _[Func interface{ func(I) B }](fn Func) {
    74  	b := fn(C{}) // I <- C
    75  	var _ I = b // I <- B
    76  }
    77  
    78  func _[Chan interface{ chan D }](ch Chan) {
    79  	var i I
    80  	for i = range ch {} // I <- D
    81  	_ = i
    82  }
    83  
    84  func _[Chan interface{ chan E }](ch Chan) {
    85  	var _ I = <-ch // I <- E
    86  }
    87  
    88  func _[Chan interface{ chan I }](ch Chan) {
    89  	ch <- F{} // I <- F
    90  }
    91  
    92  func _[Map interface{ map[G]H }](m Map) {
    93  	var k, v I
    94  	for k, v = range m {} // I <- G, I <- H
    95  	_, _ = k, v
    96  }
    97  
    98  func _[Map interface{ map[I]K }](m Map) {
    99  	var _ I = m[J{}] // I <- J, I <- K
   100  	delete(m, R{}) // I <- R
   101  	_, _ = m[J{}]
   102  }
   103  
   104  func _[Array interface{ [1]I }](a Array) {
   105  	a[0] = M{} // I <- M
   106  }
   107  
   108  func _[Array interface{ [1]N }](a Array) {
   109  	var _ I = a[0] // I <- N
   110  }
   111  
   112  func _[Array interface{ [1]O }](a Array) {
   113  	var v I
   114  	for _, v = range a {} // I <- O
   115  	_ = v
   116  }
   117  
   118  func _[ArrayPtr interface{ *[1]P }](a ArrayPtr) {
   119  	var v I
   120  	for _, v = range a {} // I <- P
   121  	_ = v
   122  }
   123  
   124  func _[Slice interface{ []Q }](s Slice) {
   125  	var v I
   126  	for _, v = range s {} // I <- Q
   127  	_ = v
   128  }
   129  
   130  func _[Func interface{ func() (S, bool) }](fn Func) {
   131  	var i I
   132  	i, _ = fn() // I <- S
   133  	_ = i
   134  }
   135  
   136  func _() I {
   137  	var _ I = T{} // I <- T
   138  	var _ I = Generic[T]{} // I <- Generic[T]
   139  	var _ I = Generic[string]{} // I <- Generic[string]
   140  	return U{} // I <- U
   141  }
   142  
   143  var _ GI[string] = Generic[string]{} //  GI[string] <- Generic[string]
   144  
   145  // universally quantified constraints:
   146  // the type parameter may appear on the left, the right, or both sides.
   147  
   148  func  _[T any](g Generic[T]) GI[T] {
   149  	return g // GI[T] <- Generic[T]
   150  }
   151  
   152  func  _[T any]() {
   153  	type GI2[T any] interface{ g(string) }
   154  	var _ GI2[T] = Generic[string]{} // GI2[T] <- Generic[string]
   155  }
   156  
   157  type Gen2[T any] struct{}
   158  func (f Gen2[T]) g(string) { global = f } // GI[string] <- Gen2[T]
   159  
   160  var global GI[string]
   161  
   162  func _() {
   163  	var x [3]V
   164  	// golang/go#56227: the finder should visit calls in the unsafe package.
   165  	_ = unsafe.Slice(&x[0], func() int { var _ I = x[0]; return 3 }()) // I <- V
   166  }
   167  `
   168  	got := constraints(t, src)
   169  	want := []string{
   170  		"p.GI2[T] <- p.Generic[string]", // implicitly "forall T" quantified
   171  		"p.GI[T] <- p.Generic[T]",       // implicitly "forall T" quantified
   172  		"p.GI[string] <- p.Gen2[T]",     // implicitly "forall T" quantified
   173  		"p.GI[string] <- p.Generic[string]",
   174  		"p.I <- p.A",
   175  		"p.I <- p.B",
   176  		"p.I <- p.C",
   177  		"p.I <- p.D",
   178  		"p.I <- p.E",
   179  		"p.I <- p.F",
   180  		"p.I <- p.G",
   181  		"p.I <- p.Generic[p.T]",
   182  		"p.I <- p.Generic[string]",
   183  		"p.I <- p.H",
   184  		"p.I <- p.J",
   185  		"p.I <- p.K",
   186  		"p.I <- p.L",
   187  		"p.I <- p.M",
   188  		"p.I <- p.N",
   189  		"p.I <- p.O",
   190  		"p.I <- p.P",
   191  		"p.I <- p.Q",
   192  		"p.I <- p.R",
   193  		"p.I <- p.S",
   194  		"p.I <- p.T",
   195  		"p.I <- p.U",
   196  		"p.I <- p.V",
   197  	}
   198  	if !reflect.DeepEqual(got, want) {
   199  		t.Fatalf("found unexpected constraints: got %s, want %s", got, want)
   200  	}
   201  }
   202  
   203  func constraints(t *testing.T, src string) []string {
   204  	// parse
   205  	fset := token.NewFileSet()
   206  	f, err := parser.ParseFile(fset, "p.go", src, 0)
   207  	if err != nil {
   208  		t.Fatal(err) // parse error
   209  	}
   210  	files := []*ast.File{f}
   211  
   212  	// type-check
   213  	info := &types.Info{
   214  		Types:      make(map[ast.Expr]types.TypeAndValue),
   215  		Defs:       make(map[*ast.Ident]types.Object),
   216  		Uses:       make(map[*ast.Ident]types.Object),
   217  		Implicits:  make(map[ast.Node]types.Object),
   218  		Scopes:     make(map[ast.Node]*types.Scope),
   219  		Selections: make(map[*ast.SelectorExpr]*types.Selection),
   220  	}
   221  	typeparams.InitInstanceInfo(info)
   222  	conf := types.Config{
   223  		Importer: importer.Default(),
   224  	}
   225  	if _, err := conf.Check("p", fset, files, info); err != nil {
   226  		t.Fatal(err) // type error
   227  	}
   228  
   229  	// gather constraints
   230  	var finder satisfy.Finder
   231  	finder.Find(info, files)
   232  	var constraints []string
   233  	for c := range finder.Result {
   234  		constraints = append(constraints, fmt.Sprintf("%v <- %v", c.LHS, c.RHS))
   235  	}
   236  	sort.Strings(constraints)
   237  	return constraints
   238  }