instantiate_test.go raw

   1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
   2  // Source: ../../cmd/compile/internal/types2/instantiate_test.go
   3  
   4  // Copyright 2021 The Go Authors. All rights reserved.
   5  // Use of this source code is governed by a BSD-style
   6  // license that can be found in the LICENSE file.
   7  package types_test
   8  
   9  import (
  10  	. "go/types"
  11  	"strings"
  12  	"testing"
  13  )
  14  
  15  func TestInstantiateEquality(t *testing.T) {
  16  	emptySignature := NewSignatureType(nil, nil, nil, nil, nil, false)
  17  	tests := []struct {
  18  		src       string
  19  		name1     string
  20  		targs1    []Type
  21  		name2     string
  22  		targs2    []Type
  23  		wantEqual bool
  24  	}{
  25  		{
  26  			"package basictype; type T[P any] int",
  27  			"T", []Type{Typ[Int]},
  28  			"T", []Type{Typ[Int]},
  29  			true,
  30  		},
  31  		{
  32  			"package differenttypeargs; type T[P any] int",
  33  			"T", []Type{Typ[Int]},
  34  			"T", []Type{Typ[String]},
  35  			false,
  36  		},
  37  		{
  38  			"package typeslice; type T[P any] int",
  39  			"T", []Type{NewSlice(Typ[Int])},
  40  			"T", []Type{NewSlice(Typ[Int])},
  41  			true,
  42  		},
  43  		{
  44  			// interface{interface{...}} is equivalent to interface{...}
  45  			"package equivalentinterfaces; type T[P any] int",
  46  			"T", []Type{
  47  				NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
  48  			},
  49  			"T", []Type{
  50  				NewInterfaceType(
  51  					nil,
  52  					[]Type{
  53  						NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
  54  					},
  55  				),
  56  			},
  57  			true,
  58  		},
  59  		{
  60  			// int|string is equivalent to string|int
  61  			"package equivalenttypesets; type T[P any] int",
  62  			"T", []Type{
  63  				NewInterfaceType(nil, []Type{
  64  					NewUnion([]*Term{NewTerm(false, Typ[Int]), NewTerm(false, Typ[String])}),
  65  				}),
  66  			},
  67  			"T", []Type{
  68  				NewInterfaceType(nil, []Type{
  69  					NewUnion([]*Term{NewTerm(false, Typ[String]), NewTerm(false, Typ[Int])}),
  70  				}),
  71  			},
  72  			true,
  73  		},
  74  		{
  75  			"package basicfunc; func F[P any]() {}",
  76  			"F", []Type{Typ[Int]},
  77  			"F", []Type{Typ[Int]},
  78  			true,
  79  		},
  80  		{
  81  			"package funcslice; func F[P any]() {}",
  82  			"F", []Type{NewSlice(Typ[Int])},
  83  			"F", []Type{NewSlice(Typ[Int])},
  84  			true,
  85  		},
  86  		{
  87  			"package funcwithparams; func F[P any](x string) float64 { return 0 }",
  88  			"F", []Type{Typ[Int]},
  89  			"F", []Type{Typ[Int]},
  90  			true,
  91  		},
  92  		{
  93  			"package differentfuncargs; func F[P any](x string) float64 { return 0 }",
  94  			"F", []Type{Typ[Int]},
  95  			"F", []Type{Typ[String]},
  96  			false,
  97  		},
  98  		{
  99  			"package funcequality; func F1[P any](x int) {}; func F2[Q any](x int) {}",
 100  			"F1", []Type{Typ[Int]},
 101  			"F2", []Type{Typ[Int]},
 102  			false,
 103  		},
 104  		{
 105  			"package funcsymmetry; func F1[P any](x P) {}; func F2[Q any](x Q) {}",
 106  			"F1", []Type{Typ[Int]},
 107  			"F2", []Type{Typ[Int]},
 108  			false,
 109  		},
 110  	}
 111  
 112  	for _, test := range tests {
 113  		pkg := mustTypecheck(test.src, nil, nil)
 114  
 115  		t.Run(pkg.Name(), func(t *testing.T) {
 116  			ctxt := NewContext()
 117  
 118  			T1 := pkg.Scope().Lookup(test.name1).Type()
 119  			res1, err := Instantiate(ctxt, T1, test.targs1, false)
 120  			if err != nil {
 121  				t.Fatal(err)
 122  			}
 123  
 124  			T2 := pkg.Scope().Lookup(test.name2).Type()
 125  			res2, err := Instantiate(ctxt, T2, test.targs2, false)
 126  			if err != nil {
 127  				t.Fatal(err)
 128  			}
 129  
 130  			if gotEqual := res1 == res2; gotEqual != test.wantEqual {
 131  				t.Errorf("%s == %s: %t, want %t", res1, res2, gotEqual, test.wantEqual)
 132  			}
 133  		})
 134  	}
 135  }
 136  
 137  func TestInstantiateNonEquality(t *testing.T) {
 138  	const src = "package p; type T[P any] int"
 139  	pkg1 := mustTypecheck(src, nil, nil)
 140  	pkg2 := mustTypecheck(src, nil, nil)
 141  	// We consider T1 and T2 to be distinct types, so their instances should not
 142  	// be deduplicated by the context.
 143  	T1 := pkg1.Scope().Lookup("T").Type().(*Named)
 144  	T2 := pkg2.Scope().Lookup("T").Type().(*Named)
 145  	ctxt := NewContext()
 146  	res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
 147  	if err != nil {
 148  		t.Fatal(err)
 149  	}
 150  	res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
 151  	if err != nil {
 152  		t.Fatal(err)
 153  	}
 154  	if res1 == res2 {
 155  		t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
 156  	}
 157  	if Identical(res1, res2) {
 158  		t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
 159  	}
 160  }
 161  
 162  func TestMethodInstantiation(t *testing.T) {
 163  	const prefix = `package p
 164  
 165  type T[P any] struct{}
 166  
 167  var X T[int]
 168  
 169  `
 170  	tests := []struct {
 171  		decl string
 172  		want string
 173  	}{
 174  		{"func (r T[P]) m() P", "func (T[int]).m() int"},
 175  		{"func (r T[P]) m(P)", "func (T[int]).m(int)"},
 176  		{"func (r *T[P]) m(P)", "func (*T[int]).m(int)"},
 177  		{"func (r T[P]) m() T[P]", "func (T[int]).m() T[int]"},
 178  		{"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
 179  		{"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
 180  		{"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
 181  	}
 182  
 183  	for _, test := range tests {
 184  		src := prefix + test.decl
 185  		pkg := mustTypecheck(src, nil, nil)
 186  		typ := NewPointer(pkg.Scope().Lookup("X").Type())
 187  		sel, ok := LookupSelection(typ, false, pkg, "m")
 188  		if !ok {
 189  			t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
 190  		}
 191  		if got := ObjectString(sel.Obj(), RelativeTo(pkg)); got != test.want {
 192  			t.Errorf("instantiated %q, want %q", got, test.want)
 193  		}
 194  	}
 195  }
 196  
 197  func TestImmutableSignatures(t *testing.T) {
 198  	const src = `package p
 199  
 200  type T[P any] struct{}
 201  
 202  func (T[P]) m() {}
 203  
 204  var _ T[int]
 205  `
 206  	pkg := mustTypecheck(src, nil, nil)
 207  	typ := pkg.Scope().Lookup("T").Type().(*Named)
 208  	sel, ok := LookupSelection(typ, false, pkg, "m")
 209  	if !ok {
 210  		t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
 211  	}
 212  
 213  	// Verify that the original method is not mutated by instantiating T (this
 214  	// bug manifested when subst did not return a new signature).
 215  	want := "func (T[P]).m()"
 216  	if got := stripAnnotations(ObjectString(sel.Obj(), RelativeTo(pkg))); got != want {
 217  		t.Errorf("instantiated %q, want %q", got, want)
 218  	}
 219  }
 220  
 221  // Copied from errors.go.
 222  func stripAnnotations(s string) string {
 223  	var buf strings.Builder
 224  	for _, r := range s {
 225  		// strip #'s and subscript digits
 226  		if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
 227  			buf.WriteRune(r)
 228  		}
 229  	}
 230  	if buf.Len() < len(s) {
 231  		return buf.String()
 232  	}
 233  	return s
 234  }
 235