github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/internal/typeparams/instance_test.go (about) 1 package typeparams 2 3 import ( 4 "go/types" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/google/go-cmp/cmp/cmpopts" 9 "github.com/gopherjs/gopherjs/internal/srctesting" 10 "github.com/gopherjs/gopherjs/internal/testingx" 11 ) 12 13 func instanceOpts() cmp.Options { 14 return cmp.Options{ 15 // Instances are represented by their IDs for diffing purposes. 16 cmp.Transformer("Instance", func(i Instance) string { 17 return i.String() 18 }), 19 // Order of instances in a slice doesn't matter, sort them by ID. 20 cmpopts.SortSlices(func(a, b Instance) bool { 21 return a.String() < b.String() 22 }), 23 } 24 } 25 26 func TestInstanceString(t *testing.T) { 27 const src = `package testcase 28 29 type Ints []int 30 31 type Typ[T any, V any] []T 32 func (t Typ[T, V]) Method(x T) {} 33 34 type typ[T any, V any] []T 35 func (t typ[T, V]) method(x T) {} 36 37 func Fun[U any, W any](x, y U) {} 38 func fun[U any, W any](x, y U) {} 39 ` 40 f := srctesting.New(t) 41 _, pkg := f.Check("pkg/test", f.Parse("test.go", src)) 42 mustType := testingx.Must[types.Type](t) 43 44 tests := []struct { 45 descr string 46 instance Instance 47 wantStr string 48 wantTypeString string 49 }{{ 50 descr: "exported type", 51 instance: Instance{ 52 Object: pkg.Scope().Lookup("Typ"), 53 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 54 }, 55 wantStr: "pkg/test.Typ<int, string>", 56 wantTypeString: "testcase.Typ[int, string]", 57 }, { 58 descr: "exported method", 59 instance: Instance{ 60 Object: pkg.Scope().Lookup("Typ").Type().(*types.Named).Method(0), 61 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 62 }, 63 wantStr: "pkg/test.Typ.Method<int, string>", 64 }, { 65 descr: "exported function", 66 instance: Instance{ 67 Object: pkg.Scope().Lookup("Fun"), 68 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 69 }, 70 wantStr: "pkg/test.Fun<int, string>", 71 }, { 72 descr: "unexported type", 73 instance: Instance{ 74 Object: pkg.Scope().Lookup("typ"), 75 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 76 }, 77 wantStr: "pkg/test.typ<int, string>", 78 wantTypeString: "testcase.typ[int, string]", 79 }, { 80 descr: "unexported method", 81 instance: Instance{ 82 Object: pkg.Scope().Lookup("typ").Type().(*types.Named).Method(0), 83 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 84 }, 85 wantStr: "pkg/test.typ.method<int, string>", 86 }, { 87 descr: "unexported function", 88 instance: Instance{ 89 Object: pkg.Scope().Lookup("fun"), 90 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.String]}, 91 }, 92 wantStr: "pkg/test.fun<int, string>", 93 }, { 94 descr: "no type params", 95 instance: Instance{ 96 Object: pkg.Scope().Lookup("Ints"), 97 }, 98 wantStr: "pkg/test.Ints", 99 wantTypeString: "testcase.Ints", 100 }, { 101 descr: "complex parameter type", 102 instance: Instance{ 103 Object: pkg.Scope().Lookup("fun"), 104 TArgs: []types.Type{ 105 types.NewSlice(types.Typ[types.Int]), 106 mustType(types.Instantiate(nil, pkg.Scope().Lookup("typ").Type(), []types.Type{ 107 types.Typ[types.Int], 108 types.Typ[types.String], 109 }, true)), 110 }, 111 }, 112 wantStr: "pkg/test.fun<[]int, pkg/test.typ[int, string]>", 113 }} 114 115 for _, test := range tests { 116 t.Run(test.descr, func(t *testing.T) { 117 got := test.instance.String() 118 if got != test.wantStr { 119 t.Errorf("Got: instance string %q. Want: %q.", got, test.wantStr) 120 } 121 if test.wantTypeString != "" { 122 got = test.instance.TypeString() 123 if got != test.wantTypeString { 124 t.Errorf("Got: instance type string %q. Want: %q.", got, test.wantTypeString) 125 } 126 } 127 }) 128 } 129 } 130 131 func TestInstanceQueue(t *testing.T) { 132 const src = `package test 133 type Typ[T any, V any] []T 134 func Fun[U any, W any](x, y U) {} 135 ` 136 f := srctesting.New(t) 137 _, pkg := f.Check("pkg/test", f.Parse("test.go", src)) 138 139 i1 := Instance{ 140 Object: pkg.Scope().Lookup("Typ"), 141 TArgs: []types.Type{types.Typ[types.String], types.Typ[types.String]}, 142 } 143 i2 := Instance{ 144 Object: pkg.Scope().Lookup("Typ"), 145 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.Int]}, 146 } 147 i3 := Instance{ 148 Object: pkg.Scope().Lookup("Fun"), 149 TArgs: []types.Type{types.Typ[types.String], types.Typ[types.String]}, 150 } 151 152 set := InstanceSet{} 153 set.Add(i1, i2) 154 155 if ex := set.exhausted(); ex { 156 t.Errorf("Got: set.exhausted() = true. Want: false") 157 } 158 159 gotValues := set.Values() 160 wantValues := []Instance{i1, i2} 161 if diff := cmp.Diff(wantValues, gotValues, instanceOpts()); diff != "" { 162 t.Errorf("set.Values() returned diff (-want,+got):\n%s", diff) 163 } 164 165 p1, ok := set.next() 166 if !ok { 167 t.Errorf("Got: _, ok := set.next(); ok == false. Want: true.") 168 } 169 p2, ok := set.next() 170 if !ok { 171 t.Errorf("Got: _, ok := set.next(); ok == false. Want: true.") 172 } 173 if ex := set.exhausted(); !ex { 174 t.Errorf("Got: set.exhausted() = false. Want: true") 175 } 176 177 _, ok = set.next() 178 if ok { 179 t.Errorf("Got: _, ok := set.next(); ok == true. Want: false.") 180 } 181 182 set.Add(i1) // Has been enqueued before. 183 if ex := set.exhausted(); !ex { 184 t.Errorf("Got: set.exhausted() = false. Want: true") 185 } 186 187 set.Add(i3) 188 p3, ok := set.next() 189 if !ok { 190 t.Errorf("Got: _, ok := set.next(); ok == false. Want: true.") 191 } 192 193 added := []Instance{i1, i2, i3} 194 processed := []Instance{p1, p2, p3} 195 196 diff := cmp.Diff(added, processed, instanceOpts()) 197 if diff != "" { 198 t.Errorf("Processed instances differ from added (-want,+got):\n%s", diff) 199 } 200 201 gotValues = set.Values() 202 wantValues = []Instance{i1, i2, i3} 203 if diff := cmp.Diff(wantValues, gotValues, instanceOpts()); diff != "" { 204 t.Errorf("set.Values() returned diff (-want,+got):\n%s", diff) 205 } 206 } 207 208 func TestInstancesByPackage(t *testing.T) { 209 f := srctesting.New(t) 210 211 const src1 = `package foo 212 type Typ[T any, V any] []T 213 ` 214 _, foo := f.Check("pkg/foo", f.Parse("foo.go", src1)) 215 216 const src2 = `package bar 217 func Fun[U any, W any](x, y U) {} 218 ` 219 _, bar := f.Check("pkg/bar", f.Parse("bar.go", src2)) 220 221 i1 := Instance{ 222 Object: foo.Scope().Lookup("Typ"), 223 TArgs: []types.Type{types.Typ[types.String], types.Typ[types.String]}, 224 } 225 i2 := Instance{ 226 Object: foo.Scope().Lookup("Typ"), 227 TArgs: []types.Type{types.Typ[types.Int], types.Typ[types.Int]}, 228 } 229 i3 := Instance{ 230 Object: bar.Scope().Lookup("Fun"), 231 TArgs: []types.Type{types.Typ[types.String], types.Typ[types.String]}, 232 } 233 234 t.Run("Add", func(t *testing.T) { 235 instByPkg := PackageInstanceSets{} 236 instByPkg.Add(i1, i2, i3) 237 238 gotFooInstances := instByPkg.Pkg(foo).Values() 239 wantFooInstances := []Instance{i1, i2} 240 if diff := cmp.Diff(wantFooInstances, gotFooInstances, instanceOpts()); diff != "" { 241 t.Errorf("instByPkg.Pkg(foo).Values() returned diff (-want,+got):\n%s", diff) 242 } 243 244 gotValues := instByPkg.Pkg(bar).Values() 245 wantValues := []Instance{i3} 246 if diff := cmp.Diff(wantValues, gotValues, instanceOpts()); diff != "" { 247 t.Errorf("instByPkg.Pkg(bar).Values() returned diff (-want,+got):\n%s", diff) 248 } 249 }) 250 251 t.Run("ID", func(t *testing.T) { 252 instByPkg := PackageInstanceSets{} 253 instByPkg.Add(i1, i2, i3) 254 255 got := []int{ 256 instByPkg.ID(i1), 257 instByPkg.ID(i2), 258 instByPkg.ID(i3), 259 } 260 want := []int{0, 1, 0} 261 262 if diff := cmp.Diff(want, got); diff != "" { 263 t.Errorf("unexpected instance IDs assigned (-want,+got):\n%s", diff) 264 } 265 }) 266 }