github.com/v2fly/tools@v0.100.0/internal/apidiff/testdata/tests.go (about) 1 // This file is split into two packages, old and new. 2 // It is syntactically valid Go so that gofmt can process it. 3 // 4 // If a comment begins with: Then: 5 // old write subsequent lines to the "old" package 6 // new write subsequent lines to the "new" package 7 // both write subsequent lines to both packages 8 // c expect a compatible error with the following text 9 // i expect an incompatible error with the following text 10 package ignore 11 12 // both 13 import "io" 14 15 //////////////// Basics 16 17 //// Same type in both: OK. 18 // both 19 type A int 20 21 //// Changing the type is an incompatible change. 22 // old 23 type B int 24 25 // new 26 // i B: changed from int to string 27 type B string 28 29 //// Adding a new type, whether alias or not, is a compatible change. 30 // new 31 // c AA: added 32 type AA = A 33 34 // c B1: added 35 type B1 bool 36 37 //// Change of type for an unexported name doesn't matter... 38 // old 39 type t int 40 41 // new 42 type t string // OK: t isn't part of the API 43 44 //// ...unless it is exposed. 45 // both 46 var V2 u 47 48 // old 49 type u string 50 51 // new 52 // i u: changed from string to int 53 type u int 54 55 //// An exposed, unexported type can be renamed. 56 // both 57 type u2 int 58 59 // old 60 type u1 int 61 62 var V5 u1 63 64 // new 65 var V5 u2 // OK: V5 has changed type, but old u1 corresopnds to new u2 66 67 //// Splitting a single type into two is an incompatible change. 68 // both 69 type u3 int 70 71 // old 72 type ( 73 Split1 = u1 74 Split2 = u1 75 ) 76 77 // new 78 type ( 79 Split1 = u2 // OK, since old u1 corresponds to new u2 80 81 // This tries to make u1 correspond to u3 82 // i Split2: changed from u1 to u3 83 Split2 = u3 84 ) 85 86 //// Merging two types into one is OK. 87 // old 88 type ( 89 GoodMerge1 = u2 90 GoodMerge2 = u3 91 ) 92 93 // new 94 type ( 95 GoodMerge1 = u3 96 GoodMerge2 = u3 97 ) 98 99 //// Merging isn't OK here because a method is lost. 100 // both 101 type u4 int 102 103 func (u4) M() {} 104 105 // old 106 type ( 107 BadMerge1 = u3 108 BadMerge2 = u4 109 ) 110 111 // new 112 type ( 113 BadMerge1 = u3 114 // i u4.M: removed 115 // What's really happening here is that old u4 corresponds to new u3, 116 // and new u3's method set is not a superset of old u4's. 117 BadMerge2 = u3 118 ) 119 120 // old 121 type Rem int 122 123 // new 124 // i Rem: removed 125 126 //////////////// Constants 127 128 //// type changes 129 // old 130 const ( 131 C1 = 1 132 C2 int = 2 133 C3 = 3 134 C4 u1 = 4 135 ) 136 137 var V8 int 138 139 // new 140 const ( 141 // i C1: changed from untyped int to untyped string 142 C1 = "1" 143 // i C2: changed from int to untyped int 144 C2 = -1 145 // i C3: changed from untyped int to int 146 C3 int = 3 147 // i V8: changed from var to const 148 V8 int = 1 149 C4 u2 = 4 // OK: u1 corresponds to u2 150 ) 151 152 // value change 153 // old 154 const ( 155 Cr1 = 1 156 Cr2 = "2" 157 Cr3 = 3.5 158 Cr4 = complex(0, 4.1) 159 ) 160 161 // new 162 const ( 163 // i Cr1: value changed from 1 to -1 164 Cr1 = -1 165 // i Cr2: value changed from "2" to "3" 166 Cr2 = "3" 167 // i Cr3: value changed from 3.5 to 3.8 168 Cr3 = 3.8 169 // i Cr4: value changed from (0 + 4.1i) to (4.1 + 0i) 170 Cr4 = complex(4.1, 0) 171 ) 172 173 //////////////// Variables 174 175 //// simple type changes 176 // old 177 var ( 178 V1 string 179 V3 A 180 V7 <-chan int 181 ) 182 183 // new 184 var ( 185 // i V1: changed from string to []string 186 V1 []string 187 V3 A // OK: same 188 // i V7: changed from <-chan int to chan int 189 V7 chan int 190 ) 191 192 //// interface type changes 193 // old 194 var ( 195 V9 interface{ M() } 196 V10 interface{ M() } 197 V11 interface{ M() } 198 ) 199 200 // new 201 var ( 202 // i V9: changed from interface{M()} to interface{} 203 V9 interface{} 204 // i V10: changed from interface{M()} to interface{M(); M2()} 205 V10 interface { 206 M2() 207 M() 208 } 209 // i V11: changed from interface{M()} to interface{M(int)} 210 V11 interface{ M(int) } 211 ) 212 213 //// struct type changes 214 // old 215 var ( 216 VS1 struct{ A, B int } 217 VS2 struct{ A, B int } 218 VS3 struct{ A, B int } 219 VS4 struct { 220 A int 221 u1 222 } 223 ) 224 225 // new 226 var ( 227 // i VS1: changed from struct{A int; B int} to struct{B int; A int} 228 VS1 struct{ B, A int } 229 // i VS2: changed from struct{A int; B int} to struct{A int} 230 VS2 struct{ A int } 231 // i VS3: changed from struct{A int; B int} to struct{A int; B int; C int} 232 VS3 struct{ A, B, C int } 233 VS4 struct { 234 A int 235 u2 236 } 237 ) 238 239 //////////////// Types 240 241 // old 242 const C5 = 3 243 244 type ( 245 A1 [1]int 246 A2 [2]int 247 A3 [C5]int 248 ) 249 250 // new 251 // i C5: value changed from 3 to 4 252 const C5 = 4 253 254 type ( 255 A1 [1]int 256 // i A2: changed from [2]int to [2]bool 257 A2 [2]bool 258 // i A3: changed from [3]int to [4]int 259 A3 [C5]int 260 ) 261 262 // old 263 type ( 264 Sl []int 265 P1 *int 266 P2 *u1 267 ) 268 269 // new 270 type ( 271 // i Sl: changed from []int to []string 272 Sl []string 273 // i P1: changed from *int to **bool 274 P1 **bool 275 P2 *u2 // OK: u1 corresponds to u2 276 ) 277 278 // old 279 type Bc1 int32 280 type Bc2 uint 281 type Bc3 float32 282 type Bc4 complex64 283 284 // new 285 // c Bc1: changed from int32 to int 286 type Bc1 int 287 288 // c Bc2: changed from uint to uint64 289 type Bc2 uint64 290 291 // c Bc3: changed from float32 to float64 292 type Bc3 float64 293 294 // c Bc4: changed from complex64 to complex128 295 type Bc4 complex128 296 297 // old 298 type Bi1 int32 299 type Bi2 uint 300 type Bi3 float64 301 type Bi4 complex128 302 303 // new 304 // i Bi1: changed from int32 to int16 305 type Bi1 int16 306 307 // i Bi2: changed from uint to uint32 308 type Bi2 uint32 309 310 // i Bi3: changed from float64 to float32 311 type Bi3 float32 312 313 // i Bi4: changed from complex128 to complex64 314 type Bi4 complex64 315 316 // old 317 type ( 318 M1 map[string]int 319 M2 map[string]int 320 M3 map[string]int 321 ) 322 323 // new 324 type ( 325 M1 map[string]int 326 // i M2: changed from map[string]int to map[int]int 327 M2 map[int]int 328 // i M3: changed from map[string]int to map[string]string 329 M3 map[string]string 330 ) 331 332 // old 333 type ( 334 Ch1 chan int 335 Ch2 <-chan int 336 Ch3 chan int 337 Ch4 <-chan int 338 ) 339 340 // new 341 type ( 342 // i Ch1, element type: changed from int to bool 343 Ch1 chan bool 344 // i Ch2: changed direction 345 Ch2 chan<- int 346 // i Ch3: changed direction 347 Ch3 <-chan int 348 // c Ch4: removed direction 349 Ch4 chan int 350 ) 351 352 // old 353 type I1 interface { 354 M1() 355 M2() 356 } 357 358 // new 359 type I1 interface { 360 // M1() 361 // i I1.M1: removed 362 M2(int) 363 // i I1.M2: changed from func() to func(int) 364 M3() 365 // i I1.M3: added 366 m() 367 // i I1.m: added unexported method 368 } 369 370 // old 371 type I2 interface { 372 M1() 373 m() 374 } 375 376 // new 377 type I2 interface { 378 M1() 379 // m() Removing an unexported method is OK. 380 m2() // OK, because old already had an unexported method 381 // c I2.M2: added 382 M2() 383 } 384 385 // old 386 type I3 interface { 387 io.Reader 388 M() 389 } 390 391 // new 392 // OK: what matters is the method set; the name of the embedded 393 // interface isn't important. 394 type I3 interface { 395 M() 396 Read([]byte) (int, error) 397 } 398 399 // old 400 type I4 io.Writer 401 402 // new 403 // OK: in both, I4 is a distinct type from io.Writer, and 404 // the old and new I4s have the same method set. 405 type I4 interface { 406 Write([]byte) (int, error) 407 } 408 409 // old 410 type I5 = io.Writer 411 412 // new 413 // i I5: changed from io.Writer to I5 414 // In old, I5 and io.Writer are the same type; in new, 415 // they are different. That can break something like: 416 // var _ func(io.Writer) = func(pkg.I6) {} 417 type I5 io.Writer 418 419 // old 420 type I6 interface{ Write([]byte) (int, error) } 421 422 // new 423 // i I6: changed from I6 to io.Writer 424 // Similar to the above. 425 type I6 = io.Writer 426 427 //// correspondence with a basic type 428 // Basic types are technically defined types, but they aren't 429 // represented that way in go/types, so the cases below are special. 430 431 // both 432 type T1 int 433 434 // old 435 var VT1 T1 436 437 // new 438 // i VT1: changed from T1 to int 439 // This fails because old T1 corresponds to both int and new T1. 440 var VT1 int 441 442 // old 443 type t2 int 444 445 var VT2 t2 446 447 // new 448 // OK: t2 corresponds to int. It's fine that old t2 449 // doesn't exist in new. 450 var VT2 int 451 452 // both 453 type t3 int 454 455 func (t3) M() {} 456 457 // old 458 var VT3 t3 459 460 // new 461 // i t3.M: removed 462 // Here the change from t3 to int is incompatible 463 // because old t3 has an exported method. 464 var VT3 int 465 466 // old 467 var VT4 int 468 469 // new 470 type t4 int 471 472 // i VT4: changed from int to t4 473 // This is incompatible because of code like 474 // VT4 + int(1) 475 // which works in old but fails in new. 476 // The difference from the above cases is that 477 // in those, we were merging two types into one; 478 // here, we are splitting int into t4 and int. 479 var VT4 t4 480 481 //////////////// Functions 482 483 // old 484 func F1(a int, b string) map[u1]A { return nil } 485 func F2(int) {} 486 func F3(int) {} 487 func F4(int) int { return 0 } 488 func F5(int) int { return 0 } 489 func F6(int) {} 490 func F7(interface{}) {} 491 492 // new 493 func F1(c int, d string) map[u2]AA { return nil } //OK: same (since u1 corresponds to u2) 494 495 // i F2: changed from func(int) to func(int) bool 496 func F2(int) bool { return true } 497 498 // i F3: changed from func(int) to func(int, int) 499 func F3(int, int) {} 500 501 // i F4: changed from func(int) int to func(bool) int 502 func F4(bool) int { return 0 } 503 504 // i F5: changed from func(int) int to func(int) string 505 func F5(int) string { return "" } 506 507 // i F6: changed from func(int) to func(...int) 508 func F6(...int) {} 509 510 // i F7: changed from func(interface{}) to func(interface{x()}) 511 func F7(a interface{ x() }) {} 512 513 // old 514 func F8(bool) {} 515 516 // new 517 // c F8: changed from func to var 518 var F8 func(bool) 519 520 // old 521 var F9 func(int) 522 523 // new 524 // i F9: changed from var to func 525 func F9(int) {} 526 527 // both 528 // OK, even though new S1 is incompatible with old S1 (see below) 529 func F10(S1) {} 530 531 //////////////// Structs 532 533 // old 534 type S1 struct { 535 A int 536 B string 537 C bool 538 d float32 539 } 540 541 // new 542 type S1 = s1 543 544 type s1 struct { 545 C chan int 546 // i S1.C: changed from bool to chan int 547 A int 548 // i S1.B: removed 549 // i S1: old is comparable, new is not 550 x []int 551 d float32 552 E bool 553 // c S1.E: added 554 } 555 556 // old 557 type embed struct { 558 E string 559 } 560 561 type S2 struct { 562 A int 563 embed 564 } 565 566 // new 567 type embedx struct { 568 E string 569 } 570 571 type S2 struct { 572 embedx // OK: the unexported embedded field changed names, but the exported field didn't 573 A int 574 } 575 576 // both 577 type F int 578 579 // old 580 type S3 struct { 581 A int 582 embed 583 } 584 585 // new 586 type embed struct{ F int } 587 588 type S3 struct { 589 // i S3.E: removed 590 embed 591 // c S3.F: added 592 A int 593 } 594 595 // old 596 type embed2 struct { 597 embed3 598 F // shadows embed3.F 599 } 600 601 type embed3 struct { 602 F bool 603 } 604 605 type alias = struct{ D bool } 606 607 type S4 struct { 608 int 609 *embed2 610 embed 611 E int // shadows embed.E 612 alias 613 A1 614 *S4 615 } 616 617 // new 618 type S4 struct { 619 // OK: removed unexported fields 620 // D and F marked as added because they are now part of the immediate fields 621 D bool 622 // c S4.D: added 623 E int // OK: same as in old 624 F F 625 // c S4.F: added 626 A1 // OK: same 627 *S4 // OK: same (recursive embedding) 628 } 629 630 //// Difference between exported selectable fields and exported immediate fields. 631 // both 632 type S5 struct{ A int } 633 634 // old 635 // Exported immediate fields: A, S5 636 // Exported selectable fields: A int, S5 S5 637 type S6 struct { 638 S5 S5 639 A int 640 } 641 642 // new 643 // Exported immediate fields: S5 644 // Exported selectable fields: A int, S5 S5. 645 646 // i S6.A: removed 647 type S6 struct { 648 S5 649 } 650 651 //// Ambiguous fields can exist; they just can't be selected. 652 // both 653 type ( 654 embed7a struct{ E int } 655 embed7b struct{ E bool } 656 ) 657 658 // old 659 type S7 struct { // legal, but no selectable fields 660 embed7a 661 embed7b 662 } 663 664 // new 665 type S7 struct { 666 embed7a 667 embed7b 668 // c S7.E: added 669 E string 670 } 671 672 //////////////// Method sets 673 674 // old 675 type SM struct { 676 embedm 677 Embedm 678 } 679 680 func (SM) V1() {} 681 func (SM) V2() {} 682 func (SM) V3() {} 683 func (SM) V4() {} 684 func (SM) v() {} 685 686 func (*SM) P1() {} 687 func (*SM) P2() {} 688 func (*SM) P3() {} 689 func (*SM) P4() {} 690 func (*SM) p() {} 691 692 type embedm int 693 694 func (embedm) EV1() {} 695 func (embedm) EV2() {} 696 func (embedm) EV3() {} 697 func (*embedm) EP1() {} 698 func (*embedm) EP2() {} 699 func (*embedm) EP3() {} 700 701 type Embedm struct { 702 A int 703 } 704 705 func (Embedm) FV() {} 706 func (*Embedm) FP() {} 707 708 type RepeatEmbedm struct { 709 Embedm 710 } 711 712 // new 713 type SM struct { 714 embedm2 715 embedm3 716 Embedm 717 // i SM.A: changed from int to bool 718 } 719 720 // c SMa: added 721 type SMa = SM 722 723 func (SM) V1() {} // OK: same 724 725 // func (SM) V2() {} 726 // i SM.V2: removed 727 728 // i SM.V3: changed from func() to func(int) 729 func (SM) V3(int) {} 730 731 // c SM.V5: added 732 func (SM) V5() {} 733 734 func (SM) v(int) {} // OK: unexported method change 735 func (SM) v2() {} // OK: unexported method added 736 737 func (*SM) P1() {} // OK: same 738 //func (*SM) P2() {} 739 // i (*SM).P2: removed 740 741 // i (*SM).P3: changed from func() to func(int) 742 func (*SMa) P3(int) {} 743 744 // c (*SM).P5: added 745 func (*SM) P5() {} 746 747 // func (*SM) p() {} // OK: unexported method removed 748 749 // Changing from a value to a pointer receiver or vice versa 750 // just looks like adding and removing a method. 751 752 // i SM.V4: removed 753 // i (*SM).V4: changed from func() to func(int) 754 func (*SM) V4(int) {} 755 756 // c SM.P4: added 757 // P4 is not removed from (*SM) because value methods 758 // are in the pointer method set. 759 func (SM) P4() {} 760 761 type embedm2 int 762 763 // i embedm.EV1: changed from func() to func(int) 764 func (embedm2) EV1(int) {} 765 766 // i embedm.EV2, method set of SM: removed 767 // i embedm.EV2, method set of *SM: removed 768 769 // i (*embedm).EP2, method set of *SM: removed 770 func (*embedm2) EP1() {} 771 772 type embedm3 int 773 774 func (embedm3) EV3() {} // OK: compatible with old embedm.EV3 775 func (*embedm3) EP3() {} // OK: compatible with old (*embedm).EP3 776 777 type Embedm struct { 778 // i Embedm.A: changed from int to bool 779 A bool 780 } 781 782 // i Embedm.FV: changed from func() to func(int) 783 func (Embedm) FV(int) {} 784 func (*Embedm) FP() {} 785 786 type RepeatEmbedm struct { 787 // i RepeatEmbedm.A: changed from int to bool 788 Embedm 789 } 790 791 //////////////// Whole-package interface satisfaction 792 793 // old 794 type WI1 interface { 795 M1() 796 m1() 797 } 798 799 type WI2 interface { 800 M2() 801 m2() 802 } 803 804 type WS1 int 805 806 func (WS1) M1() {} 807 func (WS1) m1() {} 808 809 type WS2 int 810 811 func (WS2) M2() {} 812 func (WS2) m2() {} 813 814 // new 815 type WI1 interface { 816 M1() 817 m() 818 } 819 820 type WS1 int 821 822 func (WS1) M1() {} 823 824 // i WS1: no longer implements WI1 825 //func (WS1) m1() {} 826 827 type WI2 interface { 828 M2() 829 m2() 830 // i WS2: no longer implements WI2 831 m3() 832 } 833 834 type WS2 int 835 836 func (WS2) M2() {} 837 func (WS2) m2() {} 838 839 //////////////// Miscellany 840 841 // This verifies that the code works even through 842 // multiple levels of unexported typed. 843 844 // old 845 var Z w 846 847 type w []x 848 type x []z 849 type z int 850 851 // new 852 var Z w 853 854 type w []x 855 type x []z 856 857 // i z: changed from int to bool 858 type z bool 859 860 // old 861 type H struct{} 862 863 func (H) M() {} 864 865 // new 866 // i H: changed from struct{} to interface{M()} 867 type H interface { 868 M() 869 } 870 871 //// Splitting types 872 873 //// OK: in both old and new, {J1, K1, L1} name the same type. 874 // old 875 type ( 876 J1 = K1 877 K1 = L1 878 L1 int 879 ) 880 881 // new 882 type ( 883 J1 = K1 884 K1 int 885 L1 = J1 886 ) 887 888 //// Old has one type, K2; new has J2 and K2. 889 // both 890 type K2 int 891 892 // old 893 type J2 = K2 894 895 // new 896 // i K2: changed from K2 to K2 897 type J2 K2 // old K2 corresponds with new J2 898 // old K2 also corresponds with new K2: problem 899 900 // both 901 type k3 int 902 903 var Vj3 j3 // expose j3 904 905 // old 906 type j3 = k3 907 908 // new 909 // OK: k3 isn't exposed 910 type j3 k3 911 912 // both 913 type k4 int 914 915 var Vj4 j4 // expose j4 916 var VK4 k4 // expose k4 917 918 // old 919 type j4 = k4 920 921 // new 922 // i Vj4: changed from k4 to j4 923 // e.g. p.Vj4 = p.Vk4 924 type j4 k4