--- /dev/null
+// Tests of bound method closures.
+
+package main
+
+import (
+ "errors"
+ "fmt"
+)
+
+func assert(b bool) {
+ if !b {
+ panic("oops")
+ }
+}
+
+type I int
+
+func (i I) add(x int) int {
+ return int(i) + x
+}
+
+func valueReceiver() {
+ var three I = 3
+ assert(three.add(5) == 8)
+ var add3 func(int) int = three.add
+ assert(add3(5) == 8)
+}
+
+type S struct{ x int }
+
+func (s *S) incr() {
+ s.x++
+}
+
+func (s *S) get() int {
+ return s.x
+}
+
+func pointerReceiver() {
+ ps := new(S)
+ incr := ps.incr
+ get := ps.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func addressibleValuePointerReceiver() {
+ var s S
+ incr := s.incr
+ get := s.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+type S2 struct {
+ S
+}
+
+func promotedReceiver() {
+ var s2 S2
+ incr := s2.incr
+ get := s2.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func anonStruct() {
+ var s struct{ S }
+ incr := s.incr
+ get := s.get
+ assert(get() == 0)
+ incr()
+ incr()
+ incr()
+ assert(get() == 3)
+}
+
+func typeCheck() {
+ var i interface{}
+ i = (*S).incr
+ _ = i.(func(*S)) // type assertion: receiver type prepended to params
+
+ var s S
+ i = s.incr
+ _ = i.(func()) // type assertion: receiver type disappears
+}
+
+type errString string
+
+func (err errString) Error() string {
+ return string(err)
+}
+
+// Regression test for a builder crash.
+func regress1(x error) func() string {
+ return x.Error
+}
+
+// Regression test for b/7269:
+// taking the value of an interface method performs a nil check.
+func nilInterfaceMethodValue() {
+ err := errors.New("ok")
+ f := err.Error
+ if got := f(); got != "ok" {
+ panic(got)
+ }
+
+ err = nil
+ if got := f(); got != "ok" {
+ panic(got)
+ }
+
+ defer func() {
+ r := fmt.Sprint(recover())
+ // runtime panic string varies across toolchains
+ if r != "interface conversion: interface is nil, not error" &&
+ r != "runtime error: invalid memory address or nil pointer dereference" {
+ panic("want runtime panic from nil interface method value, got " + r)
+ }
+ }()
+ f = err.Error // runtime panic: err is nil
+ panic("unreachable")
+}
+
+func main() {
+ valueReceiver()
+ pointerReceiver()
+ addressibleValuePointerReceiver()
+ promotedReceiver()
+ anonStruct()
+ typeCheck()
+
+ if e := regress1(errString("hi"))(); e != "hi" {
+ panic(e)
+ }
+
+ nilInterfaceMethodValue()
+}