github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/typeparams_test.go (about) 1 /* 2 Copyright 2022 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package gox_test 15 16 import ( 17 "go/token" 18 "go/types" 19 "log" 20 "runtime" 21 "testing" 22 23 "github.com/goplus/gox" 24 "github.com/goplus/gox/internal/goxdbg" 25 ) 26 27 func TestMethodToFunc(t *testing.T) { 28 const src = `package hello 29 30 type Itf interface { 31 X() 32 } 33 34 type Base struct { 35 } 36 37 func (p Base) F() {} 38 39 func (p *Base) PtrF() {} 40 41 type Foo struct { 42 Itf 43 Base 44 Val byte 45 } 46 47 func (a Foo) Bar() int { 48 return 0 49 } 50 51 func (a *Foo) PtrBar() string { 52 return "" 53 } 54 55 var _ = (Foo).Bar 56 var _ = (*Foo).PtrBar 57 var _ = (Foo).F 58 var _ = (*Foo).PtrF 59 var _ = (Foo).X 60 var _ = (*Foo).X 61 var _ = (Itf).X 62 ` 63 gt := newGoxTest() 64 _, err := gt.LoadGoPackage("hello", "foo.go", src) 65 if err != nil { 66 t.Fatal(err) 67 } 68 pkg := gt.NewPackage("", "main") 69 pkgRef := pkg.Import("hello") 70 objFoo := pkgRef.Ref("Foo") 71 objItf := pkgRef.Ref("Itf") 72 typ := objFoo.Type() 73 typItf := objItf.Type() 74 _, err = pkg.MethodToFunc(typ, "Val") 75 if err == nil || err.Error() != "-: undefined (type hello.Foo has no method Val)" { 76 t.Fatal("MethodToFunc failed:", err) 77 } 78 checkMethodToFunc(t, pkg, typ, "Bar", "(hello.Foo).Bar") 79 checkMethodToFunc(t, pkg, types.NewPointer(typ), "PtrBar", "(*hello.Foo).PtrBar") 80 checkMethodToFunc(t, pkg, typ, "PtrBar", "(*hello.Foo).PtrBar") 81 checkMethodToFunc(t, pkg, typ, "F", "(hello.Foo).F") 82 checkMethodToFunc(t, pkg, types.NewPointer(typ), "PtrF", "(*hello.Foo).PtrF") 83 checkMethodToFunc(t, pkg, typ, "PtrF", "(*hello.Foo).PtrF") 84 checkMethodToFunc(t, pkg, typItf, "X", "(hello.Itf).X") 85 checkMethodToFunc(t, pkg, typ, "X", "(hello.Foo).X") 86 checkMethodToFunc(t, pkg, types.NewPointer(typ), "X", "(*hello.Foo).X") 87 } 88 89 func checkMethodToFunc(t *testing.T, pkg *gox.Package, typ types.Type, name, code string) { 90 t.Helper() 91 ret, err := pkg.MethodToFunc(typ, name) 92 if err != nil { 93 t.Fatal("MethodToFunc failed:", err) 94 } 95 if _, isPtr := typ.(*types.Pointer); isPtr { 96 if recv := ret.Type.(*types.Signature).Params().At(0); !types.Identical(recv.Type(), typ) { 97 t.Fatalf("MethodToFunc: ResultType: %v, Expected: %v\n", recv.Type(), typ) 98 } 99 } 100 if v := goxdbg.Format(pkg.Fset, ret.Val); v != code { 101 t.Fatalf("MethodToFunc:\nResult:\n%s\nExpected:\n%s\n", v, code) 102 } 103 } 104 105 func TestTypeAsParamsFunc(t *testing.T) { 106 const src = `package foo 107 108 const GopPackage = true 109 110 type basetype interface { 111 int | string 112 } 113 114 func Gopx_Bar[T basetype](name string) { 115 } 116 117 func Gopx_Row__0[T basetype](name string) { 118 } 119 120 func Gopx_Row__1[Array any](v int) { 121 } 122 123 type Table struct { 124 } 125 126 func Gopt_Table_Gopx_Col__0[T basetype](p *Table, name string) { 127 } 128 129 func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { 130 } 131 ` 132 gt := newGoxTest() 133 _, err := gt.LoadGoPackage("foo", "foo.go", src) 134 if err != nil { 135 t.Fatal(err) 136 } 137 pkg := gt.NewPackage("", "test") 138 foo := pkg.Import("foo") 139 objTable := foo.Ref("Table") 140 typ := objTable.Type().(*types.Named) 141 tyInt := types.Typ[types.Int] 142 143 cb := pkg.NewFunc(nil, "Example", nil, nil, false).BodyStart(pkg). 144 NewVar(types.NewPointer(typ), "tbl") 145 _, err = cb.VarVal("tbl").Member("col", gox.MemberFlagMethodAlias) 146 if err != nil { 147 t.Fatal("tbl.Member(col):", err) 148 } 149 cb.Typ(tyInt).Val("bar").Call(2).EndStmt(). 150 Val(foo.Ref("Bar")).Typ(tyInt).Val("1").Call(2).EndStmt(). 151 Val(foo.Ref("Row")).Typ(tyInt).Val(1, source("1")).Call(2).EndStmt(). 152 End() 153 154 domTest(t, pkg, `package test 155 156 import "foo" 157 158 func Example() { 159 var tbl *foo.Table 160 foo.Gopt_Table_Gopx_Col__0[int](tbl, "bar") 161 foo.Gopx_Bar[int]("1") 162 foo.Gopx_Row__1[int](1) 163 } 164 `) 165 } 166 167 func TestCheckGopPkg(t *testing.T) { 168 const src = `package foo 169 170 import "io" 171 172 const GopPackage = "io" 173 174 type basetype interface { 175 int | string 176 } 177 178 func Gopx_Bar[T basetype](name string) { 179 } 180 181 func Gopx_Row__0[T basetype](name string) { 182 } 183 184 func Gopx_Row__1[Array any](v int) { 185 } 186 187 type EmbIntf interface { 188 io.Reader 189 Close() 190 } 191 192 type Table struct { 193 EmbIntf 194 N int 195 b string 196 } 197 198 func Gopt_Table_Gopx_Col__0[T basetype](p *Table, name string) { 199 } 200 201 func Gopt_Table_Gopx_Col__1[Array any](p *Table, v int) { 202 } 203 ` 204 gt := newGoxTest() 205 _, err := gt.LoadGoPackage("foo", "foo.go", src) 206 if err != nil { 207 t.Fatal(err) 208 } 209 pkg := gt.NewPackage("", "test") 210 foo := pkg.Import("foo") 211 objTable := foo.Ref("Table") 212 typ := objTable.Type().(*types.Named) 213 tyInt := types.Typ[types.Int] 214 215 typSlice := types.NewSlice(types.NewPointer(typ)) 216 typMap := types.NewMap(types.Typ[types.String], typSlice) 217 218 args := types.NewTuple(types.NewParam(0, pkg.Types, "tbls", typMap)) 219 cb := pkg.NewFunc(nil, "Example", args, nil, false).BodyStart(pkg) 220 _, err = cb.VarVal("tbls").Val("Hi").Index(1, false).Val(0).Index(1, false).Member("col", gox.MemberFlagMethodAlias) 221 if err != nil { 222 t.Fatal("tbl.Member(col):", err) 223 } 224 cb.Typ(tyInt).Val("bar").Call(2).EndStmt(). 225 Val(foo.Ref("Bar")).Typ(tyInt).Val("1").Call(2).EndStmt(). 226 Val(foo.Ref("Row")).Typ(tyInt).Val(1, source("1")).Call(2).EndStmt(). 227 End() 228 229 typChan := types.NewChan(types.SendRecv, typSlice) 230 typArray := types.NewArray(typChan, 2) 231 args = types.NewTuple(types.NewParam(0, pkg.Types, "", typArray)) 232 pkg.NewFunc(nil, "Create", args, nil, false).BodyStart(pkg).End() 233 234 domTest(t, pkg, `package test 235 236 import "foo" 237 238 const GopPackage = "foo" 239 240 func Example(tbls map[string][]*foo.Table) { 241 foo.Gopt_Table_Gopx_Col__0[int](tbls["Hi"][0], "bar") 242 foo.Gopx_Bar[int]("1") 243 foo.Gopx_Row__1[int](1) 244 } 245 func Create([2]chan []*foo.Table) { 246 } 247 `) 248 } 249 250 func TestOverloadNamed(t *testing.T) { 251 const src = `package foo 252 253 const GopPackage = true 254 255 type M = map[string]any 256 257 type basetype interface { 258 string | int | bool | float64 259 } 260 261 type Var__0[T basetype] struct { 262 val T 263 } 264 265 type Var__1[T map[string]any] struct { 266 val T 267 } 268 269 func Gopx_Var_Cast__0[T basetype]() *Var__0[T] { 270 return new(Var__0[T]) 271 } 272 273 func Gopx_Var_Cast__1[T map[string]any]() *Var__1[T] { 274 return new(Var__1[T]) 275 } 276 ` 277 gt := newGoxTest() 278 _, err := gt.LoadGoPackage("foo", "foo.go", src) 279 if err != nil { 280 t.Fatal(err) 281 } 282 pkg := gt.NewPackage("", "main") 283 pkgRef := pkg.Import("foo") 284 scope := pkgRef.Types.Scope() 285 log.Println("==> Lookup", scope.Lookup("Var__0")) 286 objVar := pkgRef.Ref("Var") 287 typ := objVar.Type() 288 on, ok := gox.CheckOverloadNamed(typ) 289 if !ok { 290 t.Fatal("TestOverloadNamed: not TyOverloadNamed?") 291 } 292 if on.Types[0].TypeParams() == nil { 293 t.Fatal("TestOverloadNamed: not generic") 294 } 295 296 tyInt := types.Typ[types.Int] 297 tyM := pkgRef.Ref("M").Type() 298 ty1 := pkg.Instantiate(typ, []types.Type{tyInt}) 299 ty2 := pkg.Instantiate(typ, []types.Type{tyM}) 300 pkg.NewTypeDefs().NewType("t1").InitType(pkg, ty1) 301 pkg.NewTypeDefs().NewType("t2").InitType(pkg, ty2) 302 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 303 Val(objVar).Typ(tyInt).Call(1).EndStmt(). 304 Val(objVar).Typ(tyM).Call(1).EndStmt(). 305 End() 306 307 domTest(t, pkg, `package main 308 309 import "foo" 310 311 type t1 foo.Var__0[int] 312 type t2 foo.Var__1[map[string]any] 313 314 func main() { 315 foo.Gopx_Var_Cast__0[int]() 316 foo.Gopx_Var_Cast__1[map[string]any]() 317 } 318 `) 319 320 func() { 321 defer func() { 322 if e := recover(); e == nil { 323 t.Fatal("TestOverloadNamed failed: no error?") 324 } 325 }() 326 ty3 := pkg.Instantiate(on, []types.Type{gox.TyByte}) 327 pkg.NewTypeDefs().NewType("t3").InitType(pkg, ty3) 328 }() 329 func() { 330 defer func() { 331 if e := recover(); e != nil && e.(error).Error() != "-: 1 (type untyped int) is not a type" { 332 t.Fatal("TestOverloadNamed failed:", e) 333 } 334 }() 335 pkg.NewFunc(nil, "bar", nil, nil, false).BodyStart(pkg). 336 Val(objVar).Val(1, source("1")).Call(1).EndStmt(). 337 End() 338 }() 339 } 340 341 func TestInstantiate(t *testing.T) { 342 const src = `package foo 343 344 type Data[T any] struct { 345 v T 346 } 347 348 type sliceOf[E any] interface { 349 ~[]E 350 } 351 352 type Slice[S sliceOf[T], T any] struct { 353 Data S 354 } 355 356 func (p *Slice[S, T]) Append(t ...T) S { 357 p.Data = append(p.Data, t...) 358 return p.Data 359 } 360 361 type ( 362 DataInt = Data[int] 363 SliceInt = Slice[[]int,int] 364 ) 365 ` 366 gt := newGoxTest() 367 _, err := gt.LoadGoPackage("foo", "foo.go", src) 368 if err != nil { 369 t.Fatal(err) 370 } 371 pkg := gt.NewPackage("", "main") 372 pkgRef := pkg.Import("foo") 373 tyData := pkgRef.Ref("Data").Type() 374 tyInt := types.Typ[types.Int] 375 tyInvalid := types.Typ[types.Invalid] 376 tySlice := pkgRef.Ref("Slice").Type() 377 if ret := pkg.Instantiate(tyData, []types.Type{tyInt}); ret == tyInvalid { 378 t.Fatal("TestInstantiate failed: pkg.Instantiate") 379 } 380 func() { 381 defer func() { 382 if e := recover(); e.(error).Error() != "-: int is not a generic type" { 383 t.Fatal("TestInstantiate failed:", e) 384 } 385 }() 386 pkg.Instantiate(tyInt, nil) 387 }() 388 func() { 389 defer func() { 390 if e := recover(); e == nil { 391 t.Fatal("TestInstantiate failed: no error?") 392 } 393 }() 394 pkg.Instantiate(tySlice, []types.Type{tyInt}) 395 }() 396 } 397 398 func TestTypeParamsType(t *testing.T) { 399 const src = `package foo 400 401 type Data[T any] struct { 402 v T 403 } 404 405 type sliceOf[E any] interface { 406 ~[]E 407 } 408 409 type Slice[S sliceOf[T], T any] struct { 410 Data S 411 } 412 413 func (p *Slice[S, T]) Append(t ...T) S { 414 p.Data = append(p.Data, t...) 415 return p.Data 416 } 417 418 type ( 419 DataInt = Data[int] 420 SliceInt = Slice[[]int,int] 421 ) 422 ` 423 gt := newGoxTest() 424 _, err := gt.LoadGoPackage("foo", "foo.go", src) 425 if err != nil { 426 t.Fatal(err) 427 } 428 pkg := gt.NewPackage("", "main") 429 pkgRef := pkg.Import("foo") 430 tySlice := pkgRef.Ref("Slice").Type() 431 tySliceInt := pkgRef.Ref("SliceInt").Type() 432 tyData := pkgRef.Ref("Data").Type() 433 tyDataInt := pkgRef.Ref("DataInt").Type() 434 tyInt := types.Typ[types.Int] 435 tyIntSlice := types.NewSlice(tyInt) 436 437 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 438 NewVarStart(types.NewPointer(tyDataInt), "data").Typ(tyData).Typ(tyInt).Index(1, false).Star().Val(nil).Call(1).EndInit(1). 439 NewVarStart(types.NewPointer(tySliceInt), "slice").Typ(tySlice).Typ(tyIntSlice).Typ(tyInt).Index(2, false).Star().Val(nil).Call(1).EndInit(1). 440 End() 441 domTest(t, pkg, `package main 442 443 import "foo" 444 445 func main() { 446 var data *foo.Data[int] = (*foo.Data[int])(nil) 447 var slice *foo.Slice[[]int, int] = (*foo.Slice[[]int, int])(nil) 448 } 449 `) 450 } 451 452 func TestTypeParamsFunc(t *testing.T) { 453 const src = `package foo 454 455 type Number interface { 456 ~int | float64 457 } 458 459 func Sum[T Number](vec []T) T { 460 var sum T 461 for _, elt := range vec { 462 sum = sum + elt 463 } 464 return sum 465 } 466 467 func At[T interface{ ~[]E }, E any](x T, i int) E { 468 return x[i] 469 } 470 471 func Loader[T1 any, T2 any](p1 T1, p2 T2) T1 { 472 return p1 473 } 474 475 func Add[T1 any, T2 ~int](v1 T1, v2 ...T2) (sum T2) { 476 println(v1) 477 for _, v := range v2 { 478 sum += v 479 } 480 return sum 481 } 482 483 type Int []int 484 var MyInts = Int{1,2,3,4} 485 ` 486 gt := newGoxTest() 487 _, err := gt.LoadGoPackage("foo", "foo.go", src) 488 if err != nil { 489 t.Fatal(err) 490 } 491 pkg := gt.NewPackage("", "main") 492 pkgRef := pkg.Import("foo") 493 fnSum := pkgRef.Ref("Sum") 494 fnAt := pkgRef.Ref("At") 495 fnLoader := pkgRef.Ref("Loader") 496 fnAdd := pkgRef.Ref("Add") 497 myInts := pkgRef.Ref("MyInts") 498 tyInt := types.Typ[types.Int] 499 tyString := types.Typ[types.String] 500 tyIntSlice := types.NewSlice(tyInt) 501 tyIntPointer := types.NewPointer(tyInt) 502 var fn1 *types.Var 503 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 504 VarRef(nil).Val(fnAt).Typ(tyIntSlice).Index(1, false).Assign(1, 1). 505 VarRef(nil).Val(fnSum).Typ(tyInt).Index(1, false).Assign(1, 1). 506 VarRef(nil).Val(fnLoader).Typ(tyInt).Typ(tyInt).Index(2, false).Assign(1, 1). 507 VarRef(nil).Val(fnAdd).Typ(tyString).Typ(tyInt).Index(2, false).Assign(1, 1). 508 NewVarStart(tyInt, "s1").Val(fnSum).Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).Call(1).EndInit(1). 509 NewVarStart(tyInt, "s2").Val(fnSum).Typ(tyInt).Index(1, false).Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).Call(1).EndInit(1). 510 NewVarStart(tyInt, "v1").Val(fnAt).Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).Val(1).Call(2).EndInit(1). 511 NewVarStart(tyInt, "v2").Val(fnAt).Typ(tyIntSlice).Index(1, false).Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).Val(1).Call(2).EndInit(1). 512 NewVarStart(tyInt, "v3").Val(fnAt).Typ(tyIntSlice).Typ(tyInt).Index(2, false).Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).Val(1).Call(2).EndInit(1). 513 NewVarStart(tyInt, "n1").Val(fnAdd).Val("hello").Val(1).Val(2).Val(3).Call(4).EndInit(1). 514 NewVarStart(tyInt, "n2").Val(fnAdd).Typ(tyString).Index(1, false).Val("hello").Val(1).Val(2).Val(3).Call(4).EndInit(1). 515 NewVarStart(tyInt, "n3").Val(fnAdd).Typ(tyString).Typ(tyInt).Index(2, false).Val("hello").Val(1).Val(2).Val(3).Call(4).EndInit(1). 516 NewVarStart(tyInt, "n4").Val(fnAdd).Val("hello").Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).CallWith(2, gox.InstrFlagEllipsis).EndInit(1). 517 NewVarStart(tyInt, "n5").Val(fnAdd).Val("hello").Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).CallWith(2, gox.InstrFlagEllipsis).EndInit(1). 518 NewVarStart(tyInt, "n6").Val(fnAdd).Typ(tyString).Index(1, false).Val("hello").Val(myInts).CallWith(2, gox.InstrFlagEllipsis).EndInit(1). 519 NewVarStart(tyInt, "n7").Val(fnAdd).Typ(tyString).Typ(tyInt).Index(2, false).Val("hello").Val(1).Val(2).Val(3).SliceLit(tyIntSlice, 3).CallWith(2, gox.InstrFlagEllipsis).EndInit(1). 520 NewVarStart(tyIntPointer, "p1").Val(fnLoader).Typ(tyIntPointer).Index(1, false).Val(nil).Val(1).Call(2).EndInit(1). 521 NewVarStart(tyIntPointer, "p2").Val(fnLoader).Typ(tyIntPointer).Typ(tyInt).Index(2, false).Val(nil).Val(1).Call(2).EndInit(1). 522 NewAutoVar(0, "fn1", &fn1).VarRef(fn1).Val(fnLoader).Typ(tyIntPointer).Typ(tyInt).Index(2, false).Assign(1, 1).EndStmt(). 523 Val(fn1).Val(nil).Val(1).Call(2).EndStmt(). 524 End() 525 domTest(t, pkg, `package main 526 527 import "foo" 528 529 func main() { 530 _ = foo.At[[]int] 531 _ = foo.Sum[int] 532 _ = foo.Loader[int, int] 533 _ = foo.Add[string, int] 534 var s1 int = foo.Sum([]int{1, 2, 3}) 535 var s2 int = foo.Sum[int]([]int{1, 2, 3}) 536 var v1 int = foo.At([]int{1, 2, 3}, 1) 537 var v2 int = foo.At[[]int]([]int{1, 2, 3}, 1) 538 var v3 int = foo.At[[]int, int]([]int{1, 2, 3}, 1) 539 var n1 int = foo.Add("hello", 1, 2, 3) 540 var n2 int = foo.Add[string]("hello", 1, 2, 3) 541 var n3 int = foo.Add[string, int]("hello", 1, 2, 3) 542 var n4 int = foo.Add("hello", []int{1, 2, 3}...) 543 var n5 int = foo.Add("hello", []int{1, 2, 3}...) 544 var n6 int = foo.Add[string]("hello", foo.MyInts...) 545 var n7 int = foo.Add[string, int]("hello", []int{1, 2, 3}...) 546 var p1 *int = foo.Loader[*int](nil, 1) 547 var p2 *int = foo.Loader[*int, int](nil, 1) 548 var fn1 func(p1 *int, p2 int) *int 549 fn1 = foo.Loader[*int, int] 550 fn1(nil, 1) 551 } 552 `) 553 } 554 555 func TestTypeParamsErrorInstantiate(t *testing.T) { 556 const src = `package foo 557 558 type Number interface { 559 ~int | float64 560 } 561 562 func Sum[T Number](vec []T) T { 563 var sum T 564 for _, elt := range vec { 565 sum = sum + elt 566 } 567 return sum 568 } 569 570 var SumInt = Sum[int] 571 ` 572 gt := newGoxTest() 573 _, err := gt.LoadGoPackage("foo", "foo.go", src) 574 if err != nil { 575 t.Fatal(err) 576 } 577 578 pkg := gt.NewPackage("", "main") 579 pkgRef := pkg.Import("foo") 580 fnSum := pkgRef.Ref("Sum") 581 tyUint := types.Typ[types.Uint] 582 583 var msg string 584 switch runtime.Version()[:6] { 585 case "go1.18": 586 msg = `./foo.gop:5:40: uint does not implement foo.Number` 587 case "go1.19": 588 msg = `./foo.gop:5:40: uint does not implement foo.Number (uint missing in ~int | float64)` 589 default: 590 msg = `./foo.gop:5:40: uint does not satisfy foo.Number (uint missing in ~int | float64)` 591 } 592 codeErrorTestEx(t, pkg, msg, func(pkg *gox.Package) { 593 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 594 DefineVarStart(0, "sum").Val(fnSum).Typ(tyUint).Index(1, false, source(`foo.Sum[uint]`, 5, 40)).EndInit(1). 595 End() 596 }) 597 } 598 599 func TestTypeParamsErrorMatch(t *testing.T) { 600 const src = `package foo 601 602 func At[T interface{ ~[]E }, E any](x T, i int) E { 603 return x[i] 604 } 605 606 var AtInt = At[[]int] 607 ` 608 609 gt := newGoxTest() 610 _, err := gt.LoadGoPackage("foo", "foo.go", src) 611 if err != nil { 612 t.Fatal(err) 613 } 614 615 pkg := gt.NewPackage("", "main") 616 pkgRef := pkg.Import("foo") 617 fnAt := pkgRef.Ref("At") 618 tyAtInt := pkgRef.Ref("AtInt").Type() 619 tyInt := types.Typ[types.Int] 620 621 var msg string 622 switch runtime.Version()[:6] { 623 case "go1.18", "go1.19": 624 msg = `./foo.gop:5:40: T does not match ~[]E` 625 case "go1.20": 626 msg = `./foo.gop:5:40: int does not match ~[]E` 627 default: 628 msg = `./foo.gop:5:40: T (type int) does not satisfy interface{~[]E}` 629 } 630 codeErrorTestEx(t, pkg, msg, func(pkg *gox.Package) { 631 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 632 NewVarStart(tyAtInt, "at").Val(fnAt).Typ(tyInt).Index(1, false, source(`foo.At[int]`, 5, 40)).EndInit(1). 633 End() 634 }) 635 } 636 637 func TestTypeParamsErrInferFunc(t *testing.T) { 638 const src = `package foo 639 640 func Loader[T1 any, T2 any](p1 T1, p2 T2) T1 { 641 return p1 642 } 643 ` 644 gt := newGoxTest() 645 _, err := gt.LoadGoPackage("foo", "foo.go", src) 646 if err != nil { 647 t.Fatal(err) 648 } 649 pkg := gt.NewPackage("", "main") 650 pkgRef := pkg.Import("foo") 651 fnLoader := pkgRef.Ref("Loader") 652 tyInt := types.Typ[types.Int] 653 codeErrorTestEx(t, pkg, `./foo.gop:5:40: cannot infer T2 (foo.go:3:21)`, 654 func(pkg *gox.Package) { 655 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 656 DefineVarStart(0, "v1").Val(fnLoader).Typ(tyInt).Index(1, false, source(`v1 := foo.Loader[int]`, 5, 40)).EndInit(1). 657 End() 658 }) 659 } 660 661 func TestTypeParamsErrArgumentsParameters1(t *testing.T) { 662 const src = `package foo 663 664 type Data[T1 any, T2 any] struct { 665 v1 T1 666 v2 T2 667 } 668 ` 669 gt := newGoxTest() 670 _, err := gt.LoadGoPackage("foo", "foo.go", src) 671 if err != nil { 672 t.Fatal(err) 673 } 674 pkg := gt.NewPackage("", "main") 675 pkgRef := pkg.Import("foo") 676 tyData := pkgRef.Ref("Data").Type() 677 tyInt := types.Typ[types.Int] 678 codeErrorTestEx(t, pkg, `./foo.gop:5:40: got 1 type arguments but foo.Data[T1, T2 any] has 2 type parameters`, 679 func(pkg *gox.Package) { 680 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 681 DefineVarStart(0, "v1").Typ(tyData).Typ(tyInt).Index(1, false, source(`foo.Data[int]`, 5, 40)).Star().Val(nil).Call(1).EndInit(1). 682 End() 683 }) 684 } 685 686 func TestTypeParamsErrArgumentsParameters2(t *testing.T) { 687 const src = `package foo 688 689 type Data[T1 any, T2 any] struct { 690 v1 T1 691 v2 T2 692 } 693 ` 694 gt := newGoxTest() 695 _, err := gt.LoadGoPackage("foo", "foo.go", src) 696 if err != nil { 697 t.Fatal(err) 698 } 699 pkg := gt.NewPackage("", "main") 700 pkgRef := pkg.Import("foo") 701 tyData := pkgRef.Ref("Data").Type() 702 tyInt := types.Typ[types.Int] 703 codeErrorTestEx(t, pkg, `./foo.gop:5:40: got 3 type arguments but foo.Data[T1, T2 any] has 2 type parameters`, 704 func(pkg *gox.Package) { 705 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 706 DefineVarStart(0, "v1").Typ(tyData).Typ(tyInt).Typ(tyInt).Typ(tyInt).Index(3, false, source(`foo.Data[int,int,int]`, 5, 40)).Star().Val(nil).Call(1).EndInit(1). 707 End() 708 }) 709 } 710 711 func TestTypeParamsErrArgumentsParameters3(t *testing.T) { 712 const src = `package foo 713 714 func Test[T1 any, T2 any](t1 T1, t2 T2) { 715 println(t1,t2) 716 } 717 ` 718 gt := newGoxTest() 719 _, err := gt.LoadGoPackage("foo", "foo.go", src) 720 if err != nil { 721 t.Fatal(err) 722 } 723 pkg := gt.NewPackage("", "main") 724 pkgRef := pkg.Import("foo") 725 fnTest := pkgRef.Ref("Test") 726 tyInt := types.Typ[types.Int] 727 codeErrorTestEx(t, pkg, `./foo.gop:5:40: got 3 type arguments but func[T1, T2 any](t1 T1, t2 T2) has 2 type parameters`, 728 func(pkg *gox.Package) { 729 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 730 Val(fnTest).Typ(tyInt).Typ(tyInt).Typ(tyInt).Index(3, false, source(`foo.Test[int,int,int]`, 5, 40)).Val(1).Val(1).Call(2).EndStmt(). 731 End() 732 }) 733 } 734 735 func TestTypeParamsErrCallArguments1(t *testing.T) { 736 const src = `package foo 737 738 func Test[T1 any, T2 any](t1 T1, t2 T2) { 739 println(t1,t2) 740 } 741 ` 742 gt := newGoxTest() 743 _, err := gt.LoadGoPackage("foo", "foo.go", src) 744 if err != nil { 745 t.Fatal(err) 746 } 747 pkg := gt.NewPackage("", "main") 748 pkgRef := pkg.Import("foo") 749 fnTest := pkgRef.Ref("Test") 750 codeErrorTestEx(t, pkg, `./foo.gop:5:40: not enough arguments in call to foo.Test 751 have (untyped int) 752 want (T1, T2)`, 753 func(pkg *gox.Package) { 754 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 755 Val(fnTest).Val(1).CallWith(1, 0, source("foo.Test(1)", 5, 40)).EndStmt(). 756 End() 757 }) 758 } 759 760 func TestTypeParamsErrCallArguments2(t *testing.T) { 761 const src = `package foo 762 763 func Test[T1 any, T2 any](t1 T1, t2 T2) { 764 println(t1,t2) 765 } 766 ` 767 gt := newGoxTest() 768 _, err := gt.LoadGoPackage("foo", "foo.go", src) 769 if err != nil { 770 t.Fatal(err) 771 } 772 pkg := gt.NewPackage("", "main") 773 pkgRef := pkg.Import("foo") 774 fnTest := pkgRef.Ref("Test") 775 776 codeErrorTestEx(t, pkg, `./foo.gop:5:40: too many arguments in call to foo.Test 777 have (untyped int, untyped int, untyped int) 778 want (T1, T2)`, 779 func(pkg *gox.Package) { 780 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 781 Val(fnTest).Val(1).Val(2).Val(3).CallWith(3, 0, source("foo.Test(1,2,3)", 5, 40)).EndStmt(). 782 End() 783 }) 784 } 785 786 func TestTypeParamsErrCallArguments3(t *testing.T) { 787 const src = `package foo 788 789 func Test[T1 any, T2 any]() { 790 var t1 T1 791 var t2 T2 792 println(t1,t2) 793 } 794 ` 795 gt := newGoxTest() 796 _, err := gt.LoadGoPackage("foo", "foo.go", src) 797 if err != nil { 798 t.Fatal(err) 799 } 800 pkg := gt.NewPackage("", "main") 801 pkgRef := pkg.Import("foo") 802 fnTest := pkgRef.Ref("Test") 803 codeErrorTestEx(t, pkg, `./foo.gop:5:40: too many arguments in call to foo.Test 804 have (untyped int, untyped int) 805 want ()`, 806 func(pkg *gox.Package) { 807 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 808 Val(fnTest).Val(1).Val(2).CallWith(2, 0, source("foo.Test(1,2)", 5, 40)).EndStmt(). 809 End() 810 }) 811 } 812 813 func TestTypeParamsErrCallVariadicArguments1(t *testing.T) { 814 const src = `package foo 815 816 func Add[T1 any, T2 ~int](v1 T1, v2 ...T2) (sum T2) { 817 println(v1) 818 for _, v := range v2 { 819 sum += v 820 } 821 return sum 822 } 823 ` 824 gt := newGoxTest() 825 _, err := gt.LoadGoPackage("foo", "foo.go", src) 826 if err != nil { 827 t.Fatal(err) 828 } 829 pkg := gt.NewPackage("", "main") 830 pkgRef := pkg.Import("foo") 831 fnAdd := pkgRef.Ref("Add") 832 833 codeErrorTestEx(t, pkg, `./foo.gop:5:40: not enough arguments in call to foo.Add 834 have () 835 want (T1, ...T2)`, 836 func(pkg *gox.Package) { 837 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 838 Val(fnAdd).CallWith(0, 0, source("foo.Add()", 5, 40)).EndStmt(). 839 End() 840 }) 841 } 842 843 func TestTypeParamsErrCallVariadicArguments2(t *testing.T) { 844 const src = `package foo 845 846 func Add[T1 any, T2 ~int](v1 T1, v2 ...T2) (sum T2) { 847 println(v1) 848 for _, v := range v2 { 849 sum += v 850 } 851 return sum 852 } 853 ` 854 gt := newGoxTest() 855 _, err := gt.LoadGoPackage("foo", "foo.go", src) 856 if err != nil { 857 t.Fatal(err) 858 } 859 pkg := gt.NewPackage("", "main") 860 pkgRef := pkg.Import("foo") 861 fnAdd := pkgRef.Ref("Add") 862 863 // not pass source to foo.Add 864 codeErrorTestEx(t, pkg, `./foo.gop:5:40: cannot infer T2 (-)`, 865 func(pkg *gox.Package) { 866 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 867 Val(fnAdd).Val(1).CallWith(1, 0, source("foo.Add(1)", 5, 40)).EndStmt(). 868 End() 869 }) 870 } 871 872 func TestTypeParamsErrorCall(t *testing.T) { 873 const src = `package foo 874 875 type Number interface { 876 ~int | float64 877 } 878 879 func Sum[T Number](vec []T) T { 880 var sum T 881 for _, elt := range vec { 882 sum = sum + elt 883 } 884 return sum 885 } 886 ` 887 gt := newGoxTest() 888 _, err := gt.LoadGoPackage("foo", "foo.go", src) 889 if err != nil { 890 t.Fatal(err) 891 } 892 pkg := gt.NewPackage("", "main") 893 pkgRef := pkg.Import("foo") 894 fnSum := pkgRef.Ref("Sum") 895 tyUint := types.Typ[types.Uint] 896 tyUintSlice := types.NewSlice(tyUint) 897 898 var msg string 899 switch runtime.Version()[:6] { 900 case "go1.18": 901 msg = `./foo.gop:5:40: uint does not implement foo.Number` 902 case "go1.19": 903 msg = `./foo.gop:5:40: uint does not implement foo.Number (uint missing in ~int | float64)` 904 default: 905 msg = `./foo.gop:5:40: uint does not satisfy foo.Number (uint missing in ~int | float64)` 906 } 907 codeErrorTestEx(t, pkg, msg, func(pkg *gox.Package) { 908 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 909 Val(fnSum).Val(1).Val(2).Val(3).SliceLit(tyUintSlice, 3).CallWith(1, 0, source(`foo.Sum([]uint{1,2,3})`, 5, 40)).EndInit(1). 910 End() 911 }) 912 } 913 914 func TestTypeParamsErrorInferCall(t *testing.T) { 915 const src = `package foo 916 917 func Loader[T1 any, T2 any](p1 T1, p2 T2) T1 { 918 return p1 919 } 920 ` 921 gt := newGoxTest() 922 _, err := gt.LoadGoPackage("foo", "foo.go", src) 923 if err != nil { 924 t.Fatal(err) 925 } 926 pkg := gt.NewPackage("", "main") 927 pkgRef := pkg.Import("foo") 928 fnLoader := pkgRef.Ref("Loader") 929 tyInt := types.Typ[types.Int] 930 codeErrorTestEx(t, pkg, `./foo.gop:5:40: cannot infer T2 (foo.go:3:21)`, 931 func(pkg *gox.Package) { 932 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 933 Val(fnLoader).Typ(tyInt).Index(1, false, source(`foo.Loader[int]`, 5, 40)).Val(10).Val(nil).CallWith(2, 0, source(`foo.Loader[int]`, 5, 40)).EndStmt(). 934 End() 935 }) 936 } 937 938 func TestTypeParamErrGenericType(t *testing.T) { 939 const src = `package foo 940 941 type Data struct { 942 } 943 ` 944 gt := newGoxTest() 945 _, err := gt.LoadGoPackage("foo", "foo.go", src) 946 if err != nil { 947 t.Fatal(err) 948 } 949 pkg := gt.NewPackage("", "main") 950 pkgRef := pkg.Import("foo") 951 tyData := pkgRef.Ref("Data").Type() 952 tyInt := types.Typ[types.Int] 953 codeErrorTestEx(t, pkg, `./foo.gop:5:40: foo.Data is not a generic type`, 954 func(pkg *gox.Package) { 955 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 956 DefineVarStart(0, "v1").Typ(tyData).Typ(tyInt).Index(1, false, source(`foo.Data[int]`, 5, 40)).Star().Val(nil).Call(1).EndInit(1). 957 End() 958 }) 959 } 960 961 func TestTypeParamErrGenericType2(t *testing.T) { 962 gt := newGoxTest() 963 pkg := gt.NewPackage("", "main") 964 tyInt := types.Typ[types.Int] 965 tyString := types.Typ[types.String] 966 967 codeErrorTestEx(t, pkg, `./foo.gop:5:40: string is not a generic type`, 968 func(pkg *gox.Package) { 969 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 970 DefineVarStart(0, "v1").Typ(tyString).Typ(tyInt).Index(1, false, source(`string[int]`, 5, 40)).Star().Val(nil).Call(1).EndInit(1). 971 End() 972 }) 973 } 974 975 func TestTypeParamErrGenericFunc(t *testing.T) { 976 const src = `package foo 977 978 func Loader(n int) string { 979 return "" 980 } 981 ` 982 gt := newGoxTest() 983 _, err := gt.LoadGoPackage("foo", "foo.go", src) 984 if err != nil { 985 t.Fatal(err) 986 } 987 pkg := gt.NewPackage("", "main") 988 pkgRef := pkg.Import("foo") 989 fnLoader := pkgRef.Ref("Loader") 990 tyInt := types.Typ[types.Int] 991 992 codeErrorTestEx(t, pkg, `./foo.gop:5:40: invalid operation: cannot index foo.Loader (value of type func(n int) string)`, 993 func(pkg *gox.Package) { 994 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 995 DefineVarStart(0, "v1").Val(fnLoader).Typ(tyInt).Index(1, false, source(`v1 := foo.Loader[int]`, 5, 40)).EndInit(1). 996 End() 997 }) 998 } 999 1000 func TestGenTypeParamsFunc(t *testing.T) { 1001 pkg := newMainPackage() 1002 ut1 := types.NewUnion([]*types.Term{types.NewTerm(true, types.Typ[types.Int]), types.NewTerm(false, types.Typ[types.Uint])}) 1003 ut2 := types.NewUnion([]*types.Term{types.NewTerm(true, types.Typ[types.Int])}) 1004 it := pkg.NewType("T").InitType(pkg, types.NewInterfaceType(nil, []types.Type{ut1})) 1005 tp1 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T1", nil), types.Universe.Lookup("any").Type()) 1006 tp2 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T2", nil), ut2) 1007 tp3 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T3", nil), it) 1008 p1 := types.NewParam(token.NoPos, pkg.Types, "p1", tp1) 1009 p2 := types.NewParam(token.NoPos, pkg.Types, "p2", tp2) 1010 p3 := types.NewParam(token.NoPos, pkg.Types, "p3", tp3) 1011 sig := types.NewSignatureType(nil, nil, []*types.TypeParam{tp1, tp2, tp3}, types.NewTuple(p1, p2, p3), nil, false) 1012 fn1 := pkg.NewFuncDecl(token.NoPos, "test", sig) 1013 fn1.BodyStart(pkg).End() 1014 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 1015 Val(fn1).Val("hello").Val(100).Val(200).Call(3).EndStmt(). 1016 Val(fn1).Typ(types.Typ[types.String]).Typ(types.Typ[types.Int]).Typ(types.Typ[types.Uint]).Index(3, false).Val("hello").Val(100).Val(200).Call(3).EndStmt(). 1017 Val(fn1).Typ(types.Typ[types.String]).Typ(types.Typ[types.Int]).Index(2, false).Val("hello").Val(100).Val(200).Call(3).EndStmt(). 1018 Val(fn1).Typ(types.Typ[types.String]).Index(1, false).Val("hello").Val(100).Val(200).Call(3).EndStmt(). 1019 End() 1020 1021 domTest(t, pkg, `package main 1022 1023 type T interface { 1024 ~int | uint 1025 } 1026 1027 func test[T1 any, T2 ~int, T3 T](p1 T1, p2 T2, p3 T3) { 1028 } 1029 func main() { 1030 test("hello", 100, 200) 1031 test[string, int, uint]("hello", 100, 200) 1032 test[string, int]("hello", 100, 200) 1033 test[string]("hello", 100, 200) 1034 } 1035 `) 1036 } 1037 1038 func TestGenTypeParamsType(t *testing.T) { 1039 pkg := newMainPackage() 1040 ut := types.NewUnion([]*types.Term{types.NewTerm(true, types.Typ[types.Int]), types.NewTerm(false, types.Typ[types.Uint])}) 1041 it := pkg.NewType("T").InitType(pkg, types.NewInterfaceType(nil, []types.Type{ut})) 1042 1043 // type M 1044 mp1 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T", nil), ut) 1045 mp2 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T", nil), ut) 1046 mt1 := pkg.NewType("M").InitType(pkg, types.NewStruct(nil, nil), mp1) 1047 msig1 := types.NewSignatureType(types.NewVar(token.NoPos, pkg.Types, "m1", types.NewPointer(mt1)), []*types.TypeParam{mp2}, nil, nil, nil, false) 1048 mfn1 := pkg.NewFuncDecl(token.NoPos, "test", msig1) 1049 mfn1.BodyStart(pkg).End() 1050 1051 // type S 1052 sp1 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T1", nil), types.Universe.Lookup("any").Type()) 1053 sp2 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T2", nil), ut) 1054 sp3 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T3", nil), it) 1055 1056 st := types.NewStruct([]*types.Var{ 1057 types.NewField(token.NoPos, pkg.Types, "f1", sp1, false), 1058 types.NewField(token.NoPos, pkg.Types, "f2", sp2, false), 1059 types.NewField(token.NoPos, pkg.Types, "f3", sp3, false), 1060 }, nil) 1061 named := pkg.NewType("S").InitType(pkg, st, sp1, sp2, sp3) 1062 1063 tp1 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T1", nil), types.Universe.Lookup("any").Type()) 1064 tp2 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T2", nil), ut) 1065 tp3 := types.NewTypeParam(types.NewTypeName(token.NoPos, pkg.Types, "T3", nil), it) 1066 p1 := types.NewParam(token.NoPos, pkg.Types, "p1", tp1) 1067 p2 := types.NewParam(token.NoPos, pkg.Types, "p2", tp2) 1068 p3 := types.NewParam(token.NoPos, pkg.Types, "p3", tp3) 1069 1070 sig := types.NewSignatureType(types.NewVar(token.NoPos, pkg.Types, "r1", types.NewPointer(named)), []*types.TypeParam{tp1, tp2, tp3}, nil, types.NewTuple(p1, p2, p3), nil, false) 1071 fn1 := pkg.NewFuncDecl(token.NoPos, "test", sig) 1072 fn1.BodyStart(pkg).End() 1073 1074 inst, err := types.Instantiate(nil, named, []types.Type{types.Typ[types.String], types.Typ[types.Int], types.Typ[types.Uint]}, true) 1075 if err != nil { 1076 t.Fatal(err) 1077 } 1078 pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg). 1079 DefineVarStart(token.NoPos, "s").StructLit(inst, 0, false).UnaryOp(token.AND).EndInit(1). 1080 Val(ctxRef(pkg, "s")).MemberVal("test").Val("hello").Val(100).Val(200).Call(3, false).EndStmt(). 1081 Val(pkg.Builtin().Ref("println")).Val(ctxRef(pkg, "s")).MemberVal("f1").Call(1, false).EndStmt(). 1082 End() 1083 1084 domTest(t, pkg, `package main 1085 1086 type T interface { 1087 ~int | uint 1088 } 1089 type M[T ~int | uint] struct { 1090 } 1091 1092 func (m1 *M[T]) test() { 1093 } 1094 1095 type S[T1 any, T2 ~int | uint, T3 T] struct { 1096 f1 T1 1097 f2 T2 1098 f3 T3 1099 } 1100 1101 func (r1 *S[T1, T2, T3]) test(p1 T1, p2 T2, p3 T3) { 1102 } 1103 func main() { 1104 s := &S[string, int, uint]{} 1105 s.test("hello", 100, 200) 1106 println(s.f1) 1107 } 1108 `) 1109 }