github.com/AndrienkoAleksandr/go@v0.0.19/src/go/types/instantiate_test.go (about) 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 }