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