1// Tests of bound method closures. 2 3package main 4 5import ( 6 "errors" 7 "fmt" 8) 9 10func assert(b bool) { 11 if !b { 12 panic("oops") 13 } 14} 15 16type I int 17 18func (i I) add(x int) int { 19 return int(i) + x 20} 21 22func 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 29type S struct{ x int } 30 31func (s *S) incr() { 32 s.x++ 33} 34 35func (s *S) get() int { 36 return s.x 37} 38 39func 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 50func 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 61type S2 struct { 62 S 63} 64 65func 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 76func 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 87func 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 97type errString string 98 99func (err errString) Error() string { 100 return string(err) 101} 102 103// Regression test for a builder crash. 104func 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. 110func 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 134func 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} 148