// 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() }