github.com/jd-ly/tools@v0.5.7/go/ssa/interp/testdata/boundmeth.go (about) 1 // Tests of bound method closures. 2 3 package main 4 5 import ( 6 "errors" 7 "fmt" 8 ) 9 10 func assert(b bool) { 11 if !b { 12 panic("oops") 13 } 14 } 15 16 type I int 17 18 func (i I) add(x int) int { 19 return int(i) + x 20 } 21 22 func valueReceiver() { 23 var three I = 3 24 assert(three.add(5) == 8) 25 var add3 func(int) int = three.add 26 assert(add3(5) == 8) 27 } 28 29 type S struct{ x int } 30 31 func (s *S) incr() { 32 s.x++ 33 } 34 35 func (s *S) get() int { 36 return s.x 37 } 38 39 func pointerReceiver() { 40 ps := new(S) 41 incr := ps.incr 42 get := ps.get 43 assert(get() == 0) 44 incr() 45 incr() 46 incr() 47 assert(get() == 3) 48 } 49 50 func addressibleValuePointerReceiver() { 51 var s S 52 incr := s.incr 53 get := s.get 54 assert(get() == 0) 55 incr() 56 incr() 57 incr() 58 assert(get() == 3) 59 } 60 61 type S2 struct { 62 S 63 } 64 65 func promotedReceiver() { 66 var s2 S2 67 incr := s2.incr 68 get := s2.get 69 assert(get() == 0) 70 incr() 71 incr() 72 incr() 73 assert(get() == 3) 74 } 75 76 func anonStruct() { 77 var s struct{ S } 78 incr := s.incr 79 get := s.get 80 assert(get() == 0) 81 incr() 82 incr() 83 incr() 84 assert(get() == 3) 85 } 86 87 func typeCheck() { 88 var i interface{} 89 i = (*S).incr 90 _ = i.(func(*S)) // type assertion: receiver type prepended to params 91 92 var s S 93 i = s.incr 94 _ = i.(func()) // type assertion: receiver type disappears 95 } 96 97 type errString string 98 99 func (err errString) Error() string { 100 return string(err) 101 } 102 103 // Regression test for a builder crash. 104 func regress1(x error) func() string { 105 return x.Error 106 } 107 108 // Regression test for b/7269: 109 // taking the value of an interface method performs a nil check. 110 func nilInterfaceMethodValue() { 111 err := errors.New("ok") 112 f := err.Error 113 if got := f(); got != "ok" { 114 panic(got) 115 } 116 117 err = nil 118 if got := f(); got != "ok" { 119 panic(got) 120 } 121 122 defer func() { 123 r := fmt.Sprint(recover()) 124 // runtime panic string varies across toolchains 125 if r != "interface conversion: interface is nil, not error" && 126 r != "runtime error: invalid memory address or nil pointer dereference" { 127 panic("want runtime panic from nil interface method value, got " + r) 128 } 129 }() 130 f = err.Error // runtime panic: err is nil 131 panic("unreachable") 132 } 133 134 func main() { 135 valueReceiver() 136 pointerReceiver() 137 addressibleValuePointerReceiver() 138 promotedReceiver() 139 anonStruct() 140 typeCheck() 141 142 if e := regress1(errString("hi"))(); e != "hi" { 143 panic(e) 144 } 145 146 nilInterfaceMethodValue() 147 }