// 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" &&
r != "method value: interface is nil" {
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()
}