@@ -317,15 +317,15 @@ func TestBlocking_Defers_WithReturns_WithNamedFuncs(t *testing.T) {
317
317
bt .assertNotBlocking (`nonBlockingPrint` )
318
318
319
319
bt .assertBlocking (`blockingBody` )
320
- bt .assertBlockingReturn (13 )
320
+ bt .assertBlockingReturn (13 , `` )
321
321
322
322
bt .assertBlocking (`blockingArg` )
323
323
// The defer is non-blocking so the return is not blocking
324
324
// even though the function is blocking.
325
- bt .assertNotBlockingReturn (18 )
325
+ bt .assertNotBlockingReturn (18 , `` )
326
326
327
327
bt .assertNotBlocking (`notBlocking` )
328
- bt .assertNotBlockingReturn (23 )
328
+ bt .assertNotBlockingReturn (23 , `` )
329
329
}
330
330
331
331
func TestBlocking_Defers_WithMultipleReturns (t * testing.T ) {
@@ -365,13 +365,13 @@ func TestBlocking_Defers_WithMultipleReturns(t *testing.T) {
365
365
bt .assertBlocking (`foo` )
366
366
bt .assertNotBlockingLit (4 , `` )
367
367
// Early escape from function without blocking defers is not blocking.
368
- bt .assertNotBlockingReturn (11 )
368
+ bt .assertNotBlockingReturn (11 , `` )
369
369
bt .assertNotBlockingLit (14 , `` )
370
370
// Function has had blocking by this point but no blocking defers yet.
371
- bt .assertNotBlockingReturn (20 )
371
+ bt .assertNotBlockingReturn (20 , `` )
372
372
bt .assertBlockingLit (24 , `` )
373
373
// The return is blocking because of a blocking defer.
374
- bt .assertBlockingReturn (28 )
374
+ bt .assertBlockingReturn (28 , `` )
375
375
// Technically the return on line 31 is not blocking since the defer that
376
376
// is blocking can only exit through the return on line 28, but it would be
377
377
// difficult to determine which defers would only affect certain returns
@@ -384,7 +384,7 @@ func TestBlocking_Defers_WithMultipleReturns(t *testing.T) {
384
384
//
385
385
// For now we simply build up the list of defers as we go making
386
386
// the return on line 31 also blocking.
387
- bt .assertBlockingReturn (31 )
387
+ bt .assertBlockingReturn (31 , `` )
388
388
}
389
389
390
390
func TestBlocking_Defers_WithReturnsAndDefaultBlocking (t * testing.T ) {
@@ -453,12 +453,12 @@ func TestBlocking_Defers_WithReturnsAndDefaultBlocking(t *testing.T) {
453
453
bt .assertBlocking (`deferMappedFuncCall` )
454
454
455
455
// All of these returns are blocking because they have blocking defers.
456
- bt .assertBlockingReturn (17 )
457
- bt .assertBlockingReturn (22 )
458
- bt .assertBlockingReturn (28 )
459
- bt .assertBlockingReturn (34 )
460
- bt .assertBlockingReturn (40 )
461
- bt .assertBlockingReturn (49 )
456
+ bt .assertBlockingReturn (17 , `` )
457
+ bt .assertBlockingReturn (22 , `` )
458
+ bt .assertBlockingReturn (28 , `` )
459
+ bt .assertBlockingReturn (34 , `` )
460
+ bt .assertBlockingReturn (40 , `` )
461
+ bt .assertBlockingReturn (49 , `` )
462
462
}
463
463
464
464
func TestBlocking_Defers_WithReturnsAndDeferBuiltin (t * testing.T ) {
@@ -477,7 +477,7 @@ func TestBlocking_Defers_WithReturnsAndDeferBuiltin(t *testing.T) {
477
477
478
478
bt .assertFuncInstCount (1 )
479
479
bt .assertNotBlocking (`deferBuiltinCall` )
480
- bt .assertNotBlockingReturn (10 )
480
+ bt .assertNotBlockingReturn (10 , `` )
481
481
}
482
482
483
483
func TestBlocking_Defers_WithReturnsInLoops (t * testing.T ) {
@@ -575,14 +575,14 @@ func TestBlocking_Defers_WithReturnsInLoops(t *testing.T) {
575
575
// When the following 2 returns are defined there are no defers, however,
576
576
// because of the loop, the blocking defers defined after the return will
577
577
// block the returns.
578
- bt .assertBlockingReturn (12 )
579
- bt .assertBlockingReturn (22 )
580
- bt .assertBlockingReturn (31 )
581
- bt .assertBlockingReturn (44 )
582
- bt .assertBlockingReturn (52 )
583
- bt .assertBlockingReturn (66 )
584
- bt .assertBlockingReturn (73 )
585
- bt .assertBlockingReturn (77 )
578
+ bt .assertBlockingReturn (12 , `` )
579
+ bt .assertBlockingReturn (22 , `` )
580
+ bt .assertBlockingReturn (31 , `` )
581
+ bt .assertBlockingReturn (44 , `` )
582
+ bt .assertBlockingReturn (52 , `` )
583
+ bt .assertBlockingReturn (66 , `` )
584
+ bt .assertBlockingReturn (73 , `` )
585
+ bt .assertBlockingReturn (77 , `` )
586
586
}
587
587
588
588
func TestBlocking_Defers_WithReturnsInLoopsInLoops (t * testing.T ) {
@@ -652,19 +652,19 @@ func TestBlocking_Defers_WithReturnsInLoopsInLoops(t *testing.T) {
652
652
bt .assertFuncInstCount (4 )
653
653
bt .assertBlocking (`blocking` )
654
654
bt .assertBlocking (`forLoopTheLoop` )
655
- bt .assertNotBlockingReturn (9 )
656
- bt .assertBlockingReturn (13 )
657
- bt .assertBlockingReturn (17 )
658
- bt .assertBlockingReturn (21 )
659
- bt .assertBlockingReturn (25 )
660
- bt .assertBlockingReturn (28 )
655
+ bt .assertNotBlockingReturn (9 , `` )
656
+ bt .assertBlockingReturn (13 , `` )
657
+ bt .assertBlockingReturn (17 , `` )
658
+ bt .assertBlockingReturn (21 , `` )
659
+ bt .assertBlockingReturn (25 , `` )
660
+ bt .assertBlockingReturn (28 , `` )
661
661
bt .assertBlocking (`rangeLoopTheLoop` )
662
- bt .assertBlockingReturn (36 )
663
- bt .assertBlockingReturn (41 )
662
+ bt .assertBlockingReturn (36 , `` )
663
+ bt .assertBlockingReturn (41 , `` )
664
664
bt .assertBlocking (`noopThenLoop` )
665
- bt .assertNotBlockingReturn (48 )
666
- bt .assertBlockingReturn (54 )
667
- bt .assertBlockingReturn (58 )
665
+ bt .assertNotBlockingReturn (48 , `` )
666
+ bt .assertBlockingReturn (54 , `` )
667
+ bt .assertBlockingReturn (58 , `` )
668
668
}
669
669
670
670
func TestBlocking_Returns_WithoutDefers (t * testing.T ) {
@@ -693,19 +693,67 @@ func TestBlocking_Returns_WithoutDefers(t *testing.T) {
693
693
return true // line 22
694
694
}` )
695
695
bt .assertBlocking (`blocking` )
696
- bt .assertBlockingReturn (4 )
696
+ bt .assertBlockingReturn (4 , `` )
697
697
698
698
bt .assertBlocking (`blockingBeforeReturn` )
699
- bt .assertNotBlockingReturn (9 )
699
+ bt .assertNotBlockingReturn (9 , `` )
700
700
701
701
bt .assertBlocking (`indirectlyBlocking` )
702
- bt .assertBlockingReturn (13 )
702
+ bt .assertBlockingReturn (13 , `` )
703
703
704
704
bt .assertBlocking (`indirectlyBlockingBeforeReturn` )
705
- bt .assertNotBlockingReturn (18 )
705
+ bt .assertNotBlockingReturn (18 , `` )
706
706
707
707
bt .assertNotBlocking (`notBlocking` )
708
- bt .assertNotBlockingReturn (22 )
708
+ bt .assertNotBlockingReturn (22 , `` )
709
+ }
710
+
711
+ func TestBlocking_Defers_WithReturnsInInstances (t * testing.T ) {
712
+ // This is an example of a deferred function literal inside of
713
+ // an instance of a generic function affecting the return
714
+ // differently based on the type arguments of the instance.
715
+ bt := newBlockingTest (t ,
716
+ `package test
717
+
718
+ type BazBlocker struct {
719
+ c chan bool
720
+ }
721
+ func (bb BazBlocker) Baz() {
722
+ println(<-bb.c)
723
+ }
724
+
725
+ type BazNotBlocker struct {}
726
+ func (bnb BazNotBlocker) Baz() {
727
+ println("hi")
728
+ }
729
+
730
+ type Foo interface { Baz() }
731
+ func FooBaz[T Foo]() bool {
732
+ defer func() { // line 17
733
+ var foo T
734
+ foo.Baz()
735
+ }()
736
+ return true // line 21
737
+ }
738
+
739
+ func main() {
740
+ FooBaz[BazBlocker]()
741
+ FooBaz[BazNotBlocker]()
742
+ }` )
743
+
744
+ bt .assertFuncInstCount (5 )
745
+ bt .assertBlocking (`BazBlocker.Baz` )
746
+ bt .assertNotBlocking (`BazNotBlocker.Baz` )
747
+ bt .assertBlockingInst (`pkg/test.FooBaz<pkg/test.BazBlocker>` )
748
+ bt .assertNotBlockingInst (`pkg/test.FooBaz<pkg/test.BazNotBlocker>` )
749
+ bt .assertBlocking (`main` )
750
+
751
+ bt .assertFuncLitCount (2 )
752
+ bt .assertBlockingLit (17 , `pkg/test.BazBlocker` )
753
+ bt .assertNotBlockingLit (17 , `pkg/test.BazNotBlocker` )
754
+
755
+ bt .assertBlockingReturn (21 , `pkg/test.BazBlocker` )
756
+ bt .assertNotBlockingReturn (21 , `pkg/test.BazNotBlocker` )
709
757
}
710
758
711
759
func TestBlocking_Defers_WithReturnsAndOtherPackages (t * testing.T ) {
@@ -737,10 +785,10 @@ func TestBlocking_Defers_WithReturnsAndOtherPackages(t *testing.T) {
737
785
bt := newBlockingTestWithOtherPackage (t , testSrc , otherSrc )
738
786
739
787
bt .assertBlocking (`deferOtherBlocking` )
740
- bt .assertBlockingReturn (7 )
788
+ bt .assertBlockingReturn (7 , `` )
741
789
742
790
bt .assertNotBlocking (`deferOtherNotBlocking` )
743
- bt .assertNotBlockingReturn (12 )
791
+ bt .assertNotBlockingReturn (12 , `` )
744
792
}
745
793
746
794
func TestBlocking_FunctionLiteral (t * testing.T ) {
@@ -1652,15 +1700,23 @@ func (bt *blockingTest) assertFuncInstCount(expCount int) {
1652
1700
}
1653
1701
1654
1702
func (bt * blockingTest ) assertFuncLitCount (expCount int ) {
1655
- if got := len (bt .pkgInfo .funcLitInfos ); got != expCount {
1703
+ got := 0
1704
+ for _ , fis := range bt .pkgInfo .funcLitInfos {
1705
+ got += len (fis )
1706
+ }
1707
+ if got != expCount {
1656
1708
bt .f .T .Errorf (`Got %d function literal infos but expected %d.` , got , expCount )
1657
- pos := make ([]string , 0 , len (bt .pkgInfo .funcLitInfos ))
1658
- for fl := range bt .pkgInfo .funcLitInfos {
1659
- pos = append (pos , bt .f .FileSet .Position (fl .Pos ()).String ())
1709
+
1710
+ lits := make ([]string , 0 , len (bt .pkgInfo .funcLitInfos ))
1711
+ for fl , fis := range bt .pkgInfo .funcLitInfos {
1712
+ pos := bt .f .FileSet .Position (fl .Pos ()).String ()
1713
+ for _ , fi := range fis {
1714
+ lits = append (lits , pos + `<` + fi .typeArgs .String ()+ `>` )
1715
+ }
1660
1716
}
1661
- sort .Strings (pos )
1662
- for i := range pos {
1663
- bt .f .T .Logf (` %d. %q` , i + 1 , pos )
1717
+ sort .Strings (lits )
1718
+ for i := range lits {
1719
+ bt .f .T .Logf (` %d. %q` , i + 1 , lits [ i ] )
1664
1720
}
1665
1721
}
1666
1722
}
@@ -1716,13 +1772,13 @@ func (bt *blockingTest) isTypesFuncBlocking(funcName string) bool {
1716
1772
1717
1773
func (bt * blockingTest ) assertBlockingLit (lineNo int , typeArgsStr string ) {
1718
1774
if ! bt .isFuncLitBlocking (lineNo , typeArgsStr ) {
1719
- bt .f .T .Errorf (`Got FuncLit at line %d with type args %q as not blocking but expected it to be blocking.` , lineNo , typeArgsStr )
1775
+ bt .f .T .Errorf (`Got FuncLit at line %d with type args %q as not blocking but expected it to be blocking.` , lineNo , typeArgsStr )
1720
1776
}
1721
1777
}
1722
1778
1723
1779
func (bt * blockingTest ) assertNotBlockingLit (lineNo int , typeArgsStr string ) {
1724
1780
if bt .isFuncLitBlocking (lineNo , typeArgsStr ) {
1725
- bt .f .T .Errorf (`Got FuncLit at line %d with type args %q as blocking but expected it to be not blocking.` , lineNo , typeArgsStr )
1781
+ bt .f .T .Errorf (`Got FuncLit at line %d with type args %q as blocking but expected it to be not blocking.` , lineNo , typeArgsStr )
1726
1782
}
1727
1783
}
1728
1784
@@ -1745,7 +1801,7 @@ func (bt *blockingTest) isFuncLitBlocking(lineNo int, typeArgsStr string) bool {
1745
1801
1746
1802
bt .f .T .Logf ("FuncList instances:" )
1747
1803
for i , fi := range fis {
1748
- bt .f .T .Logf ("\t %d. %q\n " , i , fi .typeArgs .String ())
1804
+ bt .f .T .Logf ("\t %d. %q\n " , i + 1 , fi .typeArgs .String ())
1749
1805
}
1750
1806
bt .f .T .Fatalf (`No FuncInfo found for FuncLit at line %d with type args %q.` , lineNo , typeArgsStr )
1751
1807
return false
@@ -1772,34 +1828,52 @@ func (bt *blockingTest) isFuncInstBlocking(instanceStr string) bool {
1772
1828
}
1773
1829
bt .f .T .Logf (`Function instances found in package info:` )
1774
1830
for i , inst := range instances {
1775
- bt .f .T .Logf (` %d. %s` , i + 1 , inst .String ())
1831
+ bt .f .T .Logf (" \t %d. %s" , i + 1 , inst .String ())
1776
1832
}
1777
1833
bt .f .T .Fatalf (`No function instance found for %q in package info.` , instanceStr )
1778
1834
return false
1779
1835
}
1780
1836
1781
- func (bt * blockingTest ) assertBlockingReturn (lineNo int ) {
1782
- if ! bt .isReturnBlocking (lineNo ) {
1783
- bt .f .T .Errorf (`Got return at line %d as not blocking but expected it to be blocking.` , lineNo )
1837
+ func (bt * blockingTest ) assertBlockingReturn (lineNo int , typeArgsStr string ) {
1838
+ if ! bt .isReturnBlocking (lineNo , typeArgsStr ) {
1839
+ bt .f .T .Errorf (`Got return at line %d (%q) as not blocking but expected it to be blocking.` , lineNo , typeArgsStr )
1784
1840
}
1785
1841
}
1786
1842
1787
- func (bt * blockingTest ) assertNotBlockingReturn (lineNo int ) {
1788
- if bt .isReturnBlocking (lineNo ) {
1789
- bt .f .T .Errorf (`Got return at line %d as blocking but expected it to be not blocking.` , lineNo )
1843
+ func (bt * blockingTest ) assertNotBlockingReturn (lineNo int , typeArgsStr string ) {
1844
+ if bt .isReturnBlocking (lineNo , typeArgsStr ) {
1845
+ bt .f .T .Errorf (`Got return at line %d (%q) as blocking but expected it to be not blocking.` , lineNo , typeArgsStr )
1790
1846
}
1791
1847
}
1792
1848
1793
- func (bt * blockingTest ) isReturnBlocking (lineNo int ) bool {
1849
+ func (bt * blockingTest ) isReturnBlocking (lineNo int , typeArgsStr string ) bool {
1794
1850
ret := srctesting .GetNodeAtLineNo [* ast.ReturnStmt ](bt .file , bt .f .FileSet , lineNo )
1795
1851
if ret == nil {
1796
1852
bt .f .T .Fatalf (`ReturnStmt on line %d not found in the AST.` , lineNo )
1797
1853
}
1854
+
1855
+ foundInfo := []* FuncInfo {}
1798
1856
for _ , info := range bt .pkgInfo .allInfos {
1799
- if blocking , found := info .Blocking [ret ]; found {
1800
- return blocking
1857
+ for _ , rs := range info .returnStmts {
1858
+ if rs .analyzeStack [len (rs .analyzeStack )- 1 ] == ret {
1859
+ if info .typeArgs .String () == typeArgsStr {
1860
+ // Found info that matches the type args and
1861
+ // has the return statement so return the blocking value.
1862
+ return info .Blocking [ret ]
1863
+ }
1864
+
1865
+ // Wrong instance, record for error message in the case
1866
+ // that the correct one instance is not found.
1867
+ foundInfo = append (foundInfo , info )
1868
+ break
1869
+ }
1801
1870
}
1802
1871
}
1803
- // If not found in any info.Blocking, then it is not blocking.
1872
+
1873
+ bt .f .T .Logf ("FuncInfo instances with ReturnStmt at line %d:" , lineNo )
1874
+ for i , info := range foundInfo {
1875
+ bt .f .T .Logf ("\t %d. %q\n " , i + 1 , info .typeArgs .String ())
1876
+ }
1877
+ bt .f .T .Fatalf (`No FuncInfo found for ReturnStmt at line %d with type args %q.` , lineNo , typeArgsStr )
1804
1878
return false
1805
1879
}
0 commit comments