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