Source file src/go/types/instantiate_test.go

     1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
     2  
     3  // Copyright 2021 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  package types_test
     7  
     8  import (
     9  	. "go/types"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestInstantiateEquality(t *testing.T) {
    15  	emptySignature := NewSignatureType(nil, nil, nil, nil, nil, false)
    16  	tests := []struct {
    17  		src       string
    18  		name1     string
    19  		targs1    []Type
    20  		name2     string
    21  		targs2    []Type
    22  		wantEqual bool
    23  	}{
    24  		{
    25  			"package basictype; type T[P any] int",
    26  			"T", []Type{Typ[Int]},
    27  			"T", []Type{Typ[Int]},
    28  			true,
    29  		},
    30  		{
    31  			"package differenttypeargs; type T[P any] int",
    32  			"T", []Type{Typ[Int]},
    33  			"T", []Type{Typ[String]},
    34  			false,
    35  		},
    36  		{
    37  			"package typeslice; type T[P any] int",
    38  			"T", []Type{NewSlice(Typ[Int])},
    39  			"T", []Type{NewSlice(Typ[Int])},
    40  			true,
    41  		},
    42  		{
    43  			// interface{interface{...}} is equivalent to interface{...}
    44  			"package equivalentinterfaces; type T[P any] int",
    45  			"T", []Type{
    46  				NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
    47  			},
    48  			"T", []Type{
    49  				NewInterfaceType(
    50  					nil,
    51  					[]Type{
    52  						NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
    53  					},
    54  				),
    55  			},
    56  			true,
    57  		},
    58  		{
    59  			// int|string is equivalent to string|int
    60  			"package equivalenttypesets; type T[P any] int",
    61  			"T", []Type{
    62  				NewInterfaceType(nil, []Type{
    63  					NewUnion([]*Term{NewTerm(false, Typ[Int]), NewTerm(false, Typ[String])}),
    64  				}),
    65  			},
    66  			"T", []Type{
    67  				NewInterfaceType(nil, []Type{
    68  					NewUnion([]*Term{NewTerm(false, Typ[String]), NewTerm(false, Typ[Int])}),
    69  				}),
    70  			},
    71  			true,
    72  		},
    73  		{
    74  			"package basicfunc; func F[P any]() {}",
    75  			"F", []Type{Typ[Int]},
    76  			"F", []Type{Typ[Int]},
    77  			true,
    78  		},
    79  		{
    80  			"package funcslice; func F[P any]() {}",
    81  			"F", []Type{NewSlice(Typ[Int])},
    82  			"F", []Type{NewSlice(Typ[Int])},
    83  			true,
    84  		},
    85  		{
    86  			"package funcwithparams; func F[P any](x string) float64 { return 0 }",
    87  			"F", []Type{Typ[Int]},
    88  			"F", []Type{Typ[Int]},
    89  			true,
    90  		},
    91  		{
    92  			"package differentfuncargs; func F[P any](x string) float64 { return 0 }",
    93  			"F", []Type{Typ[Int]},
    94  			"F", []Type{Typ[String]},
    95  			false,
    96  		},
    97  		{
    98  			"package funcequality; func F1[P any](x int) {}; func F2[Q any](x int) {}",
    99  			"F1", []Type{Typ[Int]},
   100  			"F2", []Type{Typ[Int]},
   101  			false,
   102  		},
   103  		{
   104  			"package funcsymmetry; func F1[P any](x P) {}; func F2[Q any](x Q) {}",
   105  			"F1", []Type{Typ[Int]},
   106  			"F2", []Type{Typ[Int]},
   107  			false,
   108  		},
   109  	}
   110  
   111  	for _, test := range tests {
   112  		pkg := mustTypecheck(test.src, nil, nil)
   113  
   114  		t.Run(pkg.Name(), func(t *testing.T) {
   115  			ctxt := NewContext()
   116  
   117  			T1 := pkg.Scope().Lookup(test.name1).Type()
   118  			res1, err := Instantiate(ctxt, T1, test.targs1, false)
   119  			if err != nil {
   120  				t.Fatal(err)
   121  			}
   122  
   123  			T2 := pkg.Scope().Lookup(test.name2).Type()
   124  			res2, err := Instantiate(ctxt, T2, test.targs2, false)
   125  			if err != nil {
   126  				t.Fatal(err)
   127  			}
   128  
   129  			if gotEqual := res1 == res2; gotEqual != test.wantEqual {
   130  				t.Errorf("%s == %s: %t, want %t", res1, res2, gotEqual, test.wantEqual)
   131  			}
   132  		})
   133  	}
   134  }
   135  
   136  func TestInstantiateNonEquality(t *testing.T) {
   137  	const src = "package p; type T[P any] int"
   138  	pkg1 := mustTypecheck(src, nil, nil)
   139  	pkg2 := mustTypecheck(src, nil, nil)
   140  	// We consider T1 and T2 to be distinct types, so their instances should not
   141  	// be deduplicated by the context.
   142  	T1 := pkg1.Scope().Lookup("T").Type().(*Named)
   143  	T2 := pkg2.Scope().Lookup("T").Type().(*Named)
   144  	ctxt := NewContext()
   145  	res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	if res1 == res2 {
   154  		t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
   155  	}
   156  	if Identical(res1, res2) {
   157  		t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
   158  	}
   159  }
   160  
   161  func TestMethodInstantiation(t *testing.T) {
   162  	const prefix = `package p
   163  
   164  type T[P any] struct{}
   165  
   166  var X T[int]
   167  
   168  `
   169  	tests := []struct {
   170  		decl string
   171  		want string
   172  	}{
   173  		{"func (r T[P]) m() P", "func (T[int]).m() int"},
   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() T[P]", "func (T[int]).m() T[int]"},
   177  		{"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
   178  		{"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
   179  		{"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
   180  	}
   181  
   182  	for _, test := range tests {
   183  		src := prefix + test.decl
   184  		pkg := mustTypecheck(src, nil, nil)
   185  		typ := NewPointer(pkg.Scope().Lookup("X").Type())
   186  		obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
   187  		m, _ := obj.(*Func)
   188  		if m == nil {
   189  			t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
   190  		}
   191  		if got := ObjectString(m, 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  	obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
   209  	if obj == nil {
   210  		t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
   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(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  

View as plain text